diff --git a/.gitignore b/.gitignore index ea8d6aa9..43469c37 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,6 @@ /dev.php /install.php /clear_cache.php -/pimple.json /assets project_env.sh diff --git a/.travis/backoffice_assets.sh b/.travis/backoffice_assets.sh deleted file mode 100644 index 92ba88c8..00000000 --- a/.travis/backoffice_assets.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -x -cd src || exit 1; -yarn install --pure-lockfile -yarn run install -yarn run build diff --git a/.travis/composer_install.sh b/.travis/composer_install.sh deleted file mode 100644 index 628aaebb..00000000 --- a/.travis/composer_install.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -x -phpenv config-rm xdebug.ini; -curl -s http://getcomposer.org/installer | php; -php composer.phar install --dev --no-interaction; diff --git a/.travis/php_lint.sh b/.travis/php_lint.sh deleted file mode 100644 index 624af292..00000000 --- a/.travis/php_lint.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -x -vendor/bin/phpcs --report=full --report-file=./report.txt -p ./ || exit 1; -vendor/bin/phpstan analyse -c phpstan.neon || exit 1; -#vendor/bin/console lint:twig || exit 1; -#vendor/bin/console lint:twig src/Resources/views || exit 1; diff --git a/LICENSE.md b/LICENSE.md index 747e48b2..01cd7778 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright © 2023 Ambroise Maupate, Julien Blanchet +Copyright © 2024 Ambroise Maupate, Julien Blanchet Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/composer.json b/composer.json index 0d18956c..e5bbf990 100644 --- a/composer.json +++ b/composer.json @@ -28,48 +28,48 @@ "role": "Frontend developer" } ], + "minimum-stability": "dev", "prefer-stable": true, "require": { "php": ">=8.1", "ext-zip": "*", - "doctrine/orm": "~2.17.0", + "doctrine/orm": "~2.19.0", "guzzlehttp/guzzle": "^7.2.0", "jms/serializer": "^3.9.0", "league/flysystem": "^3.0", - "pimple/pimple": "^3.3.1", "ramsey/uuid": "^4.7", - "roadiz/compat-bundle": "2.2.*", - "roadiz/core-bundle": "2.2.*", - "roadiz/doc-generator": "2.2.*", - "roadiz/documents": "2.2.*", - "roadiz/dts-generator": "2.2.*", - "roadiz/markdown": "2.2.*", - "roadiz/models": "2.2.*", + "roadiz/compat-bundle": "2.3.*", + "roadiz/core-bundle": "2.3.*", + "roadiz/doc-generator": "2.3.*", + "roadiz/documents": "2.3.*", + "roadiz/dts-generator": "2.3.*", + "roadiz/markdown": "2.3.*", + "roadiz/models": "2.3.*", "roadiz/nodetype-contracts": "~1.1.2", - "roadiz/openid": "2.2.*", - "roadiz/rozier-bundle": "2.2.*", - "symfony/asset": "5.4.*", - "symfony/filesystem": "5.4.*", - "symfony/form": "5.4.*", - "symfony/http-foundation": "5.4.*", - "symfony/http-kernel": "5.4.*", - "symfony/routing": "5.4.*", - "symfony/security-core": "5.4.*", - "symfony/security-csrf": "5.4.*", - "symfony/security-http": "5.4.*", - "symfony/translation": "5.4.*", - "symfony/validator": "5.4.*", - "symfony/workflow": "5.4.*", - "symfony/yaml": "5.4.*", + "roadiz/openid": "2.3.*", + "roadiz/rozier-bundle": "2.3.*", + "symfony/asset": "6.4.*", + "symfony/filesystem": "6.4.*", + "symfony/form": "6.4.*", + "symfony/http-foundation": "6.4.*", + "symfony/http-kernel": "6.4.*", + "symfony/routing": "6.4.*", + "symfony/security-core": "6.4.*", + "symfony/security-csrf": "6.4.*", + "symfony/security-http": "6.4.*", + "symfony/translation": "6.4.*", + "symfony/validator": "6.4.*", + "symfony/workflow": "6.4.*", + "symfony/yaml": "6.4.*", "twig/twig": "^3.1" }, "require-dev": { "php-coveralls/php-coveralls": "^2.4", "phpstan/phpstan": "^1.5.3", "phpstan/phpstan-doctrine": "^1.3", - "roadiz/entity-generator": "2.2.*", - "roadiz/random": "2.2.*", - "roadiz/jwt": "2.2.*", + "roadiz/entity-generator": "2.3.*", + "roadiz/random": "2.3.*", + "roadiz/jwt": "2.3.*", "squizlabs/php_codesniffer": "^3.5" }, "autoload": { @@ -95,8 +95,8 @@ }, "extra": { "branch-alias": { - "dev-main": "2.2.x-dev", - "dev-develop": "2.3.x-dev" + "dev-main": "2.3.x-dev", + "dev-develop": "2.4.x-dev" } } } diff --git a/phpstan.neon b/phpstan.neon index 10dbac08..6693cc61 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,5 @@ parameters: - level: 6 + level: 7 paths: - src excludePaths: @@ -9,6 +9,8 @@ parameters: doctrine: repositoryClass: RZ\Roadiz\Core\Repositories\EntityRepository ignoreErrors: + - identifier: missingType.iterableValue + - identifier: missingType.generics - '#Call to an undefined method RZ\\Roadiz\\CoreBundle\\Repository#' - '#Call to an undefined method RZ\\Roadiz\\UserBundle\\Repository#' - '#Call to an undefined method Doctrine\\Persistence\\ObjectRepository#' @@ -32,8 +34,7 @@ parameters: - '#does not accept Doctrine\\Common\\Collections\\ReadableCollection]+>#' reportUnmatchedIgnoredErrors: false - checkGenericClassInNonGenericObjectType: false - checkMissingIterableValueType: false + treatPhpDocTypesAsCertain: false includes: - vendor/phpstan/phpstan-doctrine/extension.neon diff --git a/src/AjaxControllers/AjaxAttributeValuesController.php b/src/AjaxControllers/AjaxAttributeValuesController.php index bd3d34f3..a4bc2108 100644 --- a/src/AjaxControllers/AjaxAttributeValuesController.php +++ b/src/AjaxControllers/AjaxAttributeValuesController.php @@ -5,7 +5,6 @@ namespace Themes\Rozier\AjaxControllers; use RZ\Roadiz\CoreBundle\Entity\AttributeValue; -use RZ\Roadiz\CoreBundle\Entity\Node; use RZ\Roadiz\CoreBundle\Security\Authorization\Voter\NodeVoter; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; @@ -69,7 +68,7 @@ protected function updatePosition(array $parameters, AttributeValue $attributeVa $attributable = $attributeValue->getAttributable(); $details = [ '%name%' => $attributeValue->getAttribute()->getLabelOrCode(), - '%nodeName%' => $attributable instanceof Node ? $attributable->getNodeName() : '', + '%nodeName%' => $attributable->getNodeName(), ]; if (!empty($parameters['afterAttributeValueId']) && is_numeric($parameters['afterAttributeValueId'])) { diff --git a/src/AjaxControllers/AjaxEntitiesExplorerController.php b/src/AjaxControllers/AjaxEntitiesExplorerController.php index e7fb58ce..9ce0e969 100644 --- a/src/AjaxControllers/AjaxEntitiesExplorerController.php +++ b/src/AjaxControllers/AjaxEntitiesExplorerController.php @@ -18,7 +18,7 @@ use Symfony\Component\Config\Definition\Processor; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\Routing\Exception\InvalidParameterException; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Yaml\Yaml; use Themes\Rozier\Explorer\ConfigurableExplorerItem; @@ -46,7 +46,7 @@ protected function getFieldConfiguration(NodeTypeField $nodeTypeField): array $nodeTypeField->getType() !== AbstractField::MANY_TO_MANY_T && $nodeTypeField->getType() !== AbstractField::MANY_TO_ONE_T ) { - throw new InvalidParameterException('nodeTypeField is not a valid entity join.'); + throw new BadRequestHttpException('nodeTypeField is not a valid entity join.'); } $configs = [ @@ -63,11 +63,16 @@ public function indexAction(Request $request): JsonResponse $this->denyAccessUnlessGranted('ROLE_BACKEND_USER'); if (!$request->query->has('nodeTypeFieldId')) { - throw new InvalidParameterException('nodeTypeFieldId parameter is missing.'); + throw new BadRequestHttpException('nodeTypeFieldId parameter is missing.'); } - /** @var NodeTypeField $nodeTypeField */ + /** @var NodeTypeField|null $nodeTypeField */ $nodeTypeField = $this->em()->find(NodeTypeField::class, $request->query->get('nodeTypeFieldId')); + + if (null === $nodeTypeField) { + throw new BadRequestHttpException('nodeTypeField does not exist.'); + } + $configuration = $this->getFieldConfiguration($nodeTypeField); /** @var class-string $className */ $className = $configuration['classname']; @@ -112,11 +117,11 @@ public function indexAction(Request $request): JsonResponse public function listAction(Request $request): JsonResponse { if (!$request->query->has('nodeTypeFieldId')) { - throw new InvalidParameterException('nodeTypeFieldId parameter is missing.'); + throw new BadRequestHttpException('nodeTypeFieldId parameter is missing.'); } if (!$request->query->has('ids')) { - throw new InvalidParameterException('Ids should be provided within an array'); + throw new BadRequestHttpException('Ids should be provided within an array'); } $this->denyAccessUnlessGranted('ROLE_BACKEND_USER'); @@ -124,8 +129,13 @@ public function listAction(Request $request): JsonResponse /** @var EntityManager $em */ $em = $this->em(); - /** @var NodeTypeField $nodeTypeField */ + /** @var NodeTypeField|null $nodeTypeField */ $nodeTypeField = $this->em()->find(NodeTypeField::class, $request->query->get('nodeTypeFieldId')); + + if (null === $nodeTypeField) { + throw new BadRequestHttpException('nodeTypeField does not exist.'); + } + $configuration = $this->getFieldConfiguration($nodeTypeField); /** @var class-string $className */ $className = $configuration['classname']; diff --git a/src/AjaxControllers/AjaxNodesExplorerController.php b/src/AjaxControllers/AjaxNodesExplorerController.php index f9914e3c..7efcfcd4 100644 --- a/src/AjaxControllers/AjaxNodesExplorerController.php +++ b/src/AjaxControllers/AjaxNodesExplorerController.php @@ -14,13 +14,14 @@ use RZ\Roadiz\CoreBundle\EntityApi\NodeTypeApi; use RZ\Roadiz\CoreBundle\SearchEngine\ClientRegistry; use RZ\Roadiz\CoreBundle\SearchEngine\NodeSourceSearchHandlerInterface; +use RZ\Roadiz\CoreBundle\SearchEngine\SolrSearchResultItem; use RZ\Roadiz\CoreBundle\Security\Authorization\Voter\NodeVoter; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Exception\InvalidParameterException; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; -use Symfony\Component\Security\Core\Security; +use Symfony\Bundle\SecurityBundle\Security; use Themes\Rozier\Models\NodeModel; use Themes\Rozier\Models\NodeSourceModel; @@ -184,7 +185,6 @@ protected function getSolrSearchResults( $arrayFilter, $this->getItemPerPage(), true, - 2, (int) $currentPage ); $pageCount = ceil($results->getResultCount() / $this->getItemPerPage()); @@ -250,7 +250,7 @@ public function listAction(Request $request): JsonResponse /** * Normalize response Node list result. * - * @param iterable $nodes + * @param iterable $nodes * @return array */ private function normalizeNodes(iterable $nodes): array @@ -258,24 +258,30 @@ private function normalizeNodes(iterable $nodes): array $nodesArray = []; foreach ($nodes as $node) { - if (null !== $node) { - if ($node instanceof NodesSources) { - if (!key_exists($node->getNode()->getId(), $nodesArray)) { - $nodeModel = new NodeSourceModel($node, $this->urlGenerator, $this->security); - $nodesArray[$node->getNode()->getId()] = $nodeModel->toArray(); - } - } else { - if (!key_exists($node->getId(), $nodesArray)) { - $nodeModel = new NodeModel($node, $this->urlGenerator, $this->security); - $nodesArray[$node->getId()] = $nodeModel->toArray(); - } + if ($node instanceof SolrSearchResultItem) { + $item = $node->getItem(); + if ($item instanceof NodesSources || $item instanceof Node) { + $this->normalizeItem($item, $nodesArray); } + } else { + $this->normalizeItem($node, $nodesArray); } } return array_values($nodesArray); } + private function normalizeItem(NodesSources|Node $item, array &$nodesArray): void + { + if ($item instanceof NodesSources && !key_exists($item->getNode()->getId(), $nodesArray)) { + $nodeSourceModel = new NodeSourceModel($item, $this->urlGenerator, $this->security); + $nodesArray[$item->getNode()->getId()] = $nodeSourceModel->toArray(); + } elseif ($item instanceof Node && !key_exists($item->getId(), $nodesArray)) { + $nodeModel = new NodeModel($item, $this->urlGenerator, $this->security); + $nodesArray[$item->getId()] = $nodeModel->toArray(); + } + } + /** * @param array $data * @return JsonResponse diff --git a/src/AjaxControllers/AjaxSearchNodesSourcesController.php b/src/AjaxControllers/AjaxSearchNodesSourcesController.php index 8f2e7115..b8c34594 100644 --- a/src/AjaxControllers/AjaxSearchNodesSourcesController.php +++ b/src/AjaxControllers/AjaxSearchNodesSourcesController.php @@ -14,7 +14,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; -use Symfony\Component\Security\Core\Security; +use Symfony\Bundle\SecurityBundle\Security; class AjaxSearchNodesSourcesController extends AbstractAjaxController { diff --git a/src/Controllers/AbstractAdminController.php b/src/Controllers/AbstractAdminController.php index 338f76b4..2d73a9ba 100644 --- a/src/Controllers/AbstractAdminController.php +++ b/src/Controllers/AbstractAdminController.php @@ -8,33 +8,25 @@ use JMS\Serializer\SerializationContext; use JMS\Serializer\SerializerInterface; use RZ\Roadiz\Core\AbstractEntities\PersistableInterface; +use RZ\Roadiz\CoreBundle\ListManager\SessionListFilters; use Symfony\Component\Form\Exception\InvalidConfigurationException; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\HttpFoundation\JsonResponse; -use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\String\UnicodeString; use Symfony\Contracts\EventDispatcher\Event; use Themes\Rozier\RozierApp; -use Themes\Rozier\Utils\SessionListFilters; abstract class AbstractAdminController extends RozierApp { public const ITEM_PER_PAGE = 20; - protected SerializerInterface $serializer; - protected UrlGeneratorInterface $urlGenerator; - - /** - * @param SerializerInterface $serializer - * @param UrlGeneratorInterface $urlGenerator - */ - public function __construct(SerializerInterface $serializer, UrlGeneratorInterface $urlGenerator) - { - $this->serializer = $serializer; - $this->urlGenerator = $urlGenerator; + public function __construct( + protected readonly SerializerInterface $serializer, + protected readonly UrlGeneratorInterface $urlGenerator + ) { } /** @@ -101,7 +93,7 @@ protected function getRequiredExportRole(): string * @return Response|null * @throws \Twig\Error\RuntimeError */ - public function defaultAction(Request $request) + public function defaultAction(Request $request): ?Response { $this->denyAccessUnlessGranted($this->getRequiredListingRole()); $this->additionalAssignation($request); @@ -132,10 +124,10 @@ public function defaultAction(Request $request) /** * @param Request $request - * @return RedirectResponse|Response|null + * @return Response|null * @throws \Twig\Error\RuntimeError */ - public function addAction(Request $request) + public function addAction(Request $request): ?Response { $this->denyAccessUnlessGranted($this->getRequiredCreationRole()); $this->additionalAssignation($request); @@ -188,7 +180,7 @@ public function addAction(Request $request) * @return Response|null * @throws \Twig\Error\RuntimeError */ - public function editAction(Request $request, $id) + public function editAction(Request $request, $id): ?Response { $this->denyAccessUnlessGranted($this->getRequiredEditionRole()); $this->additionalAssignation($request); @@ -271,10 +263,10 @@ public function exportAction(Request $request): JsonResponse /** * @param Request $request * @param int|string $id Numeric ID or UUID - * @return RedirectResponse|Response|null + * @return Response|null * @throws \Twig\Error\RuntimeError */ - public function deleteAction(Request $request, $id) + public function deleteAction(Request $request, $id): ?Response { $this->denyAccessUnlessGranted($this->getRequiredDeletionRole()); $this->additionalAssignation($request); @@ -502,7 +494,7 @@ protected function getPostDeleteResponse(PersistableInterface $item): Response * @param T|iterable|array|null $event * @return T|iterable|array|null */ - protected function dispatchSingleOrMultipleEvent(mixed $event): mixed + protected function dispatchSingleOrMultipleEvent(mixed $event): object|array|null { if (null === $event) { return null; diff --git a/src/Controllers/AbstractAdminWithBulkController.php b/src/Controllers/AbstractAdminWithBulkController.php index 059d22bc..1efa45a5 100644 --- a/src/Controllers/AbstractAdminWithBulkController.php +++ b/src/Controllers/AbstractAdminWithBulkController.php @@ -17,15 +17,12 @@ abstract class AbstractAdminWithBulkController extends AbstractAdminController { - protected FormFactoryInterface $formFactory; - public function __construct( - FormFactoryInterface $formFactory, + protected readonly FormFactoryInterface $formFactory, SerializerInterface $serializer, UrlGeneratorInterface $urlGenerator ) { parent::__construct($serializer, $urlGenerator); - $this->formFactory = $formFactory; } protected function additionalAssignation(Request $request): void diff --git a/src/Controllers/Attributes/AttributeController.php b/src/Controllers/Attributes/AttributeController.php index ffc952fe..49883ec6 100644 --- a/src/Controllers/Attributes/AttributeController.php +++ b/src/Controllers/Attributes/AttributeController.php @@ -21,19 +21,15 @@ class AttributeController extends AbstractAdminWithBulkController { - private AttributeImporter $attributeImporter; - public function __construct( - AttributeImporter $attributeImporter, + private readonly AttributeImporter $attributeImporter, FormFactoryInterface $formFactory, SerializerInterface $serializer, UrlGeneratorInterface $urlGenerator ) { parent::__construct($formFactory, $serializer, $urlGenerator); - $this->attributeImporter = $attributeImporter; } - /** * @inheritDoc */ @@ -161,13 +157,21 @@ public function importAction(Request $request): Response $file = $form->get('file')->getData(); if ($file->isValid()) { - $serializedData = file_get_contents($file->getPathname()); + $serializedData = \file_get_contents($file->getPathname()); if (false === $serializedData) { throw new \RuntimeException('Cannot read uploaded file.'); } $this->attributeImporter->import($serializedData); $this->em()->flush(); + + $msg = $this->getTranslator()->trans( + '%namespace%.imported', + [ + '%namespace%' => $this->getTranslator()->trans($this->getNamespace()) + ] + ); + $this->publishConfirmMessage($request, $msg); return $this->redirectToRoute('attributesHomePage'); } $form->addError(new FormError($this->getTranslator()->trans('file.not_uploaded'))); diff --git a/src/Controllers/CacheController.php b/src/Controllers/CacheController.php index ead8047e..0020827d 100644 --- a/src/Controllers/CacheController.php +++ b/src/Controllers/CacheController.php @@ -14,15 +14,10 @@ final class CacheController extends RozierApp { - private LoggerInterface $logger; - private CacheClearerInterface $cacheClearer; - public function __construct( - CacheClearerInterface $cacheClearer, - LoggerInterface $logger + private readonly CacheClearerInterface $cacheClearer, + private readonly LoggerInterface $logger ) { - $this->logger = $logger; - $this->cacheClearer = $cacheClearer; } public function deleteDoctrineCache(Request $request): Response @@ -52,7 +47,7 @@ public function deleteDoctrineCache(Request $request): Response */ return $this->redirectToRoute('adminHomePage'); } - + $this->prepareBaseAssignation(); $this->assignation['form'] = $form->createView(); return $this->render('@RoadizRozier/cache/deleteDoctrine.html.twig', $this->assignation); @@ -82,6 +77,7 @@ public function deleteAssetsCache(Request $request): Response return $this->redirectToRoute('adminHomePage'); } + $this->prepareBaseAssignation(); $this->assignation['form'] = $form->createView(); return $this->render('@RoadizRozier/cache/deleteAssets.html.twig', $this->assignation); diff --git a/src/Controllers/CustomForms/CustomFormsController.php b/src/Controllers/CustomForms/CustomFormsController.php index 42537ebf..042983c8 100644 --- a/src/Controllers/CustomForms/CustomFormsController.php +++ b/src/Controllers/CustomForms/CustomFormsController.php @@ -6,9 +6,9 @@ use RZ\Roadiz\Core\AbstractEntities\PersistableInterface; use RZ\Roadiz\CoreBundle\Entity\CustomForm; -use RZ\Roadiz\RozierBundle\Form\CustomFormType; use Symfony\Component\HttpFoundation\Request; use Themes\Rozier\Controllers\AbstractAdminWithBulkController; +use Themes\Rozier\Forms\CustomFormType; class CustomFormsController extends AbstractAdminWithBulkController { diff --git a/src/Controllers/CustomForms/CustomFormsUtilsController.php b/src/Controllers/CustomForms/CustomFormsUtilsController.php index 11516b8a..535da55d 100644 --- a/src/Controllers/CustomForms/CustomFormsUtilsController.php +++ b/src/Controllers/CustomForms/CustomFormsUtilsController.php @@ -4,30 +4,30 @@ namespace Themes\Rozier\Controllers\CustomForms; +use Doctrine\Persistence\ManagerRegistry; use PhpOffice\PhpSpreadsheet\Exception; -use RZ\Roadiz\CoreBundle\Entity\CustomForm; -use RZ\Roadiz\CoreBundle\Entity\CustomFormAnswer; use RZ\Roadiz\CoreBundle\CustomForm\CustomFormAnswerSerializer; -use RZ\Roadiz\CoreBundle\Xlsx\XlsxExporter; +use RZ\Roadiz\CoreBundle\Entity\CustomForm; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\ResponseHeaderBag; +use Symfony\Component\HttpFoundation\StreamedResponse; +use Symfony\Component\Serializer\SerializerInterface; +use Symfony\Contracts\Translation\TranslatorInterface; use Themes\Rozier\RozierApp; class CustomFormsUtilsController extends RozierApp { - private CustomFormAnswerSerializer $customFormAnswerSerializer; - - /** - * @param CustomFormAnswerSerializer $customFormAnswerSerializer - */ - public function __construct(CustomFormAnswerSerializer $customFormAnswerSerializer) - { - $this->customFormAnswerSerializer = $customFormAnswerSerializer; + public function __construct( + private readonly ManagerRegistry $managerRegistry, + private readonly TranslatorInterface $translator, + private readonly CustomFormAnswerSerializer $customFormAnswerSerializer, + private readonly SerializerInterface $serializer + ) { } /** - * Export all custom form's answer in a Xlsx file (.rzt). + * Export all custom form's answers in a CSV file. * * @param Request $request * @param int $id @@ -38,45 +38,35 @@ public function __construct(CustomFormAnswerSerializer $customFormAnswerSerializ */ public function exportAction(Request $request, int $id): Response { - /** @var CustomForm|null $customForm */ - $customForm = $this->em()->find(CustomForm::class, $id); + $customForm = $this->managerRegistry->getRepository(CustomForm::class)->find($id); if (null === $customForm) { throw $this->createNotFoundException(); } $answers = $customForm->getCustomFormAnswers(); - - /** - * @var int $key - * @var CustomFormAnswer $answer - */ + $answersArray = []; foreach ($answers as $key => $answer) { - $array = array_merge( - [$answer->getIp(), $answer->getSubmittedAt()], - $this->customFormAnswerSerializer->toSimpleArray($answer) - ); - $answers[$key] = $array; + $answersArray[$key] = $this->customFormAnswerSerializer->toSimpleArray($answer); } - $keys = ["ip", "submitted.date"]; - $fields = $customForm->getFieldsLabels(); - $keys = array_merge($keys, $fields); - - $exporter = new XlsxExporter($this->getTranslator()); - $xlsx = $exporter->exportXlsx($answers, $keys); - - $response = new Response( - $xlsx, - Response::HTTP_OK, - [] - ); - + $keys = [ + 'ip', + 'submitted.date', + ...$fields + ]; + + $response = new StreamedResponse(function () use ($answersArray, $keys) { + echo $this->serializer->serialize($answersArray, 'csv', [ + 'csv_headers' => $keys + ]); + }); + $response->headers->set('Content-Type', 'text/csv'); $response->headers->set( 'Content-Disposition', $response->headers->makeDisposition( ResponseHeaderBag::DISPOSITION_ATTACHMENT, - $customForm->getName() . '.xlsx' + $customForm->getName() . '.csv' ) ); @@ -90,15 +80,12 @@ public function exportAction(Request $request, int $id): Response * * @param Request $request * @param int $id - * * @return Response */ public function duplicateAction(Request $request, int $id): Response { $this->denyAccessUnlessGranted('ROLE_ACCESS_CUSTOMFORMS'); - /** @var CustomForm|null $existingCustomForm */ - $existingCustomForm = $this->em()->find(CustomForm::class, $id); - + $existingCustomForm = $this->managerRegistry->getRepository(CustomForm::class)->find($id); if (null === $existingCustomForm) { throw $this->createNotFoundException(); } @@ -107,7 +94,7 @@ public function duplicateAction(Request $request, int $id): Response $newCustomForm = clone $existingCustomForm; $newCustomForm->setCreatedAt(new \DateTime()); $newCustomForm->setUpdatedAt(new \DateTime()); - $em = $this->em(); + $em = $this->managerRegistry->getManager(); foreach ($newCustomForm->getFields() as $field) { $em->persist($field); @@ -116,7 +103,7 @@ public function duplicateAction(Request $request, int $id): Response $em->persist($newCustomForm); $em->flush(); - $msg = $this->getTranslator()->trans("duplicated.custom.form.%name%", [ + $msg = $this->translator->trans("duplicated.custom.form.%name%", [ '%name%' => $existingCustomForm->getDisplayName(), ]); @@ -129,7 +116,7 @@ public function duplicateAction(Request $request, int $id): Response } catch (\Exception $e) { $this->publishErrorMessage( $request, - $this->getTranslator()->trans("impossible.duplicate.custom.form.%name%", [ + $this->translator->trans("impossible.duplicate.custom.form.%name%", [ '%name%' => $existingCustomForm->getDisplayName(), ]), $newCustomForm diff --git a/src/Controllers/Documents/DocumentTranslationsController.php b/src/Controllers/Documents/DocumentTranslationsController.php index 0fcb8cdc..e8c1138f 100644 --- a/src/Controllers/Documents/DocumentTranslationsController.php +++ b/src/Controllers/Documents/DocumentTranslationsController.php @@ -12,6 +12,7 @@ use RZ\Roadiz\CoreBundle\Entity\Translation; use RZ\Roadiz\CoreBundle\Event\Document\DocumentTranslationUpdatedEvent; use Symfony\Component\Form\Extension\Core\Type\HiddenType; +use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Exception\ResourceNotFoundException; @@ -28,13 +29,13 @@ class DocumentTranslationsController extends RozierApp /** * @param Request $request - * @param int $documentId - * @param int|null $translationId + * @param int $documentId + * @param int|null $translationId * * @return Response * @throws RuntimeError */ - public function editAction(Request $request, int $documentId, ?int $translationId = null) + public function editAction(Request $request, int $documentId, ?int $translationId = null): Response { $this->denyAccessUnlessGranted('ROLE_ACCESS_DOCUMENTS'); @@ -62,69 +63,65 @@ public function editAction(Request $request, int $documentId, ?int $translationI $documentTr = $this->createDocumentTranslation($document, $translation); } - if ($documentTr !== null && $document !== null) { - $this->assignation['document'] = $document; - $this->assignation['translation'] = $translation; - $this->assignation['documentTr'] = $documentTr; + if ($documentTr === null || $document === null) { + throw new ResourceNotFoundException(); + } - /** - * Versioning - */ - if ($this->isGranted('ROLE_ACCESS_VERSIONS')) { - if (null !== $response = $this->handleVersions($request, $documentTr)) { - return $response; - } - } + $this->assignation['document'] = $document; + $this->assignation['translation'] = $translation; + $this->assignation['documentTr'] = $documentTr; - /* - * Handle main form - */ - $form = $this->createForm(DocumentTranslationType::class, $documentTr, [ - 'referer' => $this->getRequest()->get('referer'), - 'disabled' => $this->isReadOnly, - ]); - $form->handleRequest($request); + /** + * Versioning + */ + if ($this->isGranted('ROLE_ACCESS_VERSIONS')) { + if (null !== $response = $this->handleVersions($request, $documentTr)) { + return $response; + } + } - if ($form->isSubmitted() && $form->isValid()) { - $this->onPostUpdate($documentTr, $request); + /* + * Handle main form + */ + $form = $this->createForm(DocumentTranslationType::class, $documentTr, [ + 'referer' => $this->getRequest()->get('referer'), + 'disabled' => $this->isReadOnly, + ]); + $form->handleRequest($request); - $routeParams = [ - 'documentId' => $document->getId(), - 'translationId' => $translationId, - ]; + if ($form->isSubmitted() && $form->isValid()) { + $this->onPostUpdate($documentTr, $request); - if ($form->get('referer')->getData()) { - $routeParams = array_merge($routeParams, [ - 'referer' => $form->get('referer')->getData() - ]); - } + $routeParams = [ + 'documentId' => $document->getId(), + 'translationId' => $translationId, + ]; - /* - * Force redirect to avoid resending form when refreshing page - */ - return $this->redirectToRoute( - 'documentsMetaPage', - $routeParams - ); + if ($form->get('referer')->getData()) { + $routeParams = array_merge($routeParams, [ + 'referer' => $form->get('referer')->getData() + ]); } - $this->assignation['form'] = $form->createView(); - $this->assignation['readOnly'] = $this->isReadOnly; - - return $this->render('@RoadizRozier/document-translations/edit.html.twig', $this->assignation); + /* + * Force redirect to avoid resending form when refreshing page + */ + return $this->redirectToRoute( + 'documentsMetaPage', + $routeParams + ); } - throw new ResourceNotFoundException(); + $this->assignation['form'] = $form->createView(); + $this->assignation['readOnly'] = $this->isReadOnly; + + return $this->render('@RoadizRozier/document-translations/edit.html.twig', $this->assignation); } - /** - * @param Document $document - * @param TranslationInterface $translation - * - * @return DocumentTranslation - */ - protected function createDocumentTranslation(Document $document, TranslationInterface $translation) - { + protected function createDocumentTranslation( + Document $document, + TranslationInterface $translation + ): DocumentTranslation { $dt = new DocumentTranslation(); $dt->setDocument($document); $dt->setTranslation($translation); @@ -144,7 +141,7 @@ protected function createDocumentTranslation(Document $document, TranslationInte * @return Response * @throws RuntimeError */ - public function deleteAction(Request $request, int $documentId, int $translationId) + public function deleteAction(Request $request, int $documentId, int $translationId): Response { $this->denyAccessUnlessGranted('ROLE_ACCESS_DOCUMENTS_DELETE'); @@ -201,12 +198,7 @@ public function deleteAction(Request $request, int $documentId, int $translation throw new ResourceNotFoundException(); } - /** - * @param DocumentTranslation $doc - * - * @return \Symfony\Component\Form\FormInterface - */ - private function buildDeleteForm(DocumentTranslation $doc) + private function buildDeleteForm(DocumentTranslation $doc): FormInterface { $defaults = [ 'documentTranslationId' => $doc->getId(), @@ -240,11 +232,6 @@ protected function onPostUpdate(PersistableInterface $entity, Request $request): } } - /** - * @param PersistableInterface $entity - * - * @return Response - */ protected function getPostUpdateRedirection(PersistableInterface $entity): ?Response { if ( diff --git a/src/Controllers/Documents/DocumentsController.php b/src/Controllers/Documents/DocumentsController.php index b049b5d3..2aa339c6 100644 --- a/src/Controllers/Documents/DocumentsController.php +++ b/src/Controllers/Documents/DocumentsController.php @@ -19,6 +19,7 @@ use RZ\Roadiz\CoreBundle\Entity\Translation; use RZ\Roadiz\CoreBundle\EntityHandler\DocumentHandler; use RZ\Roadiz\CoreBundle\Exception\EntityAlreadyExistsException; +use RZ\Roadiz\CoreBundle\ListManager\SessionListFilters; use RZ\Roadiz\Documents\Events\DocumentCreatedEvent; use RZ\Roadiz\Documents\Events\DocumentDeletedEvent; use RZ\Roadiz\Documents\Events\DocumentFileUpdatedEvent; @@ -55,23 +56,10 @@ use Themes\Rozier\Forms\DocumentEmbedType; use Themes\Rozier\Models\DocumentModel; use Themes\Rozier\RozierApp; -use Themes\Rozier\Utils\SessionListFilters; use Twig\Error\RuntimeError; class DocumentsController extends RozierApp { - private array $documentPlatforms; - private DocumentFactory $documentFactory; - private HandlerFactoryInterface $handlerFactory; - private LoggerInterface $logger; - private RandomImageFinder $randomImageFinder; - private RendererInterface $renderer; - private DocumentUrlGeneratorInterface $documentUrlGenerator; - private UrlGeneratorInterface $urlGenerator; - private FilesystemOperator $documentsStorage; - private ?string $googleServerId; - private ?string $soundcloudClientId; - protected array $thumbnailFormat = [ 'quality' => 50, 'fit' => '128x128', @@ -81,34 +69,21 @@ class DocumentsController extends RozierApp 'controls' => false, 'loading' => 'lazy', ]; - private EmbedFinderFactory $embedFinderFactory; public function __construct( - array $documentPlatforms, - FilesystemOperator $documentsStorage, - HandlerFactoryInterface $handlerFactory, - LoggerInterface $logger, - RandomImageFinder $randomImageFinder, - DocumentFactory $documentFactory, - RendererInterface $renderer, - DocumentUrlGeneratorInterface $documentUrlGenerator, - UrlGeneratorInterface $urlGenerator, - EmbedFinderFactory $embedFinderFactory, - ?string $googleServerId = null, - ?string $soundcloudClientId = null + private readonly array $documentPlatforms, + private readonly FilesystemOperator $documentsStorage, + private readonly HandlerFactoryInterface $handlerFactory, + private readonly LoggerInterface $logger, + private readonly RandomImageFinder $randomImageFinder, + private readonly DocumentFactory $documentFactory, + private readonly RendererInterface $renderer, + private readonly DocumentUrlGeneratorInterface $documentUrlGenerator, + private readonly UrlGeneratorInterface $urlGenerator, + private readonly EmbedFinderFactory $embedFinderFactory, + private readonly ?string $googleServerId = null, + private readonly ?string $soundcloudClientId = null ) { - $this->documentPlatforms = $documentPlatforms; - $this->handlerFactory = $handlerFactory; - $this->logger = $logger; - $this->randomImageFinder = $randomImageFinder; - $this->documentFactory = $documentFactory; - $this->renderer = $renderer; - $this->documentUrlGenerator = $documentUrlGenerator; - $this->urlGenerator = $urlGenerator; - $this->googleServerId = $googleServerId; - $this->soundcloudClientId = $soundcloudClientId; - $this->documentsStorage = $documentsStorage; - $this->embedFinderFactory = $embedFinderFactory; } /** diff --git a/src/Controllers/FoldersController.php b/src/Controllers/FoldersController.php index 92b122db..c3e866b5 100644 --- a/src/Controllers/FoldersController.php +++ b/src/Controllers/FoldersController.php @@ -25,11 +25,8 @@ class FoldersController extends RozierApp { - private DocumentArchiver $documentArchiver; - - public function __construct(DocumentArchiver $documentArchiver) + public function __construct(private readonly DocumentArchiver $documentArchiver) { - $this->documentArchiver = $documentArchiver; } public function indexAction(Request $request): Response diff --git a/src/Controllers/GroupsUtilsController.php b/src/Controllers/GroupsUtilsController.php index e090be63..25e6be3e 100644 --- a/src/Controllers/GroupsUtilsController.php +++ b/src/Controllers/GroupsUtilsController.php @@ -20,17 +20,10 @@ class GroupsUtilsController extends RozierApp { - private SerializerInterface $serializer; - private GroupsImporter $groupsImporter; - - /** - * @param SerializerInterface $serializer - * @param GroupsImporter $groupsImporter - */ - public function __construct(SerializerInterface $serializer, GroupsImporter $groupsImporter) - { - $this->serializer = $serializer; - $this->groupsImporter = $groupsImporter; + public function __construct( + private readonly SerializerInterface $serializer, + private readonly GroupsImporter $groupsImporter + ) { } /** diff --git a/src/Controllers/LoginController.php b/src/Controllers/LoginController.php index 5714ba77..7dea01cb 100644 --- a/src/Controllers/LoginController.php +++ b/src/Controllers/LoginController.php @@ -41,10 +41,9 @@ public function imageAction(Request $request): Response 'quality' => 80, 'sharpen' => 5, ]); - $response->setData([ + return $response->setData([ 'url' => $this->documentUrlGenerator->getUrl() ]); - return $response; } } @@ -54,9 +53,8 @@ public function imageAction(Request $request): Response if (null !== $feed) { $url = $feed['url'] ?? $feed['urls']['regular'] ?? $feed['urls']['full'] ?? $feed['urls']['raw'] ?? null; } - $response->setData([ - 'url' => '/themes/Rozier/static/assets/img/default_login.jpg' + return $response->setData([ + 'url' => $url ?? '/themes/Rozier/static/assets/img/default_login.jpg' ]); - return $response; } } diff --git a/src/Controllers/NodeTypeFieldsController.php b/src/Controllers/NodeTypeFieldsController.php index fad5a557..4bdcd44b 100644 --- a/src/Controllers/NodeTypeFieldsController.php +++ b/src/Controllers/NodeTypeFieldsController.php @@ -12,7 +12,6 @@ use Symfony\Component\Form\FormError; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Routing\Exception\ResourceNotFoundException; @@ -22,13 +21,10 @@ class NodeTypeFieldsController extends RozierApp { - private MessageBusInterface $messageBus; - private KernelInterface $kernel; - - public function __construct(KernelInterface $kernel, MessageBusInterface $messageBus) - { - $this->messageBus = $messageBus; - $this->kernel = $kernel; + public function __construct( + private readonly bool $allowNodeTypeEdition, + private readonly MessageBusInterface $messageBus + ) { } /** @@ -82,7 +78,7 @@ public function editAction(Request $request, int $nodeTypeFieldId): Response $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - if (!$this->kernel->isDebug()) { + if (!$this->allowNodeTypeEdition) { $form->addError(new FormError('You cannot edit node-type fields in production.')); } else { $this->em()->flush(); @@ -138,12 +134,12 @@ public function addAction(Request $request, int $nodeTypeId): Response $this->assignation['field'] = $field; $form = $this->createForm(NodeTypeFieldType::class, $field, [ - 'disabled' => !$this->kernel->isDebug() + 'disabled' => !$this->allowNodeTypeEdition ]); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - if (!$this->kernel->isDebug()) { + if (!$this->allowNodeTypeEdition) { $form->addError(new FormError('You cannot add node-type fields in production.')); } else { try { @@ -198,7 +194,7 @@ public function deleteAction(Request $request, int $nodeTypeFieldId): Response $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - if (!$this->kernel->isDebug()) { + if (!$this->allowNodeTypeEdition) { $form->addError(new FormError('You cannot delete node-type fields in production.')); } else { /** @var NodeType $nodeType */ diff --git a/src/Controllers/NodeTypes/NodeTypesController.php b/src/Controllers/NodeTypes/NodeTypesController.php index 3926d683..58720914 100644 --- a/src/Controllers/NodeTypes/NodeTypesController.php +++ b/src/Controllers/NodeTypes/NodeTypesController.php @@ -6,29 +6,25 @@ use RZ\Roadiz\CoreBundle\Entity\NodeType; use RZ\Roadiz\CoreBundle\Exception\EntityAlreadyExistsException; +use RZ\Roadiz\CoreBundle\ListManager\SessionListFilters; use RZ\Roadiz\CoreBundle\Message\DeleteNodeTypeMessage; use RZ\Roadiz\CoreBundle\Message\UpdateNodeTypeSchemaMessage; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\FormError; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\MessageBusInterface; use Themes\Rozier\Forms\NodeTypeType; use Themes\Rozier\RozierApp; -use Themes\Rozier\Utils\SessionListFilters; use Twig\Error\RuntimeError; class NodeTypesController extends RozierApp { - private MessageBusInterface $messageBus; - private KernelInterface $kernel; - - public function __construct(KernelInterface $kernel, MessageBusInterface $messageBus) - { - $this->messageBus = $messageBus; - $this->kernel = $kernel; + public function __construct( + private readonly bool $allowNodeTypeEdition, + private readonly MessageBusInterface $messageBus + ) { } public function indexAction(Request $request): Response @@ -112,12 +108,12 @@ public function addAction(Request $request): Response $nodeType = new NodeType(); $form = $this->createForm(NodeTypeType::class, $nodeType, [ - 'disabled' => !$this->kernel->isDebug() + 'disabled' => !$this->allowNodeTypeEdition ]); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - if (!$this->kernel->isDebug()) { + if (!$this->allowNodeTypeEdition) { $form->addError(new FormError('You cannot create a node-type in production mode.')); } else { try { @@ -166,7 +162,7 @@ public function deleteAction(Request $request, int $nodeTypeId): Response $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - if (!$this->kernel->isDebug()) { + if (!$this->allowNodeTypeEdition) { $form->addError(new FormError('You cannot delete a node-type in production mode.')); } else { $this->messageBus->dispatch(new Envelope(new DeleteNodeTypeMessage($nodeType->getId()))); diff --git a/src/Controllers/NodeTypes/NodeTypesUtilsController.php b/src/Controllers/NodeTypes/NodeTypesUtilsController.php index b7c07e63..059a6b13 100644 --- a/src/Controllers/NodeTypes/NodeTypesUtilsController.php +++ b/src/Controllers/NodeTypes/NodeTypesUtilsController.php @@ -29,21 +29,12 @@ class NodeTypesUtilsController extends RozierApp { - private SerializerInterface $serializer; - private NodeTypes $nodeTypesBag; - private NodeTypesImporter $nodeTypesImporter; - private MessageBusInterface $messageBus; - public function __construct( - SerializerInterface $serializer, - NodeTypes $nodeTypesBag, - NodeTypesImporter $nodeTypesImporter, - MessageBusInterface $messageBus + private readonly SerializerInterface $serializer, + private readonly NodeTypes $nodeTypesBag, + private readonly NodeTypesImporter $nodeTypesImporter, + private readonly MessageBusInterface $messageBus ) { - $this->serializer = $serializer; - $this->nodeTypesBag = $nodeTypesBag; - $this->nodeTypesImporter = $nodeTypesImporter; - $this->messageBus = $messageBus; } /** @@ -81,7 +72,6 @@ public function exportJsonFileAction(Request $request, int $nodeTypeId): JsonRes /** * @param Request $request - * * @return BinaryFileResponse * @throws RuntimeError */ @@ -152,10 +142,6 @@ public function exportTypeScriptDeclarationAction(Request $request): Response return $response; } - /** - * @param Request $request - * @return BinaryFileResponse - */ public function exportAllAction(Request $request): BinaryFileResponse { $this->denyAccessUnlessGranted('ROLE_ACCESS_NODETYPES'); diff --git a/src/Controllers/Nodes/ExportController.php b/src/Controllers/Nodes/ExportController.php index 15549a66..abc4d1f1 100644 --- a/src/Controllers/Nodes/ExportController.php +++ b/src/Controllers/Nodes/ExportController.php @@ -17,14 +17,8 @@ class ExportController extends RozierApp { - private NodeSourceXlsxSerializer $xlsxSerializer; - - /** - * @param NodeSourceXlsxSerializer $xlsxSerializer - */ - public function __construct(NodeSourceXlsxSerializer $xlsxSerializer) + public function __construct(private readonly NodeSourceXlsxSerializer $xlsxSerializer) { - $this->xlsxSerializer = $xlsxSerializer; } /** @@ -40,9 +34,6 @@ public function __construct(NodeSourceXlsxSerializer $xlsxSerializer) */ public function exportAllXlsxAction(Request $request, int $translationId, ?int $parentNodeId = null): Response { - /* - * Get translation - */ $translation = $this->em() ->find(Translation::class, $translationId); @@ -75,7 +66,7 @@ public function exportAllXlsxAction(Request $request, int $translationId, ?int $ ->findBy($criteria, $order); $this->xlsxSerializer->setOnlyTexts(true); - $this->xlsxSerializer->addUrls($request, $this->getSettingsBag()->get('force_locale')); + $this->xlsxSerializer->addUrls(); $xlsx = $this->xlsxSerializer->serialize($sources); $response = new Response( diff --git a/src/Controllers/Nodes/HistoryController.php b/src/Controllers/Nodes/HistoryController.php index 0ed1677c..6915d67e 100644 --- a/src/Controllers/Nodes/HistoryController.php +++ b/src/Controllers/Nodes/HistoryController.php @@ -8,13 +8,13 @@ use RZ\Roadiz\CoreBundle\Entity\Node; use RZ\Roadiz\CoreBundle\Entity\Translation; use RZ\Roadiz\CoreBundle\ListManager\QueryBuilderListManager; +use RZ\Roadiz\CoreBundle\ListManager\SessionListFilters; use RZ\Roadiz\CoreBundle\Logger\Entity\Log; use RZ\Roadiz\CoreBundle\Security\Authorization\Voter\NodeVoter; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Exception\ResourceNotFoundException; use Themes\Rozier\RozierApp; -use Themes\Rozier\Utils\SessionListFilters; use Twig\Error\RuntimeError; class HistoryController extends RozierApp diff --git a/src/Controllers/Nodes/NodesAttributesController.php b/src/Controllers/Nodes/NodesAttributesController.php index 4ccd94bb..f1dfe96e 100644 --- a/src/Controllers/Nodes/NodesAttributesController.php +++ b/src/Controllers/Nodes/NodesAttributesController.php @@ -14,6 +14,7 @@ use RZ\Roadiz\CoreBundle\Event\NodesSources\NodesSourcesUpdatedEvent; use RZ\Roadiz\CoreBundle\Form\AttributeValueTranslationType; use RZ\Roadiz\CoreBundle\Form\AttributeValueType; +use RZ\Roadiz\CoreBundle\Form\Error\FormErrorSerializer; use RZ\Roadiz\CoreBundle\Security\Authorization\Voter\NodeVoter; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\FormFactoryInterface; @@ -26,14 +27,10 @@ class NodesAttributesController extends RozierApp { - private FormFactoryInterface $formFactory; - - /** - * @param FormFactoryInterface $formFactory - */ - public function __construct(FormFactoryInterface $formFactory) - { - $this->formFactory = $formFactory; + public function __construct( + private readonly FormFactoryInterface $formFactory, + private readonly FormErrorSerializer $formErrorSerializer + ) { } /** @@ -140,7 +137,7 @@ public function editAction(Request $request, int $nodeId, int $translationId): R 'translationId' => $translation->getId(), ]); } else { - $errors = $this->getErrorsAsArray($attributeValueTranslationForm); + $errors = $this->formErrorSerializer->getErrorsAsArray($attributeValueTranslationForm); /* * Handle errors when Ajax POST requests */ diff --git a/src/Controllers/Nodes/NodesController.php b/src/Controllers/Nodes/NodesController.php index 47fa8f37..482e097f 100644 --- a/src/Controllers/Nodes/NodesController.php +++ b/src/Controllers/Nodes/NodesController.php @@ -18,6 +18,7 @@ use RZ\Roadiz\CoreBundle\Event\Node\NodeUndeletedEvent; use RZ\Roadiz\CoreBundle\Event\Node\NodeUpdatedEvent; use RZ\Roadiz\CoreBundle\Exception\EntityAlreadyExistsException; +use RZ\Roadiz\CoreBundle\ListManager\SessionListFilters; use RZ\Roadiz\CoreBundle\Node\Exception\SameNodeUrlException; use RZ\Roadiz\CoreBundle\Node\NodeFactory; use RZ\Roadiz\CoreBundle\Node\NodeMover; @@ -36,7 +37,6 @@ use Symfony\Component\Workflow\Registry; use Themes\Rozier\RozierApp; use Themes\Rozier\Traits\NodesTrait; -use Themes\Rozier\Utils\SessionListFilters; use Twig\Error\RuntimeError; final class NodesController extends RozierApp @@ -329,7 +329,10 @@ public function addAction(Request $request, int $nodeTypeId, ?int $translationId throw new ResourceNotFoundException(sprintf('Translation #%s does not exist.', $translationId)); } - $node = new Node($type); + $node = new Node(); + $node->setNodeType($type); + $node->setTtl($type->getDefaultTtl()); + $chroot = $this->nodeChrootResolver->getChroot($this->getUser()); if (null !== $chroot) { // If user is jailed in a node, prevent moving nodes out. diff --git a/src/Controllers/Nodes/NodesSourcesController.php b/src/Controllers/Nodes/NodesSourcesController.php index ce28da25..980ed5f3 100644 --- a/src/Controllers/Nodes/NodesSourcesController.php +++ b/src/Controllers/Nodes/NodesSourcesController.php @@ -34,13 +34,10 @@ class NodesSourcesController extends RozierApp { use VersionedControllerTrait; - private JwtExtension $jwtExtension; - private FormErrorSerializer $formErrorSerializer; - - public function __construct(JwtExtension $jwtExtension, FormErrorSerializer $formErrorSerializer) - { - $this->jwtExtension = $jwtExtension; - $this->formErrorSerializer = $formErrorSerializer; + public function __construct( + private readonly JwtExtension $jwtExtension, + private readonly FormErrorSerializer $formErrorSerializer + ) { } /** @@ -241,7 +238,6 @@ public function removeAction(Request $request, int $nodeSourceId): Response $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - /** @var Node $node */ $node = $ns->getNode(); /* * Dispatch event diff --git a/src/Controllers/Nodes/NodesTreesController.php b/src/Controllers/Nodes/NodesTreesController.php index 085d4410..7604d5b6 100644 --- a/src/Controllers/Nodes/NodesTreesController.php +++ b/src/Controllers/Nodes/NodesTreesController.php @@ -32,31 +32,13 @@ class NodesTreesController extends RozierApp { - private NodeChrootResolver $nodeChrootResolver; - private TreeWidgetFactory $treeWidgetFactory; - private FormFactoryInterface $formFactory; - private HandlerFactoryInterface $handlerFactory; - private Registry $workflowRegistry; - - /** - * @param NodeChrootResolver $nodeChrootResolver - * @param TreeWidgetFactory $treeWidgetFactory - * @param FormFactoryInterface $formFactory - * @param HandlerFactoryInterface $handlerFactory - * @param Registry $workflowRegistry - */ public function __construct( - NodeChrootResolver $nodeChrootResolver, - TreeWidgetFactory $treeWidgetFactory, - FormFactoryInterface $formFactory, - HandlerFactoryInterface $handlerFactory, - Registry $workflowRegistry + private readonly NodeChrootResolver $nodeChrootResolver, + private readonly TreeWidgetFactory $treeWidgetFactory, + private readonly FormFactoryInterface $formFactory, + private readonly HandlerFactoryInterface $handlerFactory, + private readonly Registry $workflowRegistry ) { - $this->nodeChrootResolver = $nodeChrootResolver; - $this->treeWidgetFactory = $treeWidgetFactory; - $this->formFactory = $formFactory; - $this->handlerFactory = $handlerFactory; - $this->workflowRegistry = $workflowRegistry; } /** @@ -359,12 +341,7 @@ private function bulkDeleteNodes(array $data) return $this->getTranslator()->trans('wrong.request'); } - /** - * @param array $data - * - * @return string - */ - private function bulkStatusNodes(array $data) + private function bulkStatusNodes(array $data): string { if (!empty($data['nodesIds'])) { $nodesIds = trim($data['nodesIds']); @@ -393,10 +370,7 @@ private function bulkStatusNodes(array $data) return $this->getTranslator()->trans('wrong.request'); } - /** - * @return FormInterface - */ - private function buildBulkTagForm() + private function buildBulkTagForm(): FormInterface { /** @var FormBuilder $builder */ $builder = $this->formFactory diff --git a/src/Controllers/Nodes/NodesUtilsController.php b/src/Controllers/Nodes/NodesUtilsController.php index e2e293a9..cf73e9fc 100644 --- a/src/Controllers/Nodes/NodesUtilsController.php +++ b/src/Controllers/Nodes/NodesUtilsController.php @@ -16,14 +16,8 @@ class NodesUtilsController extends RozierApp { - private NodeNamePolicyInterface $nodeNamePolicy; - - /** - * @param NodeNamePolicyInterface $nodeNamePolicy - */ - public function __construct(NodeNamePolicyInterface $nodeNamePolicy) + public function __construct(private readonly NodeNamePolicyInterface $nodeNamePolicy) { - $this->nodeNamePolicy = $nodeNamePolicy; } /** diff --git a/src/Controllers/Nodes/TranstypeController.php b/src/Controllers/Nodes/TranstypeController.php index c8b51d90..7e3326ae 100644 --- a/src/Controllers/Nodes/TranstypeController.php +++ b/src/Controllers/Nodes/TranstypeController.php @@ -10,7 +10,6 @@ use RZ\Roadiz\CoreBundle\Event\NodesSources\NodesSourcesUpdatedEvent; use RZ\Roadiz\CoreBundle\Node\NodeTranstyper; use RZ\Roadiz\CoreBundle\Security\Authorization\Voter\NodeVoter; -use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Exception\ResourceNotFoundException; @@ -20,14 +19,8 @@ class TranstypeController extends RozierApp { - private NodeTranstyper $nodeTranstyper; - - /** - * @param NodeTranstyper $nodeTranstyper - */ - public function __construct(NodeTranstyper $nodeTranstyper) + public function __construct(private readonly NodeTranstyper $nodeTranstyper) { - $this->nodeTranstyper = $nodeTranstyper; } /** diff --git a/src/Controllers/RolesUtilsController.php b/src/Controllers/RolesUtilsController.php index f0a5907e..4cc08dc7 100644 --- a/src/Controllers/RolesUtilsController.php +++ b/src/Controllers/RolesUtilsController.php @@ -20,17 +20,10 @@ class RolesUtilsController extends RozierApp { - private SerializerInterface $serializer; - private RolesImporter $rolesImporter; - - /** - * @param SerializerInterface $serializer - * @param RolesImporter $rolesImporter - */ - public function __construct(SerializerInterface $serializer, RolesImporter $rolesImporter) - { - $this->serializer = $serializer; - $this->rolesImporter = $rolesImporter; + public function __construct( + private readonly SerializerInterface $serializer, + private readonly RolesImporter $rolesImporter + ) { } /** diff --git a/src/Controllers/SearchController.php b/src/Controllers/SearchController.php index d6d4aecf..e615d884 100644 --- a/src/Controllers/SearchController.php +++ b/src/Controllers/SearchController.php @@ -5,7 +5,6 @@ namespace Themes\Rozier\Controllers; use DateTime; -use IteratorAggregate; use PhpOffice\PhpSpreadsheet\Exception; use RZ\Roadiz\Core\AbstractEntities\AbstractField; use RZ\Roadiz\CoreBundle\Entity\Node; @@ -18,7 +17,7 @@ use RZ\Roadiz\CoreBundle\Form\NodeStatesType; use RZ\Roadiz\CoreBundle\Form\NodeTypesType; use RZ\Roadiz\CoreBundle\Form\SeparatorType; -use RZ\Roadiz\CoreBundle\Xlsx\XlsxExporter; +use RZ\Roadiz\CoreBundle\Xlsx\NodeSourceXlsxSerializer; use Symfony\Component\Form\ClickableInterface; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; @@ -44,6 +43,10 @@ class SearchController extends RozierApp protected bool $pagination = true; protected ?int $itemPerPage = null; + public function __construct(protected readonly NodeSourceXlsxSerializer $xlsxSerializer) + { + } + /** * @param mixed $var * @return bool @@ -68,7 +71,7 @@ public function notBlank(mixed $var): bool * * @return array */ - protected function appendDateTimeCriteria(array &$data, string $fieldName) + protected function appendDateTimeCriteria(array &$data, string $fieldName): array { $date = $data[$fieldName]['compareDatetime']; if ($date instanceof DateTime) { @@ -86,12 +89,10 @@ protected function appendDateTimeCriteria(array &$data, string $fieldName) * @param string $prefix * @return mixed */ - protected function processCriteria($data, string $prefix = "") + protected function processCriteria($data, string $prefix = ""): mixed { if (!empty($data[$prefix . "nodeName"])) { - if (isset($data[$prefix . "nodeName_exact"]) && $data[$prefix . "nodeName_exact"] === true) { - $data[$prefix . "nodeName"] = $data[$prefix . "nodeName"]; - } else { + if (!isset($data[$prefix . "nodeName_exact"]) || $data[$prefix . "nodeName_exact"] !== true) { $data[$prefix . "nodeName"] = ["LIKE", "%" . $data[$prefix . "nodeName"] . "%"]; } } @@ -139,11 +140,11 @@ protected function processCriteria($data, string $prefix = "") } /** - * @param array|\Traversable $data + * @param array $data * @param NodeType $nodetype - * @return mixed + * @return array */ - protected function processCriteriaNodetype($data, NodeType $nodetype) + protected function processCriteriaNodetype(array $data, NodeType $nodetype): array { $fields = $nodetype->getFields(); foreach ($data as $key => $value) { @@ -197,7 +198,7 @@ protected function processCriteriaNodetype($data, NodeType $nodetype) * @return Response * @throws RuntimeError */ - public function searchNodeAction(Request $request) + public function searchNodeAction(Request $request): Response { $builder = $this->buildSimpleForm(''); $form = $this->addButtons($builder)->getForm(); @@ -253,12 +254,12 @@ public function searchNodeAction(Request $request) * @param Request $request * @param int $nodetypeId * - * @return null|RedirectResponse|Response + * @return Response * @throws Exception * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception * @throws RuntimeError */ - public function searchNodeSourceAction(Request $request, int $nodetypeId) + public function searchNodeSourceAction(Request $request, int $nodetypeId): Response { /** @var NodeType|null $nodetype */ $nodetype = $this->em()->find(NodeType::class, $nodetypeId); @@ -267,7 +268,6 @@ public function searchNodeSourceAction(Request $request, int $nodetypeId) $this->extendForm($builder, $nodetype); $this->addButtons($builder, true); - /** @var Form $form */ $form = $builder->getForm(); $form->handleRequest($request); @@ -279,7 +279,7 @@ public function searchNodeSourceAction(Request $request, int $nodetypeId) return $response; } - if (null !== $response = $this->handleNodeForm($form, $nodetype)) { + if (null !== $response = $this->handleNodeForm($request, $form, $nodetype)) { return $response; } @@ -316,11 +316,11 @@ protected function buildNodeTypeForm(?int $nodetypeId = null): FormBuilderInterf /** * @param FormBuilderInterface $builder - * @param bool $exportXlsx + * @param bool $export * * @return FormBuilderInterface */ - protected function addButtons(FormBuilderInterface $builder, bool $exportXlsx = false): FormBuilderInterface + protected function addButtons(FormBuilderInterface $builder, bool $export = false): FormBuilderInterface { $builder->add('search', SubmitType::class, [ 'label' => 'search.a.node', @@ -329,7 +329,7 @@ protected function addButtons(FormBuilderInterface $builder, bool $exportXlsx = ], ]); - if ($exportXlsx) { + if ($export) { $builder->add('export', SubmitType::class, [ 'label' => 'export.all.nodesSource', 'attr' => [ @@ -346,7 +346,7 @@ protected function addButtons(FormBuilderInterface $builder, bool $exportXlsx = * * @return null|RedirectResponse */ - protected function handleNodeTypeForm(FormInterface $nodeTypeForm) + protected function handleNodeTypeForm(FormInterface $nodeTypeForm): ?RedirectResponse { if ($nodeTypeForm->isSubmitted() && $nodeTypeForm->isValid()) { if (empty($nodeTypeForm->getData()['nodetype'])) { @@ -365,6 +365,7 @@ protected function handleNodeTypeForm(FormInterface $nodeTypeForm) } /** + * @param Request $request * @param FormInterface $form * @param NodeType $nodetype * @@ -372,7 +373,7 @@ protected function handleNodeTypeForm(FormInterface $nodeTypeForm) * @throws Exception * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception */ - protected function handleNodeForm(FormInterface $form, NodeType $nodetype): ?Response + protected function handleNodeForm(Request $request, FormInterface $form, NodeType $nodetype): ?Response { if ($form->isSubmitted() && $form->isValid()) { $data = []; @@ -418,8 +419,13 @@ protected function handleNodeForm(FormInterface $form, NodeType $nodetype): ?Res */ $button = $form->get('export'); if ($button instanceof ClickableInterface && $button->isClicked()) { + $filename = 'search-' . $nodetype->getName() . '-' . date("YmdHis") . '.xlsx'; + $this->xlsxSerializer->setOnlyTexts(true); + $this->xlsxSerializer->addUrls(); + $xlsx = $this->xlsxSerializer->serialize($entities); + $response = new Response( - $this->getXlsxResults($nodetype, $entities), + $xlsx, Response::HTTP_OK, [] ); @@ -428,10 +434,11 @@ protected function handleNodeForm(FormInterface $form, NodeType $nodetype): ?Res 'Content-Disposition', $response->headers->makeDisposition( ResponseHeaderBag::DISPOSITION_ATTACHMENT, - 'search.xlsx' + $filename ) ); + $response->prepare($request); return $response; } @@ -443,43 +450,6 @@ protected function handleNodeForm(FormInterface $form, NodeType $nodetype): ?Res return null; } - /** - * @param NodeType $nodetype - * @param array|IteratorAggregate $entities - * - * @return string - * @throws Exception - * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception - */ - protected function getXlsxResults(NodeType $nodetype, $entities): string - { - $fields = $nodetype->getFields(); - $keys = []; - $answers = []; - $keys[] = "title"; - /** @var NodeTypeField $field */ - foreach ($fields as $field) { - if (!$field->isVirtual() && !$field->isCollection()) { - $keys[] = $field->getName(); - } - } - foreach ($entities as $idx => $nodesSource) { - $array = []; - foreach ($keys as $key) { - $getter = 'get' . str_replace('_', '', ucwords($key)); - $tmp = $nodesSource->$getter(); - if (is_array($tmp)) { - $tmp = implode(',', $tmp); - } - $array[] = $tmp; - } - $answers[$idx] = $array; - } - - $exporter = new XlsxExporter($this->getTranslator()); - return $exporter->exportXlsx($answers, $keys); - } - /** * @param string $prefix * @return FormBuilderInterface diff --git a/src/Controllers/SettingsController.php b/src/Controllers/SettingsController.php index 8a57e58d..4a12ba8d 100644 --- a/src/Controllers/SettingsController.php +++ b/src/Controllers/SettingsController.php @@ -15,6 +15,7 @@ use RZ\Roadiz\CoreBundle\Exception\EntityAlreadyExistsException; use RZ\Roadiz\CoreBundle\Form\Error\FormErrorSerializer; use RZ\Roadiz\CoreBundle\Form\SettingType; +use RZ\Roadiz\CoreBundle\ListManager\SessionListFilters; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormFactoryInterface; @@ -23,18 +24,14 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Exception\ResourceNotFoundException; use Themes\Rozier\RozierApp; -use Themes\Rozier\Utils\SessionListFilters; use Twig\Error\RuntimeError; class SettingsController extends RozierApp { - private FormFactoryInterface $formFactory; - private FormErrorSerializer $formErrorSerializer; - - public function __construct(FormFactoryInterface $formFactory, FormErrorSerializer $formErrorSerializer) - { - $this->formFactory = $formFactory; - $this->formErrorSerializer = $formErrorSerializer; + public function __construct( + private readonly FormFactoryInterface $formFactory, + private readonly FormErrorSerializer $formErrorSerializer + ) { } /** diff --git a/src/Controllers/SettingsUtilsController.php b/src/Controllers/SettingsUtilsController.php index dff29f0e..8d963eb4 100644 --- a/src/Controllers/SettingsUtilsController.php +++ b/src/Controllers/SettingsUtilsController.php @@ -6,9 +6,9 @@ use JMS\Serializer\SerializationContext; use JMS\Serializer\SerializerInterface; -use RZ\Roadiz\CoreBundle\Importer\SettingsImporter; use RZ\Roadiz\CoreBundle\Entity\Setting; use RZ\Roadiz\CoreBundle\Entity\SettingGroup; +use RZ\Roadiz\CoreBundle\Importer\SettingsImporter; use RZ\Roadiz\Utils\StringHandler; use Symfony\Component\Form\Extension\Core\Type\FileType; use Symfony\Component\Form\FormError; @@ -21,17 +21,10 @@ class SettingsUtilsController extends RozierApp { - private SerializerInterface $serializer; - private SettingsImporter $settingsImporter; - - /** - * @param SerializerInterface $serializer - * @param SettingsImporter $settingsImporter - */ - public function __construct(SerializerInterface $serializer, SettingsImporter $settingsImporter) - { - $this->serializer = $serializer; - $this->settingsImporter = $settingsImporter; + public function __construct( + private readonly SerializerInterface $serializer, + private readonly SettingsImporter $settingsImporter + ) { } /** diff --git a/src/Controllers/Tags/TagMultiCreationController.php b/src/Controllers/Tags/TagMultiCreationController.php index f71ddb4a..fa8632b9 100644 --- a/src/Controllers/Tags/TagMultiCreationController.php +++ b/src/Controllers/Tags/TagMultiCreationController.php @@ -9,7 +9,6 @@ use RZ\Roadiz\CoreBundle\Event\Tag\TagCreatedEvent; use RZ\Roadiz\CoreBundle\Tag\TagFactory; use Symfony\Component\Form\FormError; -use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Exception\ResourceNotFoundException; @@ -18,79 +17,73 @@ class TagMultiCreationController extends RozierApp { - private TagFactory $tagFactory; - - /** - * @param TagFactory $tagFactory - */ - public function __construct(TagFactory $tagFactory) + public function __construct(private readonly TagFactory $tagFactory) { - $this->tagFactory = $tagFactory; } /** * @param Request $request * @param int $parentTagId - * @return RedirectResponse|Response|null + * @return Response * @throws \Twig\Error\RuntimeError */ - public function addChildAction(Request $request, int $parentTagId) + public function addChildAction(Request $request, int $parentTagId): Response { $this->denyAccessUnlessGranted('ROLE_ACCESS_TAGS'); $translation = $this->em()->getRepository(Translation::class)->findDefault(); $parentTag = $this->em()->find(Tag::class, $parentTagId); - if (null !== $parentTag) { - $form = $this->createForm(MultiTagType::class); - $form->handleRequest($request); - - if ($form->isSubmitted() && $form->isValid()) { - try { - $data = $form->getData(); - $names = explode(',', $data['names']); - $names = array_map('trim', $names); - $names = array_filter($names); - $names = array_unique($names); - - /* - * Get latest position to add tags after. - */ - $latestPosition = $this->em() - ->getRepository(Tag::class) - ->findLatestPositionInParent($parentTag); + if (null === $parentTag) { + throw new ResourceNotFoundException(); + } - $tagsArray = []; - foreach ($names as $name) { - $tagsArray[] = $this->tagFactory->create($name, $translation, $parentTag, $latestPosition); - $this->em()->flush(); - } + $form = $this->createForm(MultiTagType::class); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + try { + $data = $form->getData(); + $names = explode(',', $data['names']); + $names = array_map('trim', $names); + $names = array_filter($names); + $names = array_unique($names); + + /* + * Get latest position to add tags after. + */ + $latestPosition = $this->em() + ->getRepository(Tag::class) + ->findLatestPositionInParent($parentTag); + + $tagsArray = []; + foreach ($names as $name) { + $tagsArray[] = $this->tagFactory->create($name, $translation, $parentTag, $latestPosition); + $this->em()->flush(); + } + /* + * Dispatch event and msg + */ + foreach ($tagsArray as $tag) { /* - * Dispatch event and msg + * Dispatch event */ - foreach ($tagsArray as $tag) { - /* - * Dispatch event - */ - $this->dispatchEvent(new TagCreatedEvent($tag)); - $msg = $this->getTranslator()->trans('child.tag.%name%.created', ['%name%' => $tag->getTagName()]); - $this->publishConfirmMessage($request, $msg, $tag); - } - - return $this->redirectToRoute('tagsTreePage', ['tagId' => $parentTagId]); - } catch (\InvalidArgumentException $e) { - $form->addError(new FormError($e->getMessage())); + $this->dispatchEvent(new TagCreatedEvent($tag)); + $msg = $this->getTranslator()->trans('child.tag.%name%.created', ['%name%' => $tag->getTagName()]); + $this->publishConfirmMessage($request, $msg, $tag); } - } - $this->assignation['translation'] = $translation; - $this->assignation['form'] = $form->createView(); - $this->assignation['tag'] = $parentTag; - - return $this->render('@RoadizRozier/tags/add-multiple.html.twig', $this->assignation); + return $this->redirectToRoute('tagsTreePage', ['tagId' => $parentTagId]); + } catch (\InvalidArgumentException $e) { + $form->addError(new FormError($e->getMessage())); + } } - throw new ResourceNotFoundException(); + $this->assignation['translation'] = $translation; + $this->assignation['form'] = $form->createView(); + $this->assignation['tag'] = $parentTag; + + return $this->render('@RoadizRozier/tags/add-multiple.html.twig', $this->assignation); } } diff --git a/src/Controllers/Tags/TagsController.php b/src/Controllers/Tags/TagsController.php index ca50fb93..9a766e71 100644 --- a/src/Controllers/Tags/TagsController.php +++ b/src/Controllers/Tags/TagsController.php @@ -15,6 +15,7 @@ use RZ\Roadiz\CoreBundle\Event\Tag\TagDeletedEvent; use RZ\Roadiz\CoreBundle\Event\Tag\TagUpdatedEvent; use RZ\Roadiz\CoreBundle\Exception\EntityAlreadyExistsException; +use RZ\Roadiz\CoreBundle\Form\Error\FormErrorSerializer; use RZ\Roadiz\CoreBundle\Repository\TranslationRepository; use RZ\Roadiz\Utils\StringHandler; use Symfony\Component\Form\Extension\Core\Type\HiddenType; @@ -39,23 +40,12 @@ class TagsController extends RozierApp { use VersionedControllerTrait; - private HandlerFactoryInterface $handlerFactory; - private FormFactoryInterface $formFactory; - private TreeWidgetFactory $treeWidgetFactory; - - /** - * @param FormFactoryInterface $formFactory - * @param HandlerFactoryInterface $handlerFactory - * @param TreeWidgetFactory $treeWidgetFactory - */ public function __construct( - FormFactoryInterface $formFactory, - HandlerFactoryInterface $handlerFactory, - TreeWidgetFactory $treeWidgetFactory + private readonly FormFactoryInterface $formFactory, + private readonly FormErrorSerializer $formErrorSerializer, + private readonly HandlerFactoryInterface $handlerFactory, + private readonly TreeWidgetFactory $treeWidgetFactory ) { - $this->handlerFactory = $handlerFactory; - $this->formFactory = $formFactory; - $this->treeWidgetFactory = $treeWidgetFactory; } /** @@ -214,7 +204,7 @@ public function editTranslatedAction(Request $request, int $tagId, ?int $transla * Handle errors when Ajax POST requests */ if ($isJsonRequest) { - $errors = $this->getErrorsAsArray($form); + $errors = $this->formErrorSerializer->getErrorsAsArray($form); return new JsonResponse([ 'status' => 'fail', 'errors' => $errors, @@ -304,8 +294,8 @@ public function bulkDeleteAction(Request $request): Response /** * @param Request $request - * * @return Response + * @throws RuntimeError */ public function addAction(Request $request): Response { @@ -361,6 +351,7 @@ public function addAction(Request $request): Response * @param int $tagId * * @return Response + * @throws RuntimeError */ public function editSettingsAction(Request $request, int $tagId): Response { @@ -408,7 +399,7 @@ public function editSettingsAction(Request $request, int $tagId): Response * Handle errors when Ajax POST requests */ if ($isJsonRequest) { - $errors = $this->getErrorsAsArray($form); + $errors = $this->formErrorSerializer->getErrorsAsArray($form); return new JsonResponse([ 'status' => 'fail', 'errors' => $errors, @@ -430,6 +421,7 @@ public function editSettingsAction(Request $request, int $tagId): Response * @param int|null $translationId * * @return Response + * @throws RuntimeError */ public function treeAction(Request $request, int $tagId, ?int $translationId = null): Response { @@ -461,9 +453,10 @@ public function treeAction(Request $request, int $tagId, ?int $translationId = n * Return a deletion form for requested tag. * * @param Request $request - * @param int $tagId + * @param int $tagId * * @return Response + * @throws RuntimeError */ public function deleteAction(Request $request, int $tagId): Response { @@ -523,6 +516,7 @@ public function deleteAction(Request $request, int $tagId): Response * @param int|null $translationId * * @return Response + * @throws RuntimeError */ public function addChildAction(Request $request, int $tagId, ?int $translationId = null): Response { @@ -649,13 +643,13 @@ private function buildDeleteForm(Tag $tag): FormInterface } /** - * @param false|string $referer + * @param null|string $referer * @param array $tagsIds * * @return FormInterface */ private function buildBulkDeleteForm( - $referer = false, + ?string $referer = null, array $tagsIds = [] ): FormInterface { $builder = $this->formFactory @@ -669,7 +663,7 @@ private function buildBulkDeleteForm( ], ]); - if (false !== $referer && (new UnicodeString($referer))->startsWith('/')) { + if (null !== $referer && (new UnicodeString($referer))->startsWith('/')) { $builder->add('referer', HiddenType::class, [ 'data' => $referer, ]); diff --git a/src/Controllers/Tags/TagsUtilsController.php b/src/Controllers/Tags/TagsUtilsController.php index 1108a87d..71f96693 100644 --- a/src/Controllers/Tags/TagsUtilsController.php +++ b/src/Controllers/Tags/TagsUtilsController.php @@ -14,14 +14,8 @@ class TagsUtilsController extends RozierApp { - private SerializerInterface $serializer; - - /** - * @param SerializerInterface $serializer - */ - public function __construct(SerializerInterface $serializer) + public function __construct(private readonly SerializerInterface $serializer) { - $this->serializer = $serializer; } /** diff --git a/src/Controllers/TranslationsController.php b/src/Controllers/TranslationsController.php index 968a268e..601c24b1 100644 --- a/src/Controllers/TranslationsController.php +++ b/src/Controllers/TranslationsController.php @@ -4,12 +4,12 @@ namespace Themes\Rozier\Controllers; +use RZ\Roadiz\Core\Handlers\HandlerFactoryInterface; use RZ\Roadiz\CoreBundle\Entity\Translation; +use RZ\Roadiz\CoreBundle\EntityHandler\TranslationHandler; use RZ\Roadiz\CoreBundle\Event\Translation\TranslationCreatedEvent; use RZ\Roadiz\CoreBundle\Event\Translation\TranslationDeletedEvent; use RZ\Roadiz\CoreBundle\Event\Translation\TranslationUpdatedEvent; -use RZ\Roadiz\Core\Handlers\HandlerFactoryInterface; -use RZ\Roadiz\CoreBundle\EntityHandler\TranslationHandler; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\FormError; use Symfony\Component\HttpFoundation\Request; @@ -23,11 +23,8 @@ class TranslationsController extends RozierApp { public const ITEM_PER_PAGE = 5; - private HandlerFactoryInterface $handlerFactory; - - public function __construct(HandlerFactoryInterface $handlerFactory) + public function __construct(private readonly HandlerFactoryInterface $handlerFactory) { - $this->handlerFactory = $handlerFactory; } /** diff --git a/src/Controllers/Users/UsersController.php b/src/Controllers/Users/UsersController.php index dc6999df..a2ded208 100644 --- a/src/Controllers/Users/UsersController.php +++ b/src/Controllers/Users/UsersController.php @@ -4,12 +4,15 @@ namespace Themes\Rozier\Controllers\Users; +use JMS\Serializer\SerializerInterface; use RZ\Roadiz\Core\AbstractEntities\PersistableInterface; use RZ\Roadiz\CoreBundle\Entity\Role; use RZ\Roadiz\CoreBundle\Entity\User; +use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Themes\Rozier\Controllers\AbstractAdminWithBulkController; use Themes\Rozier\Forms\UserDetailsType; use Themes\Rozier\Forms\UserType; @@ -17,6 +20,16 @@ class UsersController extends AbstractAdminWithBulkController { + public function __construct( + FormFactoryInterface $formFactory, + SerializerInterface $serializer, + UrlGeneratorInterface $urlGenerator, + private readonly bool $useGravatar + ) { + parent::__construct($formFactory, $serializer, $urlGenerator); + } + + protected function supports(PersistableInterface $item): bool { return $item instanceof User; @@ -123,7 +136,7 @@ protected function createUpdateEvent(PersistableInterface $item) /* * If pictureUrl is empty, use default Gravatar image. */ - if ($item->getPictureUrl() == '') { + if ($item->getPictureUrl() == '' && $this->useGravatar) { $item->setPictureUrl($item->getGravatarUrl()); } diff --git a/src/Controllers/WebhookController.php b/src/Controllers/WebhookController.php index b67c79f7..60bccc70 100644 --- a/src/Controllers/WebhookController.php +++ b/src/Controllers/WebhookController.php @@ -19,16 +19,13 @@ final class WebhookController extends AbstractAdminWithBulkController { - private WebhookDispatcher $webhookDispatcher; - public function __construct( - WebhookDispatcher $webhookDispatcher, + private readonly WebhookDispatcher $webhookDispatcher, FormFactoryInterface $formFactory, SerializerInterface $serializer, UrlGeneratorInterface $urlGenerator ) { parent::__construct($formFactory, $serializer, $urlGenerator); - $this->webhookDispatcher = $webhookDispatcher; } public function triggerAction(Request $request, string $id): Response diff --git a/src/Explorer/ConfigurableExplorerItem.php b/src/Explorer/ConfigurableExplorerItem.php index bc86157e..c4ee98d4 100644 --- a/src/Explorer/ConfigurableExplorerItem.php +++ b/src/Explorer/ConfigurableExplorerItem.php @@ -17,27 +17,14 @@ final class ConfigurableExplorerItem extends AbstractExplorerItem { - private PersistableInterface $entity; - private array $configuration; - private RendererInterface $renderer; - private DocumentUrlGeneratorInterface $documentUrlGenerator; - private UrlGeneratorInterface $urlGenerator; - private ?EmbedFinderFactory $embedFinderFactory; - public function __construct( - PersistableInterface $entity, - array &$configuration, - RendererInterface $renderer, - DocumentUrlGeneratorInterface $documentUrlGenerator, - UrlGeneratorInterface $urlGenerator, - ?EmbedFinderFactory $embedFinderFactory = null + private readonly PersistableInterface $entity, + private readonly array &$configuration, + private readonly RendererInterface $renderer, + private readonly DocumentUrlGeneratorInterface $documentUrlGenerator, + private readonly UrlGeneratorInterface $urlGenerator, + private readonly ?EmbedFinderFactory $embedFinderFactory = null ) { - $this->entity = $entity; - $this->configuration = $configuration; - $this->renderer = $renderer; - $this->documentUrlGenerator = $documentUrlGenerator; - $this->urlGenerator = $urlGenerator; - $this->embedFinderFactory = $embedFinderFactory; } /** diff --git a/src/Explorer/FolderExplorerItem.php b/src/Explorer/FolderExplorerItem.php index 9a85e7ae..f2ffe508 100644 --- a/src/Explorer/FolderExplorerItem.php +++ b/src/Explorer/FolderExplorerItem.php @@ -10,13 +10,10 @@ final class FolderExplorerItem extends AbstractExplorerItem { - private Folder $folder; - private UrlGeneratorInterface $urlGenerator; - - public function __construct(Folder $folder, UrlGeneratorInterface $urlGenerator) - { - $this->folder = $folder; - $this->urlGenerator = $urlGenerator; + public function __construct( + private readonly Folder $folder, + private readonly UrlGeneratorInterface $urlGenerator + ) { } /** diff --git a/src/Explorer/SettingExplorerItem.php b/src/Explorer/SettingExplorerItem.php index 5c0fd190..9145f861 100644 --- a/src/Explorer/SettingExplorerItem.php +++ b/src/Explorer/SettingExplorerItem.php @@ -10,13 +10,10 @@ final class SettingExplorerItem extends AbstractExplorerItem { - private Setting $setting; - private UrlGeneratorInterface $urlGenerator; - - public function __construct(Setting $setting, UrlGeneratorInterface $urlGenerator) - { - $this->setting = $setting; - $this->urlGenerator = $urlGenerator; + public function __construct( + private readonly Setting $setting, + private readonly UrlGeneratorInterface $urlGenerator + ) { } /** diff --git a/src/Explorer/UserExplorerItem.php b/src/Explorer/UserExplorerItem.php index b7012f16..60b1a32a 100644 --- a/src/Explorer/UserExplorerItem.php +++ b/src/Explorer/UserExplorerItem.php @@ -10,13 +10,10 @@ final class UserExplorerItem extends AbstractExplorerItem { - private User $user; - private UrlGeneratorInterface $urlGenerator; - - public function __construct(User $user, UrlGeneratorInterface $urlGenerator) - { - $this->user = $user; - $this->urlGenerator = $urlGenerator; + public function __construct( + private readonly User $user, + private readonly UrlGeneratorInterface $urlGenerator + ) { } /** diff --git a/src/Forms/CustomFormFieldType.php b/src/Forms/CustomFormFieldType.php index 0fc5675a..f0e25cd8 100644 --- a/src/Forms/CustomFormFieldType.php +++ b/src/Forms/CustomFormFieldType.php @@ -5,7 +5,9 @@ namespace Themes\Rozier\Forms; use RZ\Roadiz\CoreBundle\Entity\CustomFormField; +use RZ\Roadiz\CoreBundle\Form\DataListTextType; use RZ\Roadiz\CoreBundle\Form\MarkdownType; +use RZ\Roadiz\CoreBundle\Repository\CustomFormFieldRepository; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; @@ -16,6 +18,20 @@ class CustomFormFieldType extends AbstractType { + public function __construct( + private readonly CustomFormFieldRepository $customFormFieldRepository + ) { + } + + /** + * @param CustomFormField $field + * @return string[] + */ + protected function getAllGroupsNames(CustomFormField $field): array + { + return $this->customFormFieldRepository->findDistinctGroupNamesInCustomForm($field->getCustomForm()); + } + public function buildForm(FormBuilderInterface $builder, array $options): void { $builder->add('label', TextType::class, [ @@ -57,10 +73,51 @@ public function buildForm(FormBuilderInterface $builder, array $options): void ], ] ) - ->add('groupName', TextType::class, [ + ->add('groupName', DataListTextType::class, [ 'label' => 'groupName', 'required' => false, 'help' => 'use_the_same_group_names_over_fields_to_gather_them_in_tabs', + 'list' => $this->getAllGroupsNames($builder->getData()), + 'listName' => 'group-names', + 'attr' => [ + 'autocomplete' => 'off', + ], + ]) + ->add('autocomplete', ChoiceType::class, [ + 'label' => 'customForm.autocomplete', + 'help' => 'customForm.autocomplete.help', + 'choices' => [ + 'off', + 'name', + 'honorific-prefix', + 'honorific-suffix', + 'given-name', + 'additional-name', + 'family-name', + 'nickname', + 'email', + 'username', + 'organization-title', + 'organization', + 'street-address', + 'country', + 'country-name', + 'postal-code', + 'bday', + 'bday-day', + 'bday-month', + 'bday-year', + 'sex', + 'tel', + 'tel-national', + 'url', + 'photo', + ], + 'placeholder' => 'autocomplete.no_autocomplete', + 'choice_label' => function ($choice, $key, $value) { + return 'autocomplete.' . $value; + }, + 'required' => false, ]); } diff --git a/src/Forms/CustomFormType.php b/src/Forms/CustomFormType.php new file mode 100644 index 00000000..57858f3b --- /dev/null +++ b/src/Forms/CustomFormType.php @@ -0,0 +1,121 @@ +security = $security; + } + + public function buildForm(FormBuilderInterface $builder, array $options): void + { + $builder->add('displayName', TextType::class, [ + 'label' => 'customForm.displayName', + 'empty_data' => '', + ]) + ->add('description', MarkdownType::class, [ + 'label' => 'description', + 'required' => false, + ]) + ->add('email', TextType::class, [ + 'label' => 'email', + 'required' => false, + 'constraints' => [ + new Callback(function ($value, ExecutionContextInterface $context) { + $emails = array_filter( + array_map('trim', explode(',', $value ?? '')) + ); + foreach ($emails as $email) { + if (false === filter_var($email, FILTER_VALIDATE_EMAIL)) { + $context->buildViolation('{{ value }} is not a valid email address.') + ->setParameter('{{ value }}', $email) + ->setCode(Email::INVALID_FORMAT_ERROR) + ->addViolation(); + } + } + }), + ], + ]) + ; + if ($this->security->isGranted('ROLE_ACCESS_CUSTOMFORMS_RETENTION')) { + $builder->add('retentionTime', ChoiceType::class, [ + 'label' => 'customForm.retentionTime', + 'help' => 'customForm.retentionTime.help', + 'required' => false, + 'placeholder' => 'customForm.retentionTime.always', + 'choices' => [ + 'customForm.retentionTime.one_week' => 'P7D', + 'customForm.retentionTime.two_weeks' => 'P14D', + 'customForm.retentionTime.one_month' => 'P1M', + 'customForm.retentionTime.three_months' => 'P3M', + 'customForm.retentionTime.six_months' => 'P6M', + 'customForm.retentionTime.one_year' => 'P1Y', + 'customForm.retentionTime.two_years' => 'P2Y', + ] + ]); + } + $builder->add('open', CheckboxType::class, [ + 'label' => 'customForm.open', + 'required' => false, + ]) + ->add('closeDate', DateTimeType::class, [ + 'label' => 'customForm.closeDate', + 'required' => false, + 'date_widget' => 'single_text', + 'date_format' => 'yyyy-MM-dd', + 'attr' => [ + 'class' => 'rz-datetime-field', + ], + 'placeholder' => [ + 'hour' => 'hour', + 'minute' => 'minute', + ], + ]) + ->add('color', ColorType::class, [ + 'label' => 'customForm.color', + 'required' => false, + ]); + } + + public function getBlockPrefix(): string + { + return 'customform'; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'label' => false, + 'name' => '', + 'data_class' => CustomForm::class, + 'attr' => [ + 'class' => 'uk-form custom-form-form', + ], + ]); + $resolver->setAllowedTypes('name', 'string'); + } +} diff --git a/src/Forms/DocumentEditType.php b/src/Forms/DocumentEditType.php index 047dc8d6..b016ee93 100644 --- a/src/Forms/DocumentEditType.php +++ b/src/Forms/DocumentEditType.php @@ -17,7 +17,7 @@ use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Security\Core\Security; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\Validator\Constraints\File; use Symfony\Component\Validator\Constraints\LessThanOrEqual; use Symfony\Component\Validator\Constraints\NotBlank; diff --git a/src/Forms/DocumentTranslationType.php b/src/Forms/DocumentTranslationType.php index 946c5821..ea1fd10a 100644 --- a/src/Forms/DocumentTranslationType.php +++ b/src/Forms/DocumentTranslationType.php @@ -4,8 +4,8 @@ namespace Themes\Rozier\Forms; -use RZ\Roadiz\CoreBundle\Form\MarkdownType; use RZ\Roadiz\CoreBundle\Entity\DocumentTranslation; +use RZ\Roadiz\CoreBundle\Form\MarkdownType; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\HiddenType; use Symfony\Component\Form\Extension\Core\Type\TextType; @@ -29,7 +29,11 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'required' => false, ]) ->add('copyright', TextType::class, [ - 'label' => 'copyright', + 'label' => 'document.copyrightHolder', + 'required' => false, + ]) + ->add('externalUrl', TextType::class, [ + 'label' => 'document.externalUrl', 'required' => false, ]); } diff --git a/src/Forms/FolderCollectionType.php b/src/Forms/FolderCollectionType.php index aa1db351..c580bf84 100644 --- a/src/Forms/FolderCollectionType.php +++ b/src/Forms/FolderCollectionType.php @@ -17,14 +17,8 @@ final class FolderCollectionType extends AbstractType { - protected ManagerRegistry $managerRegistry; - - /** - * @param ManagerRegistry $managerRegistry - */ - public function __construct(ManagerRegistry $managerRegistry) + public function __construct(private readonly ManagerRegistry $managerRegistry) { - $this->managerRegistry = $managerRegistry; } /** diff --git a/src/Forms/NodeSource/NodeSourceCustomFormType.php b/src/Forms/NodeSource/NodeSourceCustomFormType.php index b46f3a90..be552197 100644 --- a/src/Forms/NodeSource/NodeSourceCustomFormType.php +++ b/src/Forms/NodeSource/NodeSourceCustomFormType.php @@ -19,16 +19,11 @@ */ final class NodeSourceCustomFormType extends AbstractNodeSourceFieldType { - protected NodeHandler $nodeHandler; - - /** - * @param ManagerRegistry $managerRegistry - * @param NodeHandler $nodeHandler - */ - public function __construct(ManagerRegistry $managerRegistry, NodeHandler $nodeHandler) - { + public function __construct( + ManagerRegistry $managerRegistry, + private readonly NodeHandler $nodeHandler + ) { parent::__construct($managerRegistry); - $this->nodeHandler = $nodeHandler; } /** @@ -85,7 +80,7 @@ public function onPreSetData(FormEvent $event): void $event->setData($this->managerRegistry ->getRepository(CustomForm::class) - ->findByNodeAndField($nodeSource->getNode(), $nodeTypeField)); + ->findByNodeAndFieldName($nodeSource->getNode(), $nodeTypeField->getName())); } /** diff --git a/src/Forms/NodeSource/NodeSourceDocumentType.php b/src/Forms/NodeSource/NodeSourceDocumentType.php index 0278872f..efcce674 100644 --- a/src/Forms/NodeSource/NodeSourceDocumentType.php +++ b/src/Forms/NodeSource/NodeSourceDocumentType.php @@ -19,16 +19,11 @@ */ final class NodeSourceDocumentType extends AbstractNodeSourceFieldType { - protected NodesSourcesHandler $nodesSourcesHandler; - - /** - * @param ManagerRegistry $managerRegistry - * @param NodesSourcesHandler $nodesSourcesHandler - */ - public function __construct(ManagerRegistry $managerRegistry, NodesSourcesHandler $nodesSourcesHandler) - { + public function __construct( + ManagerRegistry $managerRegistry, + private readonly NodesSourcesHandler $nodesSourcesHandler + ) { parent::__construct($managerRegistry); - $this->nodesSourcesHandler = $nodesSourcesHandler; } /** @@ -88,9 +83,9 @@ public function onPreSetData(FormEvent $event): void $event->setData($this->managerRegistry ->getRepository(Document::class) - ->findByNodeSourceAndField( + ->findByNodeSourceAndFieldName( $nodeSource, - $nodeTypeField + $nodeTypeField->getName() )); } diff --git a/src/Forms/NodeSource/NodeSourceNodeType.php b/src/Forms/NodeSource/NodeSourceNodeType.php index 472f3dd2..779badd0 100644 --- a/src/Forms/NodeSource/NodeSourceNodeType.php +++ b/src/Forms/NodeSource/NodeSourceNodeType.php @@ -20,16 +20,9 @@ */ final class NodeSourceNodeType extends AbstractNodeSourceFieldType { - protected NodeHandler $nodeHandler; - - /** - * @param ManagerRegistry $managerRegistry - * @param NodeHandler $nodeHandler - */ - public function __construct(ManagerRegistry $managerRegistry, NodeHandler $nodeHandler) + public function __construct(ManagerRegistry $managerRegistry, private readonly NodeHandler $nodeHandler) { parent::__construct($managerRegistry); - $this->nodeHandler = $nodeHandler; } /** diff --git a/src/Forms/NodeSource/NodeSourceProviderType.php b/src/Forms/NodeSource/NodeSourceProviderType.php index 9132793c..852728bd 100644 --- a/src/Forms/NodeSource/NodeSourceProviderType.php +++ b/src/Forms/NodeSource/NodeSourceProviderType.php @@ -19,16 +19,9 @@ final class NodeSourceProviderType extends AbstractConfigurableNodeSourceFieldType { - protected ContainerInterface $container; - - /** - * @param ManagerRegistry $managerRegistry - * @param ContainerInterface $container - */ - public function __construct(ManagerRegistry $managerRegistry, ContainerInterface $container) + public function __construct(ManagerRegistry $managerRegistry, private readonly ContainerInterface $container) { parent::__construct($managerRegistry); - $this->container = $container; } /** diff --git a/src/Forms/NodeSource/NodeSourceType.php b/src/Forms/NodeSource/NodeSourceType.php index 366408a4..22aab62a 100644 --- a/src/Forms/NodeSource/NodeSourceType.php +++ b/src/Forms/NodeSource/NodeSourceType.php @@ -18,6 +18,7 @@ use RZ\Roadiz\CoreBundle\Form\MultipleEnumerationType; use RZ\Roadiz\CoreBundle\Form\YamlType; use RZ\Roadiz\CoreBundle\Security\Authorization\Voter\NodeTypeFieldVoter; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\CountryType; @@ -31,7 +32,6 @@ use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Security\Core\Security; use Symfony\Component\Validator\Constraints\Email; use Symfony\Component\Validator\Constraints\Length; use Symfony\Component\Validator\Constraints\Type; @@ -41,13 +41,10 @@ final class NodeSourceType extends AbstractType { - protected ManagerRegistry $managerRegistry; - private Security $security; - - public function __construct(ManagerRegistry $managerRegistry, Security $security) - { - $this->managerRegistry = $managerRegistry; - $this->security = $security; + public function __construct( + private readonly ManagerRegistry $managerRegistry, + private readonly Security $security + ) { } /** diff --git a/src/Forms/NodeType.php b/src/Forms/NodeType.php index c85a0b4f..9cf491af 100644 --- a/src/Forms/NodeType.php +++ b/src/Forms/NodeType.php @@ -31,7 +31,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void /** @var Node|null $node */ $node = $builder->getData(); - $isReachable = null !== $node && $node->getNodeType()?->isReachable(); + $isReachable = null !== $node && $node->getNodeType()->isReachable(); if ($isReachable) { $builder->add('home', CheckboxType::class, [ 'label' => 'node.isHome', diff --git a/src/Models/CustomFormModel.php b/src/Models/CustomFormModel.php index 7724af37..c5f63d45 100644 --- a/src/Models/CustomFormModel.php +++ b/src/Models/CustomFormModel.php @@ -10,23 +10,14 @@ final class CustomFormModel implements ModelInterface { - private CustomForm $customForm; - private UrlGeneratorInterface $urlGenerator; - private TranslatorInterface $translator; - - /** - * @param CustomForm $customForm - * @param UrlGeneratorInterface $urlGenerator - * @param TranslatorInterface $translator - */ - public function __construct(CustomForm $customForm, UrlGeneratorInterface $urlGenerator, TranslatorInterface $translator) - { - $this->customForm = $customForm; - $this->urlGenerator = $urlGenerator; - $this->translator = $translator; + public function __construct( + private readonly CustomForm $customForm, + private readonly UrlGeneratorInterface $urlGenerator, + private readonly TranslatorInterface $translator + ) { } - public function toArray() + public function toArray(): array { $countFields = strip_tags($this->translator->trans( '{0} no.customFormField|{1} 1.customFormField|]1,Inf] %count%.customFormFields', diff --git a/src/Models/DocumentModel.php b/src/Models/DocumentModel.php index ad4e6f98..83ae0b92 100644 --- a/src/Models/DocumentModel.php +++ b/src/Models/DocumentModel.php @@ -37,31 +37,13 @@ final class DocumentModel implements ModelInterface "noProcess" => true, ]; - private DocumentInterface $document; - private RendererInterface $renderer; - private DocumentUrlGeneratorInterface $documentUrlGenerator; - private UrlGeneratorInterface $urlGenerator; - private ?EmbedFinderFactory $embedFinderFactory; - - /** - * @param DocumentInterface $document - * @param RendererInterface $renderer - * @param DocumentUrlGeneratorInterface $documentUrlGenerator - * @param UrlGeneratorInterface $urlGenerator - * @param EmbedFinderFactory|null $embedFinderFactory - */ public function __construct( - DocumentInterface $document, - RendererInterface $renderer, - DocumentUrlGeneratorInterface $documentUrlGenerator, - UrlGeneratorInterface $urlGenerator, - ?EmbedFinderFactory $embedFinderFactory = null + private readonly DocumentInterface $document, + private readonly RendererInterface $renderer, + private readonly DocumentUrlGeneratorInterface $documentUrlGenerator, + private readonly UrlGeneratorInterface $urlGenerator, + private readonly ?EmbedFinderFactory $embedFinderFactory = null ) { - $this->document = $document; - $this->renderer = $renderer; - $this->documentUrlGenerator = $documentUrlGenerator; - $this->urlGenerator = $urlGenerator; - $this->embedFinderFactory = $embedFinderFactory; } public function toArray(): array diff --git a/src/Models/NodeModel.php b/src/Models/NodeModel.php index d7ad14e8..50a1bc0c 100644 --- a/src/Models/NodeModel.php +++ b/src/Models/NodeModel.php @@ -11,7 +11,7 @@ use RZ\Roadiz\CoreBundle\Entity\Translation; use RZ\Roadiz\CoreBundle\Security\Authorization\Voter\NodeVoter; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; -use Symfony\Component\Security\Core\Security; +use Symfony\Bundle\SecurityBundle\Security; /** * @Serializer\ExclusionPolicy("all") @@ -19,9 +19,9 @@ final class NodeModel implements ModelInterface { public function __construct( - private Node $node, - private UrlGeneratorInterface $urlGenerator, - private Security $security + private readonly Node $node, + private readonly UrlGeneratorInterface $urlGenerator, + private readonly Security $security ) { } @@ -37,7 +37,7 @@ public function toArray(): array 'nodeName' => $this->node->getNodeName(), 'isPublished' => $this->node->isPublished(), 'nodeType' => [ - 'color' => $this->node->getNodeType()?->getColor() ?? '#000000', + 'color' => $this->node->getNodeType()->getColor() ?? '#000000', ] ]; if ($this->security->isGranted(NodeVoter::EDIT_SETTING, $this->node)) { @@ -60,7 +60,7 @@ public function toArray(): array 'nodeName' => $this->node->getNodeName(), 'isPublished' => $this->node->isPublished(), 'nodeType' => [ - 'color' => $this->node->getNodeType()?->getColor() ?? '#000000', + 'color' => $this->node->getNodeType()->getColor() ?? '#000000', ] ]; diff --git a/src/Models/NodeSourceModel.php b/src/Models/NodeSourceModel.php index 476cc011..831105e4 100644 --- a/src/Models/NodeSourceModel.php +++ b/src/Models/NodeSourceModel.php @@ -10,7 +10,7 @@ use RZ\Roadiz\CoreBundle\Entity\Translation; use RZ\Roadiz\CoreBundle\Security\Authorization\Voter\NodeVoter; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; -use Symfony\Component\Security\Core\Security; +use Symfony\Bundle\SecurityBundle\Security; /** * @Serializer\ExclusionPolicy("all") @@ -18,9 +18,9 @@ final class NodeSourceModel implements ModelInterface { public function __construct( - private NodesSources $nodeSource, - private UrlGeneratorInterface $urlGenerator, - private Security $security + private readonly NodesSources $nodeSource, + private readonly UrlGeneratorInterface $urlGenerator, + private readonly Security $security ) { } @@ -40,7 +40,7 @@ public function toArray(): array 'thumbnail' => $thumbnail ? $thumbnail->getDocument() : null, 'isPublished' => $node->isPublished(), 'nodeType' => [ - 'color' => $node->getNodeType()?->getColor() ?? '#000000', + 'color' => $node->getNodeType()->getColor() ?? '#000000', ] ]; diff --git a/src/Models/NodeTypeModel.php b/src/Models/NodeTypeModel.php index 6c26967f..240eb02b 100644 --- a/src/Models/NodeTypeModel.php +++ b/src/Models/NodeTypeModel.php @@ -8,14 +8,8 @@ final class NodeTypeModel implements ModelInterface { - private NodeType $nodeType; - - /** - * @param NodeType $nodeType - */ - public function __construct(NodeType $nodeType) + public function __construct(private readonly NodeType $nodeType) { - $this->nodeType = $nodeType; } public function toArray(): array diff --git a/src/Models/TagModel.php b/src/Models/TagModel.php index d22864d9..fd561900 100644 --- a/src/Models/TagModel.php +++ b/src/Models/TagModel.php @@ -9,13 +9,10 @@ final class TagModel implements ModelInterface { - private Tag $tag; - private UrlGeneratorInterface $urlGenerator; - - public function __construct(Tag $tag, UrlGeneratorInterface $urlGenerator) - { - $this->tag = $tag; - $this->urlGenerator = $urlGenerator; + public function __construct( + private readonly Tag $tag, + private readonly UrlGeneratorInterface $urlGenerator + ) { } public function toArray(): array diff --git a/src/Resources/app/less/actions_menu/actions_menu.less b/src/Resources/app/less/actions_menu/actions_menu.less index a6ce1ef6..9367a332 100644 --- a/src/Resources/app/less/actions_menu/actions_menu.less +++ b/src/Resources/app/less/actions_menu/actions_menu.less @@ -120,7 +120,7 @@ z-index: 99999; } &.uk-button-primary:before { - background-color: var(--accent-color-darker); + background-color: var(--rz-accent-color-darker); } &.uk-button-success:before { background-color: @success-color; @@ -168,7 +168,7 @@ &.uk-button-primary { .label-text { - background-color: var(--accent-color-darker); + background-color: var(--rz-accent-color-darker); } } &.uk-button-success { diff --git a/src/Resources/app/less/buttons/buttons.less b/src/Resources/app/less/buttons/buttons.less index 0468f1a5..27e5d175 100644 --- a/src/Resources/app/less/buttons/buttons.less +++ b/src/Resources/app/less/buttons/buttons.less @@ -124,18 +124,18 @@ &.uk-button-primary { background: var(--main-contrast-color-30); - border-color: var(--accent-color-darker); + border-color: var(--rz-accent-color-darker); [class*=uk-icon-]{ - color: var(--accent-color-darkest); + color: var(--rz-accent-color-darkest); } &:hover, &:focus{ background: var(--main-contrast-color-30); - border-color: var(--accent-color-darkest); + border-color: var(--rz-accent-color-darkest); [class*=uk-icon-]{ - color: var(--accent-color-darkest); + color: var(--rz-accent-color-darkest); } } } @@ -311,7 +311,7 @@ .uk-button-primary { &:not(:disabled) { - background: var(--accent-color-darker); + background: var(--rz-accent-color-darker); border-color: transparent; color: white; text-shadow: none; @@ -321,7 +321,7 @@ } &:hover, &:active, &:focus { - background: var(--accent-color); + background: var(--rz-accent-color); border-color: transparent; color: white; } @@ -351,9 +351,12 @@ &:hover { opacity: 0.8; - border-color: var(--accent-color); + border-color: var(--rz-accent-color); background: #333333; } + &:focus { + border-color: var(--rz-accent-color); + } } .uk-button-dropdown{ diff --git a/src/Resources/app/less/common.less b/src/Resources/app/less/common.less index 06a70cdb..787e4ba8 100644 --- a/src/Resources/app/less/common.less +++ b/src/Resources/app/less/common.less @@ -105,3 +105,7 @@ background: #CCC; display: none; } } + +.uk-datepicker-table a.uk-active { + background: var(--rz-accent-color); +} diff --git a/src/Resources/app/less/documents/documents.less b/src/Resources/app/less/documents/documents.less index ae1e02dc..1d91f6b6 100644 --- a/src/Resources/app/less/documents/documents.less +++ b/src/Resources/app/less/documents/documents.less @@ -95,9 +95,6 @@ table.documents { margin: 0 auto; &:hover { - .document-border{ - background: #C8C8C8; - } .document-links{ bottom:0px; } @@ -122,18 +119,18 @@ table.documents { overflow: hidden; } - .document-border{ + .document-border { position: absolute; top:0; right:0; left:0; height:4px; - background-color:#eaeaea; + background: var(--rz-accent-color); transition: 0.5s background-color @easeOutExpo; z-index:3; } - .document-image{ + .document-image { width:128px; height:128px; background: #E2E2E2; // not white to see white PNG logotypes diff --git a/src/Resources/app/less/dropdown/dropdown.less b/src/Resources/app/less/dropdown/dropdown.less index aa2095ed..49ebb608 100644 --- a/src/Resources/app/less/dropdown/dropdown.less +++ b/src/Resources/app/less/dropdown/dropdown.less @@ -161,7 +161,7 @@ } .vertical-nodetype { position: absolute; - background-color: var(--accent-color); + background-color: var(--rz-accent-color); width: 26px; top: 0; bottom: 0; diff --git a/src/Resources/app/less/dropzone/dropzone.less b/src/Resources/app/less/dropzone/dropzone.less index a4acc70e..45be9961 100644 --- a/src/Resources/app/less/dropzone/dropzone.less +++ b/src/Resources/app/less/dropzone/dropzone.less @@ -111,7 +111,7 @@ left:0; right:0; height:4px; .dz-upload{ - background-color: var(--accent-color); + background-color: var(--rz-accent-color); } } .dz-details{ diff --git a/src/Resources/app/less/forms/custom_switch.less b/src/Resources/app/less/forms/custom_switch.less index ee38b8a7..f233ec68 100644 --- a/src/Resources/app/less/forms/custom_switch.less +++ b/src/Resources/app/less/forms/custom_switch.less @@ -37,7 +37,7 @@ } .bootstrap-switch-handle-on.bootstrap-switch-primary { - background-color: var(--accent-color-darker); + background-color: var(--rz-accent-color-lighter); .border-radius(0, 0, @switch-round, @switch-round); color: rgba(255, 255, 255, 0.9); } @@ -51,6 +51,6 @@ &:focus { outline: none; box-shadow: 1px 1px 5px 1px rgba(0, 0, 0, 0.2); - border-color: var(--accent-color-darker); + border-color: var(--rz-accent-color-darker); } } diff --git a/src/Resources/app/less/forms/forms.less b/src/Resources/app/less/forms/forms.less index e37435d8..926fdf9d 100644 --- a/src/Resources/app/less/forms/forms.less +++ b/src/Resources/app/less/forms/forms.less @@ -94,7 +94,7 @@ background-color: @grey-form-submit; margin:3px; &:checked:before { - background: var(--accent-color-darker); + background: var(--rz-accent-color-darker); } } @@ -110,7 +110,7 @@ } &:checked:before{ - color: var(--accent-color-darker); + color: var(--rz-accent-color-darker); } } diff --git a/src/Resources/app/less/login/login.less b/src/Resources/app/less/login/login.less index fce6242f..7cb4d47d 100644 --- a/src/Resources/app/less/login/login.less +++ b/src/Resources/app/less/login/login.less @@ -114,39 +114,35 @@ #login-logo { width: @login-BarW; height: 70px; - background-color: var(--accent-color); - top: 0px; left: 0; + background-color: var(--rz-accent-color); + top: 0; left: 0; text-align: center; @media (min-width: @screen-sm-min) { height: 116px; } - &:before { - content: ""; - display: inline-block; + // Center vertically Default icon when no-image + .uk-icon-rz-roadiz-icon { + display: flex; + align-items: center; + justify-content: center; height: 100%; - vertical-align: middle; - - } + font-size: 40px; - .uk-icon-rz-roadiz-icon { - vertical-align: middle; - display: inline-block; - font-size: 55px; + @media (min-width: @screen-sm-min) { + font-size: 55px; + } } - picture, - img, - svg, - object { - position: relative; - max-width: 80%; - height: auto; - max-height: 100px; - vertical-align: middle; - display: inline-block; - width: auto; + img, svg, object { + display: block; + height: 100%; + width: 100%; + object-fit: contain; + object-position: center; + margin: 0 auto; + padding: 10px; } } diff --git a/src/Resources/app/less/node-types/node-types.less b/src/Resources/app/less/node-types/node-types.less index 13058cef..203b2e5a 100644 --- a/src/Resources/app/less/node-types/node-types.less +++ b/src/Resources/app/less/node-types/node-types.less @@ -11,13 +11,14 @@ /* -------- STYLES -------- */ .uk-table.attributes, +.uk-table.custom-forms, .uk-table.node-types { .name { position: relative; padding-left: 15px; .color { - background-color: var(--data-color); + background-color: var(--rz-accent-color); display: block; position: absolute; top: 0; diff --git a/src/Resources/app/less/nodes/edit.less b/src/Resources/app/less/nodes/edit.less index ce99d600..1a63598e 100644 --- a/src/Resources/app/less/nodes/edit.less +++ b/src/Resources/app/less/nodes/edit.less @@ -113,8 +113,8 @@ } &.uk-active { & > a { - background-color: var(--accent-color-darker); - border-color: var(--accent-color-darker); + background-color: var(--rz-accent-color-darker); + border-color: var(--rz-accent-color-darker); box-shadow: none; } } diff --git a/src/Resources/app/less/nodes/global.less b/src/Resources/app/less/nodes/global.less index c84008ae..497f6b14 100644 --- a/src/Resources/app/less/nodes/global.less +++ b/src/Resources/app/less/nodes/global.less @@ -200,7 +200,7 @@ -webkit-font-smoothing: antialiased; text-align: center; line-height: 12px; - color: var(--accent-color-darker); + color: var(--rz-accent-color-darker); } } } @@ -216,8 +216,11 @@ .node-item-color{ position: absolute; - top:0; bottom:0; left:0; + top:0; + bottom:0; + left:0; width:4px; + background-color: var(--rz-accent-color); } .uk-form .form-col-choice { diff --git a/src/Resources/app/less/panels/entries_panel/admin_entries.less b/src/Resources/app/less/panels/entries_panel/admin_entries.less index 2bf65f46..ec8883ce 100644 --- a/src/Resources/app/less/panels/entries_panel/admin_entries.less +++ b/src/Resources/app/less/panels/entries_panel/admin_entries.less @@ -154,25 +154,32 @@ &:before, &:after { display: none; } - i { - font-size: 20px; - } & > a { - padding: 5px 10px 5px 7px; + padding: 0; + display: flex; + gap: 10px; + align-items: center; + } + i { + font-size: 16px; + width: 16px; } .info { - display: inline-block; - background-color: transparent; - height: 43px; - line-height: 43px; - left: 28px; - font-size: @default-font-size; - color: var(--admin-entries-subnav-text-color); - .box-shadow(0px 0px 0px rgba(0,0,0,0)); + display: block; + position: relative; + background-color: transparent; + height: auto; + line-height: 1.2em; + left: 0; + padding: 5px 0; + white-space: normal; + font-size: @default-font-size; + color: var(--admin-entries-subnav-text-color); + .box-shadow(0px 0px 0px rgba(0,0,0,0)); - &:after { - display: none; - } + &:after { + display: none; + } } &:hover { background-color: #F5F5F5; diff --git a/src/Resources/app/less/panels/user_panel/user_panel.less b/src/Resources/app/less/panels/user_panel/user_panel.less index 8e7a247c..98d038ad 100644 --- a/src/Resources/app/less/panels/user_panel/user_panel.less +++ b/src/Resources/app/less/panels/user_panel/user_panel.less @@ -24,6 +24,10 @@ transition: font-size ease 1s; } + h1, h2, h3, h4, h5, h6 { + padding: 0 10px; + } + &-container{ padding-bottom:0; @@ -34,17 +38,12 @@ .uk-icon-button { text-shadow: 0 1px 0 rgba(0,0,0,.8); - font-size: 16px; - line-height: 34px; + font-size: 12px; + width: 30px; + height: 30px; + line-height: 29px; opacity: 0.3; - @media (min-width: @screen-sm-min) and (max-width: @screen-md-max) { - font-size: 12px; - width: 30px; - height: 30px; - line-height: 29px; - } - &:hover { opacity: 0.8; } @@ -57,7 +56,7 @@ &.uk-icon-rz-turn-off, &.uk-icon-rz-user { - border-color: var(--accent-color); + border-color: var(--rz-accent-color-lighter); opacity: 0.5; &:hover { @@ -109,8 +108,6 @@ } @media screen and (max-width: @screen-lg-max) { - width:90px; - #cms-version { a { display: block; @@ -125,12 +122,12 @@ } .user-actions { - padding: 15px 0px; + padding: 15px 10px; @media (max-width: @screen-xs-max) { display: block; - position:fixed; - top:50px; + position: fixed; + top: 50px; right:0; bottom:0; width:80%; @@ -148,42 +145,43 @@ } #company { - background-color: var(--accent-color); + background-color: var(--rz-accent-color); height: @global-header-height; text-align: center; .box-sizing(); padding: 0; - &:before { - content:""; - display: inline-block; - vertical-align: middle; - height: 100%; - } - a { + position: relative; font-size: 55px; color: #333333; - display: inline-block; + display: block; text-decoration: none; - opacity: 0.95; - transition: opacity ease 0.5s; - padding-left: 0px; - width: 99%; // on Firefox, prevent line-return - vertical-align: middle; + padding: 0; + height: 100%; + width: 100%; img, svg, object { display: block; - max-width: 95%; - height: auto; - width: auto; - max-height: 110px; + height: 100%; + width: 100%; + object-fit: contain; + object-position: center; margin: 0 auto; + padding: 10px; } &:hover { opacity: 1; } + + // Center vertically Default icon when no-image + &.uk-icon-rz-roadiz-icon:before { + display: flex; + align-items: center; + justify-content: center; + height: 100%; + } } } @@ -201,14 +199,14 @@ } .user-actions { - border-top: 1px solid var(--user-panel-border-color); - @media (min-width: @screen-sm-min) { + margin: 20px 0 0 0; + border-top: 1px solid var(--user-panel-border-color); display: flex; - flex-wrap: wrap; + flex-direction: column; align-items: center; justify-content: center; - gap: 5px; + gap: 10px; } } @@ -218,7 +216,7 @@ } #user-picture { - display: block; + display: flex; width: @user-picture-size; height: @user-picture-size; border-radius: 50%; @@ -241,18 +239,13 @@ padding: 0px; } } + .uk-icon { + color: rgba(255, 255, 255, 0.5); + } &:hover { + text-decoration: none; border: 3px solid #333; } - @media (max-width: @screen-lg-max) { - width:56px; - height:56px; - - img{ - width:56px; - height:56px; - } - } } #cms-version { position: absolute; diff --git a/src/Resources/app/less/responsive/less-768.less b/src/Resources/app/less/responsive/less-768.less index 1ae98fe7..73c1fc53 100644 --- a/src/Resources/app/less/responsive/less-768.less +++ b/src/Resources/app/less/responsive/less-768.less @@ -88,7 +88,7 @@ top:0; right:0; width:60px; - height:@mobile-admin-menu-height; + height: @mobile-admin-menu-height; background: var(--user-panel-color); border-radius: 0; border:0; @@ -98,7 +98,7 @@ background: #3a3a3a; } - img{ + img { position: absolute; width:38px; height:38px; @@ -107,6 +107,10 @@ border-radius: (@user-picture-size / 2)+5px; border: 3px solid var(--user-panel-color); } + + .uk-icon { + color: rgba(255, 255, 255, 0.5); + } } .uk-icon-button{ diff --git a/src/Resources/app/less/tables/tables.less b/src/Resources/app/less/tables/tables.less index 0ab5a3ef..6ba6a704 100644 --- a/src/Resources/app/less/tables/tables.less +++ b/src/Resources/app/less/tables/tables.less @@ -50,7 +50,7 @@ margin-left:5px; &.active { - color: var(--accent-color-darker); + color: var(--rz-accent-color-darker); } } } diff --git a/src/Resources/app/less/vars.less b/src/Resources/app/less/vars.less index 2d33951a..86eaefd5 100644 --- a/src/Resources/app/less/vars.less +++ b/src/Resources/app/less/vars.less @@ -73,14 +73,15 @@ /* -------- PANEL SIZES -------- */ -@user-panel-width: 150px; +@user-panel-width: 90px; @user-panel-sm-width: 90px; -@user-panel-lg-width: 120px; -@user-panel-xl-width: 150px; +@user-panel-lg-width: 90px; +@user-panel-xl-width: 90px; @entries-panel-width: 60px; @entries-panel-lg-width: 70px; @entries-panel-xl-width: 70px; + @trees-panel-width: 270px; @trees-panel-lg-width: 270px; @trees-panel-xl-width: 350px; @@ -92,8 +93,8 @@ @user-panel-color: #4d4d4d; @user-panel-text-color: #d8d8d8; @user-panel-text-alt-color: #b7b7b7; -@user-picture-size: 80px; -@user-picture-size-mini: 70px; +@user-picture-size: 56px; +@user-picture-size-mini: 56px; @user-panel-border-color: rgba(199,199,204, 0.14); @@ -156,9 +157,14 @@ --maincontent-bar-bg: #efefef; --maincontent-header-bg: @maincontent-header-bg; - --accent-color: #00deab; - --accent-color-darker: #00c497; - --accent-color-darkest: #00ab83; + --color-light-mix: 70%; + --color-darker-mix: 95%; + --color-darkest-mix: 85%; + + --rz-accent-color: #00deab; + --rz-accent-color-lighter: color-mix(in srgb, var(--rz-accent-color) var(--color-light-mix), white); + --rz-accent-color-darker: color-mix(in srgb, var(--rz-accent-color) var(--color-darker-mix), black); + --rz-accent-color-darkest: color-mix(in srgb, var(--rz-accent-color) var(--color-darkest-mix), black); } /** diff --git a/src/Resources/app/less/widgets/children_nodes_widget.less b/src/Resources/app/less/widgets/children_nodes_widget.less index c6309b75..c25a6b0a 100644 --- a/src/Resources/app/less/widgets/children_nodes_widget.less +++ b/src/Resources/app/less/widgets/children_nodes_widget.less @@ -248,6 +248,7 @@ bottom: 0; left: 0; width: 4px; + background-color: var(--rz-accent-color); } .uk-nestable-panel { @@ -296,7 +297,7 @@ height: @children-node-height - 15px; top: 6px; background-color: #CCCCCC; - border: 1px solid #C2C2C2; + border: 1px solid var(--rz-accent-color); z-index: 1; } @@ -337,7 +338,7 @@ font-size: @default-font-size; border-radius: 100%; background-color: var(--contrasted-bg); - border: 1px solid #a0a0a0; + border: 1px solid var(--rz-accent-color); width: @children-node-height / 2; height: @children-node-height / 2; display: inline-block; @@ -370,7 +371,7 @@ color: @item-color; font-size: @default-font-size; border-radius: 100%; - background-color: #a0a0a0; + background-color: var(--rz-accent-color); width: 8px; height: 8px; top: 50%; diff --git a/src/Resources/app/less/widgets/customform_widget.less b/src/Resources/app/less/widgets/customform_widget.less index 1d6f14a1..5b3a8ff2 100644 --- a/src/Resources/app/less/widgets/customform_widget.less +++ b/src/Resources/app/less/widgets/customform_widget.less @@ -117,7 +117,7 @@ position: absolute; top:0; bottom:0; left:0; width:4px; - background: var(--accent-color); + background: var(--rz-accent-color); } .custom-form-links{ diff --git a/src/Resources/app/less/widgets/documents_widget.less b/src/Resources/app/less/widgets/documents_widget.less index 14c087c5..09bf3241 100644 --- a/src/Resources/app/less/widgets/documents_widget.less +++ b/src/Resources/app/less/widgets/documents_widget.less @@ -140,12 +140,12 @@ } } - .document-border{ + .document-border { position: absolute; top:0; right:0; left:0; z-index: 15; height:4px; - background: var(--accent-color); + background: var(--rz-accent-color); } .document-image{ diff --git a/src/Resources/app/less/widgets/drawer_document_item.less b/src/Resources/app/less/widgets/drawer_document_item.less index ad3cbdec..b546bcad 100644 --- a/src/Resources/app/less/widgets/drawer_document_item.less +++ b/src/Resources/app/less/widgets/drawer_document_item.less @@ -37,7 +37,7 @@ right: 0; width: 20px; text-align: center; - background: var(--accent-color); + background: var(--rz-accent-color); font-size: 11px; padding: 2px 0; height: 15px; @@ -53,12 +53,12 @@ } } - .document-border{ + .document-border { position: absolute; top:0; right:0; left:0; z-index: 15; height:4px; - background: var(--accent-color); + background: var(--rz-accent-color); } .document-image{ diff --git a/src/Resources/app/less/widgets/drawer_item.less b/src/Resources/app/less/widgets/drawer_item.less index e2f3da0e..ee7de0ae 100644 --- a/src/Resources/app/less/widgets/drawer_item.less +++ b/src/Resources/app/less/widgets/drawer_item.less @@ -77,7 +77,7 @@ bottom: 0; left: 0; width: 4px; - background: var(--accent-color); + background: var(--rz-accent-color); z-index: 2; } diff --git a/src/Resources/app/less/widgets/folder_tree.less b/src/Resources/app/less/widgets/folder_tree.less index fd8723b9..7f6f7827 100644 --- a/src/Resources/app/less/widgets/folder_tree.less +++ b/src/Resources/app/less/widgets/folder_tree.less @@ -1,18 +1,16 @@ .foldertree { - &-element { - &-name { + &-element-name { + vertical-align: middle; + position: relative; + max-width: 80%; + + a { + white-space: nowrap; + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + display: block; vertical-align: middle; - position: relative; - max-width: 80%; - - a { - white-space: nowrap; - max-width: 100%; - overflow: hidden; - text-overflow: ellipsis; - display: block; - vertical-align: middle; - } } } @@ -123,3 +121,8 @@ } } } + +.folder-item i, +.foldertree-element > .uk-nestable-panel .uk-nestable-handle i { + color: var(--rz-accent-color); +} diff --git a/src/Resources/app/less/widgets/nestable.less b/src/Resources/app/less/widgets/nestable.less index e5860cc7..db86411d 100644 --- a/src/Resources/app/less/widgets/nestable.less +++ b/src/Resources/app/less/widgets/nestable.less @@ -146,7 +146,7 @@ .uk-icon-rz-home-unpublished { position: relative; font-size: 16px; - color: darken(@item-color, 10%); + color: var(--rz-accent-color); vertical-align: middle; top: -1px; left: -2px; @@ -167,12 +167,12 @@ z-index:4; } &:hover { - .nodetree-element-name a{ + .nodetree-element-name a { color: @item-color-name-color-hover; } .uk-icon-rz-home, .uk-icon-rz-home-unpublished { - color: @nestable-handle-border-color-hover; + color: var(--rz-accent-color-darker); } } } @@ -207,7 +207,7 @@ font-size: @default-font-size; border-radius: 100%; background-color: var(--contrasted-bg); - border: 1px solid @item-color; + border: 1px solid var(--rz-accent-color); width: 10px; display: inline-block; height: 10px; @@ -229,7 +229,7 @@ color: @item-color; font-size: @default-font-size; border-radius: 100%; - background-color: @item-color; + background-color: var(--rz-accent-color); width: 4px; height: 4px; top: 3px; @@ -473,7 +473,7 @@ font-size: @default-font-size; border-radius: 100%; background-color: var(--contrasted-bg); - border: 1px solid @item-color; + border: 1px solid var(--rz-accent-color); width: 10px; display: inline-block; height: 10px; diff --git a/src/Resources/app/less/widgets/tag_tree.less b/src/Resources/app/less/widgets/tag_tree.less index 5356d955..273717b8 100644 --- a/src/Resources/app/less/widgets/tag_tree.less +++ b/src/Resources/app/less/widgets/tag_tree.less @@ -122,3 +122,8 @@ } } } + +.tag-item i, +.tagtree-element > .uk-nestable-panel .uk-nestable-handle i { + color: var(--rz-accent-color); +} diff --git a/src/Resources/routes.yml b/src/Resources/routes.yml index 0bda10db..1bdf1967 100644 --- a/src/Resources/routes.yml +++ b/src/Resources/routes.yml @@ -233,11 +233,6 @@ webhooksRoutes: # CSS to style with main color # NOT SECURED ROUTES # -cssMainColor: - path : /css/main-color.css - defaults: - _controller: Themes\Rozier\RozierApp::cssAction - loginImagePage: path: /css/login/image defaults: diff --git a/src/Resources/translations/helps.ar.xlf b/src/Resources/translations/helps.ar.xlf index 5e2f21d6..c6900194 100644 --- a/src/Resources/translations/helps.ar.xlf +++ b/src/Resources/translations/helps.ar.xlf @@ -17,7 +17,6 @@ - diff --git a/src/Resources/translations/helps.de.xlf b/src/Resources/translations/helps.de.xlf index 602b82aa..a8042d4b 100644 --- a/src/Resources/translations/helps.de.xlf +++ b/src/Resources/translations/helps.de.xlf @@ -17,7 +17,6 @@ - diff --git a/src/Resources/translations/helps.en.xlf b/src/Resources/translations/helps.en.xlf index 2e3d338c..c4c67fea 100644 --- a/src/Resources/translations/helps.en.xlf +++ b/src/Resources/translations/helps.en.xlf @@ -30,10 +30,6 @@ nodeSource.metaTitle.help SEO title allows you to write the entire title of your page. For optimal display in search engines, the title should not exceed 55 to 65 characters on average. - - nodeSource.metaKeywords.help - - SEO keywords are now optional and are no longer taken into account by search engines. nodeSource.metaDescription.help SEO description is a summary in a few characters of your page. Its purpose is to briefly describe its content. This description must be between 120 and 155 characters long. diff --git a/src/Resources/translations/helps.es.xlf b/src/Resources/translations/helps.es.xlf index cb907e5a..32cd4ae4 100644 --- a/src/Resources/translations/helps.es.xlf +++ b/src/Resources/translations/helps.es.xlf @@ -17,7 +17,6 @@ - diff --git a/src/Resources/translations/helps.fr.xlf b/src/Resources/translations/helps.fr.xlf index 0022a1be..7c415f21 100644 --- a/src/Resources/translations/helps.fr.xlf +++ b/src/Resources/translations/helps.fr.xlf @@ -30,10 +30,6 @@ nodeSource.metaTitle.help Le titre de référencement permet de rédiger entièrement le titre de votre page. Pour un affichage optimal dans les moteurs de recherche, le titre ne doit pas dépasser 55 à 65 caractères en moyenne. - - nodeSource.metaKeywords.help - - Les mot-clés de référencement sont aujourd’hui facultatifs et ne sont plus pris en compte par les moteurs de recherche. nodeSource.metaDescription.help La description est un résumé de quelques caractères de votre page. Son objectif est de décrire succinctement son contenu. Cette description doit respecter une taille entre 120 et 155 caractères. diff --git a/src/Resources/translations/helps.id.xlf b/src/Resources/translations/helps.id.xlf index c679cebd..bdc35073 100644 --- a/src/Resources/translations/helps.id.xlf +++ b/src/Resources/translations/helps.id.xlf @@ -26,10 +26,6 @@ nodeSource.metaTitle.help Judul SEO memungkinkan Anda untuk menulis seluruh judul halaman Anda. Untuk tampilan optimal di mesin pencari, judulnya tidak boleh melebihi 55 hingga 65 karakter rata-rata. - - nodeSource.metaKeywords.help - - Kata kunci SEO sekarang opsional dan tidak lagi diperhitungkan oleh mesin pencari. nodeSource.metaDescription.help Deskripsi SEO adalah ringkasan dalam beberapa karakter halaman Anda. Tujuannya adalah untuk menggambarkan kontennya secara singkat. Deskripsi ini harus antara 120 dan 155 karakter. diff --git a/src/Resources/translations/helps.it.xlf b/src/Resources/translations/helps.it.xlf index 7f0dde99..e12bbac7 100644 --- a/src/Resources/translations/helps.it.xlf +++ b/src/Resources/translations/helps.it.xlf @@ -17,7 +17,6 @@ - diff --git a/src/Resources/translations/helps.ru.xlf b/src/Resources/translations/helps.ru.xlf index 0c5be687..c50257a7 100644 --- a/src/Resources/translations/helps.ru.xlf +++ b/src/Resources/translations/helps.ru.xlf @@ -17,7 +17,6 @@ - diff --git a/src/Resources/translations/helps.sr.xlf b/src/Resources/translations/helps.sr.xlf index cc2d90b9..ed6ba10f 100644 --- a/src/Resources/translations/helps.sr.xlf +++ b/src/Resources/translations/helps.sr.xlf @@ -17,7 +17,6 @@ - diff --git a/src/Resources/translations/helps.tr.xlf b/src/Resources/translations/helps.tr.xlf index 4bdfb973..2926e610 100644 --- a/src/Resources/translations/helps.tr.xlf +++ b/src/Resources/translations/helps.tr.xlf @@ -17,7 +17,6 @@ - diff --git a/src/Resources/translations/helps.uk.xlf b/src/Resources/translations/helps.uk.xlf index 30359369..bb642d67 100644 --- a/src/Resources/translations/helps.uk.xlf +++ b/src/Resources/translations/helps.uk.xlf @@ -17,7 +17,6 @@ - diff --git a/src/Resources/translations/helps.xlf b/src/Resources/translations/helps.xlf index 81d70f20..9169e138 100644 --- a/src/Resources/translations/helps.xlf +++ b/src/Resources/translations/helps.xlf @@ -29,10 +29,6 @@ nodeSource.metaTitle.help - - - nodeSource.metaKeywords.help - nodeSource.metaDescription.help diff --git a/src/Resources/translations/helps.zh.xlf b/src/Resources/translations/helps.zh.xlf index d3e921ad..740a56dc 100644 --- a/src/Resources/translations/helps.zh.xlf +++ b/src/Resources/translations/helps.zh.xlf @@ -26,10 +26,6 @@ nodeSource.metaTitle.help SEO 标题能让您写下您页面的全部标题。为了在搜索引擎中完全显示,标题一般不应该超过 55 到 65 个字。 - - nodeSource.metaKeywords.help - - SEO 关键词现在是可选的,且不再被搜索引擎重视。 nodeSource.metaDescription.help SEO 描述是您页面的几个字的总结。它的目的是为了简略的描述它的内容。此描述的长度必须介于 120 到 155 个字之间。 diff --git a/src/Resources/translations/messages.ar.xlf b/src/Resources/translations/messages.ar.xlf index e490318b..d41e48f9 100644 --- a/src/Resources/translations/messages.ar.xlf +++ b/src/Resources/translations/messages.ar.xlf @@ -334,10 +334,6 @@ metaTitle عنوان وصفي - - metaKeywords - الكلمات الدلالية - nodeTypeField.%name%.updated حقل نوع العقدة.%name%.تم تحديثه diff --git a/src/Resources/translations/messages.de.xlf b/src/Resources/translations/messages.de.xlf index 51dbc09b..74a59fb8 100644 --- a/src/Resources/translations/messages.de.xlf +++ b/src/Resources/translations/messages.de.xlf @@ -346,10 +346,6 @@ metaTitle Meta-Titel - - metaKeywords - Meta Stichworte - metaDescription Meta Beschreibung diff --git a/src/Resources/translations/messages.en.xlf b/src/Resources/translations/messages.en.xlf index 3cffc3f6..c4378271 100644 --- a/src/Resources/translations/messages.en.xlf +++ b/src/Resources/translations/messages.en.xlf @@ -358,10 +358,6 @@ metaTitle Meta-title - - metaKeywords - Meta-keywords - metaDescription Meta-description @@ -4719,11 +4715,6 @@ Back to working copy Version management : Button label to go back to working copy - - encrypted - Encrypted - Settings : defines if setting value will be encrypted in database. - original.document Original document diff --git a/src/Resources/translations/messages.es.xlf b/src/Resources/translations/messages.es.xlf index b5930a1a..6e4e4669 100644 --- a/src/Resources/translations/messages.es.xlf +++ b/src/Resources/translations/messages.es.xlf @@ -346,10 +346,6 @@ metaTitle Meta-título - - metaKeywords - Meta-frases clave - metaDescription Meta-descripción @@ -4293,11 +4289,6 @@ Versiones Version management - - encrypted - Encriptado - Settings : defines if setting value will be encrypted in database. - diff --git a/src/Resources/translations/messages.fr.xlf b/src/Resources/translations/messages.fr.xlf index 326d558b..1142ebc5 100644 --- a/src/Resources/translations/messages.fr.xlf +++ b/src/Resources/translations/messages.fr.xlf @@ -358,10 +358,6 @@ metaTitle Titre « méta » - - metaKeywords - Mots-clef « méta » - metaDescription Description « méta » @@ -4719,11 +4715,6 @@ Retour à la version actuelle Version management : Button label to go back to working copy - - encrypted - Chiffré - Settings : defines if setting value will be encrypted in database. - original.document Document original diff --git a/src/Resources/translations/messages.id.xlf b/src/Resources/translations/messages.id.xlf index 9a12b758..c7ebff77 100644 --- a/src/Resources/translations/messages.id.xlf +++ b/src/Resources/translations/messages.id.xlf @@ -346,10 +346,6 @@ metaTitle Judul meta - - metaKeywords - Kata kunci meta - metaDescription Deskripsi meta diff --git a/src/Resources/translations/messages.it.xlf b/src/Resources/translations/messages.it.xlf index 2e437904..9795d348 100644 --- a/src/Resources/translations/messages.it.xlf +++ b/src/Resources/translations/messages.it.xlf @@ -334,10 +334,6 @@ metaTitle Meta-titolo - - metaKeywords - Meta-parole chiavi - metaDescription Meta-descrizione diff --git a/src/Resources/translations/messages.ru.xlf b/src/Resources/translations/messages.ru.xlf index 54c60608..186e4dcf 100644 --- a/src/Resources/translations/messages.ru.xlf +++ b/src/Resources/translations/messages.ru.xlf @@ -342,10 +342,6 @@ metaTitle Мета-заголовок - - metaKeywords - Мета-ключевые слова - metaDescription Мета-описание diff --git a/src/Resources/translations/messages.sr.xlf b/src/Resources/translations/messages.sr.xlf index a31f9528..b724eb8c 100644 --- a/src/Resources/translations/messages.sr.xlf +++ b/src/Resources/translations/messages.sr.xlf @@ -342,10 +342,6 @@ metaTitle Meta-наслов - - metaKeywords - Meta-кључне речи - metaDescription Meta-опис diff --git a/src/Resources/translations/messages.tr.xlf b/src/Resources/translations/messages.tr.xlf index 674b6e25..caaaf114 100644 --- a/src/Resources/translations/messages.tr.xlf +++ b/src/Resources/translations/messages.tr.xlf @@ -346,10 +346,6 @@ metaTitle Meta başlık - - metaKeywords - Meta anahtar kelimeleri - metaDescription Meta açıklama diff --git a/src/Resources/translations/messages.uk.xlf b/src/Resources/translations/messages.uk.xlf index c0acaee8..d77fb216 100644 --- a/src/Resources/translations/messages.uk.xlf +++ b/src/Resources/translations/messages.uk.xlf @@ -346,10 +346,6 @@ metaTitle Meta-заголовок - - metaKeywords - Ключові слова Meta - metaDescription Meta - опис diff --git a/src/Resources/translations/messages.xlf b/src/Resources/translations/messages.xlf index 32f16c71..e2b993d9 100644 --- a/src/Resources/translations/messages.xlf +++ b/src/Resources/translations/messages.xlf @@ -2,6 +2,7 @@ + %namespace%.imported node.%name%.updated node.%name%.was_moved node.%nodeId%.not_exists @@ -91,7 +92,6 @@ source_translation destination_translation metaTitle - metaKeywords metaDescription nodeTypeField.%name%.updated nodeTypeField.%name%.created @@ -1329,7 +1329,6 @@ max_versions_showedVersion management : setting label to choose how many version to display in action-menu versions.back_to_working_copyVersion management : Button label to go back to working copy - encryptedSettings : defines if setting value will be encrypted in database. original.documentDocument : Label to display original document when dealing with thumbnails. see.original.documentDocument : Button Label to display original document when dealing with thumbnails. diff --git a/src/Resources/translations/messages.zh.xlf b/src/Resources/translations/messages.zh.xlf index 6f386706..ae51c187 100644 --- a/src/Resources/translations/messages.zh.xlf +++ b/src/Resources/translations/messages.zh.xlf @@ -346,10 +346,6 @@ metaTitle 元-标题 - - metaKeywords - 元-关键词 - metaDescription 元-描述 @@ -4548,11 +4544,6 @@ 回到最新版本 Version management : Button label to go back to working copy - - encrypted - 已加密 - Settings : defines if setting value will be encrypted in database. - original.document 原始文档 diff --git a/src/Resources/views/admin/blocks/adminImage.html.twig b/src/Resources/views/admin/blocks/adminImage.html.twig index b101429b..3920352d 100644 --- a/src/Resources/views/admin/blocks/adminImage.html.twig +++ b/src/Resources/views/admin/blocks/adminImage.html.twig @@ -1,6 +1,6 @@
{% if themeServices.adminImage %} - {{ themeServices.adminImage|display({width:150}) }} + {{- themeServices.adminImage|display({ picture: true, width: 180, quality: 70 }) -}} {% else %} {% endif %} diff --git a/src/Resources/views/admin/blocks/loginImage.html.twig b/src/Resources/views/admin/blocks/loginImage.html.twig index 66c9b743..44aeb3ca 100644 --- a/src/Resources/views/admin/blocks/loginImage.html.twig +++ b/src/Resources/views/admin/blocks/loginImage.html.twig @@ -1,6 +1,6 @@