Skip to content

Commit

Permalink
[8.2] make AddAllowDynamicPropertiesAttributeRector configurable (#1391)
Browse files Browse the repository at this point in the history
  • Loading branch information
mallardduck committed Dec 10, 2021
1 parent fa31841 commit 6012e41
Show file tree
Hide file tree
Showing 15 changed files with 225 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace Rector\Tests\Transform\Rector\Class_\AddAllowDynamicPropertiesAttributeRector\Fixture;
namespace Rector\Tests\Transform\Rector\Class_\AddAllowDynamicPropertiesAttributeRector\Fixture\Process;

class WantsAttribute
{
Expand All @@ -11,7 +11,7 @@ class WantsAttribute
-----
<?php

namespace Rector\Tests\Transform\Rector\Class_\AddAllowDynamicPropertiesAttributeRector\Fixture;
namespace Rector\Tests\Transform\Rector\Class_\AddAllowDynamicPropertiesAttributeRector\Fixture\Process;

#[\AllowDynamicProperties]
class WantsAttribute
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace Rector\Tests\Transform\Rector\Class_\AddAllowDynamicPropertiesAttributeRector\Fixture;
namespace Rector\Tests\Transform\Rector\Class_\AddAllowDynamicPropertiesAttributeRector\Fixture\Process;

#[\Immutable]
class AppendAttribute
Expand All @@ -12,7 +12,7 @@ class AppendAttribute
-----
<?php

namespace Rector\Tests\Transform\Rector\Class_\AddAllowDynamicPropertiesAttributeRector\Fixture;
namespace Rector\Tests\Transform\Rector\Class_\AddAllowDynamicPropertiesAttributeRector\Fixture\Process;

#[\Immutable]
#[\AllowDynamicProperties]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace Rector\Tests\Transform\Rector\Class_\AddAllowDynamicPropertiesAttributeRector\Fixture;
namespace Rector\Tests\Transform\Rector\Class_\AddAllowDynamicPropertiesAttributeRector\Fixture\Process;

use stdClass;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace Rector\Tests\Transform\Rector\Class_\AddAllowDynamicPropertiesAttributeRector\Fixture;
namespace Rector\Tests\Transform\Rector\Class_\AddAllowDynamicPropertiesAttributeRector\Fixture\Process;

class MagicSetObjects
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace Rector\Tests\Transform\Rector\Class_\AddAllowDynamicPropertiesAttributeRector\Fixture;
namespace Rector\Tests\Transform\Rector\Class_\AddAllowDynamicPropertiesAttributeRector\Fixture\Process;

#[\AllowDynamicProperties]
class AlreadyHasAttribute
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Rector\Tests\Transform\Rector\Class_\AddAllowDynamicPropertiesAttributeRector\Fixture\Skip;

class DoesNothingOnExcludedClass
{
public string $someProperty = 'hello world';
}

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

namespace Rector\Tests\Transform\Rector\Class_\AddAllowDynamicPropertiesAttributeRector\FixtureAllClasses;

class WantsAttribute
{
public string $someProperty = 'hello world';
}

?>
-----
<?php

namespace Rector\Tests\Transform\Rector\Class_\AddAllowDynamicPropertiesAttributeRector\FixtureAllClasses;

#[\AllowDynamicProperties]
class WantsAttribute
{
public string $someProperty = 'hello world';
}

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

namespace Rector\Tests\Transform\Rector\Class_\AddAllowDynamicPropertiesAttributeRector\FixtureAllClasses;

#[\Immutable]
class AppendAttribute
{
public string $someProperty = 'hello world';
}

?>
-----
<?php

namespace Rector\Tests\Transform\Rector\Class_\AddAllowDynamicPropertiesAttributeRector\FixtureAllClasses;

#[\Immutable]
#[\AllowDynamicProperties]
class AppendAttribute
{
public string $someProperty = 'hello world';
}

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

namespace Rector\Tests\Transform\Rector\Class_\AddAllowDynamicPropertiesAttributeRector\FixtureAllClasses;

use stdClass;

class ChildOfStdClass extends stdClass
{
public string $someProperty = 'hello world';
}

class DescendantOfStdClass extends ChildOfStdClass
{
public string $someProperty = 'hello space';
}

class GrandChildOfStdClass extends ChildOfStdClass
{
public string $someProperty = 'hello universe';
}

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

namespace Rector\Tests\Transform\Rector\Class_\AddAllowDynamicPropertiesAttributeRector\FixtureAllClasses;

class MagicSetObjects
{
private array $props = [];

public function __set(string $name, $value) {
$this->props[$name] = $value;
}

public function __get(string $name) {
return $this->props[$name];
}
}

class AnotherMagicObject extends MagicSetObjects
{
public string $data = 'hello world';
}

class YetAnotherMagic extends AnotherMagicObject
{
public string $data = 'hello space';
}

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

namespace Rector\Tests\Transform\Rector\Class_\AddAllowDynamicPropertiesAttributeRector\FixtureAllClasses;

#[\AllowDynamicProperties]
class AlreadyHasAttribute
{
public string $someProperty = 'hello world';
}

class ChildOfAlreadyHasAttribute extends AlreadyHasAttribute {
public string $someProperty = 'hello space';
}

class GrandkidOfAlreadyHasAttribute extends ChildOfAlreadyHasAttribute {
public string $someProperty = 'hello universe';
}

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

declare(strict_types=1);

namespace Rector\Tests\Transform\Rector\Class_\AddAllowDynamicPropertiesAttributeRector;

use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;

final class UnconfiguredAddAllowDynamicPropertiesAttributeRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}

/**
* @return Iterator<SmartFileInfo>
*/
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/FixtureAllClasses');
}

public function provideConfigFilePath(): string
{
return __DIR__ . '/config/unconfigured_rule.php';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,10 @@

return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(AddAllowDynamicPropertiesAttributeRector::class);
$services->set(AddAllowDynamicPropertiesAttributeRector::class)
->configure(
[
'*\Fixture\Process\*'
]
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

use Rector\Transform\Rector\Class_\AddAllowDynamicPropertiesAttributeRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(AddAllowDynamicPropertiesAttributeRector::class);
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,37 @@
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\Class_;
use PHPStan\Reflection\ReflectionProvider;
use Rector\Core\Contract\Rector\AllowEmptyConfigurableRectorInterface;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\MethodName;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\FamilyTree\Reflection\FamilyRelationsAnalyzer;
use Rector\Php80\NodeAnalyzer\PhpAttributeAnalyzer;
use Rector\PhpAttribute\Printer\PhpAttributeGroupFactory;
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
use Webmozart\Assert\Assert;

/**
* @changelog https://wiki.php.net/rfc/deprecate_dynamic_properties
*
* @see \Rector\Tests\Transform\Rector\Class_\AddAllowDynamicPropertiesAttributeRector\AddAllowDynamicPropertiesAttributeRectorTest
*/
final class AddAllowDynamicPropertiesAttributeRector extends AbstractRector implements MinPhpVersionInterface
final class AddAllowDynamicPropertiesAttributeRector extends AbstractRector implements AllowEmptyConfigurableRectorInterface, MinPhpVersionInterface
{
/**
* @var string
*/
private const ATTRIBUTE = 'AllowDynamicProperties';

public const TRANSFORM_ON_NAMESPACES = 'transform_on_namespaces';

/**
* @var array<array-key, string>
*/
private array $transformOnNamespaces = [];

public function __construct(
private readonly FamilyRelationsAnalyzer $familyRelationsAnalyzer,
private readonly PhpAttributeAnalyzer $phpAttributeAnalyzer,
Expand All @@ -41,20 +50,27 @@ public function __construct(
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Add the `AllowDynamicProperties` attribute to all classes', [
new CodeSample(
new ConfiguredCodeSample(
<<<'CODE_SAMPLE'
namespace Example\Domain;
class SomeObject {
public string $someProperty = 'hello world';
}
CODE_SAMPLE

,
CODE_SAMPLE,
<<<'CODE_SAMPLE'
namespace Example\Domain;
#[AllowDynamicProperties]
class SomeObject {
public string $someProperty = 'hello world';
}
CODE_SAMPLE
CODE_SAMPLE,
[
AddAllowDynamicPropertiesAttributeRector::TRANSFORM_ON_NAMESPACES => [
'Example\*',
]
],
),
]);
}
Expand All @@ -67,6 +83,17 @@ public function getNodeTypes(): array
return [Class_::class];
}


public function configure(array $configuration): void
{
$transformOnNamespaces = $configuration[self::TRANSFORM_ON_NAMESPACES] ?? $configuration;

Assert::isArray($transformOnNamespaces);
Assert::allString($transformOnNamespaces);

$this->transformOnNamespaces = $transformOnNamespaces;
}

/**
* @param Class_ $node
*/
Expand Down Expand Up @@ -118,6 +145,15 @@ private function addAllowDynamicPropertiesAttribute(Class_ $class): Class_

private function shouldSkip(Class_ $class): bool
{
if (count($this->transformOnNamespaces) !== 0) {
$className = (string) $this->nodeNameResolver->getName($class);
foreach ($this->transformOnNamespaces as $transformOnNamespace) {
if (! $this->nodeNameResolver->isStringName($className, $transformOnNamespace)) {
return true;
}
}
}

if ($this->isDescendantOfStdclass($class)) {
return true;
}
Expand Down

0 comments on commit 6012e41

Please sign in to comment.