mirror of
https://github.com/rectorphp/rector.git
synced 2025-02-21 01:41:00 +01:00
* remove doctrine/annotations * Refactor doctrine/annotation parser to static reflection with phpdoc-parser * remove doctirne-annotation-parser-syncer * remove annotation stubs * use nodes * almost there * [ci-review] Rector Rectify * skip temporary * phpstan: remove fixed messages Co-authored-by: kaizen-ci <info@kaizen-ci.org>
127 lines
3.5 KiB
PHP
127 lines
3.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Rector\Autodiscovery\Analyzer;
|
|
|
|
use PhpParser\Node\Stmt\Class_;
|
|
use PhpParser\Node\Stmt\ClassMethod;
|
|
use PHPStan\Type\ObjectType;
|
|
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
|
|
use Rector\Core\ValueObject\MethodName;
|
|
use Rector\NodeCollector\NodeCollector\NodeRepository;
|
|
use Rector\NodeNameResolver\NodeNameResolver;
|
|
use Rector\NodeTypeResolver\NodeTypeResolver;
|
|
|
|
final class ValueObjectClassAnalyzer
|
|
{
|
|
/**
|
|
* @var array<string, bool>
|
|
*/
|
|
private $valueObjectStatusByClassName = [];
|
|
|
|
/**
|
|
* @var NodeNameResolver
|
|
*/
|
|
private $nodeNameResolver;
|
|
|
|
/**
|
|
* @var NodeTypeResolver
|
|
*/
|
|
private $nodeTypeResolver;
|
|
|
|
/**
|
|
* @var PhpDocInfoFactory
|
|
*/
|
|
private $phpDocInfoFactory;
|
|
|
|
/**
|
|
* @var NodeRepository
|
|
*/
|
|
private $nodeRepository;
|
|
|
|
public function __construct(
|
|
NodeNameResolver $nodeNameResolver,
|
|
NodeTypeResolver $nodeTypeResolver,
|
|
PhpDocInfoFactory $phpDocInfoFactory,
|
|
NodeRepository $nodeRepository
|
|
) {
|
|
$this->nodeNameResolver = $nodeNameResolver;
|
|
$this->nodeTypeResolver = $nodeTypeResolver;
|
|
$this->phpDocInfoFactory = $phpDocInfoFactory;
|
|
$this->nodeRepository = $nodeRepository;
|
|
}
|
|
|
|
public function isValueObjectClass(Class_ $class): bool
|
|
{
|
|
if ($class->isAnonymous()) {
|
|
return false;
|
|
}
|
|
|
|
/** @var string $className */
|
|
$className = $this->nodeNameResolver->getName($class);
|
|
|
|
if (isset($this->valueObjectStatusByClassName[$className])) {
|
|
return $this->valueObjectStatusByClassName[$className];
|
|
}
|
|
|
|
$constructClassMethod = $class->getMethod(MethodName::CONSTRUCT);
|
|
|
|
if (! $constructClassMethod instanceof ClassMethod) {
|
|
return $this->analyseWithoutConstructor($class, $className);
|
|
}
|
|
|
|
// resolve constructor types
|
|
foreach ($constructClassMethod->params as $param) {
|
|
$paramType = $this->nodeTypeResolver->resolve($param);
|
|
if (! $paramType instanceof ObjectType) {
|
|
continue;
|
|
}
|
|
|
|
// awesome!
|
|
// is it services or value object?
|
|
$paramTypeClass = $this->nodeRepository->findClass($paramType->getClassName());
|
|
if (! $paramTypeClass instanceof Class_) {
|
|
// 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 analyseWithoutConstructor(Class_ $class, string $className): bool
|
|
{
|
|
// 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;
|
|
}
|
|
|
|
private function hasAllPropertiesWithSerialize(Class_ $class): bool
|
|
{
|
|
foreach ($class->getProperties() as $property) {
|
|
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($property);
|
|
if ($phpDocInfo->hasByAnnotationClass('JMS\Serializer\Annotation\Type')) {
|
|
continue;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|