PaginatorHelper cleanup - markstory/cakephp GitHub Wiki

PaginatorHelper has grown a pile of options over the years, this has made documentation, testing, and using the helper more complex and tedious over time. Instead of adding options forever more, restructuring how HTML is generated is necessary. In addition to option-itis, PaginatorHelper has a number of other flaws:

  • Generated HTML should always emit the same number of HTML elements. Both disabled and active states should generate the same number of HTML elements by default.
  • Use current conventions for HTML. Present day CSS frameworks prefer un-ordered lists for pagination links. Update the default HTML settings to generate markup that easily integrates with libraries like twitter bootstrap.

While updating the types + number of HTML elements is reasonably straightforward, curbing option-itis is a bit more difficult.

Use template strings instead of options

Template strings could allow developers to more simply and directly express the rendered HTML they want generated. HtmlHelper already uses this approach successfully, albiet with a somewhat sub-optimal interface.

By adding a templates() method that allows developers to replace some or all of the templates with customized versions.

<?php
$this->Paginator->templates([
  'nextDisabled' => '<li><span class="next">{text}</span></li>',
  'nextActive' => '<li><a href="{url}" class="next">{text}</a></li>',
]);

By using the existing placeholder syntax already in use for PaginatorHelper::counter() we reduce the number of simple template formats a developer needs to learn, and keep substitution simple.

A template configuration file could also be provided to PaginatorHelper when included in a controller's $helpers array.

<?php
class ArticlesController extends AppController {
  public $helpers = [
    'Paginator' => ['templates' => 'paginator-templates.php'
  ];
}

The above would load `App/Config/paginator-templates.php' and call the templates() function with the result of including the named file. Template strings are always merged with the existing loaded templates. This allows developers to only override the templates they need. It also allows specializations, or themes to define only what is different.

Templates in PaginatorHelper

The list of templates required for PaginatorHelper is:

  • nextActive - The next link + wrapping markup.
  • nextDisabled - A disabled next link + wrapping markup.
  • prevActive - The prev link + wrapping markup.
  • prevDisabled - A disabled prev link + wrapping markup.
  • counter - The counter text.
  • sortAsc - Ascending sort link.
  • sortDesc - Descending sort link.
  • pagingActive - Links used in page numbers.
  • pagingDisabled - Disabled links in page numbers.
  • firstActive - First links HTML
  • lastActive - Last links HTML
  • ellipsis - The content to use between large ranges.
  • separator - The content to put between link sets.

Template implementation

String templates would be handled by a separate object that could be re-used across many different helpers. It would have the following responsibilities.

  • Register templates.
  • Load templates from files. Either in the app or in a plugin.
  • Do templating. Insert arrays of data into template strings.

The templates() method on Helpers would simply proxy to this method. The new HelperTemplate object could be used by to replace the internals of HtmlHelper::useTag() and make the tags file consistent between HtmlHelper & PaginatorHelper.

Default templates

Default templates would be defined in an array inside the helper. This avoids loading a separate file with the default templates.

API changes

With the simplified templates many methods can drop arguments and options. Some changes will require changes in PaginatorComponent as well:

Changes only in PaginatorHelper

  • Reduce number of arguments in sortDir, sortKey methods.

Methods such as prev(), next() currently take both enabled + disabled options. Instead of separate parameters, most of these options can be replace with a single options parameter that uses a disabled key to provide overrides. The new signature for these methods will look like:

<?php
echo $this->Paginator->next('Next', [
  'disabledTitle' => 'No Next',
  'template' => '<li class="next paging"><a href="{url}">{text}</a></li>',
  'disabledTemplate' => '<li class="next paging disabled"><span>{text}</span></li>',
  'escape' => true,
  'model' => 'Article',
]);

Methods like first() and last() and numbers() will drop their tag and class options. Instead templates should be used. The formatting of pagination elements is generally consistent across an application, which makes using templates a simple and efficient way to handle this kind of content. Applications with multiple styles of pagination could load different template sets.

Simplify the params['paging'] structure

  • Collapse the options key into the paging key. The options key doesn't provide any clarity, and only contributes to a more deeply nested structure.
  • Remove the 'defaults' option, the helper should only receive the merged option set.
  • Remove the order option. This option duplicates the sort and direction options.
⚠️ **GitHub.com Fallback** ⚠️