From 9c7fa4e80200b72056f855735b7a0e7a9cbdd296 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Sat, 9 Jun 2018 20:26:42 +0200 Subject: [PATCH] Make CoreController actions CaaSes --- src/Controller/CoreController.php | 75 ++--------- src/Controller/DashboardAction.php | 82 ++++++++++++ src/Controller/SearchAction.php | 116 ++++++++++++++++ src/Resources/config/controllers.xml | 17 +++ src/Resources/config/routing/sonata_admin.xml | 4 +- tests/Controller/CoreControllerTest.php | 69 ++++------ tests/Controller/DashboardActionTest.php | 124 ++++++++++++++++++ 7 files changed, 374 insertions(+), 113 deletions(-) create mode 100644 src/Controller/DashboardAction.php create mode 100644 src/Controller/SearchAction.php create mode 100644 src/Resources/config/controllers.xml create mode 100644 tests/Controller/DashboardActionTest.php diff --git a/src/Controller/CoreController.php b/src/Controller/CoreController.php index bf7be53c772..468682c969a 100644 --- a/src/Controller/CoreController.php +++ b/src/Controller/CoreController.php @@ -11,12 +11,16 @@ namespace Sonata\AdminBundle\Controller; -use Sonata\AdminBundle\Admin\AdminInterface; +@trigger_error( + 'The '.__NAMESPACE__.'\CoreController class is deprecated since version 3.x and will be removed in 4.0.' + .' Use '.__NAMESPACE__.'\SearchAction or '.__NAMESPACE__.'\DashboardAction instead.', + E_USER_DEPRECATED +); + use Sonata\AdminBundle\Admin\Pool; use Sonata\AdminBundle\Search\SearchHandler; use Sonata\AdminBundle\Templating\TemplateRegistryInterface; use Symfony\Bundle\FrameworkBundle\Controller\Controller; -use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -31,29 +35,7 @@ class CoreController extends Controller */ public function dashboardAction() { - $blocks = [ - 'top' => [], - 'left' => [], - 'center' => [], - 'right' => [], - 'bottom' => [], - ]; - - foreach ($this->container->getParameter('sonata.admin.configuration.dashboard_blocks') as $block) { - $blocks[$block['position']][] = $block; - } - - $parameters = [ - 'base_template' => $this->getBaseTemplate(), - 'admin_pool' => $this->container->get('sonata.admin.pool'), - 'blocks' => $blocks, - ]; - - if (!$this->getCurrentRequest()->isXmlHttpRequest()) { - $parameters['breadcrumbs_builder'] = $this->get('sonata.admin.breadcrumbs_builder'); - } - - return $this->render($this->getTemplateRegistry()->getTemplate('dashboard'), $parameters); + return $this->container->get(DashboardAction::class)($this->getCurrentRequest()); } /** @@ -66,48 +48,7 @@ public function dashboardAction() */ public function searchAction(Request $request) { - if ($request->get('admin') && $request->isXmlHttpRequest()) { - try { - $admin = $this->getAdminPool()->getAdminByAdminCode($request->get('admin')); - } catch (ServiceNotFoundException $e) { - throw new \RuntimeException('Unable to find the Admin instance', $e->getCode(), $e); - } - - if (!$admin instanceof AdminInterface) { - throw new \RuntimeException('The requested service is not an Admin instance'); - } - - $handler = $this->getSearchHandler(); - - $results = []; - - if ($pager = $handler->search($admin, $request->get('q'), $request->get('page'), $request->get('offset'))) { - foreach ($pager->getResults() as $result) { - $results[] = [ - 'label' => $admin->toString($result), - 'link' => $admin->generateObjectUrl('edit', $result), - 'id' => $admin->id($result), - ]; - } - } - - $response = new JsonResponse([ - 'results' => $results, - 'page' => $pager ? (int) $pager->getPage() : false, - 'total' => $pager ? (int) $pager->getNbResults() : false, - ]); - $response->setPrivate(); - - return $response; - } - - return $this->render($this->getTemplateRegistry()->getTemplate('search'), [ - 'base_template' => $this->getBaseTemplate(), - 'breadcrumbs_builder' => $this->get('sonata.admin.breadcrumbs_builder'), - 'admin_pool' => $this->container->get('sonata.admin.pool'), - 'query' => $request->get('q'), - 'groups' => $this->getAdminPool()->getDashboardGroups(), - ]); + return $this->container->get(SearchAction::class)($request); } /** diff --git a/src/Controller/DashboardAction.php b/src/Controller/DashboardAction.php new file mode 100644 index 00000000000..7bb288732ba --- /dev/null +++ b/src/Controller/DashboardAction.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\AdminBundle\Controller; + +use Sonata\AdminBundle\Admin\BreadcrumbsBuilderInterface; +use Sonata\AdminBundle\Admin\Pool; +use Sonata\AdminBundle\Templating\TemplateRegistryInterface; +use Symfony\Bundle\FrameworkBundle\Controller\Controller; +use Symfony\Component\HttpFoundation\Request; + +final class DashboardAction extends Controller +{ + /** + * @var array + */ + private $dashboardBlocks; + + /** + * @var BreadcrumbsBuilderInterface + */ + private $breadcrumbsBuilder; + + /** + * @var TemplateRegistryInterface + */ + private $templateRegistry; + + /** + * @var Pool + */ + private $pool; + + public function __construct( + array $dashboardBlocks, + BreadcrumbsBuilderInterface $breadcrumbsBuilder, + TemplateRegistryInterface $templateRegistry, + Pool $pool + ) { + $this->dashboardBlocks = $dashboardBlocks; + $this->breadcrumbsBuilder = $breadcrumbsBuilder; + $this->templateRegistry = $templateRegistry; + $this->pool = $pool; + } + + public function __invoke(Request $request) + { + $blocks = [ + 'top' => [], + 'left' => [], + 'center' => [], + 'right' => [], + 'bottom' => [], + ]; + + foreach ($this->dashboardBlocks as $block) { + $blocks[$block['position']][] = $block; + } + + $parameters = [ + 'base_template' => $request->isXmlHttpRequest() ? + $this->templateRegistry->getTemplate('ajax') : + $this->templateRegistry->getTemplate('layout'), + 'admin_pool' => $this->pool, + 'blocks' => $blocks, + ]; + + if (!$request->isXmlHttpRequest()) { + $parameters['breadcrumbs_builder'] = $this->breadcrumbsBuilder; + } + + return $this->render($this->templateRegistry->getTemplate('dashboard'), $parameters); + } +} diff --git a/src/Controller/SearchAction.php b/src/Controller/SearchAction.php new file mode 100644 index 00000000000..21c3b99425f --- /dev/null +++ b/src/Controller/SearchAction.php @@ -0,0 +1,116 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\AdminBundle\Controller; + +use Sonata\AdminBundle\Admin\AdminInterface; +use Sonata\AdminBundle\Admin\BreadcrumbsBuilderInterface; +use Sonata\AdminBundle\Admin\Pool; +use Sonata\AdminBundle\Search\SearchHandler; +use Sonata\AdminBundle\Templating\TemplateRegistryInterface; +use Symfony\Bundle\FrameworkBundle\Controller\Controller; +use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; +use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\Request; + +final class SearchAction extends Controller +{ + /** + * @var Pool + */ + private $pool; + + /** + * @var SearchHandler + */ + private $searchHandler; + + /** + * @var TemplateRegistryInterface + */ + private $templateRegistry; + + /** + * @var BreadcrumbsBuilderInterface + */ + private $breadcrumbsBuilder; + + public function __construct( + Pool $pool, + SearchHandler $searchHandler, + TemplateRegistryInterface $templateRegistry, + BreadcrumbsBuilderInterface $breadcrumbsBuilder + ) { + $this->pool = $pool; + $this->searchHandler = $searchHandler; + $this->templateRegistry = $templateRegistry; + $this->breadcrumbsBuilder = $breadcrumbsBuilder; + } + + /** + * The search action first render an empty page, if the query is set, then the template generates + * some ajax request to retrieve results for each admin. The Ajax query returns a JSON response. + * + * @throws \RuntimeException + * + * @return JsonResponse|Response + */ + public function __invoke(Request $request) + { + if ($request->get('admin') && $request->isXmlHttpRequest()) { + try { + $admin = $this->pool->getAdminByAdminCode($request->get('admin')); + } catch (ServiceNotFoundException $e) { + throw new \RuntimeException('Unable to find the Admin instance', $e->getCode(), $e); + } + + if (!$admin instanceof AdminInterface) { + throw new \RuntimeException('The requested service is not an Admin instance'); + } + + $results = []; + + if ($pager = $this->searchHandler->search( + $admin, + $request->get('q'), + $request->get('page'), + $request->get('offset') + )) { + foreach ($pager->getResults() as $result) { + $results[] = [ + 'label' => $admin->toString($result), + 'link' => $admin->generateObjectUrl('edit', $result), + 'id' => $admin->id($result), + ]; + } + } + + $response = new JsonResponse([ + 'results' => $results, + 'page' => $pager ? (int) $pager->getPage() : false, + 'total' => $pager ? (int) $pager->getNbResults() : false, + ]); + $response->setPrivate(); + + return $response; + } + + return $this->render($this->templateRegistry->getTemplate('search'), [ + 'base_template' => $request->isXmlHttpRequest() ? + $this->templateRegistry->getTemplate('ajax') : + $this->templateRegistry->getTemplate('layout'), + 'breadcrumbs_builder' => $this->breadcrumbsBuilder, + 'admin_pool' => $this->pool, + 'query' => $request->get('q'), + 'groups' => $this->pool->getDashboardGroups(), + ]); + } +} diff --git a/src/Resources/config/controllers.xml b/src/Resources/config/controllers.xml new file mode 100644 index 00000000000..60569abd875 --- /dev/null +++ b/src/Resources/config/controllers.xml @@ -0,0 +1,17 @@ + + + + + %sonata.admin.configuration.dashboard_blocks% + + + + + + + + + + + + diff --git a/src/Resources/config/routing/sonata_admin.xml b/src/Resources/config/routing/sonata_admin.xml index 6cb78f08b1c..d5da7bdfba4 100644 --- a/src/Resources/config/routing/sonata_admin.xml +++ b/src/Resources/config/routing/sonata_admin.xml @@ -6,7 +6,7 @@ true - SonataAdminBundle:Core:dashboard + Sonata\AdminBundle\Controller\DashboardAction sonata.admin.controller.admin:retrieveFormFieldElementAction @@ -23,7 +23,7 @@ sonata.admin.controller.admin:setObjectFieldValueAction - SonataAdminBundle:Core:search + Sonata\AdminBundle\Controller\SearchAction sonata.admin.controller.admin:retrieveAutocompleteItemsAction diff --git a/tests/Controller/CoreControllerTest.php b/tests/Controller/CoreControllerTest.php index 7be1d15e4e2..4b74228c835 100644 --- a/tests/Controller/CoreControllerTest.php +++ b/tests/Controller/CoreControllerTest.php @@ -15,6 +15,7 @@ use Sonata\AdminBundle\Admin\BreadcrumbsBuilderInterface; use Sonata\AdminBundle\Admin\Pool; use Sonata\AdminBundle\Controller\CoreController; +use Sonata\AdminBundle\Controller\DashboardAction; use Sonata\AdminBundle\Templating\MutableTemplateRegistryInterface; use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -24,6 +25,9 @@ class CoreControllerTest extends TestCase { + /** + * @group legacy + */ public function testdashboardActionStandardRequest() { $container = $this->createMock(ContainerInterface::class); @@ -45,12 +49,16 @@ public function testdashboardActionStandardRequest() $breadcrumbsBuilder = $this->getMockForAbstractClass(BreadcrumbsBuilderInterface::class); $values = [ - 'sonata.admin.breadcrumbs_builder' => $breadcrumbsBuilder, - 'sonata.admin.pool' => $pool, + DashboardAction::class => $dashboardAction = new DashboardAction( + [], + $breadcrumbsBuilder, + $templateRegistry->reveal(), + $pool + ), 'templating' => $templating, 'request_stack' => $requestStack, - 'sonata.admin.global_template_registry' => $templateRegistry->reveal(), ]; + $dashboardAction->setContainer($container); $container->expects($this->any())->method('get')->will($this->returnCallback(function ($id) use ($values) { return $values[$id]; @@ -59,34 +67,18 @@ public function testdashboardActionStandardRequest() $container->expects($this->any()) ->method('has') ->will($this->returnCallback(function ($id) { - if ('templating' == $id) { - return true; - } - - return false; + return 'templating' === $id; })); - $container->expects($this->any())->method('getParameter')->will($this->returnCallback(function ($name) { - if ('sonata.admin.configuration.dashboard_blocks' == $name) { - return []; - } - })); - $container->expects($this->any())->method('has')->will($this->returnCallback(function ($id) { - if ('templating' == $id) { - return true; - } - - return false; - })); - $controller = new CoreController(); $controller->setContainer($container); - $response = $controller->dashboardAction($request); - - $this->isInstanceOf(Response::class, $response); + $this->isInstanceOf(Response::class, $controller->dashboardAction()); } + /** + * @group legacy + */ public function testdashboardActionAjaxLayout() { $container = $this->createMock(ContainerInterface::class); @@ -95,6 +87,7 @@ public function testdashboardActionAjaxLayout() $templateRegistry->getTemplate('ajax')->willReturn('ajax.html'); $templateRegistry->getTemplate('dashboard')->willReturn('dashboard.html'); $templateRegistry->getTemplate('layout')->willReturn('layout.html'); + $breadcrumbsBuilder = $this->getMockForAbstractClass(BreadcrumbsBuilderInterface::class); $pool = new Pool($container, 'title', 'logo.png'); $pool->setTemplateRegistry($templateRegistry->reveal()); @@ -107,11 +100,16 @@ public function testdashboardActionAjaxLayout() $requestStack->push($request); $values = [ - 'sonata.admin.pool' => $pool, + DashboardAction::class => $dashboardAction = new DashboardAction( + [], + $breadcrumbsBuilder, + $templateRegistry->reveal(), + $pool + ), 'templating' => $templating, 'request_stack' => $requestStack, - 'sonata.admin.global_template_registry' => $templateRegistry->reveal(), ]; + $dashboardAction->setContainer($container); $container->expects($this->any())->method('get')->will($this->returnCallback(function ($id) use ($values) { return $values[$id]; @@ -120,26 +118,9 @@ public function testdashboardActionAjaxLayout() $container->expects($this->any()) ->method('has') ->will($this->returnCallback(function ($id) { - if ('templating' == $id) { - return true; - } - - return false; + return 'templating' === $id; })); - $container->expects($this->any())->method('getParameter')->will($this->returnCallback(function ($name) { - if ('sonata.admin.configuration.dashboard_blocks' == $name) { - return []; - } - })); - $container->expects($this->any())->method('has')->will($this->returnCallback(function ($id) { - if ('templating' == $id) { - return true; - } - - return false; - })); - $controller = new CoreController(); $controller->setContainer($container); diff --git a/tests/Controller/DashboardActionTest.php b/tests/Controller/DashboardActionTest.php new file mode 100644 index 00000000000..c7a98f59a30 --- /dev/null +++ b/tests/Controller/DashboardActionTest.php @@ -0,0 +1,124 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\AdminBundle\Tests\Controller; + +use PHPUnit\Framework\TestCase; +use Sonata\AdminBundle\Admin\BreadcrumbsBuilderInterface; +use Sonata\AdminBundle\Admin\Pool; +use Sonata\AdminBundle\Controller\CoreController; +use Sonata\AdminBundle\Controller\DashboardAction; +use Sonata\AdminBundle\Templating\MutableTemplateRegistryInterface; +use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\HttpFoundation\Response; + +class DashboardActionTest extends TestCase +{ + /** + * @group legacy + */ + public function testdashboardActionStandardRequest() + { + $container = $this->createMock(ContainerInterface::class); + + $templateRegistry = $this->prophesize(MutableTemplateRegistryInterface::class); + $templateRegistry->getTemplate('ajax')->willReturn('ajax.html'); + $templateRegistry->getTemplate('dashboard')->willReturn('dashboard.html'); + $templateRegistry->getTemplate('layout')->willReturn('layout.html'); + + $pool = new Pool($container, 'title', 'logo.png'); + $pool->setTemplateRegistry($templateRegistry->reveal()); + + $templating = $this->createMock(EngineInterface::class); + $request = new Request(); + + $requestStack = new RequestStack(); + $requestStack->push($request); + + $breadcrumbsBuilder = $this->getMockForAbstractClass(BreadcrumbsBuilderInterface::class); + + $dashboardAction = new DashboardAction( + [], + $breadcrumbsBuilder, + $templateRegistry->reveal(), + $pool + ); + $values = [ + 'templating' => $templating, + 'request_stack' => $requestStack, + ]; + $dashboardAction->setContainer($container); + + $container->expects($this->any())->method('get')->will($this->returnCallback(function ($id) use ($values) { + return $values[$id]; + })); + + $container->expects($this->any()) + ->method('has') + ->will($this->returnCallback(function ($id) { + return 'templating' === $id; + })); + + $this->isInstanceOf(Response::class, $dashboardAction($request)); + } + + /** + * @group legacy + */ + public function testdashboardActionAjaxLayout() + { + $container = $this->createMock(ContainerInterface::class); + + $templateRegistry = $this->prophesize(MutableTemplateRegistryInterface::class); + $templateRegistry->getTemplate('ajax')->willReturn('ajax.html'); + $templateRegistry->getTemplate('dashboard')->willReturn('dashboard.html'); + $templateRegistry->getTemplate('layout')->willReturn('layout.html'); + $breadcrumbsBuilder = $this->getMockForAbstractClass(BreadcrumbsBuilderInterface::class); + + $pool = new Pool($container, 'title', 'logo.png'); + $pool->setTemplateRegistry($templateRegistry->reveal()); + + $templating = $this->createMock(EngineInterface::class); + $request = new Request(); + $request->headers->set('X-Requested-With', 'XMLHttpRequest'); + + $requestStack = new RequestStack(); + $requestStack->push($request); + + $dashboardAction = new DashboardAction( + [], + $breadcrumbsBuilder, + $templateRegistry->reveal(), + $pool + ); + $dashboardAction->setContainer($container); + $values = [ + 'templating' => $templating, + 'request_stack' => $requestStack, + ]; + $dashboardAction->setContainer($container); + + $container->expects($this->any())->method('get')->will($this->returnCallback(function ($id) use ($values) { + return $values[$id]; + })); + + $container->expects($this->any()) + ->method('has') + ->will($this->returnCallback(function ($id) { + return 'templating' === $id; + })); + + $this->isInstanceOf(Response::class, $dashboardAction($request)); + } +}