#3581133: Automate MR review using PHPCS: disallow `\Drupal::service('something')`, require `\Drupal::service(Something::class)` whenever possible, with automatic fixing
Problem
It's easy to use magic strings like 'entity_type.manager' when calling \Drupal::service() or $this->container->get(). These magic strings:
- defeat static analysis (PHPStan, IDE refactoring)
- are typo-prone with zero compile-time feedback
- obscure the actual type being retrieved
Solution
Add a new PHPCS sniff Canvas.Services.ClassServiceId that:
-
Forbids string-based service IDs:
// ❌ Forbidden: $this->container->get('entity_type.manager') \Drupal::service('entity_type.manager') -
Requires the equivalent
::classconstant:// ✅ Required: $this->container->get(EntityTypeManagerInterface::class) \Drupal::service(EntityTypeManagerInterface::class) -
Auto-fixes violations via
phpcbf:- Replaces the string with
ShortName::class - Adds the
useimport in alphabetical order (respectsAlphabeticallySortedUses) - Falls back to
\Full\Qualified\Name::classon short-name collisions
- Replaces the string with
How it works
The sniff parses *.services.yml files at runtime to build a mapping from string service IDs to their FQCN. It prefers interface aliases (e.g. EntityTypeManagerInterface) over concrete classes (e.g. EntityTypeManager).
Scanned files:
core/core.services.ymlcore/modules/**/*.services.yml(all core modules and their test modules)canvas.services.ymlmodules/**/*.services.yml(all Canvas submodules and their test modules)
Detected patterns:
$this->container->get('service.id')$container->get('service.id')\Drupal::service('service.id')
Skipped (no false positives):
- Services with no known FQCN mapping (e.g.
kernel,uuid) ->get()calls on non-container objects (e.g.$entity->get(...),$config->get(...))- Strings that already use
::class
Limitations
- Services registered dynamically via
ServiceProviderInterface::register()or altered viaServiceModifierInterface::alter()are NOT detected — they don't appear in any*.services.ymlfile. - Services from contrib/custom modules outside of Canvas are not scanned. andards/Canvas/ruleset.xml` | Register the new rule |
AI-Generated: Yes
Testing instructions
- CI passes
- Changes made to
/srcand/testsin MR look reasonable
Closes #3581133
Edited by Wim Leers