From 4a0dc367692a6c78ca051b04aef9f3397ceab917 Mon Sep 17 00:00:00 2001 From: Juan Pablo Ramirez <pabloelcolombiano@gmail.com> Date: Wed, 10 Mar 2021 15:47:09 +0100 Subject: [PATCH] Handle non conventional controller names --- .gitignore | 1 + README.md | 9 +- .../Component/ApiPaginationComponent.php | 3 +- ...entOnNonConventionalControllerNameTest.php | 113 ++++++++++++++++++ .../Component/ApiPaginationComponentTest.php | 2 +- .../Controller/ArticlesIndexController.php | 15 +++ 6 files changed, 139 insertions(+), 4 deletions(-) create mode 100644 tests/TestCase/Controller/Component/ApiPaginationComponentOnNonConventionalControllerNameTest.php create mode 100644 tests/test_app/TestApp/Controller/ArticlesIndexController.php diff --git a/.gitignore b/.gitignore index b6bd0e7..6bbc55f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ build composer.lock vendor .phpunit.result.cache +.idea diff --git a/README.md b/README.md index 6e4fc83..b4303ea 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ and will look something like this: ### Configuring the Pagination Output -ApiPagination has three keys for configuration: `key`, `aliases`, and `visible`. +ApiPagination has four keys for configuration: `key`, `aliases`, `visible` and `model`. * `key` allows you to change the name of the pagination key. @@ -83,6 +83,10 @@ ApiPagination has three keys for configuration: `key`, `aliases`, and `visible`. response. **Note:** Whenever setting a key's visibility, make sure to use the aliased name if you've given it one. +* `model` allows you to set the name of the model the pagination is applied on + if the controller does not follow CakePHP conventions, e.g. `ArticlesIndexController`. + Per default the model is the name of the controller, e.g. `Articles` for `ArticlesController`. + An example using all these configuration keys: ``` php @@ -97,7 +101,8 @@ $this->loadComponent('BryanCrowe/ApiPagination.ApiPagination', [ 'resultCount', 'prevPage', 'nextPage' - ] + ], + 'model' => 'Articles', ]); ``` diff --git a/src/Controller/Component/ApiPaginationComponent.php b/src/Controller/Component/ApiPaginationComponent.php index 0d700f3..8a4b938 100644 --- a/src/Controller/Component/ApiPaginationComponent.php +++ b/src/Controller/Component/ApiPaginationComponent.php @@ -45,7 +45,8 @@ public function beforeRender(Event $event) } $subject = $event->getSubject(); - $this->pagingInfo = $this->getController()->getRequest()->getAttribute('paging')[$subject->getName()]; + $modelName = ucfirst($this->getConfig('model', $subject->getName())); + $this->pagingInfo = $this->getController()->getRequest()->getAttribute('paging')[$modelName]; $config = $this->getConfig(); if (!empty($config['aliases'])) { diff --git a/tests/TestCase/Controller/Component/ApiPaginationComponentOnNonConventionalControllerNameTest.php b/tests/TestCase/Controller/Component/ApiPaginationComponentOnNonConventionalControllerNameTest.php new file mode 100644 index 0000000..39a6c67 --- /dev/null +++ b/tests/TestCase/Controller/Component/ApiPaginationComponentOnNonConventionalControllerNameTest.php @@ -0,0 +1,113 @@ +<?php +declare(strict_types=1); + +namespace BryanCrowe\ApiPagination\Test; + +use BryanCrowe\ApiPagination\Controller\Component\ApiPaginationComponent; +use BryanCrowe\ApiPagination\TestApp\Controller\ArticlesIndexController; +use Cake\Event\Event; +use Cake\Http\ServerRequest as Request; +use Cake\ORM\TableRegistry; +use Cake\TestSuite\TestCase; + +/** + * ApiPaginationComponentTest class + * + * @property ArticlesIndexController $controller + */ +class ApiPaginationComponentOnNonConventionalControllerNameTest extends TestCase +{ + public $fixtures = ['plugin.BryanCrowe/ApiPagination.Articles']; + + /** + * setUp method + * + * @return void + */ + public function setUp(): void + { + $this->request = new Request(['url' => '/articles']); + $this->response = $this->createMock('Cake\Http\Response'); + $this->controller = new ArticlesIndexController($this->request, $this->response); + $this->Articles = TableRegistry::getTableLocator()->get('BryanCrowe/ApiPagination.Articles', ['table' => 'bryancrowe_articles']); + parent::setUp(); + } + + /** + * tearDown method + * + * @return void + */ + public function tearDown(): void + { + parent::tearDown(); + } + + /** + * Test that a non conventional controller name is supported using the 'model' config. + * + * @dataProvider dataForTestVariousModelValueOnNonConventionalController + * @param array $config + * @param $expected + * @return void + */ + public function testVariousModelValueOnNonConventionalController(array $config, $expected) + { + $this->controller->setRequest( + $this->controller->getRequest()->withEnv('HTTP_ACCEPT', 'application/json') + ); + $this->controller->set('data', $this->controller->paginate($this->Articles)); + $apiPaginationComponent = new ApiPaginationComponent($this->controller->components(), $config); + $event = new Event('Controller.beforeRender', $this->controller); + $apiPaginationComponent->beforeRender($event); + + $result = $apiPaginationComponent->getController()->viewBuilder()->getVar('pagination'); + $this->assertSame($expected, $result); + } + + /** + * If the name of the paginated model is not specified, the result of the pagination + * on a controller not having the same name as the model fails. + * + * @return array[] + */ + public function dataForTestVariousModelValueOnNonConventionalController(): array + { + return [ + + [[], null], + [['model' => 'Articles'], $this->getDefaultPagination()], + [['model' => 'articles'], $this->getDefaultPagination()], + [['model' => 'NonExistingModel'], null], + ]; + } + + /** + * Returns the standard pagination result. + * + * @return array + */ + private function getDefaultPagination(): array + { + return [ + 'count' => 23, + 'current' => 20, + 'perPage' => 20, + 'page' => 1, + 'requestedPage' => 1, + 'pageCount' => 2, + 'start' => 1, + 'end' => 20, + 'prevPage' => false, + 'nextPage' => true, + 'sort' => null, + 'direction' => null, + 'sortDefault' => false, + 'directionDefault' => false, + 'completeSort' => [], + 'limit' => null, + 'scope' => null, + 'finder' => 'all', + ]; + } +} diff --git a/tests/TestCase/Controller/Component/ApiPaginationComponentTest.php b/tests/TestCase/Controller/Component/ApiPaginationComponentTest.php index ddb7f95..2d13563 100644 --- a/tests/TestCase/Controller/Component/ApiPaginationComponentTest.php +++ b/tests/TestCase/Controller/Component/ApiPaginationComponentTest.php @@ -29,7 +29,7 @@ public function setUp(): void $this->request = new Request(['url' => '/articles']); $this->response = $this->createMock('Cake\Http\Response'); $this->controller = new ArticlesController($this->request, $this->response); - $this->Articles = TableRegistry::get('BryanCrowe/ApiPagination.Articles', ['table' => 'bryancrowe_articles']); + $this->Articles = TableRegistry::getTableLocator()->get('BryanCrowe/ApiPagination.Articles', ['table' => 'bryancrowe_articles']); parent::setUp(); } diff --git a/tests/test_app/TestApp/Controller/ArticlesIndexController.php b/tests/test_app/TestApp/Controller/ArticlesIndexController.php new file mode 100644 index 0000000..a999113 --- /dev/null +++ b/tests/test_app/TestApp/Controller/ArticlesIndexController.php @@ -0,0 +1,15 @@ +<?php +declare(strict_types=1); + +namespace BryanCrowe\ApiPagination\TestApp\Controller; + +use Cake\Controller\Controller; + +class ArticlesIndexController extends Controller +{ + public function initialize(): void + { + parent::initialize(); + $this->loadComponent('Paginator'); + } +}