Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #17 from msmakouz/feature/scaffolders
Add scaffolders for Entities, Repositories and Migraions from SF
- Loading branch information
Showing
15 changed files
with
687 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Spiral\Cycle\Bootloader; | ||
|
||
use Spiral\Console\Bootloader\ConsoleBootloader; | ||
use Spiral\Cycle\Scaffolder\Declaration; | ||
use Spiral\Boot\Bootloader\Bootloader; | ||
use Spiral\Scaffolder\Bootloader\ScaffolderBootloader as BaseScaffolderBootloader; | ||
|
||
class ScaffolderBootloader extends Bootloader | ||
{ | ||
public const DEPENDENCIES = [ | ||
ConsoleBootloader::class, | ||
BaseScaffolderBootloader::class | ||
]; | ||
|
||
public function boot(BaseScaffolderBootloader $scaffolder): void | ||
{ | ||
$scaffolder->addDeclaration('migration', [ | ||
'namespace' => '', | ||
'postfix' => 'Migration', | ||
'class' => Declaration\MigrationDeclaration::class, | ||
]); | ||
|
||
$scaffolder->addDeclaration('entity', [ | ||
'namespace' => 'Database', | ||
'postfix' => '', | ||
'options' => [ | ||
'annotated' => Declaration\Entity\AnnotatedDeclaration::class, | ||
], | ||
]); | ||
|
||
$scaffolder->addDeclaration('repository', [ | ||
'namespace' => 'Repository', | ||
'postfix' => 'Repository', | ||
'class' => Declaration\RepositoryDeclaration::class, | ||
]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Spiral\Cycle\Console\Command\Scaffolder; | ||
|
||
use Spiral\Console\Console; | ||
use Spiral\Cycle\Scaffolder\Declaration\Entity\AnnotatedDeclaration; | ||
use Spiral\Reactor\AbstractDeclaration; | ||
use Spiral\Scaffolder\Command\AbstractCommand; | ||
use Spiral\Scaffolder\Config\ScaffolderConfig; | ||
use Spiral\Scaffolder\Exception\ScaffolderException; | ||
use Symfony\Component\Console\Input\InputArgument; | ||
use Symfony\Component\Console\Input\InputOption; | ||
use Throwable; | ||
|
||
use function Spiral\Scaffolder\trimPostfix; | ||
|
||
class EntityCommand extends AbstractCommand | ||
{ | ||
protected const ELEMENT = 'entity'; | ||
|
||
protected const NAME = 'create:entity'; | ||
protected const DESCRIPTION = 'Create entity declaration'; | ||
protected const ARGUMENTS = [ | ||
['name', InputArgument::REQUIRED, 'Entity name'], | ||
['format', InputArgument::OPTIONAL, 'Declaration format (annotated, xml?, yaml?, php?)', 'annotated'], | ||
]; | ||
protected const OPTIONS = [ | ||
[ | ||
'role', | ||
'r', | ||
InputOption::VALUE_OPTIONAL, | ||
'Entity role, defaults to lowercase class name without a namespace', | ||
], | ||
[ | ||
'mapper', | ||
'm', | ||
InputOption::VALUE_OPTIONAL, | ||
'Mapper class name, defaults to Cycle\ORM\Mapper\Mapper', | ||
], | ||
[ | ||
'repository', | ||
'e', | ||
InputOption::VALUE_NONE, | ||
'Repository class to represent read operations for an entity, defaults to Cycle\ORM\Select\Repository', | ||
], | ||
[ | ||
'table', | ||
't', | ||
InputOption::VALUE_OPTIONAL, | ||
'Entity source table, defaults to plural form of entity role', | ||
], | ||
[ | ||
'database', | ||
'd', | ||
InputOption::VALUE_OPTIONAL, | ||
'Database name, defaults to null (default database)', | ||
], | ||
[ | ||
'accessibility', | ||
'a', | ||
InputOption::VALUE_OPTIONAL, | ||
'Accessibility accessor (public, protected, private)', | ||
AbstractDeclaration::ACCESS_PUBLIC, | ||
], | ||
[ | ||
'inflection', | ||
'i', | ||
InputOption::VALUE_OPTIONAL, | ||
'Column name inflection, allowed values: tableize (t), camelize (c)', | ||
'tableize', | ||
], | ||
[ | ||
'field', | ||
'f', | ||
InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, | ||
'Add field in a format "name:type"', | ||
], | ||
[ | ||
'comment', | ||
'c', | ||
InputOption::VALUE_OPTIONAL, | ||
'Optional comment to add as class header', | ||
], | ||
]; | ||
|
||
/** | ||
* Create entity declaration. | ||
* | ||
* @throws Throwable | ||
*/ | ||
public function perform(Console $console, ScaffolderConfig $config): int | ||
{ | ||
$accessibility = (string)$this->option('accessibility'); | ||
$this->validateAccessibility($accessibility); | ||
|
||
/** @var AnnotatedDeclaration $declaration */ | ||
$declaration = $this->createDeclaration(); | ||
|
||
$repository = trimPostfix((string)$this->argument('name'), 'repository'); | ||
if ($this->option('repository')) { | ||
$repositoryClass = $config->className(RepositoryCommand::ELEMENT, $repository); | ||
$repositoryNamespace = $config->classNamespace(RepositoryCommand::ELEMENT, $repository); | ||
$declaration->setRepository("\\$repositoryNamespace\\$repositoryClass"); | ||
} | ||
|
||
$declaration->setRole((string)$this->option('role')); | ||
$declaration->setMapper((string)$this->option('mapper')); | ||
$declaration->setTable((string)$this->option('table')); | ||
$declaration->setDatabase((string)$this->option('database')); | ||
$declaration->setInflection((string)$this->option('inflection')); | ||
|
||
foreach ($this->option('field') as $field) { | ||
if (\strpos($field, ':') === false) { | ||
throw new ScaffolderException("Field definition must in 'name:type' or 'name:type' form"); | ||
} | ||
|
||
$parts = \explode(':', $field); | ||
[$name, $type] = $parts; | ||
|
||
$declaration->addField($name, $accessibility, $type); | ||
} | ||
|
||
$declaration->declareSchema(); | ||
|
||
$this->writeDeclaration($declaration); | ||
|
||
if ($this->option('repository')) { | ||
$console->run('create:repository', [ | ||
'name' => !empty($repository) ? $repository : $this->argument('name'), | ||
]); | ||
} | ||
|
||
return self::SUCCESS; | ||
} | ||
|
||
protected function declarationClass(string $element): string | ||
{ | ||
return $this->config->declarationOptions($element)[(string)$this->argument('format')]; | ||
} | ||
|
||
private function validateAccessibility(string $accessibility): void | ||
{ | ||
if ( | ||
!\in_array($accessibility, [ | ||
AbstractDeclaration::ACCESS_PUBLIC, | ||
AbstractDeclaration::ACCESS_PROTECTED, | ||
AbstractDeclaration::ACCESS_PRIVATE, | ||
], true) | ||
) { | ||
throw new ScaffolderException("Invalid accessibility value `$accessibility`"); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Spiral\Cycle\Console\Command\Scaffolder; | ||
|
||
use Spiral\Cycle\Scaffolder\Declaration\MigrationDeclaration; | ||
use Cycle\Migrations\Migrator; | ||
use Spiral\Reactor\FileDeclaration; | ||
use Spiral\Scaffolder\Command\AbstractCommand; | ||
use Spiral\Scaffolder\Exception\ScaffolderException; | ||
use Symfony\Component\Console\Input\InputArgument; | ||
use Symfony\Component\Console\Input\InputOption; | ||
|
||
class MigrationCommand extends AbstractCommand | ||
{ | ||
protected const ELEMENT = 'migration'; | ||
|
||
protected const NAME = 'create:migration'; | ||
protected const DESCRIPTION = 'Create migration declaration'; | ||
protected const ARGUMENTS = [ | ||
['name', InputArgument::REQUIRED, 'Migration name'], | ||
]; | ||
protected const OPTIONS = [ | ||
[ | ||
'table', | ||
't', | ||
InputOption::VALUE_OPTIONAL, | ||
'Table to be created table', | ||
], | ||
[ | ||
'field', | ||
'f', | ||
InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, | ||
'Create field in a format "name:type"', | ||
], | ||
[ | ||
'comment', | ||
null, | ||
InputOption::VALUE_OPTIONAL, | ||
'Optional comment to add as class header', | ||
], | ||
]; | ||
|
||
/** | ||
* Create migration declaration. | ||
* | ||
* @throws ScaffolderException | ||
*/ | ||
public function perform(Migrator $migrator): int | ||
{ | ||
/** @var MigrationDeclaration $declaration */ | ||
$declaration = $this->createDeclaration(); | ||
|
||
if (!empty($this->option('table'))) { | ||
$fields = []; | ||
foreach ($this->option('field') as $field) { | ||
if (!\str_contains($field, ':')) { | ||
throw new ScaffolderException("Field definition must in 'name:type' form"); | ||
} | ||
|
||
[$name, $type] = \explode(':', $field); | ||
$fields[$name] = $type; | ||
} | ||
|
||
$declaration->declareCreation((string)$this->option('table'), $fields); | ||
} | ||
|
||
$file = new FileDeclaration($this->getNamespace()); | ||
$file->setDirectives('strict_types=1'); | ||
$file->setComment($this->config->headerLines()); | ||
$file->addElement($declaration); | ||
|
||
$filename = $migrator->getRepository()->registerMigration( | ||
(string)$this->argument('name'), | ||
$declaration->getName(), | ||
$file->render() | ||
); | ||
|
||
$this->writeln( | ||
"Declaration of '<info>{$declaration->getName()}</info>' " | ||
. "has been successfully written into '<comment>{$filename}</comment>'." | ||
); | ||
|
||
return self::SUCCESS; | ||
} | ||
} |
Oops, something went wrong.