rector/rules/symfony5/src/Rector/MethodCall/ReflectionExtractorEnableMagicCallExtractorRector.php
Tomas Votruba a8a0030bf9
Move package to 1st position in recipe (#4882)
* add alias

* [recipe] enable set by default, most contributors are core

* move package to 1st place, close to rule name where we think about package

* [ci-review] Rector Rectify

* fix recipe test

Co-authored-by: rector-bot <tomas@getrector.org>
2020-12-14 16:24:33 +00:00

182 lines
5.1 KiB
PHP

<?php
declare(strict_types=1);
namespace Rector\Symfony5\Rector\MethodCall;
use PhpParser\Node;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ArrayItem;
use PhpParser\Node\Expr\BinaryOp\BitwiseOr;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Scalar\String_;
use Rector\Core\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* @see https://github.com/symfony/symfony/blob/5.x/UPGRADE-5.2.md#propertyinfo
* @see \Rector\Symfony5\Tests\Rector\MethodCall\ReflectionExtractorEnableMagicCallExtractorRector\ReflectionExtractorEnableMagicCallExtractorRectorTest
*/
final class ReflectionExtractorEnableMagicCallExtractorRector extends AbstractRector
{
/**
* @var string
*/
private const OLD_OPTION_NAME = 'enable_magic_call_extraction';
/**
* @var string
*/
private const NEW_OPTION_NAME = 'enable_magic_methods_extraction';
/**
* @var string[]
*/
private const METHODS_WITH_OPTION = ['getWriteInfo', 'getReadInfo'];
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition(
'Migrates from deprecated enable_magic_call_extraction context option in ReflectionExtractor',
[
new CodeSample(
<<<'CODE_SAMPLE'
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
class SomeClass
{
public function run()
{
$reflectionExtractor = new ReflectionExtractor();
$readInfo = $reflectionExtractor->getReadInfo(Dummy::class, 'bar', [
'enable_magic_call_extraction' => true,
]);
}
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
class SomeClass
{
public function run()
{
$reflectionExtractor = new ReflectionExtractor();
$readInfo = $reflectionExtractor->getReadInfo(Dummy::class, 'bar', [
'enable_magic_methods_extraction' => ReflectionExtractor::MAGIC_CALL | ReflectionExtractor::MAGIC_GET | ReflectionExtractor::MAGIC_SET,
]);
}
}
CODE_SAMPLE
),
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [MethodCall::class];
}
/**
* @param MethodCall $node
*/
public function refactor(Node $node): ?Node
{
if ($this->shouldSkip($node)) {
return null;
}
$contextOptionValue = $this->getContextOptionValue($node);
if ($contextOptionValue === null) {
return null;
}
/** @var Array_ $contextOptions */
$contextOptions = $node->args[2]->value;
$contextOptions->items[] = new ArrayItem(
$this->prepareEnableMagicMethodsExtractionFlags($contextOptionValue),
new String_(self::NEW_OPTION_NAME),
);
return $node;
}
private function shouldSkip(MethodCall $methodCall): bool
{
if (! $this->isObjectType($methodCall, 'Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor')) {
return true;
}
if (! $this->isNames($methodCall->name, self::METHODS_WITH_OPTION)) {
return true;
}
if (count((array) $methodCall->args) < 3) {
return true;
}
/** @var Array_ $contextOptions */
$contextOptions = $methodCall->args[2]->value;
return $contextOptions->items === [];
}
private function getContextOptionValue(MethodCall $methodCall): ?bool
{
/** @var Array_ $contextOptions */
$contextOptions = $methodCall->args[2]->value;
$contextOptionValue = null;
/** @var ArrayItem $arrayItem */
foreach ($contextOptions->items as $index => $arrayItem) {
if ($arrayItem === null) {
continue;
}
if (! $arrayItem->key instanceof String_) {
continue;
}
if ($arrayItem->key->value !== self::OLD_OPTION_NAME) {
continue;
}
$contextOptionValue = $this->isTrue($arrayItem->value);
unset($contextOptions->items[$index]);
}
return $contextOptionValue;
}
private function prepareEnableMagicMethodsExtractionFlags(bool $enableMagicCallExtractionValue): BitwiseOr
{
$classConstFetch = $this->createClassConstFetch(
'Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor',
'MAGIC_GET'
);
$magicSet = $this->createClassConstFetch(
'Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor',
'MAGIC_SET'
);
if (! $enableMagicCallExtractionValue) {
return new BitwiseOr($classConstFetch, $magicSet);
}
return new BitwiseOr(
new BitwiseOr(
$this->createClassConstFetch(
'Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor',
'MAGIC_CALL'
),
$classConstFetch,
),
$magicSet,
);
}
}