[Gedmo to Knp] Add Translatable Behavior Rector (#2503)

[Gedmo to Knp] Add Translatable Behavior Rector
This commit is contained in:
Tomas Votruba 2019-12-27 13:43:08 +01:00 committed by GitHub
commit f73f38fa01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 629 additions and 51 deletions

View File

@ -3,3 +3,4 @@ services:
Rector\DoctrineGedmoToKnplabs\Rector\Class_\TimestampableBehaviorRector: null
Rector\DoctrineGedmoToKnplabs\Rector\Class_\SluggableBehaviorRector: null
Rector\DoctrineGedmoToKnplabs\Rector\Class_\TreeBehaviorRector: ~
Rector\DoctrineGedmoToKnplabs\Rector\Class_\TranslationBehaviorRector: ~

View File

@ -220,6 +220,23 @@ final class PhpDocInfo
return null;
}
public function removeByType(string $type): void
{
$this->ensureTypeIsTagValueNode($type, __METHOD__);
foreach ($this->phpDocNode->children as $key => $phpDocChildNode) {
if (! $phpDocChildNode instanceof PhpDocTagNode) {
continue;
}
if (! is_a($phpDocChildNode->value, $type, true)) {
continue;
}
unset($this->phpDocNode->children[$key]);
}
}
private function getParamTagValueByName(string $name): ?AttributeAwareParamTagValueNode
{
$phpDocNode = $this->getPhpDocNode();

View File

@ -19,12 +19,15 @@ final class EntityTagValueNode extends AbstractDoctrineTagValueNode
private $repositoryClass;
/**
* @var bool
* @var bool|null
*/
private $readOnly = false;
private $readOnly;
public function __construct(?string $repositoryClass, bool $readOnly, ?string $originalContent)
{
public function __construct(
?string $repositoryClass = null,
?bool $readOnly = null,
?string $originalContent = null
) {
$this->repositoryClass = $repositoryClass;
$this->readOnly = $readOnly;
@ -39,7 +42,9 @@ final class EntityTagValueNode extends AbstractDoctrineTagValueNode
$contentItems['repositoryClass'] = sprintf('repositoryClass="%s"', $this->repositoryClass);
}
$contentItems['readOnly'] = sprintf('readOnly=%s', $this->readOnly ? 'true' : 'false');
if ($this->readOnly !== null) {
$contentItems['readOnly'] = sprintf('readOnly=%s', $this->readOnly ? 'true' : 'false');
}
return $this->printContentItems($contentItems);
}

View File

@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace Rector\BetterPhpDocParser\PhpDocNode\Gedmo;
use Gedmo\Mapping\Annotation\Locale;
use Rector\BetterPhpDocParser\PhpDocNode\AbstractTagValueNode;
final class LocaleTagValueNode extends AbstractTagValueNode
{
/**
* @var string
*/
public const CLASS_NAME = Locale::class;
public function __toString(): string
{
return '';
}
}

View File

@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace Rector\BetterPhpDocParser\PhpDocNode\Gedmo;
use Gedmo\Mapping\Annotation\Translatable;
use Rector\BetterPhpDocParser\PhpDocNode\AbstractTagValueNode;
final class TranslatableTagValueNode extends AbstractTagValueNode
{
/**
* @var string
*/
public const CLASS_NAME = Translatable::class;
public function __toString(): string
{
return '';
}
}

View File

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace Rector\BetterPhpDocParser\PhpDocNodeFactory\Gedmo;
use Gedmo\Mapping\Annotation\Locale;
use PhpParser\Node;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode;
use PHPStan\PhpDocParser\Parser\TokenIterator;
use Rector\BetterPhpDocParser\PhpDocNode\Gedmo\LocaleTagValueNode;
use Rector\BetterPhpDocParser\PhpDocNodeFactory\AbstractBasicPropertyPhpDocNodeFactory;
final class LocalePhpDocNodeFactory extends AbstractBasicPropertyPhpDocNodeFactory
{
public function getClass(): string
{
return Locale::class;
}
/**
* @return LocaleTagValueNode|null
*/
public function createFromNodeAndTokens(Node $node, TokenIterator $tokenIterator): ?PhpDocTagValueNode
{
return $this->createFromNode($node);
}
protected function getTagValueNodeClass(): string
{
return LocaleTagValueNode::class;
}
}

View File

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace Rector\BetterPhpDocParser\PhpDocNodeFactory\Gedmo;
use Gedmo\Mapping\Annotation\Translatable;
use PhpParser\Node;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode;
use PHPStan\PhpDocParser\Parser\TokenIterator;
use Rector\BetterPhpDocParser\PhpDocNode\Gedmo\TranslatableTagValueNode;
use Rector\BetterPhpDocParser\PhpDocNodeFactory\AbstractBasicPropertyPhpDocNodeFactory;
final class TranslatablePhpDocNodeFactory extends AbstractBasicPropertyPhpDocNodeFactory
{
public function getClass(): string
{
return Translatable::class;
}
/**
* @return TranslatableTagValueNode|null
*/
public function createFromNodeAndTokens(Node $node, TokenIterator $tokenIterator): ?PhpDocTagValueNode
{
return $this->createFromNode($node);
}
protected function getTagValueNodeClass(): string
{
return TranslatableTagValueNode::class;
}
}

View File

@ -12,7 +12,6 @@ use Rector\NodeContainer\ParsedNodesByType;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\PhpParser\Node\Manipulator\ClassManipulator;
use Rector\PhpParser\Node\Manipulator\ClassMethodManipulator;
use Rector\PhpParser\Printer\BetterStandardPrinter;
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;
@ -58,21 +57,14 @@ final class RemoveUnusedParameterRector extends AbstractRector
'__wakeup',
];
/**
* @var BetterStandardPrinter
*/
private $betterStandardPrinter;
public function __construct(
ClassManipulator $classManipulator,
ClassMethodManipulator $classMethodManipulator,
ParsedNodesByType $parsedNodesByType,
BetterStandardPrinter $betterStandardPrinter
ParsedNodesByType $parsedNodesByType
) {
$this->classManipulator = $classManipulator;
$this->classMethodManipulator = $classMethodManipulator;
$this->parsedNodesByType = $parsedNodesByType;
$this->betterStandardPrinter = $betterStandardPrinter;
}
public function getDefinition(): RectorDefinition
@ -187,7 +179,7 @@ PHP
$parameters1,
$parameters2,
function (Param $a, Param $b): int {
return $this->betterStandardPrinter->areNodesEqual($a, $b) ? 0 : 1;
return $this->areNodesEqual($a, $b) ? 0 : 1;
}
);
}

View File

@ -10,6 +10,7 @@ use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use Ramsey\Uuid\UuidInterface;
use Rector\BetterPhpDocParser\Attributes\Ast\PhpDoc\SpacelessPhpDocTagNode;
use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\Class_\EntityTagValueNode;
use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\Property_\ColumnTagValueNode;
use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\Property_\GeneratedValueTagValueNode;
use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\Property_\IdTagValueNode;
@ -49,6 +50,11 @@ final class PhpDocTagNodeFactory
return new SpacelessPhpDocTagNode(IdTagValueNode::SHORT_NAME, new IdTagValueNode());
}
public function createEntityTag(): PhpDocTagNode
{
return new SpacelessPhpDocTagNode(EntityTagValueNode::SHORT_NAME, new EntityTagValueNode());
}
public function createIdColumnTag(): PhpDocTagNode
{
$columnTagValueNode = new ColumnTagValueNode(null, 'integer', null, null, null, null, null);

View File

@ -0,0 +1,273 @@
<?php
declare(strict_types=1);
namespace Rector\DoctrineGedmoToKnplabs\Rector\Class_;
use Nette\Utils\FileSystem;
use PhpParser\Node;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Namespace_;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\BetterPhpDocParser\PhpDocNode\Gedmo\LocaleTagValueNode;
use Rector\BetterPhpDocParser\PhpDocNode\Gedmo\TranslatableTagValueNode;
use Rector\Doctrine\PhpDocParser\Ast\PhpDoc\PhpDocTagNodeFactory;
use Rector\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\PhpParser\Node\Manipulator\ClassManipulator;
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;
use Symplify\SmartFileSystem\SmartFileInfo;
/**
* @see https://lab.axioma.lv/symfony2/pagebundle/commit/062f9f87add5740ea89072e376dd703f3188d2ce
*
* @see \Rector\DoctrineGedmoToKnplabs\Tests\Rector\Class_\TranslationBehaviorRector\TranslationBehaviorRectorTest
*/
final class TranslationBehaviorRector extends AbstractRector
{
/**
* @var ClassManipulator
*/
private $classManipulator;
/**
* @var PhpDocTagNodeFactory
*/
private $phpDocTagNodeFactory;
public function __construct(ClassManipulator $classManipulator, PhpDocTagNodeFactory $phpDocTagNodeFactory)
{
$this->classManipulator = $classManipulator;
$this->phpDocTagNodeFactory = $phpDocTagNodeFactory;
}
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Change Translation from gedmo/doctrine-extensions to knplabs/doctrine-behaviors', [
new CodeSample(
<<<'PHP'
use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Translatable\Translatable;
/**
* @ORM\Table
*/
class Article implements Translatable
{
/**
* @Gedmo\Translatable
* @ORM\Column(length=128)
*/
private $title;
/**
* @Gedmo\Translatable
* @ORM\Column(type="text")
*/
private $content;
/**
* @Gedmo\Locale
* Used locale to override Translation listener`s locale
* this is not a mapped field of entity metadata, just a simple property
* and it is not necessary because globally locale can be set in listener
*/
private $locale;
public function setTitle($title)
{
$this->title = $title;
}
public function getTitle()
{
return $this->title;
}
public function setContent($content)
{
$this->content = $content;
}
public function getContent()
{
return $this->content;
}
public function setTranslatableLocale($locale)
{
$this->locale = $locale;
}
}
PHP
,
<<<'PHP'
use Knp\DoctrineBehaviors\Model\Translatable\TranslatableTrait;
use Knp\DoctrineBehaviors\Contract\Entity\TranslatableInterface;
class SomeClass implements TranslatableInterface
{
use TranslatableTrait;
}
use Knp\DoctrineBehaviors\Contract\Entity\TranslationInterface;
use Knp\DoctrineBehaviors\Model\Translatable\TranslationTrait;
class SomeClassTranslation implements TranslationInterface
{
use TranslationTrait;
/**
* @ORM\Column(length=128)
*/
private $title;
/**
* @ORM\Column(type="text")
*/
private $content;
}
PHP
),
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [Class_::class];
}
/**
* @param Class_ $node
*/
public function refactor(Node $node): ?Node
{
if (! $this->classManipulator->hasInterface($node, 'Gedmo\Translatable\Translatable')) {
return null;
}
$this->classManipulator->removeInterface($node, 'Gedmo\Translatable\Translatable');
// 1. replace trait
$this->classManipulator->addAsFirstTrait($node, 'Knp\DoctrineBehaviors\Model\Translatable\TranslatableTrait');
// 2. add interface
$node->implements[] = new FullyQualified('Knp\DoctrineBehaviors\Contract\Entity\TranslatableInterface');
$removedPropertyNameToPhpDocInfo = $this->collectAndRemoveTranslatableProperties($node);
$removePropertyNames = array_keys($removedPropertyNameToPhpDocInfo);
// @todo add them as a @method annotation, so the autocomplete still works?
$this->removeSetAndGetMethods($node, $removePropertyNames);
$this->dumpEntityTranslation($node, $removedPropertyNameToPhpDocInfo);
return $node;
}
/**
* @param string[] $removedPropertyNames
*/
private function removeSetAndGetMethods(Class_ $class, array $removedPropertyNames): void
{
foreach ($removedPropertyNames as $removedPropertyName) {
foreach ($class->getMethods() as $method) {
if ($this->isName($method, 'set' . ucfirst($removedPropertyName))) {
$this->removeNode($method);
}
if ($this->isName($method, 'get' . ucfirst($removedPropertyName))) {
$this->removeNode($method);
}
if ($this->isName($method, 'setTranslatableLocale')) {
$this->removeNode($method);
}
}
}
}
/**
* @return PhpDocInfo[]
*/
private function collectAndRemoveTranslatableProperties(Class_ $class): array
{
$removedPropertyNameToPhpDocInfo = [];
foreach ($class->getProperties() as $property) {
$propertyPhpDocInfo = $this->getPhpDocInfo($property);
if ($propertyPhpDocInfo === null) {
continue;
}
if ($propertyPhpDocInfo->getByType(LocaleTagValueNode::class)) {
$this->removeNode($property);
continue;
}
if (! $propertyPhpDocInfo->getByType(TranslatableTagValueNode::class)) {
continue;
}
$propertyPhpDocInfo->removeByType(TranslatableTagValueNode::class);
$propertyName = $this->getName($property);
$removedPropertyNameToPhpDocInfo[$propertyName] = $propertyPhpDocInfo;
$this->removeNode($property);
}
return $removedPropertyNameToPhpDocInfo;
}
/**
* @param PhpDocInfo[] $translatedPropertyToPhpDocInfos
*/
private function dumpEntityTranslation(Class_ $class, array $translatedPropertyToPhpDocInfos): void
{
/** @var SmartFileInfo|null $fileInfo */
$fileInfo = $class->getAttribute(AttributeKey::FILE_INFO);
if ($fileInfo === null) {
throw new ShouldNotHappenException();
}
$classShortName = (string) $class->name . 'Translation';
$filePath = dirname($fileInfo->getRealPath()) . DIRECTORY_SEPARATOR . $classShortName . '.php';
$namespace = $class->getAttribute(AttributeKey::PARENT_NODE);
if (! $namespace instanceof Namespace_) {
throw new ShouldNotHappenException();
}
$namespace = new Namespace_($namespace->name);
$class = new Class_($classShortName);
$class->implements[] = new FullyQualified('Knp\DoctrineBehaviors\Contract\Entity\TranslationInterface');
$this->classManipulator->addAsFirstTrait($class, 'Knp\DoctrineBehaviors\Model\Translatable\TranslationTrait');
$this->docBlockManipulator->addTag($class, $this->phpDocTagNodeFactory->createEntityTag());
foreach ($translatedPropertyToPhpDocInfos as $translatedPropertyName => $translatedPhpDocInfo) {
$property = $this->nodeFactory->createPrivateProperty($translatedPropertyName);
$this->docBlockManipulator->updateNodeWithPhpDocInfo($property, $translatedPhpDocInfo);
$class->stmts[] = $property;
}
$namespace->stmts[] = $class;
// @todo make temporary
$content = '<?php' . PHP_EOL . $this->print($namespace) . PHP_EOL;
FileSystem::write($filePath, $content);
}
}

View File

@ -0,0 +1,78 @@
<?php
namespace Rector\DoctrineGedmoToKnplabs\Tests\Rector\Class_\TranslationBehaviorRector\Fixture;
use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Translatable\Translatable;
/**
* @ORM\Table
*/
class SomeClass implements Translatable
{
/**
* @Gedmo\Translatable
* @ORM\Column(length=128)
*/
private $title;
/**
* @Gedmo\Translatable
* @ORM\Column(type="text")
*/
private $content;
/**
* @Gedmo\Locale
* Used locale to override Translation listener`s locale
* this is not a mapped field of entity metadata, just a simple property
* and it is not necessary because globally locale can be set in listener
*/
private $locale;
public function setTitle($title)
{
$this->title = $title;
}
public function getTitle()
{
return $this->title;
}
public function setContent($content)
{
$this->content = $content;
}
public function getContent()
{
return $this->content;
}
public function setTranslatableLocale($locale)
{
$this->locale = $locale;
}
}
?>
-----
<?php
namespace Rector\DoctrineGedmoToKnplabs\Tests\Rector\Class_\TranslationBehaviorRector\Fixture;
use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Translatable\Translatable;
/**
* @ORM\Table
*/
class SomeClass implements \Knp\DoctrineBehaviors\Contract\Entity\TranslatableInterface
{
use \Knp\DoctrineBehaviors\Model\Translatable\TranslatableTrait;
}
?>

View File

@ -0,0 +1,18 @@
<?php
namespace Rector\DoctrineGedmoToKnplabs\Tests\Rector\Class_\TranslationBehaviorRector\Fixture;
/**
* @ORM\Entity
*/
class SomeClassTranslation implements \Knp\DoctrineBehaviors\Contract\Entity\TranslationInterface
{
use \Knp\DoctrineBehaviors\Model\Translatable\TranslationTrait;
/**
* @ORM\Column(length=128)
*/
private $title;
/**
* @ORM\Column(type="text")
*/
private $content;
}

View File

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace Rector\DoctrineGedmoToKnplabs\Tests\Rector\Class_\TranslationBehaviorRector;
use Nette\Utils\FileSystem;
use Rector\DoctrineGedmoToKnplabs\Rector\Class_\TranslationBehaviorRector;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
final class TranslationBehaviorRectorTest extends AbstractRectorTestCase
{
protected function tearDown(): void
{
// remove generated file
FileSystem::delete(__DIR__ . '/Fixture/SomeClassTranslation.php');
}
public function test(): void
{
$this->doTestFile(__DIR__ . '/Fixture/fixture.php.inc');
$generatedFile = sys_get_temp_dir() . '/rector_temp_tests/SomeClassTranslation.php';
$this->assertFileExists($generatedFile);
$this->assertFileEquals(__DIR__ . '/Source/ExpectedSomeClassTranslation.php', $generatedFile);
}
protected function getRectorClass(): string
{
return TranslationBehaviorRector::class;
}
}

View File

@ -28,7 +28,6 @@ use PhpParser\Node\Stmt\Namespace_;
use Rector\CodingStyle\Naming\ClassNaming;
use Rector\NetteToSymfony\Collector\CollectOnFormVariableMethodCallsCollector;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\PhpParser\Printer\BetterStandardPrinter;
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;
@ -54,19 +53,12 @@ final class FormControlToControllerAndFormTypeRector extends AbstractRector
*/
private $classNaming;
/**
* @var BetterStandardPrinter
*/
private $betterStandardPrinter;
public function __construct(
CollectOnFormVariableMethodCallsCollector $collectOnFormVariableMethodCallsCollector,
ClassNaming $classNaming,
BetterStandardPrinter $betterStandardPrinter
ClassNaming $classNaming
) {
$this->collectOnFormVariableMethodCallsCollector = $collectOnFormVariableMethodCallsCollector;
$this->classNaming = $classNaming;
$this->betterStandardPrinter = $betterStandardPrinter;
}
public function getDefinition(): RectorDefinition
@ -269,7 +261,7 @@ PHP
$filePath = dirname($fileInfo->getRealPath()) . DIRECTORY_SEPARATOR . 'SomeFormController.php';
// @todo make temporary
$content = '<?php' . PHP_EOL . $this->betterStandardPrinter->print([$namespace]) . PHP_EOL;
$content = '<?php' . PHP_EOL . $this->print([$namespace]) . PHP_EOL;
FileSystem::write($filePath, $content);
}

View File

@ -4,18 +4,14 @@ declare(strict_types=1);
namespace Rector\NetteToSymfony\Tests\Rector\Assign\FormControlToControllerAndFormTypeRector;
use Iterator;
use Rector\NetteToSymfony\Rector\Assign\FormControlToControllerAndFormTypeRector;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
final class FormControlToControllerAndFormTypeRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideDataForTest()
*/
public function test(string $file): void
public function test(): void
{
$this->doTestFile($file);
$this->doTestFile(__DIR__ . '/Fixture/fixture.php.inc');
$controllerFilePath = sys_get_temp_dir() . '/rector_temp_tests/SomeFormController.php';
$this->assertFileExists($controllerFilePath);
@ -23,11 +19,6 @@ final class FormControlToControllerAndFormTypeRectorTest extends AbstractRectorT
$this->assertFileEquals(__DIR__ . '/Source/SomeFormController.php', $controllerFilePath);
}
public function provideDataForTest(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
protected function getRectorClass(): string
{
return FormControlToControllerAndFormTypeRector::class;

View File

@ -479,15 +479,10 @@ final class DocBlockManipulator
PhpDocInfo $phpDocInfo,
bool $shouldSkipEmptyLinesAbove = false
): bool {
// skip if has no doc comment
if ($node->getDocComment() === null) {
return false;
}
$phpDoc = $this->phpDocInfoPrinter->printFormatPreserving($phpDocInfo, $shouldSkipEmptyLinesAbove);
if ($phpDoc !== '') {
// no change, don't save it
if ($node->getDocComment()->getText() === $phpDoc) {
if ($node->getDocComment() && $node->getDocComment()->getText() === $phpDoc) {
return false;
}

View File

@ -440,6 +440,30 @@ final class ClassManipulator
return [];
}
public function hasInterface(Class_ $class, string $desiredInterface): bool
{
foreach ($class->implements as $implement) {
if (! $this->nameResolver->isName($implement, $desiredInterface)) {
continue;
}
return true;
}
return false;
}
public function removeInterface(Class_ $class, string $desiredInterface): void
{
foreach ($class->implements as $implement) {
if (! $this->nameResolver->isName($implement, $desiredInterface)) {
continue;
}
$this->nodeRemovingCommander->addNode($implement);
}
}
private function tryInsertBeforeFirstMethod(Class_ $classNode, Stmt $stmt): bool
{
foreach ($classNode->stmts as $key => $classStmt) {

View File

@ -228,10 +228,12 @@ final class NodeFactory
);
}
public function createPrivateProperty(string $name): Property
public function createStaticProtectedPropertyWithDefault(string $name, Node $node): Property
{
$propertyBuilder = $this->builderFactory->property($name);
$propertyBuilder->makePrivate();
$propertyBuilder->makeProtected();
$propertyBuilder->makeStatic();
$propertyBuilder->setDefault($node);
$property = $propertyBuilder->getNode();
@ -240,12 +242,10 @@ final class NodeFactory
return $property;
}
public function createStaticProtectedPropertyWithDefault(string $name, Node $node): Property
public function createPrivateProperty(string $name): Property
{
$propertyBuilder = $this->builderFactory->property($name);
$propertyBuilder->makeProtected();
$propertyBuilder->makeStatic();
$propertyBuilder->setDefault($node);
$propertyBuilder->makePrivate();
$property = $propertyBuilder->getNode();

View File

@ -22,7 +22,7 @@ trait BetterStandardPrinterTrait
/**
* @var BetterStandardPrinter
*/
private $betterStandardPrinter;
protected $betterStandardPrinter;
/**
* @required

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace Gedmo\Mapping\Annotation;
if (class_exists('Gedmo\Mapping\Annotation\Locale')) {
return;
}
/**
* @Annotation
*/
class Locale
{
}

View File

@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace Gedmo\Mapping\Annotation;
if (class_exists('Gedmo\Mapping\Annotation\Translatable')) {
return;
}
/**
* @Annotation
*/
class Translatable
{
/** @var boolean */
public $fallback;
}

View File

@ -1,9 +1,8 @@
<?php declare(strict_types=1);
namespace Gedmo\Timestampable\Traits;
if (class_exists('Gedmo\Timestampable\Traits\TimestampableEntity')) {
if (trait_exists('Gedmo\Timestampable\Traits\TimestampableEntity')) {
return;
}

View File

@ -0,0 +1,12 @@
<?php declare(strict_types=1);
namespace Gedmo\Translatable;
if (interface_exists('Gedmo\Translatable\Translatable')) {
return;
}
interface Translatable
{
}