PaginatorHelperTest.php 110 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  5. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  6. *
  7. * Licensed under The MIT License
  8. * For full copyright and license information, please see the LICENSE.txt
  9. * Redistributions of files must retain the above copyright notice
  10. *
  11. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  12. * @link https://cakephp.org CakePHP(tm) Project
  13. * @since 1.2.0
  14. * @license https://opensource.org/licenses/mit-license.php MIT License
  15. */
  16. namespace Cake\Test\TestCase\View\Helper;
  17. use Cake\Core\Configure;
  18. use Cake\Datasource\Paging\PaginatedResultSet;
  19. use Cake\Http\ServerRequest;
  20. use Cake\I18n\I18n;
  21. use Cake\ORM\ResultSet;
  22. use Cake\Routing\Router;
  23. use Cake\TestSuite\TestCase;
  24. use Cake\View\Helper\PaginatorHelper;
  25. use Cake\View\View;
  26. /**
  27. * PaginatorHelperTest class
  28. */
  29. class PaginatorHelperTest extends TestCase
  30. {
  31. /**
  32. * @var \Cake\View\View
  33. */
  34. protected $View;
  35. /**
  36. * @var \Cake\View\Helper\PaginatorHelper
  37. */
  38. protected $Paginator;
  39. /**
  40. * @var \Cake\Datasource\Pagination\PaginatedResultSet
  41. */
  42. protected $paginatedResult;
  43. /**
  44. * setUp method
  45. */
  46. public function setUp(): void
  47. {
  48. parent::setUp();
  49. Configure::write('Config.language', 'eng');
  50. $request = new ServerRequest([
  51. 'url' => '/',
  52. 'params' => [
  53. 'plugin' => null,
  54. 'controller' => 'Articles',
  55. 'action' => 'index',
  56. ],
  57. ]);
  58. $this->paginatedResult = new PaginatedResultSet(new ResultSet([]), [
  59. 'alias' => 'Articles',
  60. 'currentPage' => 1,
  61. 'count' => 9,
  62. 'totalCount' => 62,
  63. 'hasPrevPage' => false,
  64. 'hasNextPage' => true,
  65. 'pageCount' => 7,
  66. ]);
  67. $this->View = new View($request, null, null, ['viewVars' => ['articles' => $this->paginatedResult]]);
  68. $this->Paginator = new PaginatorHelper($this->View);
  69. Router::reload();
  70. $builder = Router::createRouteBuilder('/');
  71. $builder->connect('/', ['controller' => 'Articles', 'action' => 'index']);
  72. $builder->connect('/{controller}/{action}/*');
  73. $builder->connect('/{plugin}/{controller}/{action}/*');
  74. Router::setRequest($request);
  75. }
  76. /**
  77. * tearDown method
  78. */
  79. public function tearDown(): void
  80. {
  81. parent::tearDown();
  82. unset($this->View, $this->Paginator);
  83. I18n::setLocale(I18n::getDefaultLocale());
  84. }
  85. protected function setPaginatedResult(array $params, bool $merge = true)
  86. {
  87. if ($merge) {
  88. $params += [
  89. 'alias' => 'Articles',
  90. 'currentPage' => 1,
  91. 'count' => 9,
  92. 'totalCount' => 62,
  93. 'hasPrevPage' => false,
  94. 'hasNextPage' => true,
  95. 'pageCount' => 7,
  96. ];
  97. }
  98. $this->paginatedResult = new PaginatedResultSet(new ResultSet([]), $params);
  99. $this->Paginator->setPaginated($this->paginatedResult);
  100. }
  101. /**
  102. * Test the templates method.
  103. */
  104. public function testTemplates(): void
  105. {
  106. $result = $this->Paginator->setTemplates([
  107. 'test' => 'val',
  108. ]);
  109. $this->assertSame(
  110. $this->Paginator,
  111. $result,
  112. 'Setting should return the same object'
  113. );
  114. $result = $this->Paginator->getTemplates();
  115. $this->assertArrayHasKey('test', $result);
  116. $this->assertSame('val', $result['test']);
  117. $this->assertSame('val', $this->Paginator->getTemplates('test'));
  118. }
  119. /**
  120. * testHasPrevious method
  121. */
  122. public function testHasPrevious(): void
  123. {
  124. $this->assertFalse($this->Paginator->hasPrev());
  125. $this->setPaginatedResult([
  126. 'hasPrevPage' => true,
  127. ]);
  128. $this->assertTrue($this->Paginator->hasPrev());
  129. }
  130. /**
  131. * testHasNext method
  132. */
  133. public function testHasNext(): void
  134. {
  135. $this->assertTrue($this->Paginator->hasNext());
  136. $this->setPaginatedResult([
  137. 'hasNextPage' => false,
  138. ]);
  139. $this->assertFalse($this->Paginator->hasNext());
  140. }
  141. /**
  142. * testSortLinks method
  143. */
  144. public function testSortLinks(): void
  145. {
  146. $request = new ServerRequest([
  147. 'url' => '/accounts/',
  148. 'params' => [
  149. 'plugin' => null, 'controller' => 'Accounts', 'action' => 'index', 'pass' => [],
  150. ],
  151. 'base' => '',
  152. 'webroot' => '/',
  153. ]);
  154. Router::setRequest($request);
  155. $this->setPaginatedResult([
  156. 'currentPage' => 1,
  157. 'count' => 9,
  158. 'totalCount' => 62,
  159. 'hasPrevPage' => false,
  160. 'hasNextPage' => true,
  161. 'pageCount' => 7,
  162. 'sort' => 'date',
  163. 'direction' => 'asc',
  164. ], false);
  165. $this->Paginator->options(['url' => ['param']]);
  166. $result = $this->Paginator->sort('title');
  167. $expected = [
  168. 'a' => ['href' => '/Accounts/index/param?sort=title&amp;direction=asc'],
  169. 'Title',
  170. '/a',
  171. ];
  172. $this->assertHtml($expected, $result);
  173. $result = $this->Paginator->sort('title', null, ['model' => 'Nope']);
  174. $this->assertHtml($expected, $result);
  175. $result = $this->Paginator->sort('title', null, ['model' => 'Article']);
  176. $this->assertHtml($expected, $result);
  177. $result = $this->Paginator->sort('date');
  178. $expected = [
  179. 'a' => ['href' => '/Accounts/index/param?sort=date&amp;direction=desc', 'class' => 'asc'],
  180. 'Date',
  181. '/a',
  182. ];
  183. $this->assertHtml($expected, $result);
  184. $result = $this->Paginator->sort('title', 'TestTitle');
  185. $expected = [
  186. 'a' => ['href' => '/Accounts/index/param?sort=title&amp;direction=asc'],
  187. 'TestTitle',
  188. '/a',
  189. ];
  190. $this->assertHtml($expected, $result);
  191. $result = $this->Paginator->sort('title', ['asc' => 'ascending', 'desc' => 'descending']);
  192. $expected = [
  193. 'a' => ['href' => '/Accounts/index/param?sort=title&amp;direction=asc'],
  194. 'ascending',
  195. '/a',
  196. ];
  197. $this->assertHtml($expected, $result);
  198. $this->setPaginatedResult([
  199. 'sort' => 'title',
  200. ]);
  201. $result = $this->Paginator->sort('title', ['asc' => 'ascending', 'desc' => 'descending']);
  202. $expected = [
  203. 'a' => ['href' => '/Accounts/index/param?sort=title&amp;direction=desc', 'class' => 'asc'],
  204. 'descending',
  205. '/a',
  206. ];
  207. $this->assertHtml($expected, $result);
  208. $this->setPaginatedResult([
  209. 'alias' => 'Article',
  210. 'sort' => 'Article.title',
  211. 'direction' => 'desc',
  212. ]);
  213. $result = $this->Paginator->sort('title');
  214. $expected = [
  215. 'a' => ['href' => '/Accounts/index/param?sort=title&amp;direction=asc', 'class' => 'desc'],
  216. 'Title',
  217. '/a',
  218. ];
  219. $this->assertHtml($expected, $result);
  220. $this->setPaginatedResult([
  221. 'alias' => 'Article',
  222. 'sort' => 'Article.title',
  223. 'direction' => 'asc',
  224. ]);
  225. $result = $this->Paginator->sort('title');
  226. $expected = [
  227. 'a' => ['href' => '/Accounts/index/param?sort=title&amp;direction=desc', 'class' => 'asc'],
  228. 'Title',
  229. '/a',
  230. ];
  231. $this->assertHtml($expected, $result);
  232. $this->setPaginatedResult([
  233. 'alias' => 'Article',
  234. 'sort' => 'Article.title',
  235. 'direction' => 'desc',
  236. ]);
  237. $result = $this->Paginator->sort('title', 'Title', ['direction' => 'desc']);
  238. $expected = [
  239. 'a' => ['href' => '/Accounts/index/param?sort=title&amp;direction=asc', 'class' => 'desc'],
  240. 'Title',
  241. '/a',
  242. ];
  243. $this->assertHtml($expected, $result);
  244. $this->setPaginatedResult([
  245. 'alias' => 'Article',
  246. 'sort' => 'Article.title',
  247. 'direction' => 'desc',
  248. ]);
  249. $result = $this->Paginator->sort('title', 'Title', ['direction' => 'ASC']);
  250. $expected = [
  251. 'a' => ['href' => '/Accounts/index/param?sort=title&amp;direction=asc', 'class' => 'desc'],
  252. 'Title',
  253. '/a',
  254. ];
  255. $this->assertHtml($expected, $result);
  256. $this->setPaginatedResult([
  257. 'alias' => 'Article',
  258. 'sort' => 'Article.title',
  259. 'direction' => 'asc',
  260. ]);
  261. $result = $this->Paginator->sort('title', 'Title', ['direction' => 'asc']);
  262. $expected = [
  263. 'a' => ['href' => '/Accounts/index/param?sort=title&amp;direction=desc', 'class' => 'asc'],
  264. 'Title',
  265. '/a',
  266. ];
  267. $this->assertHtml($expected, $result);
  268. $result = $this->Paginator->sort('title', 'Title', ['direction' => 'desc']);
  269. $expected = [
  270. 'a' => ['href' => '/Accounts/index/param?sort=title&amp;direction=desc', 'class' => 'asc'],
  271. 'Title',
  272. '/a',
  273. ];
  274. $this->assertHtml($expected, $result);
  275. }
  276. /**
  277. * test sort() with escape option
  278. */
  279. public function testSortEscape(): void
  280. {
  281. $result = $this->Paginator->sort('title', 'TestTitle >');
  282. $expected = [
  283. 'a' => ['href' => '/?sort=title&amp;direction=asc'],
  284. 'TestTitle &gt;',
  285. '/a',
  286. ];
  287. $this->assertHtml($expected, $result);
  288. $result = $this->Paginator->sort('title', 'TestTitle >', ['escape' => true]);
  289. $this->assertHtml($expected, $result);
  290. $result = $this->Paginator->sort('title', 'TestTitle >', ['escape' => false]);
  291. $expected = [
  292. 'a' => ['href' => '/?sort=title&amp;direction=asc'],
  293. 'TestTitle >',
  294. '/a',
  295. ];
  296. $this->assertHtml($expected, $result);
  297. }
  298. /**
  299. * test that sort() works with virtual field order options.
  300. */
  301. public function testSortLinkWithVirtualField(): void
  302. {
  303. $request = new ServerRequest([
  304. 'url' => '/accounts/',
  305. 'params' => [
  306. 'plugin' => null, 'controller' => 'Accounts', 'action' => 'index', 'pass' => [],
  307. ],
  308. 'base' => '',
  309. 'webroot' => '/',
  310. ]);
  311. Router::setRequest($request);
  312. $this->setPaginatedResult([
  313. 'alias' => 'Article',
  314. 'sort' => 'full_name',
  315. 'direction' => 'asc',
  316. ]);
  317. $result = $this->Paginator->sort('Article.full_name');
  318. $expected = [
  319. 'a' => ['href' => '/Accounts/index?sort=Article.full_name&amp;direction=desc', 'class' => 'asc'],
  320. 'Article Full Name',
  321. '/a',
  322. ];
  323. $this->assertHtml($expected, $result);
  324. $result = $this->Paginator->sort('full_name');
  325. $expected = [
  326. 'a' => ['href' => '/Accounts/index?sort=full_name&amp;direction=desc', 'class' => 'asc'],
  327. 'Full Name',
  328. '/a',
  329. ];
  330. $this->assertHtml($expected, $result);
  331. $this->setPaginatedResult([
  332. 'alias' => 'Article',
  333. 'sort' => 'full_name',
  334. 'direction' => 'desc',
  335. ]);
  336. $result = $this->Paginator->sort('Article.full_name');
  337. $expected = [
  338. 'a' => ['href' => '/Accounts/index?sort=Article.full_name&amp;direction=asc', 'class' => 'desc'],
  339. 'Article Full Name',
  340. '/a',
  341. ];
  342. $this->assertHtml($expected, $result);
  343. $result = $this->Paginator->sort('full_name');
  344. $expected = [
  345. 'a' => ['href' => '/Accounts/index?sort=full_name&amp;direction=asc', 'class' => 'desc'],
  346. 'Full Name',
  347. '/a',
  348. ];
  349. $this->assertHtml($expected, $result);
  350. }
  351. /**
  352. * testSortLinksUsingDirectionOption method
  353. */
  354. public function testSortLinksUsingDirectionOption(): void
  355. {
  356. $request = new ServerRequest([
  357. 'url' => '/accounts/',
  358. 'params' => [
  359. 'plugin' => null, 'controller' => 'Accounts', 'action' => 'index', 'pass' => [],
  360. ],
  361. 'base' => '',
  362. 'webroot' => '/',
  363. ]);
  364. Router::setRequest($request);
  365. $this->Paginator->options(['url' => ['param']]);
  366. $result = $this->Paginator->sort('title', 'TestTitle', ['direction' => 'desc']);
  367. $expected = [
  368. 'a' => ['href' => '/Accounts/index/param?sort=title&amp;direction=desc'],
  369. 'TestTitle',
  370. '/a',
  371. ];
  372. $this->assertHtml($expected, $result);
  373. $result = $this->Paginator->sort('title', ['asc' => 'ascending', 'desc' => 'descending'], ['direction' => 'desc']);
  374. $expected = [
  375. 'a' => ['href' => '/Accounts/index/param?sort=title&amp;direction=desc'],
  376. 'descending',
  377. '/a',
  378. ];
  379. $this->assertHtml($expected, $result);
  380. }
  381. /**
  382. * testSortLinksUsingDotNotation method
  383. */
  384. public function testSortLinksUsingDotNotation(): void
  385. {
  386. $request = new ServerRequest([
  387. 'url' => '/accounts/',
  388. 'params' => [
  389. 'plugin' => null, 'controller' => 'Accounts', 'action' => 'index', 'pass' => [],
  390. ],
  391. 'base' => '',
  392. 'webroot' => '/',
  393. ]);
  394. Router::setRequest($request);
  395. $this->setPaginatedResult([
  396. 'alias' => 'Article',
  397. 'sort' => 'Article.title',
  398. 'direction' => 'desc',
  399. ]);
  400. $result = $this->Paginator->sort('Article.title');
  401. $expected = [
  402. 'a' => ['href' => '/Accounts/index?sort=Article.title&amp;direction=asc', 'class' => 'desc'],
  403. 'Article Title',
  404. '/a',
  405. ];
  406. $this->assertHtml($expected, $result);
  407. $this->setPaginatedResult([
  408. 'alias' => 'Article',
  409. 'sort' => 'Article.title',
  410. 'direction' => 'desc',
  411. ]);
  412. $result = $this->Paginator->sort('Article.title', 'Title');
  413. $expected = [
  414. 'a' => ['href' => '/Accounts/index?sort=Article.title&amp;direction=asc', 'class' => 'desc'],
  415. 'Title',
  416. '/a',
  417. ];
  418. $this->assertHtml($expected, $result);
  419. $this->setPaginatedResult([
  420. 'alias' => 'Article',
  421. 'sort' => 'Article.title',
  422. 'direction' => 'asc',
  423. ]);
  424. $result = $this->Paginator->sort('Article.title', 'Title');
  425. $expected = [
  426. 'a' => ['href' => '/Accounts/index?sort=Article.title&amp;direction=desc', 'class' => 'asc'],
  427. 'Title',
  428. '/a',
  429. ];
  430. $this->assertHtml($expected, $result);
  431. $this->setPaginatedResult([
  432. 'alias' => 'Article',
  433. 'sort' => 'Account.title',
  434. 'direction' => 'asc',
  435. ]);
  436. $result = $this->Paginator->sort('title');
  437. $expected = [
  438. 'a' => ['href' => '/Accounts/index?sort=title&amp;direction=asc'],
  439. 'Title',
  440. '/a',
  441. ];
  442. $this->assertHtml($expected, $result);
  443. }
  444. /**
  445. * test multiple pagination sort links
  446. */
  447. public function testSortLinksMultiplePagination(): void
  448. {
  449. $request = new ServerRequest([
  450. 'url' => '/accounts/',
  451. 'params' => [
  452. 'plugin' => null, 'controller' => 'Accounts', 'action' => 'index', 'pass' => [],
  453. ],
  454. 'base' => '',
  455. 'webroot' => '/',
  456. ]);
  457. Router::setRequest($request);
  458. $this->setPaginatedResult([
  459. 'count' => 9,
  460. 'totalCount' => 62,
  461. 'hasPrevPage' => false,
  462. 'hasNextPage' => true,
  463. 'pageCount' => 7,
  464. 'sort' => 'date',
  465. 'direction' => 'asc',
  466. 'page' => 1,
  467. 'scope' => 'article',
  468. ], false);
  469. $result = $this->Paginator->sort('title', 'Title', ['model' => 'Articles']);
  470. $expected = [
  471. 'a' => ['href' => '/Accounts/index?article%5Bsort%5D=title&amp;article%5Bdirection%5D=asc'],
  472. 'Title',
  473. '/a',
  474. ];
  475. $this->assertHtml($expected, $result);
  476. $this->Paginator->setPaginated(new PaginatedResultSet(
  477. new ResultSet([]),
  478. [
  479. 'count' => 1,
  480. 'totalCount' => 100,
  481. 'hasPrevPage' => false,
  482. 'hasNextPage' => true,
  483. 'pageCount' => 5,
  484. 'sort' => 'tag',
  485. 'direction' => 'asc',
  486. 'page' => 1,
  487. 'scope' => 'tags',
  488. ]
  489. ));
  490. $result = $this->Paginator->sort('tag', 'Tag', ['model' => 'Tags']);
  491. $expected = [
  492. 'a' => ['class' => 'asc', 'href' => '/Accounts/index?tags%5Bsort%5D=tag&amp;tags%5Bdirection%5D=desc'],
  493. 'Tag',
  494. '/a',
  495. ];
  496. $this->assertHtml($expected, $result);
  497. }
  498. /**
  499. * testSortAdminLinks method
  500. */
  501. public function testSortAdminLinks(): void
  502. {
  503. Router::reload();
  504. Router::createRouteBuilder('/')->connect('/admin/{controller}/{action}/*', ['prefix' => 'Admin']);
  505. $request = new ServerRequest([
  506. 'url' => '/admin/users',
  507. 'params' => [
  508. 'plugin' => null, 'controller' => 'Users', 'action' => 'index', 'prefix' => 'Admin',
  509. ],
  510. 'base' => '',
  511. 'webroot' => '/',
  512. ]);
  513. Router::setRequest($request);
  514. $this->setPaginatedResult([
  515. 'alias' => 'Article',
  516. 'currentPage' => 1,
  517. ]);
  518. $result = $this->Paginator->next('Next');
  519. $expected = [
  520. 'li' => ['class' => 'next'],
  521. 'a' => ['href' => '/admin/Users/index?page=2', 'rel' => 'next'],
  522. 'Next',
  523. '/a',
  524. '/li',
  525. ];
  526. $this->assertHtml($expected, $result);
  527. $this->Paginator->options(['url' => ['param']]);
  528. $result = $this->Paginator->sort('title');
  529. $expected = [
  530. 'a' => ['href' => '/admin/Users/index/param?sort=title&amp;direction=asc'],
  531. 'Title',
  532. '/a',
  533. ];
  534. $this->assertHtml($expected, $result);
  535. $this->Paginator->options(['url' => ['param']]);
  536. $result = $this->Paginator->sort('Article.title', 'Title');
  537. $expected = [
  538. 'a' => ['href' => '/admin/Users/index/param?sort=Article.title&amp;direction=asc'],
  539. 'Title',
  540. '/a',
  541. ];
  542. $this->assertHtml($expected, $result);
  543. }
  544. /**
  545. * Test that generated URLs work without sort defined within the request
  546. */
  547. public function testDefaultSortAndNoSort(): void
  548. {
  549. $request = new ServerRequest([
  550. 'url' => '/articles/index',
  551. 'params' => [
  552. 'plugin' => null, 'controller' => 'Articles', 'action' => 'index',
  553. ],
  554. 'base' => '',
  555. 'webroot' => '/',
  556. ]);
  557. Router::setRequest($request);
  558. $this->View->setRequest($this->View->getRequest()->withAttribute('paging', [
  559. 'Article' => [
  560. 'page' => 1, 'current' => 3, 'count' => 13,
  561. 'prevPage' => false, 'nextPage' => true, 'pageCount' => 8,
  562. 'sortDefault' => 'Article.title', 'directionDefault' => 'ASC',
  563. 'sort' => null,
  564. ],
  565. ]));
  566. $result = $this->Paginator->next('Next');
  567. $expected = [
  568. 'li' => ['class' => 'next'],
  569. 'a' => ['rel' => 'next', 'href' => '/?page=2'],
  570. 'Next',
  571. '/a',
  572. '/li',
  573. ];
  574. $this->assertHtml($expected, $result);
  575. }
  576. /**
  577. * testUrlGeneration method
  578. */
  579. public function testUrlGeneration(): void
  580. {
  581. $result = $this->Paginator->sort('controller');
  582. $expected = [
  583. 'a' => ['href' => '/?sort=controller&amp;direction=asc'],
  584. 'Controller',
  585. '/a',
  586. ];
  587. $this->assertHtml($expected, $result);
  588. $result = $this->Paginator->generateUrl();
  589. $this->assertSame('/', $result);
  590. $this->setPaginatedResult([
  591. 'alias' => 'Article',
  592. 'currentPage' => 2,
  593. ]);
  594. $result = $this->Paginator->generateUrl();
  595. $this->assertSame('/?page=2', $result);
  596. $options = ['sort' => 'Article', 'direction' => 'desc'];
  597. $result = $this->Paginator->generateUrl($options);
  598. $this->assertSame('/?sort=Article&amp;direction=desc&amp;page=2', $result);
  599. $this->setPaginatedResult([
  600. 'alias' => 'Article',
  601. 'currentPage' => 3,
  602. ]);
  603. $options = ['sort' => 'Article.name', 'direction' => 'desc'];
  604. $result = $this->Paginator->generateUrl($options);
  605. $this->assertSame('/?sort=Article.name&amp;direction=desc&amp;page=3', $result);
  606. $options = ['sort' => 'Article.name', 'direction' => 'desc'];
  607. $result = $this->Paginator->generateUrl($options, [], ['escape' => false]);
  608. $this->assertSame('/?sort=Article.name&direction=desc&page=3', $result);
  609. $options = ['sort' => 'Article.name', 'direction' => 'desc'];
  610. $result = $this->Paginator->generateUrl($options, [], ['fullBase' => true]);
  611. $this->assertSame('http://localhost/?sort=Article.name&amp;direction=desc&amp;page=3', $result);
  612. }
  613. /**
  614. * Verify that sort links always result in a url that is page 1 (page not
  615. * present in the url)
  616. *
  617. * @param string $field
  618. * @param array $options
  619. * @param string $expected
  620. * @dataProvider urlGenerationResetsToPage1Provider
  621. */
  622. public function testUrlGenerationResetsToPage1($field, $options, $expected): void
  623. {
  624. $this->setPaginatedResult([
  625. 'alias' => 'Article',
  626. 'currentPage' => 2,
  627. 'sort' => 'name',
  628. 'direction' => 'asc',
  629. ]);
  630. $result = $this->Paginator->sort($field, null, ['url' => ['?' => $options]]);
  631. $this->assertSame($expected, $result);
  632. }
  633. /**
  634. * Returns data sets of:
  635. * * the name of the field being sorted on
  636. * * url parameters to pass to paginator sort
  637. * * expected result as a string
  638. *
  639. * @return array
  640. */
  641. public static function urlGenerationResetsToPage1Provider(): array
  642. {
  643. return [
  644. 'Sorting the field currently sorted asc, asc' => [
  645. 'name',
  646. ['sort' => 'name', 'direction' => 'asc'],
  647. '<a class="asc" href="/?sort=name&amp;direction=asc">Name</a>',
  648. ],
  649. 'Sorting the field currently sorted asc, desc' => [
  650. 'name',
  651. ['sort' => 'name', 'direction' => 'desc'],
  652. '<a class="asc" href="/?sort=name&amp;direction=desc">Name</a>',
  653. ],
  654. 'Sorting other asc' => [
  655. 'other',
  656. ['sort' => 'other', 'direction' => 'asc'],
  657. '<a href="/?sort=other&amp;direction=asc">Other</a>',
  658. ],
  659. 'Sorting other desc' => [
  660. 'other',
  661. ['sort' => 'other', 'direction' => 'desc'],
  662. '<a href="/?sort=other&amp;direction=desc">Other</a>',
  663. ],
  664. ];
  665. }
  666. /**
  667. * test URL generation with prefix routes
  668. */
  669. public function testGenerateUrlWithPrefixes(): void
  670. {
  671. Router::reload();
  672. $builder = Router::createRouteBuilder('/');
  673. $builder->connect('/members/{controller}/{action}/*', ['prefix' => 'Members']);
  674. $builder->connect('/{controller}/{action}/*');
  675. $request = new ServerRequest([
  676. 'url' => '/Posts/index',
  677. 'params' => [
  678. 'plugin' => null, 'controller' => 'Posts', 'action' => 'index', 'pass' => [],
  679. ],
  680. 'base' => '',
  681. 'webroot' => '/',
  682. ]);
  683. Router::setRequest($request);
  684. $this->setPaginatedResult([
  685. 'alias' => 'Article',
  686. 'currentPage' => 2,
  687. 'hasPrevPage' => true,
  688. 'hasNextPage' => true,
  689. ], false);
  690. $url = ['prefix' => 'Members'];
  691. $result = $this->Paginator->generateUrl([], $url);
  692. $expected = '/members/Posts/index?page=2';
  693. $this->assertSame($expected, $result);
  694. $result = $this->Paginator->sort('name', null, ['url' => $url]);
  695. $expected = [
  696. 'a' => ['href' => '/members/Posts/index?sort=name&amp;direction=asc'],
  697. 'Name',
  698. '/a',
  699. ];
  700. $this->assertHtml($expected, $result);
  701. $result = $this->Paginator->next('next', ['url' => $url]);
  702. $expected = [
  703. 'li' => ['class' => 'next'],
  704. 'a' => ['href' => '/members/Posts/index?page=3', 'rel' => 'next'],
  705. 'next',
  706. '/a',
  707. '/li',
  708. ];
  709. $this->assertHtml($expected, $result);
  710. $result = $this->Paginator->prev('prev', ['url' => $url]);
  711. $expected = [
  712. 'li' => ['class' => 'prev'],
  713. 'a' => ['href' => '/members/Posts/index', 'rel' => 'prev'],
  714. 'prev',
  715. '/a',
  716. '/li',
  717. ];
  718. $this->assertHtml($expected, $result);
  719. $options = ['sort' => 'name', 'direction' => 'desc'];
  720. $url = [
  721. 'prefix' => 'Members',
  722. 'controller' => 'Posts',
  723. ];
  724. $result = $this->Paginator->generateUrl($options, $url);
  725. $expected = '/members/Posts/index?sort=name&amp;direction=desc&amp;page=2';
  726. $this->assertSame($expected, $result);
  727. $options = ['sort' => 'Article.name', 'direction' => 'desc'];
  728. $url = ['controller' => 'Posts'];
  729. $result = $this->Paginator->generateUrl($options, $url);
  730. $expected = '/Posts/index?sort=Article.name&amp;direction=desc&amp;page=2';
  731. $this->assertSame($expected, $result);
  732. }
  733. /**
  734. * test URL generation can leave prefix routes
  735. */
  736. public function testGenerateUrlWithPrefixesLeavePrefix(): void
  737. {
  738. Router::reload();
  739. $builder = Router::createRouteBuilder('/');
  740. $builder->connect('/members/{controller}/{action}/*', ['prefix' => 'Members']);
  741. $builder->connect('/{controller}/{action}/*');
  742. $request = new ServerRequest([
  743. 'params' => [
  744. 'prefix' => 'Members',
  745. 'controller' => 'Posts',
  746. 'action' => 'index',
  747. 'plugin' => null,
  748. ],
  749. 'webroot' => '/',
  750. ]);
  751. $request = $request->withAttribute('paging', ['Article' => ['page' => 2, 'prevPage' => true]]);
  752. Router::setRequest($request);
  753. $this->View->setRequest($request);
  754. $this->setPaginatedResult([
  755. 'currentPage' => 2,
  756. 'hasPrevPage' => true,
  757. 'hasNextPage' => true,
  758. ]);
  759. $result = $this->Paginator->generateUrl();
  760. $expected = '/members/Posts/index?page=2';
  761. $this->assertSame($expected, $result);
  762. $result = $this->Paginator->generateUrl([], ['prefix' => 'Members']);
  763. $expected = '/members/Posts/index?page=2';
  764. $this->assertSame($expected, $result);
  765. $result = $this->Paginator->generateUrl([], ['prefix' => false]);
  766. $expected = '/Posts/index?page=2';
  767. $this->assertSame($expected, $result);
  768. $this->Paginator->options(['url' => ['prefix' => false]]);
  769. $result = $this->Paginator->generateUrl();
  770. $this->assertSame($expected, $result, 'Setting prefix in options should work too.');
  771. }
  772. /**
  773. * test generateUrl with multiple pagination
  774. */
  775. public function testGenerateUrlMultiplePagination(): void
  776. {
  777. $request = new ServerRequest([
  778. 'url' => '/Posts/index',
  779. 'params' => [
  780. 'plugin' => null, 'controller' => 'Posts', 'action' => 'index', 'pass' => [],
  781. ],
  782. 'base' => '',
  783. 'webroot' => '/',
  784. ]);
  785. Router::setRequest($request);
  786. $this->setPaginatedResult([
  787. 'alias' => 'Article',
  788. 'scope' => 'article',
  789. 'currentPage' => 3,
  790. 'hasPrevPage' => true,
  791. ]);
  792. $result = $this->Paginator->generateUrl([]);
  793. $expected = '/Posts/index?article%5Bpage%5D=3';
  794. $this->assertSame($expected, $result);
  795. $result = $this->Paginator->sort('name');
  796. $expected = [
  797. 'a' => ['href' => '/Posts/index?article%5Bsort%5D=name&amp;article%5Bdirection%5D=asc'],
  798. 'Name',
  799. '/a',
  800. ];
  801. $this->assertHtml($expected, $result);
  802. $result = $this->Paginator->next('next');
  803. $expected = [
  804. 'li' => ['class' => 'next'],
  805. 'a' => ['href' => '/Posts/index?article%5Bpage%5D=4', 'rel' => 'next'],
  806. 'next',
  807. '/a',
  808. '/li',
  809. ];
  810. $this->assertHtml($expected, $result);
  811. $result = $this->Paginator->prev('prev');
  812. $expected = [
  813. 'li' => ['class' => 'prev'],
  814. 'a' => ['href' => '/Posts/index?article%5Bpage%5D=2', 'rel' => 'prev'],
  815. 'prev',
  816. '/a',
  817. '/li',
  818. ];
  819. $this->assertHtml($expected, $result);
  820. $result = $this->Paginator->generateUrl(['sort' => 'name']);
  821. $expected = '/Posts/index?article%5Bsort%5D=name&amp;article%5Bpage%5D=3';
  822. $this->assertSame($expected, $result);
  823. $result = $this->Paginator->generateUrl([], ['#' => 'foo']);
  824. $expected = '/Posts/index?article%5Bpage%5D=3#foo';
  825. $this->assertSame($expected, $result);
  826. }
  827. /**
  828. * test generateUrl with multiple pagination and query string values
  829. */
  830. public function testGenerateUrlMultiplePaginationQueryStringData(): void
  831. {
  832. $request = new ServerRequest([
  833. 'url' => '/Posts/index',
  834. 'params' => [
  835. 'plugin' => null, 'controller' => 'Posts', 'action' => 'index',
  836. ],
  837. 'query' => [
  838. 'article' => [
  839. 'puppy' => 'no',
  840. ],
  841. ],
  842. ]);
  843. Router::setRequest($request);
  844. $paginatedResult = new PaginatedResultSet(new ResultSet([]), [
  845. 'alias' => 'Article',
  846. 'scope' => 'article',
  847. 'currentPage' => 3,
  848. 'hasPrevPage' => true,
  849. ]);
  850. $this->View->setRequest($request);
  851. // Need to run __construct to update _config['url']
  852. $paginator = new PaginatorHelper($this->View);
  853. $paginator->setPaginated($paginatedResult);
  854. $result = $paginator->generateUrl(['sort' => 'name']);
  855. $expected = '/Posts/index?article%5Bsort%5D=name&amp;article%5Bpage%5D=3&amp;article%5Bpuppy%5D=no';
  856. $this->assertSame($expected, $result);
  857. $result = $paginator->generateUrl([]);
  858. $expected = '/Posts/index?article%5Bpage%5D=3&amp;article%5Bpuppy%5D=no';
  859. $this->assertSame($expected, $result);
  860. }
  861. /**
  862. * testPassedArgsMergingWithUrlOptions method
  863. */
  864. public function testPassedArgsMergingWithUrlOptions(): void
  865. {
  866. $request = new ServerRequest([
  867. 'url' => '/articles/',
  868. 'params' => [
  869. 'plugin' => null, 'controller' => 'Articles', 'action' => 'index', 'pass' => [2],
  870. ],
  871. 'query' => ['page' => 1, 'foo' => 'bar', 'x' => 'y', 'num' => 0],
  872. ]);
  873. $this->setPaginatedResult([
  874. 'currentPage' => 1, 'count' => 3, 'totalCount' => 13,
  875. 'hasPrevPage' => false, 'hasNextPage' => true, 'pageCount' => 8,
  876. 'sort' => null, 'direction' => null,
  877. ]);
  878. $this->View->setRequest($request);
  879. $this->Paginator = new PaginatorHelper($this->View);
  880. $this->Paginator->setPaginated($this->paginatedResult);
  881. $result = $this->Paginator->sort('title');
  882. $expected = [
  883. 'a' => ['href' => '/Articles/index/2?foo=bar&amp;x=y&amp;num=0&amp;sort=title&amp;direction=asc'],
  884. 'Title',
  885. '/a',
  886. ];
  887. $this->assertHtml($expected, $result);
  888. $result = $this->Paginator->numbers();
  889. $expected = [
  890. ['li' => ['class' => 'active']], '<a href=""', '1', '/a', '/li',
  891. ['li' => []], ['a' => ['href' => '/Articles/index/2?foo=bar&amp;x=y&amp;num=0&amp;page=2']], '2', '/a', '/li',
  892. ['li' => []], ['a' => ['href' => '/Articles/index/2?foo=bar&amp;x=y&amp;num=0&amp;page=3']], '3', '/a', '/li',
  893. ['li' => []], ['a' => ['href' => '/Articles/index/2?foo=bar&amp;x=y&amp;num=0&amp;page=4']], '4', '/a', '/li',
  894. ['li' => []], ['a' => ['href' => '/Articles/index/2?foo=bar&amp;x=y&amp;num=0&amp;page=5']], '5', '/a', '/li',
  895. ['li' => []], ['a' => ['href' => '/Articles/index/2?foo=bar&amp;x=y&amp;num=0&amp;page=6']], '6', '/a', '/li',
  896. ['li' => []], ['a' => ['href' => '/Articles/index/2?foo=bar&amp;x=y&amp;num=0&amp;page=7']], '7', '/a', '/li',
  897. ];
  898. $this->assertHtml($expected, $result);
  899. $result = $this->Paginator->next('Next');
  900. $expected = [
  901. 'li' => ['class' => 'next'],
  902. 'a' => ['href' => '/Articles/index/2?foo=bar&amp;x=y&amp;num=0&amp;page=2', 'rel' => 'next'],
  903. 'Next',
  904. '/a',
  905. '/li',
  906. ];
  907. $this->assertHtml($expected, $result);
  908. }
  909. /**
  910. * Test that generated URLs don't include sort and direction parameters
  911. */
  912. public function testDefaultSortRemovedFromUrl(): void
  913. {
  914. $request = new ServerRequest([
  915. 'url' => '/Articles/',
  916. 'params' => [
  917. 'plugin' => null, 'controller' => 'Articles', 'action' => 'index',
  918. ],
  919. ]);
  920. Router::setRequest($request);
  921. $this->View->setRequest($this->View->getRequest()->withAttribute('paging', [
  922. 'Article' => [
  923. 'page' => 1, 'current' => 3, 'count' => 13,
  924. 'prevPage' => false, 'nextPage' => true, 'pageCount' => 8,
  925. 'sort' => 'Article.title', 'direction' => 'ASC',
  926. 'sortDefault' => 'Article.title', 'directionDefault' => 'ASC',
  927. ],
  928. ]));
  929. $result = $this->Paginator->next('Next');
  930. $expected = [
  931. 'li' => ['class' => 'next'],
  932. 'a' => ['rel' => 'next', 'href' => '/?page=2'],
  933. 'Next',
  934. '/a',
  935. '/li',
  936. ];
  937. $this->assertHtml($expected, $result);
  938. }
  939. /**
  940. * Tests that generated default order URL doesn't include sort and direction parameters.
  941. */
  942. public function testDefaultSortRemovedFromUrlWithAliases(): void
  943. {
  944. $request = new ServerRequest([
  945. 'params' => ['controller' => 'Articles', 'action' => 'index', 'plugin' => null],
  946. 'url' => '/Articles?sort=title&direction=asc',
  947. ]);
  948. Router::setRequest($request);
  949. $this->setPaginatedResult([
  950. 'currentPage' => 1,
  951. 'count' => 3,
  952. 'totalCount' => 13,
  953. 'hasPrevPage' => true,
  954. 'hasNextPage' => true,
  955. 'pageCount' => 8,
  956. 'alias' => 'Articles',
  957. 'sort' => 'Articles.title', 'direction' => 'asc',
  958. 'sortDefault' => 'Articles.title', 'directionDefault' => 'desc',
  959. ], false);
  960. $result = $this->Paginator->sort('title');
  961. $expected = [
  962. 'a' => ['class' => 'asc', 'href' => '/'],
  963. 'Title',
  964. '/a',
  965. ];
  966. $this->assertHtml($expected, $result);
  967. }
  968. /**
  969. * Test the prev() method.
  970. */
  971. public function testPrev(): void
  972. {
  973. $this->setPaginatedResult([
  974. 'currentPage' => 1,
  975. 'count' => 3,
  976. 'totalCount' => 13,
  977. 'hasPrevPage' => false,
  978. 'hasNextPage' => true,
  979. 'pageCount' => 5,
  980. ], false);
  981. $result = $this->Paginator->prev('<< Previous');
  982. $expected = [
  983. 'li' => ['class' => 'prev disabled'],
  984. 'a' => ['href' => '', 'onclick' => 'return false;'],
  985. '&lt;&lt; Previous',
  986. '/a',
  987. '/li',
  988. ];
  989. $this->assertHtml($expected, $result);
  990. $result = $this->Paginator->prev('<< Previous', ['disabledTitle' => 'Prev']);
  991. $expected = [
  992. 'li' => ['class' => 'prev disabled'],
  993. 'a' => ['href' => '', 'onclick' => 'return false;'],
  994. 'Prev',
  995. '/a',
  996. '/li',
  997. ];
  998. $this->assertHtml($expected, $result);
  999. $result = $this->Paginator->prev('<< Previous', ['disabledTitle' => false]);
  1000. $this->assertSame('', $result, 'disabled + no text = no link');
  1001. $this->setPaginatedResult([
  1002. 'currentPage' => 2,
  1003. 'hasPrevPage' => true,
  1004. ], false);
  1005. $result = $this->Paginator->prev('<< Previous');
  1006. $expected = [
  1007. 'li' => ['class' => 'prev'],
  1008. 'a' => ['href' => '/', 'rel' => 'prev'],
  1009. '&lt;&lt; Previous',
  1010. '/a',
  1011. '/li',
  1012. ];
  1013. $this->assertHtml($expected, $result);
  1014. $result = $this->Paginator->prev('Prev', [
  1015. 'templates' => [
  1016. 'prevActive' => '<a rel="prev" href="{{url}}">{{text}}</a>',
  1017. ],
  1018. ]);
  1019. $expected = [
  1020. 'a' => ['href' => '/', 'rel' => 'prev'],
  1021. 'Prev',
  1022. '/a',
  1023. ];
  1024. $this->assertHtml($expected, $result);
  1025. }
  1026. /**
  1027. * Test that prev() and the shared implementation underneath picks up from options
  1028. */
  1029. public function testPrevWithOptions(): void
  1030. {
  1031. $this->setPaginatedResult([
  1032. 'currentPage' => 2,
  1033. 'count' => 1,
  1034. 'totalCount' => 13,
  1035. 'hasPrevPage' => true,
  1036. 'hasNextPage' => false,
  1037. 'pageCount' => 2,
  1038. 'limit' => 10,
  1039. ], false);
  1040. $this->Paginator->options(['url' => [12, 'page' => 3]]);
  1041. $result = $this->Paginator->prev('Prev', ['url' => ['?' => ['foo' => 'bar']]]);
  1042. $expected = [
  1043. 'li' => ['class' => 'prev'],
  1044. 'a' => ['href' => '/Articles/index/12?foo=bar&amp;limit=10', 'rel' => 'prev'],
  1045. 'Prev',
  1046. '/a',
  1047. '/li',
  1048. ];
  1049. $this->assertHtml($expected, $result);
  1050. }
  1051. /**
  1052. * test the next() method.
  1053. */
  1054. public function testNext(): void
  1055. {
  1056. $result = $this->Paginator->next('Next >>');
  1057. $expected = [
  1058. 'li' => ['class' => 'next'],
  1059. 'a' => ['href' => '/?page=2', 'rel' => 'next'],
  1060. 'Next &gt;&gt;',
  1061. '/a',
  1062. '/li',
  1063. ];
  1064. $this->assertHtml($expected, $result);
  1065. $result = $this->Paginator->next('Next', [
  1066. 'templates' => [
  1067. 'nextActive' => '<a rel="next" href="{{url}}">{{text}}</a>',
  1068. ],
  1069. ]);
  1070. $expected = [
  1071. 'a' => ['href' => '/?page=2', 'rel' => 'next'],
  1072. 'Next',
  1073. '/a',
  1074. ];
  1075. $this->assertHtml($expected, $result);
  1076. $result = $this->Paginator->next('Next >>', ['escape' => false]);
  1077. $expected = [
  1078. 'li' => ['class' => 'next'],
  1079. 'a' => ['href' => '/?page=2', 'rel' => 'next'],
  1080. 'preg:/Next >>/',
  1081. '/a',
  1082. '/li',
  1083. ];
  1084. $this->assertHtml($expected, $result);
  1085. }
  1086. /**
  1087. * test next() with disabled links
  1088. */
  1089. public function testNextDisabled(): void
  1090. {
  1091. $this->setPaginatedResult([
  1092. 'currentPage' => 5,
  1093. 'count' => 3,
  1094. 'totalCount' => 13,
  1095. 'hasPrevPage' => true,
  1096. 'hasNextPage' => false,
  1097. 'pageCount' => 5,
  1098. ], false);
  1099. $result = $this->Paginator->next('Next >>');
  1100. $expected = [
  1101. 'li' => ['class' => 'next disabled'],
  1102. 'a' => ['href' => '', 'onclick' => 'return false;'],
  1103. 'Next &gt;&gt;',
  1104. '/a',
  1105. '/li',
  1106. ];
  1107. $this->assertHtml($expected, $result);
  1108. $result = $this->Paginator->next('Next >>', ['disabledTitle' => 'Next']);
  1109. $expected = [
  1110. 'li' => ['class' => 'next disabled'],
  1111. 'a' => ['href' => '', 'onclick' => 'return false;'],
  1112. 'Next',
  1113. '/a',
  1114. '/li',
  1115. ];
  1116. $this->assertHtml($expected, $result);
  1117. $result = $this->Paginator->next('Next >>', ['disabledTitle' => false]);
  1118. $this->assertSame('', $result, 'disabled + no text = no link');
  1119. }
  1120. /**
  1121. * testNumbers method
  1122. */
  1123. public function testNumbers(): void
  1124. {
  1125. $this->setPaginatedResult([
  1126. 'currentPage' => 8,
  1127. 'count' => 3,
  1128. 'totalCount' => 30,
  1129. 'hasPrevPage' => true,
  1130. 'hasNextPage' => true,
  1131. 'pageCount' => 15,
  1132. ], false);
  1133. $result = $this->Paginator->numbers();
  1134. $expected = [
  1135. ['li' => []], ['a' => ['href' => '/?page=4']], '4', '/a', '/li',
  1136. ['li' => []], ['a' => ['href' => '/?page=5']], '5', '/a', '/li',
  1137. ['li' => []], ['a' => ['href' => '/?page=6']], '6', '/a', '/li',
  1138. ['li' => []], ['a' => ['href' => '/?page=7']], '7', '/a', '/li',
  1139. ['li' => ['class' => 'active']], '<a href=""', '8', '/a', '/li',
  1140. ['li' => []], ['a' => ['href' => '/?page=9']], '9', '/a', '/li',
  1141. ['li' => []], ['a' => ['href' => '/?page=10']], '10', '/a', '/li',
  1142. ['li' => []], ['a' => ['href' => '/?page=11']], '11', '/a', '/li',
  1143. ['li' => []], ['a' => ['href' => '/?page=12']], '12', '/a', '/li',
  1144. ];
  1145. $this->assertHtml($expected, $result);
  1146. $result = $this->Paginator->numbers(['first' => 'first', 'last' => 'last']);
  1147. $expected = [
  1148. ['li' => ['class' => 'first']], ['a' => ['href' => '/']], 'first', '/a', '/li',
  1149. ['li' => ['class' => 'ellipsis']], '&hellip;', '/li',
  1150. ['li' => []], ['a' => ['href' => '/?page=4']], '4', '/a', '/li',
  1151. ['li' => []], ['a' => ['href' => '/?page=5']], '5', '/a', '/li',
  1152. ['li' => []], ['a' => ['href' => '/?page=6']], '6', '/a', '/li',
  1153. ['li' => []], ['a' => ['href' => '/?page=7']], '7', '/a', '/li',
  1154. ['li' => ['class' => 'active']], '<a href=""', '8', '/a', '/li',
  1155. ['li' => []], ['a' => ['href' => '/?page=9']], '9', '/a', '/li',
  1156. ['li' => []], ['a' => ['href' => '/?page=10']], '10', '/a', '/li',
  1157. ['li' => []], ['a' => ['href' => '/?page=11']], '11', '/a', '/li',
  1158. ['li' => []], ['a' => ['href' => '/?page=12']], '12', '/a', '/li',
  1159. ['li' => ['class' => 'ellipsis']], '&hellip;', '/li',
  1160. ['li' => ['class' => 'last']], ['a' => ['href' => '/?page=15']], 'last', '/a', '/li',
  1161. ];
  1162. $this->assertHtml($expected, $result);
  1163. $result = $this->Paginator->numbers(['first' => '2', 'last' => '8']);
  1164. $expected = [
  1165. ['li' => ['class' => 'first']], ['a' => ['href' => '/']], '2', '/a', '/li',
  1166. ['li' => ['class' => 'ellipsis']], '&hellip;', '/li',
  1167. ['li' => []], ['a' => ['href' => '/?page=4']], '4', '/a', '/li',
  1168. ['li' => []], ['a' => ['href' => '/?page=5']], '5', '/a', '/li',
  1169. ['li' => []], ['a' => ['href' => '/?page=6']], '6', '/a', '/li',
  1170. ['li' => []], ['a' => ['href' => '/?page=7']], '7', '/a', '/li',
  1171. ['li' => ['class' => 'active']], '<a href=""', '8', '/a', '/li',
  1172. ['li' => []], ['a' => ['href' => '/?page=9']], '9', '/a', '/li',
  1173. ['li' => []], ['a' => ['href' => '/?page=10']], '10', '/a', '/li',
  1174. ['li' => []], ['a' => ['href' => '/?page=11']], '11', '/a', '/li',
  1175. ['li' => []], ['a' => ['href' => '/?page=12']], '12', '/a', '/li',
  1176. ['li' => ['class' => 'ellipsis']], '&hellip;', '/li',
  1177. ['li' => ['class' => 'last']], ['a' => ['href' => '/?page=15']], '8', '/a', '/li',
  1178. ];
  1179. $this->assertHtml($expected, $result);
  1180. $result = $this->Paginator->numbers(['first' => '8', 'last' => '8']);
  1181. $expected = [
  1182. ['li' => ['class' => 'first']], ['a' => ['href' => '/']], '8', '/a', '/li',
  1183. ['li' => ['class' => 'ellipsis']], '&hellip;', '/li',
  1184. ['li' => []], ['a' => ['href' => '/?page=4']], '4', '/a', '/li',
  1185. ['li' => []], ['a' => ['href' => '/?page=5']], '5', '/a', '/li',
  1186. ['li' => []], ['a' => ['href' => '/?page=6']], '6', '/a', '/li',
  1187. ['li' => []], ['a' => ['href' => '/?page=7']], '7', '/a', '/li',
  1188. ['li' => ['class' => 'active']], '<a href=""', '8', '/a', '/li',
  1189. ['li' => []], ['a' => ['href' => '/?page=9']], '9', '/a', '/li',
  1190. ['li' => []], ['a' => ['href' => '/?page=10']], '10', '/a', '/li',
  1191. ['li' => []], ['a' => ['href' => '/?page=11']], '11', '/a', '/li',
  1192. ['li' => []], ['a' => ['href' => '/?page=12']], '12', '/a', '/li',
  1193. ['li' => ['class' => 'ellipsis']], '&hellip;', '/li',
  1194. ['li' => ['class' => 'last']], ['a' => ['href' => '/?page=15']], '8', '/a', '/li',
  1195. ];
  1196. $this->assertHtml($expected, $result);
  1197. $this->setPaginatedResult([
  1198. 'currentPage' => 1,
  1199. 'count' => 3,
  1200. 'totalCount' => 30,
  1201. 'hasPrevPage' => true,
  1202. 'hasNextPage' => true,
  1203. 'pageCount' => 15,
  1204. ], false);
  1205. $result = $this->Paginator->numbers();
  1206. $expected = [
  1207. ['li' => ['class' => 'active']], '<a href=""', '1', '/a', '/li',
  1208. ['li' => []], ['a' => ['href' => '/?page=2']], '2', '/a', '/li',
  1209. ['li' => []], ['a' => ['href' => '/?page=3']], '3', '/a', '/li',
  1210. ['li' => []], ['a' => ['href' => '/?page=4']], '4', '/a', '/li',
  1211. ['li' => []], ['a' => ['href' => '/?page=5']], '5', '/a', '/li',
  1212. ['li' => []], ['a' => ['href' => '/?page=6']], '6', '/a', '/li',
  1213. ['li' => []], ['a' => ['href' => '/?page=7']], '7', '/a', '/li',
  1214. ['li' => []], ['a' => ['href' => '/?page=8']], '8', '/a', '/li',
  1215. ['li' => []], ['a' => ['href' => '/?page=9']], '9', '/a', '/li',
  1216. ];
  1217. $this->assertHtml($expected, $result);
  1218. $this->setPaginatedResult([
  1219. 'currentPage' => 14,
  1220. 'count' => 3,
  1221. 'totalCount' => 30,
  1222. 'hasPrevPage' => true,
  1223. 'hasNextPage' => true,
  1224. 'pageCount' => 15,
  1225. ], false);
  1226. $result = $this->Paginator->numbers();
  1227. $expected = [
  1228. ['li' => []], ['a' => ['href' => '/?page=7']], '7', '/a', '/li',
  1229. ['li' => []], ['a' => ['href' => '/?page=8']], '8', '/a', '/li',
  1230. ['li' => []], ['a' => ['href' => '/?page=9']], '9', '/a', '/li',
  1231. ['li' => []], ['a' => ['href' => '/?page=10']], '10', '/a', '/li',
  1232. ['li' => []], ['a' => ['href' => '/?page=11']], '11', '/a', '/li',
  1233. ['li' => []], ['a' => ['href' => '/?page=12']], '12', '/a', '/li',
  1234. ['li' => []], ['a' => ['href' => '/?page=13']], '13', '/a', '/li',
  1235. ['li' => ['class' => 'active']], '<a href=""', '14', '/a', '/li',
  1236. ['li' => []], ['a' => ['href' => '/?page=15']], '15', '/a', '/li',
  1237. ];
  1238. $this->assertHtml($expected, $result);
  1239. $this->setPaginatedResult([
  1240. 'currentPage' => 2,
  1241. 'count' => 3,
  1242. 'totalCount' => 27,
  1243. 'hasPrevPage' => true,
  1244. 'hasNextPage' => true,
  1245. 'pageCount' => 9,
  1246. ], false);
  1247. $result = $this->Paginator->numbers(['first' => 1]);
  1248. $expected = [
  1249. ['li' => []], ['a' => ['href' => '/']], '1', '/a', '/li',
  1250. ['li' => ['class' => 'active']], '<a href=""', '2', '/a', '/li',
  1251. ['li' => []], ['a' => ['href' => '/?page=3']], '3', '/a', '/li',
  1252. ['li' => []], ['a' => ['href' => '/?page=4']], '4', '/a', '/li',
  1253. ['li' => []], ['a' => ['href' => '/?page=5']], '5', '/a', '/li',
  1254. ['li' => []], ['a' => ['href' => '/?page=6']], '6', '/a', '/li',
  1255. ['li' => []], ['a' => ['href' => '/?page=7']], '7', '/a', '/li',
  1256. ['li' => []], ['a' => ['href' => '/?page=8']], '8', '/a', '/li',
  1257. ['li' => []], ['a' => ['href' => '/?page=9']], '9', '/a', '/li',
  1258. ];
  1259. $this->assertHtml($expected, $result);
  1260. $result = $this->Paginator->numbers(['last' => 1]);
  1261. $expected = [
  1262. ['li' => []], ['a' => ['href' => '/']], '1', '/a', '/li',
  1263. ['li' => ['class' => 'active']], '<a href=""', '2', '/a', '/li',
  1264. ['li' => []], ['a' => ['href' => '/?page=3']], '3', '/a', '/li',
  1265. ['li' => []], ['a' => ['href' => '/?page=4']], '4', '/a', '/li',
  1266. ['li' => []], ['a' => ['href' => '/?page=5']], '5', '/a', '/li',
  1267. ['li' => []], ['a' => ['href' => '/?page=6']], '6', '/a', '/li',
  1268. ['li' => []], ['a' => ['href' => '/?page=7']], '7', '/a', '/li',
  1269. ['li' => []], ['a' => ['href' => '/?page=8']], '8', '/a', '/li',
  1270. ['li' => []], ['a' => ['href' => '/?page=9']], '9', '/a', '/li',
  1271. ];
  1272. $this->assertHtml($expected, $result);
  1273. $this->setPaginatedResult([
  1274. 'currentPage' => 15,
  1275. 'count' => 3,
  1276. 'totalCount' => 30,
  1277. 'hasPrevPage' => true,
  1278. 'hasNextPage' => true,
  1279. 'pageCount' => 15,
  1280. ], false);
  1281. $result = $this->Paginator->numbers(['first' => 1]);
  1282. $expected = [
  1283. ['li' => []], ['a' => ['href' => '/']], '1', '/a', '/li',
  1284. ['li' => ['class' => 'ellipsis']], '&hellip;', '/li',
  1285. ['li' => []], ['a' => ['href' => '/?page=7']], '7', '/a', '/li',
  1286. ['li' => []], ['a' => ['href' => '/?page=8']], '8', '/a', '/li',
  1287. ['li' => []], ['a' => ['href' => '/?page=9']], '9', '/a', '/li',
  1288. ['li' => []], ['a' => ['href' => '/?page=10']], '10', '/a', '/li',
  1289. ['li' => []], ['a' => ['href' => '/?page=11']], '11', '/a', '/li',
  1290. ['li' => []], ['a' => ['href' => '/?page=12']], '12', '/a', '/li',
  1291. ['li' => []], ['a' => ['href' => '/?page=13']], '13', '/a', '/li',
  1292. ['li' => []], ['a' => ['href' => '/?page=14']], '14', '/a', '/li',
  1293. ['li' => ['class' => 'active']], '<a href=""', '15', '/a', '/li',
  1294. ];
  1295. $this->assertHtml($expected, $result);
  1296. $this->setPaginatedResult([
  1297. 'currentPage' => 10,
  1298. 'count' => 3,
  1299. 'totalCount' => 30,
  1300. 'hasPrevPage' => true,
  1301. 'hasNextPage' => true,
  1302. 'pageCount' => 15,
  1303. ], false);
  1304. $result = $this->Paginator->numbers(['first' => 1, 'last' => 1]);
  1305. $expected = [
  1306. ['li' => []], ['a' => ['href' => '/']], '1', '/a', '/li',
  1307. ['li' => ['class' => 'ellipsis']], '&hellip;', '/li',
  1308. ['li' => []], ['a' => ['href' => '/?page=6']], '6', '/a', '/li',
  1309. ['li' => []], ['a' => ['href' => '/?page=7']], '7', '/a', '/li',
  1310. ['li' => []], ['a' => ['href' => '/?page=8']], '8', '/a', '/li',
  1311. ['li' => []], ['a' => ['href' => '/?page=9']], '9', '/a', '/li',
  1312. ['li' => ['class' => 'active']], '<a href=""', '10', '/a', '/li',
  1313. ['li' => []], ['a' => ['href' => '/?page=11']], '11', '/a', '/li',
  1314. ['li' => []], ['a' => ['href' => '/?page=12']], '12', '/a', '/li',
  1315. ['li' => []], ['a' => ['href' => '/?page=13']], '13', '/a', '/li',
  1316. ['li' => []], ['a' => ['href' => '/?page=14']], '14', '/a', '/li',
  1317. ['li' => []], ['a' => ['href' => '/?page=15']], '15', '/a', '/li',
  1318. ];
  1319. $this->assertHtml($expected, $result);
  1320. $this->setPaginatedResult([
  1321. 'currentPage' => 6,
  1322. 'count' => 15,
  1323. 'totalCount' => 623,
  1324. 'hasPrevPage' => true,
  1325. 'hasNextPage' => true,
  1326. 'pageCount' => 42,
  1327. ], false);
  1328. $result = $this->Paginator->numbers(['first' => 1, 'last' => 1]);
  1329. $expected = [
  1330. ['li' => []], ['a' => ['href' => '/']], '1', '/a', '/li',
  1331. ['li' => []], ['a' => ['href' => '/?page=2']], '2', '/a', '/li',
  1332. ['li' => []], ['a' => ['href' => '/?page=3']], '3', '/a', '/li',
  1333. ['li' => []], ['a' => ['href' => '/?page=4']], '4', '/a', '/li',
  1334. ['li' => []], ['a' => ['href' => '/?page=5']], '5', '/a', '/li',
  1335. ['li' => ['class' => 'active']], '<a href=""', '6', '/a', '/li',
  1336. ['li' => []], ['a' => ['href' => '/?page=7']], '7', '/a', '/li',
  1337. ['li' => []], ['a' => ['href' => '/?page=8']], '8', '/a', '/li',
  1338. ['li' => []], ['a' => ['href' => '/?page=9']], '9', '/a', '/li',
  1339. ['li' => []], ['a' => ['href' => '/?page=10']], '10', '/a', '/li',
  1340. ['li' => ['class' => 'ellipsis']], '&hellip;', '/li',
  1341. ['li' => []], ['a' => ['href' => '/?page=42']], '42', '/a', '/li',
  1342. ];
  1343. $this->assertHtml($expected, $result);
  1344. $this->setPaginatedResult([
  1345. 'currentPage' => 37,
  1346. 'count' => 15,
  1347. 'totalCount' => 623,
  1348. 'hasPrevPage' => true,
  1349. 'hasNextPage' => true,
  1350. 'pageCount' => 42,
  1351. ], false);
  1352. $result = $this->Paginator->numbers(['first' => 1, 'last' => 1]);
  1353. $expected = [
  1354. ['li' => []], ['a' => ['href' => '/']], '1', '/a', '/li',
  1355. ['li' => ['class' => 'ellipsis']], '&hellip;', '/li',
  1356. ['li' => []], ['a' => ['href' => '/?page=33']], '33', '/a', '/li',
  1357. ['li' => []], ['a' => ['href' => '/?page=34']], '34', '/a', '/li',
  1358. ['li' => []], ['a' => ['href' => '/?page=35']], '35', '/a', '/li',
  1359. ['li' => []], ['a' => ['href' => '/?page=36']], '36', '/a', '/li',
  1360. ['li' => ['class' => 'active']], '<a href=""', '37', '/a', '/li',
  1361. ['li' => []], ['a' => ['href' => '/?page=38']], '38', '/a', '/li',
  1362. ['li' => []], ['a' => ['href' => '/?page=39']], '39', '/a', '/li',
  1363. ['li' => []], ['a' => ['href' => '/?page=40']], '40', '/a', '/li',
  1364. ['li' => []], ['a' => ['href' => '/?page=41']], '41', '/a', '/li',
  1365. ['li' => []], ['a' => ['href' => '/?page=42']], '42', '/a', '/li',
  1366. ];
  1367. $this->assertHtml($expected, $result);
  1368. }
  1369. /**
  1370. * Test for URLs with paging params as route placeholders instead of query string params.
  1371. */
  1372. public function testRoutePlaceholder(): void
  1373. {
  1374. Router::reload();
  1375. Router::createRouteBuilder('/')->connect('/{controller}/{action}/{page}');
  1376. $request = $this->View
  1377. ->getRequest()
  1378. ->withAttribute('params', [
  1379. 'plugin' => null,
  1380. 'controller' => 'Clients',
  1381. 'action' => 'index',
  1382. ]);
  1383. $this->View->setRequest($request);
  1384. Router::setRequest($request);
  1385. $this->setPaginatedResult([
  1386. 'currentPage' => 8,
  1387. 'count' => 3,
  1388. 'totalCount' => 30,
  1389. 'hasPrevPage' => true,
  1390. 'hasNextPage' => true,
  1391. 'pageCount' => 15,
  1392. ], false);
  1393. $this->Paginator->options(['routePlaceholders' => ['page']]);
  1394. $result = $this->Paginator->numbers();
  1395. $expected = [
  1396. ['li' => []], ['a' => ['href' => '/Clients/index/4']], '4', '/a', '/li',
  1397. ['li' => []], ['a' => ['href' => '/Clients/index/5']], '5', '/a', '/li',
  1398. ['li' => []], ['a' => ['href' => '/Clients/index/6']], '6', '/a', '/li',
  1399. ['li' => []], ['a' => ['href' => '/Clients/index/7']], '7', '/a', '/li',
  1400. ['li' => ['class' => 'active']], '<a href=""', '8', '/a', '/li',
  1401. ['li' => []], ['a' => ['href' => '/Clients/index/9']], '9', '/a', '/li',
  1402. ['li' => []], ['a' => ['href' => '/Clients/index/10']], '10', '/a', '/li',
  1403. ['li' => []], ['a' => ['href' => '/Clients/index/11']], '11', '/a', '/li',
  1404. ['li' => []], ['a' => ['href' => '/Clients/index/12']], '12', '/a', '/li',
  1405. ];
  1406. $this->assertHtml($expected, $result);
  1407. Router::reload();
  1408. Router::createRouteBuilder('/')->connect('/{controller}/{action}/{sort}/{direction}');
  1409. Router::setRequest($request);
  1410. $this->Paginator->options(['routePlaceholders' => ['sort', 'direction']]);
  1411. $result = $this->Paginator->sort('title');
  1412. $expected = [
  1413. 'a' => ['href' => '/Clients/index/title/asc'],
  1414. 'Title',
  1415. '/a',
  1416. ];
  1417. $this->assertHtml($expected, $result);
  1418. }
  1419. /**
  1420. * testNumbersPages method
  1421. */
  1422. public function testNumbersMulti(): void
  1423. {
  1424. $expected = [
  1425. 1 => '*1 2 3 4 5 6 7 ',
  1426. 2 => '1 *2 3 4 5 6 7 ',
  1427. 3 => '1 2 *3 4 5 6 7 ',
  1428. 4 => '1 2 3 *4 5 6 7 ',
  1429. 5 => '1 2 3 4 *5 6 7 ',
  1430. 6 => '1 2 3 4 5 *6 7 ',
  1431. 7 => '1 2 3 4 5 6 *7 ',
  1432. ];
  1433. $result = $this->getNumbersForMultiplePages(array_keys($expected), 7);
  1434. $this->assertEquals($expected, $result);
  1435. $result = $this->getNumbersForMultiplePages(array_keys($expected), 7, ['first' => 'F', 'last' => 'L']);
  1436. $this->assertEquals($expected, $result);
  1437. $expected = [
  1438. 1 => '*1 2 3 4 5 6 7 8 9 ',
  1439. 2 => '1 *2 3 4 5 6 7 8 9 ',
  1440. 3 => '1 2 *3 4 5 6 7 8 9 ',
  1441. 4 => '1 2 3 *4 5 6 7 8 9 ',
  1442. 5 => '1 2 3 4 *5 6 7 8 9 ',
  1443. 6 => '2 3 4 5 *6 7 8 9 10 ',
  1444. 7 => '3 4 5 6 *7 8 9 10 11 ',
  1445. 10 => '6 7 8 9 *10 11 12 13 14 ',
  1446. 15 => '11 12 13 14 *15 16 17 18 19 ',
  1447. 16 => '12 13 14 15 *16 17 18 19 20 ',
  1448. 17 => '12 13 14 15 16 *17 18 19 20 ',
  1449. 18 => '12 13 14 15 16 17 *18 19 20 ',
  1450. 19 => '12 13 14 15 16 17 18 *19 20 ',
  1451. 20 => '12 13 14 15 16 17 18 19 *20 ',
  1452. ];
  1453. $result = $this->getNumbersForMultiplePages(array_keys($expected), 20);
  1454. $this->assertEquals($expected, $result);
  1455. $expected = [
  1456. 1 => '*1 2 3 4 5 6 7 8 9 ',
  1457. 2 => '1 *2 3 4 5 6 7 8 9 ',
  1458. 3 => '1 2 *3 4 5 6 7 8 9 ',
  1459. 4 => '1 2 3 *4 5 6 7 8 9 ',
  1460. 5 => '1 2 3 4 *5 6 7 8 9 ',
  1461. 6 => '1 2 3 4 5 *6 7 8 9 10 ',
  1462. 7 => '1 2 3 4 5 6 *7 8 9 10 11 ',
  1463. 8 => '<F ... 4 5 6 7 *8 9 10 11 12 ',
  1464. 9 => '<F ... 5 6 7 8 *9 10 11 12 13 ',
  1465. 10 => '<F ... 6 7 8 9 *10 11 12 13 14 ',
  1466. 15 => '<F ... 11 12 13 14 *15 16 17 18 19 ',
  1467. 16 => '<F ... 12 13 14 15 *16 17 18 19 20 ',
  1468. 17 => '<F ... 12 13 14 15 16 *17 18 19 20 ',
  1469. 18 => '<F ... 12 13 14 15 16 17 *18 19 20 ',
  1470. 19 => '<F ... 12 13 14 15 16 17 18 *19 20 ',
  1471. 20 => '<F ... 12 13 14 15 16 17 18 19 *20 ',
  1472. ];
  1473. $result = $this->getNumbersForMultiplePages(array_keys($expected), 20, ['first' => 'F']);
  1474. $this->assertEquals($expected, $result);
  1475. $expected = [
  1476. 1 => '*1 2 3 4 5 6 7 8 9 ',
  1477. 2 => '1 *2 3 4 5 6 7 8 9 ',
  1478. 3 => '1 2 *3 4 5 6 7 8 9 ',
  1479. 4 => '1 2 3 *4 5 6 7 8 9 ',
  1480. 5 => '1 2 3 4 *5 6 7 8 9 ',
  1481. 6 => '1 2 3 4 5 *6 7 8 9 10 ',
  1482. 7 => '1 2 3 4 5 6 *7 8 9 10 11 ',
  1483. 8 => '1 2 3 4 5 6 7 *8 9 10 11 12 ',
  1484. 9 => '1 2 ... 5 6 7 8 *9 10 11 12 13 ',
  1485. 10 => '1 2 ... 6 7 8 9 *10 11 12 13 14 ',
  1486. 15 => '1 2 ... 11 12 13 14 *15 16 17 18 19 ',
  1487. 16 => '1 2 ... 12 13 14 15 *16 17 18 19 20 ',
  1488. 17 => '1 2 ... 12 13 14 15 16 *17 18 19 20 ',
  1489. 18 => '1 2 ... 12 13 14 15 16 17 *18 19 20 ',
  1490. 19 => '1 2 ... 12 13 14 15 16 17 18 *19 20 ',
  1491. 20 => '1 2 ... 12 13 14 15 16 17 18 19 *20 ',
  1492. ];
  1493. $result = $this->getNumbersForMultiplePages(array_keys($expected), 20, ['first' => 2]);
  1494. $this->assertEquals($expected, $result);
  1495. $expected = [
  1496. 1 => '*1 2 3 4 5 6 7 8 9 ... L> ',
  1497. 2 => '1 *2 3 4 5 6 7 8 9 ... L> ',
  1498. 3 => '1 2 *3 4 5 6 7 8 9 ... L> ',
  1499. 4 => '1 2 3 *4 5 6 7 8 9 ... L> ',
  1500. 5 => '1 2 3 4 *5 6 7 8 9 ... L> ',
  1501. 6 => '2 3 4 5 *6 7 8 9 10 ... L> ',
  1502. 7 => '3 4 5 6 *7 8 9 10 11 ... L> ',
  1503. 8 => '4 5 6 7 *8 9 10 11 12 ... L> ',
  1504. 9 => '5 6 7 8 *9 10 11 12 13 ... L> ',
  1505. 10 => '6 7 8 9 *10 11 12 13 14 ... L> ',
  1506. 11 => '7 8 9 10 *11 12 13 14 15 ... L> ',
  1507. 12 => '8 9 10 11 *12 13 14 15 16 ... L> ',
  1508. 13 => '9 10 11 12 *13 14 15 16 17 ... L> ',
  1509. 14 => '10 11 12 13 *14 15 16 17 18 19 20 ',
  1510. 15 => '11 12 13 14 *15 16 17 18 19 20 ',
  1511. 16 => '12 13 14 15 *16 17 18 19 20 ',
  1512. 17 => '12 13 14 15 16 *17 18 19 20 ',
  1513. 18 => '12 13 14 15 16 17 *18 19 20 ',
  1514. 19 => '12 13 14 15 16 17 18 *19 20 ',
  1515. 20 => '12 13 14 15 16 17 18 19 *20 ',
  1516. ];
  1517. $result = $this->getNumbersForMultiplePages(array_keys($expected), 20, ['last' => 'L']);
  1518. $this->assertEquals($expected, $result);
  1519. $expected = [
  1520. 1 => '*1 2 3 4 5 6 7 8 9 ... L> ',
  1521. 2 => '1 *2 3 4 5 6 7 8 9 ... L> ',
  1522. 3 => '1 2 *3 4 5 6 7 8 9 ... L> ',
  1523. 4 => '1 2 3 *4 5 6 7 8 9 ... L> ',
  1524. 5 => '1 2 3 4 *5 6 7 8 9 ... L> ',
  1525. 6 => '1 2 3 4 5 *6 7 8 9 10 ... L> ',
  1526. 7 => '1 2 3 4 5 6 *7 8 9 10 11 ... L> ',
  1527. 8 => '<F ... 4 5 6 7 *8 9 10 11 12 ... L> ',
  1528. 9 => '<F ... 5 6 7 8 *9 10 11 12 13 ... L> ',
  1529. 10 => '<F ... 6 7 8 9 *10 11 12 13 14 ... L> ',
  1530. 11 => '<F ... 7 8 9 10 *11 12 13 14 15 ... L> ',
  1531. 12 => '<F ... 8 9 10 11 *12 13 14 15 16 ... L> ',
  1532. 13 => '<F ... 9 10 11 12 *13 14 15 16 17 ... L> ',
  1533. 14 => '<F ... 10 11 12 13 *14 15 16 17 18 19 20 ',
  1534. 15 => '<F ... 11 12 13 14 *15 16 17 18 19 20 ',
  1535. 16 => '<F ... 12 13 14 15 *16 17 18 19 20 ',
  1536. 17 => '<F ... 12 13 14 15 16 *17 18 19 20 ',
  1537. 18 => '<F ... 12 13 14 15 16 17 *18 19 20 ',
  1538. 19 => '<F ... 12 13 14 15 16 17 18 *19 20 ',
  1539. 20 => '<F ... 12 13 14 15 16 17 18 19 *20 ',
  1540. ];
  1541. $result = $this->getNumbersForMultiplePages(array_keys($expected), 20, ['first' => 'F', 'last' => 'L']);
  1542. $this->assertEquals($expected, $result);
  1543. $expected = [
  1544. 1 => '*1 2 3 4 5 6 7 8 9 ... 19 20 ',
  1545. 2 => '1 *2 3 4 5 6 7 8 9 ... 19 20 ',
  1546. 3 => '1 2 *3 4 5 6 7 8 9 ... 19 20 ',
  1547. 4 => '1 2 3 *4 5 6 7 8 9 ... 19 20 ',
  1548. 5 => '1 2 3 4 *5 6 7 8 9 ... 19 20 ',
  1549. 6 => '1 2 3 4 5 *6 7 8 9 10 ... 19 20 ',
  1550. 7 => '1 2 3 4 5 6 *7 8 9 10 11 ... 19 20 ',
  1551. 8 => '1 2 3 4 5 6 7 *8 9 10 11 12 ... 19 20 ',
  1552. 9 => '1 2 ... 5 6 7 8 *9 10 11 12 13 ... 19 20 ',
  1553. 10 => '1 2 ... 6 7 8 9 *10 11 12 13 14 ... 19 20 ',
  1554. 11 => '1 2 ... 7 8 9 10 *11 12 13 14 15 ... 19 20 ',
  1555. 12 => '1 2 ... 8 9 10 11 *12 13 14 15 16 ... 19 20 ',
  1556. 13 => '1 2 ... 9 10 11 12 *13 14 15 16 17 18 19 20 ',
  1557. 14 => '1 2 ... 10 11 12 13 *14 15 16 17 18 19 20 ',
  1558. 15 => '1 2 ... 11 12 13 14 *15 16 17 18 19 20 ',
  1559. 16 => '1 2 ... 12 13 14 15 *16 17 18 19 20 ',
  1560. 17 => '1 2 ... 12 13 14 15 16 *17 18 19 20 ',
  1561. 18 => '1 2 ... 12 13 14 15 16 17 *18 19 20 ',
  1562. 19 => '1 2 ... 12 13 14 15 16 17 18 *19 20 ',
  1563. 20 => '1 2 ... 12 13 14 15 16 17 18 19 *20 ',
  1564. ];
  1565. $result = $this->getNumbersForMultiplePages(array_keys($expected), 20, ['first' => 2, 'last' => 2]);
  1566. $this->assertEquals($expected, $result);
  1567. $expected = [
  1568. 1 => '*1 2 3 4 5 6 7 8 9 ... 19 20 ',
  1569. 2 => '1 *2 3 4 5 6 7 8 9 ... 19 20 ',
  1570. 3 => '1 2 *3 4 5 6 7 8 9 ... 19 20 ',
  1571. 4 => '1 2 3 *4 5 6 7 8 9 ... 19 20 ',
  1572. 5 => '1 2 3 4 *5 6 7 8 9 ... 19 20 ',
  1573. 6 => '2 3 4 5 *6 7 8 9 10 ... 19 20 ',
  1574. 7 => '3 4 5 6 *7 8 9 10 11 ... 19 20 ',
  1575. 8 => '4 5 6 7 *8 9 10 11 12 ... 19 20 ',
  1576. 9 => '5 6 7 8 *9 10 11 12 13 ... 19 20 ',
  1577. 10 => '6 7 8 9 *10 11 12 13 14 ... 19 20 ',
  1578. 11 => '7 8 9 10 *11 12 13 14 15 ... 19 20 ',
  1579. 12 => '8 9 10 11 *12 13 14 15 16 ... 19 20 ',
  1580. 13 => '9 10 11 12 *13 14 15 16 17 18 19 20 ',
  1581. 14 => '10 11 12 13 *14 15 16 17 18 19 20 ',
  1582. 15 => '11 12 13 14 *15 16 17 18 19 20 ',
  1583. 16 => '12 13 14 15 *16 17 18 19 20 ',
  1584. 17 => '12 13 14 15 16 *17 18 19 20 ',
  1585. 18 => '12 13 14 15 16 17 *18 19 20 ',
  1586. 19 => '12 13 14 15 16 17 18 *19 20 ',
  1587. 20 => '12 13 14 15 16 17 18 19 *20 ',
  1588. ];
  1589. $result = $this->getNumbersForMultiplePages(array_keys($expected), 20, ['last' => 2]);
  1590. $this->assertEquals($expected, $result);
  1591. }
  1592. /**
  1593. * Retrieves result of PaginatorHelper::numbers for multiple pages
  1594. *
  1595. * @param int[] $pagesToCheck Pages to get result for
  1596. * @param int $pageCount Number of total pages
  1597. * @param array $options Options for PaginatorHelper::numbers
  1598. * @return string[]
  1599. */
  1600. protected function getNumbersForMultiplePages($pagesToCheck, $pageCount, $options = []): array
  1601. {
  1602. $options['templates'] = [
  1603. 'first' => '<{{text}} ',
  1604. 'last' => '{{text}}> ',
  1605. 'number' => '{{text}} ',
  1606. 'current' => '*{{text}} ',
  1607. 'ellipsis' => '... ',
  1608. ];
  1609. $params = [
  1610. 'currentPage' => 1,
  1611. 'pageCount' => $pageCount,
  1612. ];
  1613. $result = [];
  1614. foreach ($pagesToCheck as $page) {
  1615. $params['currentPage'] = $page;
  1616. $this->setPaginatedResult($params, false);
  1617. $result[$page] = $this->Paginator->numbers($options);
  1618. }
  1619. return $result;
  1620. }
  1621. /**
  1622. * Test that numbers() lets you overwrite templates.
  1623. *
  1624. * The templates file has no li elements.
  1625. */
  1626. public function testNumbersTemplates(): void
  1627. {
  1628. $this->setPaginatedResult([
  1629. 'currentPage' => 8,
  1630. 'count' => 3,
  1631. 'totalCount' => 30,
  1632. 'hasPrevPage' => true,
  1633. 'hasNextPage' => true,
  1634. 'pageCount' => 15,
  1635. ], false);
  1636. $result = $this->Paginator->numbers(['templates' => 'htmlhelper_tags']);
  1637. $expected = [
  1638. ['a' => ['href' => '/?page=4']], '4', '/a',
  1639. ['a' => ['href' => '/?page=5']], '5', '/a',
  1640. ['a' => ['href' => '/?page=6']], '6', '/a',
  1641. ['a' => ['href' => '/?page=7']], '7', '/a',
  1642. 'span' => ['class' => 'active'], '8', '/span',
  1643. ['a' => ['href' => '/?page=9']], '9', '/a',
  1644. ['a' => ['href' => '/?page=10']], '10', '/a',
  1645. ['a' => ['href' => '/?page=11']], '11', '/a',
  1646. ['a' => ['href' => '/?page=12']], '12', '/a',
  1647. ];
  1648. $this->assertHtml($expected, $result);
  1649. $this->assertStringContainsString(
  1650. '<li',
  1651. $this->Paginator->templater()->get('current'),
  1652. 'Templates were not restored.'
  1653. );
  1654. }
  1655. /**
  1656. * Test modulus option for numbers()
  1657. */
  1658. public function testNumbersModulus(): void
  1659. {
  1660. $this->setPaginatedResult([
  1661. 'currentPage' => 1,
  1662. 'count' => 10,
  1663. 'totalCount' => 30,
  1664. 'hasPrevPage' => false,
  1665. 'hasNextPage' => true,
  1666. 'pageCount' => 3,
  1667. ]);
  1668. $result = $this->Paginator->numbers(['modulus' => 10]);
  1669. $expected = [
  1670. ['li' => ['class' => 'active']], '<a href=""', '1', '/a', '/li',
  1671. ['li' => []], ['a' => ['href' => '/?page=2']], '2', '/a', '/li',
  1672. ['li' => []], ['a' => ['href' => '/?page=3']], '3', '/a', '/li',
  1673. ];
  1674. $this->assertHtml($expected, $result);
  1675. $result = $this->Paginator->numbers(['modulus' => 3]);
  1676. $expected = [
  1677. ['li' => ['class' => 'active']], '<a href=""', '1', '/a', '/li',
  1678. ['li' => []], ['a' => ['href' => '/?page=2']], '2', '/a', '/li',
  1679. ['li' => []], ['a' => ['href' => '/?page=3']], '3', '/a', '/li',
  1680. ];
  1681. $this->assertHtml($expected, $result);
  1682. $this->setPaginatedResult([
  1683. 'currentPage' => 4895,
  1684. 'count' => 10,
  1685. 'totalCount' => 48962,
  1686. 'hasPrevPage' => true,
  1687. 'hasNextPage' => true,
  1688. 'pageCount' => 4897,
  1689. ], false);
  1690. $result = $this->Paginator->numbers(['first' => 2, 'modulus' => 2, 'last' => 2]);
  1691. $expected = [
  1692. ['li' => []], ['a' => ['href' => '/']], '1', '/a', '/li',
  1693. ['li' => []], ['a' => ['href' => '/?page=2']], '2', '/a', '/li',
  1694. ['li' => ['class' => 'ellipsis']], '&hellip;', '/li',
  1695. ['li' => []], ['a' => ['href' => '/?page=4894']], '4,894', '/a', '/li',
  1696. ['li' => ['class' => 'active']], '<a href=""', '4,895', '/a', '/li',
  1697. ['li' => []], ['a' => ['href' => '/?page=4896']], '4,896', '/a', '/li',
  1698. ['li' => []], ['a' => ['href' => '/?page=4897']], '4,897', '/a', '/li',
  1699. ];
  1700. $this->assertHtml($expected, $result);
  1701. $this->setPaginatedResult([
  1702. 'currentPage' => 3,
  1703. 'pageCount' => 4897,
  1704. ], false);
  1705. $result = $this->Paginator->numbers(['first' => 2, 'modulus' => 2, 'last' => 2]);
  1706. $expected = [
  1707. ['li' => []], ['a' => ['href' => '/']], '1', '/a', '/li',
  1708. ['li' => []], ['a' => ['href' => '/?page=2']], '2', '/a', '/li',
  1709. ['li' => ['class' => 'active']], '<a href=""', '3', '/a', '/li',
  1710. ['li' => []], ['a' => ['href' => '/?page=4']], '4', '/a', '/li',
  1711. ['li' => ['class' => 'ellipsis']], '&hellip;', '/li',
  1712. ['li' => []], ['a' => ['href' => '/?page=4896']], '4,896', '/a', '/li',
  1713. ['li' => []], ['a' => ['href' => '/?page=4897']], '4,897', '/a', '/li',
  1714. ];
  1715. $this->assertHtml($expected, $result);
  1716. $result = $this->Paginator->numbers(['first' => 5, 'modulus' => 5, 'last' => 5]);
  1717. $expected = [
  1718. ['li' => []], ['a' => ['href' => '/']], '1', '/a', '/li',
  1719. ['li' => []], ['a' => ['href' => '/?page=2']], '2', '/a', '/li',
  1720. ['li' => ['class' => 'active']], '<a href=""', '3', '/a', '/li',
  1721. ['li' => []], ['a' => ['href' => '/?page=4']], '4', '/a', '/li',
  1722. ['li' => []], ['a' => ['href' => '/?page=5']], '5', '/a', '/li',
  1723. ['li' => []], ['a' => ['href' => '/?page=6']], '6', '/a', '/li',
  1724. ['li' => ['class' => 'ellipsis']], '&hellip;', '/li',
  1725. ['li' => []], ['a' => ['href' => '/?page=4893']], '4,893', '/a', '/li',
  1726. ['li' => []], ['a' => ['href' => '/?page=4894']], '4,894', '/a', '/li',
  1727. ['li' => []], ['a' => ['href' => '/?page=4895']], '4,895', '/a', '/li',
  1728. ['li' => []], ['a' => ['href' => '/?page=4896']], '4,896', '/a', '/li',
  1729. ['li' => []], ['a' => ['href' => '/?page=4897']], '4,897', '/a', '/li',
  1730. ];
  1731. $this->assertHtml($expected, $result);
  1732. $this->setPaginatedResult([
  1733. 'currentPage' => 4893,
  1734. 'pageCount' => 4897,
  1735. ]);
  1736. $result = $this->Paginator->numbers(['first' => 5, 'modulus' => 4, 'last' => 5]);
  1737. $expected = [
  1738. ['li' => []], ['a' => ['href' => '/']], '1', '/a', '/li',
  1739. ['li' => []], ['a' => ['href' => '/?page=2']], '2', '/a', '/li',
  1740. ['li' => []], ['a' => ['href' => '/?page=3']], '3', '/a', '/li',
  1741. ['li' => []], ['a' => ['href' => '/?page=4']], '4', '/a', '/li',
  1742. ['li' => []], ['a' => ['href' => '/?page=5']], '5', '/a', '/li',
  1743. ['li' => ['class' => 'ellipsis']], '&hellip;', '/li',
  1744. ['li' => []], ['a' => ['href' => '/?page=4891']], '4,891', '/a', '/li',
  1745. ['li' => []], ['a' => ['href' => '/?page=4892']], '4,892', '/a', '/li',
  1746. ['li' => ['class' => 'active']], '<a href=""', '4,893', '/a', '/li',
  1747. ['li' => []], ['a' => ['href' => '/?page=4894']], '4,894', '/a', '/li',
  1748. ['li' => []], ['a' => ['href' => '/?page=4895']], '4,895', '/a', '/li',
  1749. ['li' => []], ['a' => ['href' => '/?page=4896']], '4,896', '/a', '/li',
  1750. ['li' => []], ['a' => ['href' => '/?page=4897']], '4,897', '/a', '/li',
  1751. ];
  1752. $this->assertHtml($expected, $result);
  1753. $this->setPaginatedResult([
  1754. 'currentPage' => 58,
  1755. 'pageCount' => 4897,
  1756. ]);
  1757. $result = $this->Paginator->numbers(['first' => 5, 'modulus' => 4, 'last' => 5]);
  1758. $expected = [
  1759. ['li' => []], ['a' => ['href' => '/']], '1', '/a', '/li',
  1760. ['li' => []], ['a' => ['href' => '/?page=2']], '2', '/a', '/li',
  1761. ['li' => []], ['a' => ['href' => '/?page=3']], '3', '/a', '/li',
  1762. ['li' => []], ['a' => ['href' => '/?page=4']], '4', '/a', '/li',
  1763. ['li' => []], ['a' => ['href' => '/?page=5']], '5', '/a', '/li',
  1764. ['li' => ['class' => 'ellipsis']], '&hellip;', '/li',
  1765. ['li' => []], ['a' => ['href' => '/?page=56']], '56', '/a', '/li',
  1766. ['li' => []], ['a' => ['href' => '/?page=57']], '57', '/a', '/li',
  1767. ['li' => ['class' => 'active']], '<a href=""', '58', '/a', '/li',
  1768. ['li' => []], ['a' => ['href' => '/?page=59']], '59', '/a', '/li',
  1769. ['li' => []], ['a' => ['href' => '/?page=60']], '60', '/a', '/li',
  1770. ['li' => ['class' => 'ellipsis']], '&hellip;', '/li',
  1771. ['li' => []], ['a' => ['href' => '/?page=4893']], '4,893', '/a', '/li',
  1772. ['li' => []], ['a' => ['href' => '/?page=4894']], '4,894', '/a', '/li',
  1773. ['li' => []], ['a' => ['href' => '/?page=4895']], '4,895', '/a', '/li',
  1774. ['li' => []], ['a' => ['href' => '/?page=4896']], '4,896', '/a', '/li',
  1775. ['li' => []], ['a' => ['href' => '/?page=4897']], '4,897', '/a', '/li',
  1776. ];
  1777. $this->assertHtml($expected, $result);
  1778. $this->setPaginatedResult([
  1779. 'currentPage' => 5,
  1780. 'pageCount' => 4897,
  1781. ]);
  1782. $result = $this->Paginator->numbers(['first' => 5, 'modulus' => 4, 'last' => 5]);
  1783. $expected = [
  1784. ['li' => []], ['a' => ['href' => '/']], '1', '/a', '/li',
  1785. ['li' => []], ['a' => ['href' => '/?page=2']], '2', '/a', '/li',
  1786. ['li' => []], ['a' => ['href' => '/?page=3']], '3', '/a', '/li',
  1787. ['li' => []], ['a' => ['href' => '/?page=4']], '4', '/a', '/li',
  1788. ['li' => ['class' => 'active']], '<a href=""', '5', '/a', '/li',
  1789. ['li' => []], ['a' => ['href' => '/?page=6']], '6', '/a', '/li',
  1790. ['li' => []], ['a' => ['href' => '/?page=7']], '7', '/a', '/li',
  1791. ['li' => ['class' => 'ellipsis']], '&hellip;', '/li',
  1792. ['li' => []], ['a' => ['href' => '/?page=4893']], '4,893', '/a', '/li',
  1793. ['li' => []], ['a' => ['href' => '/?page=4894']], '4,894', '/a', '/li',
  1794. ['li' => []], ['a' => ['href' => '/?page=4895']], '4,895', '/a', '/li',
  1795. ['li' => []], ['a' => ['href' => '/?page=4896']], '4,896', '/a', '/li',
  1796. ['li' => []], ['a' => ['href' => '/?page=4897']], '4,897', '/a', '/li',
  1797. ];
  1798. $this->assertHtml($expected, $result);
  1799. $this->setPaginatedResult([
  1800. 'currentPage' => 3,
  1801. 'pageCount' => 4897,
  1802. ]);
  1803. $result = $this->Paginator->numbers(['first' => 2, 'modulus' => 2, 'last' => 2]);
  1804. $expected = [
  1805. ['li' => []], ['a' => ['href' => '/']], '1', '/a', '/li',
  1806. ['li' => []], ['a' => ['href' => '/?page=2']], '2', '/a', '/li',
  1807. ['li' => ['class' => 'active']], '<a href=""', '3', '/a', '/li',
  1808. ['li' => []], ['a' => ['href' => '/?page=4']], '4', '/a', '/li',
  1809. ['li' => ['class' => 'ellipsis']], '&hellip;', '/li',
  1810. ['li' => []], ['a' => ['href' => '/?page=4896']], '4,896', '/a', '/li',
  1811. ['li' => []], ['a' => ['href' => '/?page=4897']], '4,897', '/a', '/li',
  1812. ];
  1813. $this->assertHtml($expected, $result);
  1814. $result = $this->Paginator->numbers(['first' => 2, 'modulus' => 0, 'last' => 2]);
  1815. $expected = [
  1816. ['li' => []], ['a' => ['href' => '/']], '1', '/a', '/li',
  1817. ['li' => []], ['a' => ['href' => '/?page=2']], '2', '/a', '/li',
  1818. ['li' => ['class' => 'active']], '<a href=""', '3', '/a', '/li',
  1819. ['li' => ['class' => 'ellipsis']], '&hellip;', '/li',
  1820. ['li' => []], ['a' => ['href' => '/?page=4896']], '4,896', '/a', '/li',
  1821. ['li' => []], ['a' => ['href' => '/?page=4897']], '4,897', '/a', '/li',
  1822. ];
  1823. $this->assertHtml($expected, $result);
  1824. }
  1825. /**
  1826. * Test modulus option for numbers()
  1827. */
  1828. public function testNumbersModulusMulti(): void
  1829. {
  1830. $expected = [
  1831. 1 => '*1 2 3 4 ',
  1832. 2 => '1 *2 3 4 ',
  1833. 3 => '1 2 *3 4 ',
  1834. 4 => '2 3 *4 5 ',
  1835. 5 => '3 4 *5 6 ',
  1836. 6 => '4 5 *6 7 ',
  1837. 7 => '4 5 6 *7 ',
  1838. ];
  1839. $result = $this->getNumbersForMultiplePages(array_keys($expected), 7, ['modulus' => 3]);
  1840. $this->assertEquals($expected, $result);
  1841. $expected = [
  1842. 1 => '*1 2 3 4 ... L> ',
  1843. 2 => '1 *2 3 4 ... L> ',
  1844. 3 => '1 2 *3 4 ... L> ',
  1845. 4 => '1 2 3 *4 5 6 7 ',
  1846. 5 => '1 2 3 4 *5 6 7 ',
  1847. 6 => '<F ... 4 5 *6 7 ',
  1848. 7 => '<F ... 4 5 6 *7 ',
  1849. ];
  1850. $result = $this->getNumbersForMultiplePages(array_keys($expected), 7, ['modulus' => 3, 'first' => 'F', 'last' => 'L']);
  1851. $this->assertEquals($expected, $result);
  1852. $expected = [
  1853. 1 => '*1 2 3 ... 19 20 ',
  1854. 2 => '1 *2 3 ... 19 20 ',
  1855. 3 => '1 2 *3 4 ... 19 20 ',
  1856. 4 => '1 2 3 *4 5 ... 19 20 ',
  1857. 5 => '1 2 3 4 *5 6 ... 19 20 ',
  1858. 6 => '1 2 ... 5 *6 7 ... 19 20 ',
  1859. 15 => '1 2 ... 14 *15 16 ... 19 20 ',
  1860. 16 => '1 2 ... 15 *16 17 18 19 20 ',
  1861. 17 => '1 2 ... 16 *17 18 19 20 ',
  1862. 18 => '1 2 ... 17 *18 19 20 ',
  1863. 19 => '1 2 ... 18 *19 20 ',
  1864. 20 => '1 2 ... 18 19 *20 ',
  1865. ];
  1866. $result = $this->getNumbersForMultiplePages(array_keys($expected), 20, ['first' => 2, 'modulus' => 2, 'last' => 2]);
  1867. $this->assertEquals($expected, $result);
  1868. $expected = [
  1869. 1 => '*1 2 3 4 5 ... 16 17 18 19 20 ',
  1870. 2 => '1 *2 3 4 5 ... 16 17 18 19 20 ',
  1871. 3 => '1 2 *3 4 5 ... 16 17 18 19 20 ',
  1872. 4 => '1 2 3 *4 5 6 ... 16 17 18 19 20 ',
  1873. 5 => '1 2 3 4 *5 6 7 ... 16 17 18 19 20 ',
  1874. 6 => '1 2 3 4 5 *6 7 8 ... 16 17 18 19 20 ',
  1875. 7 => '1 2 3 4 5 6 *7 8 9 ... 16 17 18 19 20 ',
  1876. 8 => '1 2 3 4 5 6 7 *8 9 10 ... 16 17 18 19 20 ',
  1877. 9 => '1 2 3 4 5 6 7 8 *9 10 11 ... 16 17 18 19 20 ',
  1878. 10 => '1 2 3 4 5 ... 8 9 *10 11 12 ... 16 17 18 19 20 ',
  1879. 11 => '1 2 3 4 5 ... 9 10 *11 12 13 ... 16 17 18 19 20 ',
  1880. 12 => '1 2 3 4 5 ... 10 11 *12 13 14 15 16 17 18 19 20 ',
  1881. 13 => '1 2 3 4 5 ... 11 12 *13 14 15 16 17 18 19 20 ',
  1882. 14 => '1 2 3 4 5 ... 12 13 *14 15 16 17 18 19 20 ',
  1883. 15 => '1 2 3 4 5 ... 13 14 *15 16 17 18 19 20 ',
  1884. 16 => '1 2 3 4 5 ... 14 15 *16 17 18 19 20 ',
  1885. 17 => '1 2 3 4 5 ... 15 16 *17 18 19 20 ',
  1886. 18 => '1 2 3 4 5 ... 16 17 *18 19 20 ',
  1887. 19 => '1 2 3 4 5 ... 16 17 18 *19 20 ',
  1888. 20 => '1 2 3 4 5 ... 16 17 18 19 *20 ',
  1889. ];
  1890. $result = $this->getNumbersForMultiplePages(array_keys($expected), 20, ['first' => 5, 'modulus' => 4, 'last' => 5]);
  1891. $this->assertEquals($expected, $result);
  1892. }
  1893. /**
  1894. * Tests that disabling modulus displays all page links.
  1895. */
  1896. public function testModulusDisabled(): void
  1897. {
  1898. $this->setPaginatedResult([
  1899. 'currentPage' => 4,
  1900. 'count' => 2,
  1901. 'totalCount' => 30,
  1902. 'hasPrevPage' => true,
  1903. 'hasNextPage' => true,
  1904. 'pageCount' => 6,
  1905. ], false);
  1906. $result = $this->Paginator->numbers(['modulus' => false]);
  1907. $expected = [
  1908. ['li' => []], '<a href="/"', '1', '/a', '/li',
  1909. ['li' => []], ['a' => ['href' => '/?page=2']], '2', '/a', '/li',
  1910. ['li' => []], ['a' => ['href' => '/?page=3']], '3', '/a', '/li',
  1911. ['li' => ['class' => 'active']], ['a' => ['href' => '']], '4', '/a', '/li',
  1912. ['li' => []], ['a' => ['href' => '/?page=5']], '5', '/a', '/li',
  1913. ['li' => []], ['a' => ['href' => '/?page=6']], '6', '/a', '/li',
  1914. ];
  1915. $this->assertHtml($expected, $result);
  1916. }
  1917. /**
  1918. * Test that numbers() with url options.
  1919. */
  1920. public function testNumbersWithUrlOptions(): void
  1921. {
  1922. $this->setPaginatedResult([
  1923. 'currentPage' => 8,
  1924. 'count' => 3,
  1925. 'totalCount' => 30,
  1926. 'hasPrevPage' => true,
  1927. 'hasNextPage' => true,
  1928. 'pageCount' => 15,
  1929. ], false);
  1930. $result = $this->Paginator->numbers(['url' => ['#' => 'foo']]);
  1931. $expected = [
  1932. ['li' => []], ['a' => ['href' => '/?page=4#foo']], '4', '/a', '/li',
  1933. ['li' => []], ['a' => ['href' => '/?page=5#foo']], '5', '/a', '/li',
  1934. ['li' => []], ['a' => ['href' => '/?page=6#foo']], '6', '/a', '/li',
  1935. ['li' => []], ['a' => ['href' => '/?page=7#foo']], '7', '/a', '/li',
  1936. ['li' => ['class' => 'active']], '<a href=""', '8', '/a', '/li',
  1937. ['li' => []], ['a' => ['href' => '/?page=9#foo']], '9', '/a', '/li',
  1938. ['li' => []], ['a' => ['href' => '/?page=10#foo']], '10', '/a', '/li',
  1939. ['li' => []], ['a' => ['href' => '/?page=11#foo']], '11', '/a', '/li',
  1940. ['li' => []], ['a' => ['href' => '/?page=12#foo']], '12', '/a', '/li',
  1941. ];
  1942. $this->assertHtml($expected, $result);
  1943. $this->setPaginatedResult([
  1944. 'currentPage' => 3,
  1945. 'count' => 10,
  1946. 'totalCount' => 48962,
  1947. 'hasPrevPage' => true,
  1948. 'hasNextPage' => true,
  1949. 'pageCount' => 4897,
  1950. ], false);
  1951. $result = $this->Paginator->numbers([
  1952. 'first' => 2,
  1953. 'modulus' => 2,
  1954. 'last' => 2,
  1955. 'url' => ['?' => ['foo' => 'bar']]]);
  1956. $expected = [
  1957. ['li' => []], ['a' => ['href' => '/?foo=bar']], '1', '/a', '/li',
  1958. ['li' => []], ['a' => ['href' => '/?foo=bar&amp;page=2']], '2', '/a', '/li',
  1959. ['li' => ['class' => 'active']], '<a href=""', '3', '/a', '/li',
  1960. ['li' => []], ['a' => ['href' => '/?foo=bar&amp;page=4']], '4', '/a', '/li',
  1961. ['li' => ['class' => 'ellipsis']], '&hellip;', '/li',
  1962. ['li' => []], ['a' => ['href' => '/?foo=bar&amp;page=4896']], '4,896', '/a', '/li',
  1963. ['li' => []], ['a' => ['href' => '/?foo=bar&amp;page=4897']], '4,897', '/a', '/li',
  1964. ];
  1965. $this->assertHtml($expected, $result);
  1966. }
  1967. /**
  1968. * test numbers() with routing parameters.
  1969. */
  1970. public function testNumbersRouting(): void
  1971. {
  1972. $this->setPaginatedResult([
  1973. 'currentPage' => 2,
  1974. 'count' => 2,
  1975. 'totalCount' => 30,
  1976. 'hasPrevPage' => true,
  1977. 'hasNextPage' => true,
  1978. 'pageCount' => 3,
  1979. ], false);
  1980. $request = new ServerRequest([
  1981. 'params' => ['controller' => 'Clients', 'action' => 'index', 'plugin' => null],
  1982. 'url' => '/Clients/index/?page=2',
  1983. ]);
  1984. Router::setRequest($request);
  1985. $result = $this->Paginator->numbers();
  1986. $expected = [
  1987. ['li' => []], ['a' => ['href' => '/Clients/index']], '1', '/a', '/li',
  1988. ['li' => ['class' => 'active']], '<a href=""', '2', '/a', '/li',
  1989. ['li' => []], ['a' => ['href' => '/Clients/index?page=3']], '3', '/a', '/li',
  1990. ];
  1991. $this->assertHtml($expected, $result);
  1992. }
  1993. /**
  1994. * test first() and last() with tag options
  1995. */
  1996. public function testFirstAndLastTag(): void
  1997. {
  1998. $this->setPaginatedResult([
  1999. 'currentPage' => 2,
  2000. ]);
  2001. $result = $this->Paginator->first('<<');
  2002. $expected = [
  2003. 'li' => ['class' => 'first'],
  2004. 'a' => ['href' => '/'],
  2005. '&lt;&lt;',
  2006. '/a',
  2007. '/li',
  2008. ];
  2009. $this->assertHtml($expected, $result);
  2010. $result = $this->Paginator->first('5');
  2011. $expected = [
  2012. 'li' => ['class' => 'first'],
  2013. 'a' => ['href' => '/'],
  2014. '5',
  2015. '/a',
  2016. '/li',
  2017. ];
  2018. $this->assertHtml($expected, $result);
  2019. $result = $this->Paginator->last(2);
  2020. $expected = [
  2021. '<li',
  2022. ['a' => ['href' => '/?page=6']], '6', '/a',
  2023. '/li',
  2024. '<li',
  2025. ['a' => ['href' => '/?page=7']], '7', '/a',
  2026. '/li',
  2027. ];
  2028. $this->assertHtml($expected, $result);
  2029. $result = $this->Paginator->last('9');
  2030. $expected = [
  2031. 'li' => ['class' => 'last'],
  2032. 'a' => ['href' => '/?page=7'],
  2033. '9',
  2034. '/a',
  2035. '/li',
  2036. ];
  2037. $this->assertHtml($expected, $result);
  2038. $result = $this->Paginator->first('first', ['url' => ['action' => 'paged']]);
  2039. $expected = [
  2040. 'li' => ['class' => 'first'],
  2041. 'a' => ['href' => '/Articles/paged'],
  2042. 'first',
  2043. '/a',
  2044. '/li',
  2045. ];
  2046. $this->assertHtml($expected, $result);
  2047. }
  2048. /**
  2049. * test that on the last page you don't get a link ot the last page.
  2050. */
  2051. public function testLastNoOutput(): void
  2052. {
  2053. $this->setPaginatedResult([
  2054. 'currentPage' => 15,
  2055. 'pageCount' => 15,
  2056. ]);
  2057. $result = $this->Paginator->last();
  2058. $expected = '';
  2059. $this->assertSame($expected, $result);
  2060. }
  2061. /**
  2062. * test first() on the first page.
  2063. */
  2064. public function testFirstEmpty(): void
  2065. {
  2066. $this->View->setRequest($this->View->getRequest()->withParam('paging.Article.page', 1));
  2067. $result = $this->Paginator->first();
  2068. $expected = '';
  2069. $this->assertSame($expected, $result);
  2070. }
  2071. /**
  2072. * test first() and options()
  2073. */
  2074. public function testFirstFullBaseUrl(): void
  2075. {
  2076. $this->setPaginatedResult([
  2077. 'alias' => 'Article',
  2078. 'currentPage' => 3,
  2079. 'pageCount' => 4,
  2080. 'hasPrevPage' => true,
  2081. 'sort' => 'Article.title',
  2082. 'direction' => 'DESC',
  2083. ]);
  2084. $this->Paginator->options(['url' => ['_full' => true, '#' => 'foo']]);
  2085. $result = $this->Paginator->first();
  2086. $expected = [
  2087. 'li' => ['class' => 'first'],
  2088. ['a' => [
  2089. 'href' => Configure::read('App.fullBaseUrl') . '/?sort=Article.title&amp;direction=DESC#foo',
  2090. ]],
  2091. '&lt;&lt; first',
  2092. '/a',
  2093. '/li',
  2094. ];
  2095. $this->assertHtml($expected, $result);
  2096. }
  2097. /**
  2098. * test first() on the fence-post
  2099. */
  2100. public function testFirstBoundaries(): void
  2101. {
  2102. $params = $this->Paginator->params();
  2103. $params['currentPage'] = 3;
  2104. $this->setPaginatedResult($params, false);
  2105. $result = $this->Paginator->first();
  2106. $expected = [
  2107. 'li' => ['class' => 'first'],
  2108. 'a' => ['href' => '/'],
  2109. '&lt;&lt; first',
  2110. '/a',
  2111. '/li',
  2112. ];
  2113. $this->assertHtml($expected, $result);
  2114. $result = $this->Paginator->first(2);
  2115. $expected = [
  2116. '<li',
  2117. ['a' => ['href' => '/']], '1', '/a',
  2118. '/li',
  2119. '<li',
  2120. ['a' => ['href' => '/?page=2']], '2', '/a',
  2121. '/li',
  2122. ];
  2123. $this->assertHtml($expected, $result);
  2124. $params = $this->Paginator->params();
  2125. $params['currentPage'] = 2;
  2126. $this->setPaginatedResult($params, false);
  2127. $result = $this->Paginator->first(3);
  2128. $this->assertSame('', $result, 'When inside the first links range, no links should be made');
  2129. }
  2130. /**
  2131. * test params() method
  2132. */
  2133. public function testParams(): void
  2134. {
  2135. $result = $this->Paginator->params();
  2136. $this->assertArrayHasKey('currentPage', $result);
  2137. $this->assertArrayHasKey('pageCount', $result);
  2138. }
  2139. /**
  2140. * test param() method
  2141. */
  2142. public function testParam(): void
  2143. {
  2144. $result = $this->Paginator->param('totalCount');
  2145. $this->assertSame(62, $result);
  2146. $result = $this->Paginator->param('imaginary');
  2147. $this->assertNull($result);
  2148. }
  2149. /**
  2150. * test last() method
  2151. */
  2152. public function testLast(): void
  2153. {
  2154. $result = $this->Paginator->last();
  2155. $expected = [
  2156. 'li' => ['class' => 'last'],
  2157. 'a' => ['href' => '/?page=7'],
  2158. 'last &gt;&gt;',
  2159. '/a',
  2160. '/li',
  2161. ];
  2162. $this->assertHtml($expected, $result);
  2163. $result = $this->Paginator->last(1);
  2164. $expected = [
  2165. '<li',
  2166. 'a' => ['href' => '/?page=7'],
  2167. '7',
  2168. '/a',
  2169. '/li',
  2170. ];
  2171. $this->assertHtml($expected, $result);
  2172. $params = $this->Paginator->params();
  2173. $params['currentPage'] = 6;
  2174. $this->setPaginatedResult($params, false);
  2175. $result = $this->Paginator->last(2);
  2176. $expected = [
  2177. '<li',
  2178. ['a' => ['href' => '/?page=6']], '6', '/a',
  2179. '/li',
  2180. '<li',
  2181. ['a' => ['href' => '/?page=7']], '7', '/a',
  2182. '/li',
  2183. ];
  2184. $this->assertHtml($expected, $result);
  2185. $result = $this->Paginator->last(3);
  2186. $this->assertSame('', $result, 'When inside the last links range, no links should be made');
  2187. $result = $this->Paginator->last('lastest', ['url' => ['action' => 'paged']]);
  2188. $expected = [
  2189. 'li' => ['class' => 'last'],
  2190. 'a' => ['href' => '/Articles/paged?page=7'],
  2191. 'lastest',
  2192. '/a',
  2193. '/li',
  2194. ];
  2195. $this->assertHtml($expected, $result);
  2196. }
  2197. /**
  2198. * test the options for last()
  2199. */
  2200. public function testLastOptions(): void
  2201. {
  2202. $this->setPaginatedResult([
  2203. 'currentPage' => 4,
  2204. 'count' => 3,
  2205. 'totalCount' => 30,
  2206. 'hasPrevPage' => false,
  2207. 'hasNextPage' => 2,
  2208. 'pageCount' => 15,
  2209. 'sort' => 'Client.name',
  2210. 'direction' => 'DESC',
  2211. ]);
  2212. $result = $this->Paginator->last();
  2213. $expected = [
  2214. 'li' => ['class' => 'last'],
  2215. 'a' => [
  2216. 'href' => '/?page=15&amp;sort=Client.name&amp;direction=DESC',
  2217. ],
  2218. 'last &gt;&gt;', '/a',
  2219. '/li',
  2220. ];
  2221. $this->assertHtml($expected, $result);
  2222. $result = $this->Paginator->last(1);
  2223. $expected = [
  2224. '<li',
  2225. ['a' => ['href' => '/?page=15&amp;sort=Client.name&amp;direction=DESC']], '15', '/a',
  2226. '/li',
  2227. ];
  2228. $this->assertHtml($expected, $result);
  2229. $result = $this->Paginator->last(2);
  2230. $expected = [
  2231. '<li',
  2232. ['a' => ['href' => '/?page=14&amp;sort=Client.name&amp;direction=DESC']], '14', '/a',
  2233. '/li',
  2234. '<li',
  2235. ['a' => ['href' => '/?page=15&amp;sort=Client.name&amp;direction=DESC']], '15', '/a',
  2236. '/li',
  2237. ];
  2238. $this->assertHtml($expected, $result);
  2239. }
  2240. /**
  2241. * testCounter method
  2242. */
  2243. public function testCounter(): void
  2244. {
  2245. $this->setPaginatedResult([
  2246. 'currentPage' => 1,
  2247. 'count' => 3,
  2248. 'totalCount' => 13,
  2249. 'perPage' => 3,
  2250. 'hasPrevPage' => false,
  2251. 'hasNextPage' => true,
  2252. 'pageCount' => 5,
  2253. 'limit' => 3,
  2254. 'sort' => 'Client.name',
  2255. 'order' => 'DESC',
  2256. 'start' => 1,
  2257. 'end' => 3,
  2258. 'alias' => 'Client',
  2259. ], false);
  2260. $input = 'Page {{page}} of {{pages}}, showing {{current}} records out of {{count}} total, ';
  2261. $input .= 'starting on record {{start}}, ending on {{end}}';
  2262. $expected = 'Page 1 of 5, showing 3 records out of 13 total, starting on record 1, ';
  2263. $expected .= 'ending on 3';
  2264. $result = $this->Paginator->counter($input);
  2265. $this->assertSame($expected, $result);
  2266. $result = $this->Paginator->counter('pages');
  2267. $expected = '1 of 5';
  2268. $this->assertSame($expected, $result);
  2269. $result = $this->Paginator->counter('range');
  2270. $expected = '1 - 3 of 13';
  2271. $this->assertSame($expected, $result);
  2272. $result = $this->Paginator->counter('Showing {{page}} of {{pages}} {{model}}');
  2273. $this->assertSame('Showing 1 of 5 clients', $result);
  2274. }
  2275. /**
  2276. * Tests that numbers are formatted according to the locale when using counter()
  2277. */
  2278. public function testCounterBigNumbers(): void
  2279. {
  2280. $this->setPaginatedResult([
  2281. 'currentPage' => 1523,
  2282. 'count' => 3000,
  2283. 'totalCount' => 4800001,
  2284. 'perPage' => 3000,
  2285. 'hasPrevPage' => false,
  2286. 'hasNextPage' => true,
  2287. 'pageCount' => 1600,
  2288. 'limit' => 5000,
  2289. 'sort' => 'Client.name',
  2290. 'order' => 'DESC',
  2291. 'start' => 4566001,
  2292. 'end' => 4569001,
  2293. 'alias' => 'Client',
  2294. ], false);
  2295. $input = 'Page {{page}} of {{pages}}, showing {{current}} records out of {{count}} total, ';
  2296. $input .= 'starting on record {{start}}, ending on {{end}}';
  2297. $expected = 'Page 1,523 of 1,600, showing 3,000 records out of 4,800,001 total, ';
  2298. $expected .= 'starting on record 4,566,001, ending on 4,569,001';
  2299. $result = $this->Paginator->counter($input);
  2300. $this->assertSame($expected, $result);
  2301. I18n::setLocale('de-DE');
  2302. $expected = 'Page 1.523 of 1.600, showing 3.000 records out of 4.800.001 total, ';
  2303. $expected .= 'starting on record 4.566.001, ending on 4.569.001';
  2304. $result = $this->Paginator->counter($input);
  2305. $this->assertSame($expected, $result);
  2306. }
  2307. /**
  2308. * testHasPage method
  2309. */
  2310. public function testHasPage(): void
  2311. {
  2312. $result = $this->Paginator->hasPage(15);
  2313. $this->assertFalse($result);
  2314. $result = $this->Paginator->hasPage(2);
  2315. $this->assertTrue($result);
  2316. }
  2317. /**
  2318. * testNextLinkUsingDotNotation method
  2319. */
  2320. public function testNextLinkUsingDotNotation(): void
  2321. {
  2322. $request = new ServerRequest([
  2323. 'url' => '/Accounts/index',
  2324. 'params' => [
  2325. 'plugin' => null, 'controller' => 'Accounts', 'action' => 'index',
  2326. ],
  2327. ]);
  2328. Router::setRequest($request);
  2329. $this->setPaginatedResult([
  2330. 'alias' => 'Article',
  2331. 'sort' => 'Article.title',
  2332. 'direction' => 'asc',
  2333. 'currentPage' => 1,
  2334. ]);
  2335. $test = ['url' => [
  2336. 'page' => '1',
  2337. 'sort' => 'Article.title',
  2338. 'direction' => 'asc',
  2339. ]];
  2340. $this->Paginator->options($test);
  2341. $result = $this->Paginator->next('Next');
  2342. $expected = [
  2343. 'li' => ['class' => 'next'],
  2344. 'a' => [
  2345. 'href' => '/Accounts/index?page=2&amp;sort=Article.title&amp;direction=asc',
  2346. 'rel' => 'next',
  2347. ],
  2348. 'Next',
  2349. '/a',
  2350. '/li',
  2351. ];
  2352. $this->assertHtml($expected, $result);
  2353. }
  2354. /**
  2355. * test the current() method
  2356. */
  2357. public function testCurrent(): void
  2358. {
  2359. $result = $this->Paginator->current();
  2360. $params = $this->Paginator->params();
  2361. $this->assertSame($params['currentPage'], $result);
  2362. }
  2363. /**
  2364. * test the total() method
  2365. */
  2366. public function testTotal(): void
  2367. {
  2368. $result = $this->Paginator->total();
  2369. $params = $this->Paginator->params();
  2370. $this->assertSame($params['pageCount'], $result);
  2371. }
  2372. /**
  2373. * test the numbers() method when there is only one page
  2374. */
  2375. public function testWithOnePage(): void
  2376. {
  2377. $this->setPaginatedResult([
  2378. 'currentPage' => 1,
  2379. 'count' => 2,
  2380. 'totalCount' => 2,
  2381. 'hasPrevPage' => false,
  2382. 'hasNextPage' => true,
  2383. 'pageCount' => 1,
  2384. ], false);
  2385. $this->assertSame('', $this->Paginator->numbers());
  2386. $this->assertSame('', $this->Paginator->first());
  2387. $this->assertSame('', $this->Paginator->last());
  2388. }
  2389. /**
  2390. * Test data for meta()
  2391. *
  2392. * @return array
  2393. */
  2394. public static function dataMetaProvider(): array
  2395. {
  2396. return [
  2397. // Verifies that no next and prev links are created for single page results.
  2398. [1, false, false, 1, [], ''],
  2399. // Verifies that first and last pages are created for single page results.
  2400. [1, false, false, 1, ['first' => true, 'last' => true], '<link href="http://localhost/?foo=bar" rel="first">' .
  2401. '<link href="http://localhost/?foo=bar" rel="last">'],
  2402. // Verifies that first page is created for single page results.
  2403. [1, false, false, 1, ['first' => true], '<link href="http://localhost/?foo=bar" rel="first">'],
  2404. // Verifies that last page is created for single page results.
  2405. [1, false, false, 1, ['last' => true], '<link href="http://localhost/?foo=bar" rel="last">'],
  2406. // Verifies that page 1 only has a next link.
  2407. [1, false, true, 2, [], '<link href="http://localhost/?foo=bar&amp;page=2" rel="next">'],
  2408. // Verifies that page 1 only has next, first and last link.
  2409. [1, false, true, 2, ['first' => true, 'last' => true], '<link href="http://localhost/?foo=bar&amp;page=2" rel="next">' .
  2410. '<link href="http://localhost/?foo=bar" rel="first">' .
  2411. '<link href="http://localhost/?foo=bar&amp;page=2" rel="last">'],
  2412. // Verifies that page 1 only has next and first link.
  2413. [1, false, true, 2, ['first' => true], '<link href="http://localhost/?foo=bar&amp;page=2" rel="next">' .
  2414. '<link href="http://localhost/?foo=bar" rel="first">'],
  2415. // Verifies that page 1 only has next and last link.
  2416. [1, false, true, 2, ['last' => true], '<link href="http://localhost/?foo=bar&amp;page=2" rel="next">' .
  2417. '<link href="http://localhost/?foo=bar&amp;page=2" rel="last">'],
  2418. // Verifies that the last page only has a prev link.
  2419. [2, true, false, 2, [], '<link href="http://localhost/?foo=bar" rel="prev">'],
  2420. // Verifies that the last page only has a prev, first and last link.
  2421. [2, true, false, 2, ['first' => true, 'last' => true], '<link href="http://localhost/?foo=bar" rel="prev">' .
  2422. '<link href="http://localhost/?foo=bar" rel="first">' .
  2423. '<link href="http://localhost/?foo=bar&amp;page=2" rel="last">'],
  2424. // Verifies that a page in the middle has both links.
  2425. [5, true, true, 10, [], '<link href="http://localhost/?foo=bar&amp;page=4" rel="prev">' .
  2426. '<link href="http://localhost/?foo=bar&amp;page=6" rel="next">'],
  2427. // Verifies that a page in the middle has both links.
  2428. [5, true, true, 10, ['first' => true, 'last' => true], '<link href="http://localhost/?foo=bar&amp;page=4" rel="prev">' .
  2429. '<link href="http://localhost/?foo=bar&amp;page=6" rel="next">' .
  2430. '<link href="http://localhost/?foo=bar" rel="first">' .
  2431. '<link href="http://localhost/?foo=bar&amp;page=10" rel="last">'],
  2432. ];
  2433. }
  2434. /**
  2435. * @param int $page
  2436. * @param int $prevPage
  2437. * @param int $nextPage
  2438. * @param int $pageCount
  2439. * @param array $options
  2440. * @param string $expected
  2441. * @dataProvider dataMetaProvider
  2442. */
  2443. public function testMeta($page, $prevPage, $nextPage, $pageCount, $options, $expected): void
  2444. {
  2445. $this->setPaginatedResult([
  2446. 'currentPage' => $page,
  2447. 'hasPrevPage' => $prevPage,
  2448. 'hasNextPage' => $nextPage,
  2449. 'pageCount' => $pageCount,
  2450. ], false);
  2451. $this->Paginator->options(['url' => ['?' => ['foo' => 'bar']]]);
  2452. $result = $this->Paginator->meta($options);
  2453. $this->assertSame($expected, $result);
  2454. $this->assertSame('', $this->View->fetch('meta'));
  2455. $result = $this->Paginator->meta($options + ['block' => true]);
  2456. $this->assertNull($result);
  2457. $this->assertSame($expected, $this->View->fetch('meta'));
  2458. }
  2459. /**
  2460. * test the limitControl() method
  2461. */
  2462. public function testLimitControl(): void
  2463. {
  2464. $this->setPaginatedResult(['perPage' => 10]);
  2465. $out = $this->Paginator->limitControl([1 => 1]);
  2466. $expected = [
  2467. ['form' => ['method' => 'get', 'accept-charset' => 'utf-8', 'action' => '/']],
  2468. ['div' => ['class' => 'input select']],
  2469. ['label' => ['for' => 'limit']],
  2470. 'View',
  2471. '/label',
  2472. ['select' => ['name' => 'limit', 'id' => 'limit', 'onChange' => 'this.form.submit()']],
  2473. ['option' => ['value' => '1']],
  2474. '1',
  2475. '/option',
  2476. '/select',
  2477. '/div',
  2478. '/form',
  2479. ];
  2480. $this->assertHtml($expected, $out);
  2481. $out = $this->Paginator->limitControl([1 => 1, 5 => 5], null, ['class' => 'form-control']);
  2482. $expected = [
  2483. ['form' => ['method' => 'get', 'accept-charset' => 'utf-8', 'action' => '/']],
  2484. ['div' => ['class' => 'input select']],
  2485. ['label' => ['for' => 'limit']],
  2486. 'View',
  2487. '/label',
  2488. ['select' => ['name' => 'limit', 'id' => 'limit', 'onChange' => 'this.form.submit()', 'class' => 'form-control']],
  2489. ['option' => ['value' => '1']],
  2490. '1',
  2491. '/option',
  2492. ['option' => ['value' => '5']],
  2493. '5',
  2494. '/option',
  2495. '/select',
  2496. '/div',
  2497. '/form',
  2498. ];
  2499. $this->assertHtml($expected, $out);
  2500. $out = $this->Paginator->limitControl([], null, ['class' => 'form-control']);
  2501. $expected = [
  2502. ['form' => ['method' => 'get', 'accept-charset' => 'utf-8', 'action' => '/']],
  2503. ['div' => ['class' => 'input select']],
  2504. ['label' => ['for' => 'limit']],
  2505. 'View',
  2506. '/label',
  2507. ['select' => ['name' => 'limit', 'id' => 'limit', 'onChange' => 'this.form.submit()', 'class' => 'form-control']],
  2508. ['option' => ['value' => '20']],
  2509. '20',
  2510. '/option',
  2511. ['option' => ['value' => '50']],
  2512. '50',
  2513. '/option',
  2514. ['option' => ['value' => '100']],
  2515. '100',
  2516. '/option',
  2517. '/select',
  2518. '/div',
  2519. '/form',
  2520. ];
  2521. $this->assertHtml($expected, $out);
  2522. $out = $this->Paginator->limitControl();
  2523. $expected = [
  2524. ['form' => ['method' => 'get', 'accept-charset' => 'utf-8', 'action' => '/']],
  2525. ['div' => ['class' => 'input select']],
  2526. ['label' => ['for' => 'limit']],
  2527. 'View',
  2528. '/label',
  2529. ['select' => ['name' => 'limit', 'id' => 'limit', 'onChange' => 'this.form.submit()']],
  2530. ['option' => ['value' => '20']],
  2531. '20',
  2532. '/option',
  2533. ['option' => ['value' => '50']],
  2534. '50',
  2535. '/option',
  2536. ['option' => ['value' => '100']],
  2537. '100',
  2538. '/option',
  2539. '/select',
  2540. '/div',
  2541. '/form',
  2542. ];
  2543. $this->assertHtml($expected, $out);
  2544. }
  2545. /**
  2546. * test the limitControl() with a request url and query.
  2547. *
  2548. * @return void
  2549. */
  2550. public function testLimitControlUrlWithQuery()
  2551. {
  2552. $request = new ServerRequest([
  2553. 'url' => '/batches?owner=billy&expected=1',
  2554. 'params' => [
  2555. 'plugin' => null, 'controller' => 'Batches', 'action' => 'index', 'pass' => [],
  2556. ],
  2557. 'query' => ['owner' => 'billy', 'expected' => 1],
  2558. 'base' => '',
  2559. 'webroot' => '/',
  2560. ]);
  2561. Router::setRequest($request);
  2562. $this->View->setRequest($request);
  2563. $this->setPaginatedResult(['perPage' => 10]);
  2564. $out = $this->Paginator->limitControl([1 => 1]);
  2565. $expected = [
  2566. ['form' => ['method' => 'get', 'accept-charset' => 'utf-8', 'action' => '/batches?owner=billy&amp;expected=1']],
  2567. ['div' => ['class' => 'input select']],
  2568. ['label' => ['for' => 'limit']],
  2569. 'View',
  2570. '/label',
  2571. ['select' => ['name' => 'limit', 'id' => 'limit', 'onChange' => 'this.form.submit()']],
  2572. ['option' => ['value' => '1']],
  2573. '1',
  2574. '/option',
  2575. '/select',
  2576. '/div',
  2577. '/form',
  2578. ];
  2579. $this->assertHtml($expected, $out);
  2580. }
  2581. /**
  2582. * test the limitControl() method with defaults and query
  2583. */
  2584. public function testLimitControlQuery(): void
  2585. {
  2586. $out = $this->Paginator->limitControl([], 50);
  2587. $expected = [
  2588. ['form' => ['method' => 'get', 'accept-charset' => 'utf-8', 'action' => '/']],
  2589. ['div' => ['class' => 'input select']],
  2590. ['label' => ['for' => 'limit']],
  2591. 'View',
  2592. '/label',
  2593. ['select' => ['name' => 'limit', 'id' => 'limit', 'onChange' => 'this.form.submit()']],
  2594. ['option' => ['value' => '20']],
  2595. '20',
  2596. '/option',
  2597. ['option' => ['value' => '50', 'selected' => 'selected']],
  2598. '50',
  2599. '/option',
  2600. ['option' => ['value' => '100']],
  2601. '100',
  2602. '/option',
  2603. '/select',
  2604. '/div',
  2605. '/form',
  2606. ];
  2607. $this->assertHtml($expected, $out);
  2608. $this->View->setRequest($this->View->getRequest()->withQueryParams(['limit' => '100']));
  2609. $out = $this->Paginator->limitControl([], 50);
  2610. $expected = [
  2611. ['form' => ['method' => 'get', 'accept-charset' => 'utf-8', 'action' => '/']],
  2612. ['div' => ['class' => 'input select']],
  2613. ['label' => ['for' => 'limit']],
  2614. 'View',
  2615. '/label',
  2616. ['select' => ['name' => 'limit', 'id' => 'limit', 'onChange' => 'this.form.submit()']],
  2617. ['option' => ['value' => '20']],
  2618. '20',
  2619. '/option',
  2620. ['option' => ['value' => '50']],
  2621. '50',
  2622. '/option',
  2623. ['option' => ['value' => '100', 'selected' => 'selected']],
  2624. '100',
  2625. '/option',
  2626. '/select',
  2627. '/div',
  2628. '/form',
  2629. ];
  2630. $this->assertHtml($expected, $out);
  2631. }
  2632. /**
  2633. * test the limitControl() method with scope
  2634. */
  2635. public function testLimitControlWithScope(): void
  2636. {
  2637. $request = new ServerRequest([
  2638. 'url' => '/accounts/',
  2639. 'params' => [
  2640. 'plugin' => null, 'controller' => 'Accounts', 'action' => 'index', 'pass' => [],
  2641. ],
  2642. 'base' => '',
  2643. 'webroot' => '/',
  2644. ]);
  2645. Router::setRequest($request);
  2646. $this->setPaginatedResult([
  2647. 'perPage' => 25,
  2648. 'count' => 9,
  2649. 'totalCount' => 62,
  2650. 'hasPrevPage' => false,
  2651. 'hasNextPage' => true,
  2652. 'pageCount' => 7,
  2653. 'sort' => 'date',
  2654. 'direction' => 'asc',
  2655. 'page' => 1,
  2656. 'scope' => 'article',
  2657. ], false);
  2658. $out = $this->Paginator->limitControl([25 => 25, 50 => 50]);
  2659. $expected = [
  2660. ['form' => ['method' => 'get', 'accept-charset' => 'utf-8', 'action' => '/']],
  2661. ['div' => ['class' => 'input select']],
  2662. ['label' => ['for' => 'article-limit']],
  2663. 'View',
  2664. '/label',
  2665. ['select' => ['name' => 'article[limit]', 'id' => 'article-limit', 'onChange' => 'this.form.submit()']],
  2666. ['option' => ['value' => '25', 'selected' => 'selected']],
  2667. '25',
  2668. '/option',
  2669. ['option' => ['value' => '50']],
  2670. '50',
  2671. '/option',
  2672. '/select',
  2673. '/div',
  2674. '/form',
  2675. ];
  2676. $this->assertHtml($expected, $out);
  2677. }
  2678. /**
  2679. * Test using paging params set by SimplePaginator which doesn't do count query.
  2680. */
  2681. public function testMethodsWhenThereIsNoPageCount(): void
  2682. {
  2683. $request = new ServerRequest([
  2684. 'url' => '/',
  2685. ]);
  2686. $view = new View($request);
  2687. $paginator = new PaginatorHelper($view);
  2688. $paginator->setPaginated(new PaginatedResultSet(new ResultSet([]), [
  2689. 'currentPage' => 1,
  2690. 'count' => 9,
  2691. 'totalCount' => null,
  2692. 'hasPrevPage' => false,
  2693. 'hasNextPage' => true,
  2694. 'pageCount' => null,
  2695. 'start' => 1,
  2696. 'end' => 9,
  2697. 'sort' => null,
  2698. 'direction' => null,
  2699. 'limit' => null,
  2700. ]));
  2701. $result = $paginator->first();
  2702. $this->assertSame('', $result);
  2703. $result = $paginator->last();
  2704. $this->assertSame('', $result);
  2705. // Using below methods when SimplePaginator is used makes no practical sense.
  2706. // The asserts are just to ensure they return a reasonable value.
  2707. $result = $paginator->numbers();
  2708. $this->assertSame('', $result);
  2709. $result = $paginator->hasNext();
  2710. $this->assertTrue($result);
  2711. $result = $paginator->counter();
  2712. // counter() sets `pageCount` to 1 if empty.
  2713. $this->assertSame('1 of 1', $result);
  2714. $result = $paginator->total();
  2715. $this->assertNull($result);
  2716. }
  2717. /**
  2718. * Test that generates a URL that keeps the passed parameters
  2719. */
  2720. public function testPaginationWithPassedParams(): void
  2721. {
  2722. $request = new ServerRequest([
  2723. 'url' => '/articles/index/whatever/3',
  2724. 'params' => [
  2725. 'plugin' => null,
  2726. 'controller' => 'Articles',
  2727. 'action' => 'index',
  2728. 'pass' => ['whatever', '3'],
  2729. ],
  2730. 'base' => '',
  2731. 'webroot' => '/',
  2732. ]);
  2733. Router::setRequest($request);
  2734. $this->View->setRequest($request->withAttribute('paging', [
  2735. 'Article' => [
  2736. 'scope' => 'article',
  2737. ],
  2738. ]));
  2739. $this->Paginator = new PaginatorHelper($this->View);
  2740. $this->Paginator->setPaginated($this->paginatedResult, ['paging' => ['scope' => 'article']]);
  2741. $result = $this->Paginator->generateUrl(['page' => 2]);
  2742. $expected = '/Articles/index/whatever/3?article%5Bpage%5D=2';
  2743. $this->assertSame($expected, $result);
  2744. }
  2745. }