Completed
Push — master ( 169128...3c5d2d )
by Sebastian
01:56
created

PaginateRoute   B

Complexity

Total Complexity 36

Size/Duplication

Total Lines 327
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 23
Bugs 3 Features 3
Metric Value
wmc 36
c 23
b 3
f 3
lcom 1
cbo 6
dl 0
loc 327
rs 8.8

16 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 1
A currentPage() 0 6 2
A isCurrentPage() 0 4 1
A nextPage() 0 8 2
A hasNextPage() 0 4 1
A nextPageUrl() 0 10 2
A previousPage() 0 8 2
A hasPreviousPage() 0 4 1
A previousPageUrl() 0 10 2
A allUrls() 0 14 3
C renderPageList() 0 33 8
B renderRelLinks() 0 22 4
A renderHtml() 0 4 1
A pageUrl() 0 12 2
A addPageQuery() 0 9 3
A registerMacros() 0 13 1
1
<?php
2
3
namespace Spatie\PaginateRoute;
4
5
use Illuminate\Contracts\Pagination\Paginator;
6
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
7
use Illuminate\Contracts\Routing\UrlGenerator;
8
use Illuminate\Routing\Router;
9
use Illuminate\Translation\Translator;
10
11
class PaginateRoute
12
{
13
    /**
14
     * @var \Illuminate\Translation\Translator
15
     */
16
    protected $translator;
17
18
    /**
19
     * @var \Illuminate\Routing\Router
20
     */
21
    protected $router;
22
23
    /**
24
     * @var \Illuminate\Contracts\Routing\UrlGenerator
25
     */
26
    protected $urlGenerator;
27
28
    /**
29
     * @var string
30
     */
31
    protected $pageKeyword;
32
33
    /**
34
     * @param \Illuminate\Translation\Translator         $translator
35
     * @param \Illuminate\Routing\Router                 $router
36
     * @param \Illuminate\Contracts\Routing\UrlGenerator $urlGenerator
37
     */
38
    public function __construct(Translator $translator, Router $router, UrlGenerator $urlGenerator)
39
    {
40
        $this->translator = $translator;
41
        $this->router = $router;
42
        $this->urlGenerator = $urlGenerator;
43
44
        // Unfortunately we can't do this in the service provider since routes are booted first
45
        $this->translator->addNamespace('paginateroute', __DIR__.'/../resources/lang');
46
47
        $this->pageKeyword = $this->translator->get('paginateroute::paginateroute.page');
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->translator->get('...e::paginateroute.page') can also be of type array. However, the property $pageKeyword is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
48
    }
49
50
    /**
51
     * Return the current page.
52
     *
53
     * @return int
54
     */
55
    public function currentPage()
56
    {
57
        $query = $this->router->getCurrentRoute()->parameter('pageQuery');
58
59
        return (int) str_replace($this->pageKeyword.'/', '', $query) ?: 1;
60
    }
61
62
    /**
63
     * Check if the given page is the current page.
64
     *
65
     * @param int $page
66
     *
67
     * @return bool
68
     */
69
    public function isCurrentPage($page)
70
    {
71
        return $this->currentPage() === $page;
72
    }
73
74
    /**
75
     * Get the next page number.
76
     *
77
     * @param \Illuminate\Contracts\Pagination\Paginator $paginator
78
     *
79
     * @return string|null
80
     */
81
    public function nextPage(Paginator $paginator)
82
    {
83
        if (!$paginator->hasMorePages()) {
84
            return;
85
        }
86
87
        return $this->currentPage() + 1;
88
    }
89
90
    /**
91
     * Determine wether there is a next page.
92
     *
93
     * @param \Illuminate\Contracts\Pagination\Paginator $paginator
94
     *
95
     * @return bool
96
     */
97
    public function hasNextPage(Paginator $paginator)
98
    {
99
        return $this->nextPage($paginator) !== null;
100
    }
101
102
    /**
103
     * Get the next page URL.
104
     *
105
     * @param \Illuminate\Contracts\Pagination\Paginator $paginator
106
     *
107
     * @return string|null
108
     */
109
    public function nextPageUrl(Paginator $paginator)
110
    {
111
        $nextPage = $this->nextPage($paginator);
112
113
        if ($nextPage === null) {
114
            return;
115
        }
116
117
        return $this->pageUrl($nextPage);
118
    }
119
120
    /**
121
     * Get the previous page number.
122
     *
123
     * @return string|null
124
     */
125
    public function previousPage()
126
    {
127
        if ($this->currentPage() <= 1) {
128
            return;
129
        }
130
131
        return $this->currentPage() - 1;
132
    }
133
134
    /**
135
     * Determine wether there is a previous page.
136
     *
137
     * @return bool
138
     */
139
    public function hasPreviousPage()
140
    {
141
        return $this->previousPage() !== null;
142
    }
143
144
    /**
145
     * Get the previous page URL.
146
     *
147
     * @param bool $full Return the full version of the URL in for the first page
148
     *                   Ex. /users/page/1 instead of /users
149
     *
150
     * @return string|null
151
     */
152
    public function previousPageUrl($full = false)
153
    {
154
        $previousPage = $this->previousPage();
155
156
        if ($previousPage === null) {
157
            return;
158
        }
159
160
        return $this->pageUrl($previousPage, $full);
161
    }
162
163
    /**
164
     * Get all urls in an array.
165
     *
166
     * @param \Illuminate\Contracts\Pagination\LengthAwarePaginator $paginator
167
     * @param bool                                                  $full      Return the full version of the URL in for the first page
168
     *                                                                         Ex. /users/page/1 instead of /users
169
     *
170
     * @return array
171
     */
172
    public function allUrls(LengthAwarePaginator $paginator, $full = false)
173
    {
174
        if (!$paginator->hasPages()) {
175
            return [];
176
        }
177
178
        $urls = [];
179
180
        for ($page = 1; $page <= $paginator->lastPage(); ++$page) {
181
            $urls[] = $this->pageUrl($page, $full);
182
        }
183
184
        return $urls;
185
    }
186
187
    /**
188
     * Render a plain html list with previous, next and all urls. The current page gets a current class on the list item.
189
     *
190
     * @param \Illuminate\Contracts\Pagination\LengthAwarePaginator $paginator
191
     * @param bool                                                  $full              Return the full version of the URL in for the first page
192
     *                                                                                 Ex. /users/page/1 instead of /users
193
     * @param string                                                $class             Include class on pagination list
194
     *                                                                                 Ex. <ul class="pagination">
195
     * @param bool                                                  $additionalLinks   Include prev and next links on pagination list
196
     *
197
     * @return string
198
     */
199
    public function renderPageList(LengthAwarePaginator $paginator, $full = false, $class = null, $additionalLinks = false)
200
    {
201
        $urls = $this->allUrls($paginator, $full);
202
203
        if ($class) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $class of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
204
            $class = " class=\"$class\"";
205
        }
206
207
        $listItems = "<ul{$class}>";
208
209
        if($this->hasPreviousPage() && $additionalLinks) {
210
            $listItems .= "<li><a href=\"{$this->previousPageUrl()}\">&laquo;</a></li>";
211
        }
212
213
        foreach ($urls as $i => $url) {
214
215
            $pageNum = $i + 1;
216
            $css = '';
217
218
            if ($pageNum == $this->currentPage()) {
219
                $css = " class=\"active\"";
220
            }
221
222
            $listItems .= "<li{$css}><a href=\"{$url}\">{$pageNum}</a></li>";
223
        }
224
225
        if($this->hasNextPage($paginator) && $additionalLinks) {
226
            $listItems .= "<li><a href=\"{$this->nextPageUrl($paginator)}\">&raquo;</a></li>";
227
        }
228
229
        $listItems .= "</ul>";
230
        return $listItems;
231
    }
232
233
    /**
234
     * Render html link tags for SEO indication of previous and next page.
235
     *
236
     * @param \Illuminate\Contracts\Pagination\LengthAwarePaginator $paginator
237
     * @param bool                                                  $full       Return the full version of the URL in for the first page
238
     *                                                                          Ex. /users/page/1 instead of /users
239
     *
240
     * @return string
241
     */
242
    public function renderRelLinks(LengthAwarePaginator $paginator, $full = false)
243
    {
244
        $urls = $this->allUrls($paginator, $full);
245
246
        $linkItems = "";
247
248
        foreach ($urls as $i => $url) {
249
250
            $pageNum = $i + 1;
251
252
            switch ($pageNum - $this->currentPage()) {
253
                case -1:
254
                    $linkItems .= "<link rel=\"prev\" href=\"{$url}\" />";
255
                    break;
256
                case 1:
257
                    $linkItems .= "<link rel=\"next\" href=\"{$url}\" />";
258
                    break;
259
            }
260
        }
261
262
        return $linkItems;
263
    }
264
265
    /**
266
     * @deprecated in favor of renderPageList.
267
     *
268
     * @param \Illuminate\Contracts\Pagination\LengthAwarePaginator $paginator
269
     * @param bool                                                  $full      Return the full version of the URL in for the first page
270
     *                                                                         Ex. /users/page/1 instead of /users
271
     *
272
     * @return string
273
     */
274
    public function renderHtml(LengthAwarePaginator $paginator, $full = false)
275
    {
276
        return $this->renderPageList($paginator, $full);
277
    }
278
279
    /**
280
     * Generate a page URL, based on the request's current URL.
281
     *
282
     * @param int  $page
283
     * @param bool $full Return the full version of the URL in for the first page
284
     *                   Ex. /users/page/1 instead of /users
285
     *
286
     * @return string
287
     */
288
    public function pageUrl($page, $full = false)
289
    {
290
        $currentPageUrl = $this->router->getCurrentRoute()->getUri();
291
292
        $url = $this->addPageQuery(str_replace('{pageQuery?}', '', $currentPageUrl), $page, $full);
293
294
        foreach ($this->router->getCurrentRoute()->bindParameters(app('request')) as $parameterName => $parameterValue) {
295
            $url = str_replace(['{'.$parameterName.'}', '{'.$parameterName.'?}'], $parameterValue, $url);
296
        }
297
298
        return $this->urlGenerator->to($url);
299
    }
300
301
    /**
302
     * Append the page query to a URL.
303
     *
304
     * @param string $url
305
     * @param int    $page
306
     * @param bool   $full Return the full version of the URL in for the first page
307
     *                     Ex. /users/page/1 instead of /users
308
     *
309
     * @return string
310
     */
311
    public function addPageQuery($url, $page, $full = false)
312
    {
313
        // If the first page's URL is requested and $full is set to false, there's nothing to be added.
314
        if ($page === 1 && !$full) {
315
            return $url;
316
        }
317
318
        return trim($url, '/')."/{$this->pageKeyword}/{$page}";
319
    }
320
321
    /**
322
     * Register the Route::paginate macro.
323
     */
324
    public function registerMacros()
325
    {
326
        $pageKeyword = $this->pageKeyword;
327
        $router = $this->router;
328
329
        $router->macro('paginate', function ($uri, $action) use ($pageKeyword, $router) {
330
            $router->group(
331
                ['middleware' => 'Spatie\PaginateRoute\SetPageMiddleware'],
332
                function () use ($pageKeyword, $router, $uri, $action) {
333
                    $router->get($uri.'/{pageQuery?}', $action)->where('pageQuery', $pageKeyword.'/[0-9]+');
334
                });
335
        });
336
    }
337
}
338