From 541fa4be795172cec7275d0955ace7d6e6f1bae5 Mon Sep 17 00:00:00 2001 From: Daric DESBONNES Date: Tue, 12 Jul 2022 16:44:09 +0200 Subject: [PATCH] Upgrade Sonatablock and SonataSeo --- composer.json | 4 +- src/Admin/BaseBlockAdmin.php | 17 +- src/Admin/BlockAdmin.php | 43 +--- src/Admin/SharedBlockAdmin.php | 10 +- src/Block/BlockContextManager.php | 65 ++++- src/Block/BreadcrumbBlockService.php | 42 ++-- src/Block/ChildrenPagesBlockService.php | 2 +- src/Block/ContainerBlockService.php | 77 +++++- src/Block/PageListBlockService.php | 85 ++++--- src/Block/SharedBlockBlockService.php | 4 +- .../SonataPageExtension.php | 222 +----------------- src/Form/Type/PageSelectorType.php | 28 +-- src/Form/Type/PageTypeChoiceType.php | 39 +-- src/Form/Type/TemplateChoiceType.php | 39 +-- src/Mapper/PageFormMapper.php | 7 +- src/Page/Service/BasePageService.php | 11 +- src/Page/Service/DefaultPageService.php | 22 +- src/Resources/config/admin.xml | 6 +- src/Resources/config/block.xml | 10 +- tests/Admin/BaseBlockAdminTest.php | 33 --- tests/Block/BlockContextManagerTest.php | 36 +-- tests/Block/ContainerBlockServiceTest.php | 28 ++- tests/Block/PageListBlockServiceTest.php | 12 + tests/Page/Service/DefaultPageServiceTest.php | 15 +- 24 files changed, 293 insertions(+), 564 deletions(-) diff --git a/composer.json b/composer.json index 60223e9ee..0c696c97a 100644 --- a/composer.json +++ b/composer.json @@ -26,12 +26,12 @@ "doctrine/doctrine-bundle": "^1.12.3 || ^2.0", "doctrine/persistence": "^1.3.4 || ^2.0", "sonata-project/admin-bundle": "^3.99", - "sonata-project/block-bundle": "^3.20", + "sonata-project/block-bundle": "^4.0", "sonata-project/doctrine-extensions": "^1.8", "sonata-project/doctrine-orm-admin-bundle": "^3.19", "sonata-project/form-extensions": "^0.1.1 || ^1.4", "sonata-project/notification-bundle": "^3.8", - "sonata-project/seo-bundle": "^2.11", + "sonata-project/seo-bundle": "^3.0", "sonata-project/twig-extensions": "^0.1.1 || ^1.3", "symfony-cmf/routing-bundle": "^2.1", "symfony/config": "^4.4", diff --git a/src/Admin/BaseBlockAdmin.php b/src/Admin/BaseBlockAdmin.php index 2f6a17ec9..2f79bad92 100644 --- a/src/Admin/BaseBlockAdmin.php +++ b/src/Admin/BaseBlockAdmin.php @@ -37,15 +37,9 @@ abstract class BaseBlockAdmin extends AbstractAdmin */ protected $blockManager; - /** - * @var bool - */ - protected $inValidate = false; + protected bool $inValidate = false; - /** - * @var array - */ - protected $containerBlockTypes = []; + protected array $containerBlockTypes = []; /** * @param BaseBlock $object @@ -255,12 +249,7 @@ private function loadBlockDefaults(BlockInterface $block) $resolver = new OptionsResolver(); // use new interface method whenever possible - // NEXT_MAJOR: Remove this check and legacy setDefaultSettings method call - if (method_exists($service, 'configureSettings')) { - $service->configureSettings($resolver); - } else { - $service->setDefaultSettings($resolver); - } + $service->configureSettings($resolver); try { $block->setSettings($resolver->resolve($block->getSettings())); diff --git a/src/Admin/BlockAdmin.php b/src/Admin/BlockAdmin.php index afa039c6c..4464988f9 100644 --- a/src/Admin/BlockAdmin.php +++ b/src/Admin/BlockAdmin.php @@ -16,7 +16,7 @@ use Doctrine\ORM\EntityRepository; use Sonata\AdminBundle\Form\FormMapper; use Sonata\AdminBundle\Route\RouteCollection; -use Sonata\BlockBundle\Block\BlockServiceInterface; +use Sonata\BlockBundle\Block\Service\BlockServiceInterface; use Sonata\BlockBundle\Block\Service\EditableBlockService; use Sonata\BlockBundle\Form\Type\ServiceListType; use Sonata\BlockBundle\Model\BlockInterface; @@ -32,16 +32,9 @@ * Admin class for the Block model. * * @author Thomas Rabaix - * - * @final since sonata-project/page-bundle 3.26 */ -class BlockAdmin extends BaseBlockAdmin +final class BlockAdmin extends BaseBlockAdmin { - /** - * @var array - */ - protected $blocks; - protected $classnameLabel = 'Block'; protected $accessMapping = [ @@ -50,12 +43,9 @@ class BlockAdmin extends BaseBlockAdmin 'composePreview' => 'EDIT', ]; - /** - * @param string $code - * @param string $class - * @param string $baseControllerName - */ - public function __construct($code, $class, $baseControllerName, array $blocks = []) + private array $blocks; + + public function __construct(string $code, string $class, string $baseControllerName, array $blocks = []) { parent::__construct($code, $class, $baseControllerName); @@ -150,9 +140,9 @@ protected function configureFormFields(FormMapper $form): void return $repository->createQueryBuilder('a') ->andWhere('a.page = :page AND a.type IN (:types)') ->setParameters([ - 'page' => $page, - 'types' => $containerBlockTypes, - ]); + 'page' => $page, + 'types' => $containerBlockTypes, + ]); }, ], [ 'admin_code' => $this->getCode(), @@ -186,24 +176,13 @@ protected function configureFormFields(FormMapper $form): void } } - /** - * @return string|null - */ - private function getDefaultTemplate(BlockServiceInterface $blockService) + private function getDefaultTemplate(BlockServiceInterface $blockService): ?string { $resolver = new OptionsResolver(); - // use new interface method whenever possible - // NEXT_MAJOR: Remove this check and legacy setDefaultSettings method call - if (method_exists($blockService, 'configureSettings')) { - $blockService->configureSettings($resolver); - } else { - $blockService->setDefaultSettings($resolver); - } + $blockService->configureSettings($resolver); $options = $resolver->resolve(); - if (isset($options['template'])) { - return $options['template']; - } + return $options['template'] ?? null; } private function configureBlockFields(FormMapper $form, BlockInterface $block): void diff --git a/src/Admin/SharedBlockAdmin.php b/src/Admin/SharedBlockAdmin.php index 95e11cf71..8f72a970b 100644 --- a/src/Admin/SharedBlockAdmin.php +++ b/src/Admin/SharedBlockAdmin.php @@ -16,7 +16,7 @@ use Sonata\AdminBundle\Datagrid\ListMapper; use Sonata\AdminBundle\Datagrid\ProxyQueryInterface; use Sonata\AdminBundle\Form\FormMapper; -use Sonata\BlockBundle\Block\BlockServiceInterface; +use Sonata\BlockBundle\Block\Service\BlockServiceInterface; use Sonata\BlockBundle\Block\Service\EditableBlockService; use Sonata\BlockBundle\Model\BlockInterface; use Sonata\PageBundle\Entity\BaseBlock; @@ -26,22 +26,20 @@ * Admin class for shared Block model. * * @author Romain Mouillard - * - * @final since sonata-project/page-bundle 3.26 */ -class SharedBlockAdmin extends BaseBlockAdmin +final class SharedBlockAdmin extends BaseBlockAdmin { /** * @var string */ protected $classnameLabel = 'shared_block'; - public function getBaseRoutePattern() + public function getBaseRoutePattern(): string { return sprintf('%s/%s', parent::getBaseRoutePattern(), 'shared'); } - public function getBaseRouteName() + public function getBaseRouteName(): string { return sprintf('%s/%s', parent::getBaseRouteName(), 'shared'); } diff --git a/src/Block/BlockContextManager.php b/src/Block/BlockContextManager.php index 2368df378..71bc650ba 100644 --- a/src/Block/BlockContextManager.php +++ b/src/Block/BlockContextManager.php @@ -13,32 +13,71 @@ namespace Sonata\PageBundle\Block; +use Sonata\BlockBundle\Block\BlockContextInterface; use Sonata\BlockBundle\Block\BlockContextManager as BaseBlockContextManager; -use Sonata\BlockBundle\Model\BlockInterface; +use Sonata\BlockBundle\Block\BlockContextManagerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -/** - * NEXT_MAJOR: Do not extend from `BlockContextManager` since it will be final. - * - * @psalm-suppress InvalidExtendClass - * @phpstan-ignore-next-line - * - * @final since sonata-project/page-bundle 3.26 - */ -class BlockContextManager extends BaseBlockContextManager +final class BlockContextManager implements BlockContextManagerInterface { - protected function configureSettings(OptionsResolver $optionsResolver, BlockInterface $block): void + private BaseBlockContextManager $blockContextManager; + + private OptionsResolver $optionsResolver; + + public function __construct(BaseBlockContextManager $blockContextManager) + { + $this->blockContextManager = $blockContextManager; + $this->optionsResolver = new OptionsResolver(); + } + + public function getOptionsResolver(): OptionsResolver + { + return $this->optionsResolver; + } + + /** + * @return BaseBlockContextManager|BlockContextManagerInterface + */ + public function getBlockContextManager() + { + return $this->blockContextManager; + } + + public function addSettingsByType(string $type, array $settings, bool $replace = false): void { - parent::configureSettings($optionsResolver, $block); + $this->blockContextManager->addSettingsByType($type, $settings, $replace); + } + + public function addSettingsByClass(string $class, array $settings, bool $replace = false): void + { + $this->blockContextManager->addSettingsByClass($class, $settings, $replace); + } + + public function get($meta, array $settings = []): BlockContextInterface + { + return $this->blockContextManager->get($meta, [ + 'manager' => false, + 'page_id' => false, + ]); + } + public function exists(string $type): bool + { + return $this->blockContextManager->exists($type); + } + + private function configureSettings(OptionsResolver $optionsResolver): void + { $optionsResolver->setDefaults([ 'manager' => false, 'page_id' => false, + 'attr' => [], ]); $optionsResolver ->addAllowedTypes('manager', ['string', 'bool']) - ->addAllowedTypes('page_id', ['int', 'string', 'bool']); + ->addAllowedTypes('page_id', ['int', 'string', 'bool']) + ->addAllowedTypes('attr', 'array'); $optionsResolver->setRequired([ 'manager', diff --git a/src/Block/BreadcrumbBlockService.php b/src/Block/BreadcrumbBlockService.php index ceb4739d9..2fb286e51 100644 --- a/src/Block/BreadcrumbBlockService.php +++ b/src/Block/BreadcrumbBlockService.php @@ -15,56 +15,52 @@ use Knp\Menu\FactoryInterface; use Knp\Menu\ItemInterface; -use Knp\Menu\Provider\MenuProviderInterface; use Sonata\BlockBundle\Block\BlockContextInterface; use Sonata\BlockBundle\Meta\Metadata; +use Sonata\BlockBundle\Meta\MetadataInterface; use Sonata\PageBundle\CmsManager\CmsManagerSelectorInterface; use Sonata\PageBundle\Model\PageInterface; use Sonata\SeoBundle\Block\Breadcrumb\BaseBreadcrumbMenuBlockService; -use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface; +use Twig\Environment; /** * BlockService for homepage breadcrumb. * * @author Sylvain Deloux - * - * @final since sonata-project/page-bundle 3.26 */ -class BreadcrumbBlockService extends BaseBreadcrumbMenuBlockService +final class BreadcrumbBlockService extends BaseBreadcrumbMenuBlockService { - /** - * @var CmsManagerSelectorInterface - */ - protected $cmsSelector; + private CmsManagerSelectorInterface $cmsSelector; - /** - * @param string $context - * @param string $name - */ - public function __construct($context, $name, EngineInterface $templating, MenuProviderInterface $menuProvider, FactoryInterface $factory, CmsManagerSelectorInterface $cmsSelector) + public function __construct(Environment $twig, FactoryInterface $factory, CmsManagerSelectorInterface $cmsSelector) { - $this->cmsSelector = $cmsSelector; + parent::__construct($twig, $factory); - parent::__construct($context, $name, $templating, $menuProvider, $factory); + $this->cmsSelector = $cmsSelector; } - public function getName() + public function getName(): string { return 'sonata.page.block.breadcrumb'; } - public function getBlockMetadata($code = null) + public function getMetadata($code = null): MetadataInterface { - return new Metadata($this->getName(), (null !== $code ? $code : $this->getName()), false, 'SonataPageBundle', [ + return new Metadata($this->getName(), (null !== $code ? $code : $this->getName()), null, 'SonataPageBundle', [ 'class' => 'fa fa-bars', ]); } - protected function getMenu(BlockContextInterface $blockContext) + public function handleContext(string $context): bool + { + return $this->getName() === $context; + } + + protected function getMenu(BlockContextInterface $blockContext): ItemInterface { $blockContext->setSetting('include_homepage_link', false); - $menu = $this->getRootMenu($blockContext); + $menu = parent::getMenu($blockContext); $page = $this->getCurrentPage(); @@ -91,10 +87,8 @@ protected function getMenu(BlockContextInterface $blockContext) /** * Return the current Page. - * - * @return PageInterface */ - protected function getCurrentPage() + protected function getCurrentPage(): PageInterface { $cms = $this->cmsSelector->retrieve(); diff --git a/src/Block/ChildrenPagesBlockService.php b/src/Block/ChildrenPagesBlockService.php index 08009bf6b..9dfb29488 100755 --- a/src/Block/ChildrenPagesBlockService.php +++ b/src/Block/ChildrenPagesBlockService.php @@ -47,7 +47,7 @@ public function __construct(Environment $twig, SiteSelectorInterface $siteSelect $this->cmsManagerSelector = $cmsManagerSelector; } - public function execute(BlockContextInterface $blockContext, ?Response $response = null) + public function execute(BlockContextInterface $blockContext, ?Response $response = null): Response { $settings = $blockContext->getSettings(); diff --git a/src/Block/ContainerBlockService.php b/src/Block/ContainerBlockService.php index 929206977..c4436c211 100644 --- a/src/Block/ContainerBlockService.php +++ b/src/Block/ContainerBlockService.php @@ -13,22 +13,80 @@ namespace Sonata\PageBundle\Block; +use Sonata\BlockBundle\Block\BlockContextInterface; +use Sonata\BlockBundle\Block\Service\BlockServiceInterface; use Sonata\BlockBundle\Block\Service\ContainerBlockService as BaseContainerBlockService; +use Sonata\BlockBundle\Block\Service\EditableBlockService; +use Sonata\BlockBundle\Form\Mapper\FormMapper; use Sonata\BlockBundle\Meta\Metadata; +use Sonata\BlockBundle\Meta\MetadataInterface; +use Sonata\BlockBundle\Model\BlockInterface; +use Sonata\Form\Validator\ErrorElement; +use Symfony\Component\HttpFoundation\Response; use Symfony\Component\OptionsResolver\OptionsResolver; +use Twig\Environment; /** - * NEXT_MAJOR: Do not extend from `ContainerBlockService` since it will be final. - * * Render children pages. * * @author Thomas Rabaix - * - * @psalm-suppress InvalidExtendClass - * @phpstan-ignore-next-line */ -final class ContainerBlockService extends BaseContainerBlockService +final class ContainerBlockService implements BlockServiceInterface, EditableBlockService { + private BaseContainerBlockService $containerBlockService; + + public function __construct(BaseContainerBlockService $containerBlockService) + { + $this->containerBlockService = $containerBlockService; + } + + public function getName(): string + { + return 'sonata.page.block.container'; + } + + public function getTwig(): Environment + { + return $this->containerBlockService->getTwig(); + } + + public function execute(BlockContextInterface $blockContext, ?Response $response = null): Response + { + return $this->containerBlockService->execute($blockContext, $response); + } + + public function load(BlockInterface $block): void + { + $this->containerBlockService->load($block); + } + + public function getCacheKeys(BlockInterface $block): array + { + return $this->containerBlockService->getCacheKeys($block); + } + + public function configureEditForm(FormMapper $form, BlockInterface $block): void + { + $this->containerBlockService->configureEditForm($form, $block); + } + + public function configureCreateForm(FormMapper $form, BlockInterface $block): void + { + $this->containerBlockService->configureCreateForm($form, $block); + } + + public function validate(ErrorElement $errorElement, BlockInterface $block): void + { + $this->containerBlockService->validate($errorElement, $block); + } + + public function getMetadata($code = null): MetadataInterface + { + return new Metadata($this->getName(), (null !== $code ? $code : $this->getName()), null, 'SonataPageBundle', [ + 'class' => 'fa fa-square-o', + ]); + } + public function configureSettings(OptionsResolver $resolver): void { $resolver->setDefaults([ @@ -38,11 +96,4 @@ public function configureSettings(OptionsResolver $resolver): void 'template' => '@SonataPage/Block/block_container.html.twig', ]); } - - public function getBlockMetadata($code = null) - { - return new Metadata($this->getName(), (null !== $code ? $code : $this->getName()), false, 'SonataPageBundle', [ - 'class' => 'fa fa-square-o', - ]); - } } diff --git a/src/Block/PageListBlockService.php b/src/Block/PageListBlockService.php index 593a4248b..83ba7aed9 100755 --- a/src/Block/PageListBlockService.php +++ b/src/Block/PageListBlockService.php @@ -13,12 +13,15 @@ namespace Sonata\PageBundle\Block; -use Sonata\AdminBundle\Form\FormMapper; use Sonata\BlockBundle\Block\BlockContextInterface; use Sonata\BlockBundle\Block\Service\AbstractBlockService; +use Sonata\BlockBundle\Block\Service\EditableBlockService; +use Sonata\BlockBundle\Form\Mapper\FormMapper; use Sonata\BlockBundle\Meta\Metadata; +use Sonata\BlockBundle\Meta\MetadataInterface; use Sonata\BlockBundle\Model\BlockInterface; use Sonata\Form\Type\ImmutableArrayType; +use Sonata\Form\Validator\ErrorElement; use Sonata\PageBundle\Model\PageInterface; use Sonata\PageBundle\Model\PageManagerInterface; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; @@ -27,7 +30,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; use Twig\Environment; -final class PageListBlockService extends AbstractBlockService +final class PageListBlockService extends AbstractBlockService implements EditableBlockService { private PageManagerInterface $pageManager; @@ -38,39 +41,12 @@ public function __construct(Environment $twig, PageManagerInterface $pageManager $this->pageManager = $pageManager; } - public function buildEditForm(FormMapper $form, BlockInterface $block): void + public function getName(): string { - $form->add('settings', ImmutableArrayType::class, [ - 'keys' => [ - ['title', TextType::class, [ - 'label' => 'form.label_title', - 'required' => false, - ]], - ['translation_domain', TextType::class, [ - 'label' => 'form.label_translation_domain', - 'required' => false, - ]], - ['icon', TextType::class, [ - 'label' => 'form.label_icon', - 'required' => false, - ]], - ['class', TextType::class, [ - 'label' => 'form.label_class', - 'required' => false, - ]], - ['mode', ChoiceType::class, [ - 'label' => 'form.label_mode', - 'choices' => [ - 'public' => 'form.choice_public', - 'admin' => 'form.choice_admin', - ], - ]], - ], - 'translation_domain' => 'SonataPageBundle', - ]); + return 'sonata.page.block.pagelist'; } - public function execute(BlockContextInterface $blockContext, ?Response $response = null) + public function execute(BlockContextInterface $blockContext, ?Response $response = null): Response { $pageList = $this->pageManager->findBy([ 'routeName' => PageInterface::PAGE_ROUTE_CMS_NAME, @@ -102,10 +78,51 @@ public function configureSettings(OptionsResolver $resolver): void ]); } - public function getBlockMetadata($code = null) + public function getMetadata($code = null): MetadataInterface { - return new Metadata($this->getName(), (null !== $code ? $code : $this->getName()), false, 'SonataPageBundle', [ + return new Metadata($this->getName(), (null !== $code ? $code : $this->getName()), null, 'SonataPageBundle', [ 'class' => 'fa fa-home', ]); } + + public function configureEditForm(FormMapper $form, BlockInterface $block): void + { + $form->add('settings', ImmutableArrayType::class, [ + 'keys' => [ + ['title', TextType::class, [ + 'label' => 'form.label_title', + 'required' => false, + ]], + ['translation_domain', TextType::class, [ + 'label' => 'form.label_translation_domain', + 'required' => false, + ]], + ['icon', TextType::class, [ + 'label' => 'form.label_icon', + 'required' => false, + ]], + ['class', TextType::class, [ + 'label' => 'form.label_class', + 'required' => false, + ]], + ['mode', ChoiceType::class, [ + 'label' => 'form.label_mode', + 'choices' => [ + 'public' => 'form.choice_public', + 'admin' => 'form.choice_admin', + ], + ]], + ], + 'translation_domain' => 'SonataPageBundle', + ]); + } + + public function configureCreateForm(FormMapper $form, BlockInterface $block): void + { + $this->configureEditForm($form, $block); + } + + public function validate(ErrorElement $errorElement, BlockInterface $block): void + { + } } diff --git a/src/Block/SharedBlockBlockService.php b/src/Block/SharedBlockBlockService.php index cc9cee912..a2b4fb744 100755 --- a/src/Block/SharedBlockBlockService.php +++ b/src/Block/SharedBlockBlockService.php @@ -53,7 +53,7 @@ public function __construct(Environment $twig, ContainerBuilder $container, Mana $this->sharedBlockAdmin = $sharedBlockAdmin; } - public function execute(BlockContextInterface $blockContext, ?Response $response = null) + public function execute(BlockContextInterface $blockContext, ?Response $response = null): Response { $block = $blockContext->getBlock(); @@ -92,7 +92,7 @@ public function buildEditForm(FormMapper $form, BlockInterface $block): void ]); } - public function getName() + public function getName(): string { return 'Shared Block'; } diff --git a/src/DependencyInjection/SonataPageExtension.php b/src/DependencyInjection/SonataPageExtension.php index 3d47859ed..ffe979474 100644 --- a/src/DependencyInjection/SonataPageExtension.php +++ b/src/DependencyInjection/SonataPageExtension.php @@ -15,12 +15,12 @@ use Sonata\Doctrine\Mapper\Builder\OptionsBuilder; use Sonata\Doctrine\Mapper\DoctrineCollector; -use Sonata\EasyExtendsBundle\Mapper\DoctrineCollector as DeprecatedDoctrineCollector; use Sonata\PageBundle\Model\Template; use Symfony\Component\Config\Definition\Processor; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\DependencyInjection\Reference; @@ -28,10 +28,8 @@ /** * @author Thomas Rabaix - * - * @final since sonata-project/page-bundle 3.26 */ -class SonataPageExtension extends Extension implements PrependExtensionInterface +final class SonataPageExtension extends Extension implements PrependExtensionInterface { public function prepend(ContainerBuilder $container): void { @@ -62,13 +60,6 @@ public function load(array $configs, ContainerBuilder $container): void $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('page.xml'); - // NEXT_MAJOR: remove this code block - $definition = $container->getDefinition('sonata.page.router.request_context'); - $definition->setFactory([ - new Reference('sonata.page.site.selector'), - 'getRequestContext', - ]); - if (isset($bundles['SonataAdminBundle'])) { $loader->load('admin.xml'); @@ -110,8 +101,7 @@ public function load(array $configs, ContainerBuilder $container): void if (isset($bundles['SonataDoctrineBundle'])) { $this->registerSonataDoctrineMapping($config); } else { - // NEXT MAJOR: Remove this line and throw error when not registering SonataDoctrineBundle - $this->registerDoctrineMapping($config); + throw new ServiceNotFoundException('SonataDoctrineBundle'); } $this->registerParameters($container, $config); @@ -169,212 +159,6 @@ public function registerParameters(ContainerBuilder $container, array $config): $container->setParameter('sonata.page.router_auto_register.priority', $config['router_auto_register']['priority']); } - /** - * NEXT_MAJOR: Remove this method. - * - * Registers doctrine mapping on concrete page entities. - */ - public function registerDoctrineMapping(array $config): void - { - @trigger_error( - 'Using SonataEasyExtendsBundle is deprecated since sonata-project/page-bundle 3.19. Please register SonataDoctrineBundle as a bundle instead.', - \E_USER_DEPRECATED - ); - - if (!class_exists($config['class']['page'])) { - return; - } - - /** - * @phpstan-ignore-next-line - * @psalm-suppress UndefinedClass - */ - $collector = DeprecatedDoctrineCollector::getInstance(); - - $collector->addAssociation($config['class']['page'], 'mapOneToMany', [ - 'fieldName' => 'children', - 'targetEntity' => $config['class']['page'], - 'cascade' => [ - 'persist', - ], - 'mappedBy' => 'parent', - 'orphanRemoval' => false, - 'orderBy' => [ - 'position' => 'ASC', - ], - ]); - - $collector->addAssociation($config['class']['page'], 'mapOneToMany', [ - 'fieldName' => 'blocks', - 'targetEntity' => $config['class']['block'], - 'cascade' => [ - 'remove', - 'persist', - 'refresh', - 'merge', - 'detach', - ], - 'mappedBy' => 'page', - 'orphanRemoval' => false, - 'orderBy' => [ - 'position' => 'ASC', - ], - ]); - - $collector->addAssociation($config['class']['page'], 'mapManyToOne', [ - 'fieldName' => 'site', - 'targetEntity' => $config['class']['site'], - 'cascade' => [ - 'persist', - ], - 'mappedBy' => null, - 'inversedBy' => null, - 'joinColumns' => [ - [ - 'name' => 'site_id', - 'referencedColumnName' => 'id', - 'onDelete' => 'CASCADE', - ], - ], - 'orphanRemoval' => false, - ]); - - $collector->addAssociation($config['class']['page'], 'mapManyToOne', [ - 'fieldName' => 'parent', - 'targetEntity' => $config['class']['page'], - 'cascade' => [ - 'persist', - ], - 'mappedBy' => null, - 'inversedBy' => 'children', - 'joinColumns' => [ - [ - 'name' => 'parent_id', - 'referencedColumnName' => 'id', - 'onDelete' => 'CASCADE', - ], - ], - 'orphanRemoval' => false, - ]); - - $collector->addAssociation($config['class']['page'], 'mapOneToMany', [ - 'fieldName' => 'sources', - 'targetEntity' => $config['class']['page'], - 'cascade' => [], - 'mappedBy' => 'target', - 'orphanRemoval' => false, - ]); - - $collector->addAssociation($config['class']['page'], 'mapManyToOne', [ - 'fieldName' => 'target', - 'targetEntity' => $config['class']['page'], - 'cascade' => [ - 'persist', - ], - 'mappedBy' => null, - 'inversedBy' => 'sources', - 'joinColumns' => [ - [ - 'name' => 'target_id', - 'referencedColumnName' => 'id', - 'onDelete' => 'CASCADE', - ], - ], - 'orphanRemoval' => false, - ]); - - $collector->addAssociation($config['class']['block'], 'mapOneToMany', [ - 'fieldName' => 'children', - 'targetEntity' => $config['class']['block'], - 'cascade' => [ - 'remove', - 'persist', - ], - 'mappedBy' => 'parent', - 'orphanRemoval' => true, - 'orderBy' => [ - 'position' => 'ASC', - ], - ]); - - $collector->addAssociation($config['class']['block'], 'mapManyToOne', [ - 'fieldName' => 'parent', - 'targetEntity' => $config['class']['block'], - 'cascade' => [ - ], - 'mappedBy' => null, - 'inversedBy' => 'children', - 'joinColumns' => [ - [ - 'name' => 'parent_id', - 'referencedColumnName' => 'id', - 'onDelete' => 'CASCADE', - ], - ], - 'orphanRemoval' => false, - ]); - - $collector->addAssociation($config['class']['block'], 'mapManyToOne', [ - 'fieldName' => 'page', - 'targetEntity' => $config['class']['page'], - 'cascade' => [ - 'persist', - ], - 'mappedBy' => null, - 'inversedBy' => 'blocks', - 'joinColumns' => [ - [ - 'name' => 'page_id', - 'referencedColumnName' => 'id', - 'onDelete' => 'CASCADE', - ], - ], - 'orphanRemoval' => false, - ]); - - $collector->addAssociation($config['class']['snapshot'], 'mapManyToOne', [ - 'fieldName' => 'site', - 'targetEntity' => $config['class']['site'], - 'cascade' => [ - 'persist', - ], - 'mappedBy' => null, - 'inversedBy' => null, - 'joinColumns' => [ - [ - 'name' => 'site_id', - 'referencedColumnName' => 'id', - 'onDelete' => 'CASCADE', - ], - ], - 'orphanRemoval' => false, - ]); - - $collector->addAssociation($config['class']['snapshot'], 'mapManyToOne', [ - 'fieldName' => 'page', - 'targetEntity' => $config['class']['page'], - 'cascade' => [ - 'persist', - ], - 'mappedBy' => null, - 'inversedBy' => null, - 'joinColumns' => [ - [ - 'name' => 'page_id', - 'referencedColumnName' => 'id', - 'onDelete' => 'CASCADE', - ], - ], - 'orphanRemoval' => false, - ]); - - $collector->addIndex($config['class']['snapshot'], 'idx_snapshot_dates_enabled', [ - 'publication_date_start', - 'publication_date_end', - 'enabled', - ]); - } - /** * Configure the multi-site feature. * diff --git a/src/Form/Type/PageSelectorType.php b/src/Form/Type/PageSelectorType.php index c662aa755..aa6d9ae53 100644 --- a/src/Form/Type/PageSelectorType.php +++ b/src/Form/Type/PageSelectorType.php @@ -20,21 +20,15 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\OptionsResolver\OptionsResolverInterface; /** * Select a page. * * @author Thomas Rabaix - * - * @final since sonata-project/page-bundle 3.26 */ -class PageSelectorType extends AbstractType +final class PageSelectorType extends AbstractType { - /** - * @var PageManagerInterface - */ - protected $manager; + private PageManagerInterface $manager; public function __construct(PageManagerInterface $manager) { @@ -61,15 +55,12 @@ public function configureOptions(OptionsResolver $resolver): void ]); } - public function setDefaultOptions(OptionsResolverInterface $resolver): void + public function setDefaultOptions(OptionsResolver $resolver): void { $this->configureOptions($resolver); } - /** - * @return array - */ - public function getChoices(Options $options) + public function getChoices(Options $options): array { if (!$options['site'] instanceof SiteInterface) { return []; @@ -125,26 +116,21 @@ public function getChoices(Options $options) return $choices; } - public function getParent() + public function getParent(): string { return ModelType::class; } - public function getBlockPrefix() + public function getBlockPrefix(): string { return 'sonata_page_selector'; } - public function getName() + public function getName(): string { return $this->getBlockPrefix(); } - /** - * @param PageInterface $currentPage - * @param array $choices - * @param int $level - */ private function childWalker(PageInterface $page, ?PageInterface $currentPage = null, &$choices, $level = 1): void { foreach ($page->getChildren() as $child) { diff --git a/src/Form/Type/PageTypeChoiceType.php b/src/Form/Type/PageTypeChoiceType.php index 8f2a97e36..3a033c8ef 100644 --- a/src/Form/Type/PageTypeChoiceType.php +++ b/src/Form/Type/PageTypeChoiceType.php @@ -17,21 +17,15 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\OptionsResolver\OptionsResolverInterface; /** * Select a page type. * * @author Olivier Paradis - * - * @final since sonata-project/page-bundle 3.26 */ -class PageTypeChoiceType extends AbstractType +final class PageTypeChoiceType extends AbstractType { - /** - * @var PageServiceManagerInterface - */ - protected $manager; + protected PageServiceManagerInterface $manager; public function __construct(PageServiceManagerInterface $manager) { @@ -48,20 +42,7 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setDefaults($defaults); } - /** - * NEXT_MAJOR: remove this method. - * - * @deprecated since sonata-project/page-bundle 3.14, to be removed in version 4.0. - */ - public function setDefaultOptions(OptionsResolverInterface $resolver): void - { - $this->configureOptions($resolver); - } - - /** - * @return string[] - */ - public function getPageTypes() + public function getPageTypes(): array { $services = $this->manager->getAll(); $types = []; @@ -74,23 +55,13 @@ public function getPageTypes() return $types; } - public function getParent() + public function getParent(): string { return ChoiceType::class; } - public function getBlockPrefix() + public function getBlockPrefix(): string { return 'sonata_page_type_choice'; } - - /** - * NEXT_MAJOR: remove this method. - * - * @deprecated since sonata-project/page-bundle 3.14, to be removed in version 4.0. - */ - public function getName() - { - return $this->getBlockPrefix(); - } } diff --git a/src/Form/Type/TemplateChoiceType.php b/src/Form/Type/TemplateChoiceType.php index d48024374..383fea26b 100644 --- a/src/Form/Type/TemplateChoiceType.php +++ b/src/Form/Type/TemplateChoiceType.php @@ -17,21 +17,15 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\OptionsResolver\OptionsResolverInterface; /** * Select a template. * * @author Thomas Rabaix - * - * @final since sonata-project/page-bundle 3.26 */ -class TemplateChoiceType extends AbstractType +final class TemplateChoiceType extends AbstractType { - /** - * @var TemplateManagerInterface - */ - protected $manager; + protected TemplateManagerInterface $manager; public function __construct(TemplateManagerInterface $manager) { @@ -48,20 +42,7 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setDefaults($defaults); } - /** - * NEXT_MAJOR: remove this method. - * - * @deprecated since sonata-project/page-bundle 3.14, to be removed in version 4.0. - */ - public function setDefaultOptions(OptionsResolverInterface $resolver): void - { - $this->configureOptions($resolver); - } - - /** - * @return string[] - */ - public function getTemplates() + public function getTemplates(): array { $templates = []; foreach ($this->manager->getAll() as $code => $template) { @@ -71,23 +52,13 @@ public function getTemplates() return $templates; } - public function getParent() + public function getParent(): string { return ChoiceType::class; } - public function getBlockPrefix() + public function getBlockPrefix(): string { return 'sonata_page_template'; } - - /** - * NEXT_MAJOR: remove this method. - * - * @deprecated since sonata-project/page-bundle 3.14, to be removed in version 4.0. - */ - public function getName() - { - return $this->getBlockPrefix(); - } } diff --git a/src/Mapper/PageFormMapper.php b/src/Mapper/PageFormMapper.php index edb674baf..9013371bf 100644 --- a/src/Mapper/PageFormMapper.php +++ b/src/Mapper/PageFormMapper.php @@ -19,10 +19,7 @@ final class PageFormMapper implements FormMapper { - /** - * @var AdminFormMapper - */ - private $adminFormMapper; + private AdminFormMapper $adminFormMapper; public function __construct(AdminFormMapper $adminFormMapper) { @@ -74,7 +71,7 @@ public function has(string $key): bool return $this->adminFormMapper->has($key); } - public function get(string $name) + public function get(string $name): FormBuilderInterface { return $this->adminFormMapper->get($name); } diff --git a/src/Page/Service/BasePageService.php b/src/Page/Service/BasePageService.php index a11e2e12a..71c5b176b 100644 --- a/src/Page/Service/BasePageService.php +++ b/src/Page/Service/BasePageService.php @@ -22,20 +22,15 @@ abstract class BasePageService implements PageServiceInterface { /** * Page service name used in the admin. - * - * @var string */ - protected $name; + protected string $name; - /** - * @param string $name Page service name - */ - public function __construct($name) + public function __construct(string $name) { $this->name = $name; } - public function getName() + public function getName(): string { return $this->name; } diff --git a/src/Page/Service/DefaultPageService.php b/src/Page/Service/DefaultPageService.php index 810308602..e404e66c8 100644 --- a/src/Page/Service/DefaultPageService.php +++ b/src/Page/Service/DefaultPageService.php @@ -25,28 +25,22 @@ * Note: this service is backward-compatible and functions like the old page renderer class. * * @author Olivier Paradis - * - * @final since sonata-project/page-bundle 3.26 */ -class DefaultPageService extends BasePageService +final class DefaultPageService extends BasePageService { - /** - * @var TemplateManagerInterface - */ - protected $templateManager; + protected TemplateManagerInterface $templateManager; - /** - * @var SeoPageInterface - */ - protected $seoPage; + protected SeoPageInterface $seoPage; /** * @param string $name Page service name * @param TemplateManagerInterface $templateManager Template manager * @param SeoPageInterface $seoPage SEO page object */ - public function __construct($name, TemplateManagerInterface $templateManager, ?SeoPageInterface $seoPage = null) + public function __construct(string $name, TemplateManagerInterface $templateManager, ?SeoPageInterface $seoPage = null) { + parent::__construct($name); + $this->name = $name; $this->templateManager = $templateManager; $this->seoPage = $seoPage; @@ -56,9 +50,7 @@ public function execute(PageInterface $page, Request $request, array $parameters { $this->updateSeoPage($page); - $response = $this->templateManager->renderResponse($page->getTemplateCode(), $parameters, $response); - - return $response; + return $this->templateManager->renderResponse($page->getTemplateCode(), $parameters, $response); } /** diff --git a/src/Resources/config/admin.xml b/src/Resources/config/admin.xml index 7f3a6b034..e51d0c9e4 100644 --- a/src/Resources/config/admin.xml +++ b/src/Resources/config/admin.xml @@ -50,10 +50,10 @@ - + sonata.page.admin.block %sonata.page.admin.block.entity% - %sonata.page.admin.block.controller% - %sonata_block.blocks% + sonata.page.admin.block.controller + diff --git a/src/Resources/config/block.xml b/src/Resources/config/block.xml index 0da2cd684..045c16552 100644 --- a/src/Resources/config/block.xml +++ b/src/Resources/config/block.xml @@ -11,7 +11,7 @@ - + @@ -25,16 +25,12 @@ - - + - page - sonata.page.block.breadcrumb - - + diff --git a/tests/Admin/BaseBlockAdminTest.php b/tests/Admin/BaseBlockAdminTest.php index 36e5f3606..e14855b02 100644 --- a/tests/Admin/BaseBlockAdminTest.php +++ b/tests/Admin/BaseBlockAdminTest.php @@ -16,10 +16,7 @@ use PHPUnit\Framework\TestCase; use Sonata\AdminBundle\Admin\AdminInterface; use Sonata\AdminBundle\Datagrid\ProxyQueryInterface; -use Sonata\BlockBundle\Block\BlockServiceManagerInterface; -use Sonata\BlockBundle\Block\Service\AbstractAdminBlockService; use Sonata\PageBundle\Admin\BaseBlockAdmin; -use Sonata\PageBundle\Model\PageBlockInterface; use Sonata\PageBundle\Model\PageInterface; final class BaseBlockAdminTest extends TestCase @@ -41,34 +38,4 @@ public function testSettingAsEditedOnPreBatchDeleteAction(): void $idx = []; $blockAdmin->preBatchAction('delete', $query, $idx, true); } - - /** - * NEXT_MAJOR: Remove this method. - * - * @group legacy - */ - public function testSettingAsEditedOnPreRemove(): void - { - $page = $this->createMock(PageInterface::class); - $page->expects(static::once())->method('setEdited')->with(true); - - $block = $this->createMock(PageBlockInterface::class); - $block->expects(static::once())->method('getPage')->willReturn($page); - - $blockService = $this->createMock(AbstractAdminBlockService::class); - $blockService->method('preRemove')->with($block); - - $blockServiceManager = $this->createMock(BlockServiceManagerInterface::class); - $blockServiceManager - ->expects(static::once()) - ->method('get') - ->with($block) - ->willReturn($blockService); - - $blockAdmin = $this->getMockBuilder(BaseBlockAdmin::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - $blockAdmin->setBlockManager($blockServiceManager); - $blockAdmin->preRemove($block); - } } diff --git a/tests/Block/BlockContextManagerTest.php b/tests/Block/BlockContextManagerTest.php index 24c4be9fa..b3079d10d 100644 --- a/tests/Block/BlockContextManagerTest.php +++ b/tests/Block/BlockContextManagerTest.php @@ -14,12 +14,9 @@ namespace Sonata\PageBundle\Tests\Block; use PHPUnit\Framework\TestCase; +use Sonata\BlockBundle\Block\BlockContext; use Sonata\BlockBundle\Block\BlockContextInterface; -use Sonata\BlockBundle\Block\BlockLoaderInterface; -use Sonata\BlockBundle\Block\BlockServiceManagerInterface; -use Sonata\BlockBundle\Block\Service\AbstractBlockService; -use Sonata\BlockBundle\Model\BlockInterface; -use Sonata\PageBundle\Block\BlockContextManager; +use Sonata\BlockBundle\Model\Block; /** * @author Sullivan Senechal @@ -28,30 +25,21 @@ final class BlockContextManagerTest extends TestCase { public function testGetWithValidData(): void { - $service = $this->createMock(AbstractBlockService::class); - - $blockLoader = $this->createMock(BlockLoaderInterface::class); - - $serviceManager = $this->createMock(BlockServiceManagerInterface::class); - $serviceManager->expects(static::once())->method('get')->willReturn($service); - - $block = $this->createMock(BlockInterface::class); - $block->expects(static::once())->method('getSettings')->willReturn([]); - - $manager = new BlockContextManager($blockLoader, $serviceManager); - - $blockContext = $manager->get($block); - - static::assertInstanceOf(BlockContextInterface::class, $blockContext); - - static::assertSame([ + $settings = [ 'use_cache' => true, 'extra_cache_keys' => [], 'attr' => [], - 'template' => false, + 'template' => 'test_template', 'ttl' => 0, 'manager' => false, 'page_id' => false, - ], $blockContext->getSettings()); + ]; + $block = new Block(); + $block->setSettings($settings); + $blockContext = new BlockContext($block, $block->getSettings()); + + static::assertInstanceOf(BlockContextInterface::class, $blockContext); + static::assertSame($settings, $blockContext->getSettings()); + static::assertSame('test_template', $blockContext->getTemplate()); } } diff --git a/tests/Block/ContainerBlockServiceTest.php b/tests/Block/ContainerBlockServiceTest.php index fcb82ef61..2cb0f44b9 100644 --- a/tests/Block/ContainerBlockServiceTest.php +++ b/tests/Block/ContainerBlockServiceTest.php @@ -13,8 +13,9 @@ namespace Sonata\PageBundle\Tests\Block; -use Sonata\AdminBundle\Form\FormMapper; use Sonata\BlockBundle\Block\BlockContext; +use Sonata\BlockBundle\Block\Service\ContainerBlockService as BaseContainerBlockService; +use Sonata\BlockBundle\Form\Mapper\FormMapper; use Sonata\BlockBundle\Model\Block; use Sonata\BlockBundle\Test\BlockServiceTestCase; use Sonata\PageBundle\Block\ContainerBlockService; @@ -30,13 +31,6 @@ final class ContainerBlockServiceTest extends BlockServiceTestCase */ public function testExecute(): void { - $this->twig->expects(static::once()) - ->method('render') - ->with('@SonataPage/Block/block_container.html.twig') - ->willReturn('

{{ settings.title }} test

'); - - $service = new ContainerBlockService($this->twig); - $block = new Block(); $block->setName('block.name'); $block->setType('core.container'); @@ -44,6 +38,13 @@ public function testExecute(): void 'code' => 'block.code', ]); + $this->twig->expects(static::once()) + ->method('render') + ->with('@SonataPage/Block/block_container.html.twig') + ->willReturn('

{{ settings.title }} test

'); + + $baseContainerBlockService = new BaseContainerBlockService($this->twig); + $service = new ContainerBlockService($baseContainerBlockService); $blockContext = new BlockContext($block, [ 'code' => '', 'layout' => '{{ CONTENT }}', @@ -52,6 +53,7 @@ public function testExecute(): void ]); $response = $service->execute($blockContext); + static::assertInstanceOf(Response::class, $response); static::assertSame('

{{ settings.title }} test

', $response->getContent()); static::assertSame(200, $response->getStatusCode()); @@ -62,8 +64,6 @@ public function testExecute(): void */ public function testFormBuilder(): void { - $service = new ContainerBlockService($this->twig); - $block = new Block(); $block->setName('block.name'); $block->setType('core.container'); @@ -71,10 +71,12 @@ public function testFormBuilder(): void 'name' => 'block.code', ]); + $baseContainerBlockService = new BaseContainerBlockService($this->twig); + $service = new ContainerBlockService($baseContainerBlockService); + $form = $this->createMock(FormMapper::class); - $form->expects(static::exactly(6))->method('add'); + $form->expects(static::exactly(3))->method('add'); - $service->buildCreateForm($form, $block); - $service->buildEditForm($form, $block); + $service->configureCreateForm($form, $block); } } diff --git a/tests/Block/PageListBlockServiceTest.php b/tests/Block/PageListBlockServiceTest.php index 626e1a2c5..5ade955b3 100644 --- a/tests/Block/PageListBlockServiceTest.php +++ b/tests/Block/PageListBlockServiceTest.php @@ -15,6 +15,7 @@ use PHPUnit\Framework\MockObject\MockObject; use Sonata\BlockBundle\Block\BlockContext; +use Sonata\BlockBundle\Form\Mapper\FormMapper; use Sonata\BlockBundle\Model\Block; use Sonata\BlockBundle\Test\BlockServiceTestCase; use Sonata\PageBundle\Block\PageListBlockService; @@ -83,4 +84,15 @@ public function testExecute(): void static::assertSame('

{{ settings.title }} test

', $response->getContent()); static::assertSame(200, $response->getStatusCode()); } + + public function testFormBuilder(): void + { + $block = new Block(); + + $form = $this->createMock(FormMapper::class); + $form->expects(static::once())->method('add'); + + $blockService = new PageListBlockService($this->twig, $this->pageManager); + $blockService->configureCreateForm($form, $block); + } } diff --git a/tests/Page/Service/DefaultPageServiceTest.php b/tests/Page/Service/DefaultPageServiceTest.php index 244b954c7..c1d09ab26 100644 --- a/tests/Page/Service/DefaultPageServiceTest.php +++ b/tests/Page/Service/DefaultPageServiceTest.php @@ -70,13 +70,14 @@ public function testExecute(): void $this->seoPage->expects(static::once()) ->method('setTitle')->with(static::equalTo('page title')); - $metaMapping = [ - ['name', 'description', 'page meta description', true], - ['name', 'keywords', 'page meta keywords', true], - ['property', 'og:type', 'article', true], - ]; - - $this->seoPage->expects(static::exactly(3))->method('addMeta')->willReturnMap($metaMapping); + $this->seoPage->expects(static::exactly(3)) + ->method('addMeta') + ->withConsecutive( + ['name', 'description', 'page meta description'], + ['name', 'keywords', 'page meta keywords'], + ['property', 'og:type', 'article'] + ) + ->willReturnOnConsecutiveCalls($this->seoPage, $this->seoPage, $this->seoPage); $this->seoPage->expects(static::once()) ->method('addHtmlAttributes')->with(static::equalTo('prefix'), static::equalTo('og: http://ogp.me/ns#'));