diff --git a/.claude/skills/rector-live-test/SKILL.md b/.claude/skills/rector-live-test/SKILL.md index fce351163..8a4ac94fb 100644 --- a/.claude/skills/rector-live-test/SKILL.md +++ b/.claude/skills/rector-live-test/SKILL.md @@ -183,7 +183,81 @@ git -C ~/projects/drupal-rector-test checkout -- web/modules/contrib/ rm ~/projects/drupal-rector-test/rector-live-test.php ``` -### 5. Report results +### 5. Capture the PHPStan deprecation message + +While the contrib module is still installed and the pre-transform code is on +disk, run PHPStan against the file the rector matched and capture the +deprecation message PHPStan emits for the targeted symbol. This is the literal +string the rector "covers", and is what upgrade_status's +`DeprecationAnalyzer::isRectorCovered()` does an exact string match against +(after a small set of normalizations — see below). + +```bash +cd ~/projects/drupal-rector-test +ddev exec vendor/bin/phpstan analyse \ + web/modules/contrib//.php \ + --level=max --no-progress --error-format=raw 2>&1 \ + | grep -i "deprecated.*" +``` + +If no contrib file matched (or the symbol is already fully removed from +installed core so PHPStan emits "not found" rather than a deprecation), fall +back to a synthetic probe — see the `rector-extract-phpstan-error` skill's +"Synthetic probe" section for templates. + +**Normalize and store.** Pipe the raw message through the normalizer (which +applies the three transforms upgrade_status applies before its `in_array()` +lookup — whitespace collapse, `: in` → `. Deprecated in`, leading `\Drupal` +strip): + +```bash +ddev exec php scripts/normalize-phpstan-message.php "" +# or: +printf '' | ddev exec php scripts/normalize-phpstan-message.php +``` + +Add the normalized string to the rector source: + +- **Custom rector class** (`src/Drupal*/Rector/Deprecation/.php`) + — add or extend the `public const PHPSTAN_MESSAGES` array. One element per + distinct call shape the rector handles. + + ```php + public const PHPSTAN_MESSAGES = [ + 'Call to deprecated method foo() of class Drupal\Bar. Deprecated in drupal:11.4.0 ...', + ]; + ``` + +- **Config-only registration** (`config/drupal-*/drupal-*.N-deprecations.php`) + — add a `// PHPSTAN_MESSAGES :` comment block immediately + above the `ruleWithConfiguration(...)` call, one message per `//` line: + + ```php + // PHPSTAN_MESSAGES FunctionToServiceRector: + // Call to deprecated function foo(). Deprecated in drupal:11.4.0 and is removed from drupal:12.0.0. Use Drupal\Bar::baz() instead. + $rectorConfig->ruleWithConfiguration(FunctionToServiceRector::class, [ /* ... */ ]); + ``` + +Then regenerate the flat registry: + +```bash +ddev exec php scripts/generate-coverage-registry.php +``` + +This writes `config/coverage-registry.php` (a `return [...]` file mapping +rector short name → list of normalized messages). The registry is the +artifact a future upgrade_status PR will consume to replace its hardcoded +`$rector_covered` array. + +If PHPStan emits no deprecation for the symbol — symbol present but not +annotated `@deprecated`, or already fully removed — record a `TODO +PHPSTAN_MESSAGES :` comment with the reason instead of +guessing the message text. Do **not** synthesize the string from the +`@deprecated` docblock by hand: PHPStan's exact wording differs between +"Call to deprecated method", "Instantiation of deprecated class", "Class X +implements deprecated interface", etc. + +### 6. Report results For each tested module, report: ``` @@ -192,9 +266,9 @@ For each tested module, report: ``` For every module with **zero changes**, do not just say "no match" — always show the actual -code and explain why. See step 6. +code and explain why. See step 7. -### 6. Diagnose zero-match results +### 7. Diagnose zero-match results For **every** module that produced no changes, you must: diff --git a/CHANGELOG.md b/CHANGELOG.md index 639de4fac..349976df1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,142 @@ Historical entries (≤ 0.21.2) are reproduced from the they were originally published; their format and level of detail varies release-by-release. +## [Unreleased] + +### Added + +- **`RemovePhpUnitCompatibilityTraitRector`** — removes + `use Drupal\Tests\PhpUnitCompatibilityTrait;` from test class + declarations. The trait was a forward-compatibility shim for PHPUnit + API differences across versions; it is **deleted from Drupal core in + Drupal 12** via [#3582118](https://www.drupal.org/i/3582118), at which + point any test class still composing the trait fatal-errors at + autoload time because the trait class no longer exists. + + **Gated to Drupal 12 only — and deliberately off by default.** The + trait still exists on Drupal 10 (and may still hold shim methods that + tests depend on) and is an empty no-op on Drupal 11. Because the + trait composition is a structural `Class_` change, not an Expr → Expr + rewrite, it cannot be BC-wrapped with `DeprecationHelper`. Running + the rule prematurely on a D10-only codebase risks silently stripping + a composition that the tests still rely on. The rector therefore only + fires when the consumer explicitly sets the target Drupal version to + `12.0.0` or higher via + `DrupalRectorSettings::setDrupalVersion('12.0.0')`; the stub default + (`11.99.x-dev`) keeps it inert for normal D11-focused runs. The + orphan top-of-file `use Drupal\Tests\PhpUnitCompatibilityTrait;` + import is left in place — PHP never resolves an unused alias, so it + remains harmless on D12; cleanup is optional and out of scope. +- **`RemoveAliasManagerCacheMethodCallsRector`** — deletes calls to + `AliasManager::setCacheKey()` and `AliasManager::writeCache()`. Both + methods were deprecated in drupal:11.3.0 and are 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. + The receiver must be typed as `\Drupal\path_alias\AliasManager` or + `AliasManagerInterface`; this guard prevents accidentally removing + unrelated methods that share the name (notably + `ModuleHandler::writeCache()`). Removes the entire expression + statement, leaving surrounding code intact. No BC wrapping is needed + since dropping a no-op call is safe on every Drupal version. + [#3496369](https://www.drupal.org/i/3496369) / + [CR](https://www.drupal.org/node/3532412). +- **`ReplaceLocaleTranslationPathConfigRector`** — rewrites chained + `\Drupal::config('locale.settings')->get('translation.path')` (and + equivalents via `configFactory()->get('locale.settings')->get(...)`, + `$this->config('locale.settings')->get(...)`, and similar) to + `\Drupal\Core\Site\Settings::get('locale_translation_path', 'public://translations')`. + The `locale.settings:translation.path` config key was deprecated in + drupal:11.4.0 and is removed in drupal:13.0.0; the interface + translations directory path must now be set as + `$settings['locale_translation_path']` in `settings.php`. On older + Drupal the value still lives in config, so the replacement is + BC-wrapped with `DeprecationHelper::backwardsCompatibleCall()`. + Matching is purely structural — two literal keys + (`'locale.settings'` and `'translation.path'`) must both appear in the + expected positions, so unrelated config reads and standalone + `$config->get('translation.path')` calls are left untouched. + **Caveat:** the BC wrapper gates on `\Drupal::VERSION`, not on where + the value is stored. Before running this rule, confirm that any + customised translation path has been moved to + `$settings['locale_translation_path']` in `settings.php`; otherwise + the new branch silently returns the default + `'public://translations'` even when the config still holds the + customised value. PHPStan / upgrade_status cannot detect this + deprecation — the deprecated symbol is the config key, not a PHP API + with `@deprecated` or `trigger_error()`, so this rule must be applied + proactively as part of an 11.4 → 13 migration plan. + [#3571593](https://www.drupal.org/i/3571593) / + [CR](https://www.drupal.org/node/3571594). +- **`ViewsConfigUpdaterClassResolverToServiceRector`** — rewrites + `\Drupal::classResolver(\Drupal\views\ViewsConfigUpdater::class)` to + `\Drupal::service(\Drupal\views\ViewsConfigUpdater::class)`. In + drupal:11.3.0 `ViewsConfigUpdater` was registered as a service; + `classResolver()` returns a fresh instance on each call, so state set via + `setDeprecationsEnabled(FALSE)` was lost across hook invocations. The new + call only resolves on Drupal ≥ 11.3.0 (the service isn't registered on + older versions), so the replacement is BC-wrapped with + `DeprecationHelper::backwardsCompatibleCall()`. Three layered guards + ensure only the targeted call shape is touched: receiver must be + `\Drupal`, method must be `classResolver`, and the single argument must be + `\Drupal\views\ViewsConfigUpdater::class`. + [#3529274](https://www.drupal.org/i/3529274) / + [CR](https://www.drupal.org/node/3530638). +- **`EntityFormModeEmptyDescriptionToNullRector`** — rewrites + `EntityFormMode::create([..., 'description' => '', ...])` to use `NULL` + instead of the empty string. Setting the description property of an + `EntityFormMode` to `''` was deprecated in drupal:11.2.0 and must be `NULL` + in drupal:12.0.0. Matches both the short class name (`use`-imported) and + the fully-qualified `\Drupal\Core\Entity\Entity\EntityFormMode::create()` + form, and leaves unrelated classes (e.g. `EntityViewMode`), non-empty + descriptions, and already-migrated NULL values untouched. The replacement + is plain PHP, so no BC wrapping is needed. + [#3448457](https://www.drupal.org/i/3448457) / + [CR](https://www.drupal.org/node/3452144). +- **`DrupalGetHeadersAssocArrayRector`** — converts the two deprecated + `UiHelperTrait::drupalGet()` `$headers` argument shapes to the documented + associative format: integer-keyed colon-separated strings + (`['X-Requested-With: XMLHttpRequest']`) are split to + `['X-Requested-With' => 'XMLHttpRequest']`, and `null` values + (`['Accept-Language' => NULL]`) become empty strings + (`['Accept-Language' => '']`). Guarded against `Drupal\Tests\BrowserTestBase` + so `KernelTestBase` (which uses `HttpKernelUiHelperTrait` and does not emit + this deprecation) is left alone. Deprecated in drupal:11.1.0, removed in + drupal:12.0.0; replacement is plain PHP so no BC wrapping is needed. + Live-tested against `pager_serializer`. + [#3440169](https://www.drupal.org/i/3440169) / + [CR (indexed headers)](https://www.drupal.org/node/3456178) / + [CR (null values)](https://www.drupal.org/node/3456233). +- **`ReplaceHideShowWithPrintedRector`** — replaces statement-level calls to the + deprecated global `hide()` and `show()` functions (deprecated in drupal:11.4.0, + removed in drupal:13.0.0) with direct `$element['#printed'] = TRUE/FALSE` + assignment. Expression-context uses (where the return value is captured) are + intentionally skipped because the original returns the element while the + rewrite would not. Live-tested against `fpa`, `saml_sp`, `vertical_tabs_config`, + and `field_group_background_image`. + [#2258355](https://www.drupal.org/i/2258355) / + [CR](https://www.drupal.org/node/3261271). +- **`ReplaceExpectDeprecationRector`** — migrates removed test framework methods + to their PHPUnit 11+ replacements. Renames are BC-wrapped with + `DeprecationHelper::backwardsCompatibleCall()` so tests keep passing on both + pre-11.4 (old methods) and 11.4+ (new methods). Covers: + `$this->expectDeprecation($msg)` and `$this->expectDeprecationMessage($msg)` → + `$this->expectUserDeprecationMessage($msg)`; + `$this->expectDeprecationMessageMatches($p)` → + `$this->expectUserDeprecationMessageMatches($p)`; bare + `$this->expectDeprecation()` (no-arg PHPUnit form) → removed. + `ExpectDeprecationTrait` is deprecated in drupal:11.4.0 and removed in + drupal:12.0.0. + [#3550268](https://www.drupal.org/i/3550268) / + [CR](https://www.drupal.org/node/3545276). +- Class-rename entries for the four `Drupal\block_content\Access\*` aliases + (`AccessGroupAnd`, `DependentAccessInterface`, + `RefinableDependentAccessInterface`, `RefinableDependentAccessTrait`) → + their canonical `Drupal\Core\Access\*` homes. Deprecated in drupal:11.3.0, + removed in drupal:12.0.0; registered via Rector's built-in + `RenameClassRector` in `drupal-11.3-deprecations.php`. + [#3571874](https://www.drupal.org/i/3571874) / + [CR](https://www.drupal.org/node/3527501). + ## [1.0.0-beta1] — 2026-05-25 First beta of the 1.0 line. Adds full Drupal 11 deprecation coverage (versions 11.0 diff --git a/config/coverage-registry.php b/config/coverage-registry.php new file mode 100644 index 000000000..d64254c55 --- /dev/null +++ b/config/coverage-registry.php @@ -0,0 +1,38 @@ + + array ( + 0 => 'Call to deprecated method getDrupalRoot() of class Drupal\\KernelTests\\KernelTestBase. Deprecated in drupal:11.4.0 and is removed from drupal:13.0.0. Access $this->root directly.', + 1 => 'Call to deprecated method getDrupalRoot() of class Drupal\\Tests\\BrowserTestBase. Deprecated in drupal:11.4.0 and is removed from drupal:13.0.0. Access $this->root directly.', + 2 => 'Call to deprecated method getDrupalRoot() of class Drupal\\Tests\\UnitTestCase. Deprecated in drupal:11.4.0 and is removed from drupal:13.0.0. Access $this->root directly.', + ), + 'RemoveAliasManagerCacheMethodCallsRector' => + array ( + 0 => '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.', + 1 => 'Call to deprecated method writeCache() of class Drupal\\path_alias\\AliasManager. Deprecated in drupal:11.3.0 and is removed from drupal:13.0.0. There is no replacement.', + ), + 'ReplaceExpectDeprecationRector' => + array ( + 0 => 'Call to deprecated method expectDeprecation() of class Drupal\\KernelTests\\KernelTestBase. Deprecated in drupal:11.4.0 and is removed from drupal:12.0.0. Use $this->expectUserDeprecationMessage() or $this->expectUserDeprecationMessageMatches() instead.', + ), +); diff --git a/config/drupal-10/drupal-10.3-deprecations.php b/config/drupal-10/drupal-10.3-deprecations.php index f743ed1e3..f07b3d306 100644 --- a/config/drupal-10/drupal-10.3-deprecations.php +++ b/config/drupal-10/drupal-10.3-deprecations.php @@ -41,6 +41,7 @@ ]); // https://www.drupal.org/node/3426517 + // https://www.drupal.org/node/3575575 // FileSystemInterface::EXISTS_* deprecated in drupal:10.3.0, removed in drupal:12.0.0. // Replaced by \Drupal\Core\File\FileExists enum cases. $rectorConfig->ruleWithConfiguration(ClassConstantToClassConstantRector::class, [ diff --git a/config/drupal-11/drupal-11.0-deprecations.php b/config/drupal-11/drupal-11.0-deprecations.php index 1bfda948d..e85c68df5 100644 --- a/config/drupal-11/drupal-11.0-deprecations.php +++ b/config/drupal-11/drupal-11.0-deprecations.php @@ -17,12 +17,14 @@ $rectorConfig->rule(GetNameToNameRector::class); // https://www.drupal.org/node/3436954 - // https://www.drupal.org/node/2575105 (change record) + // https://www.drupal.org/node/3443018 (change record) + // https://www.drupal.org/node/2575105 (related) // $settings['state_cache'] deprecated in drupal:11.0.0. // State caching is now permanently enabled and the setting has no effect. $rectorConfig->rule(RemoveStateCacheSettingRector::class); // https://www.drupal.org/node/3395986 + // https://www.drupal.org/node/3395991 (change record) // REQUEST_TIME constant deprecated in drupal:8.3.0, removed in drupal:11.0.0. // Replaced by \Drupal::time()->getRequestTime(). $rectorConfig->ruleWithConfiguration(ReplaceRequestTimeConstantRector::class, [ diff --git a/config/drupal-11/drupal-11.1-deprecations.php b/config/drupal-11/drupal-11.1-deprecations.php index f10884043..37765b8fa 100644 --- a/config/drupal-11/drupal-11.1-deprecations.php +++ b/config/drupal-11/drupal-11.1-deprecations.php @@ -3,6 +3,7 @@ declare(strict_types=1); use DrupalRector\Drupal11\Rector\Deprecation\BlockContentTestBaseStringToArrayRector; +use DrupalRector\Drupal11\Rector\Deprecation\DrupalGetHeadersAssocArrayRector; use DrupalRector\Drupal11\Rector\Deprecation\MovePointerToMouseOverRector; use DrupalRector\Drupal11\Rector\Deprecation\PluginBaseIsConfigurableRector; use DrupalRector\Drupal11\Rector\Deprecation\RemoveModuleHandlerDeprecatedMethodsRector; @@ -19,14 +20,16 @@ return static function (RectorConfig $rectorConfig): void { // https://www.drupal.org/node/3459533 - // https://www.drupal.org/node/2946122 (change record) + // https://www.drupal.org/node/3459535 (change record) + // https://www.drupal.org/node/2946122 (related) // PluginBase::isConfigurable() deprecated in drupal:11.1.0, removed in drupal:12.0.0. // Replaced by instanceof \Drupal\Component\Plugin\ConfigurableInterface. $rectorConfig->ruleWithConfiguration(PluginBaseIsConfigurableRector::class, [ new DrupalIntroducedVersionConfiguration('11.1.0'), ]); - // https://www.drupal.org/node/3467559 + // https://www.drupal.org/node/3151086 + // https://www.drupal.org/node/3467559 (change record) // AliasWhitelist and AliasWhitelistInterface deprecated in drupal:11.1.0, removed in drupal:12.0.0. // Replaced by AliasPrefixList and AliasPrefixListInterface. // AliasManager::pathAliasWhitelistRebuild() deprecated in drupal:11.1.0, removed in drupal:12.0.0. @@ -41,7 +44,8 @@ ]); // https://www.drupal.org/node/3442009 - // https://www.drupal.org/node/3368812 (change record) + // https://www.drupal.org/node/3442349 (change record) + // https://www.drupal.org/node/3368812 (related) // ModuleHandlerInterface::writeCache() deprecated in drupal:11.1.0, removed in drupal:12.0.0. No replacement needed. // ModuleHandlerInterface::getHookInfo() deprecated in drupal:11.1.0, removed in drupal:12.0.0. Replaced by []. $rectorConfig->rule(RemoveModuleHandlerDeprecatedMethodsRector::class); @@ -81,13 +85,24 @@ ]); // https://www.drupal.org/node/3488176 + // https://www.drupal.org/node/3488470 (change record) // drupal_common_theme() removed in drupal:11.1.0. // Replaced by \Drupal\Core\Theme\ThemeCommonElements::commonElements(). - // https://www.drupal.org/node/3268441 + // https://www.drupal.org/node/2350849 + // https://www.drupal.org/node/3268441 (change record) + // https://www.drupal.org/node/3574424 // image_filter_keyword() deprecated in drupal:11.1.0, removed in drupal:12.0.0. // Replaced by \Drupal\Component\Utility\Image::getKeywordOffset(). $rectorConfig->ruleWithConfiguration(FunctionToStaticRector::class, [ new FunctionToStaticConfiguration('11.1.0', 'drupal_common_theme', 'Drupal\Core\Theme\ThemeCommonElements', 'commonElements'), new FunctionToStaticConfiguration('11.1.0', 'image_filter_keyword', 'Drupal\Component\Utility\Image', 'getKeywordOffset'), ]); + + // https://www.drupal.org/node/3440169 + // https://www.drupal.org/node/3456178 (change record: integer-keyed headers) + // https://www.drupal.org/node/3456233 (change record: null header values) + // UiHelperTrait::drupalGet() $headers as indexed colon-separated strings or null values + // deprecated in drupal:11.1.0, removed in drupal:12.0.0. Replaced by the associative array + // format ['Header-Name' => 'value'], with empty strings in place of null. + $rectorConfig->rule(DrupalGetHeadersAssocArrayRector::class); }; diff --git a/config/drupal-11/drupal-11.2-deprecations.php b/config/drupal-11/drupal-11.2-deprecations.php index e8dac77f2..371c111ff 100644 --- a/config/drupal-11/drupal-11.2-deprecations.php +++ b/config/drupal-11/drupal-11.2-deprecations.php @@ -2,6 +2,7 @@ declare(strict_types=1); +use DrupalRector\Drupal11\Rector\Deprecation\EntityFormModeEmptyDescriptionToNullRector; use DrupalRector\Drupal11\Rector\Deprecation\RemoveCacheTagChecksumAssertionsRector; use DrupalRector\Drupal11\Rector\Deprecation\RemoveHandlerBaseDefineExtraOptionsRector; use DrupalRector\Drupal11\Rector\Deprecation\RemoveModuleHandlerAddModuleCallsRector; @@ -16,6 +17,7 @@ use DrupalRector\Drupal11\Rector\Deprecation\ReplacePdoFetchConstantsRector; use DrupalRector\Drupal11\Rector\Deprecation\ReplaceSessionWritesWithRequestSessionRector; use DrupalRector\Drupal11\Rector\Deprecation\StatementPrefetchIteratorFetchColumnRector; +use DrupalRector\Drupal11\Rector\Deprecation\ViewsBlockItemsPerPageNoneToNullRector; use DrupalRector\Rector\Deprecation\ClassConstantToClassConstantRector; use DrupalRector\Rector\Deprecation\ConstantToClassConstantRector; use DrupalRector\Rector\Deprecation\FunctionCallRemovalRector; @@ -43,14 +45,16 @@ new DrupalIntroducedVersionConfiguration('11.2.0'), ]); - // https://www.drupal.org/node/3500622 + // https://www.drupal.org/node/3498947 + // https://www.drupal.org/node/3500622 (change record) // CacheBackendInterface::invalidateAll() deprecated in drupal:11.2.0, removed in drupal:12.0.0. // Replaced by deleteAll(). $rectorConfig->ruleWithConfiguration(MethodToMethodWithCheckRector::class, [ new MethodToMethodWithCheckConfiguration('Drupal\Core\Cache\CacheBackendInterface', 'invalidateAll', 'deleteAll'), ]); - // https://www.drupal.org/node/3504125 + // https://www.drupal.org/node/3501136 + // https://www.drupal.org/node/3504125 (change record) // template_preprocess_*() functions deprecated in drupal:11.2.0, removed in drupal:12.0.0. // Replaced by ThemePreprocess and DatePreprocess service methods. $rectorConfig->ruleWithConfiguration(FunctionToServiceRector::class, [ @@ -64,8 +68,11 @@ ]); // https://www.drupal.org/node/3501136 + // https://www.drupal.org/node/3504125 (change record) + // https://www.drupal.org/node/2340341 // template_preprocess() deprecated in drupal:11.2.0, removed in drupal:12.0.0. - // https://www.drupal.org/node/3522119 + // https://www.drupal.org/node/3521059 + // https://www.drupal.org/node/3522119 (change record) // update_clear_update_disk_cache(), update_delete_file_if_stale(), // _update_manager_cache_directory(), _update_manager_extract_directory(), // and _update_manager_unique_identifier() deprecated in drupal:11.2.0, removed in drupal:13.0.0. @@ -91,6 +98,7 @@ $rectorConfig->rule(RemoveHandlerBaseDefineExtraOptionsRector::class); // https://www.drupal.org/node/3410938 + // https://www.drupal.org/node/3410939 (change record) // drupal_requirements_severity() deprecated in drupal:11.2.0, removed in drupal:12.0.0. // Replaced by RequirementSeverity::maxSeverityFromRequirements(). // https://www.drupal.org/node/3495966 @@ -104,9 +112,11 @@ ]); // https://www.drupal.org/node/3489415 + // https://www.drupal.org/node/3489502 (change record) // views_field_default_views_data() and _views_field_get_entity_type_storage() deprecated in drupal:11.2.0, removed in drupal:12.0.0. // Replaced by views.field_data_provider service methods. - // https://www.drupal.org/node/3489411 + // https://www.drupal.org/node/3069442 + // https://www.drupal.org/node/3489411 (change record) // views_entity_field_label() deprecated in drupal:11.2.0, removed in drupal:12.0.0. // Replaced by entity_field.manager::getFieldLabels(). $rectorConfig->ruleWithConfiguration(FunctionToServiceRector::class, [ @@ -118,7 +128,8 @@ // https://www.drupal.org/node/3575841 // REQUIREMENT_INFO/OK/WARNING/ERROR global constants deprecated in drupal:11.2.0, removed in drupal:12.0.0. // Replaced by RequirementSeverity enum cases. - // https://www.drupal.org/node/3488133 + // https://www.drupal.org/node/3477277 + // https://www.drupal.org/node/3488133 (change record) // LOCALE_TRANSLATION_DEFAULT_SERVER_PATTERN deprecated in drupal:11.2.0, removed in drupal:12.0.0. // Replaced by \Drupal::TRANSLATION_DEFAULT_SERVER_PATTERN. $rectorConfig->ruleWithConfiguration(ConstantToClassConstantRector::class, [ @@ -130,7 +141,7 @@ ]); // https://www.drupal.org/node/3473440 - // https://www.drupal.org/node/3474692 (change record) + // https://www.drupal.org/node/3474692 (related) // TwigNodeTrans 6th $tag constructor argument deprecated in twig/twig 3.12, removed in drupal:11.2.0. // Drop the argument. $rectorConfig->ruleWithConfiguration(RemoveTwigNodeTransTagArgumentRector::class, [ @@ -170,7 +181,8 @@ new DrupalIntroducedVersionConfiguration('11.2.0'), ]); - // https://www.drupal.org/node/3494172 + // https://www.drupal.org/node/3494126 + // https://www.drupal.org/node/3494172 (change record) // file_get_content_headers($file) deprecated in drupal:11.2.0, removed in drupal:12.0.0. // Replaced by $file->getDownloadHeaders(). $rectorConfig->ruleWithConfiguration(FunctionToFirstArgMethodRector::class, [ @@ -201,15 +213,19 @@ ]); // https://www.drupal.org/node/3495943 + // https://www.drupal.org/node/3496491 (change record) // #[StopProceduralHookScan] attribute renamed to #[ProceduralHookScanStop] in drupal:11.2.0. $rectorConfig->rule(RenameStopProceduralHookScanRector::class); // https://www.drupal.org/node/3488572 + // https://www.drupal.org/node/3488580 (change record) // Drupal\Core\Entity\Query\Sql\pgsql\* deprecated in drupal:11.2.0, removed in drupal:12.0.0. // Moved to Drupal\pgsql\EntityQuery\*. // https://www.drupal.org/node/3472008 + // https://www.drupal.org/node/3478687 (change record) // Drupal\jsonapi\EventSubscriber\ResourceResponseValidator moved to jsonapi_response_validator submodule. - // https://www.drupal.org/node/3498916 + // https://www.drupal.org/node/3498915 + // https://www.drupal.org/node/3498916 (change record) // Drupal\migrate_drupal\Plugin\migrate\source\ContentEntity/ContentEntityDeriver deprecated in drupal:11.2.0, // removed in drupal:12.0.0. Moved to Drupal\migrate namespace. $rectorConfig->ruleWithConfiguration(RenameClassRector::class, [ @@ -231,7 +247,8 @@ // Pass NULL explicitly instead of the root path argument. $rectorConfig->rule(RemoveRootFromCreateConnectionOptionsFromUrlRector::class); - // https://www.drupal.org/node/3410939 + // https://www.drupal.org/node/3410938 + // https://www.drupal.org/node/3410939 (change record) // SystemManager::REQUIREMENT_* deprecated in drupal:11.2.0, removed in drupal:12.0.0. // Replaced by \Drupal\Core\Extension\Requirement\RequirementSeverity enum cases. $rectorConfig->ruleWithConfiguration(ClassConstantToClassConstantRector::class, [ @@ -254,4 +271,18 @@ 'Error', ), ]); + + // https://www.drupal.org/node/3520946 + // https://www.drupal.org/node/3522240 (change record) + // ViewsBlockBase::setConfigurationValue('items_per_page', 'none') deprecated in drupal:11.2.0, + // removed in drupal:12.0.0. Replaced by NULL, which is the canonical value for inheriting + // the items-per-page setting from the view. + $rectorConfig->rule(ViewsBlockItemsPerPageNoneToNullRector::class); + + // https://www.drupal.org/node/3448457 + // https://www.drupal.org/node/3452144 (change record) + // EntityFormMode::create() with 'description' => '' deprecated in drupal:11.2.0, + // removed in drupal:12.0.0. Replaced by NULL, which is the canonical "no description" value + // for entity display modes. + $rectorConfig->rule(EntityFormModeEmptyDescriptionToNullRector::class); }; diff --git a/config/drupal-11/drupal-11.3-deprecations.php b/config/drupal-11/drupal-11.3-deprecations.php index 2401edcc1..894e3c2a2 100644 --- a/config/drupal-11/drupal-11.3-deprecations.php +++ b/config/drupal-11/drupal-11.3-deprecations.php @@ -7,8 +7,10 @@ use DrupalRector\Drupal11\Rector\Deprecation\FileSystemBasenameToNativeRector; use DrupalRector\Drupal11\Rector\Deprecation\LoadAllIncludesRector; use DrupalRector\Drupal11\Rector\Deprecation\NodeStorageDeprecatedMethodsRector; +use DrupalRector\Drupal11\Rector\Deprecation\RemoveAliasManagerCacheMethodCallsRector; use DrupalRector\Drupal11\Rector\Deprecation\RemoveRootFromConvertDbUrlRector; use DrupalRector\Drupal11\Rector\Deprecation\ReplaceCommentManagerGetCountNewCommentsRector; +use DrupalRector\Drupal11\Rector\Deprecation\ReplaceCommentPreviewConstantsRector; use DrupalRector\Drupal11\Rector\Deprecation\ReplaceNodeAccessViewAllNodesRector; use DrupalRector\Drupal11\Rector\Deprecation\ReplaceNodeAddBodyFieldRector; use DrupalRector\Drupal11\Rector\Deprecation\ReplaceNodeModuleProceduralFunctionsRector; @@ -16,6 +18,7 @@ use DrupalRector\Drupal11\Rector\Deprecation\ReplaceThemeGetSettingRector; use DrupalRector\Drupal11\Rector\Deprecation\ReplaceTwigExtensionRector; use DrupalRector\Drupal11\Rector\Deprecation\ReplaceUserSessionNamePropertyRector; +use DrupalRector\Drupal11\Rector\Deprecation\ViewsConfigUpdaterClassResolverToServiceRector; use DrupalRector\Rector\Deprecation\ConstantToClassConstantRector; use DrupalRector\Rector\Deprecation\FunctionCallRemovalRector; use DrupalRector\Rector\Deprecation\FunctionToFirstArgMethodRector; @@ -52,9 +55,11 @@ $rectorConfig->rule(NodeStorageDeprecatedMethodsRector::class); // https://www.drupal.org/node/3533083 + // https://www.drupal.org/node/3533315 (change record) // node_mass_update() deprecated in drupal:11.3.0, removed in drupal:13.0.0. // Replaced by \Drupal\node\NodeBulkUpdate::process(). - // https://www.drupal.org/node/3547356 + // https://www.drupal.org/node/1685492 + // https://www.drupal.org/node/3547356 (change record) // twig_render_template() deprecated in drupal:11.3.0, removed in drupal:12.0.0. // Replaced by \Drupal::service(TwigThemeEngine::class)->renderTemplate(). // twig_extension() is handled by ReplaceTwigExtensionRector below. @@ -63,7 +68,9 @@ new FunctionToServiceConfiguration('11.3.0', 'twig_render_template', 'Drupal\Core\Template\TwigThemeEngine', 'renderTemplate'), ]); - // https://www.drupal.org/node/3504125 + // https://www.drupal.org/node/3501136 + // https://www.drupal.org/node/3571382 + // https://www.drupal.org/node/3504125 (change record) // template_preprocess_layout() deprecated in drupal:11.3.0, removed in drupal:12.0.0. // Replaced by \Drupal\layout_discovery\Hook\LayoutDiscoveryThemeHooks::preprocessLayout(). $rectorConfig->ruleWithConfiguration(FunctionToServiceRector::class, [ @@ -71,6 +78,7 @@ ]); // https://www.drupal.org/node/1685492 + // https://www.drupal.org/node/3547356 (change record) // twig_extension() deprecated in drupal:11.3.0, removed in drupal:12.0.0. // Replaced by the '.html.twig' string literal. $rectorConfig->ruleWithConfiguration(ReplaceTwigExtensionRector::class, [ @@ -80,7 +88,8 @@ new DrupalIntroducedVersionConfiguration('11.3.0'), ]); - // https://www.drupal.org/node/3535528 + // https://www.drupal.org/node/3535526 + // https://www.drupal.org/node/3535528 (change record) // block_content_add_body_field() deprecated in drupal:11.3.0, removed in drupal:13.0.0. // The body field is now added via config. $rectorConfig->ruleWithConfiguration(FunctionCallRemovalRector::class, [ @@ -88,9 +97,11 @@ ]); // https://www.drupal.org/node/2010202 + // https://www.drupal.org/node/3384294 (change record) // comment_uri($comment) deprecated in drupal:11.3.0, removed in drupal:12.0.0. // Replaced by $comment->permalink(). - // https://www.drupal.org/node/3531945 + // https://www.drupal.org/node/3531944 + // https://www.drupal.org/node/3531945 (change record) // node_type_get_description($node_type) deprecated in drupal:11.3.0, removed in drupal:12.0.0. // Replaced by $node_type->getDescription(). $rectorConfig->ruleWithConfiguration(FunctionToFirstArgMethodRector::class, [ @@ -107,7 +118,9 @@ new DrupalIntroducedVersionConfiguration('11.3.0'), ]); - // https://www.drupal.org/node/3548329 + // https://www.drupal.org/node/3548326 + // https://www.drupal.org/node/3548329 (change record) + // https://www.drupal.org/node/3574424 // responsive_image_* functions deprecated in drupal:11.3.0, removed in drupal:12.0.0. // Replaced by \Drupal::service(ResponsiveImageBuilder::class)->method() calls. $rectorConfig->ruleWithConfiguration(FunctionToServiceRector::class, [ @@ -134,6 +147,7 @@ ]); // https://www.drupal.org/node/3534092 + // https://www.drupal.org/node/3534099 (change record) // file_system_settings_submit() deprecated in drupal:11.3.0, removed in drupal:13.0.0. // Replaced by \Drupal\file\Hook\FileHooks::settingsSubmit(). // https://www.drupal.org/node/3534089 @@ -153,7 +167,8 @@ new DrupalIntroducedVersionConfiguration('11.3.0'), ]); - // https://www.drupal.org/node/3495601 + // https://www.drupal.org/node/3495600 + // https://www.drupal.org/node/3495601 (change record) // JSONAPI_FILTER_AMONG_* global constants deprecated in drupal:11.3.0, removed in drupal:13.0.0. // Replaced by \Drupal\jsonapi\JsonApiFilter::AMONG_* class constants. $rectorConfig->ruleWithConfiguration(ConstantToClassConstantRector::class, [ @@ -203,11 +218,54 @@ new DrupalIntroducedVersionConfiguration('11.3.0'), ]); - // https://www.drupal.org/node/3551450 + // https://www.drupal.org/node/3551446 + // https://www.drupal.org/node/3551450 (change record) // workspaces.association service and WorkspaceAssociationInterface renamed in drupal:11.3.0. // Replaced by workspaces.tracker and WorkspaceTrackerInterface. $rectorConfig->ruleWithConfiguration(RenameClassRector::class, [ 'Drupal\workspaces\WorkspaceAssociationInterface' => 'Drupal\workspaces\WorkspaceTrackerInterface', 'Drupal\workspaces\WorkspaceAssociation' => 'Drupal\workspaces\WorkspaceTracker', ]); + + // https://www.drupal.org/node/3571874 + // https://www.drupal.org/node/3527501 (change record) + // Drupal\block_content\Access\* class aliases deprecated in drupal:11.3.0, removed in drupal:12.0.0. + // Replaced by their canonical Drupal\Core\Access homes. + // + // TODO PHPSTAN_MESSAGES RenameClassRector: capture against a Drupal 11.3.x + // test env (aliases are already gone from 11.4-dev, so live capture is + // not possible here). Expected shape from phpstan-deprecation-rules is + // either "Class MyBlock implements deprecated interface + // Drupal\block_content\Access\..." (for `implements`) or "Extending + // deprecated class Drupal\block_content\Access\..." (for `extends`). + $rectorConfig->ruleWithConfiguration(RenameClassRector::class, [ + 'Drupal\block_content\Access\AccessGroupAnd' => 'Drupal\Core\Access\AccessGroupAnd', + 'Drupal\block_content\Access\DependentAccessInterface' => 'Drupal\Core\Access\DependentAccessInterface', + 'Drupal\block_content\Access\RefinableDependentAccessInterface' => 'Drupal\Core\Access\RefinableDependentAccessInterface', + 'Drupal\block_content\Access\RefinableDependentAccessTrait' => 'Drupal\Core\Access\RefinableDependentAccessTrait', + ]); + + // https://www.drupal.org/node/3538660 + // https://www.drupal.org/node/3538678 (change record) + // Passing an int to CommentTestBase::setCommentPreview() deprecated in drupal:11.3.0, removed in drupal:13.0.0. + // Replaced by Drupal\comment\CommentPreviewMode enum cases. + $rectorConfig->ruleWithConfiguration(ReplaceCommentPreviewConstantsRector::class, [ + new DrupalIntroducedVersionConfiguration('11.3.0'), + ]); + + // https://www.drupal.org/node/3529274 + // https://www.drupal.org/node/3530638 (change record) + // ViewsConfigUpdater registered as a service in drupal:11.3.0. Replace + // \Drupal::classResolver(ViewsConfigUpdater::class) with + // \Drupal::service(ViewsConfigUpdater::class) so state set via + // setDeprecationsEnabled(FALSE) persists across hook invocations. + $rectorConfig->ruleWithConfiguration(ViewsConfigUpdaterClassResolverToServiceRector::class, [ + new DrupalIntroducedVersionConfiguration('11.3.0'), + ]); + + // 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); }; diff --git a/config/drupal-11/drupal-11.4-deprecations.php b/config/drupal-11/drupal-11.4-deprecations.php index a4b52fdde..91186e683 100644 --- a/config/drupal-11/drupal-11.4-deprecations.php +++ b/config/drupal-11/drupal-11.4-deprecations.php @@ -5,6 +5,7 @@ use DrupalRector\Drupal11\Rector\Deprecation\CheckMarkupToProcessedTextRector; use DrupalRector\Drupal11\Rector\Deprecation\DeprecatedFilterFunctionsRector; use DrupalRector\Drupal11\Rector\Deprecation\FilterFormatFunctionsToServiceRector; +use DrupalRector\Drupal11\Rector\Deprecation\GetDrupalRootToRootPropertyRector; use DrupalRector\Drupal11\Rector\Deprecation\GetOriginalClassToGetDecoratedClassesRector; use DrupalRector\Drupal11\Rector\Deprecation\LocaleCompareIncToServiceRector; use DrupalRector\Drupal11\Rector\Deprecation\MediaFilterFormatEditFormValidateRector; @@ -14,10 +15,14 @@ use DrupalRector\Drupal11\Rector\Deprecation\RemoveConfigSaveTrustedDataArgRector; use DrupalRector\Drupal11\Rector\Deprecation\RemoveFilterTipsLongParamRector; use DrupalRector\Drupal11\Rector\Deprecation\RemoveLinkWidgetValidateTitleElementRector; +use DrupalRector\Drupal11\Rector\Deprecation\RemovePhpUnitCompatibilityTraitRector; use DrupalRector\Drupal11\Rector\Deprecation\RemoveSetUriCallbackRector; use DrupalRector\Drupal11\Rector\Deprecation\RemoveTrustDataCallRector; use DrupalRector\Drupal11\Rector\Deprecation\RemoveViewsRowCacheKeysRector; use DrupalRector\Drupal11\Rector\Deprecation\ReplaceEntityReferenceRecursiveLimitRector; +use DrupalRector\Drupal11\Rector\Deprecation\ReplaceExpectDeprecationRector; +use DrupalRector\Drupal11\Rector\Deprecation\ReplaceHideShowWithPrintedRector; +use DrupalRector\Drupal11\Rector\Deprecation\ReplaceLocaleTranslationPathConfigRector; use DrupalRector\Drupal11\Rector\Deprecation\ReplaceRecipeRunnerInstallModuleRector; use DrupalRector\Drupal11\Rector\Deprecation\ReplaceSessionManagerDeleteRector; use DrupalRector\Drupal11\Rector\Deprecation\ReplaceSystemPerformanceGzipKeyRector; @@ -48,7 +53,8 @@ new DrupalIntroducedVersionConfiguration('11.4.0'), ]); - // https://www.drupal.org/node/3578055 + // https://www.drupal.org/node/2473041 + // https://www.drupal.org/node/3578055 (change record) // node_access_grants() deprecated in drupal:11.4.0, removed in drupal:13.0.0. // Replaced by \Drupal\node\NodeGrantsHelper::nodeAccessGrants(). $rectorConfig->ruleWithConfiguration(FunctionToServiceRector::class, [ @@ -89,7 +95,9 @@ new DrupalIntroducedVersionConfiguration('11.4.0'), ]); - // https://www.drupal.org/node/3570851 + // https://www.drupal.org/node/3570849 + // https://www.drupal.org/node/3570851 (change record) + // https://www.drupal.org/node/3577376 // SessionManager::delete() deprecated in drupal:11.4.0, removed in drupal:12.0.0. // Replaced by \Drupal\Core\Session\UserSessionRepositoryInterface::deleteAll(). $rectorConfig->ruleWithConfiguration(ReplaceSessionManagerDeleteRector::class, [ @@ -97,9 +105,11 @@ ]); // https://www.drupal.org/node/3550054 + // https://www.drupal.org/node/3550055 (change record) // CommentItemInterface::FORM_BELOW and FORM_SEPARATE_PAGE deprecated in 11.4.0, // removed in 13.0.0. Replaced by FormLocation enum cases. - // https://www.drupal.org/node/3547352 + // https://www.drupal.org/node/3547349 + // https://www.drupal.org/node/3547352 (change record) // CommentItemInterface::HIDDEN/CLOSED/OPEN and CommentInterface::ANONYMOUS_* // deprecated in 11.4.0, removed in 13.0.0. Replaced by CommentingStatus and // AnonymousContact enum cases. @@ -155,31 +165,41 @@ ]); // https://www.drupal.org/node/3574727 + // https://www.drupal.org/node/3566774 (change record) // language_configuration_element_submit() deprecated in 11.4.0, removed in 13.0.0. // Replaced by LanguageConfiguration::submit(). // language_process_language_select() deprecated in 11.4.0, removed in 12.0.0. // Replaced by LanguageHooks::processLanguageSelect() via the service container. // https://www.drupal.org/node/3566792 + // https://www.drupal.org/node/3566774 (change record) // ckeditor5_filter_format_edit_form_submit() and _update_ckeditor5_html_filter() // deprecated in 11.4.0, removed in 12.0.0. Replaced by Ckeditor5Hooks service. // https://www.drupal.org/node/3560398 + // https://www.drupal.org/node/3560399 (change record) // _dblog_get_message_types() and dblog_filters() deprecated in 11.4.0, // removed in 13.0.0. Replaced by DbLogFilters service. // https://www.drupal.org/node/3566888 + // https://www.drupal.org/node/3566774 (change record) // contact_user_profile_form_submit() and contact_form_user_admin_settings_submit() // deprecated in 11.4.0, removed in 12.0.0. Replaced by ContactFormHooks service. // https://www.drupal.org/node/3548571 + // https://www.drupal.org/node/3548573 (change record) // content_translation_* functions deprecated in 11.4.0, removed in 12.0.0/13.0.0. // https://www.drupal.org/node/3572339 + // https://www.drupal.org/node/3572345 (change record) // locale_translation_batch_update_build() and locale_translation_batch_fetch_build() // deprecated in 11.4.0, removed in 13.0.0. Replaced by LocaleFetch service. // https://www.drupal.org/node/3569328 + // https://www.drupal.org/node/3569330 (change record) // locale.translation.inc functions deprecated in 11.4.0, removed in 13.0.0. // https://www.drupal.org/node/3571400 + // https://www.drupal.org/node/3571402 (change record) // menu_ui.module procedural functions deprecated in 11.4.0, removed in 12.0.0/13.0.0. // https://www.drupal.org/node/3568387 + // https://www.drupal.org/node/3568389 (change record) // text_summary() deprecated in 11.4.0, removed in 13.0.0. Replaced by TextSummary service. - // https://www.drupal.org/node/3582107 + // https://www.drupal.org/node/3582106 + // https://www.drupal.org/node/3582107 (change record) // user_form_process_password_confirm() deprecated in 11.4.0, removed in 13.0.0. $rectorConfig->ruleWithConfiguration(FunctionToServiceRector::class, [ new FunctionToServiceConfiguration('11.4.0', 'language_process_language_select', 'Drupal\language\Hook\LanguageHooks', 'processLanguageSelect'), @@ -220,15 +240,21 @@ ]); // https://www.drupal.org/node/3035340 + // https://www.drupal.org/node/3040111 (change record) // views_ui_contextual_links_suppress*() deprecated in drupal:11.4.0, removed in drupal:13.0.0. // These are no-ops and can be removed. // https://www.drupal.org/node/3566768 // https://www.drupal.org/node/3566774 (change record) // automated_cron_settings_submit() deprecated in drupal:11.4.0, removed in drupal:13.0.0. // Config saving is now handled automatically via #config_target on the interval element. - // https://www.drupal.org/node/3566783 + // https://www.drupal.org/node/3566782 + // https://www.drupal.org/node/3566783 (change record) // block_theme_initialize() deprecated in drupal:11.4.0, removed in drupal:13.0.0. // Logic moved to protected BlockHooks::themeInitialize(); external callers must drop the call. + // https://www.drupal.org/node/3570235 + // syslog_facility_list() and syslog_logging_settings_submit() deprecated in drupal:11.4.0, removed in drupal:13.0.0. + // https://www.drupal.org/node/3570238 + // taxonomy_build_node_index() and taxonomy_delete_node_index() deprecated in drupal:11.4.0, removed in drupal:13.0.0. $rectorConfig->ruleWithConfiguration(FunctionCallRemovalRector::class, [ new FunctionCallRemovalConfiguration('views_ui_contextual_links_suppress'), new FunctionCallRemovalConfiguration('views_ui_contextual_links_suppress_push'), @@ -324,26 +350,31 @@ ]); // https://www.drupal.org/node/3568144 + // https://www.drupal.org/node/3568146 (change record) // editor_filter_xss() deprecated in drupal:11.4.0, removed in drupal:13.0.0. // Replaced by \Drupal::service('element.editor')->filterXss(). // https://www.drupal.org/node/3570917 + // https://www.drupal.org/node/3570919 (change record) // editor_image_upload_settings_form() deprecated in drupal:11.4.0, removed in drupal:13.0.0. // Replaced by \Drupal::service(EditorImageUploadSettings::class)->getForm(). // https://www.drupal.org/node/2907780 + // https://www.drupal.org/node/3494023 (change record) // field_purge_batch() deprecated in drupal:11.4.0, removed in drupal:13.0.0. // Replaced by \Drupal::service(FieldPurger::class)->purgeBatch(). - // https://www.drupal.org/node/3566774 + // https://www.drupal.org/node/3570839 + // https://www.drupal.org/node/3566774 (change record) // _media_library_media_type_form_submit() and _media_library_views_form_media_library_after_build() // deprecated in drupal:11.4.0, removed in drupal:12.0.0. Replaced by MediaLibraryHooks service. $rectorConfig->ruleWithConfiguration(FunctionToServiceRector::class, [ new FunctionToServiceConfiguration('11.4.0', 'editor_filter_xss', 'element.editor', 'filterXss'), new FunctionToServiceConfiguration('11.4.0', 'editor_image_upload_settings_form', 'Drupal\editor\EditorImageUploadSettings', 'getForm'), new FunctionToServiceConfiguration('11.4.0', 'field_purge_batch', 'Drupal\Core\Field\FieldPurger', 'purgeBatch'), - new FunctionToServiceConfiguration('11.4.0', '_media_library_media_type_form_submit', 'Drupal\media_library\Hook\MediaLibraryHooks', 'mediaTypeFormSubmit'), - new FunctionToServiceConfiguration('11.4.0', '_media_library_views_form_media_library_after_build', 'Drupal\media_library\Hook\MediaLibraryHooks', 'viewsFormAfterBuild'), + new FunctionToServiceConfiguration('11.4.0', '_media_library_media_type_form_submit', 'Drupal\media_library\Hook\MediaLibraryHooks', 'mediaTypeFormSubmit', true), + new FunctionToServiceConfiguration('11.4.0', '_media_library_views_form_media_library_after_build', 'Drupal\media_library\Hook\MediaLibraryHooks', 'viewsFormAfterBuild', true), ]); - // https://www.drupal.org/node/3566774 + // https://www.drupal.org/node/3570839 + // https://www.drupal.org/node/3566774 (change record) // _media_library_configure_form_display() and _media_library_configure_view_display() // deprecated in drupal:11.4.0, removed in drupal:12.0.0. // Replaced by MediaLibraryDisplayManager static methods. @@ -353,9 +384,11 @@ ]); // https://www.drupal.org/node/3574727 + // https://www.drupal.org/node/3566774 (change record) // language_configuration_element_submit() deprecated in 11.4.0, removed in 13.0.0. // Replaced by LanguageConfiguration::submit(). - // https://www.drupal.org/node/3566774 + // https://www.drupal.org/node/3035340 + // https://www.drupal.org/node/3566774 (change record) // views_ui/admin.inc static trait functions deprecated in 11.4.0, removed in 13.0.0. $rectorConfig->ruleWithConfiguration(FunctionToStaticRector::class, [ new FunctionToStaticConfiguration('11.4.0', 'language_configuration_element_submit', 'Drupal\language\Element\LanguageConfiguration', 'submit'), @@ -366,12 +399,15 @@ ]); // https://www.drupal.org/node/3568087 + // https://www.drupal.org/node/3568088 (change record) // contextual_links_to_id() and contextual_id_to_links() deprecated in drupal:11.4.0, removed in drupal:13.0.0. // Replaced by ContextualLinksSerializer service. // https://www.drupal.org/node/3567618 + // https://www.drupal.org/node/3567619 (change record) // image_path_flush() and image_style_options() deprecated in drupal:11.4.0, removed in drupal:13.0.0. // Replaced by ImageDerivativeUtilities service. - // https://www.drupal.org/node/3577675 + // https://www.drupal.org/node/3577671 + // https://www.drupal.org/node/3577675 (change record) // locale_translate_get_interface_translation_files() deprecated in drupal:11.4.0, removed in drupal:13.0.0. // Replaced by LocaleFileManager::getInterfaceTranslationFiles(). $rectorConfig->ruleWithConfiguration(FunctionToServiceRector::class, [ @@ -393,7 +429,8 @@ new FunctionToServiceConfiguration('11.4.0', 'views_add_contextual_links', 'Drupal\views\ContextualLinksHelper', 'addLinks', true), ]); - // https://www.drupal.org/node/3567619 + // https://www.drupal.org/node/3567618 + // https://www.drupal.org/node/3567619 (change record) // IMAGE_DERIVATIVE_TOKEN deprecated in drupal:11.4.0, removed in drupal:13.0.0. // Replaced by \Drupal\image\ImageStyleInterface::TOKEN. $rectorConfig->ruleWithConfiguration(ConstantToClassConstantRector::class, [ @@ -408,6 +445,7 @@ ]); // https://www.drupal.org/node/3015812 + // https://www.drupal.org/node/3015925 (change record) // system_region_list() and system_default_region() deprecated in drupal:11.4.0, removed in drupal:13.0.0. // Replaced by Theme object methods via \Drupal::service('theme_handler')->getTheme(). $rectorConfig->ruleWithConfiguration(SystemRegionFunctionsRector::class, [ @@ -431,11 +469,57 @@ // Replaced by an inline static closure. $rectorConfig->rule(SystemSortThemesRector::class); + // https://www.drupal.org/node/2258355 + // https://www.drupal.org/node/3261271 (change record) + // hide() and show() deprecated in drupal:11.4.0, removed in drupal:13.0.0. + // Replaced by direct $element['#printed'] = TRUE/FALSE assignment. + $rectorConfig->rule(ReplaceHideShowWithPrintedRector::class); + + // https://www.drupal.org/node/3550268 + // https://www.drupal.org/node/3545276 (change record) + // ExpectDeprecationTrait deprecated in drupal:11.4.0, removed in drupal:12.0.0. + // Replaced by PHPUnit 11+ expectUserDeprecationMessage() / expectUserDeprecationMessageMatches(). + $rectorConfig->ruleWithConfiguration(ReplaceExpectDeprecationRector::class, [ + new DrupalIntroducedVersionConfiguration('11.4.0'), + ]); + // https://www.drupal.org/node/3037031 + // https://www.drupal.org/node/3037033 (change record) // locale_translation_flush_projects(), locale_translation_build_projects(), locale_translation_check_projects(), // and locale_translation_check_projects_local() deprecated in drupal:11.4.0, removed in drupal:13.0.0. // Replaced by LocaleProjectRepository and LocaleProjectChecker service methods. $rectorConfig->ruleWithConfiguration(LocaleCompareIncToServiceRector::class, [ new DrupalIntroducedVersionConfiguration('11.4.0'), ]); + + // https://www.drupal.org/node/3589047 + // https://www.drupal.org/node/3574112 (change record) + // DrupalTestCaseTrait::getDrupalRoot() deprecated in drupal:11.4.0, removed in drupal:13.0.0. + // Replaced by direct access to the $this->root property on Drupal base test classes. + $rectorConfig->rule(GetDrupalRootToRootPropertyRector::class); + + // https://www.drupal.org/node/3571593 + // https://www.drupal.org/node/3571594 (change record) + // locale.settings:translation.path config key deprecated in drupal:11.4.0, removed in drupal:13.0.0. + // Replaced by \Drupal\Core\Site\Settings::get('locale_translation_path', 'public://translations'). + $rectorConfig->ruleWithConfiguration(ReplaceLocaleTranslationPathConfigRector::class, [ + new DrupalIntroducedVersionConfiguration('11.4.0'), + ]); + + // https://www.drupal.org/node/3582118 + // PhpUnitCompatibilityTrait is DELETED FROM CORE in Drupal 12 — any test + // class still composing the trait fatal-errors at autoload on D12. + // + // GATED TO 12.0.0 INTENTIONALLY. The trait still exists (and may still + // hold shim methods) on Drupal 10. On Drupal 11 it is an empty no-op but + // removing the composition is harmless. On Drupal 12 the trait class is + // gone and the composition MUST be removed. Because the trait composition + // cannot be BC-wrapped (it's a structural Class_ change, not an Expr → + // Expr rewrite), the rector is deliberately OFF by default and only fires + // when the consumer sets DrupalRectorSettings::setDrupalVersion('12.0.0') + // or higher. This prevents accidentally stripping a still-functional + // trait composition from a D10/D11-only codebase. + $rectorConfig->ruleWithConfiguration(RemovePhpUnitCompatibilityTraitRector::class, [ + new DrupalIntroducedVersionConfiguration('12.0.0'), + ]); }; diff --git a/scripts/generate-coverage-registry.php b/scripts/generate-coverage-registry.php new file mode 100644 index 000000000..5c6598ea6 --- /dev/null +++ b/scripts/generate-coverage-registry.php @@ -0,0 +1,217 @@ +Rector.php + * — public const PHPSTAN_MESSAGES on the rector class. + * + * config/drupal-{8,9,10,11}/.php + * — // PHPSTAN_MESSAGES: comment block above a ruleWithConfiguration() + * or rule() call. Used for config-only rector registrations (e.g. + * FunctionToServiceRector, RenameClassRector) where there is no + * custom rector class to attach a const to. + * + * Output: config/coverage-registry.php is a `return [ ... ]` file mapping + * each rector class name (short, e.g. "ReplaceSessionManagerDeleteRector") + * to an array of normalized PHPStan deprecation message strings. + * + * Consumers (e.g. a future upgrade_status PR) can require this file and + * flatten via array_merge(...array_values($registry)) for a drop-in + * replacement of DeprecationAnalyzer::isRectorCovered()'s hardcoded array. + */ +$repoRoot = realpath(__DIR__.'/..'); +if ($repoRoot === false) { + fwrite(STDERR, "Could not resolve repo root\n"); + exit(1); +} + +require_once $repoRoot.'/scripts/normalize-phpstan-message.php'; + +$autoload = $repoRoot.'/vendor/autoload.php'; +if (!is_file($autoload)) { + fwrite(STDERR, "Run `composer install` first — vendor/autoload.php is missing.\n"); + exit(1); +} +require_once $autoload; + +$registry = []; + +// --- Source 1: PHPSTAN_MESSAGES const on rector classes --------------------- +$srcGlobs = [ + $repoRoot.'/src/Drupal8/Rector/Deprecation/*.php', + $repoRoot.'/src/Drupal9/Rector/Deprecation/*.php', + $repoRoot.'/src/Drupal10/Rector/Deprecation/*.php', + $repoRoot.'/src/Drupal11/Rector/Deprecation/*.php', +]; +foreach ($srcGlobs as $glob) { + foreach (glob($glob) ?: [] as $file) { + $fqcn = fqcnFromFile($file); + if ($fqcn === null) { + continue; + } + try { + $reflection = new ReflectionClass($fqcn); + } catch (ReflectionException) { + continue; + } + if (!$reflection->hasConstant('PHPSTAN_MESSAGES')) { + continue; + } + $messages = $reflection->getConstant('PHPSTAN_MESSAGES'); + if (!is_array($messages) || $messages === []) { + continue; + } + $short = $reflection->getShortName(); + foreach ($messages as $msg) { + if (!is_string($msg) || $msg === '') { + continue; + } + $registry[$short][] = normalizePhpstanMessage($msg); + } + } +} + +// --- Source 2: // PHPSTAN_MESSAGES: blocks in config/drupal-N/*.php -------- +$configGlobs = [ + $repoRoot.'/config/drupal-8/*.php', + $repoRoot.'/config/drupal-9/*.php', + $repoRoot.'/config/drupal-10/*.php', + $repoRoot.'/config/drupal-11/*.php', +]; +foreach ($configGlobs as $glob) { + foreach (glob($glob) ?: [] as $file) { + foreach (extractConfigMessages($file) as $rector => $messages) { + foreach ($messages as $msg) { + $registry[$rector][] = normalizePhpstanMessage($msg); + } + } + } +} + +// Deduplicate + sort within each rector, sort rectors alphabetically. +foreach ($registry as $rector => $messages) { + $messages = array_values(array_unique($messages)); + sort($messages); + $registry[$rector] = $messages; +} +ksort($registry); + +// Emit the registry file. +$outPath = $repoRoot.'/config/coverage-registry.php'; +$header = <<<'PHP' +: + * // + * // + * $rectorConfig->ruleWithConfiguration(...); + * + * The rector name on the header line is required so one config file can + * register multiple rectors with separate message lists. + * + * @return array> rector short name => messages + */ +function extractConfigMessages(string $file): array +{ + $src = file_get_contents($file); + if ($src === false) { + return []; + } + $result = []; + if (!preg_match_all( + '!^[ \t]*//\s*PHPSTAN_MESSAGES\s+([A-Za-z0-9_]+):\s*$\n((?:[ \t]*//[^\n]*\n)+)!m', + $src, + $matches, + PREG_SET_ORDER + )) { + return []; + } + foreach ($matches as $m) { + $rector = $m[1]; + $messageLines = []; + foreach (preg_split('/\R/', trim($m[2])) as $line) { + // Strip the `//` prefix and one optional space. + if (!preg_match('!^\s*//\s?(.*)$!', $line, $lineMatch)) { + continue; + } + $content = rtrim($lineMatch[1]); + if ($content === '') { + continue; + } + $messageLines[] = $content; + } + // Each non-empty `//` line is one message. Multi-line messages are + // not supported in the comment-block shape — split them in source. + foreach ($messageLines as $msg) { + $result[$rector][] = $msg; + } + } + + return $result; +} diff --git a/scripts/normalize-phpstan-message.php b/scripts/normalize-phpstan-message.php new file mode 100644 index 000000000..b51dea083 --- /dev/null +++ b/scripts/normalize-phpstan-message.php @@ -0,0 +1,47 @@ += 4.x). + * + * Usage: + * php scripts/normalize-phpstan-message.php "" + * echo "" | php scripts/normalize-phpstan-message.php + */ +function normalizePhpstanMessage(string $error): string +{ + // 1. trim + collapse runs of whitespace + $error = preg_replace('!\s+!', ' ', trim($error)); + // 2. ": in" / ": as of" → ". Deprecated in" / ". Deprecated as of" + $error = preg_replace('!:\s+(in|as of)!', '. Deprecated \1', $error); + // 3. "Use \Drupal..." → "Use Drupal..." + $error = preg_replace('!(u|U)se \\\\Drupal!', '\1se Drupal', $error); + + return $error; +} + +if (PHP_SAPI === 'cli' && realpath($argv[0] ?? '') === __FILE__) { + $input = $argv[1] ?? stream_get_contents(STDIN); + if ($input === false || $input === '') { + fwrite(STDERR, "Usage: php scripts/normalize-phpstan-message.php \"\"\n"); + fwrite(STDERR, " echo \"\" | php scripts/normalize-phpstan-message.php\n"); + exit(2); + } + echo normalizePhpstanMessage($input).PHP_EOL; +} diff --git a/src/Drupal11/Rector/Deprecation/DrupalGetHeadersAssocArrayRector.php b/src/Drupal11/Rector/Deprecation/DrupalGetHeadersAssocArrayRector.php new file mode 100644 index 000000000..347f06bb0 --- /dev/null +++ b/src/Drupal11/Rector/Deprecation/DrupalGetHeadersAssocArrayRector.php @@ -0,0 +1,125 @@ + ['Header-Name' => 'value'] + * - Null header values => empty string ''. + * + * Deprecated in drupal:11.1.0 and removed in drupal:12.0.0. The replacement is + * the documented associative format, which has always been valid; no new + * Drupal API is involved, so no BC wrapping is needed. + * + * @see https://www.drupal.org/node/3440169 + * @see https://www.drupal.org/node/3456178 + * @see https://www.drupal.org/node/3456233 + */ +class DrupalGetHeadersAssocArrayRector extends AbstractRector +{ + // TODO PHPSTAN_MESSAGES DrupalGetHeadersAssocArrayRector: PHPStan emits no + // deprecation for the targeted call. The deprecation is triggered at + // runtime via @trigger_error inside UiHelperTrait::drupalGet() when a + // header name is an integer or a header value is null. The method itself + // carries no @deprecated annotation, so phpstan-deprecation-rules does + // not flag callers. No string is available to add here. + + public function getRuleDefinition(): RuleDefinition + { + return new RuleDefinition( + 'Convert drupalGet() $headers from indexed colon-separated strings or null values to an associative array, as required by Drupal 11.1.0.', + [ + new CodeSample( + <<<'CODE_BEFORE' +$this->drupalGet('/path', [], ['X-Requested-With: XMLHttpRequest']); +$this->drupalGet('', [], ['Accept-Language' => NULL]); +CODE_BEFORE, + <<<'CODE_AFTER' +$this->drupalGet('/path', [], ['X-Requested-With' => 'XMLHttpRequest']); +$this->drupalGet('', [], ['Accept-Language' => '']); +CODE_AFTER + ), + ] + ); + } + + /** @return array> */ + public function getNodeTypes(): array + { + return [MethodCall::class]; + } + + /** + * @param MethodCall $node + */ + public function refactor(Node $node): ?Node + { + if (!$this->isName($node->name, 'drupalGet')) { + return null; + } + + // The deprecation fires only from Drupal\Tests\UiHelperTrait::drupalGet(), + // which is used by BrowserTestBase (and its subclasses, including + // WebDriverTestBase). KernelTestBase uses HttpKernelUiHelperTrait, whose + // drupalGet() does not emit this deprecation, so we exclude it by typing. + if (!$this->isObjectType($node->var, new ObjectType('Drupal\Tests\BrowserTestBase'))) { + return null; + } + + // $headers is the third argument (index 2). + if (count($node->args) < 3) { + return null; + } + + $headersArg = $node->args[2]; + if (!$headersArg instanceof Arg) { + return null; + } + + $headersArray = $headersArg->value; + if (!$headersArray instanceof Array_) { + return null; + } + + $changed = false; + + foreach ($headersArray->items as $item) { + // Pattern 1: integer-keyed item with 'Header-Name: value' string. + // Deprecated since drupal:11.1.0 — see https://www.drupal.org/node/3456178 + if ($item->key === null && $item->value instanceof String_) { + $raw = $item->value->value; + if (str_contains($raw, ':')) { + [$headerName, $headerValue] = explode(':', $raw, 2); + $item->key = new String_(trim($headerName)); + $item->value = new String_(trim($headerValue)); + $changed = true; + continue; + } + } + + // Pattern 2: null header value. + // Deprecated since drupal:11.1.0 — see https://www.drupal.org/node/3456233 + if ($item->value instanceof ConstFetch + && strtolower((string) $item->value->name) === 'null' + ) { + $item->value = new String_(''); + $changed = true; + } + } + + return $changed ? $node : null; + } +} diff --git a/src/Drupal11/Rector/Deprecation/EntityFormModeEmptyDescriptionToNullRector.php b/src/Drupal11/Rector/Deprecation/EntityFormModeEmptyDescriptionToNullRector.php new file mode 100644 index 000000000..c4aca189d --- /dev/null +++ b/src/Drupal11/Rector/Deprecation/EntityFormModeEmptyDescriptionToNullRector.php @@ -0,0 +1,125 @@ + 'user.test', + 'label' => 'Test', + 'description' => '', + 'targetEntityType' => 'user', +]); +CODE_BEFORE, + <<<'CODE_AFTER' +EntityFormMode::create([ + 'id' => 'user.test', + 'label' => 'Test', + 'description' => NULL, + 'targetEntityType' => 'user', +]); +CODE_AFTER + ), + ] + ); + } + + /** @return array> */ + public function getNodeTypes(): array + { + return [StaticCall::class]; + } + + /** + * @param StaticCall $node + */ + public function refactor(Node $node): ?Node + { + if (!$this->isName($node->name, 'create')) { + return null; + } + + if (!$node->class instanceof Name) { + return null; + } + + // Static-call guard: match against the fully-qualified class name. + if (!$this->isName($node->class, 'Drupal\Core\Entity\Entity\EntityFormMode')) { + return null; + } + + if (empty($node->args)) { + return null; + } + + $firstArg = $node->args[0]; + if (!$firstArg instanceof Arg) { + return null; + } + + if (!$firstArg->value instanceof Array_) { + return null; + } + + $changed = false; + foreach ($firstArg->value->items as $item) { + if (!$item->key instanceof String_) { + continue; + } + + if ($item->key->value !== 'description') { + continue; + } + + if (!$item->value instanceof String_) { + continue; + } + + if ($item->value->value !== '') { + continue; + } + + $item->value = new ConstFetch(new Name('NULL')); + $changed = true; + } + + return $changed ? $node : null; + } +} diff --git a/src/Drupal11/Rector/Deprecation/GetDrupalRootToRootPropertyRector.php b/src/Drupal11/Rector/Deprecation/GetDrupalRootToRootPropertyRector.php new file mode 100644 index 000000000..fda5466ed --- /dev/null +++ b/src/Drupal11/Rector/Deprecation/GetDrupalRootToRootPropertyRector.php @@ -0,0 +1,90 @@ +root property access. + * + * The method was deprecated in drupal:11.4.0 and removed in drupal:13.0.0. The rule targets + * subclasses of BrowserTestBase, KernelTestBase, and UnitTestCase — all of which expose the + * pre-existing $root property via DrupalTestCaseTrait. Static calls (static::getDrupalRoot()) + * are intentionally left untouched: callers in @dataProvider methods cannot reach $this->root + * and require a structural rewrite. BuildTestBase overrides getDrupalRoot() with a non-deprecated + * implementation and is also left untouched. + * + * @see https://www.drupal.org/node/3589047 + * @see https://www.drupal.org/node/3574112 + */ +final class GetDrupalRootToRootPropertyRector extends AbstractRector +{ + public const PHPSTAN_MESSAGES = [ + 'Call to deprecated method getDrupalRoot() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:11.4.0 and is removed from drupal:13.0.0. Access $this->root directly.', + 'Call to deprecated method getDrupalRoot() of class Drupal\KernelTests\KernelTestBase. Deprecated in drupal:11.4.0 and is removed from drupal:13.0.0. Access $this->root directly.', + 'Call to deprecated method getDrupalRoot() of class Drupal\Tests\UnitTestCase. Deprecated in drupal:11.4.0 and is removed from drupal:13.0.0. Access $this->root directly.', + ]; + + /** + * Base test classes that use DrupalTestCaseTrait and do not override getDrupalRoot(). + * + * @var array + */ + private const BASE_TEST_CLASSES = [ + 'Drupal\Tests\BrowserTestBase', + 'Drupal\KernelTests\KernelTestBase', + 'Drupal\Tests\UnitTestCase', + ]; + + public function getRuleDefinition(): RuleDefinition + { + return new RuleDefinition( + 'Replace deprecated DrupalTestCaseTrait::getDrupalRoot() calls with $this->root property access in Drupal test classes.', + [ + new CodeSample( + <<<'CODE_BEFORE' +$dir = $this->getDrupalRoot() . '/core/tests/fixtures'; +CODE_BEFORE, + <<<'CODE_AFTER' +$dir = $this->root . '/core/tests/fixtures'; +CODE_AFTER + ), + ] + ); + } + + /** @return array> */ + public function getNodeTypes(): array + { + return [MethodCall::class]; + } + + /** @param MethodCall $node */ + public function refactor(Node $node): ?Node + { + if (!$this->isName($node->name, 'getDrupalRoot')) { + return null; + } + + if (count($node->args) !== 0) { + return null; + } + + foreach (self::BASE_TEST_CLASSES as $fqcn) { + if ($this->isObjectType($node->var, new ObjectType($fqcn))) { + return new PropertyFetch($node->var, new Identifier('root')); + } + } + + return null; + } +} diff --git a/src/Drupal11/Rector/Deprecation/RemoveAliasManagerCacheMethodCallsRector.php b/src/Drupal11/Rector/Deprecation/RemoveAliasManagerCacheMethodCallsRector.php new file mode 100644 index 000000000..d37c87eec --- /dev/null +++ b/src/Drupal11/Rector/Deprecation/RemoveAliasManagerCacheMethodCallsRector.php @@ -0,0 +1,76 @@ +aliasManager->setCacheKey($path);', + '' + ), + ] + ); + } + + /** @return array> */ + public function getNodeTypes(): array + { + return [Expression::class]; + } + + public function refactor(Node $node): ?int + { + assert($node instanceof Expression); + if (!$node->expr instanceof MethodCall) { + return null; + } + + $methodCall = $node->expr; + if (!$this->isNames($methodCall->name, self::TARGET_METHODS)) { + return null; + } + + if ( + !$this->isObjectType($methodCall->var, new ObjectType('Drupal\path_alias\AliasManager')) + && !$this->isObjectType($methodCall->var, new ObjectType('Drupal\path_alias\AliasManagerInterface')) + ) { + return null; + } + + return NodeVisitor::REMOVE_NODE; + } +} diff --git a/src/Drupal11/Rector/Deprecation/RemovePhpUnitCompatibilityTraitRector.php b/src/Drupal11/Rector/Deprecation/RemovePhpUnitCompatibilityTraitRector.php new file mode 100644 index 000000000..69f02e6fb --- /dev/null +++ b/src/Drupal11/Rector/Deprecation/RemovePhpUnitCompatibilityTraitRector.php @@ -0,0 +1,130 @@ +> */ + public function getNodeTypes(): array + { + return [Class_::class, Trait_::class]; + } + + protected function refactorWithConfiguration(Node $node, VersionedConfigurationInterface $configuration): ?Node + { + if (!$node instanceof Class_ && !$node instanceof Trait_) { + return null; + } + + $hasChanged = false; + foreach ($node->stmts as $key => $stmt) { + if (!$stmt instanceof TraitUse) { + continue; + } + foreach ($stmt->traits as $traitKey => $trait) { + if (!$this->isName($trait, self::TRAIT_FQCN)) { + continue; + } + unset($stmt->traits[$traitKey]); + $hasChanged = true; + } + if ($stmt->traits === []) { + unset($node->stmts[$key]); + } + } + + return $hasChanged ? $node : null; + } + + /** + * Trait composition is a structural change, not an Expr → Expr rewrite, + * so it cannot be BC-wrapped via DeprecationHelper. Disable BC entirely. + */ + public function supportBackwardsCompatibility(VersionedConfigurationInterface $configuration): bool + { + return false; + } +} diff --git a/src/Drupal11/Rector/Deprecation/ReplaceCommentPreviewConstantsRector.php b/src/Drupal11/Rector/Deprecation/ReplaceCommentPreviewConstantsRector.php new file mode 100644 index 000000000..19ac3bad9 --- /dev/null +++ b/src/Drupal11/Rector/Deprecation/ReplaceCommentPreviewConstantsRector.php @@ -0,0 +1,124 @@ += 11.3.0, so the replacement is wrapped in DeprecationHelper::backwardsCompatibleCall(). + * + * @see https://www.drupal.org/node/3538660 + * @see https://www.drupal.org/node/3538678 + */ +final class ReplaceCommentPreviewConstantsRector extends AbstractDrupalCoreRector +{ + // TODO PHPSTAN_MESSAGES ReplaceCommentPreviewConstantsRector: PHPStan emits + // no deprecation for the targeted call. The deprecation is triggered at + // runtime via @trigger_error inside CommentTestBase::setCommentPreview() + // when the $mode parameter is an int, but the method itself is not + // @deprecated. The DRUPAL_DISABLED/OPTIONAL/REQUIRED constants in + // system.module carry @deprecated docblocks but phpstan-deprecation-rules + // does not flag file-scope const usage. No string is available to add to + // the coverage registry; upgrade_status will need a different mechanism + // (deprecation message text rather than PHPStan) to detect this case. + + /** + * @var array + */ + private const CONSTANT_TO_ENUM_CASE = [ + 'DRUPAL_DISABLED' => 'Disabled', + 'DRUPAL_OPTIONAL' => 'Optional', + 'DRUPAL_REQUIRED' => 'Required', + ]; + + /** + * @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); + } + + /** @return array> */ + public function getNodeTypes(): array + { + return [MethodCall::class]; + } + + public function refactorWithConfiguration(Node $node, VersionedConfigurationInterface $configuration): ?Node + { + if (!$node instanceof MethodCall) { + return null; + } + + if (!$this->isName($node->name, 'setCommentPreview')) { + return null; + } + + if (!isset($node->args[0]) || !$node->args[0] instanceof Arg) { + return null; + } + + $argValue = $node->args[0]->value; + if (!$argValue instanceof ConstFetch) { + return null; + } + + $constName = $this->getName($argValue); + if ($constName === null || !isset(self::CONSTANT_TO_ENUM_CASE[$constName])) { + return null; + } + + if (!$this->isObjectType($node->var, new ObjectType('Drupal\Tests\comment\Functional\CommentTestBase'))) { + return null; + } + + $enumCase = self::CONSTANT_TO_ENUM_CASE[$constName]; + + $newArgs = $node->args; + $newArgs[0] = new Arg(new ClassConstFetch(new FullyQualified('Drupal\comment\CommentPreviewMode'), $enumCase)); + + return new MethodCall($node->var, $node->name, $newArgs); + } + + public function getRuleDefinition(): RuleDefinition + { + return new RuleDefinition('Replace DRUPAL_DISABLED/OPTIONAL/REQUIRED with CommentPreviewMode enum in CommentTestBase::setCommentPreview() calls.', [ + new ConfiguredCodeSample( + <<<'CODE_BEFORE' +$this->setCommentPreview(DRUPAL_DISABLED); +CODE_BEFORE, + <<<'CODE_AFTER' +$this->setCommentPreview(\Drupal\comment\CommentPreviewMode::Disabled); +CODE_AFTER, + [new DrupalIntroducedVersionConfiguration('11.3.0')] + ), + ]); + } +} diff --git a/src/Drupal11/Rector/Deprecation/ReplaceExpectDeprecationRector.php b/src/Drupal11/Rector/Deprecation/ReplaceExpectDeprecationRector.php new file mode 100644 index 000000000..ac2b4b905 --- /dev/null +++ b/src/Drupal11/Rector/Deprecation/ReplaceExpectDeprecationRector.php @@ -0,0 +1,169 @@ +expectDeprecation() (PHPUnit no-arg form) → removed + * - $this->expectDeprecation($msg) (Drupal trait form) → $this->expectUserDeprecationMessage($msg) + * - $this->expectDeprecationMessage($msg) → $this->expectUserDeprecationMessage($msg) + * - $this->expectDeprecationMessageMatches($p) → $this->expectUserDeprecationMessageMatches($p) + * + * Renames are wrapped in DeprecationHelper::backwardsCompatibleCall() so tests + * keep passing on both pre-11.4 (where the old methods still exist) and + * 11.4+ (where the new PHPUnit 11+ replacements must be used). + * + * Note: the Drupal trait method internally treats $message as a regex fragment + * with %A boundaries. Renaming to expectUserDeprecationMessage() switches to + * exact-match semantics, which matches how Drupal core itself migrated its + * tests and the typical contrib pattern (literal deprecation message). Tests + * that intentionally relied on partial matching should be reviewed and + * switched to expectUserDeprecationMessageMatches() manually. + * + * @see https://www.drupal.org/node/3550268 + * @see https://www.drupal.org/node/3545276 + */ +final class ReplaceExpectDeprecationRector extends AbstractDrupalCoreRector +{ + /** + * Verbatim PHPStan deprecation messages this rector covers. + * + * Stored in upgrade_status's normalized form (whitespace collapsed, + * ": in" → ". Deprecated in", leading "\Drupal" stripped) so they can be + * compared with DeprecationAnalyzer::isRectorCovered() via exact match. + * + * Capture method: synthetic probe extending KernelTestBase against + * Drupal 11.4-dev, then `scripts/normalize-phpstan-message.php`. + */ + public const PHPSTAN_MESSAGES = [ + 'Call to deprecated method expectDeprecation() of class Drupal\KernelTests\KernelTestBase. Deprecated in drupal:11.4.0 and is removed from drupal:12.0.0. Use $this->expectUserDeprecationMessage() or $this->expectUserDeprecationMessageMatches() instead.', + ]; + + private const RENAME_MAP = [ + 'expectDeprecation' => 'expectUserDeprecationMessage', + 'expectDeprecationMessage' => 'expectUserDeprecationMessage', + 'expectDeprecationMessageMatches' => 'expectUserDeprecationMessageMatches', + ]; + + /** + * @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); + } + + /** @return array> */ + public function getNodeTypes(): array + { + // Expression targets the 0-arg `expectDeprecation()` REMOVE case; + // MethodCall handles the renames so the parent class auto-wraps + // them in DeprecationHelper::backwardsCompatibleCall(). + return [Expression::class, MethodCall::class]; + } + + protected function refactorWithConfiguration(Node $node, VersionedConfigurationInterface $configuration): Node|int|null + { + if ($node instanceof Expression) { + return $this->refactorBareCall($node); + } + + if ($node instanceof MethodCall) { + return $this->refactorRename($node); + } + + return null; + } + + private function refactorBareCall(Expression $node): ?int + { + if (!$node->expr instanceof MethodCall) { + return null; + } + + $call = $node->expr; + if (!$this->isThisCall($call)) { + return null; + } + + if ($this->getName($call->name) !== 'expectDeprecation') { + return null; + } + + if ($call->args !== []) { + return null; + } + + return NodeVisitor::REMOVE_NODE; + } + + private function refactorRename(MethodCall $node): ?MethodCall + { + if (!$this->isThisCall($node)) { + return null; + } + + $name = $this->getName($node->name); + if ($name === null || !isset(self::RENAME_MAP[$name])) { + return null; + } + + // 0-arg `expectDeprecation()` is handled by the Expression path (REMOVE); + // skip it here so we don't emit a malformed `expectUserDeprecationMessage()`. + if ($name === 'expectDeprecation' && $node->args === []) { + return null; + } + + return new MethodCall($node->var, new Identifier(self::RENAME_MAP[$name]), $node->args); + } + + private function isThisCall(MethodCall $node): bool + { + return $node->var instanceof Variable && $node->var->name === 'this'; + } + + public function getRuleDefinition(): RuleDefinition + { + return new RuleDefinition( + 'Replace removed expectDeprecation*() test methods with PHPUnit 11+ expectUserDeprecationMessage*() equivalents.', + [ + new ConfiguredCodeSample( + <<<'BEFORE' +$this->expectDeprecation(); +$this->expectDeprecationMessage('Foo is deprecated'); +BEFORE, + <<<'AFTER' +$this->expectUserDeprecationMessage('Foo is deprecated'); +AFTER, + [new DrupalIntroducedVersionConfiguration('11.4.0')] + ), + ] + ); + } +} diff --git a/src/Drupal11/Rector/Deprecation/ReplaceHideShowWithPrintedRector.php b/src/Drupal11/Rector/Deprecation/ReplaceHideShowWithPrintedRector.php new file mode 100644 index 000000000..f64e287ca --- /dev/null +++ b/src/Drupal11/Rector/Deprecation/ReplaceHideShowWithPrintedRector.php @@ -0,0 +1,95 @@ + */ + private const FUNCTION_TO_PRINTED_VALUE = [ + 'hide' => true, + 'show' => false, + ]; + + public function getRuleDefinition(): RuleDefinition + { + return new RuleDefinition( + 'Replace deprecated global hide() and show() functions with direct #printed property assignment on the render element.', + [ + new CodeSample( + 'hide($element);', + "\$element['#printed'] = TRUE;", + ), + new CodeSample( + 'show($element);', + "\$element['#printed'] = FALSE;", + ), + ] + ); + } + + public function getNodeTypes(): array + { + return [Expression::class]; + } + + public function refactor(Node $node): ?Node + { + assert($node instanceof Expression); + + if (!$node->expr instanceof FuncCall) { + return null; + } + + $call = $node->expr; + + if (!$this->isNames($call->name, ['hide', 'show'])) { + return null; + } + + if (count($call->args) !== 1 || !$call->args[0] instanceof Arg) { + return null; + } + + $funcName = $this->getName($call->name); + + if ($funcName === null || !isset(self::FUNCTION_TO_PRINTED_VALUE[$funcName])) { + return null; + } + + $value = self::FUNCTION_TO_PRINTED_VALUE[$funcName] + ? $this->nodeFactory->createTrue() + : $this->nodeFactory->createFalse(); + + $node->expr = new Assign( + new ArrayDimFetch($call->args[0]->value, new String_('#printed')), + $value, + ); + + return $node; + } +} diff --git a/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector.php b/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector.php new file mode 100644 index 000000000..d54d73af6 --- /dev/null +++ b/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector.php @@ -0,0 +1,161 @@ += 11.4 + * it must live in settings.php. The wrapper switches branches on Drupal + * version, not on where the value is stored. Before running this rule, + * confirm that any customised translation path has been moved to + * $settings['locale_translation_path'] in settings.php; otherwise the new + * branch will silently fall back to the default 'public://translations' + * even when the config still holds the customised value. + * + * @see https://www.drupal.org/node/3571593 + * @see https://www.drupal.org/node/3571594 + */ +class ReplaceLocaleTranslationPathConfigRector extends AbstractDrupalCoreRector +{ + // TODO PHPSTAN_MESSAGES ReplaceLocaleTranslationPathConfigRector: + // PHPStan cannot detect this deprecation. The deprecated symbol is the + // config KEY 'locale.settings:translation.path' — neither the `get()` + // method nor the key string carries a PHP-level @deprecated annotation, + // and Drupal core does not trigger_error() on access. The deprecation + // notice is emitted only by locale.post_update.php after update. + + private const CONFIG_ACCESSOR_METHODS = ['config', 'get', 'getEditable']; + + private const SETTINGS_CLASS = 'Drupal\\Core\\Site\\Settings'; + + private const SETTINGS_KEY = 'locale_translation_path'; + + private const SETTINGS_DEFAULT = 'public://translations'; + + /** + * @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( + "Replace deprecated \\Drupal::config('locale.settings')->get('translation.path') with Settings::get('locale_translation_path')", + [ + new ConfiguredCodeSample( + "\\Drupal::config('locale.settings')->get('translation.path');", + "\\Drupal\\Core\\Site\\Settings::get('locale_translation_path', 'public://translations');", + [new DrupalIntroducedVersionConfiguration('11.4.0')] + ), + ] + ); + } + + /** @return array> */ + public function getNodeTypes(): array + { + return [MethodCall::class]; + } + + protected function refactorWithConfiguration(Node $node, VersionedConfigurationInterface $configuration): ?Node + { + assert($node instanceof MethodCall); + if (!$this->isName($node->name, 'get')) { + return null; + } + if (count($node->args) < 1) { + return null; + } + $firstArg = $node->args[0]; + if (!$firstArg instanceof Arg) { + return null; + } + if (!$firstArg->value instanceof String_) { + return null; + } + if ($firstArg->value->value !== 'translation.path') { + return null; + } + if (!$this->isLocaleSettingsConfigReceiver($node->var)) { + return null; + } + + return new StaticCall( + new FullyQualified(self::SETTINGS_CLASS), + new Identifier('get'), + [ + new Arg(new String_(self::SETTINGS_KEY)), + new Arg(new String_(self::SETTINGS_DEFAULT)), + ] + ); + } + + /** + * Walks a chained config-accessor expression to check whether it ultimately + * targets the locale.settings configuration object. + * + * Matches forms like: + * \Drupal::config('locale.settings') + * \Drupal::configFactory()->get('locale.settings') + * $this->config('locale.settings') + * $this->configFactory->get('locale.settings') + */ + private function isLocaleSettingsConfigReceiver(Node $receiver): bool + { + $current = $receiver; + while ($current instanceof MethodCall) { + if ($this->isNames($current->name, self::CONFIG_ACCESSOR_METHODS)) { + if (!empty($current->args) && $current->args[0] instanceof Arg) { + $arg = $current->args[0]->value; + if ($arg instanceof String_ && $arg->value === 'locale.settings') { + return true; + } + } + } + $current = $current->var; + } + if ($current instanceof StaticCall) { + if ($this->isName($current->name, 'config') && !empty($current->args)) { + $arg = $current->args[0]; + if ($arg instanceof Arg && $arg->value instanceof String_) { + return $arg->value->value === 'locale.settings'; + } + } + } + + return false; + } +} diff --git a/src/Drupal11/Rector/Deprecation/ViewsBlockItemsPerPageNoneToNullRector.php b/src/Drupal11/Rector/Deprecation/ViewsBlockItemsPerPageNoneToNullRector.php new file mode 100644 index 000000000..6062a2c25 --- /dev/null +++ b/src/Drupal11/Rector/Deprecation/ViewsBlockItemsPerPageNoneToNullRector.php @@ -0,0 +1,87 @@ +setConfigurationValue('items_per_page', 'none') with NULL for Views block plugins. + * + * The string 'none' was deprecated in drupal:11.2.0 and removed in drupal:12.0.0; + * NULL is the canonical value to inherit the items-per-page setting from the view. + * The transformed code is safe to run on all Drupal versions, so no BC wrapping is required. + * + * @see https://www.drupal.org/node/3520946 + * @see https://www.drupal.org/node/3522240 + */ +final class ViewsBlockItemsPerPageNoneToNullRector extends AbstractRector +{ + public function getRuleDefinition(): RuleDefinition + { + return new RuleDefinition( + "Replace \$block->setConfigurationValue('items_per_page', 'none') with NULL for Views block plugins.", + [ + new CodeSample( + <<<'CODE_BEFORE' +$block->setConfigurationValue('items_per_page', 'none'); +CODE_BEFORE, + <<<'CODE_AFTER' +$block->setConfigurationValue('items_per_page', NULL); +CODE_AFTER + ), + ] + ); + } + + /** @return array> */ + public function getNodeTypes(): array + { + return [MethodCall::class]; + } + + /** @param MethodCall $node */ + public function refactor(Node $node): ?Node + { + if (!$this->isName($node->name, 'setConfigurationValue')) { + return null; + } + + if (count($node->args) < 2) { + return null; + } + + $firstArg = $node->args[0]; + if (!$firstArg instanceof Arg || !$firstArg->value instanceof String_) { + return null; + } + if ($firstArg->value->value !== 'items_per_page') { + return null; + } + + $secondArg = $node->args[1]; + if (!$secondArg instanceof Arg || !$secondArg->value instanceof String_) { + return null; + } + if ($secondArg->value->value !== 'none') { + return null; + } + + if (!$this->isObjectType($node->var, new ObjectType('Drupal\views\Plugin\Block\ViewsBlockBase'))) { + return null; + } + + $node->args[1] = new Arg(new ConstFetch(new Node\Name('NULL'))); + + return $node; + } +} diff --git a/src/Drupal11/Rector/Deprecation/ViewsConfigUpdaterClassResolverToServiceRector.php b/src/Drupal11/Rector/Deprecation/ViewsConfigUpdaterClassResolverToServiceRector.php new file mode 100644 index 000000000..cf7f39437 --- /dev/null +++ b/src/Drupal11/Rector/Deprecation/ViewsConfigUpdaterClassResolverToServiceRector.php @@ -0,0 +1,126 @@ += 11.3.0 because + * the service isn't registered on older versions, so the replacement is + * BC-wrapped. + * + * @see https://www.drupal.org/node/3529274 + * @see https://www.drupal.org/node/3530638 + */ +class ViewsConfigUpdaterClassResolverToServiceRector extends AbstractDrupalCoreRector +{ + // TODO PHPSTAN_MESSAGES ViewsConfigUpdaterClassResolverToServiceRector: + // PHPStan emits no deprecation for this call. \Drupal::classResolver() + // itself is not @deprecated — only its use to resolve + // Drupal\views\ViewsConfigUpdater is now considered wrong, and that + // constraint is documented only in the change record. No string is + // available to add here. + + /** @var 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); + } + + /** @return array> */ + public function getNodeTypes(): array + { + return [StaticCall::class]; + } + + public function refactorWithConfiguration(Node $node, VersionedConfigurationInterface $configuration) + { + if (!$node instanceof StaticCall) { + return null; + } + + // Must be \Drupal::something(). + if (!$this->isName($node->class, 'Drupal')) { + return null; + } + + // Must be ::classResolver(). + if (!$this->isName($node->name, 'classResolver')) { + return null; + } + + if (count($node->args) !== 1) { + return null; + } + + $arg = $node->args[0]; + if (!$arg instanceof Arg) { + return null; + } + + $value = $arg->value; + if (!$value instanceof ClassConstFetch) { + return null; + } + + if (!$this->isName($value->name, 'class')) { + return null; + } + + // The argument must be Drupal\views\ViewsConfigUpdater::class. + if (!$this->isName($value->class, 'Drupal\views\ViewsConfigUpdater')) { + return null; + } + + // Clone before mutating: the base class re-reads $node when building + // the BC fallback closure, and a direct mutation would propagate the + // new identifier into both sides of the DeprecationHelper call. + $new = clone $node; + $new->name = new Identifier('service'); + + return $new; + } + + public function getRuleDefinition(): RuleDefinition + { + return new RuleDefinition( + 'Replace \Drupal::classResolver(ViewsConfigUpdater::class) with \Drupal::service(ViewsConfigUpdater::class) since ViewsConfigUpdater is now registered as a service in drupal:11.3.0.', + [ + new ConfiguredCodeSample( + <<<'CODE_BEFORE' +$view_config_updater = \Drupal::classResolver(\Drupal\views\ViewsConfigUpdater::class); +CODE_BEFORE, + <<<'CODE_AFTER' +$view_config_updater = \Drupal::service(\Drupal\views\ViewsConfigUpdater::class); +CODE_AFTER, + [new DrupalIntroducedVersionConfiguration('11.3.0')] + ), + ] + ); + } +} diff --git a/stubs/Drupal/Tests/comment/Functional/CommentTestBase.php b/stubs/Drupal/Tests/comment/Functional/CommentTestBase.php new file mode 100644 index 000000000..5c00969b8 --- /dev/null +++ b/stubs/Drupal/Tests/comment/Functional/CommentTestBase.php @@ -0,0 +1,18 @@ +doTestFile($filePath); + } + + public static function provideData(): \Iterator + { + return self::yieldFilesFromDirectory(__DIR__.'/fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__.'/config/configured_rule.php'; + } +} diff --git a/tests/src/Drupal11/Rector/Deprecation/DrupalGetHeadersAssocArrayRector/config/configured_rule.php b/tests/src/Drupal11/Rector/Deprecation/DrupalGetHeadersAssocArrayRector/config/configured_rule.php new file mode 100644 index 000000000..d85fbfa6b --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/DrupalGetHeadersAssocArrayRector/config/configured_rule.php @@ -0,0 +1,11 @@ +drupalGet('/path', [], ['X-Requested-With: XMLHttpRequest']); + } + + /** + * Tests null header values. + */ + public function testNullHeader() { + $this->drupalGet('', [], ['Accept-Language' => NULL]); + } + + /** + * Tests a mix of indexed and null headers in one call. + */ + public function testMixed() { + $this->drupalGet('/p', [], ['X-Foo: bar', 'Accept-Language' => NULL, 'X-Already' => 'ok']); + } + + /** + * Tests a header value that itself contains a colon (e.g. Authorization). + */ + public function testColonInValue() { + $this->drupalGet('/p', [], ['Authorization: Bearer abc:def']); + } +} +?> +----- +drupalGet('/path', [], ['X-Requested-With' => 'XMLHttpRequest']); + } + + /** + * Tests null header values. + */ + public function testNullHeader() { + $this->drupalGet('', [], ['Accept-Language' => '']); + } + + /** + * Tests a mix of indexed and null headers in one call. + */ + public function testMixed() { + $this->drupalGet('/p', [], ['X-Foo' => 'bar', 'Accept-Language' => '', 'X-Already' => 'ok']); + } + + /** + * Tests a header value that itself contains a colon (e.g. Authorization). + */ + public function testColonInValue() { + $this->drupalGet('/p', [], ['Authorization' => 'Bearer abc:def']); + } +} +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/DrupalGetHeadersAssocArrayRector/fixture/no_change_unrelated.php.inc b/tests/src/Drupal11/Rector/Deprecation/DrupalGetHeadersAssocArrayRector/fixture/no_change_unrelated.php.inc new file mode 100644 index 000000000..84f87665d --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/DrupalGetHeadersAssocArrayRector/fixture/no_change_unrelated.php.inc @@ -0,0 +1,41 @@ +drupalGet('/path', [], ['X-Requested-With: XMLHttpRequest']); + $client->drupalGet('', [], ['Accept-Language' => NULL]); +} + +// Untyped variable: rector cannot prove it is a BrowserTestBase instance. +function untyped_caller($thing) { + $thing->drupalGet('/path', [], ['X-Requested-With: XMLHttpRequest']); +} +?> +----- +drupalGet('/path', [], ['X-Requested-With: XMLHttpRequest']); + $client->drupalGet('', [], ['Accept-Language' => NULL]); +} + +// Untyped variable: rector cannot prove it is a BrowserTestBase instance. +function untyped_caller($thing) { + $thing->drupalGet('/path', [], ['X-Requested-With: XMLHttpRequest']); +} +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/EntityFormModeEmptyDescriptionToNullRector/EntityFormModeEmptyDescriptionToNullRectorTest.php b/tests/src/Drupal11/Rector/Deprecation/EntityFormModeEmptyDescriptionToNullRector/EntityFormModeEmptyDescriptionToNullRectorTest.php new file mode 100644 index 000000000..d0c01e96d --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/EntityFormModeEmptyDescriptionToNullRector/EntityFormModeEmptyDescriptionToNullRectorTest.php @@ -0,0 +1,26 @@ +doTestFile($filePath); + } + + public static function provideData(): \Iterator + { + return self::yieldFilesFromDirectory(__DIR__.'/fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__.'/config/configured_rule.php'; + } +} diff --git a/tests/src/Drupal11/Rector/Deprecation/EntityFormModeEmptyDescriptionToNullRector/config/configured_rule.php b/tests/src/Drupal11/Rector/Deprecation/EntityFormModeEmptyDescriptionToNullRector/config/configured_rule.php new file mode 100644 index 000000000..a29bc1d02 --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/EntityFormModeEmptyDescriptionToNullRector/config/configured_rule.php @@ -0,0 +1,11 @@ + 'user.test', + 'label' => 'Test', + 'description' => '', + 'targetEntityType' => 'user', + ]); +} + +function create_fqcn() { + \Drupal\Core\Entity\Entity\EntityFormMode::create([ + 'id' => 'node.preview', + 'label' => 'Preview', + 'description' => '', + 'targetEntityType' => 'node', + ]); +} + +function create_only_label() { + EntityFormMode::create([ + 'id' => 'taxonomy_term.simple', + 'label' => 'Simple', + 'description' => '', + 'targetEntityType' => 'taxonomy_term', + ]); +} +?> +----- + 'user.test', + 'label' => 'Test', + 'description' => NULL, + 'targetEntityType' => 'user', + ]); +} + +function create_fqcn() { + \Drupal\Core\Entity\Entity\EntityFormMode::create([ + 'id' => 'node.preview', + 'label' => 'Preview', + 'description' => NULL, + 'targetEntityType' => 'node', + ]); +} + +function create_only_label() { + EntityFormMode::create([ + 'id' => 'taxonomy_term.simple', + 'label' => 'Simple', + 'description' => NULL, + 'targetEntityType' => 'taxonomy_term', + ]); +} +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/EntityFormModeEmptyDescriptionToNullRector/fixture/no_change_unrelated.php.inc b/tests/src/Drupal11/Rector/Deprecation/EntityFormModeEmptyDescriptionToNullRector/fixture/no_change_unrelated.php.inc new file mode 100644 index 000000000..fca5885db --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/EntityFormModeEmptyDescriptionToNullRector/fixture/no_change_unrelated.php.inc @@ -0,0 +1,99 @@ + 'user.test', + 'label' => 'Test', + 'description' => '', + 'targetEntityType' => 'user', + ]); +} + +function unrelated_method() { + // Same class, different method — must not be transformed. + EntityFormMode::load('user.test'); +} + +function nonempty_description() { + // Description has a real value — must not be transformed. + EntityFormMode::create([ + 'id' => 'user.test', + 'label' => 'Test', + 'description' => 'A real description.', + 'targetEntityType' => 'user', + ]); +} + +function description_already_null() { + // Already migrated — must not be re-touched. + EntityFormMode::create([ + 'id' => 'user.test', + 'label' => 'Test', + 'description' => NULL, + 'targetEntityType' => 'user', + ]); +} + +function unrelated_key() { + // Empty-string elsewhere in the array — must not be transformed. + EntityFormMode::create([ + 'id' => 'user.test', + 'label' => '', + 'targetEntityType' => 'user', + ]); +} +?> +----- + 'user.test', + 'label' => 'Test', + 'description' => '', + 'targetEntityType' => 'user', + ]); +} + +function unrelated_method() { + // Same class, different method — must not be transformed. + EntityFormMode::load('user.test'); +} + +function nonempty_description() { + // Description has a real value — must not be transformed. + EntityFormMode::create([ + 'id' => 'user.test', + 'label' => 'Test', + 'description' => 'A real description.', + 'targetEntityType' => 'user', + ]); +} + +function description_already_null() { + // Already migrated — must not be re-touched. + EntityFormMode::create([ + 'id' => 'user.test', + 'label' => 'Test', + 'description' => NULL, + 'targetEntityType' => 'user', + ]); +} + +function unrelated_key() { + // Empty-string elsewhere in the array — must not be transformed. + EntityFormMode::create([ + 'id' => 'user.test', + 'label' => '', + 'targetEntityType' => 'user', + ]); +} +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/GetDrupalRootToRootPropertyRector/GetDrupalRootToRootPropertyRectorTest.php b/tests/src/Drupal11/Rector/Deprecation/GetDrupalRootToRootPropertyRector/GetDrupalRootToRootPropertyRectorTest.php new file mode 100644 index 000000000..18a2a87f4 --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/GetDrupalRootToRootPropertyRector/GetDrupalRootToRootPropertyRectorTest.php @@ -0,0 +1,26 @@ +doTestFile($filePath); + } + + public static function provideData(): \Iterator + { + return self::yieldFilesFromDirectory(__DIR__.'/fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__.'/config/configured_rule.php'; + } +} diff --git a/tests/src/Drupal11/Rector/Deprecation/GetDrupalRootToRootPropertyRector/config/configured_rule.php b/tests/src/Drupal11/Rector/Deprecation/GetDrupalRootToRootPropertyRector/config/configured_rule.php new file mode 100644 index 000000000..ff5c2f190 --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/GetDrupalRootToRootPropertyRector/config/configured_rule.php @@ -0,0 +1,11 @@ +getDrupalRoot() . '/core/tests/fixtures'; + +/** @var \Drupal\KernelTests\KernelTestBase $kernel */ +$path = $kernel->getDrupalRoot(); + +/** @var \Drupal\Tests\UnitTestCase $unit */ +echo $unit->getDrupalRoot(); +?> +----- +root . '/core/tests/fixtures'; + +/** @var \Drupal\KernelTests\KernelTestBase $kernel */ +$path = $kernel->root; + +/** @var \Drupal\Tests\UnitTestCase $unit */ +echo $unit->root; +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/GetDrupalRootToRootPropertyRector/fixture/no_change_unrelated.php.inc b/tests/src/Drupal11/Rector/Deprecation/GetDrupalRootToRootPropertyRector/fixture/no_change_unrelated.php.inc new file mode 100644 index 000000000..b9932b894 --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/GetDrupalRootToRootPropertyRector/fixture/no_change_unrelated.php.inc @@ -0,0 +1,29 @@ +getDrupalRoot(); + +// BuildTestBase overrides getDrupalRoot() with a non-deprecated implementation; must not change. +/** @var \Drupal\BuildTests\Framework\BuildTestBase $build */ +$dir = $build->getDrupalRoot(); + +// Method called with arguments — must not change (deprecated method is parameterless). +/** @var \Drupal\Tests\BrowserTestBase $browser */ +$dir = $browser->getDrupalRoot('extra'); +?> +----- +getDrupalRoot(); + +// BuildTestBase overrides getDrupalRoot() with a non-deprecated implementation; must not change. +/** @var \Drupal\BuildTests\Framework\BuildTestBase $build */ +$dir = $build->getDrupalRoot(); + +// Method called with arguments — must not change (deprecated method is parameterless). +/** @var \Drupal\Tests\BrowserTestBase $browser */ +$dir = $browser->getDrupalRoot('extra'); +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/RemoveAliasManagerCacheMethodCallsRector/RemoveAliasManagerCacheMethodCallsRectorTest.php b/tests/src/Drupal11/Rector/Deprecation/RemoveAliasManagerCacheMethodCallsRector/RemoveAliasManagerCacheMethodCallsRectorTest.php new file mode 100644 index 000000000..b40784cb4 --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/RemoveAliasManagerCacheMethodCallsRector/RemoveAliasManagerCacheMethodCallsRectorTest.php @@ -0,0 +1,26 @@ +doTestFile($filePath); + } + + public static function provideData(): \Iterator + { + return self::yieldFilesFromDirectory(__DIR__.'/fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__.'/config/configured_rule.php'; + } +} diff --git a/tests/src/Drupal11/Rector/Deprecation/RemoveAliasManagerCacheMethodCallsRector/config/configured_rule.php b/tests/src/Drupal11/Rector/Deprecation/RemoveAliasManagerCacheMethodCallsRector/config/configured_rule.php new file mode 100644 index 000000000..51c146428 --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/RemoveAliasManagerCacheMethodCallsRector/config/configured_rule.php @@ -0,0 +1,11 @@ +setCacheKey('/some/path'); + $aliasManager->writeCache(); + \Drupal::messenger()->addStatus('done'); +} +?> +----- +addStatus('done'); +} +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/RemoveAliasManagerCacheMethodCallsRector/fixture/concrete_class.php.inc b/tests/src/Drupal11/Rector/Deprecation/RemoveAliasManagerCacheMethodCallsRector/fixture/concrete_class.php.inc new file mode 100644 index 000000000..6a8fc68dd --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/RemoveAliasManagerCacheMethodCallsRector/fixture/concrete_class.php.inc @@ -0,0 +1,17 @@ +setCacheKey('/some/path'); + $aliasManager->writeCache(); + \Drupal::messenger()->addStatus('done'); +} +?> +----- +addStatus('done'); +} +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/RemoveAliasManagerCacheMethodCallsRector/fixture/no_change_module_handler_writecache.php.inc b/tests/src/Drupal11/Rector/Deprecation/RemoveAliasManagerCacheMethodCallsRector/fixture/no_change_module_handler_writecache.php.inc new file mode 100644 index 000000000..1c8ee6e61 --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/RemoveAliasManagerCacheMethodCallsRector/fixture/no_change_module_handler_writecache.php.inc @@ -0,0 +1,17 @@ +writeCache(); +} +?> +----- +writeCache(); +} +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/RemoveAliasManagerCacheMethodCallsRector/fixture/no_change_unrelated.php.inc b/tests/src/Drupal11/Rector/Deprecation/RemoveAliasManagerCacheMethodCallsRector/fixture/no_change_unrelated.php.inc new file mode 100644 index 000000000..3a5bbef2b --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/RemoveAliasManagerCacheMethodCallsRector/fixture/no_change_unrelated.php.inc @@ -0,0 +1,19 @@ +setCacheKey('/some/path'); + $aliasManager->writeCache(); +} +?> +----- +setCacheKey('/some/path'); + $aliasManager->writeCache(); +} +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/RemoveAliasManagerCacheMethodCallsRector/fixture/no_change_unrelated_method.php.inc b/tests/src/Drupal11/Rector/Deprecation/RemoveAliasManagerCacheMethodCallsRector/fixture/no_change_unrelated_method.php.inc new file mode 100644 index 000000000..c7269f2b4 --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/RemoveAliasManagerCacheMethodCallsRector/fixture/no_change_unrelated_method.php.inc @@ -0,0 +1,17 @@ +getAliasByPath('/node/1'); +} +?> +----- +getAliasByPath('/node/1'); +} +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/RemovePhpUnitCompatibilityTraitRector/RemovePhpUnitCompatibilityTraitRectorTest.php b/tests/src/Drupal11/Rector/Deprecation/RemovePhpUnitCompatibilityTraitRector/RemovePhpUnitCompatibilityTraitRectorTest.php new file mode 100644 index 000000000..93092251a --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/RemovePhpUnitCompatibilityTraitRector/RemovePhpUnitCompatibilityTraitRectorTest.php @@ -0,0 +1,46 @@ +make(DrupalRectorSettings::class)->setDrupalVersion('99.99.99'); + $this->doTestFile($filePath); + } + + /** + * @return \Iterator<> + */ + public static function provideData(): \Iterator + { + return self::yieldFilesFromDirectory(__DIR__.'/fixture'); + } + + #[\PHPUnit\Framework\Attributes\DataProvider('provideDataBelowVersion')] + public function testBelowVersion(string $filePath): void + { + static::getContainer()->make(DrupalRectorSettings::class)->setDrupalVersion('1.0.0'); + $this->doTestFile($filePath); + } + + /** + * @return \Iterator<> + */ + public static function provideDataBelowVersion(): \Iterator + { + return self::yieldFilesFromDirectory(__DIR__.'/fixture-below-version'); + } + + public function provideConfigFilePath(): string + { + return __DIR__.'/config/configured_rule.php'; + } +} diff --git a/tests/src/Drupal11/Rector/Deprecation/RemovePhpUnitCompatibilityTraitRector/config/configured_rule.php b/tests/src/Drupal11/Rector/Deprecation/RemovePhpUnitCompatibilityTraitRector/config/configured_rule.php new file mode 100644 index 000000000..60c6fadc6 --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/RemovePhpUnitCompatibilityTraitRector/config/configured_rule.php @@ -0,0 +1,14 @@ + +----- + diff --git a/tests/src/Drupal11/Rector/Deprecation/RemovePhpUnitCompatibilityTraitRector/fixture/basic.php.inc b/tests/src/Drupal11/Rector/Deprecation/RemovePhpUnitCompatibilityTraitRector/fixture/basic.php.inc new file mode 100644 index 000000000..af26b0bf6 --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/RemovePhpUnitCompatibilityTraitRector/fixture/basic.php.inc @@ -0,0 +1,31 @@ + +----- + diff --git a/tests/src/Drupal11/Rector/Deprecation/RemovePhpUnitCompatibilityTraitRector/fixture/no_change_unrelated_trait.php.inc b/tests/src/Drupal11/Rector/Deprecation/RemovePhpUnitCompatibilityTraitRector/fixture/no_change_unrelated_trait.php.inc new file mode 100644 index 000000000..62c25865a --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/RemovePhpUnitCompatibilityTraitRector/fixture/no_change_unrelated_trait.php.inc @@ -0,0 +1,39 @@ + +----- + diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceCommentPreviewConstantsRector/ReplaceCommentPreviewConstantsRectorTest.php b/tests/src/Drupal11/Rector/Deprecation/ReplaceCommentPreviewConstantsRector/ReplaceCommentPreviewConstantsRectorTest.php new file mode 100644 index 000000000..0b78c26dd --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceCommentPreviewConstantsRector/ReplaceCommentPreviewConstantsRectorTest.php @@ -0,0 +1,46 @@ +make(DrupalRectorSettings::class)->setDrupalVersion('99.99.99'); + $this->doTestFile($filePath); + } + + /** + * @return \Iterator<> + */ + public static function provideData(): \Iterator + { + return self::yieldFilesFromDirectory(__DIR__.'/fixture'); + } + + #[\PHPUnit\Framework\Attributes\DataProvider('provideDataBelowVersion')] + public function testBelowVersion(string $filePath): void + { + static::getContainer()->make(DrupalRectorSettings::class)->setDrupalVersion('1.0.0'); + $this->doTestFile($filePath); + } + + /** + * @return \Iterator<> + */ + public static function provideDataBelowVersion(): \Iterator + { + return self::yieldFilesFromDirectory(__DIR__.'/fixture-below-version'); + } + + public function provideConfigFilePath(): string + { + return __DIR__.'/config/configured_rule.php'; + } +} diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceCommentPreviewConstantsRector/config/configured_rule.php b/tests/src/Drupal11/Rector/Deprecation/ReplaceCommentPreviewConstantsRector/config/configured_rule.php new file mode 100644 index 000000000..bf3f01f0e --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceCommentPreviewConstantsRector/config/configured_rule.php @@ -0,0 +1,14 @@ +setCommentPreview(DRUPAL_DISABLED); +?> +----- +setCommentPreview(DRUPAL_DISABLED); +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceCommentPreviewConstantsRector/fixture/basic.php.inc b/tests/src/Drupal11/Rector/Deprecation/ReplaceCommentPreviewConstantsRector/fixture/basic.php.inc new file mode 100644 index 000000000..0fdad8af4 --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceCommentPreviewConstantsRector/fixture/basic.php.inc @@ -0,0 +1,17 @@ +setCommentPreview(DRUPAL_DISABLED); +$base->setCommentPreview(DRUPAL_OPTIONAL); +$base->setCommentPreview(DRUPAL_REQUIRED); +$base->setCommentPreview(DRUPAL_DISABLED, 'field_comments'); +?> +----- + $base->setCommentPreview(\Drupal\comment\CommentPreviewMode::Disabled), fn() => $base->setCommentPreview(DRUPAL_DISABLED)); +\Drupal\Component\Utility\DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '11.3.0', fn() => $base->setCommentPreview(\Drupal\comment\CommentPreviewMode::Optional), fn() => $base->setCommentPreview(DRUPAL_OPTIONAL)); +\Drupal\Component\Utility\DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '11.3.0', fn() => $base->setCommentPreview(\Drupal\comment\CommentPreviewMode::Required), fn() => $base->setCommentPreview(DRUPAL_REQUIRED)); +\Drupal\Component\Utility\DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '11.3.0', fn() => $base->setCommentPreview(\Drupal\comment\CommentPreviewMode::Disabled, 'field_comments'), fn() => $base->setCommentPreview(DRUPAL_DISABLED, 'field_comments')); +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceCommentPreviewConstantsRector/fixture/no_change_unrelated.php.inc b/tests/src/Drupal11/Rector/Deprecation/ReplaceCommentPreviewConstantsRector/fixture/no_change_unrelated.php.inc new file mode 100644 index 000000000..a2e84e785 --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceCommentPreviewConstantsRector/fixture/no_change_unrelated.php.inc @@ -0,0 +1,33 @@ +setCommentPreview(DRUPAL_DISABLED); + +// Different method on a CommentTestBase — must not change. +/** @var \Drupal\Tests\comment\Functional\CommentTestBase $base */ +$base->setCommentSettings('preview', DRUPAL_DISABLED, '', 'comment'); + +// First arg is a different constant — must not change. +$base->setCommentPreview(SOME_OTHER_CONSTANT); + +// First arg is a literal int — must not change (rector only handles named constants). +$base->setCommentPreview(0); +?> +----- +setCommentPreview(DRUPAL_DISABLED); + +// Different method on a CommentTestBase — must not change. +/** @var \Drupal\Tests\comment\Functional\CommentTestBase $base */ +$base->setCommentSettings('preview', DRUPAL_DISABLED, '', 'comment'); + +// First arg is a different constant — must not change. +$base->setCommentPreview(SOME_OTHER_CONSTANT); + +// First arg is a literal int — must not change (rector only handles named constants). +$base->setCommentPreview(0); +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceExpectDeprecationRector/ReplaceExpectDeprecationRectorTest.php b/tests/src/Drupal11/Rector/Deprecation/ReplaceExpectDeprecationRector/ReplaceExpectDeprecationRectorTest.php new file mode 100644 index 000000000..55890cc1f --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceExpectDeprecationRector/ReplaceExpectDeprecationRectorTest.php @@ -0,0 +1,46 @@ +make(DrupalRectorSettings::class)->setDrupalVersion('99.99.99'); + $this->doTestFile($filePath); + } + + /** + * @return \Iterator<> + */ + public static function provideData(): \Iterator + { + return self::yieldFilesFromDirectory(__DIR__.'/fixture'); + } + + #[\PHPUnit\Framework\Attributes\DataProvider('provideDataBelowVersion')] + public function testBelowVersion(string $filePath): void + { + static::getContainer()->make(DrupalRectorSettings::class)->setDrupalVersion('1.0.0'); + $this->doTestFile($filePath); + } + + /** + * @return \Iterator<> + */ + public static function provideDataBelowVersion(): \Iterator + { + return self::yieldFilesFromDirectory(__DIR__.'/fixture-below-version'); + } + + public function provideConfigFilePath(): string + { + return __DIR__.'/config/configured_rule.php'; + } +} diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceExpectDeprecationRector/config/configured_rule.php b/tests/src/Drupal11/Rector/Deprecation/ReplaceExpectDeprecationRector/config/configured_rule.php new file mode 100644 index 000000000..0589f999e --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceExpectDeprecationRector/config/configured_rule.php @@ -0,0 +1,13 @@ +ruleWithConfiguration(ReplaceExpectDeprecationRector::class, [ + new DrupalIntroducedVersionConfiguration('11.4.0'), + ]); +}; diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceExpectDeprecationRector/fixture-below-version/basic.php.inc b/tests/src/Drupal11/Rector/Deprecation/ReplaceExpectDeprecationRector/fixture-below-version/basic.php.inc new file mode 100644 index 000000000..ac9fd7343 --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceExpectDeprecationRector/fixture-below-version/basic.php.inc @@ -0,0 +1,21 @@ +expectDeprecation(); + $this->expectDeprecationMessage('Foo::bar is deprecated'); + $this->expectDeprecationMessageMatches('/deprecated/'); + } +} +?> +----- +expectDeprecation(); + $this->expectDeprecationMessage('Foo::bar is deprecated'); + $this->expectDeprecationMessageMatches('/deprecated/'); + } +} +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceExpectDeprecationRector/fixture-below-version/drupal_trait_one_arg.php.inc b/tests/src/Drupal11/Rector/Deprecation/ReplaceExpectDeprecationRector/fixture-below-version/drupal_trait_one_arg.php.inc new file mode 100644 index 000000000..6774c5fb3 --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceExpectDeprecationRector/fixture-below-version/drupal_trait_one_arg.php.inc @@ -0,0 +1,19 @@ +expectDeprecation('Drupal trait variant with a string arg'); + $this->expectDeprecation('foo() is deprecated in mymodule:2.0.0 and is removed from mymodule:3.0.0.'); + } +} +?> +----- +expectDeprecation('Drupal trait variant with a string arg'); + $this->expectDeprecation('foo() is deprecated in mymodule:2.0.0 and is removed from mymodule:3.0.0.'); + } +} +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceExpectDeprecationRector/fixture/basic.php.inc b/tests/src/Drupal11/Rector/Deprecation/ReplaceExpectDeprecationRector/fixture/basic.php.inc new file mode 100644 index 000000000..b44da3d85 --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceExpectDeprecationRector/fixture/basic.php.inc @@ -0,0 +1,20 @@ +expectDeprecation(); + $this->expectDeprecationMessage('Foo::bar is deprecated'); + $this->expectDeprecationMessageMatches('/deprecated/'); + } +} +?> +----- + $this->expectUserDeprecationMessage('Foo::bar is deprecated'), fn() => $this->expectDeprecationMessage('Foo::bar is deprecated')); + \Drupal\Component\Utility\DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '11.4.0', fn() => $this->expectUserDeprecationMessageMatches('/deprecated/'), fn() => $this->expectDeprecationMessageMatches('/deprecated/')); + } +} +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceExpectDeprecationRector/fixture/drupal_trait_one_arg.php.inc b/tests/src/Drupal11/Rector/Deprecation/ReplaceExpectDeprecationRector/fixture/drupal_trait_one_arg.php.inc new file mode 100644 index 000000000..adecec97e --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceExpectDeprecationRector/fixture/drupal_trait_one_arg.php.inc @@ -0,0 +1,19 @@ +expectDeprecation('Drupal trait variant with a string arg'); + $this->expectDeprecation('foo() is deprecated in mymodule:2.0.0 and is removed from mymodule:3.0.0.'); + } +} +?> +----- + $this->expectUserDeprecationMessage('Drupal trait variant with a string arg'), fn() => $this->expectDeprecation('Drupal trait variant with a string arg')); + \Drupal\Component\Utility\DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '11.4.0', fn() => $this->expectUserDeprecationMessage('foo() is deprecated in mymodule:2.0.0 and is removed from mymodule:3.0.0.'), fn() => $this->expectDeprecation('foo() is deprecated in mymodule:2.0.0 and is removed from mymodule:3.0.0.')); + } +} +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceExpectDeprecationRector/fixture/no_change_other_method.php.inc b/tests/src/Drupal11/Rector/Deprecation/ReplaceExpectDeprecationRector/fixture/no_change_other_method.php.inc new file mode 100644 index 000000000..a37e74bbe --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceExpectDeprecationRector/fixture/no_change_other_method.php.inc @@ -0,0 +1,19 @@ +expectException(\RuntimeException::class); + $this->expectExceptionMessage('boom'); + } +} +?> +----- +expectException(\RuntimeException::class); + $this->expectExceptionMessage('boom'); + } +} +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceExpectDeprecationRector/fixture/no_change_other_receiver.php.inc b/tests/src/Drupal11/Rector/Deprecation/ReplaceExpectDeprecationRector/fixture/no_change_other_receiver.php.inc new file mode 100644 index 000000000..330f2b5a7 --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceExpectDeprecationRector/fixture/no_change_other_receiver.php.inc @@ -0,0 +1,19 @@ +expectDeprecation(); + $helper->expectDeprecationMessage('foo'); + } +} +?> +----- +expectDeprecation(); + $helper->expectDeprecationMessage('foo'); + } +} +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceHideShowWithPrintedRector/ReplaceHideShowWithPrintedRectorTest.php b/tests/src/Drupal11/Rector/Deprecation/ReplaceHideShowWithPrintedRector/ReplaceHideShowWithPrintedRectorTest.php new file mode 100644 index 000000000..e9d7d113f --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceHideShowWithPrintedRector/ReplaceHideShowWithPrintedRectorTest.php @@ -0,0 +1,29 @@ +doTestFile($filePath); + } + + /** + * @return \Iterator<> + */ + public static function provideData(): \Iterator + { + return self::yieldFilesFromDirectory(__DIR__.'/fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__.'/config/configured_rule.php'; + } +} diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceHideShowWithPrintedRector/config/configured_rule.php b/tests/src/Drupal11/Rector/Deprecation/ReplaceHideShowWithPrintedRector/config/configured_rule.php new file mode 100644 index 000000000..53a38f52a --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceHideShowWithPrintedRector/config/configured_rule.php @@ -0,0 +1,10 @@ +rule(ReplaceHideShowWithPrintedRector::class); +}; diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceHideShowWithPrintedRector/fixture/basic.php.inc b/tests/src/Drupal11/Rector/Deprecation/ReplaceHideShowWithPrintedRector/fixture/basic.php.inc new file mode 100644 index 000000000..de076de05 --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceHideShowWithPrintedRector/fixture/basic.php.inc @@ -0,0 +1,15 @@ + +----- + diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceHideShowWithPrintedRector/fixture/nested_element.php.inc b/tests/src/Drupal11/Rector/Deprecation/ReplaceHideShowWithPrintedRector/fixture/nested_element.php.inc new file mode 100644 index 000000000..63a4f6e20 --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceHideShowWithPrintedRector/fixture/nested_element.php.inc @@ -0,0 +1,15 @@ + +----- + diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceHideShowWithPrintedRector/fixture/no_change_expression_context.php.inc b/tests/src/Drupal11/Rector/Deprecation/ReplaceHideShowWithPrintedRector/fixture/no_change_expression_context.php.inc new file mode 100644 index 000000000..4ff0c97d0 --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceHideShowWithPrintedRector/fixture/no_change_expression_context.php.inc @@ -0,0 +1,19 @@ + +----- + diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceHideShowWithPrintedRector/fixture/no_change_method_call.php.inc b/tests/src/Drupal11/Rector/Deprecation/ReplaceHideShowWithPrintedRector/fixture/no_change_method_call.php.inc new file mode 100644 index 000000000..df47bfebd --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceHideShowWithPrintedRector/fixture/no_change_method_call.php.inc @@ -0,0 +1,19 @@ +hide($element); + $obj->show($element); + } +} +?> +----- +hide($element); + $obj->show($element); + } +} +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceHideShowWithPrintedRector/fixture/no_change_wrong_arg_count.php.inc b/tests/src/Drupal11/Rector/Deprecation/ReplaceHideShowWithPrintedRector/fixture/no_change_wrong_arg_count.php.inc new file mode 100644 index 000000000..917b0cdbe --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceHideShowWithPrintedRector/fixture/no_change_wrong_arg_count.php.inc @@ -0,0 +1,15 @@ + +----- + diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/ReplaceLocaleTranslationPathConfigRectorTest.php b/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/ReplaceLocaleTranslationPathConfigRectorTest.php new file mode 100644 index 000000000..8e9e76c49 --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/ReplaceLocaleTranslationPathConfigRectorTest.php @@ -0,0 +1,46 @@ +make(DrupalRectorSettings::class)->setDrupalVersion('99.99.99'); + $this->doTestFile($filePath); + } + + /** + * @return \Iterator<> + */ + public static function provideData(): \Iterator + { + return self::yieldFilesFromDirectory(__DIR__.'/fixture'); + } + + #[\PHPUnit\Framework\Attributes\DataProvider('provideDataBelowVersion')] + public function testBelowVersion(string $filePath): void + { + static::getContainer()->make(DrupalRectorSettings::class)->setDrupalVersion('1.0.0'); + $this->doTestFile($filePath); + } + + /** + * @return \Iterator<> + */ + public static function provideDataBelowVersion(): \Iterator + { + return self::yieldFilesFromDirectory(__DIR__.'/fixture-below-version'); + } + + public function provideConfigFilePath(): string + { + return __DIR__.'/config/configured_rule.php'; + } +} diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/config/configured_rule.php b/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/config/configured_rule.php new file mode 100644 index 000000000..5d929ab35 --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/config/configured_rule.php @@ -0,0 +1,14 @@ +get('translation.path'); +?> +----- +get('translation.path'); +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/fixture-below-version/config_factory_static.php.inc b/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/fixture-below-version/config_factory_static.php.inc new file mode 100644 index 000000000..82decc6de --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/fixture-below-version/config_factory_static.php.inc @@ -0,0 +1,9 @@ +get('locale.settings')->get('translation.path'); +?> +----- +get('locale.settings')->get('translation.path'); +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/fixture-below-version/this_config_method.php.inc b/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/fixture-below-version/this_config_method.php.inc new file mode 100644 index 000000000..b5047e6ba --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/fixture-below-version/this_config_method.php.inc @@ -0,0 +1,29 @@ +config('locale.settings')->get('translation.path'); + } +} +?> +----- +config('locale.settings')->get('translation.path'); + } +} +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/fixture/basic.php.inc b/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/fixture/basic.php.inc new file mode 100644 index 000000000..9f1a5c1bf --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/fixture/basic.php.inc @@ -0,0 +1,9 @@ +get('translation.path'); +?> +----- + \Drupal\Core\Site\Settings::get('locale_translation_path', 'public://translations'), fn() => \Drupal::config('locale.settings')->get('translation.path')); +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/fixture/config_factory_static.php.inc b/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/fixture/config_factory_static.php.inc new file mode 100644 index 000000000..463efde25 --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/fixture/config_factory_static.php.inc @@ -0,0 +1,9 @@ +get('locale.settings')->get('translation.path'); +?> +----- + \Drupal\Core\Site\Settings::get('locale_translation_path', 'public://translations'), fn() => \Drupal::configFactory()->get('locale.settings')->get('translation.path')); +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/fixture/no_change_standalone_get.php.inc b/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/fixture/no_change_standalone_get.php.inc new file mode 100644 index 000000000..106f5463e --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/fixture/no_change_standalone_get.php.inc @@ -0,0 +1,17 @@ +get() without a recognisable chained loader — not transformed. +// The rule deliberately matches only chained config-accessor expressions to keep the +// rewrite obviously correct; users with the standalone pattern can refactor manually. +/** @var \Drupal\Core\Config\ImmutableConfig $config */ +$path = $config->get('translation.path'); +?> +----- +get() without a recognisable chained loader — not transformed. +// The rule deliberately matches only chained config-accessor expressions to keep the +// rewrite obviously correct; users with the standalone pattern can refactor manually. +/** @var \Drupal\Core\Config\ImmutableConfig $config */ +$path = $config->get('translation.path'); +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/fixture/no_change_unrelated_config.php.inc b/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/fixture/no_change_unrelated_config.php.inc new file mode 100644 index 000000000..a70334f6f --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/fixture/no_change_unrelated_config.php.inc @@ -0,0 +1,11 @@ +get('translation.path'); +?> +----- +get('translation.path'); +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/fixture/no_change_unrelated_key.php.inc b/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/fixture/no_change_unrelated_key.php.inc new file mode 100644 index 000000000..020884a59 --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/fixture/no_change_unrelated_key.php.inc @@ -0,0 +1,11 @@ +get('javascript.directory'); +?> +----- +get('javascript.directory'); +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/fixture/this_config_method.php.inc b/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/fixture/this_config_method.php.inc new file mode 100644 index 000000000..56f72423d --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ReplaceLocaleTranslationPathConfigRector/fixture/this_config_method.php.inc @@ -0,0 +1,29 @@ +config('locale.settings')->get('translation.path'); + } +} +?> +----- + \Drupal\Core\Site\Settings::get('locale_translation_path', 'public://translations'), fn() => $this->config('locale.settings')->get('translation.path')); + } +} +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/ViewsBlockItemsPerPageNoneToNullRector/ViewsBlockItemsPerPageNoneToNullRectorTest.php b/tests/src/Drupal11/Rector/Deprecation/ViewsBlockItemsPerPageNoneToNullRector/ViewsBlockItemsPerPageNoneToNullRectorTest.php new file mode 100644 index 000000000..3c7c67fcc --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ViewsBlockItemsPerPageNoneToNullRector/ViewsBlockItemsPerPageNoneToNullRectorTest.php @@ -0,0 +1,26 @@ +doTestFile($filePath); + } + + public static function provideData(): \Iterator + { + return self::yieldFilesFromDirectory(__DIR__.'/fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__.'/config/configured_rule.php'; + } +} diff --git a/tests/src/Drupal11/Rector/Deprecation/ViewsBlockItemsPerPageNoneToNullRector/config/configured_rule.php b/tests/src/Drupal11/Rector/Deprecation/ViewsBlockItemsPerPageNoneToNullRector/config/configured_rule.php new file mode 100644 index 000000000..422bb753e --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ViewsBlockItemsPerPageNoneToNullRector/config/configured_rule.php @@ -0,0 +1,11 @@ +setConfigurationValue('items_per_page', 'none'); +?> +----- +setConfigurationValue('items_per_page', NULL); +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/ViewsBlockItemsPerPageNoneToNullRector/fixture/no_change_unrelated.php.inc b/tests/src/Drupal11/Rector/Deprecation/ViewsBlockItemsPerPageNoneToNullRector/fixture/no_change_unrelated.php.inc new file mode 100644 index 000000000..e3a619bd9 --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ViewsBlockItemsPerPageNoneToNullRector/fixture/no_change_unrelated.php.inc @@ -0,0 +1,33 @@ +setConfigurationValue('items_per_page', 'none'); + +// Different first arg — must not change. +/** @var \Drupal\views\Plugin\Block\ViewsBlockBase $block */ +$block->setConfigurationValue('label', 'none'); + +// Different second arg value — must not change. +$block->setConfigurationValue('items_per_page', 5); + +// Different method name on the same type — must not change. +$block->setConfiguration(['items_per_page' => 'none']); +?> +----- +setConfigurationValue('items_per_page', 'none'); + +// Different first arg — must not change. +/** @var \Drupal\views\Plugin\Block\ViewsBlockBase $block */ +$block->setConfigurationValue('label', 'none'); + +// Different second arg value — must not change. +$block->setConfigurationValue('items_per_page', 5); + +// Different method name on the same type — must not change. +$block->setConfiguration(['items_per_page' => 'none']); +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/ViewsConfigUpdaterClassResolverToServiceRector/ViewsConfigUpdaterClassResolverToServiceRectorTest.php b/tests/src/Drupal11/Rector/Deprecation/ViewsConfigUpdaterClassResolverToServiceRector/ViewsConfigUpdaterClassResolverToServiceRectorTest.php new file mode 100644 index 000000000..463ea11ab --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ViewsConfigUpdaterClassResolverToServiceRector/ViewsConfigUpdaterClassResolverToServiceRectorTest.php @@ -0,0 +1,40 @@ +make(DrupalRectorSettings::class)->setDrupalVersion('99.99.99'); + $this->doTestFile($filePath); + } + + public static function provideData(): \Iterator + { + return self::yieldFilesFromDirectory(__DIR__.'/fixture'); + } + + #[\PHPUnit\Framework\Attributes\DataProvider('provideDataBelowVersion')] + public function testBelowVersion(string $filePath): void + { + static::getContainer()->make(DrupalRectorSettings::class)->setDrupalVersion('1.0.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'; + } +} diff --git a/tests/src/Drupal11/Rector/Deprecation/ViewsConfigUpdaterClassResolverToServiceRector/config/configured_rule.php b/tests/src/Drupal11/Rector/Deprecation/ViewsConfigUpdaterClassResolverToServiceRector/config/configured_rule.php new file mode 100644 index 000000000..e154d3448 --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ViewsConfigUpdaterClassResolverToServiceRector/config/configured_rule.php @@ -0,0 +1,14 @@ +setDeprecationsEnabled(FALSE); +} + +function example_fqcn() { + $updater = \Drupal::classResolver(\Drupal\views\ViewsConfigUpdater::class); + $updater->setDeprecationsEnabled(FALSE); +} +?> +----- +setDeprecationsEnabled(FALSE); +} + +function example_fqcn() { + $updater = \Drupal::classResolver(\Drupal\views\ViewsConfigUpdater::class); + $updater->setDeprecationsEnabled(FALSE); +} +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/ViewsConfigUpdaterClassResolverToServiceRector/fixture/basic.php.inc b/tests/src/Drupal11/Rector/Deprecation/ViewsConfigUpdaterClassResolverToServiceRector/fixture/basic.php.inc new file mode 100644 index 000000000..2bbe0aeb0 --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ViewsConfigUpdaterClassResolverToServiceRector/fixture/basic.php.inc @@ -0,0 +1,29 @@ +setDeprecationsEnabled(FALSE); +} + +function example_fqcn() { + $updater = \Drupal::classResolver(\Drupal\views\ViewsConfigUpdater::class); + $updater->setDeprecationsEnabled(FALSE); +} +?> +----- + \Drupal::service(ViewsConfigUpdater::class), fn() => \Drupal::classResolver(ViewsConfigUpdater::class)); + $view_config_updater->setDeprecationsEnabled(FALSE); +} + +function example_fqcn() { + $updater = \Drupal\Component\Utility\DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '11.3.0', fn() => \Drupal::service(\Drupal\views\ViewsConfigUpdater::class), fn() => \Drupal::classResolver(\Drupal\views\ViewsConfigUpdater::class)); + $updater->setDeprecationsEnabled(FALSE); +} +?> diff --git a/tests/src/Drupal11/Rector/Deprecation/ViewsConfigUpdaterClassResolverToServiceRector/fixture/no_change_unrelated.php.inc b/tests/src/Drupal11/Rector/Deprecation/ViewsConfigUpdaterClassResolverToServiceRector/fixture/no_change_unrelated.php.inc new file mode 100644 index 000000000..88d058b68 --- /dev/null +++ b/tests/src/Drupal11/Rector/Deprecation/ViewsConfigUpdaterClassResolverToServiceRector/fixture/no_change_unrelated.php.inc @@ -0,0 +1,63 @@ + +----- + diff --git a/tests/src/Rector/Deprecation/FunctionToServiceRector/config/configured_rule.php b/tests/src/Rector/Deprecation/FunctionToServiceRector/config/configured_rule.php index e9470ee86..4c8fa67d8 100644 --- a/tests/src/Rector/Deprecation/FunctionToServiceRector/config/configured_rule.php +++ b/tests/src/Rector/Deprecation/FunctionToServiceRector/config/configured_rule.php @@ -54,9 +54,9 @@ new FunctionToServiceConfiguration('11.4.0', 'locale_translation_http_check', 'Drupal\locale\File\LocaleFileManager', 'checkRemoteFileStatus'), new FunctionToServiceConfiguration('11.4.0', 'locale_translate_delete_translation_files', 'Drupal\locale\File\LocaleFileManager', 'deleteTranslationFiles'), new FunctionToServiceConfiguration('11.4.0', 'locale_translation_download_source', 'Drupal\locale\File\LocaleFileManager', 'downloadTranslationSource'), - // https://www.drupal.org/node/3566774 (Drupal 11.4) - new FunctionToServiceConfiguration('11.4.0', '_media_library_media_type_form_submit', 'Drupal\media_library\Hook\MediaLibraryHooks', 'mediaTypeFormSubmit'), - new FunctionToServiceConfiguration('11.4.0', '_media_library_views_form_media_library_after_build', 'Drupal\media_library\Hook\MediaLibraryHooks', 'viewsFormAfterBuild'), + // https://www.drupal.org/node/3570839 (Drupal 11.4) + new FunctionToServiceConfiguration('11.4.0', '_media_library_media_type_form_submit', 'Drupal\media_library\Hook\MediaLibraryHooks', 'mediaTypeFormSubmit', true), + new FunctionToServiceConfiguration('11.4.0', '_media_library_views_form_media_library_after_build', 'Drupal\media_library\Hook\MediaLibraryHooks', 'viewsFormAfterBuild', true), // https://www.drupal.org/node/3574727 (Drupal 11.4) new FunctionToServiceConfiguration('11.4.0', 'language_process_language_select', 'Drupal\language\Hook\LanguageHooks', 'processLanguageSelect'), // https://www.drupal.org/node/3566792 (Drupal 11.4) diff --git a/tests/src/Rector/Deprecation/FunctionToServiceRector/fixture/media_library_procedural_functions.php.inc b/tests/src/Rector/Deprecation/FunctionToServiceRector/fixture/media_library_procedural_functions.php.inc index e48c132f8..fb0a07f31 100644 --- a/tests/src/Rector/Deprecation/FunctionToServiceRector/fixture/media_library_procedural_functions.php.inc +++ b/tests/src/Rector/Deprecation/FunctionToServiceRector/fixture/media_library_procedural_functions.php.inc @@ -9,7 +9,7 @@ function example($form, $form_state) { \Drupal::service('Drupal\media_library\Hook\MediaLibraryHooks')->mediaTypeFormSubmit($form, $form_state), fn() => _media_library_media_type_form_submit($form, $form_state)); - $result = \Drupal\Component\Utility\DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '11.4.0', fn() => \Drupal::service('Drupal\media_library\Hook\MediaLibraryHooks')->viewsFormAfterBuild($form, $form_state), fn() => _media_library_views_form_media_library_after_build($form, $form_state)); + \Drupal\Component\Utility\DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '11.4.0', fn() => \Drupal::service(\Drupal\media_library\Hook\MediaLibraryHooks::class)->mediaTypeFormSubmit($form, $form_state), fn() => _media_library_media_type_form_submit($form, $form_state)); + $result = \Drupal\Component\Utility\DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '11.4.0', fn() => \Drupal::service(\Drupal\media_library\Hook\MediaLibraryHooks::class)->viewsFormAfterBuild($form, $form_state), fn() => _media_library_views_form_media_library_after_build($form, $form_state)); } ?> diff --git a/tests/src/Rector/Deprecation/FunctionToStaticRector/config/configured_rule.php b/tests/src/Rector/Deprecation/FunctionToStaticRector/config/configured_rule.php index 64f0d2168..db72c63e6 100644 --- a/tests/src/Rector/Deprecation/FunctionToStaticRector/config/configured_rule.php +++ b/tests/src/Rector/Deprecation/FunctionToStaticRector/config/configured_rule.php @@ -25,7 +25,7 @@ new FunctionToStaticConfiguration('11.3.0', 'file_system_settings_submit', 'Drupal\file\Hook\FileHooks', 'settingsSubmit'), // https://www.drupal.org/node/3534089 (Drupal 11.3) new FunctionToStaticConfiguration('11.3.0', 'file_managed_file_submit', 'Drupal\file\Element\ManagedFile', 'submit'), - // https://www.drupal.org/node/3566774 (Drupal 11.4) + // https://www.drupal.org/node/3570839 (Drupal 11.4) new FunctionToStaticConfiguration('11.4.0', '_media_library_configure_form_display', 'Drupal\media_library\MediaLibraryDisplayManager', 'configureFormDisplay'), new FunctionToStaticConfiguration('11.4.0', '_media_library_configure_view_display', 'Drupal\media_library\MediaLibraryDisplayManager', 'configureViewDisplay'), // https://www.drupal.org/node/3495966 (Drupal 11.2)