CakePHP3.3より前のバージョンで複数一覧をページングする

私はどうにもページャと聞くと瞬間的に邪魔くさいと感じるのだけど、これは過去の体験のせいで、今となってはすごく簡単だ。

方法はいろいろあるだろうが、とにかくCakePHP3を使えばよい。

以下のリンクのページネータコンポーネントとページネータヘルパーを使う。

https://book.cakephp.org/3.0/ja/controllers/pages-controller.html
https://book.cakephp.org/3.0/ja/views/helpers/paginator.html

使う方法は説明されている。まったく付け入るすきがない。口を挟む余地がない。黙って上のドキュメントを読んでほしい。

こんなのはどうだろう

しかし、こんな人間でも人のためになりたい。いや、こんな人間だからかも知れない。とにかく今は人の役に立ちたいのだ。

例えば、同じページで複数一覧を同時にページングする方法をご存知だろうか?なんなら私が記載致しましょうか?これが人のためになるのですか?

けれど、これもドキュメントに書いてあるのだ。

https://book.cakephp.org/3.0/ja/controllers/components/pagination.html#paginating-multiple-queries
https://book.cakephp.org/3.0/ja/views/helpers/paginator.html#paginator-helper-multiple

ただただ、ありがたい。そもそも考えてみれば公式ドキュメントに戦いを挑むのは無謀だ。

ひとのため、ありました

一つ問題がありまして、複数一覧の同時ページャはCakePHPバージョン3.3から追加された新機能です。もしそれ以前のバージョンでやりたかったらどうしますか?

それはこれ、以下のようにすると、動きます。

検証version: 3.1.13

use Cake\Controller\Component\PaginatorComponent;
use Cake\Utility\Hash;

class AppPaginatorComponent extends PaginatorComponent
{
    public function paginate($object, array $settings = [])
    {
        if ($object instanceof QueryInterface) {
            $query = $object;
            $object = $query->repository();
        }

        $alias = $object->alias();
        $options = $this->mergeOptions($alias, $settings);
        $options = $this->validateSort($object, $options);
        $options = $this->checkLimit($options);

		$options += ['page' => 1, 'scope' => null];
		$options['page'] = (int)$options['page'] < 1 ? 1 : (int)$options['page'];
        list($finder, $options) = $this->_extractFinder($options);

        if (empty($query)) {
            $query = $object->find($finder, $options);
        } else {
            $query->applyOptions($options);
        }

        $results = $query->all();
        $numResults = count($results);
        $count = $numResults ? $query->count() : 0;

        $defaults = $this->getDefaults($alias, $settings);
        unset($defaults[0]);

        $page = $options['page'];
        $limit = $options['limit'];
        $pageCount = (int)ceil($count / $limit);
        $requestedPage = $page;
        $page = max(min($page, $pageCount), 1);
        $request = $this->_registry->getController()->request;

        $order = (array)$options['order'];
        $sortDefault = $directionDefault = false;
        if (!empty($defaults['order']) && count($defaults['order']) == 1) {
            $sortDefault = key($defaults['order']);
            $directionDefault = current($defaults['order']);
        }

        $paging = [
            'finder' => $finder,
            'page' => $page,
            'current' => $numResults,
            'count' => $count,
            'perPage' => $limit,
            'prevPage' => ($page > 1),
            'nextPage' => ($count > ($page * $limit)),
            'pageCount' => $pageCount,
            'sort' => key($order),
            'direction' => current($order),
            'limit' => $defaults['limit'] != $limit ? $limit : null,
            'sortDefault' => $sortDefault,
            'directionDefault' => $directionDefault,
            'scope' => $options['scope'],
        ];

        if (!isset($request['paging'])) {
            $request['paging'] = [];
        }
        $request['paging'] = [$alias => $paging] + (array)$request['paging'];

        if ($requestedPage > $page) {
            throw new NotFoundException();
        }

        return $results;
    }

	public function mergeOptions($alias, $settings)
	{
		$defaults = $this->getDefaults($alias, $settings);
		$request = $this->_registry->getController()->request;
		$scope = Hash::get($settings, 'scope', null);
		$query = $request->query;
		if ($scope) {
			$query = Hash::get($query, $scope, []);
		}

		$request = array_intersect_key($query, array_flip($this->_config['whitelist']));
		return array_merge($defaults, $request);
	}
}
use Cake\View\Helper;
use Cake\View\Helper\PaginatorHelper;
use Cake\Utility\Hash;

class AppPaginatorHelper extends PaginatorHelper
{
	public function generateUrl(array $options = [], $model = null, $full = false)
	{
		$paging = $this->params($model);
		$paging += ['page' => null, 'sort' => null, 'direction' => null, 'limit' => null];
		$url = [
			'page' => $paging['page'],
			'limit' => $paging['limit'],
			'sort' => $paging['sort'],
			'direction' => $paging['direction'],
		];

		if (!empty($this->_config['options']['url'])) {
			$key = implode('.', array_filter(['options.url', Hash::get($paging, 'scope', null)]));
			$url = array_merge($url, Hash::get($this->_config, $key, []));
		}

		$url = array_filter($url, function ($value) {
			return ($value || is_numeric($value));
		});
		$url = array_merge($url, $options);

		if (!empty($url['page']) && $url['page'] == 1) {
			$url['page'] = false;
		}
		if (isset($paging['sortDefault'], $paging['directionDefault'], $url['sort'], $url['direction']) &&
			$url['sort'] === $paging['sortDefault'] &&
			$url['direction'] === $paging['directionDefault']
		) {
			$url['sort'] = $url['direction'] = null;
		}

		if (!empty($paging['scope'])) {
			$scope = $paging['scope'];
			$currentParams = $this->_config['options']['url'];

			// Merge existing query parameters in the scope.
			if (isset($currentParams['?'][$scope]) && is_array($currentParams['?'][$scope])) {
				$url += $currentParams['?'][$scope];
				unset($currentParams['?'][$scope]);
			}
			$url = [$scope => $url] + $currentParams;
			if (empty($url[$scope]['page'])) {
				unset($url[$scope]['page']);
			}
		}

		return $this->Url->build($url, $full);
	}
}

わざわざ書くまでも無いですが、最新のソースを参考に移植しただけです。

https://github.com/cakephp

人のためになるのは難しい。

大体、人のためになって何を望むのか。何を得ようというのか。何が得られれば満足なのか。人のためになる目的はなんなのか。

今回の記事の目的は査定のためです。ひいては・・・。

以上