Merge pull request #1328 from kakuilan/master

Added `ModelRewriteInheritanceVisitor` to rewrite the model inheritance for command `gen:model`.
This commit is contained in:
李铭昕 2020-02-12 09:24:23 +08:00 committed by GitHub
commit 6daca6b65d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 191 additions and 19 deletions

View File

@ -2,6 +2,7 @@
## Added
- [#1328](https://github.com/hyperf/hyperf/pull/1328) Added `ModelRewriteInheritanceVisitor` to rewrite the model inheritance for command `gen:model`.
- [#1331](https://github.com/hyperf/hyperf/pull/1331) Added `Hyperf\LoadBalancer\LoadBalancerInterface::getNodes()`.
## Changed

View File

@ -0,0 +1,103 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://doc.hyperf.io
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Database\Commands\Ast;
use Hyperf\Database\Commands\ModelData;
use Hyperf\Database\Commands\ModelOption;
use PhpParser\Node;
use PhpParser\Node\Identifier;
use PhpParser\NodeVisitorAbstract;
class ModelRewriteInheritanceVisitor extends NodeVisitorAbstract
{
/**
* @var ModelOption
*/
protected $option;
/**
* @var ModelData
*/
protected $data;
/**
* @var null|string
*/
protected $parentClass;
/**
* @var bool
*/
protected $shouldAddUseUse = true;
public function __construct(ModelOption $option, ModelData $data)
{
$this->option = $option;
$this->data = $data;
if (! empty($option->getUses())) {
preg_match_all('/\s*([a-z0-9\\\\]+)(as)?([a-z0-9]+)?;?\s*/is', $option->getUses(), $match);
if (isset($match[1][0])) {
$this->parentClass = $match[1][0];
}
}
}
public function afterTraverse(array $nodes)
{
if (empty($this->option->getUses())) {
return null;
}
$use = new Node\Stmt\UseUse(
new Node\Name($this->parentClass),
$this->option->getInheritance()
);
foreach ($nodes as $namespace) {
if (! $namespace instanceof Node\Stmt\Namespace_) {
continue;
}
if ($this->shouldAddUseUse) {
array_unshift($namespace->stmts, new Node\Stmt\Use_([$use]));
}
}
return null;
}
public function leaveNode(Node $node)
{
switch ($node) {
case $node instanceof Node\Stmt\Class_:
$inheritance = $this->option->getInheritance();
if (is_object($node->extends) && ! empty($inheritance)) {
$node->extends->parts = [$inheritance];
}
return $node;
case $node instanceof Node\Stmt\UseUse:
$class = implode('\\', $node->name->parts);
$alias = is_object($node->alias) ? $node->alias->name : null;
if ($class == $this->parentClass) {
// The parent class is exists.
$this->shouldAddUseUse = false;
if (end($node->name->parts) !== $this->option->getInheritance() && $alias !== $this->option->getInheritance()) {
// Rewrite the alias, if the class is not equal with inheritance.
$node->alias = new Identifier($this->option->getInheritance());
}
}
return $node;
}
}
}

View File

@ -98,7 +98,8 @@ class ModelCommand extends Command
->setRefreshFillable($this->getOption('refresh-fillable', 'commands.gen:model.refresh_fillable', $pool, false))
->setTableMapping($this->getOption('table-mapping', 'commands.gen:model.table_mapping', $pool, []))
->setIgnoreTables($this->getOption('ignore-tables', 'commands.gen:model.ignore_tables', $pool, []))
->setWithComments($this->getOption('with-comments', 'commands.gen:model.with_comments', $pool, false));
->setWithComments($this->getOption('with-comments', 'commands.gen:model.with_comments', $pool, false))
->setVisitors($this->getOption('visitors', 'commands.gen:model.visitors', $pool, []));
if ($table) {
$this->createModel($table, $option);
@ -121,6 +122,7 @@ class ModelCommand extends Command
$this->addOption('table-mapping', 'M', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Table mappings for model.');
$this->addOption('ignore-tables', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Ignore tables for creating models.');
$this->addOption('with-comments', null, InputOption::VALUE_NONE, 'Whether generate the property comments for model.');
$this->addOption('visitors', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Custom visitors for ast traverser.');
}
protected function getSchemaBuilder(string $poolName): MySqlBuilder
@ -172,7 +174,6 @@ class ModelCommand extends Command
if (! is_dir($dir)) {
@mkdir($dir, 0755, true);
}
file_put_contents($path, $this->buildClass($table, $class, $option));
}
@ -180,12 +181,15 @@ class ModelCommand extends Command
$stms = $this->astParser->parse(file_get_contents($path));
$traverser = new NodeTraverser();
$visitor = make(ModelUpdateVisitor::class, [
$traverser->addVisitor(make(ModelUpdateVisitor::class, [
'columns' => $columns,
'option' => $option,
]);
$traverser->addVisitor($visitor);
]));
$traverser->addVisitor(make(ModelRewriteConnectionVisitor::class, [$class, $option->getPool()]));
foreach ($option->getVisitors() as $visitorClass) {
$data = make(ModelData::class)->setClass($class)->setColumns($columns);
$traverser->addVisitor(make($visitorClass, [$option, $data]));
}
$stms = $traverser->traverse($stms);
$code = $this->printer->prettyPrintFile($stms);
@ -233,7 +237,7 @@ class ModelCommand extends Command
if (in_array($name, ['force-casts', 'refresh-fillable', 'with-comments'])) {
$nonInput = false;
}
if (in_array($name, ['table-mapping', 'ignore-tables'])) {
if (in_array($name, ['table-mapping', 'ignore-tables', 'visitors'])) {
$nonInput = [];
}

View File

@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://doc.hyperf.io
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Database\Commands;
class ModelData
{
/**
* @var array
*/
protected $columns;
/**
* @var string
*/
protected $class;
public function getColumns(): array
{
return $this->columns;
}
public function setColumns(array $columns): self
{
$this->columns = $columns;
return $this;
}
public function getClass(): string
{
return $this->class;
}
public function setClass(string $class): self
{
$this->class = $class;
return $this;
}
}

View File

@ -64,12 +64,17 @@ class ModelOption
*/
protected $ignoreTables = [];
/**
* @var array
*/
protected $visitors = [];
public function getPool(): string
{
return $this->pool;
}
public function setPool(string $pool): ModelOption
public function setPool(string $pool): self
{
$this->pool = $pool;
return $this;
@ -80,7 +85,7 @@ class ModelOption
return $this->path;
}
public function setPath(string $path): ModelOption
public function setPath(string $path): self
{
$this->path = $path;
return $this;
@ -91,7 +96,7 @@ class ModelOption
return $this->forceCasts;
}
public function setForceCasts(bool $forceCasts): ModelOption
public function setForceCasts(bool $forceCasts): self
{
$this->forceCasts = $forceCasts;
return $this;
@ -102,7 +107,7 @@ class ModelOption
return $this->prefix;
}
public function setPrefix(string $prefix): ModelOption
public function setPrefix(string $prefix): self
{
$this->prefix = $prefix;
return $this;
@ -113,7 +118,7 @@ class ModelOption
return $this->inheritance;
}
public function setInheritance(string $inheritance): ModelOption
public function setInheritance(string $inheritance): self
{
$this->inheritance = $inheritance;
return $this;
@ -124,7 +129,7 @@ class ModelOption
return $this->uses;
}
public function setUses(string $uses): ModelOption
public function setUses(string $uses): self
{
$this->uses = $uses;
return $this;
@ -135,7 +140,7 @@ class ModelOption
return $this->refreshFillable;
}
public function setRefreshFillable(bool $refreshFillable): ModelOption
public function setRefreshFillable(bool $refreshFillable): self
{
$this->refreshFillable = $refreshFillable;
return $this;
@ -146,7 +151,7 @@ class ModelOption
return $this->tableMapping;
}
public function setTableMapping(array $tableMapping): ModelOption
public function setTableMapping(array $tableMapping): self
{
foreach ($tableMapping as $item) {
[$key, $name] = explode(':', $item);
@ -161,7 +166,7 @@ class ModelOption
return $this->ignoreTables;
}
public function setIgnoreTables(array $ignoreTables): ModelOption
public function setIgnoreTables(array $ignoreTables): self
{
$this->ignoreTables = $ignoreTables;
return $this;
@ -172,9 +177,20 @@ class ModelOption
return $this->withComments;
}
public function setWithComments(bool $withComments): ModelOption
public function setWithComments(bool $withComments): self
{
$this->withComments = $withComments;
return $this;
}
public function getVisitors(): array
{
return $this->visitors;
}
public function setVisitors(array $visitors): self
{
$this->visitors = $visitors;
return $this;
}
}

View File

@ -408,7 +408,7 @@ class Blueprint
*
* @param array|string $columns
* @param string $name
* @return \Hyperf\Utils\Fluent|\Hyperf\Database\Schema\ForeignKeyDefinition
* @return \Hyperf\Database\Schema\ForeignKeyDefinition|\Hyperf\Utils\Fluent
*/
public function foreign($columns, $name = null)
{

View File

@ -15,7 +15,7 @@ namespace Hyperf\Database\Schema;
use Hyperf\Utils\Fluent;
/**
* @method ForeignKeyDefinition references(string|array $columns) Specify the referenced column(s)
* @method ForeignKeyDefinition references(array|string $columns) Specify the referenced column(s)
* @method ForeignKeyDefinition on(string $table) Specify the referenced table
* @method ForeignKeyDefinition onDelete(string $action) Add an ON DELETE action
* @method ForeignKeyDefinition onUpdate(string $action) Add an ON UPDATE action
@ -24,4 +24,4 @@ use Hyperf\Utils\Fluent;
*/
class ForeignKeyDefinition extends Fluent
{
}
}