Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ services:
Rector\Rector\Architecture\RepositoryAsService\ReplaceParentRepositoryCallsByRepositoryPropertyRector: ~
Rector\Rector\Architecture\RepositoryAsService\MoveRepositoryFromParentToConstructorRector: ~
Rector\Rector\Architecture\RepositoryAsService\ServiceLocatorToDIRector: ~
Rector\Architecture\Rector\Class_\RemoveRepositoryFromEntityAnnotationRector: ~
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<?php declare(strict_types=1);

namespace Rector\Architecture\Rector\Class_;

use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PHPStan\PhpDocParser\Ast\PhpDoc\GenericTagValueNode;
use Rector\Architecture\Tests\Rector\Class_\RemoveRepositoryFromEntityAnnotationRector\RemoveRepositoryFromEntityAnnotationRectorTest;
use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockManipulator;
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;

/**
* @see RemoveRepositoryFromEntityAnnotationRectorTest
*/
final class RemoveRepositoryFromEntityAnnotationRector extends AbstractRector
{
/**
* @var string
*/
private const DOCTRINE_ORM_MAPPING_ENTITY = 'Doctrine\ORM\Mapping\Entity';

/**
* @var DocBlockManipulator
*/
private $docBlockManipulator;

public function __construct(DocBlockManipulator $docBlockManipulator)
{
$this->docBlockManipulator = $docBlockManipulator;
}

public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Removes repository class from @Entity annotation', [
new CodeSample(
<<<'CODE_SAMPLE'
use Doctrine\ORM\Mapping as ORM;

/**
* @ORM\Entity(repositoryClass="ProductRepository")
*/
class Product
{
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
use Doctrine\ORM\Mapping as ORM;

/**
* @ORM\Entity
*/
class Product
{
}
CODE_SAMPLE
),
]);
}

/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [Class_::class];
}

/**
* @param Node\Stmt\Class_ $node
*/
public function refactor(Node $node): ?Node
{
if ($node->getDocComment() === null) {
return null;
}

$phpDocInfo = $this->docBlockManipulator->createPhpDocInfoFromNode($node);
if (! $phpDocInfo->hasTag(self::DOCTRINE_ORM_MAPPING_ENTITY)) {
return null;
}

$entityTags = $phpDocInfo->getTagsByName(self::DOCTRINE_ORM_MAPPING_ENTITY);
if ($entityTags === []) {
return null;
}

$entityTag = $entityTags[0];
if (! $entityTag->value instanceof GenericTagValueNode) {
return null;
}

$entityTag->value->value = Strings::replace($entityTag->value->value, '#\(repositoryClass="(.*?)"\)#');

// save the entity tag
$this->docBlockManipulator->updateNodeWithPhpDocInfo($node, $phpDocInfo);

return $node;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace Rector\Architecture\Tests\Rector\Class_\RemoveRepositoryFromEntityAnnotationRector\Fixture;

use Doctrine\ORM\Mapping as ORM;

/**
* @ORM\Entity(repositoryClass="ProductRepository")
*/
class Product
{
}

?>
-----
<?php

namespace Rector\Architecture\Tests\Rector\Class_\RemoveRepositoryFromEntityAnnotationRector\Fixture;

use Doctrine\ORM\Mapping as ORM;

/**
* @ORM\Entity
*/
class Product
{
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

namespace Rector\Architecture\Tests\Rector\Class_\RemoveRepositoryFromEntityAnnotationRector\Fixture;

use Doctrine\ORM\Mapping as ORM;

/**
* @ORM\Entity
*/
class SkipDone
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php declare(strict_types=1);

namespace Rector\Architecture\Tests\Rector\Class_\RemoveRepositoryFromEntityAnnotationRector;

use Rector\Architecture\Rector\Class_\RemoveRepositoryFromEntityAnnotationRector;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

final class RemoveRepositoryFromEntityAnnotationRectorTest extends AbstractRectorTestCase
{
public function test(): void
{
$this->doTestFiles([
__DIR__ . '/Fixture/fixture.php.inc',
__DIR__ . '/Fixture/skip_done.php.inc',
]);
}

protected function getRectorClass(): string
{
return RemoveRepositoryFromEntityAnnotationRector::class;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,18 @@ public function updateNodeWithPhpDocInfo(Node $node, PhpDocInfo $phpDocInfo): bo
return true;
}

public function createPhpDocInfoFromNode(Node $node): PhpDocInfo
{
if ($node->getDocComment() === null) {
throw new ShouldNotHappenException(sprintf(
'Node must have a comment. Check `$node->getDocComment() !== null` before passing it to %s',
__METHOD__
));
}

return $this->phpDocInfoFactory->createFromNode($node);
}

private function addTypeSpecificTag(Node $node, string $name, string $type): void
{
// there might be no phpdoc at all
Expand All @@ -553,18 +565,6 @@ private function addTypeSpecificTag(Node $node, string $name, string $type): voi
}
}

private function createPhpDocInfoFromNode(Node $node): PhpDocInfo
{
if ($node->getDocComment() === null) {
throw new ShouldNotHappenException(sprintf(
'Node must have a comment. Check `$node->getDocComment() !== null` before passing it to %s',
__METHOD__
));
}

return $this->phpDocInfoFactory->createFromNode($node);
}

private function isTagValueNodeWithType(PhpDocTagNode $phpDocTagNode): bool
{
return $phpDocTagNode->value instanceof ParamTagValueNode ||
Expand Down