Problem/Motivation
When using drupal/menu_normalizer 2.1.0 with Drupal 11 and Symfony 7, a PHP Fatal error occurs on cache rebuild (drush cr) because the normalize() method signature in MenuLinkNormalizer and MenuLinkTreeNormalizer is incompatible with the updated NormalizerInterface in Symfony 7.
PHP Fatal error: Declaration of Drupal\menu_normalizer\Normalizer\MenuLinkNormalizer::normalize($object, $format = null, array $context = []) must be compatible with Symfony\Component\Serializer\Normalizer\NormalizerInterface::normalize(mixed $data, ?string $format = null, array $context = []): ArrayObject|array|string|int|float|bool|null in .../menu_normalizer/src/Normalizer/MenuLinkNormalizer.php on line 23
Steps to reproduce
- Install Drupal 11 with Symfony 7
- Enable
menu_normalizer2.1.0 - Run
drush cr - PHP Fatal error occurs
Proposed resolution
Update the normalize() method signature in both normalizer classes to match Symfony 7's NormalizerInterface:
public function normalize(mixed $object, ?string $format = NULL, array $context = []): array|\ArrayObject|string|int|float|bool|null {
Files to update:
src/Normalizer/MenuLinkNormalizer.phpsrc/Normalizer/MenuLinkTreeNormalizer.php
Remaining tasks
Apply fix and release a new version compatible with Drupal 11 / Symfony 7.
User interface changes
None.
API changes
None.
Data model changes
None.
Issue fork menu_normalizer-3584180
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
- 3584180-drupal-11-symfony-7-fatal-error
changes, plain diff MR !9
- 2.x
changes, plain diff MR !7
Comments
Comment #4
brian.seek commentedAdded a MR to update the normalize method signature as suggested.
Comment #5
brian.seek commentedComment #6
brian.seek commentedComment #10
batigolixI opened MR !9 as an alternative to MR !7 by @brian.seek.
It contains the same Symfony 7 fix (
normalize()signature +getSupportedTypes()), minus themeta_data→metadatarename — that belongs in a separate issue. Also updated tests to useMenuLinkMock::createMock()(renamed in D11).Comment #12
fabianderijkConfirmed the fatal on 2.1.0 and confirmed MR !9 resolves it. One note on the reproduction steps: drush cr on its own does not trigger the fatal, because RegisterSerializationClassesCompilerPass only collects tagged service IDs and never loads the classes. The fatal appears as soon as the serializer service is actually instantiated — so it will surface during a cache rebuild only if a module such as jsonapi or rest instantiates it. A minimal reproduction is drush php:eval '\Drupal::service("serializer");' with serialization and menu_normalizer enabled.
I pushed two follow-up commits to the MR branch:
Results after those two commits: PHPUnit 4 tests / 23 assertions pass, phpcs --standard=Drupal,DrupalPractice reports zero issues, drush cr succeeds on a cold cache (cache tables truncated), the serializer instantiates, and normalizing a real MenuLinkTreeElement from the admin menu produces the expected nested structure. No new entries in the PHP watchdog log.
Two pre-existing problems I noticed while testing, both out of scope for this issue — I can open separate issues if wanted:
- delete_route and edit_route are not passed through $this->serializer->normalize(), so raw Url objects end up in the returned array and serialize to "edit_route":{} in JSON.
- menu_normalizer.info.yml does not declare dependencies: - drupal:serialization, even though both normalizers extend a class from that module. drush pmu serialization succeeds while menu_normalizer stays enabled.
With the two follow-up commits included, this is RTBC from my side.
Comment #13
batigolixThanks. I will merge this