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 1302ac2..4f91819 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,26 @@ 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 { + /** @var array $classUses */ + $classUses = \class_uses($class) ?: []; + $traits = \array_merge($classUses, $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(); diff --git a/src/Resources/assets/js/plugins/menuSearch.js b/src/Resources/assets/js/plugins/menuSearch.js index 812165a..0a38010 100644 --- a/src/Resources/assets/js/plugins/menuSearch.js +++ b/src/Resources/assets/js/plugins/menuSearch.js @@ -1,14 +1,9 @@ 'use strict'; import '../jquery-global'; import $ from 'jquery'; -import select2Init from 'select2/dist/js/select2'; +import 'select2/dist/js/select2'; import observer from "../../component/observer"; -// Select2 UMD CommonJS branch exports a factory function — call it to register $.fn.select2 -if (typeof select2Init === 'function') { - select2Init(window, $); -} - $.fn.select2.defaults.set("theme", "bootstrap-5"); const Select = { diff --git a/src/Resources/assets/js/select2/index.js b/src/Resources/assets/js/select2/index.js index 49f0448..3f2757b 100644 --- a/src/Resources/assets/js/select2/index.js +++ b/src/Resources/assets/js/select2/index.js @@ -2,14 +2,9 @@ import '../jquery-global'; import './index.scss'; import $ from 'jquery'; -import select2Init from 'select2/dist/js/select2'; +import 'select2/dist/js/select2'; import observer from "../../component/observer"; -// Select2 UMD CommonJS branch exports a factory function — call it to register $.fn.select2 -if (typeof select2Init === 'function') { - select2Init(window, $); -} - $.fn.select2.defaults.set("theme", "bootstrap-5"); observer.observe('select:not(.flatpickr-monthDropdown-months):not([readonly]):not(.no-plugin):not(.no-auto-select2)', (el) => { diff --git a/src/Resources/assets/js/select2/theme/bootstrap/layout.scss b/src/Resources/assets/js/select2/theme/bootstrap/layout.scss index 72926dc..14487b9 100644 --- a/src/Resources/assets/js/select2/theme/bootstrap/layout.scss +++ b/src/Resources/assets/js/select2/theme/bootstrap/layout.scss @@ -12,7 +12,8 @@ // input-group .input-group .select2-container--bootstrap-5 { - flex-grow: 1; + flex: 1 1 0%; + min-width: 0; } // BS5: input-group-prepend removed, use :not(:first-child) selector 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 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 -%} 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}) %}