Passed
Push — master ( 78fac6...512cd1 )
by Arnaud
05:16
created

Pagination   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 140
Duplicated Lines 0 %

Test Coverage

Coverage 95.83%

Importance

Changes 5
Bugs 1 Features 0
Metric Value
eloc 89
c 5
b 1
f 0
dl 0
loc 140
ccs 92
cts 96
cp 0.9583
rs 10
wmc 20

1 Method

Rating   Name   Duplication   Size   Complexity  
F generate() 0 135 20
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of Cecil.
7
 *
8
 * Copyright (c) Arnaud Ligny <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Cecil\Generator;
15
16
use Cecil\Collection\Page\Collection as PagesCollection;
17
use Cecil\Collection\Page\Page;
18
use Cecil\Collection\Page\Type;
19
use Cecil\Exception\RuntimeException;
20
21
/**
22
 * Class Generator\Pagination.
23
 */
24
class Pagination extends AbstractGenerator implements GeneratorInterface
25
{
26
    /**
27
     * {@inheritdoc}
28
     */
29 1
    public function generate(): void
30
    {
31 1
        if ($this->config->get('pagination.enabled') === false) {
32
            return;
33
        }
34
35
        // filters list pages (home, sections and terms)
36 1
        $filteredPages = $this->builder->getPages()->filter(function (Page $page) {
37 1
            return \in_array($page->getType(), [Type::HOMEPAGE, Type::SECTION, Type::TERM]);
38 1
        });
39
        /** @var Page $page */
40 1
        foreach ($filteredPages as $page) {
41 1
            $pages = $page->getPages()->filter(function (Page $page) {
42 1
                return $page->getVariable('published');
43 1
            });
44
            // if no sub-pages: by-pass
45 1
            if ($pages === null) {
46
                continue;
47
            }
48 1
            $path = $page->getPath();
49
            // site pagination configuration
50 1
            $paginationPerPage = \intval($this->config->get('pagination.max') ?? 5);
51 1
            $paginationPath = (string) $this->config->get('pagination.path') ?? 'page';
52
            // page pagination configuration
53 1
            $pagePagination = $page->getVariable('pagination');
54 1
            if ($pagePagination) {
55 1
                if (isset($pagePagination['enabled']) && $pagePagination['enabled'] === false) {
56
                    continue;
57
                }
58 1
                if (isset($pagePagination['max'])) {
59 1
                    $paginationPerPage = \intval($pagePagination['max']);
60
                }
61 1
                if (isset($pagePagination['path'])) {
62 1
                    $paginationPath = (string) $pagePagination['path'];
63
                }
64
            }
65 1
            $pagesTotal = \count($pages);
66
            // is pagination not necessary?
67 1
            if ($pagesTotal <= $paginationPerPage) {
68 1
                continue;
69
            }
70
            // sorts (by date by default)
71 1
            $pages = $pages->sortByDate();
72
            /*
73
             * sortby: date|updated|title|weight
74
             *
75
             * sortby:
76
             *   variable: date|updated
77
             *   desc_title: false|true
78
             *   reverse: false|true
79
             */
80 1
            if ($page->hasVariable('sortby')) {
81 1
                $sortby = (string) $page->getVariable('sortby');
82
                // options?
83 1
                $sortby = $page->getVariable('sortby')['variable'] ?? $sortby;
84 1
                $descTitle = $page->getVariable('sortby')['desc_title'] ?? false;
85 1
                $reverse = $page->getVariable('sortby')['reverse'] ?? false;
86
                // sortby: date, title or weight
87 1
                $sortMethod = sprintf('sortBy%s', ucfirst(str_replace('updated', 'date', $sortby)));
88 1
                if (!method_exists($pages, $sortMethod)) {
89
                    throw new RuntimeException(sprintf('In "%s" section "%s" is not a valid value for "sortby" variable.', $page->getId(), $sortby));
90
                }
91 1
                $pages = $pages->$sortMethod(['variable' => $sortby, 'descTitle' => $descTitle, 'reverse' => $reverse]);
92
            }
93
            // builds paginator
94 1
            $paginatorPagesCount = \intval(ceil($pagesTotal / $paginationPerPage));
95 1
            for ($i = 0; $i < $paginatorPagesCount; $i++) {
96 1
                $itPagesInPagination = new \LimitIterator($pages->getIterator(), ($i * $paginationPerPage), $paginationPerPage);
97 1
                $pagesInPagination = new PagesCollection(
98 1
                    $page->getId() . '-page-' . ($i + 1),
99 1
                    iterator_to_array($itPagesInPagination)
100 1
                );
101 1
                $alteredPage = clone $page;
102 1
                if ($i == 0) { // first page (ie: blog/page/1 -> blog)
103 1
                    $pageId = $page->getId();
104 1
                    $alteredPage
105 1
                        ->setVariable('alias', [
106 1
                            sprintf('%s/%s/%s', $path, $paginationPath, 1),
107 1
                        ]);
108
                } else { // others pages (ie: blog/page/X)
109 1
                    $pageId = Page::slugify(sprintf('%s/%s/%s', $page->getId(), $paginationPath, $i + 1));
110 1
                    $alteredPage
111 1
                        ->setId($pageId)
112 1
                        ->setVirtual(true)
113 1
                        ->setPath(Page::slugify(sprintf('%s/%s/%s', $path, $paginationPath, $i + 1)))
114 1
                        ->unVariable('menu')
115 1
                        ->unVariable('alias')
116 1
                        ->unVariable('aliases') // backward compatibility
117 1
                        ->unVariable('langref')
118 1
                        ->setVariable('paginated', true);
119
                }
120
                // set paginator values
121 1
                $paginator = [
122 1
                    'pages'       => $pagesInPagination,
123 1
                    'pages_total' => $pagesTotal,
124 1
                    'totalpages'  => $pagesTotal, // backward compatibility
125 1
                    'count'       => $paginatorPagesCount,
126 1
                    'current'     => $i + 1,
127 1
                ];
128
                // adds links
129 1
                $paginator['links'] = ['first' => $page->getId() ?: 'index'];
130 1
                if ($i == 1) {
131 1
                    $paginator['links'] += ['prev' => $page->getId() ?: 'index'];
132
                }
133 1
                if ($i > 1) {
134 1
                    $paginator['links'] += ['prev' => Page::slugify(sprintf(
135 1
                        '%s/%s/%s',
136 1
                        $page->getId(),
137 1
                        $paginationPath,
138 1
                        $i
139 1
                    ))];
140
                }
141 1
                $paginator['links'] += ['self' => $pageId ?: 'index'];
142 1
                if ($i < $paginatorPagesCount - 1) {
143 1
                    $paginator['links'] += ['next' => Page::slugify(sprintf(
144 1
                        '%s/%s/%s',
145 1
                        $page->getId(),
146 1
                        $paginationPath,
147 1
                        $i + 2
148 1
                    ))];
149
                }
150 1
                $paginator['links'] += ['last' => Page::slugify(sprintf(
151 1
                    '%s/%s/%s',
152 1
                    $page->getId(),
153 1
                    $paginationPath,
154 1
                    $paginatorPagesCount
155 1
                ))];
156 1
                $paginator['links'] += ['path' => Page::slugify(sprintf('%s/%s', $page->getId(), $paginationPath))];
157
                // set paginator to cloned page
158 1
                $alteredPage->setPaginator($paginator);
159 1
                $alteredPage->setVariable('pagination', $paginator); // backward compatibility
160
                // updates date with the first element of the collection
161 1
                $alteredPage->setVariable('date', $pagesInPagination->first()->getVariable('date'));
162
163 1
                $this->generatedPages->add($alteredPage);
164
            }
165
        }
166
    }
167
}
168