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
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,19 @@ release-by-release.

## [Unreleased]

### Fixed

- **`RemoveAliasManagerCacheMethodCallsRector`** — no longer removes calls to
`AliasManager::setCacheKey()` / `writeCache()` unconditionally, which broke
backward compatibility on Drupal < 11.3. These methods only became no-ops in
11.3.0 (when the path alias preload cache was replaced by a Fiber-based
bulk-lookup strategy); before 11.3.0 they performed real caching work. The
rector now extends `AbstractDrupalCoreRector` and, when BC support is enabled,
wraps the call in a `DeprecationHelper::backwardsCompatibleCall()` with a
no-op current callable so the caching still runs on Drupal < 11.3 and is
skipped on 11.3+. When BC support is disabled the call is removed as before.
Reported by Berdir ([#3600789](https://git.drupalcode.org/project/rector/-/work_items/3600789)).

### Added

- **`AddSymfonyConstraintValidatorTypeDeclarationsRector`** — adds the Symfony 8 / Drupal 12 type declarations (`mixed $value` and `: void` on `validate()`, `: void` on `initialize()`) to `Symfony\Component\Validator\ConstraintValidatorInterface` implementers. Backward compatible on all supported Drupal versions, so no version gate. [#3600790]
Expand Down
8 changes: 6 additions & 2 deletions config/drupal-11/drupal-11.3-deprecations.php
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,12 @@
// https://www.drupal.org/node/3496369
// https://www.drupal.org/node/3532412 (change record)
// AliasManager::setCacheKey() and AliasManager::writeCache() deprecated in drupal:11.3.0,
// removed in drupal:13.0.0 with no replacement (they are no-ops).
$rectorConfig->rule(RemoveAliasManagerCacheMethodCallsRector::class);
// removed in drupal:13.0.0 with no replacement. They only became no-ops in
// 11.3.0; before that they performed real caching work, so the call is
// wrapped in a backwards-compatible no-op when BC support is enabled.
$rectorConfig->ruleWithConfiguration(RemoveAliasManagerCacheMethodCallsRector::class, [
new DrupalIntroducedVersionConfiguration('11.3.0'),
]);

// https://www.drupal.org/node/3525388
// https://www.drupal.org/node/3525389 (change record)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,37 @@

namespace DrupalRector\Drupal11\Rector\Deprecation;

use DrupalRector\Contract\VersionedConfigurationInterface;
use DrupalRector\Rector\AbstractDrupalCoreRector;
use DrupalRector\Rector\ValueObject\DrupalIntroducedVersionConfiguration;
use PhpParser\Node;
use PhpParser\Node\Expr\ConstFetch;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt\Expression;
use PhpParser\NodeVisitor;
use PHPStan\Type\ObjectType;
use Rector\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

/**
* Removes calls to AliasManager::setCacheKey() and AliasManager::writeCache().
*
* Both methods are deprecated in drupal:11.3.0 and removed in drupal:13.0.0
* with no replacement. They became no-ops when the path alias preload cache
* was replaced by a Fiber-based bulk-lookup strategy, so callers can simply
* drop the call.
* with no replacement. They only became no-ops in 11.3.0, when the path alias
* preload cache was replaced by a Fiber-based bulk-lookup strategy; before
* 11.3.0 they performed real caching work. Removing the call outright is
* therefore only safe when the code no longer supports Drupal < 11.3.
*
* When backwards compatibility is enabled the call is wrapped in a
* DeprecationHelper::backwardsCompatibleCall() with a no-op current callable,
* so the caching still runs on Drupal < 11.3 and is skipped on 11.3+. When
* backwards compatibility is disabled the call is removed.
*
* @see https://www.drupal.org/node/3496369
* @see https://www.drupal.org/node/3532412
*/
class RemoveAliasManagerCacheMethodCallsRector extends AbstractRector
final class RemoveAliasManagerCacheMethodCallsRector extends AbstractDrupalCoreRector
{
public const PHPSTAN_MESSAGES = [
'Call to deprecated method setCacheKey() of class Drupal\path_alias\AliasManager. Deprecated in drupal:11.3.0 and is removed from drupal:13.0.0. There is no replacement.',
Expand All @@ -33,14 +43,31 @@ class RemoveAliasManagerCacheMethodCallsRector extends AbstractRector

private const TARGET_METHODS = ['setCacheKey', 'writeCache'];

/**
* @var array|DrupalIntroducedVersionConfiguration[]
*/
protected array $configuration = [];

public function configure(array $configuration): void
{
foreach ($configuration as $value) {
if (!$value instanceof DrupalIntroducedVersionConfiguration) {
throw new \InvalidArgumentException(sprintf('Each configuration item must be an instance of "%s"', DrupalIntroducedVersionConfiguration::class));
}
}

parent::configure($configuration);
}

public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition(
'Remove calls to AliasManager::setCacheKey() and AliasManager::writeCache(), deprecated in drupal:11.3.0 and removed in drupal:13.0.0 with no replacement.',
[
new CodeSample(
new ConfiguredCodeSample(
'$this->aliasManager->setCacheKey($path);',
''
'',
[new DrupalIntroducedVersionConfiguration('11.3.0')]
),
]
);
Expand All @@ -52,7 +79,7 @@ public function getNodeTypes(): array
return [Expression::class];
}

public function refactor(Node $node): ?int
public function refactorWithConfiguration(Node $node, VersionedConfigurationInterface $configuration): int|Node|null
{
assert($node instanceof Expression);
if (!$node->expr instanceof MethodCall) {
Expand All @@ -71,6 +98,17 @@ public function refactor(Node $node): ?int
return null;
}

// The shared createBcCallOnExpr() helper cannot be reached through the
// parent's Expr → Expr path here: the matched node is a whole statement
// and the "current" (11.3+) behaviour is to do nothing, which has no
// replacement expression. Build the wrapper ourselves, using a no-op
// current callable and the original call as the deprecated callable.
if ($this->supportBackwardsCompatibility($configuration)) {
$noOp = new ConstFetch(new Name('null'));

return new Expression($this->createBcCallOnExpr($methodCall, $noOp, $configuration));
}

return NodeVisitor::REMOVE_NODE;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace DrupalRector\Tests\Drupal11\Rector\Deprecation\RemoveAliasManagerCacheMethodCallsRector;

use DrupalRector\Services\DrupalRectorSettings;
use DrupalRector\Tests\AbstractDrupalRectorTestCase;

class BackwardsCompatibilityRemoveAliasManagerCacheMethodCallsRectorTest extends AbstractDrupalRectorTestCase
{
#[\PHPUnit\Framework\Attributes\DataProvider('provideData')]
public function test(string $filePath): void
{
// Backward compatibility enabled with a minimum supported core version
// below 11.3.0: the deprecated call is wrapped in a
// DeprecationHelper::backwardsCompatibleCall() with a no-op current
// callable.
static::getContainer()->make(DrupalRectorSettings::class)
->enableBackwardCompatibility()
->setMinimumCoreVersionSupported('10.1.0');
$this->doTestFile($filePath);
}

public static function provideData(): \Iterator
{
return self::yieldFilesFromDirectory(__DIR__.'/fixture-bc');
}

public function provideConfigFilePath(): string
{
return __DIR__.'/config/configured_rule_bc.php';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@

namespace DrupalRector\Tests\Drupal11\Rector\Deprecation\RemoveAliasManagerCacheMethodCallsRector;

use DrupalRector\Services\DrupalRectorSettings;
use DrupalRector\Tests\AbstractDrupalRectorTestCase;

class RemoveAliasManagerCacheMethodCallsRectorTest extends AbstractDrupalRectorTestCase
{
#[\PHPUnit\Framework\Attributes\DataProvider('provideData')]
public function test(string $filePath): void
{
// Backward compatibility disabled: the deprecated call is removed.
static::getContainer()->make(DrupalRectorSettings::class)->disableBackwardCompatibility();
$this->doTestFile($filePath);
}

Expand All @@ -19,6 +22,20 @@ public static function provideData(): \Iterator
return self::yieldFilesFromDirectory(__DIR__.'/fixture');
}

#[\PHPUnit\Framework\Attributes\DataProvider('provideDataBelowVersion')]
public function testBelowVersion(string $filePath): void
{
// Target Drupal is below the 11.3.0 deprecation: the rector must not
// fire, regardless of the backward-compatibility setting.
static::getContainer()->make(DrupalRectorSettings::class)->setDrupalVersion('11.2.0');
$this->doTestFile($filePath);
}

public static function provideDataBelowVersion(): \Iterator
{
return self::yieldFilesFromDirectory(__DIR__.'/fixture-below-version');
}

public function provideConfigFilePath(): string
{
return __DIR__.'/config/configured_rule.php';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
declare(strict_types=1);

use DrupalRector\Drupal11\Rector\Deprecation\RemoveAliasManagerCacheMethodCallsRector;
use DrupalRector\Rector\ValueObject\DrupalIntroducedVersionConfiguration;
use DrupalRector\Tests\Rector\Deprecation\DeprecationBase;
use Rector\Config\RectorConfig;

return static function (RectorConfig $rectorConfig): void {
DeprecationBase::addClass(RemoveAliasManagerCacheMethodCallsRector::class, $rectorConfig, false);
DeprecationBase::addClass(RemoveAliasManagerCacheMethodCallsRector::class, $rectorConfig, false, [
new DrupalIntroducedVersionConfiguration('11.3.0'),
]);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

use DrupalRector\Drupal11\Rector\Deprecation\RemoveAliasManagerCacheMethodCallsRector;
use DrupalRector\Rector\ValueObject\DrupalIntroducedVersionConfiguration;
use DrupalRector\Tests\Rector\Deprecation\DeprecationBase;
use Rector\Config\RectorConfig;

return static function (RectorConfig $rectorConfig): void {
DeprecationBase::addClass(RemoveAliasManagerCacheMethodCallsRector::class, $rectorConfig, false, [
new DrupalIntroducedVersionConfiguration('11.3.0'),
]);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

function someBasicCallSite(\Drupal\path_alias\AliasManagerInterface $aliasManager): void
{
$aliasManager->setCacheKey('/some/path');
$aliasManager->writeCache();
\Drupal::messenger()->addStatus('done');
}
?>
-----
<?php

function someBasicCallSite(\Drupal\path_alias\AliasManagerInterface $aliasManager): void
{
\Drupal\Component\Utility\DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '11.3.0', fn() => null, fn() => $aliasManager->setCacheKey('/some/path'));
\Drupal\Component\Utility\DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '11.3.0', fn() => null, fn() => $aliasManager->writeCache());
\Drupal::messenger()->addStatus('done');
}
?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

function someConcreteCallSite(\Drupal\path_alias\AliasManager $aliasManager): void
{
$aliasManager->setCacheKey('/some/path');
$aliasManager->writeCache();
\Drupal::messenger()->addStatus('done');
}
?>
-----
<?php

function someConcreteCallSite(\Drupal\path_alias\AliasManager $aliasManager): void
{
\Drupal\Component\Utility\DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '11.3.0', fn() => null, fn() => $aliasManager->setCacheKey('/some/path'));
\Drupal\Component\Utility\DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '11.3.0', fn() => null, fn() => $aliasManager->writeCache());
\Drupal::messenger()->addStatus('done');
}
?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

// Target Drupal is below 11.3.0: the methods are not yet deprecated and still
// perform real caching work, so the rector must not touch the call.
function belowVersionCallSite(\Drupal\path_alias\AliasManagerInterface $aliasManager): void
{
$aliasManager->setCacheKey('/some/path');
$aliasManager->writeCache();
}
?>
Loading