diff --git a/composer.json b/composer.json index c252b5ca3..8d1bb001c 100644 --- a/composer.json +++ b/composer.json @@ -54,6 +54,7 @@ "dama/doctrine-test-bundle": "^6.7", "doctrine/annotations": "^1.13.3", "friendsofphp/php-cs-fixer": "^3.4", + "masterminds/html5": "^2.7", "matthiasnoback/symfony-dependency-injection-test": "^4.1.1", "phpstan/extension-installer": "^1.0", "phpstan/phpstan": "^1.0", diff --git a/src/Admin/BlockAdmin.php b/src/Admin/BlockAdmin.php index 3acdb085e..f72d94fed 100644 --- a/src/Admin/BlockAdmin.php +++ b/src/Admin/BlockAdmin.php @@ -22,7 +22,6 @@ use Sonata\BlockBundle\Block\Service\EditableBlockService; use Sonata\BlockBundle\Form\Type\ServiceListType; use Sonata\BlockBundle\Model\BlockInterface; -use Sonata\PageBundle\Mapper\PageFormMapper; use Sonata\PageBundle\Model\PageBlockInterface; use Sonata\PageBundle\Model\PageInterface; use Symfony\Bridge\Doctrine\Form\Type\EntityType; @@ -232,12 +231,10 @@ private function configureBlockFields(FormMapper $form, BlockInterface $block): )); } - $blockMapper = new PageFormMapper($form); - if ($block->getId() > 0) { - $service->configureEditForm($blockMapper, $block); + $service->configureEditForm($form, $block); } else { - $service->configureCreateForm($blockMapper, $block); + $service->configureCreateForm($form, $block); } if ($form->has('settings') && isset($this->blocks[$blockType]['templates'])) { diff --git a/src/Admin/SharedBlockAdmin.php b/src/Admin/SharedBlockAdmin.php index 53cf3c85a..e412b9d48 100644 --- a/src/Admin/SharedBlockAdmin.php +++ b/src/Admin/SharedBlockAdmin.php @@ -19,7 +19,6 @@ use Sonata\BlockBundle\Block\Service\EditableBlockService; use Sonata\BlockBundle\Model\BlockInterface; use Sonata\DoctrineORMAdminBundle\Datagrid\ProxyQuery; -use Sonata\PageBundle\Mapper\PageFormMapper; use Sonata\PageBundle\Model\PageBlockInterface; /** @@ -103,12 +102,10 @@ private function configureBlockFields(FormMapper $form, BlockInterface $block): )); } - $blockMapper = new PageFormMapper($form); - if ($block->getId() > 0) { - $service->configureEditForm($blockMapper, $block); + $service->configureEditForm($form, $block); } else { - $service->configureCreateForm($blockMapper, $block); + $service->configureCreateForm($form, $block); } } } diff --git a/src/Block/ChildrenPagesBlockService.php b/src/Block/ChildrenPagesBlockService.php index 9c001b0a9..61a8f0006 100755 --- a/src/Block/ChildrenPagesBlockService.php +++ b/src/Block/ChildrenPagesBlockService.php @@ -170,20 +170,6 @@ public function configureSettings(OptionsResolver $resolver): void ]); } - public function prePersist(BlockInterface $block): void - { - $page = $block->getSetting('pageId'); - - $block->setSetting('pageId', $page instanceof PageInterface ? $page->getId() : null); - } - - public function preUpdate(BlockInterface $block): void - { - $page = $block->getSetting('pageId'); - - $block->setSetting('pageId', $page instanceof PageInterface ? $page->getId() : null); - } - public function load(BlockInterface $block): void { if (!$block instanceof PageBlockInterface) { diff --git a/src/Block/SharedBlockBlockService.php b/src/Block/SharedBlockBlockService.php index 23f0ea300..4254afad6 100755 --- a/src/Block/SharedBlockBlockService.php +++ b/src/Block/SharedBlockBlockService.php @@ -13,7 +13,7 @@ namespace Sonata\PageBundle\Block; -use Sonata\AdminBundle\Admin\AdminInterface; +use Sonata\AdminBundle\Form\FormMapper as AdminFormMapper; use Sonata\AdminBundle\Form\Type\ModelListType; use Sonata\BlockBundle\Block\BlockContextInterface; use Sonata\BlockBundle\Block\Service\AbstractBlockService; @@ -42,24 +42,16 @@ final class SharedBlockBlockService extends AbstractBlockService implements Edit */ private ManagerInterface $blockManager; - /** - * @var AdminInterface - */ - private AdminInterface $sharedBlockAdmin; - /** * @param ManagerInterface $blockManager - * @param AdminInterface $sharedBlockAdmin */ public function __construct( Environment $twig, - ManagerInterface $blockManager, - AdminInterface $sharedBlockAdmin + ManagerInterface $blockManager ) { parent::__construct($twig); $this->blockManager = $blockManager; - $this->sharedBlockAdmin = $sharedBlockAdmin; } public function execute(BlockContextInterface $blockContext, ?Response $response = null): Response @@ -76,10 +68,10 @@ public function execute(BlockContextInterface $blockContext, ?Response $response \assert(null !== $template); return $this->renderResponse($template, [ - 'block' => $blockContext->getBlock(), - 'settings' => $blockContext->getSettings(), - 'sharedBlock' => $sharedBlock, - ], $response); + 'block' => $blockContext->getBlock(), + 'settings' => $blockContext->getSettings(), + 'sharedBlock' => $sharedBlock, + ], $response); } public function validate(ErrorElement $errorElement, BlockInterface $block): void @@ -92,13 +84,17 @@ public function validate(ErrorElement $errorElement, BlockInterface $block): voi public function configureEditForm(FormMapper $form, BlockInterface $block): void { + if (!$form instanceof AdminFormMapper) { + throw new \InvalidArgumentException('Shared Block requires to be used in the Admin context'); + } + if (!$block->getSetting('blockId') instanceof BlockInterface) { $this->load($block); } $form->add('settings', ImmutableArrayType::class, [ 'keys' => [ - [$this->getBlockBuilder(), null, []], + [$this->getBlockBuilder($form), null, []], ], ]); } @@ -134,31 +130,23 @@ public function load(BlockInterface $block): void $block->setSetting('blockId', $sharedBlock); } - public function prePersist(BlockInterface $block): void - { - $block = $block->getSetting('blockId'); - - $block->setSetting('blockId', $block instanceof BlockInterface ? $block->getId() : null); - } - - public function preUpdate(BlockInterface $block): void + /** + * @param AdminFormMapper $form + */ + private function getBlockBuilder(AdminFormMapper $form): FormBuilderInterface { - $block = $block->getSetting('blockId'); + $admin = $form->getAdmin(); - $block->setSetting('blockId', $block instanceof BlockInterface ? $block->getId() : null); - } - - private function getBlockBuilder(): FormBuilderInterface - { - $fieldDescription = $this->sharedBlockAdmin->createFieldDescription('block', [ + $fieldDescription = $admin->createFieldDescription('block', [ 'translation_domain' => 'SonataPageBundle', 'edit' => 'list', ]); + $fieldDescription->setAssociationAdmin($admin); - return $this->sharedBlockAdmin->getFormBuilder()->create('blockId', ModelListType::class, [ + return $form->getFormBuilder()->create('blockId', ModelListType::class, [ 'sonata_field_description' => $fieldDescription, - 'class' => $this->sharedBlockAdmin->getClass(), - 'model_manager' => $this->sharedBlockAdmin->getModelManager(), + 'class' => $admin->getClass(), + 'model_manager' => $admin->getModelManager(), 'label' => 'form.label_block', 'required' => false, ]); diff --git a/src/Mapper/PageFormMapper.php b/src/Mapper/PageFormMapper.php deleted file mode 100644 index 826a9c4f5..000000000 --- a/src/Mapper/PageFormMapper.php +++ /dev/null @@ -1,73 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Sonata\PageBundle\Mapper; - -use Sonata\AdminBundle\Form\FormMapper as AdminFormMapper; -use Sonata\BlockBundle\Form\Mapper\FormMapper; -use Symfony\Component\Form\FormBuilderInterface; - -/** - * @phpstan-template T of object - */ -final class PageFormMapper implements FormMapper -{ - /** - * @var AdminFormMapper - */ - private AdminFormMapper $adminFormMapper; - - /** - * @param AdminFormMapper $adminFormMapper - */ - public function __construct(AdminFormMapper $adminFormMapper) - { - $this->adminFormMapper = $adminFormMapper; - } - - public function create(string $name, ?string $type = null, array $options = []): FormBuilderInterface - { - return $this->adminFormMapper->create($name, $type, $options); - } - - public function reorder(array $keys): FormMapper - { - $this->adminFormMapper->reorder($keys); - - return $this; - } - - public function add(string $name, ?string $type = null, array $options = []): FormMapper - { - $this->adminFormMapper->add($name, $type, $options); - - return $this; - } - - public function remove(string $key): FormMapper - { - $this->adminFormMapper->remove($key); - - return $this; - } - - public function has(string $key): bool - { - return $this->adminFormMapper->has($key); - } - - public function get(string $key): FormBuilderInterface - { - return $this->adminFormMapper->get($key); - } -} diff --git a/src/Resources/config/block.php b/src/Resources/config/block.php index 3ef7a772a..cd9665901 100644 --- a/src/Resources/config/block.php +++ b/src/Resources/config/block.php @@ -53,7 +53,6 @@ ->args([ new ReferenceConfigurator('twig'), new ReferenceConfigurator('sonata.page.manager.block'), - new ReferenceConfigurator('sonata.page.admin.shared_block'), ]) ->set('sonata.page.block.pagelist', PageListBlockService::class) diff --git a/tests/Functional/Admin/SharedBlockAdminTest.php b/tests/Functional/Admin/SharedBlockAdminTest.php index 2981b8294..1414a9f2a 100644 --- a/tests/Functional/Admin/SharedBlockAdminTest.php +++ b/tests/Functional/Admin/SharedBlockAdminTest.php @@ -45,11 +45,151 @@ public function testCrudUrls(string $url, array $parameters = []): void public static function provideCrudUrlsCases(): iterable { yield 'List Block' => ['/admin/tests/app/sonatapageblock/shared/list']; - yield 'Create Block' => ['/admin/tests/app/sonatapageblock/shared/create']; + yield 'List Block types' => ['/admin/tests/app/sonatapageblock/shared/create']; + + yield 'Create Block' => ['/admin/tests/app/sonatapageblock/shared/create', [ + 'type' => 'sonata.page.block.shared_block', + ]]; + yield 'Edit Block' => ['/admin/tests/app/sonatapageblock/shared/1/edit']; yield 'Remove Block' => ['/admin/tests/app/sonatapageblock/shared/1/delete']; } + /** + * @dataProvider provideFormUrlsCases + * + * @param array $parameters + * @param array $fieldValues + */ + public function testFormsUrls(string $url, array $parameters, string $button, array $fieldValues = []): void + { + $client = self::createClient(); + + $this->prepareData(); + + $client->request('GET', $url, $parameters); + $client->submitForm($button, $fieldValues); + $client->followRedirect(); + + self::assertResponseIsSuccessful(); + } + + /** + * @return iterable>> + * + * @phpstan-return iterable, 2: string, 3?: array}> + */ + public static function provideFormUrlsCases(): iterable + { + // Blocks From SonataBlockBundle + // yield 'Create Shared Block - Container' => ['/admin/tests/app/sonatapageblock/shared/create', [ + // 'uniqid' => 'shared_block', + // 'type' => 'sonata.block.service.container', + // ], 'btn_create_and_list', [ + // 'shared_block[name]' => 'Name', + // 'shared_block[enabled]' => 1, + // 'shared_block[settings][code]' => 'code', + // 'shared_block[settings][layout]' => '{{ CONTENT }}', + // 'shared_block[settings][class]' => 'custom_class', + // 'shared_block[settings][template]' => '@SonataPage/Block/block_container.html.twig', + // 'shared_block[children]' => '', + // ]]; + + yield 'Create Shared Block - Text' => ['/admin/tests/app/sonatapageblock/shared/create', [ + 'uniqid' => 'shared_block', + 'type' => 'sonata.block.service.text', + ], 'btn_create_and_list', [ + 'shared_block[name]' => 'Name', + 'shared_block[enabled]' => 1, + 'shared_block[settings][content]' => 'Text', + ]]; + + yield 'Create Shared Block - Template' => ['/admin/tests/app/sonatapageblock/shared/create', [ + 'uniqid' => 'shared_block', + 'type' => 'sonata.block.service.template', + ], 'btn_create_and_list', [ + 'shared_block[name]' => 'Name', + 'shared_block[enabled]' => 1, + 'shared_block[settings][template]' => '@SonataBlock/Block/block_template.html.twig', + ]]; + + yield 'Create Shared Block - Menu' => ['/admin/tests/app/sonatapageblock/shared/create', [ + 'uniqid' => 'shared_block', + 'type' => 'sonata.block.service.menu', + ], 'btn_create_and_list', [ + 'shared_block[name]' => 'Name', + 'shared_block[enabled]' => 1, + 'shared_block[settings][title]' => 'Title', + 'shared_block[settings][menu_name]' => 'sonata_admin_sidebar', + 'shared_block[settings][safe_labels]' => 1, + 'shared_block[settings][current_class]' => 'active', + 'shared_block[settings][first_class]' => 'first', + 'shared_block[settings][last_class]' => 'last', + 'shared_block[settings][menu_class]' => 'menu_sonata', + 'shared_block[settings][children_class]' => 'children', + 'shared_block[settings][menu_template]' => '@SonataBlock/Block/block_core_menu.html.twig', + ]]; + + yield 'Create Shared Block - RSS' => ['/admin/tests/app/sonatapageblock/shared/create', [ + 'uniqid' => 'shared_block', + 'type' => 'sonata.block.service.rss', + ], 'btn_create_and_list', [ + 'shared_block[name]' => 'Name', + 'shared_block[enabled]' => 1, + 'shared_block[settings][url]' => 'https://sonata-project.org', + 'shared_block[settings][title]' => 'Title', + 'shared_block[settings][translation_domain]' => 'SonataPageBundle', + 'shared_block[settings][icon]' => 'fa fa-home', + 'shared_block[settings][class]' => 'custom_class', + ]]; + + // Blocks From SonataPageBundle + yield 'Create Shared Block - Children Pages' => ['/admin/tests/app/sonatapageblock/shared/create', [ + 'uniqid' => 'shared_block', + 'type' => 'sonata.page.block.children_pages', + ], 'btn_create_and_list', [ + 'shared_block[name]' => 'Name', + 'shared_block[enabled]' => 1, + 'shared_block[settings][title]' => 'Title', + 'shared_block[settings][translation_domain]' => 'SonataPageBundle', + 'shared_block[settings][icon]' => 'fa fa-home', + 'shared_block[settings][current]' => 1, + // 'shared_block[settings][pageId]' => 1, + 'shared_block[settings][class]' => 'custom_class', + ]]; + + // yield 'Create Shared Block - Breadcrumb' => ['/admin/tests/app/sonatapageblock/shared/create', [ + // 'uniqid' => 'shared_block', + // 'type' => 'sonata.page.block.breadcrumb', + // ], 'btn_create_and_list', [ + // ]]; + + yield 'Create Shared Block - Shared Block' => ['/admin/tests/app/sonatapageblock/shared/create', [ + 'uniqid' => 'shared_block', + 'type' => 'sonata.page.block.shared_block', + ], 'btn_create_and_list', [ + 'shared_block[name]' => 'Name', + 'shared_block[enabled]' => 1, + 'shared_block[settings][blockId]' => 1, + ]]; + + yield 'Create Shared Block - Page List' => ['/admin/tests/app/sonatapageblock/shared/create', [ + 'uniqid' => 'shared_block', + 'type' => 'sonata.page.block.pagelist', + ], 'btn_create_and_list', [ + 'shared_block[name]' => 'Name', + 'shared_block[enabled]' => 1, + 'shared_block[settings][title]' => 'Title', + 'shared_block[settings][translation_domain]' => 'SonataPageBundle', + 'shared_block[settings][icon]' => 'fa fa-home', + 'shared_block[settings][class]' => 'custom_class', + 'shared_block[settings][mode]' => 'form.choice_public', + ]]; + + yield 'Edit Shared Block' => ['/admin/tests/app/sonatapageblock/shared/1/edit', [], 'btn_update_and_list', []]; + yield 'Remove Shared Block' => ['/admin/tests/app/sonatapageblock/shared/1/delete', [], 'btn_delete']; + } + /** * @return class-string */ diff --git a/tests/Functional/Admin/SiteAdminTest.php b/tests/Functional/Admin/SiteAdminTest.php index 324435330..6a93d1817 100644 --- a/tests/Functional/Admin/SiteAdminTest.php +++ b/tests/Functional/Admin/SiteAdminTest.php @@ -52,6 +52,43 @@ public static function provideCrudUrlsCases(): iterable yield 'Snaphosts Site' => ['/admin/tests/app/sonatapagesite/1/snapshots']; } + /** + * @dataProvider provideFormUrlsCases + * + * @param array $parameters + * @param array $fieldValues + */ + public function testFormsUrls(string $url, array $parameters, string $button, array $fieldValues = []): void + { + $client = self::createClient(); + + $this->prepareData(); + + $client->request('GET', $url, $parameters); + $client->submitForm($button, $fieldValues); + $client->followRedirect(); + + self::assertResponseIsSuccessful(); + } + + /** + * @return iterable>> + * + * @phpstan-return iterable, 2: string, 3?: array}> + */ + public static function provideFormUrlsCases(): iterable + { + yield 'Create Site' => ['/admin/tests/app/sonatapagesite/create', [ + 'uniqid' => 'site', + ], 'btn_create_and_list', [ + 'site[name]' => 'Name', + 'site[host]' => 'localhost', + ]]; + + yield 'Edit Site' => ['/admin/tests/app/sonatapagesite/1/edit', [], 'btn_update_and_list', []]; + yield 'Remove Site' => ['/admin/tests/app/sonatapagesite/1/delete', [], 'btn_delete']; + } + /** * @return class-string */