From 4c7f0bb752ceccd68dc76b53733f4ffb431701da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Tue, 28 Jan 2020 19:53:51 +0100 Subject: [PATCH 01/20] Make sure all commands return integers This is forward-compatible with future versions of Symfony, and addresses some deprecations. --- src/Command/CreateClassCacheCommand.php | 2 ++ src/Command/ExplainAdminCommand.php | 2 ++ src/Command/GenerateObjectAclCommand.php | 6 ++++-- src/Command/ListAdminCommand.php | 2 ++ src/Command/SetupAclCommand.php | 2 ++ 5 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Command/CreateClassCacheCommand.php b/src/Command/CreateClassCacheCommand.php index 9f6b1d3b06..18e95a727d 100644 --- a/src/Command/CreateClassCacheCommand.php +++ b/src/Command/CreateClassCacheCommand.php @@ -79,5 +79,7 @@ public function execute(InputInterface $input, OutputInterface $output) ); $output->writeln(' done!'); + + return 0; } } diff --git a/src/Command/ExplainAdminCommand.php b/src/Command/ExplainAdminCommand.php index ce4e4d9f56..64b1e2149f 100644 --- a/src/Command/ExplainAdminCommand.php +++ b/src/Command/ExplainAdminCommand.php @@ -160,5 +160,7 @@ public function execute(InputInterface $input, OutputInterface $output) $output->writeln(''); $output->writeln('done!'); + + return 0; } } diff --git a/src/Command/GenerateObjectAclCommand.php b/src/Command/GenerateObjectAclCommand.php index 587f252f09..88219a9d6b 100644 --- a/src/Command/GenerateObjectAclCommand.php +++ b/src/Command/GenerateObjectAclCommand.php @@ -118,14 +118,14 @@ public function execute(InputInterface $input, OutputInterface $output) } catch (\Exception $e) { $output->writeln(sprintf('%s', $e->getMessage())); - return; + return 1; } } if (!$this->aclObjectManipulators) { $output->writeln('No manipulators are implemented : ignoring'); - return; + return 1; } foreach ($this->pool->getAdminServiceIds() as $id) { @@ -167,6 +167,8 @@ public function execute(InputInterface $input, OutputInterface $output) \assert($admin instanceof AdminInterface); $manipulator->batchConfigureAcls($output, $admin, $securityIdentity); } + + return 0; } /** diff --git a/src/Command/ListAdminCommand.php b/src/Command/ListAdminCommand.php index a74cb715a2..ce31a62345 100644 --- a/src/Command/ListAdminCommand.php +++ b/src/Command/ListAdminCommand.php @@ -54,5 +54,7 @@ public function execute(InputInterface $input, OutputInterface $output) $instance->getClass() )); } + + return 0; } } diff --git a/src/Command/SetupAclCommand.php b/src/Command/SetupAclCommand.php index 9a191846be..19a674bf63 100644 --- a/src/Command/SetupAclCommand.php +++ b/src/Command/SetupAclCommand.php @@ -69,5 +69,7 @@ public function execute(InputInterface $input, OutputInterface $output) \assert($admin instanceof AdminInterface); $this->aclManipulator->configureAcls($output, $admin); } + + return 0; } } From 498e10793e35ab76a82e80559cebf1752eb10083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Tue, 28 Jan 2020 19:57:31 +0100 Subject: [PATCH 02/20] Put method argument on its own line Not doing so is a PSR-2 violation. --- src/Command/ListAdminCommand.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Command/ListAdminCommand.php b/src/Command/ListAdminCommand.php index ce31a62345..1a15738d53 100644 --- a/src/Command/ListAdminCommand.php +++ b/src/Command/ListAdminCommand.php @@ -49,7 +49,8 @@ public function execute(InputInterface $input, OutputInterface $output) $output->writeln('Admin services:'); foreach ($this->pool->getAdminServiceIds() as $id) { $instance = $this->pool->getInstance($id); - $output->writeln(sprintf(' %-40s %-60s', + $output->writeln(sprintf( + ' %-40s %-60s', $id, $instance->getClass() )); From 369d85c617b535f82a18a8371f53c5ead21148c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Tue, 28 Jan 2020 20:07:20 +0100 Subject: [PATCH 03/20] Address deprecations from block bundle --- tests/Block/AdminListBlockServiceTest.php | 15 +++++++++++++-- tests/Block/AdminSearchBlockServiceTest.php | 21 +++++++++++++-------- tests/Block/AdminStatsBlockServiceTest.php | 7 ++++++- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/tests/Block/AdminListBlockServiceTest.php b/tests/Block/AdminListBlockServiceTest.php index 024fa25c3d..1ba550d929 100644 --- a/tests/Block/AdminListBlockServiceTest.php +++ b/tests/Block/AdminListBlockServiceTest.php @@ -18,6 +18,7 @@ use Sonata\AdminBundle\Templating\TemplateRegistryInterface; use Sonata\AdminBundle\Tests\Fixtures\Block\FakeBlockService; use Sonata\BlockBundle\Test\BlockServiceTestCase; +use Twig\Environment; /** * @author Sullivan Senechal @@ -45,7 +46,12 @@ protected function setUp(): void public function testDefaultSettings(): void { - $blockService = new AdminListBlockService('foo', $this->templating, $this->pool, $this->templateRegistry->reveal()); + $blockService = new AdminListBlockService( + $this->createMock(Environment::class), + null, + $this->pool, + $this->templateRegistry->reveal() + ); $blockContext = $this->getBlockContext($blockService); $this->assertSettings([ @@ -58,7 +64,12 @@ public function testDefaultSettings(): void */ public function testOverriddenDefaultSettings(): void { - $blockService = new FakeBlockService('foo', $this->templating, $this->pool, $this->templateRegistry->reveal()); + $blockService = new FakeBlockService( + $this->createMock(Environment::class), + null, + $this->pool, + $this->templateRegistry->reveal() + ); $blockContext = $this->getBlockContext($blockService); $this->assertSettings([ diff --git a/tests/Block/AdminSearchBlockServiceTest.php b/tests/Block/AdminSearchBlockServiceTest.php index 1d0263f6c2..02ca9d828a 100644 --- a/tests/Block/AdminSearchBlockServiceTest.php +++ b/tests/Block/AdminSearchBlockServiceTest.php @@ -18,8 +18,8 @@ use Sonata\AdminBundle\Block\AdminSearchBlockService; use Sonata\AdminBundle\Search\SearchHandler; use Sonata\BlockBundle\Test\BlockServiceTestCase; -use Sonata\BlockBundle\Test\FakeTemplating; use Symfony\Component\HttpFoundation\Response; +use Twig\Environment; /** * @author Sullivan Senechal @@ -46,7 +46,12 @@ protected function setUp(): void public function testDefaultSettings(): void { - $blockService = new AdminSearchBlockService('foo', $this->templating, $this->pool, $this->searchHandler); + $blockService = new AdminSearchBlockService( + $this->createMock(Environment::class), + null, + $this->pool, + $this->searchHandler + ); $blockContext = $this->getBlockContext($blockService); $this->assertSettings([ @@ -61,19 +66,19 @@ public function testDefaultSettings(): void public function testGlobalSearchReturnsEmptyWhenFiltersAreDisabled(): void { $admin = $this->getMockBuilder(AbstractAdmin::class)->disableOriginalConstructor()->getMock(); - $templating = $this->getMockBuilder(FakeTemplating::class)->disableOriginalConstructor()->getMock(); - $blockService = new AdminSearchBlockService('foo', $templating, $this->pool, $this->searchHandler); + $blockService = new AdminSearchBlockService( + $this->createMock(Environment::class), + null, + $this->pool, + $this->searchHandler + ); $blockContext = $this->getBlockContext($blockService); $this->searchHandler->expects(self::once())->method('search')->willReturn(false); $this->pool->expects(self::once())->method('getAdminByAdminCode')->willReturn($admin); $admin->expects(self::once())->method('checkAccess')->with('list')->willReturn(true); - // Make sure the template is never generated (empty response is required, - // but the FakeTemplate always returns an empty response) - $templating->expects(self::never())->method('renderResponse'); - $response = $blockService->execute($blockContext); static::assertSame('', $response->getContent()); diff --git a/tests/Block/AdminStatsBlockServiceTest.php b/tests/Block/AdminStatsBlockServiceTest.php index 4cac044133..3457be2f12 100644 --- a/tests/Block/AdminStatsBlockServiceTest.php +++ b/tests/Block/AdminStatsBlockServiceTest.php @@ -16,6 +16,7 @@ use Sonata\AdminBundle\Admin\Pool; use Sonata\AdminBundle\Block\AdminStatsBlockService; use Sonata\BlockBundle\Test\BlockServiceTestCase; +use Twig\Environment; /** * @author Sullivan Senechal @@ -36,7 +37,11 @@ protected function setUp(): void public function testDefaultSettings(): void { - $blockService = new AdminStatsBlockService('foo', $this->templating, $this->pool); + $blockService = new AdminStatsBlockService( + $this->createMock(Environment::class), + null, + $this->pool + ); $blockContext = $this->getBlockContext($blockService); $this->assertSettings([ From c7a4c0b849c7ed2bf5154a1df29d82337bd143a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Tue, 28 Jan 2020 20:07:31 +0100 Subject: [PATCH 04/20] Simplify mocking --- tests/Block/AdminListBlockServiceTest.php | 2 +- tests/Block/AdminSearchBlockServiceTest.php | 6 +++--- tests/Block/AdminStatsBlockServiceTest.php | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/Block/AdminListBlockServiceTest.php b/tests/Block/AdminListBlockServiceTest.php index 1ba550d929..f133251374 100644 --- a/tests/Block/AdminListBlockServiceTest.php +++ b/tests/Block/AdminListBlockServiceTest.php @@ -39,7 +39,7 @@ protected function setUp(): void { parent::setUp(); - $this->pool = $this->getMockBuilder(Pool::class)->disableOriginalConstructor()->getMock(); + $this->pool = $this->createMock(Pool::class); $this->templateRegistry = $this->prophesize(TemplateRegistryInterface::class); } diff --git a/tests/Block/AdminSearchBlockServiceTest.php b/tests/Block/AdminSearchBlockServiceTest.php index 02ca9d828a..651012ba06 100644 --- a/tests/Block/AdminSearchBlockServiceTest.php +++ b/tests/Block/AdminSearchBlockServiceTest.php @@ -40,8 +40,8 @@ protected function setUp(): void { parent::setUp(); - $this->pool = $this->getMockBuilder(Pool::class)->disableOriginalConstructor()->getMock(); - $this->searchHandler = $this->getMockBuilder(SearchHandler::class)->disableOriginalConstructor()->getMock(); + $this->pool = $this->createMock(Pool::class); + $this->searchHandler = $this->createMock(SearchHandler::class); } public function testDefaultSettings(): void @@ -65,7 +65,7 @@ public function testDefaultSettings(): void public function testGlobalSearchReturnsEmptyWhenFiltersAreDisabled(): void { - $admin = $this->getMockBuilder(AbstractAdmin::class)->disableOriginalConstructor()->getMock(); + $admin = $this->createMock(AbstractAdmin::class); $blockService = new AdminSearchBlockService( $this->createMock(Environment::class), diff --git a/tests/Block/AdminStatsBlockServiceTest.php b/tests/Block/AdminStatsBlockServiceTest.php index 3457be2f12..5bba916791 100644 --- a/tests/Block/AdminStatsBlockServiceTest.php +++ b/tests/Block/AdminStatsBlockServiceTest.php @@ -32,7 +32,7 @@ protected function setUp(): void { parent::setUp(); - $this->pool = $this->getMockBuilder(Pool::class)->disableOriginalConstructor()->getMock(); + $this->pool = $this->createMock(Pool::class); } public function testDefaultSettings(): void From 6f21cefc337807c84149f88bee302e14846e4e46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Tue, 28 Jan 2020 20:14:19 +0100 Subject: [PATCH 05/20] Address deprecations from the event dispatcher --- tests/Admin/Extension/LockExtensionTest.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/Admin/Extension/LockExtensionTest.php b/tests/Admin/Extension/LockExtensionTest.php index ef77363e9e..f3a0bf4a76 100644 --- a/tests/Admin/Extension/LockExtensionTest.php +++ b/tests/Admin/Extension/LockExtensionTest.php @@ -89,7 +89,7 @@ public function testConfigureFormFields(): void )->shouldBeCalled(); $this->lockExtension->configureFormFields($formMapper); - $this->eventDispatcher->dispatch(FormEvents::PRE_SET_DATA, $event); + $this->eventDispatcher->dispatch($event, FormEvents::PRE_SET_DATA); } public function testConfigureFormFieldsWhenModelManagerIsNotImplementingLockerInterface(): void @@ -103,7 +103,7 @@ public function testConfigureFormFieldsWhenModelManagerIsNotImplementingLockerIn $form->add()->shouldNotBeCalled(); $this->lockExtension->configureFormFields($formMapper); - $this->eventDispatcher->dispatch(FormEvents::PRE_SET_DATA, $event); + $this->eventDispatcher->dispatch($event, FormEvents::PRE_SET_DATA); } public function testConfigureFormFieldsWhenFormEventHasNoData(): void @@ -115,7 +115,7 @@ public function testConfigureFormFieldsWhenFormEventHasNoData(): void $form->add()->shouldNotBeCalled(); $this->lockExtension->configureFormFields($formMapper); - $this->eventDispatcher->dispatch(FormEvents::PRE_SET_DATA, $event); + $this->eventDispatcher->dispatch($event, FormEvents::PRE_SET_DATA); } public function testConfigureFormFieldsWhenFormHasParent(): void @@ -128,7 +128,7 @@ public function testConfigureFormFieldsWhenFormHasParent(): void $form->add()->shouldNotBeCalled(); $this->lockExtension->configureFormFields($formMapper); - $this->eventDispatcher->dispatch(FormEvents::PRE_SET_DATA, $event); + $this->eventDispatcher->dispatch($event, FormEvents::PRE_SET_DATA); } public function testConfigureFormFieldsWhenModelManagerHasNoLockedVersion(): void @@ -142,7 +142,7 @@ public function testConfigureFormFieldsWhenModelManagerHasNoLockedVersion(): voi $form->add()->shouldNotBeCalled(); $this->lockExtension->configureFormFields($formMapper); - $this->eventDispatcher->dispatch(FormEvents::PRE_SET_DATA, $event); + $this->eventDispatcher->dispatch($event, FormEvents::PRE_SET_DATA); } public function testPreUpdateIfAdminHasNoRequest(): void From d1adb1c01193a51c97d7af7a731fc55a00f56495 Mon Sep 17 00:00:00 2001 From: Christian Gripp Date: Wed, 29 Jan 2020 14:51:29 +0100 Subject: [PATCH 06/20] Add stale workflow --- .github/workflows/stale.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/stale.yml diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000000..7ab66d6de9 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,24 @@ +# https://github.com/actions/stale + +name: "Stale" + +on: + schedule: + - cron: "0 12 * * *" + +jobs: + stale: + runs-on: "ubuntu-latest" + + steps: + - name: "Close stale issues and pull requests" + uses: "actions/stale@v1.1.0" + with: + days-before-close: 7 + days-before-stale: 180 + repo-token: "${{ secrets.GITHUB_TOKEN }}" + stale-issue-label: "pending author" + stale-issue-message: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. From 2728a2fda0133a6972cf89a45ee29a8d8df5c4b8 Mon Sep 17 00:00:00 2001 From: Vincent Langlet Date: Sun, 12 Jan 2020 20:43:14 +0100 Subject: [PATCH 07/20] Add restore function --- src/Route/RouteCollection.php | 85 +++++++++++++++++++++++++++++------ 1 file changed, 72 insertions(+), 13 deletions(-) diff --git a/src/Route/RouteCollection.php b/src/Route/RouteCollection.php index c1cfef6bf5..c3c3893543 100644 --- a/src/Route/RouteCollection.php +++ b/src/Route/RouteCollection.php @@ -47,6 +47,11 @@ class RouteCollection */ protected $baseRoutePattern; + /** + * @var Route[] + */ + private $cachedElements = []; + /** * @param string $baseCodeRoute * @param string $baseRouteName @@ -101,10 +106,10 @@ public function add( $defaults['_sonata_name'] = $routeName; - $this->elements[$this->getCode($name)] = static function () use ( - $pattern, $defaults, $requirements, $options, $host, $schemes, $methods, $condition) { + $element = static function () use ($pattern, $defaults, $requirements, $options, $host, $schemes, $methods, $condition) { return new Route($pattern, $defaults, $requirements, $options, $host, $schemes, $methods, $condition); }; + $this->addElement($code, $element); return $this; } @@ -128,8 +133,8 @@ public function getCode($name) */ public function addCollection(self $collection) { - foreach ($collection->getElements() as $code => $route) { - $this->elements[$code] = $route; + foreach ($collection->getElements() as $code => $element) { + $this->addElement($code, $element); } return $this; @@ -140,8 +145,8 @@ public function addCollection(self $collection) */ public function getElements() { - foreach ($this->elements as $name => $element) { - $this->elements[$name] = $this->resolve($element); + foreach ($this->elements as $code => $element) { + $this->resolveElement($code); } return $this->elements; @@ -157,6 +162,16 @@ public function has($name) return \array_key_exists($this->getCode($name), $this->elements); } + /** + * @param string $name + * + * @return bool + */ + public function hasCached($name) + { + return \array_key_exists($this->getCode($name), $this->cachedElements); + } + /** * @param string $name * @@ -168,8 +183,7 @@ public function get($name) { if ($this->has($name)) { $code = $this->getCode($name); - - $this->elements[$code] = $this->resolve($this->elements[$code]); + $this->resolveElement($code); return $this->elements[$code]; } @@ -189,6 +203,25 @@ public function remove($name) return $this; } + /** + * @param string $name + * + * @throws \InvalidArgumentException + * + * @return RouteCollection + */ + public function restore($name) + { + if ($this->hasCached($name)) { + $code = $this->getCode($name); + $this->addElement($code, $this->cachedElements[$code]); + + return $this; + } + + throw new \InvalidArgumentException(sprintf('Element "%s" does not exist in cache.', $name)); + } + /** * Remove all routes except routes in $routeList. * @@ -208,9 +241,9 @@ public function clearExcept($routeList) } $elements = $this->elements; - foreach ($elements as $key => $element) { - if (!\in_array($key, $routeCodeList, true)) { - unset($this->elements[$key]); + foreach ($elements as $code => $element) { + if (!\in_array($code, $routeCodeList, true)) { + unset($this->elements[$code]); } } @@ -283,8 +316,34 @@ public function getBaseRoutePattern() return $this->baseRoutePattern; } - private function resolve($element): Route + /** + * @param string $code + * @param Route|callable $element + */ + protected function addElement($code, $element) + { + $this->elements[$code] = $element; + $this->updateCachedElement($code); + } + + /** + * @param string $code + */ + protected function updateCachedElement($code) + { + $this->cachedElements[$code] = $this->elements[$code]; + } + + /** + * @param string $code + */ + private function resolveElement($code) { - return \is_callable($element) ? $element() : $element; + $element = $this->elements[$code]; + + if (\is_callable($element)) { + $this->elements[$code] = $element(); + $this->updateCachedElement($code); + } } } From fdf95a89fabe5c62d2bc938d257c7a17d395fe3d Mon Sep 17 00:00:00 2001 From: Vincent Langlet Date: Sun, 12 Jan 2020 20:53:58 +0100 Subject: [PATCH 08/20] Add final and php7 type --- src/Route/RouteCollection.php | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/src/Route/RouteCollection.php b/src/Route/RouteCollection.php index c3c3893543..2e5e017a85 100644 --- a/src/Route/RouteCollection.php +++ b/src/Route/RouteCollection.php @@ -162,12 +162,7 @@ public function has($name) return \array_key_exists($this->getCode($name), $this->elements); } - /** - * @param string $name - * - * @return bool - */ - public function hasCached($name) + final public function hasCached(string $name): bool { return \array_key_exists($this->getCode($name), $this->cachedElements); } @@ -204,13 +199,9 @@ public function remove($name) } /** - * @param string $name - * * @throws \InvalidArgumentException - * - * @return RouteCollection */ - public function restore($name) + final public function restore(string $name): self { if ($this->hasCached($name)) { $code = $this->getCode($name); @@ -317,27 +308,20 @@ public function getBaseRoutePattern() } /** - * @param string $code * @param Route|callable $element */ - protected function addElement($code, $element) + final protected function addElement(string $code, $element): void { $this->elements[$code] = $element; $this->updateCachedElement($code); } - /** - * @param string $code - */ - protected function updateCachedElement($code) + final protected function updateCachedElement(string $code): void { $this->cachedElements[$code] = $this->elements[$code]; } - /** - * @param string $code - */ - private function resolveElement($code) + private function resolveElement(string $code): void { $element = $this->elements[$code]; From 749a4bfe6232413c1745194073d6886b8856e08a Mon Sep 17 00:00:00 2001 From: Vincent Langlet Date: Sun, 12 Jan 2020 21:39:21 +0100 Subject: [PATCH 09/20] Add tests --- tests/Route/RouteCollectionTest.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/Route/RouteCollectionTest.php b/tests/Route/RouteCollectionTest.php index 61763d273a..0a9db26a29 100644 --- a/tests/Route/RouteCollectionTest.php +++ b/tests/Route/RouteCollectionTest.php @@ -61,9 +61,15 @@ public function testCollection(): void $routeCollection->add('view'); $this->assertTrue($routeCollection->has('view')); + $this->assertTrue($routeCollection->hasCached('view')); $routeCollection->remove('view'); $this->assertFalse($routeCollection->has('view')); + $this->assertTrue($routeCollection->hasCached('view')); + + $routeCollection->restore('view'); + $this->assertTrue($routeCollection->has('view')); + $this->assertTrue($routeCollection->hasCached('view')); $routeCollection->add('create'); $route = $routeCollection->get('create'); From 66933dc1a1222581130602e397de84312d6ed1d4 Mon Sep 17 00:00:00 2001 From: Vincent Langlet Date: Wed, 29 Jan 2020 23:36:27 +0100 Subject: [PATCH 10/20] Add doc --- docs/reference/routing.rst | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/reference/routing.rst b/docs/reference/routing.rst index 31dd4fcb92..caddc62cfb 100644 --- a/docs/reference/routing.rst +++ b/docs/reference/routing.rst @@ -340,6 +340,24 @@ can use ``hasParentFieldDescription()`` to detect this case and remove the route } } +Restoring a single route +^^^^^^^^^^^^^^^^^^^^^^^^ + +Any previously removed route can be restored by name:: + + // src/Admin/DeletableMediaAdmin.php + + use Sonata\AdminBundle\Route\RouteCollection; + + final class DeletableMediaAdmin extends MediaAdmin + { + protected function configureRoutes(RouteCollection $collection) + { + $collection->restore('delete'); + } + } + + Persistent parameters --------------------- From 7f3919315dcaa5491a64eaa7381ba5d0a53adf8f Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Mon, 29 Apr 2019 10:57:05 +0200 Subject: [PATCH 11/20] added DOCtor-RST for linintg the docs --- .github/workflows/lint.yaml | 14 ++++++++++++++ docs/.doctor-rst.yaml | 30 ++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 .github/workflows/lint.yaml create mode 100644 docs/.doctor-rst.yaml diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml new file mode 100644 index 0000000000..a441c78f1a --- /dev/null +++ b/.github/workflows/lint.yaml @@ -0,0 +1,14 @@ +on: [push, pull_request] +name: Lint +jobs: + doctor-rst: + name: DOCtor-RST + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: DOCtor-RST + uses: docker://oskarstark/doctor-rst + with: + args: --short + env: + DOCS_DIR: 'docs/' diff --git a/docs/.doctor-rst.yaml b/docs/.doctor-rst.yaml new file mode 100644 index 0000000000..3bdb7122f3 --- /dev/null +++ b/docs/.doctor-rst.yaml @@ -0,0 +1,30 @@ +rules: + blank_line_after_directive: ~ + short_array_syntax: ~ + no_app_console: ~ + typo: ~ + replacement: ~ + composer_dev_option_at_the_end: ~ + yarn_dev_option_at_the_end: ~ + versionadded_directive_should_have_version: ~ + no_composer_req: ~ + no_php_open_tag_in_code_block_php_directive: ~ + blank_line_after_filepath_in_code_block: ~ + no_php_prefix_before_bin_console: ~ + use_deprecated_directive_instead_of_versionadded: ~ + no_space_before_self_xml_closing_tag: ~ + no_explicit_use_of_code_block_php: ~ + ensure_order_of_code_blocks_in_configuration_block: ~ + american_english: ~ + valid_use_statements: ~ + yaml_instead_of_yml_suffix: ~ + extend_abstract_admin: ~ + final_admin_class: ~ + final_admin_extension_classes: ~ + kernel_instead_of_app_kernel: ~ + no_admin_yaml: ~ + no_app_bundle: ~ + no_bash_prompt: ~ + no_composer_phar: ~ + no_config_yaml: ~ + no_inheritdoc: ~ From b2ff6c6f9fd2107832ad9cf0dd1a460d5c631890 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Thu, 30 Jan 2020 12:15:25 +0100 Subject: [PATCH 12/20] Fix: Errors reported by DOCtor-RST --- docs/cookbook/recipe_lock_protection.rst | 14 ++--- .../recipe_sortable_sonata_type_model.rst | 6 +-- docs/getting_started/the_form_view.rst | 12 ++--- docs/reference/action_create_edit.rst | 52 +++++++++---------- docs/reference/batch_actions.rst | 12 ++--- docs/reference/field_types.rst | 4 +- docs/reference/translation.rst | 4 +- 7 files changed, 47 insertions(+), 57 deletions(-) diff --git a/docs/cookbook/recipe_lock_protection.rst b/docs/cookbook/recipe_lock_protection.rst index 9735c9b4be..2eda1ada6b 100644 --- a/docs/cookbook/recipe_lock_protection.rst +++ b/docs/cookbook/recipe_lock_protection.rst @@ -29,7 +29,7 @@ You can enable it in your ``sonata_admin`` configuration: sonata_admin: options: lock_protection: true - + You must also configure each entity that you want to support by adding a field called ``$version`` on which the Doctrine ``Version`` feature is activated. @@ -38,19 +38,19 @@ Using Annotations:: // src/Entity/Car.php namespace App\Entity\Car; - + use Doctrine\ORM\Mapping as ORM; class Car { // ... - + /** * @ORM\Column(type="integer") * @ORM\Version */ protected $version; - + // ... } @@ -58,14 +58,14 @@ Using XML: .. code-block:: xml - + - + - + diff --git a/docs/cookbook/recipe_sortable_sonata_type_model.rst b/docs/cookbook/recipe_sortable_sonata_type_model.rst index 9175103632..0ca43e5fde 100644 --- a/docs/cookbook/recipe_sortable_sonata_type_model.rst +++ b/docs/cookbook/recipe_sortable_sonata_type_model.rst @@ -66,7 +66,7 @@ We now need to create the join entity configuration, create the following file i .. code-block:: xml - + @@ -288,9 +288,7 @@ Part 3 : Update admin classes ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This is a very important part, the admin class **should** be created for the join entity. If you don't do that, the field will never display properly. -So we are going to start by creating this ``UserBundle\Admin\UserHasExpectationsAdmin.php`` ... - -.. code-block:: php +So we are going to start by creating this ``UserBundle\Admin\UserHasExpectationsAdmin.php``:: namespace UserBundle\Admin; diff --git a/docs/getting_started/the_form_view.rst b/docs/getting_started/the_form_view.rst index 87ee21ebbe..bcc413f7c6 100644 --- a/docs/getting_started/the_form_view.rst +++ b/docs/getting_started/the_form_view.rst @@ -233,13 +233,7 @@ While it's very friendly of the SonataAdminBundle to notify the admin of a successful creation, the classname and some sort of hash aren't really nice to read. This is the default string representation of an object in the SonataAdminBundle. You can change it by defining a ``toString()`` method in the -Admin class. This receives the object to transform to a string as the first parameter: - -.. note:: - - No underscore prefix! ``toString()`` is correct! - -.. code-block:: php +Admin class. This receives the object to transform to a string as the first parameter:: // src/Admin/BlogPostAdmin.php @@ -255,6 +249,10 @@ Admin class. This receives the object to transform to a string as the first para } } +.. note:: + + No underscore prefix! ``toString()`` is correct! + Round Up -------- diff --git a/docs/reference/action_create_edit.rst b/docs/reference/action_create_edit.rst index 5bdeee7f46..6ab876028e 100644 --- a/docs/reference/action_create_edit.rst +++ b/docs/reference/action_create_edit.rst @@ -36,7 +36,7 @@ For more information about optional libraries: .. note:: - **TODO**: + **TODO** * options available when adding fields, inc custom templates Routes @@ -64,32 +64,11 @@ For more detailed information about routes, see :doc:`routing`:: Adding form fields ------------------ -Within the configureFormFields method you can define which fields should -be shown when editing or creating entities. -Each field has to be added to a specific form group. And form groups can -optionally be added to a tab. See `FormGroup options`_ for additional -information about configuring form groups. - -Using the FormMapper add method, you can add form fields. The add method -has 4 parameters: - -- ``name``: The name of your entity. -- ``type``: The type of field to show; by defaults this is ``null`` to let - Sonata decide which type to use. See :doc:`Field Types ` - for more information on available types. -- ``options``: The form options to be used for the field. These may differ - per type. See :doc:`Field Types ` for more information on - available options. -- ``fieldDescriptionOptions``: The field description options. Options here - are passed through to the field template. See :ref:`Form Types, FieldDescription - options ` for more information. - -.. note:: - - The property entered in ``name`` should be available in your Entity - through getters/setters or public access. - -.. code-block:: php +Within the ``configureFormFields`` method you can define which fields should +be shown when editing or creating entities. Each field has to be added to a +specific form group. And form groups can optionally be added to a tab. +See `FormGroup options`_ for additional information about configuring form +groups:: // src/Admin/PersonAdmin.php @@ -110,6 +89,25 @@ has 4 parameters: } } +Using the FormMapper add method, you can add form fields. The add method +has 4 parameters: + +- ``name``: The name of your entity. +- ``type``: The type of field to show; by defaults this is ``null`` to let + Sonata decide which type to use. See :doc:`Field Types ` + for more information on available types. +- ``options``: The form options to be used for the field. These may differ + per type. See :doc:`Field Types ` for more information on + available options. +- ``fieldDescriptionOptions``: The field description options. Options here + are passed through to the field template. See :ref:`Form Types, FieldDescription + options ` for more information. + +.. note:: + + The property entered in ``name`` should be available in your Entity + through getters/setters or public access. + FormGroup options ~~~~~~~~~~~~~~~~~ diff --git a/docs/reference/batch_actions.rst b/docs/reference/batch_actions.rst index 4473e3cfd0..ae7ac7f60f 100644 --- a/docs/reference/batch_actions.rst +++ b/docs/reference/batch_actions.rst @@ -50,13 +50,7 @@ The method ``batchAction`` will be executed to process your batch in y objects are passed to this method through a query argument which can be used to retrieve them. If for some reason it makes sense to perform your batch action without the default selection method (for example you defined another way, at template level, to select model at a lower -granularity), the passed query is ``null``. - -.. note:: - - You can check how to declare your own ``CRUDController`` class in the Architecture section. - -.. code-block:: php +granularity), the passed query is ``null``:: // src/Controller/CRUDController.php @@ -127,6 +121,10 @@ granularity), the passed query is ``null``. // ... } +.. note:: + + You can check how to declare your own ``CRUDController`` class in the Architecture section. + (Optional) Overriding the batch selection template -------------------------------------------------- diff --git a/docs/reference/field_types.rst b/docs/reference/field_types.rst index 780aa93612..36df1a4972 100644 --- a/docs/reference/field_types.rst +++ b/docs/reference/field_types.rst @@ -91,9 +91,7 @@ Parameter Description ; } -The ``choice`` field type also supports multiple values that can be separated by a ``delimiter``. - -.. code-block:: php +The ``choice`` field type also supports multiple values that can be separated by a ``delimiter``:: protected function configureListFields(ListMapper $listMapper) { diff --git a/docs/reference/translation.rst b/docs/reference/translation.rst index dfef10779d..32c1ee3862 100644 --- a/docs/reference/translation.rst +++ b/docs/reference/translation.rst @@ -148,8 +148,8 @@ The ``AdminBundle`` comes with different key label generation strategies: ``sonata.admin.label.strategy.underscore`` will be better for i18n applications and ``sonata.admin.label.strategy.native`` will be better for native (single) language -apps based on the field name. It is reasonable to start with the ``native`` strategy -and then, when the application needs to be translated using generic keys, the +applications based on the field name. It is reasonable to start with the ``native`` +strategy and then, when the application needs to be translated using generic keys, the configuration can be switched to ``underscore``. The strategy can be quickly configured when the Admin class is registered in From a9695005f3befa1a8f53c32f139933240f0ad7d2 Mon Sep 17 00:00:00 2001 From: SonataCI Date: Sat, 25 Jan 2020 02:05:09 +0100 Subject: [PATCH 13/20] DevKit updates --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9b975d1233..dd04ce016b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,7 +45,7 @@ matrix: - php: '7.2' env: COMPOSER_FLAGS="--prefer-lowest" - php: '7.3' - env: SYMFONY=4.4.* + env: SYMFONY=3.4.* - php: '7.3' env: SYMFONY='dev-master as 3.4.x-dev' - php: '7.3' From 840f024e414344a72c771bde0cf6987efc997bf3 Mon Sep 17 00:00:00 2001 From: SonataCI Date: Thu, 30 Jan 2020 02:05:08 +0100 Subject: [PATCH 14/20] DevKit updates --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index dd04ce016b..4de1eafb90 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,7 +33,7 @@ env: - SYMFONY_DEPRECATIONS_HELPER=max[self]=0 - TARGET=test - UPSTREAM_URL=https://github.com/sonata-project/SonataAdminBundle.git - - PHPUNIT_VERSION=7 + - PHPUNIT_VERSION=8 matrix: fast_finish: true @@ -45,9 +45,9 @@ matrix: - php: '7.2' env: COMPOSER_FLAGS="--prefer-lowest" - php: '7.3' - env: SYMFONY=3.4.* + env: SYMFONY=4.4.* - php: '7.3' - env: SYMFONY='dev-master as 3.4.x-dev' + env: SYMFONY='dev-master as 4.4.x-dev' - php: '7.3' env: SONATA_CORE=3.* - php: '7.3' @@ -62,7 +62,7 @@ matrix: - php: 7.4snapshot - php: nightly - env: SYMFONY_DEPRECATIONS_HELPER=0 - - env: SYMFONY='dev-master as 3.4.x-dev' + - env: SYMFONY='dev-master as 4.4.x-dev' - env: SONATA_CORE='dev-master as 3.x-dev' - env: SONATA_BLOCK='dev-master as 3.x-dev' From b445684ef7c334bce0c4ec37316d5bec9ce04f8d Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Thu, 30 Jan 2020 14:42:33 +0100 Subject: [PATCH 15/20] Bump SonataCoreBundle and symfony-dependency-injection-test --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index fdc9af2dd2..99ec7264ad 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "doctrine/inflector": "^1.1", "knplabs/knp-menu-bundle": "^2.2.2", "sonata-project/block-bundle": "^3.18", - "sonata-project/core-bundle": "^3.17.0", + "sonata-project/core-bundle": "^3.18.0", "sonata-project/exporter": "^1.11.0 || ^2.0", "symfony/asset": "^4.3", "symfony/config": "^4.3", @@ -65,7 +65,7 @@ }, "require-dev": { "jms/translation-bundle": "^1.4", - "matthiasnoback/symfony-dependency-injection-test": "^3.1", + "matthiasnoback/symfony-dependency-injection-test": "^4.1", "sonata-project/intl-bundle": "^2.4", "symfony/browser-kit": "^4.3", "symfony/css-selector": "^4.3", From 926d52a02b1d34f71a7a0cf1120ed95e040cf623 Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Thu, 30 Jan 2020 15:15:14 +0100 Subject: [PATCH 16/20] Fix some tests type arguments --- tests/Controller/CRUDControllerTest.php | 5 +++-- tests/Mapper/BaseGroupedMapperTest.php | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/Controller/CRUDControllerTest.php b/tests/Controller/CRUDControllerTest.php index 3f002a9b53..aa7dec150d 100644 --- a/tests/Controller/CRUDControllerTest.php +++ b/tests/Controller/CRUDControllerTest.php @@ -58,6 +58,7 @@ use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\KernelInterface; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Component\Security\Csrf\CsrfToken; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; @@ -375,7 +376,7 @@ protected function setUp(): void ->method('generateUrl') ->willReturnCallback( - static function ($name, array $parameters = [], $absolute = false) { + static function ($name, array $parameters = []) { $result = $name; if (!empty($parameters)) { $result .= '?'.http_build_query($parameters); @@ -390,7 +391,7 @@ static function ($name, array $parameters = [], $absolute = false) { ->method('generateObjectUrl') ->willReturnCallback( - static function (string $name, $object, array $parameters = [], bool $absolute = false): string { + static function (string $name, $object, array $parameters = []): string { $result = \get_class($object).'_'.$name; if (!empty($parameters)) { $result .= '?'.http_build_query($parameters); diff --git a/tests/Mapper/BaseGroupedMapperTest.php b/tests/Mapper/BaseGroupedMapperTest.php index 1ec6edf8d6..8776834de8 100644 --- a/tests/Mapper/BaseGroupedMapperTest.php +++ b/tests/Mapper/BaseGroupedMapperTest.php @@ -203,7 +203,7 @@ public function testEndException(): void $this->baseGroupedMapper->end(); } - public function labelDataProvider() + public function labelDataProvider(): array { return [ 'nominal use case not translated' => [false, 'fooGroup1', null, 'fooGroup1'], @@ -216,7 +216,7 @@ public function labelDataProvider() /** * @dataProvider labelDataProvider */ - public function testLabel(string $translated, string $name, ?string $label, string $expectedLabel): void + public function testLabel(bool $translated, string $name, ?string $label, string $expectedLabel): void { $container = $this->baseGroupedMapper ->getAdmin() From 69e45dc5d48fedab063d7ae901e1a0cd224e5eca Mon Sep 17 00:00:00 2001 From: Sullivan SENECHAL Date: Thu, 30 Jan 2020 15:16:52 +0100 Subject: [PATCH 17/20] Applied fixes from FlintCI (#5856) --- tests/Controller/CRUDControllerTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Controller/CRUDControllerTest.php b/tests/Controller/CRUDControllerTest.php index aa7dec150d..1b475fcaf5 100644 --- a/tests/Controller/CRUDControllerTest.php +++ b/tests/Controller/CRUDControllerTest.php @@ -58,7 +58,6 @@ use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\KernelInterface; -use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Component\Security\Csrf\CsrfToken; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; From a3ea4708c78db0daf7447422938ed6447f31eacd Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Thu, 30 Jan 2020 14:35:29 +0100 Subject: [PATCH 18/20] Remove use of transchoice in twig --- src/Resources/views/Block/block_stats.html.twig | 4 +--- src/Resources/views/CRUD/batch_confirmation.html.twig | 4 +--- src/Resources/views/Pager/base_results.html.twig | 4 +--- src/Resources/views/Pager/simple_pager_results.html.twig | 4 +--- 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/Resources/views/Block/block_stats.html.twig b/src/Resources/views/Block/block_stats.html.twig index dd1303d3a2..9a59c1f73f 100644 --- a/src/Resources/views/Block/block_stats.html.twig +++ b/src/Resources/views/Block/block_stats.html.twig @@ -20,9 +20,7 @@ file that was distributed with this source code.

{{ pager.count() }}

{% if translation_domain %} - {{ settings.text|transchoice(pager.count(), {}, translation_domain) }} - {# NEXT_MAJOR: bump "symfony/translation" to ^4.2 and replace the previous line with the following #} - {# {{ settings.text|trans({'%count%': pager.count()}, translation_domain) }} #} + {{ settings.text|trans({'%count%': pager.count()}, translation_domain) }} {% else %} {{ settings.text }} {% endif %} diff --git a/src/Resources/views/CRUD/batch_confirmation.html.twig b/src/Resources/views/CRUD/batch_confirmation.html.twig index e8cfcade03..d1c8d13688 100644 --- a/src/Resources/views/CRUD/batch_confirmation.html.twig +++ b/src/Resources/views/CRUD/batch_confirmation.html.twig @@ -35,9 +35,7 @@ file that was distributed with this source code. {% if data.all_elements %} {{ 'message_batch_all_confirmation'|trans({}, 'SonataAdminBundle') }} {% else %} - {% transchoice data.idx|length with {'%count%': data.idx|length} from 'SonataAdminBundle' %}message_batch_confirmation{% endtranschoice %} - {# NEXT_MAJOR: bump "symfony/translation" to ^4.2 and replace the previous line with the following #} - {# {% trans with {'%count%': data.idx|length} from 'SonataAdminBundle' %}message_batch_confirmation{% endtrans %} #} + {% trans with {'%count%': data.idx|length} from 'SonataAdminBundle' %}message_batch_confirmation{% endtrans %} {% endif %}