From 7083ac4db547c3ac4dc406bcb5682239232d73fb Mon Sep 17 00:00:00 2001 From: dev Date: Mon, 2 Mar 2026 12:57:23 +0300 Subject: [PATCH 1/7] [fix] read icon from extras in actions menu template IconExtension moves icon from options to extras['icon']. Use item.getExtra('icon') instead of item.option('icon'). --- src/Resources/views/menu/actions.html.twig | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Resources/views/menu/actions.html.twig b/src/Resources/views/menu/actions.html.twig index 3ec7502..009b699 100644 --- a/src/Resources/views/menu/actions.html.twig +++ b/src/Resources/views/menu/actions.html.twig @@ -17,7 +17,9 @@ {%- macro nav_item(item, attr) -%} - {%- if item.option('icon') -%} + {%- set icon = item.getExtra('icon') -%} + + {%- if icon -%} {%- set attr = attr|merge({ 'data-bs-toggle': 'tooltip', 'title': item.name|trans, @@ -33,8 +35,8 @@ {%- set attr = attr|merge({class: (attr.class|default('')) ~ ' ' ~ classes|join(' ')}) -%} - {%- if item.option('icon') -%} - + {%- if icon -%} + {%- else -%} {{- item.name|trans -}} {%- endif -%} From ba9e550e297c30b97719fa775cb98a57fc137f5f Mon Sep 17 00:00:00 2001 From: dev Date: Mon, 2 Mar 2026 14:56:53 +0300 Subject: [PATCH 2/7] [fix] replace MetaBundle namespace refs with Meta namespace - MetaDto: use ChamberOrchestra\Meta\Entity\Helper\RobotsBehaviour - MetaType: same namespace fix, remove @phpstan-ignore comments - CrudUtils: replace MetaInterface instanceof check with MetaTrait detection via classUsesRecursive(); use reflection for property access instead of getter calls Co-Authored-By: Claude Sonnet 4.6 --- src/Form/Dto/MetaDto.php | 4 ++-- src/Form/Type/MetaType.php | 14 +++++------ src/Processor/Utils/CrudUtils.php | 40 ++++++++++++++++++++++--------- 3 files changed, 38 insertions(+), 20 deletions(-) diff --git a/src/Form/Dto/MetaDto.php b/src/Form/Dto/MetaDto.php index 5cf7127..1a19974 100644 --- a/src/Form/Dto/MetaDto.php +++ b/src/Form/Dto/MetaDto.php @@ -11,13 +11,13 @@ namespace ChamberOrchestra\CmsBundle\Form\Dto; +use ChamberOrchestra\Meta\Entity\Helper\RobotsBehaviour; use Symfony\Component\HttpFoundation\File\File; class MetaDto extends AbstractDto { public ?string $title = null; - /** @phpstan-ignore class.notFound */ - public ?\ChamberOrchestra\MetaBundle\Entity\Helper\RobotsBehaviour $robotsBehaviour = null; + public ?RobotsBehaviour $robotsBehaviour = null; public ?string $metaTitle = null; public ?string $metaDescription = null; public ?string $metaKeywords = null; diff --git a/src/Form/Type/MetaType.php b/src/Form/Type/MetaType.php index 2bb1080..1c5d626 100644 --- a/src/Form/Type/MetaType.php +++ b/src/Form/Type/MetaType.php @@ -12,7 +12,7 @@ namespace ChamberOrchestra\CmsBundle\Form\Type; use ChamberOrchestra\CmsBundle\Form\Dto\MetaDto; -use ChamberOrchestra\MetaBundle\Entity\Helper\RobotsBehaviour; +use ChamberOrchestra\Meta\Entity\Helper\RobotsBehaviour; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\EnumType; use Symfony\Component\Form\Extension\Core\Type\TextareaType; @@ -55,13 +55,13 @@ public function buildForm(FormBuilderInterface $builder, array $options): void ], ]) ->add('robotsBehaviour', EnumType::class, [ - 'class' => RobotsBehaviour::class, // @phpstan-ignore class.notFound + 'class' => RobotsBehaviour::class, 'required' => true, - 'choice_label' => static fn (RobotsBehaviour $case): string => match ($case) { // @phpstan-ignore class.notFound, match.unhandled - RobotsBehaviour::IndexFollow => 'robots_behaviour.indexfollow', // @phpstan-ignore class.notFound - RobotsBehaviour::IndexNoFollow => 'robots_behaviour.indexnofollow', // @phpstan-ignore class.notFound - RobotsBehaviour::NoIndexFollow => 'robots_behaviour.noindexfollow', // @phpstan-ignore class.notFound - RobotsBehaviour::NoIndexNoFollow => 'robots_behaviour.noindexnofollow', // @phpstan-ignore class.notFound + 'choice_label' => static fn (RobotsBehaviour $case): string => match ($case) { + RobotsBehaviour::IndexFollow => 'robots_behaviour.indexfollow', + RobotsBehaviour::IndexNoFollow => 'robots_behaviour.indexnofollow', + RobotsBehaviour::NoIndexFollow => 'robots_behaviour.noindexfollow', + RobotsBehaviour::NoIndexNoFollow => 'robots_behaviour.noindexnofollow', }, 'constraints' => [ new NotBlank(), diff --git a/src/Processor/Utils/CrudUtils.php b/src/Processor/Utils/CrudUtils.php index 9d31bd1..72e2795 100644 --- a/src/Processor/Utils/CrudUtils.php +++ b/src/Processor/Utils/CrudUtils.php @@ -16,7 +16,7 @@ use ChamberOrchestra\CmsBundle\Form\Dto\DtoInterface; use ChamberOrchestra\CmsBundle\Processor\Instantiator; use ChamberOrchestra\CmsBundle\Processor\Reflector; -use ChamberOrchestra\MetaBundle\Entity\MetaInterface; +use ChamberOrchestra\Meta\Entity\MetaTrait; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\Common\Util\ClassUtils; @@ -147,7 +147,7 @@ public function sync(object $source, object $target): void $this->setPropertyValue($target, $name, $sourceValue); } - if ($target instanceof MetaInterface) { // @phpstan-ignore class.notFound + if (\in_array(MetaTrait::class, $this->classUsesRecursive($target::class), true)) { $refl = $this->reflector->create($target); $props = $refl->getAccessibleProperties(); @@ -166,34 +166,35 @@ public function sync(object $source, object $target): void return null; }; - if (!$target->getTitle()) { // @phpstan-ignore class.notFound + $titleProp = $refl->getAccessibleProperty('title'); + if (empty($titleProp->getValue($target))) { $value = $getFirstNonEmptyValue('name'); if ($value) { - $metaTitleProp = $refl->getAccessibleProperty('title'); - $metaTitleProp->setValue($target, $value); + $titleProp->setValue($target, $value); } } - if (!$target->getMetaTitle()) { // @phpstan-ignore class.notFound + $metaTitleProp = $refl->getAccessibleProperty('metaTitle'); + if (empty($metaTitleProp->getValue($target))) { $value = $getFirstNonEmptyValue('title', 'name'); if ($value) { - $metaTitleProp = $refl->getAccessibleProperty('metaTitle'); $metaTitleProp->setValue($target, $value); } } - if (!$target->getMetaDescription()) { // @phpstan-ignore class.notFound + $metaDescProp = $refl->getAccessibleProperty('metaDescription'); + if (empty($metaDescProp->getValue($target))) { $value = $getFirstNonEmptyValue('description'); if ($value) { /** @var string $valueStr */ $valueStr = $value; $value = (string) (new UnicodeString(\strip_tags($valueStr)))->truncate(255); - $metaDescProp = $refl->getAccessibleProperty('metaDescription'); $metaDescProp->setValue($target, $value); } } - if (!$target->getMetaImage()) { // @phpstan-ignore class.notFound + $metaImageProp = $refl->getAccessibleProperty('metaImage'); + if (empty($metaImageProp->getValue($target))) { foreach ($props as $prop) { if (!\str_contains(\mb_strtolower($prop->getName()), 'image')) { continue; @@ -206,7 +207,6 @@ public function sync(object $source, object $target): void $image = $prop->getValue($target); if ($image instanceof File) { $newFile = $this->copyFile($image); - $metaImageProp = $refl->getAccessibleProperty('metaImage'); $metaImageProp->setValue($target, $newFile); break; } @@ -412,6 +412,24 @@ private function getIntersectedProperties(object $source, object $target): array return \array_values(\array_intersect($sourceProperties, $targetProperties)); } + /** + * @param class-string $class + * + * @return array + */ + private function classUsesRecursive(string $class): array + { + $traits = []; + do { + $traits = \array_merge(\class_uses($class) ?: [], $traits); + } while ($class = \get_parent_class($class)); + foreach ($traits as $trait) { + $traits = \array_merge($this->classUsesRecursive($trait), $traits); + } + + return $traits; + } + public function copyFile(File $file): File { $originalPath = $file->getRealPath() ?: $file->getPathname(); From 472b32f35fe7165d0992d2241413a59e3af6ab02 Mon Sep 17 00:00:00 2001 From: dev Date: Mon, 2 Mar 2026 16:55:42 +0300 Subject: [PATCH 3/7] [fix] add missing meta field and robots_behaviour translations Co-Authored-By: Claude Sonnet 4.6 --- src/Resources/translations/cms+intl-icu.en.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/Resources/translations/cms+intl-icu.en.yaml b/src/Resources/translations/cms+intl-icu.en.yaml index 09728ff..3a3140d 100644 --- a/src/Resources/translations/cms+intl-icu.en.yaml +++ b/src/Resources/translations/cms+intl-icu.en.yaml @@ -102,6 +102,21 @@ security: email: E-mail password: Password +meta: + field: + title: Title + metaTitle: Meta Title + metaDescription: Meta Description + metaKeywords: Meta Keywords + metaImage: Meta Image + robotsBehaviour: Robots Behaviour + +robots_behaviour: + indexfollow: 'Index, Follow' + indexnofollow: 'Index, No Follow' + noindexfollow: 'No Index, Follow' + noindexnofollow: 'No Index, No Follow' + crud: flash: created: Object has been successfully created From 1020c3bd7f00403352acd16c7b6523f8ad22235f Mon Sep 17 00:00:00 2001 From: dev Date: Mon, 2 Mar 2026 18:14:45 +0300 Subject: [PATCH 4/7] [fix] pagination/base.html.twig: sync var names with pagination-bundle 8.0 RangeType::buildView() now sets: - parameter (was pageParameter) - start / end (were startPage / endPage) - previous/next as null instead of undefined Co-Authored-By: Claude Sonnet 4.6 --- src/Resources/views/pagination/base.html.twig | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Resources/views/pagination/base.html.twig b/src/Resources/views/pagination/base.html.twig index fd7a3f4..ac9f5cc 100644 --- a/src/Resources/views/pagination/base.html.twig +++ b/src/Resources/views/pagination/base.html.twig @@ -2,8 +2,8 @@ @var current int @var pagesCount int @var elementsCount int, -@var startPage int -@var endPage int +@var start int +@var end int @var previous int @var next int @var pages array @@ -12,21 +12,21 @@ {%- if pagesCount > 1 %} {%- set _route = app.request.attributes.get("_route") %} {%- set _route_params = app.request.attributes.get("_route_params")|merge(app.request.query.all()) %} - {%- set _route_params = _route_params|merge({(pageParameter): null}) %} + {%- set _route_params = _route_params|merge({(parameter): null}) %}