mirror of
https://github.com/rectorphp/rector.git
synced 2025-04-22 00:12:29 +02:00
init MoveValueObjectsToValueObjectDirectoryRector (#2481)
init MoveValueObjectsToValueObjectDirectoryRector
This commit is contained in:
commit
a8b194244b
1
ecs.yaml
1
ecs.yaml
@ -84,6 +84,7 @@ parameters:
|
||||
- 'packages/Php71/src/Rector/FuncCall/RemoveExtraParametersRector.php'
|
||||
- 'packages/SOLID/src/Analyzer/ClassConstantFetchAnalyzer.php'
|
||||
# tough logic
|
||||
- 'packages/Autodiscovery/src/Analyzer/ClassAnalyzer.php'
|
||||
- 'packages/CodingStyle/src/Imports/ImportSkipper.php'
|
||||
- 'packages/PHPUnit/src/Rector/Class_/ArrayArgumentInTestToDataProviderRector.php'
|
||||
- 'packages/BetterPhpDocParser/src/Ast/PhpDoc/*/*TagValueNode.php'
|
||||
|
122
packages/Autodiscovery/src/Analyzer/ClassAnalyzer.php
Normal file
122
packages/Autodiscovery/src/Analyzer/ClassAnalyzer.php
Normal file
@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Autodiscovery\Analyzer;
|
||||
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use PHPStan\Type\ObjectType;
|
||||
use Rector\NodeContainer\ParsedNodesByType;
|
||||
use Rector\NodeTypeResolver\NodeTypeResolver;
|
||||
use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockManipulator;
|
||||
use Rector\PhpParser\Node\Resolver\NameResolver;
|
||||
|
||||
final class ClassAnalyzer
|
||||
{
|
||||
/**
|
||||
* @var bool[]
|
||||
*/
|
||||
private $valueObjectStatusByClassName = [];
|
||||
|
||||
/**
|
||||
* @var NameResolver
|
||||
*/
|
||||
private $nameResolver;
|
||||
|
||||
/**
|
||||
* @var ParsedNodesByType
|
||||
*/
|
||||
private $parsedNodesByType;
|
||||
|
||||
/**
|
||||
* @var NodeTypeResolver
|
||||
*/
|
||||
private $nodeTypeResolver;
|
||||
|
||||
/**
|
||||
* @var DocBlockManipulator
|
||||
*/
|
||||
private $docBlockManipulator;
|
||||
|
||||
public function __construct(
|
||||
NameResolver $nameResolver,
|
||||
ParsedNodesByType $parsedNodesByType,
|
||||
NodeTypeResolver $nodeTypeResolver,
|
||||
DocBlockManipulator $docBlockManipulator
|
||||
) {
|
||||
$this->nameResolver = $nameResolver;
|
||||
$this->parsedNodesByType = $parsedNodesByType;
|
||||
$this->nodeTypeResolver = $nodeTypeResolver;
|
||||
$this->docBlockManipulator = $docBlockManipulator;
|
||||
}
|
||||
|
||||
public function isValueObjectClass(Class_ $class): bool
|
||||
{
|
||||
if ($class->isAnonymous()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$className = $this->nameResolver->getName($class);
|
||||
|
||||
if (isset($this->valueObjectStatusByClassName[$className])) {
|
||||
return $this->valueObjectStatusByClassName[$className];
|
||||
}
|
||||
|
||||
$constructClassMethod = $class->getMethod('__construct');
|
||||
|
||||
if ($constructClassMethod === null) {
|
||||
// A. has all properties with serialize?
|
||||
if ($this->hasAllPropertiesWithSerialize($class)) {
|
||||
$this->valueObjectStatusByClassName[$className] = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// probably not a value object
|
||||
$this->valueObjectStatusByClassName[$className] = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// resolve constructor types
|
||||
foreach ($constructClassMethod->params as $param) {
|
||||
$paramType = $this->nodeTypeResolver->getObjectType($param);
|
||||
if (! $paramType instanceof ObjectType) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// awesome!
|
||||
// is it services or value object?
|
||||
$paramTypeClass = $this->parsedNodesByType->findClass($paramType->getClassName());
|
||||
if ($paramTypeClass === null) {
|
||||
// not sure :/
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $this->isValueObjectClass($paramTypeClass)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// if we didn't prove it's not a value object so far → fallback to true
|
||||
$this->valueObjectStatusByClassName[$className] = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function hasAllPropertiesWithSerialize(Class_ $class)
|
||||
{
|
||||
foreach ($class->stmts as $stmt) {
|
||||
if (! $stmt instanceof Property) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->docBlockManipulator->hasTag($stmt, 'JMS\Serializer\Annotation\Type')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Autodiscovery\Rector\FileSystem;
|
||||
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use Rector\Autodiscovery\Analyzer\ClassAnalyzer;
|
||||
use Rector\Autodiscovery\FileMover\FileMover;
|
||||
use Rector\FileSystemRector\Rector\AbstractFileSystemRector;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
/**
|
||||
* Inspiration @see https://github.com/rectorphp/rector/pull/1865/files#diff-0d18e660cdb626958662641b491623f8
|
||||
* @wip
|
||||
*
|
||||
* @sponsor Thanks https://spaceflow.io/ for sponsoring this rule - visit them on https://github.com/SpaceFlow-app
|
||||
*/
|
||||
final class MoveValueObjectsToValueObjectDirectoryRector extends AbstractFileSystemRector
|
||||
{
|
||||
/**
|
||||
* @var FileMover
|
||||
*/
|
||||
private $fileMover;
|
||||
|
||||
/**
|
||||
* @var ClassAnalyzer
|
||||
*/
|
||||
private $classAnalyzer;
|
||||
|
||||
public function __construct(FileMover $fileMover, ClassAnalyzer $classAnalyzer)
|
||||
{
|
||||
$this->fileMover = $fileMover;
|
||||
$this->classAnalyzer = $classAnalyzer;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition('Move value object to ValueObject namespace/directory');
|
||||
}
|
||||
|
||||
public function refactor(SmartFileInfo $smartFileInfo): void
|
||||
{
|
||||
$nodes = $this->parseFileInfoToNodes($smartFileInfo);
|
||||
|
||||
/** @var Class_|null $class */
|
||||
$class = $this->betterNodeFinder->findFirstInstanceOf($nodes, Class_::class);
|
||||
if ($class === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// get class
|
||||
if (! $this->classAnalyzer->isValueObjectClass($class)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$moved = $this->fileMover->createMovedNodesAndFilePath($smartFileInfo, $nodes, 'ValueObject');
|
||||
|
||||
// nothing to move
|
||||
if ($moved === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
[$nodes, $newFileDestination] = $moved;
|
||||
|
||||
$this->removeFile($smartFileInfo);
|
||||
$this->printNewNodesToFilePath($nodes, $newFileDestination);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user