diff --git a/README.md b/README.md
index e1d52a7..1c064b9 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@ a set of sample data and behaviour.
## Usage
-Simply running `dev/build` will take care of most sample data setup.
+Simply running `sake db:build` will take care of most sample data setup.
In order to use any of the optional test behaviour targeted at modules,
install the module and remove the `_manifest_exclude` file from the relevant folder.
@@ -26,7 +26,7 @@ For example, to test the tagfield module, remove the `frameworktest/code/tagfiel
The module creates some default pages for different CMS behaviours.
The CMS is intended to be perform well with a couple of thousand pages.
If you want to test the CMS behaviour for a large and nested tree,
-the module includes a simple generator task: `dev/tasks/FTPageMakerTask`.
+the module includes a simple generator task: `sake tasks:FTPageMakerTask`.
It will create 3^5 pages by default, so takes a while to run through.
## Configuring the amount of data
@@ -35,9 +35,9 @@ Both `FTPageMagerTask` and `FTFileMakerTask` allow the amount of generated conte
To do this, pass a comma-seprarated list of integers representing the amount of records to create at each
depth.
-`$ vendor/bin/sake dev/tasks/FTPageMakerTask pageCounts=10,200,5,5`
+`$ vendor/bin/sake tasks:FTPageMakerTask --pageCounts=10,200,5,5`
-`$ vendor/bin/sake dev/tasks/FTFileMakerTask fileCounts=5,300,55,5 folderCounts=1,5,5,5`
+`$ vendor/bin/sake tasks:FTFileMakerTask --fileCounts=5,300,55,5 --folderCounts=1,5,5,5`
## Guaranteed unique images
@@ -64,8 +64,8 @@ Usage:
```
# Generate some sample files to associate with blocks
-sake dev/tasks/FTFileMakerTask
-sake dev/tasks/FTPageMakerTask withBlocks=true
+sake tasks:FTFileMakerTask
+sake tasks:FTPageMakerTask withBlocks=true
```
## Requirements
diff --git a/_config/extensions.yml b/_config/extensions.yml
index ee8e25f..6828e29 100644
--- a/_config/extensions.yml
+++ b/_config/extensions.yml
@@ -28,9 +28,9 @@ SilverStripe\FrameworkTest\Fields\NestedGridField\NonRelationalData:
extensions:
- SilverStripe\FrameworkTest\Extension\TestDataObjectExtension
-SilverStripe\ORM\DatabaseAdmin:
+SilverStripe\Dev\Command\DbBuild:
extensions:
- - SilverStripe\FrameworkTest\GridFieldArbitraryData\DatabaseBuildExtension
+ - SilverStripe\FrameworkTest\GridFieldArbitraryData\DbBuildExtension
---
Only:
@@ -38,7 +38,7 @@ Only:
---
SilverStripe\TestSession\TestSessionEnvironment:
extensions:
- - SilverStripe\FrameworkTest\GridFieldArbitraryData\DatabaseBuildExtension
+ - SilverStripe\FrameworkTest\GridFieldArbitraryData\DbBuildExtension
---
Only:
diff --git a/code/GridFieldArbitraryData/DatabaseBuildExtension.php b/code/GridFieldArbitraryData/DbBuildExtension.php
similarity index 52%
rename from code/GridFieldArbitraryData/DatabaseBuildExtension.php
rename to code/GridFieldArbitraryData/DbBuildExtension.php
index 1267045..bec63d8 100644
--- a/code/GridFieldArbitraryData/DatabaseBuildExtension.php
+++ b/code/GridFieldArbitraryData/DbBuildExtension.php
@@ -4,7 +4,8 @@
use SilverStripe\Control\Director;
use SilverStripe\Core\Extension;
-use SilverStripe\ORM\DatabaseAdmin;
+use SilverStripe\Dev\Command\DbBuild;
+use SilverStripe\PolyExecution\PolyOutput;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DB;
use SilverStripe\ORM\FieldType\DBDatetime;
@@ -13,87 +14,66 @@
/**
* Builds the table and adds default records for the ArbitraryDataModel.
*/
-class DatabaseBuildExtension extends Extension
+class DbBuildExtension extends Extension
{
/**
* This extension hook is on TestSessionEnvironment, which is used by behat but not by phpunit.
- * For whatever reason, behat doesn't use dev/build, so we can't rely on the below onAfterbuild
+ * For whatever reason, behat doesn't build the db, so we can't rely on the below onAfterbuild
* being run in that scenario.
*/
protected function onAfterStartTestSession()
{
- $this->buildTable(true);
+ $output = PolyOutput::create(
+ Director::is_cli() ? PolyOutput::FORMAT_ANSI : PolyOutput::FORMAT_HTML,
+ PolyOutput::VERBOSITY_QUIET
+ );
+ $output->startList();
+ $this->buildTable($output);
+ $output->stopList();
$this->populateData();
}
/**
- * This extension hook is on DatabaseAdmin, after dev/build has finished building the database.
+ * This extension hook is on DbBuild, after building the database.
*/
- protected function onAfterBuild(bool $quiet, bool $populate, bool $testMode): void
+ protected function onAfterBuild(PolyOutput $output, bool $populate, bool $testMode): void
{
if ($testMode) {
return;
}
- if (!$quiet) {
- if (Director::is_cli()) {
- echo "\nCREATING TABLE FOR FRAMEWORKTEST ARBITRARY DATA\n\n";
- } else {
- echo "\n
Creating table for frameworktest arbitrary data
\n\n";
- }
- }
-
- $this->buildTable($quiet);
-
- if (!$quiet && !Director::is_cli()) {
- echo '
';
- }
-
+ $output->writeln('Creating table for frameworktest arbitrary data>');
+ $output->startList();
+ $this->buildTable($output);
+ $output->stopList();
if ($populate) {
- if (!$quiet) {
- if (Director::is_cli()) {
- echo "\nCREATING DATABASE RECORDS FOR FRAMEWORKTEST ARBITRARY DATA\n\n";
- } else {
- echo "\nCreating database records arbitrary data
\n\n";
- }
- }
-
+ $output->writeln('Creating database records arbitrary data>');
+ $output->startList();
$this->populateData();
-
- if (!$quiet && !Director::is_cli()) {
- echo '
';
- }
- }
-
- if (!$quiet) {
- echo (Director::is_cli()) ? "\n Frameworktest database build completed!\n\n" : 'Frameworktest database build completed!
';
+ $output->stopList();
}
+ $output->writeln(['Frameworktest database build completed!>', '']);
}
- private function buildTable(bool $quiet): void
+ private function buildTable(PolyOutput $output): void
{
$tableName = ArbitraryDataModel::TABLE_NAME;
// Log data
- if (!$quiet) {
- $showRecordCounts = DatabaseAdmin::config()->get('show_record_counts');
- if ($showRecordCounts && DB::get_schema()->hasTable($tableName)) {
- try {
- $count = SQLSelect::create()->setFrom($tableName)->count();
- $countSuffix = " ($count records)";
- } catch (\Exception $e) {
- $countSuffix = ' (error getting record count)';
- }
- } else {
- $countSuffix = "";
- }
-
- if (Director::is_cli()) {
- echo " * $tableName$countSuffix\n";
- } else {
- echo "$tableName$countSuffix\n";
+ $showRecordCounts = DbBuild::config()->get('show_record_counts');
+ if ($showRecordCounts && DB::get_schema()->hasTable($tableName)) {
+ try {
+ $count = SQLSelect::create()->setFrom($tableName)->count();
+ $countSuffix = " ($count records)";
+ } catch (\Exception $e) {
+ $countSuffix = ' (error getting record count)';
}
+ } else {
+ $countSuffix = "";
}
+ // We're adding one list item, but we need to do it this way for consistency
+ // with the rest of the db build output
+ $output->writeListItem($tableName . $countSuffix);
// Get field schema
$fields = [
diff --git a/code/tasks/FTFileMakerTask.php b/code/tasks/FTFileMakerTask.php
index c23dfd1..3d3b006 100644
--- a/code/tasks/FTFileMakerTask.php
+++ b/code/tasks/FTFileMakerTask.php
@@ -11,6 +11,10 @@
use SilverStripe\Security\Security;
use SilverStripe\Core\Path;
use SilverStripe\Core\Manifest\ModuleResourceLoader;
+use SilverStripe\PolyExecution\PolyOutput;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
/**
* Creates sample folder and file structure, useful to test performance,
@@ -24,10 +28,6 @@
* recursively delete any generated ones through the following bash command in `assets/`:
* `find . -name '*Resampled*' -print0 | xargs -0 rm`
*
- * Parameters:
- * - reset=1: Optionally truncate ALL files and folders in the database, plus delete
- * the entire `assets/` directory.
- *
*
* Configuration
*
@@ -58,7 +58,7 @@
* - 0
*
* Flush and run:
- * /dev/tasks/FTFileMakerTask?flush&reset=1
+ * sake tasks:FTFileMakerTask --flush --reset
*
* @todo Automatically retrieve file listing from S3
* @todo Handle HTTP errors from S3
@@ -180,8 +180,6 @@ class FTFileMakerTask extends BuildTask
'video.m4v' => 'SilverStripe\Assets\File',
];
- protected $lineBreak = "\n
";
-
/** @var Member */
protected $anonymousMember = null;
@@ -197,7 +195,7 @@ class FTFileMakerTask extends BuildTask
*/
protected $folderCounts = [];
- public function run($request)
+ protected function execute(InputInterface $input, PolyOutput $output): int
{
set_time_limit(0);
@@ -213,15 +211,11 @@ public function run($request)
}
Security::setCurrentUser($this->anonymousMember);
- if (php_sapi_name() == "cli") {
- $this->lineBreak = "\n";
- }
-
- if ($request->getVar('reset')) {
- $this->reset();
+ if ($input->getOption('reset')) {
+ $this->reset($output);
}
- $fileCounts = $request->getVar('fileCounts');
+ $fileCounts = $input->getOption('fileCounts');
if ($fileCounts) {
$counts = explode(',', $fileCounts ?? '');
$this->fileCounts = array_map(function ($int) {
@@ -231,7 +225,7 @@ public function run($request)
$this->fileCounts = FTFileMakerTask::config()->get('fileCountByDepth');
}
- $folderCounts = $request->getVar('folderCounts');
+ $folderCounts = $input->getOption('folderCounts');
if ($folderCounts) {
$counts = explode(',', $folderCounts ?? '');
$this->folderCounts = array_map(function ($int) {
@@ -241,26 +235,27 @@ public function run($request)
$this->folderCounts = FTFileMakerTask::config()->get('folderCountByDepth');
}
- echo "Downloading fixtures" . $this->lineBreak;
- $fixtureFilePaths = $this->downloadFixtureFiles();
+ $output->writeln('Downloading fixtures');
+ $fixtureFilePaths = $this->downloadFixtureFiles($output);
if (!FTFileMakerTask::config()->get('documentsOnly')) {
- echo "Generate thumbnails" . $this->lineBreak;
+ $output->writeln('Generate thumbnails');
$this->generateThumbnails($fixtureFilePaths);
}
- echo "Generate files" . $this->lineBreak;
+ $output->writeln('Generate files');
$this->generateFiles($fixtureFilePaths);
if (!FTFileMakerTask::config()->get('doPutProtectedFilesInPublicStore')) {
- echo "Incorrectly putting protected files into public asset store on purpose" . $this->lineBreak;
+ $output->writeln('Incorrectly putting protected files into public asset store on purpose');
$this->putProtectedFilesInPublicAssetStore();
}
+ return Command::SUCCESS;
}
- protected function reset()
+ protected function reset(PolyOutput $output)
{
- echo "Resetting assets" . $this->lineBreak;
+ $output->writeln('Resetting assets');
DB::query('TRUNCATE "File"');
DB::query('TRUNCATE "File_Live"');
@@ -271,7 +266,7 @@ protected function reset()
}
}
- protected function downloadFixtureFiles()
+ protected function downloadFixtureFiles(PolyOutput $output)
{
$client = new Client(['base_uri' => $this->fixtureFileBaseUrl]);
@@ -293,7 +288,7 @@ protected function downloadFixtureFiles()
$promises[$filename] = $client->getAsync($filename, [
'sink' => $path
]);
- echo "Downloading $url" . $this->lineBreak;
+ $output->writeln("Downloading $url");
}
}
@@ -497,4 +492,28 @@ protected function watermarkImage(string $stampPath, string $targetPath): ?strin
return $targetPath;
}
+ public function getOptions(): array
+ {
+ return [
+ new InputOption(
+ 'reset',
+ null,
+ InputOption::VALUE_NONE,
+ 'Optionally truncate ALL files and folders in the database,'
+ . ' plus delete the entire `assets/` directory',
+ ),
+ new InputOption(
+ 'fileCounts',
+ null,
+ InputOption::VALUE_REQUIRED,
+ 'Comma separated string'
+ ),
+ new InputOption(
+ 'folderCounts',
+ null,
+ InputOption::VALUE_REQUIRED,
+ 'Comma separated string'
+ ),
+ ];
+ }
}
diff --git a/code/tasks/FTPageMakerTask.php b/code/tasks/FTPageMakerTask.php
index 4d8b276..3c96a68 100644
--- a/code/tasks/FTPageMakerTask.php
+++ b/code/tasks/FTPageMakerTask.php
@@ -8,7 +8,10 @@
use SilverStripe\ElementalFileBlock\Block\FileBlock;
use SilverStripe\CMS\Model\SiteTree;
use DNADesign\Elemental\Extensions\ElementalPageExtension;
-use DNADesign\Elemental\Models\BaseElement;
+use SilverStripe\PolyExecution\PolyOutput;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
/**
* Creates sample page structure, useful to test tree performance,
@@ -48,16 +51,16 @@ class FTPageMakerTask extends BuildTask
'SilverStripe\ElementalFileBlock\Block\FileBlock' => [FTPageMakerTask::class, 'generateFileBlock'],
];
- public function run($request)
+ protected function execute(InputInterface $input, PolyOutput $output): int
{
// Optionally add blocks
- $withBlocks = (bool)$request->getVar('withBlocks');
+ $withBlocks = (bool)$input->getOption('withBlocks');
if ($withBlocks && !class_exists('DNADesign\Elemental\Models\BaseElement')) {
throw new \LogicException('withBlocks requested, but BaseElement class not found');
}
// Allow pageCountByDepth to be passed as comma-separated value, e.g. pageCounts=5,100,1,1
- $pageCounts = $request->getVar('pageCounts');
+ $pageCounts = $input->getOption('pageCounts');
if ($pageCounts) {
$counts = explode(',', $pageCounts ?? '');
$this->pageCountByDepth = array_map(function ($int) {
@@ -65,10 +68,11 @@ public function run($request)
}, $counts ?? []);
}
- $this->generatePages(0, "", 0, $withBlocks);
+ $this->generatePages($output, 0, "", 0, $withBlocks);
+ return Command::SUCCESS;
}
- protected function generatePages($depth = 0, $prefix = "", $parentID = 0, $withBlocks = false)
+ protected function generatePages(PolyOutput $output, $depth = 0, $prefix = "", $parentID = 0, $withBlocks = false)
{
$maxDepth = count($this->pageCountByDepth ?? []);
$pageCount = $this->pageCountByDepth[$depth];
@@ -84,10 +88,10 @@ protected function generatePages($depth = 0, $prefix = "", $parentID = 0, $withB
$page->write();
$page->copyVersionToStage('Stage', 'Live');
- echo "Created '$page->Title' ($page->ClassName)\n";
+ $output->writeln("Created '$page->Title' ($page->ClassName)");
if ($withBlocks) {
- $this->generateBlocksForPage($page);
+ $this->generateBlocksForPage($output, $page);
}
$pageID = $page->ID;
@@ -95,12 +99,12 @@ protected function generatePages($depth = 0, $prefix = "", $parentID = 0, $withB
unset($page);
if ($depth < $maxDepth-1) {
- $this->generatePages($depth+1, $fullPrefix, $pageID, $withBlocks);
+ $this->generatePages($output, $depth+1, $fullPrefix, $pageID, $withBlocks);
}
}
}
- protected function generateBlocksForPage(Page $page)
+ protected function generateBlocksForPage(PolyOutput $output, Page $page)
{
$classes = array_filter($this->config()->get('block_generators') ?? [], function ($callable, $class) {
return class_exists($class ?? '');
@@ -121,7 +125,7 @@ protected function generateBlocksForPage(Page $page)
$block->publishRecursive();
}
- echo sprintf(" Added '%s' block #%d to page #%d\n", $class, $block->ID, $page->ID);
+ $output->writeln(sprintf(" Added '%s' block #%d to page #%d", $class, $block->ID, $page->ID));
}
}
@@ -193,4 +197,21 @@ public static function generateBannerBlock(?SiteTree $page = null): BannerBlock
return $block;
}
+ public function getOptions(): array
+ {
+ return [
+ new InputOption(
+ 'withBlocks',
+ null,
+ InputOption::VALUE_NONE,
+ 'Include elemental blocks on the page',
+ ),
+ new InputOption(
+ 'pageCounts',
+ null,
+ InputOption::VALUE_REQUIRED,
+ 'Comma separated string'
+ ),
+ ];
+ }
}
diff --git a/code/tasks/FTPageTypeCreatorTask.php b/code/tasks/FTPageTypeCreatorTask.php
index 541b822..96d7874 100644
--- a/code/tasks/FTPageTypeCreatorTask.php
+++ b/code/tasks/FTPageTypeCreatorTask.php
@@ -2,10 +2,13 @@
use SilverStripe\Dev\BuildTask;
use Faker\Factory;
-use SilverStripe\Control\HTTPRequest;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;
use SilverStripe\Core\Manifest\ModuleLoader;
+use SilverStripe\PolyExecution\PolyOutput;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Filesystem\Exception\IOException;
class FTPageTypeCreatorTask extends BuildTask
@@ -36,12 +39,9 @@ public function __construct()
$this->finder = new Finder();
}
- /**
- * @param HTTPRequest $request
- */
- public function run($request)
+ protected function execute(InputInterface $input, PolyOutput $output): int
{
- $count = $request->getVar('count') ?: 20;
+ $count = $input->getOption('count');
$module = ModuleLoader::getModule('silverstripe/frameworktest');
$testPageDir = $module->getPath() . '/code/test-pages';
if (!$this->fs->exists($testPageDir)) {
@@ -66,11 +66,19 @@ class_exists(basename($className ?? '', 'php'))
$this->fs->dumpFile($filePath, $code);
$created++;
} catch (IOException $e) {
- echo "Could not write to file $filePath. Got error: {$e->getMessage()}\n";
+ $output->writeln("Could not write to file $filePath. Got error: {$e->getMessage()}");
die();
}
- echo "Created page type $className\n";
+ $output->writeln("Created page type $className");
}
+ return Command::SUCCESS;
+ }
+
+ public function getOptions(): array
+ {
+ return [
+ new InputOption('count', null, InputOption::VALUE_REQUIRED, 'Number of page types to create', 20),
+ ];
}
private function getExistingClassNames($dir)
@@ -107,5 +115,4 @@ class $className extends Page implements TestPageInterface
PHP;
return $code;
}
-
-}
\ No newline at end of file
+}