Fix Doctrine stubs + separate reported files into 2 (#1967)

Fix Doctrine stubs + separate reported files into 2
This commit is contained in:
Tomáš Votruba 2019-09-10 15:28:15 +02:00 committed by GitHub
commit 418182b782
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 179 additions and 112 deletions

View File

@ -86,10 +86,7 @@
"Rector\\TypeDeclaration\\": "packages/TypeDeclaration/src",
"Rector\\Utils\\DocumentationGenerator\\": "utils/DocumentationGenerator/src",
"Rector\\Utils\\RectorGenerator\\": "utils/RectorGenerator/src"
},
"classmap": [
"stubs"
]
}
},
"autoload-dev": {
"psr-4": {

View File

@ -2,39 +2,58 @@
namespace Rector\Doctrine\Collector;
use Rector\DoctrinePhpDocParser\Contract\Ast\PhpDoc\DoctrineRelationTagValueNodeInterface;
use Rector\DoctrinePhpDocParser\Contract\Ast\PhpDoc\ToManyTagNodeInterface;
final class UuidMigrationDataCollector
{
/**
* @var mixed[]
* @var string[][][]
*/
private $propertiesByClass = [];
private $columnPropertiesByClass = [];
public function addClassAndProperty(string $class, string $property): void
/**
* @var string[][][][]
*/
private $relationPropertiesByClass = [];
public function addClassAndColumnProperty(string $class, string $propertyName): void
{
$this->propertiesByClass[$class]['properties'][] = $property;
$this->columnPropertiesByClass[$class]['properties'][] = $propertyName;
}
public function addClassToManyRelationProperty(
string $class,
string $oldPropertyName,
string $uuidPropertyName
string $uuidPropertyName,
DoctrineRelationTagValueNodeInterface $doctrineRelationTagValueNode
): void {
$this->propertiesByClass[$class]['to_many_relations'][] = [
$kind = $this->resolveKind($doctrineRelationTagValueNode);
$this->relationPropertiesByClass[$class][$kind][] = [
'property_name' => $oldPropertyName,
'uuid_property_name' => $uuidPropertyName,
];
}
public function addClassToOneRelationProperty(string $class, string $property): void
{
$this->propertiesByClass[$class]['to_one_relations'][] = $property;
}
/**
* @return string[][][]
*/
public function getPropertiesByClass(): array
public function getColumnPropertiesByClass(): array
{
return $this->propertiesByClass;
return $this->columnPropertiesByClass;
}
/**
* @return string[][][][]
*/
public function getRelationPropertiesByClass(): array
{
return $this->relationPropertiesByClass;
}
private function resolveKind(DoctrineRelationTagValueNodeInterface $doctrineRelationTagValueNode): string
{
return $doctrineRelationTagValueNode instanceof ToManyTagNodeInterface ? 'to_many_relations' : 'to_one_relations';
}
}

View File

@ -30,23 +30,31 @@ final class ReportEntitiesWithAddedPropertiesFinishExtension implements Finishin
public function run(): void
{
$propertiesByClass = $this->uuidMigrationDataCollector->getPropertiesByClass();
if ($propertiesByClass === []) {
$this->generatePropertiesJsonWithFileName(
'uuid-migration-new-column-properties.json',
$this->uuidMigrationDataCollector->getColumnPropertiesByClass()
);
$this->generatePropertiesJsonWithFileName(
'uuid-migration-new-relation-properties.json',
$this->uuidMigrationDataCollector->getRelationPropertiesByClass()
);
}
/**
* @param mixed[] $data
*/
private function generatePropertiesJsonWithFileName(string $fileName, array $data): void
{
if ($data === []) {
return;
}
$data = [
'title' => 'Entities with new properties',
'added_properties_by_class' => $propertiesByClass,
];
$jsonContent = Json::encode(['new_columns_by_class' => $data], Json::PRETTY);
$jsonContent = Json::encode($data, Json::PRETTY);
$filePath = getcwd() . '/uuid-migration.json';
$filePath = getcwd() . '/' . $fileName;
FileSystem::write($filePath, $jsonContent);
$this->symfonyStyle->warning(
'See freshly created "uuid-migration.json" file for changes on entities and further SQL migration steps'
);
$this->symfonyStyle->warning(sprintf('See freshly created "%s" file for changes on entities', $fileName));
}
}

View File

@ -36,9 +36,8 @@ final class PhpDocTagNodeFactory
public function createVarTagUuidInterface(): PhpDocTagNode
{
$varTagValueNode = new VarTagValueNode(new IdentifierTypeNode(
'\\' . DoctrineClass::RAMSEY_UUID_INTERFACE
), '', '');
$identifierTypeNode = new IdentifierTypeNode('\\' . DoctrineClass::RAMSEY_UUID_INTERFACE);
$varTagValueNode = new VarTagValueNode($identifierTypeNode, '', '');
return new PhpDocTagNode('@var', $varTagValueNode);
}
@ -78,12 +77,14 @@ final class PhpDocTagNodeFactory
public function createJoinTableTagNode(Property $property): PhpDocTagNode
{
$joinTableName = $this->joinTableNameResolver->resolveManyToManyTableNameForProperty($property);
$uuidJoinTable = $joinTableName . '_uuid';
$uuidJoinTable = $this->joinTableNameResolver->resolveManyToManyUuidTableNameForProperty($property);
$joinTableTagValueNode = new JoinTableTagValueNode($uuidJoinTable, null, [
new JoinColumnTagValueNode(null, 'uuid'),
], [new JoinColumnTagValueNode(null, 'uuid')]);
$joinTableTagValueNode = new JoinTableTagValueNode(
$uuidJoinTable,
null,
[new JoinColumnTagValueNode(null, 'uuid')],
[new JoinColumnTagValueNode(null, 'uuid')]
);
return new AttributeAwarePhpDocTagNode(JoinTableTagValueNode::SHORT_NAME, $joinTableTagValueNode);
}

View File

@ -96,7 +96,7 @@ final class AddUuidMirrorForRelationPropertyRector extends AbstractRector
*/
private function createMirrorNullable(Property $property): Property
{
$oldProperytName = $this->getName($property);
$oldPropertyName = $this->getName($property);
$propertyWithUuid = clone $property;
@ -105,11 +105,11 @@ final class AddUuidMirrorForRelationPropertyRector extends AbstractRector
// name must be changed after the doc comment update, because the reflection annotation needed for update of doc comment
// would miss non existing *Uuid property
$uuidPropertyName = $oldProperytName . 'Uuid';
$uuidPropertyName = $oldPropertyName . 'Uuid';
$newPropertyProperty = new PropertyProperty(new VarLikeIdentifier($uuidPropertyName));
$propertyWithUuid->props = [$newPropertyProperty];
$this->addNewPropertyToCollector($property, $oldProperytName, $uuidPropertyName);
$this->addNewPropertyToCollector($property, $oldPropertyName, $uuidPropertyName);
return $propertyWithUuid;
}
@ -186,6 +186,10 @@ final class AddUuidMirrorForRelationPropertyRector extends AbstractRector
return true;
}
if (! property_exists($targetEntity, 'uuid')) {
return true;
}
return false;
}
@ -200,14 +204,11 @@ final class AddUuidMirrorForRelationPropertyRector extends AbstractRector
/** @var DoctrineRelationTagValueNodeInterface $doctrineRelationTagValueNode */
$doctrineRelationTagValueNode = $this->getDoctrineRelationTagValueNode($property);
if ($doctrineRelationTagValueNode instanceof ToManyTagNodeInterface) {
$this->uuidMigrationDataCollector->addClassToManyRelationProperty(
$className,
$oldPropertyName,
$uuidPropertyName
);
} elseif ($doctrineRelationTagValueNode instanceof ToOneTagNodeInterface) {
$this->uuidMigrationDataCollector->addClassToOneRelationProperty($className, $uuidPropertyName);
}
$this->uuidMigrationDataCollector->addClassToManyRelationProperty(
$className,
$oldPropertyName,
$uuidPropertyName,
$doctrineRelationTagValueNode
);
}
}

View File

@ -86,7 +86,7 @@ final class AddUuidToEntityWhereMissingRector extends AbstractRector
/** @var string $class */
$class = $this->getName($node);
$this->uuidMigrationDataCollector->addClassAndProperty($class, 'uuid');
$this->uuidMigrationDataCollector->addClassAndColumnProperty($class, 'uuid');
return $node;
}

View File

@ -3,11 +3,9 @@
namespace Rector\Doctrine\Uuid;
use Nette\Utils\Strings;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Property;
use Rector\Doctrine\PhpDocParser\DoctrineDocBlockResolver;
use Rector\Exception\ShouldNotHappenException;
use Rector\NodeContainer\ParsedNodesByType;
use Rector\NodeTypeResolver\Node\AttributeKey;
final class JoinTableNameResolver
@ -17,42 +15,28 @@ final class JoinTableNameResolver
*/
private $doctrineDocBlockResolver;
/**
* @var ParsedNodesByType
*/
private $parsedNodesByType;
public function __construct(
DoctrineDocBlockResolver $doctrineDocBlockResolver,
ParsedNodesByType $parsedNodesByType
) {
public function __construct(DoctrineDocBlockResolver $doctrineDocBlockResolver)
{
$this->doctrineDocBlockResolver = $doctrineDocBlockResolver;
$this->parsedNodesByType = $parsedNodesByType;
}
/**
* Guessed many-to-many table name like: first_table_second_table
* Create many-to-many table name like: "first_table_second_table_uuid"
*/
public function resolveManyToManyTableNameForProperty(Property $property): string
public function resolveManyToManyUuidTableNameForProperty(Property $property): string
{
/** @var Class_ $currentClass */
$currentClass = $property->getAttribute(AttributeKey::CLASS_NODE);
$currentTableName = $this->resolveTableNameFromClass($currentClass);
/** @var string $className */
$className = $property->getAttribute(AttributeKey::CLASS_NAME);
$currentTableName = $this->resolveShortClassName($className);
$targetEntity = $this->doctrineDocBlockResolver->getTargetEntity($property);
if ($targetEntity === null) {
throw new ShouldNotHappenException(__METHOD__);
}
$targetEntityClass = $this->parsedNodesByType->findClass($targetEntity);
if ($targetEntityClass === null) {
// dummy fallback
$targetTableName = $this->resolveShortClassName($targetEntity);
} else {
$targetTableName = $this->resolveTableNameFromClass($targetEntityClass);
}
$targetTableName = $this->resolveShortClassName($targetEntity);
return strtolower($currentTableName . '_' . $targetTableName);
return strtolower($currentTableName . '_' . $targetTableName) . '_uuid';
}
private function resolveShortClassName(string $currentClass): string
@ -63,20 +47,4 @@ final class JoinTableNameResolver
return (string) Strings::after($currentClass, '\\', -1);
}
private function resolveTableNameFromClass(Class_ $class): string
{
$tableTagValueNode = $this->doctrineDocBlockResolver->getDoctrineTableTagValueNode($class);
if ($tableTagValueNode !== null) {
$tableName = $tableTagValueNode->getName();
if ($tableName !== null) {
return $tableName;
}
}
/** @var string $className */
$className = $class->getAttribute(AttributeKey::CLASS_NAME);
return $this->resolveShortClassName($className);
}
}

View File

@ -23,6 +23,7 @@ final class AddUuidMirrorForRelationPropertyRectorTest extends AbstractRectorTes
yield [__DIR__ . '/Fixture/to_one.php.inc'];
yield [__DIR__ . '/Fixture/to_many.php.inc'];
yield [__DIR__ . '/Fixture/skip_already_added.php.inc'];
yield [__DIR__ . '/Fixture/skip_to_many_without_target_entity_uuid.php.inc'];
}
protected function getRectorClass(): string

View File

@ -0,0 +1,31 @@
<?php
namespace Rector\Doctrine\Tests\Rector\Class_\AddUuidMirrorForRelationPropertyRector\Fixture;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="wohoo")
*/
class SkipTooManyWithoutTargetEntityUuid
{
/**
* @ORM\ManyToMany(targetEntity="Rector\Doctrine\Tests\Rector\Class_\AddUuidMirrorForRelationPropertyRector\Fixture\FooEntityWithoutUuid", cascade={"persist", "merge"})
*/
private $amenity;
}
/**
* @ORM\Entity
*/
class FooEntityWithoutUuid
{
/**
* @var int
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
}

View File

@ -28,6 +28,8 @@ class FooEntity
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
private $uuid;
}
?>
@ -50,7 +52,7 @@ class ToMany
private $amenity;
/**
* @ORM\ManyToMany(targetEntity="Rector\Doctrine\Tests\Rector\Class_\AddUuidMirrorForRelationPropertyRector\Fixture\FooEntity", cascade={"persist", "merge"})
* @ORM\JoinTable (name="wohoo_fooentity_uuid", joinColumns={@ORM\JoinColumn(referencedColumnName="uuid")}, inverseJoinColumns={@ORM\JoinColumn(referencedColumnName="uuid")})
* @ORM\JoinTable (name="tomany_fooentity_uuid", joinColumns={@ORM\JoinColumn(referencedColumnName="uuid")}, inverseJoinColumns={@ORM\JoinColumn(referencedColumnName="uuid")})
*/
private $amenityUuid;
}
@ -67,6 +69,8 @@ class FooEntity
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
private $uuid;
}
?>

View File

@ -28,6 +28,8 @@ class AnotherEntity
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
private $uuid;
}
?>
@ -67,6 +69,8 @@ class AnotherEntity
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
private $uuid;
}
?>

View File

@ -32,6 +32,8 @@ use Rector\RectorDefinition\RectorDefinition;
/**
* @see \Rector\PHPUnit\Tests\Rector\Class_\ArrayArgumentInTestToDataProviderRector\ArrayArgumentInTestToDataProviderRectorTest
*
* @see why https://blog.martinhujer.cz/how-to-use-data-providers-in-phpunit/
*/
final class ArrayArgumentInTestToDataProviderRector extends AbstractPHPUnitRector
{

View File

@ -10,6 +10,9 @@ parameters:
reportUnmatchedIgnoredErrors: false
level: max
autoload_directories:
- stubs
excludes_analyse:
# complex printer
- "packages/ContributorTools/src/Command/DumpNodesCommand.php"

View File

@ -2,6 +2,7 @@
namespace Rector\Application;
use Nette\Loaders\RobotLoader;
use PhpParser\Lexer;
use PhpParser\Node;
use Rector\Exception\ShouldNotHappenException;
@ -49,6 +50,11 @@ final class FileProcessor
*/
private $currentFileInfoProvider;
/**
* @var bool
*/
private $areStubsLoaded = false;
public function __construct(
FormatPerservingPrinter $formatPerservingPrinter,
Parser $parser,
@ -108,6 +114,8 @@ final class FileProcessor
public function refactor(SmartFileInfo $smartFileInfo): void
{
$this->loadStubs();
$this->makeSureFileIsParsed($smartFileInfo);
[$newStmts, $oldStmts, $oldTokens] = $this->tokensByFilePath[$smartFileInfo->getRealPath()];
@ -149,4 +157,24 @@ final class FileProcessor
self::class . '::parseFileInfoToLocalCache()'
));
}
/**
* Load stubs after composer autoload is loaded + rector "process <src>" is loaded,
* so it is loaded only if the classes are really missing
*/
private function loadStubs(): void
{
if ($this->areStubsLoaded) {
return;
}
$stubDirectory = __DIR__ . '/../../stubs';
$robotLoader = new RobotLoader();
$robotLoader->addDirectory($stubDirectory);
$robotLoader->setTempDirectory(sys_get_temp_dir() . '/rector_stubs');
$robotLoader->register();
$this->areStubsLoaded = true;
}
}

View File

@ -2,7 +2,7 @@
namespace Doctrine\ORM\Mapping;
if (interface_exists('Doctrine\ORM\Mapping\Column')) {
if (class_exists('Doctrine\ORM\Mapping\Column')) {
return;
}
@ -10,7 +10,7 @@ if (interface_exists('Doctrine\ORM\Mapping\Column')) {
* @Annotation
* @Target({"PROPERTY","ANNOTATION"})
*/
final class Column implements Annotation
class Column implements Annotation
{
/**
* @var string

View File

@ -2,7 +2,7 @@
namespace Doctrine\ORM\Mapping;
if (interface_exists('Doctrine\ORM\Mapping\Entity')) {
if (class_exists('Doctrine\ORM\Mapping\Entity')) {
return;
}
@ -10,7 +10,7 @@ if (interface_exists('Doctrine\ORM\Mapping\Entity')) {
* @Annotation
* @Target("CLASS")
*/
final class Entity implements Annotation
class Entity implements Annotation
{
/**
* @var string

View File

@ -2,7 +2,7 @@
namespace Doctrine\ORM\Mapping;
if (interface_exists('Doctrine\ORM\Mapping\Id')) {
if (class_exists('Doctrine\ORM\Mapping\Id')) {
return;
}
@ -10,6 +10,6 @@ if (interface_exists('Doctrine\ORM\Mapping\Id')) {
* @Annotation
* @Target("PROPERTY")
*/
final class Id implements Annotation
class Id implements Annotation
{
}

View File

@ -2,7 +2,7 @@
namespace Doctrine\ORM\Mapping;
if (interface_exists('Doctrine\ORM\Mapping\JoinColumn')) {
if (class_exists('Doctrine\ORM\Mapping\JoinColumn')) {
return;
}
@ -10,7 +10,7 @@ if (interface_exists('Doctrine\ORM\Mapping\JoinColumn')) {
* @Annotation
* @Target({"PROPERTY","ANNOTATION"})
*/
final class JoinColumn implements Annotation
class JoinColumn implements Annotation
{
/**
* @var string

View File

@ -2,7 +2,7 @@
namespace Doctrine\ORM\Mapping;
if (interface_exists('Doctrine\ORM\Mapping\JoinTable')) {
if (class_exists('Doctrine\ORM\Mapping\JoinTable')) {
return;
}
@ -10,7 +10,7 @@ if (interface_exists('Doctrine\ORM\Mapping\JoinTable')) {
* @Annotation
* @Target({"PROPERTY","ANNOTATION"})
*/
final class JoinTable implements Annotation
class JoinTable implements Annotation
{
/**
* @var string

View File

@ -2,7 +2,7 @@
namespace Doctrine\ORM\Mapping;
if (interface_exists('Doctrine\ORM\Mapping\ManyToMany')) {
if (class_exists('Doctrine\ORM\Mapping\ManyToMany')) {
return;
}
@ -10,7 +10,7 @@ if (interface_exists('Doctrine\ORM\Mapping\ManyToMany')) {
* @Annotation
* @Target("PROPERTY")
*/
final class ManyToMany implements Annotation
class ManyToMany implements Annotation
{
/**
* @var string

View File

@ -2,7 +2,7 @@
namespace Doctrine\ORM\Mapping;
if (interface_exists('Doctrine\ORM\Mapping\ManyToOne')) {
if (class_exists('Doctrine\ORM\Mapping\ManyToOne')) {
return;
}
@ -10,7 +10,7 @@ if (interface_exists('Doctrine\ORM\Mapping\ManyToOne')) {
* @Annotation
* @Target("PROPERTY")
*/
final class ManyToOne implements Annotation
class ManyToOne implements Annotation
{
/**
* @var string

View File

@ -2,7 +2,7 @@
namespace Doctrine\ORM\Mapping;
if (interface_exists('Doctrine\ORM\Mapping\OneToMany')) {
if (class_exists('Doctrine\ORM\Mapping\OneToMany')) {
return;
}
@ -10,7 +10,7 @@ if (interface_exists('Doctrine\ORM\Mapping\OneToMany')) {
* @Annotation
* @Target("PROPERTY")
*/
final class OneToMany implements Annotation
class OneToMany implements Annotation
{
/**
* @var string

View File

@ -2,7 +2,7 @@
namespace Doctrine\ORM\Mapping;
if (interface_exists('Doctrine\ORM\Mapping\OneToOne')) {
if (class_exists('Doctrine\ORM\Mapping\OneToOne')) {
return;
}
@ -10,7 +10,7 @@ if (interface_exists('Doctrine\ORM\Mapping\OneToOne')) {
* @Annotation
* @Target("PROPERTY")
*/
final class OneToOne implements Annotation
class OneToOne implements Annotation
{
/**
* @var string

View File

@ -2,7 +2,7 @@
namespace Doctrine\ORM\Mapping;
if (interface_exists('Doctrine\ORM\Mapping\Table')) {
if (class_exists('Doctrine\ORM\Mapping\Table')) {
return;
}
@ -10,7 +10,7 @@ if (interface_exists('Doctrine\ORM\Mapping\Table')) {
* @Annotation
* @Target("CLASS")
*/
final class Table implements Annotation
class Table implements Annotation
{
/**
* @var string