Completed
Push — master ( c95648...9320fe )
by Vipul
04:13
created

PaginateRoute::renderHtml()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
1
<?php
2
3
namespace Vipertecpro\PaginateRoute;
4
5
use Illuminate\Contracts\Pagination\Paginator;
6
use Illuminate\Contracts\Routing\UrlGenerator;
7
use Illuminate\Pagination\LengthAwarePaginator;
8
use Illuminate\Routing\RouteParameterBinder;
9
use Illuminate\Routing\Router;
10
use Illuminate\Support\Facades\Request;
11
use Illuminate\Translation\Translator;
12
13
class PaginateRoute
14
{
15
    /**
16
     * @var Translator
17
     */
18
    protected $translator;
19
20
    /**
21
     * @var Router
22
     */
23
    protected $router;
24
25
    /**
26
     * @var UrlGenerator
27
     */
28
    protected $urlGenerator;
29
30
    /**
31
     * @var string|array
32
     */
33
    protected $pageKeyword;
34
35
    /**
36
     * @param Translator $translator
37
     * @param Router $router
38
     * @param UrlGenerator $urlGenerator
39
     */
40
    public function __construct(Translator $translator, Router $router, UrlGenerator $urlGenerator)
41
    {
42
        $this->translator = $translator;
43
        $this->router = $router;
44
        $this->urlGenerator = $urlGenerator;
45
46
        // Unfortunately we can't do this in the service provider since routes are booted first
47
        $this->translator->addNamespace('paginateroute', __DIR__.'/../resources/lang');
48
49
        $this->pageKeyword = $this->translator->get('paginateroute::paginateroute.page');
50
    }
51
52
    /**
53
     * Return the current page.
54
     *
55
     * @return int
56
     */
57
    public function currentPage()
58
    {
59
        $currentRoute = $this->router->getCurrentRoute();
60
61
        if (! $currentRoute) {
62
            return 1;
63
        }
64
65
        $query = $currentRoute->parameter('pageQuery');
66
67
        return (int) str_replace($this->pageKeyword.'/', '', $query) ?: 1;
68
    }
69
70
    /**
71
     * Check if the given page is the current page.
72
     *
73
     * @param int $page
74
     *
75
     * @return bool
76
     */
77
    public function isCurrentPage($page): bool
78
    {
79
        return $this->currentPage() === $page;
80
    }
81
82
    /**
83
     * Get the next page number.
84
     *
85
     * @param Paginator $paginator
86
     *
87
     * @return int|void
88
     */
89
    public function nextPage(Paginator $paginator)
90
    {
91
        if (! $paginator->hasMorePages()) {
92
            return;
93
        }
94
95
        return $this->currentPage() + 1;
96
    }
97
98
    /**
99
     * Determine wether there is a next page.
100
     *
101
     * @param Paginator $paginator
102
     *
103
     * @return bool
104
     */
105
    public function hasNextPage(Paginator $paginator): bool
106
    {
107
        return $this->nextPage($paginator) !== null;
108
    }
109
110
    /**
111
     * Get the next page URL.
112
     *
113
     * @param Paginator $paginator
114
     *
115
     * @return string|void
116
     */
117
    public function nextPageUrl(Paginator $paginator)
118
    {
119
        $nextPage = $this->nextPage($paginator);
120
121
        if ($nextPage === null) {
122
            return;
123
        }
124
125
        return $this->pageUrl($nextPage);
126
    }
127
128
    /**
129
     * Get the previous page number.
130
     *
131
     * @return int|void|null
132
     */
133
    public function previousPage()
134
    {
135
        if ($this->currentPage() <= 1) {
136
            return;
137
        }
138
139
        return $this->currentPage() - 1;
140
    }
141
142
    /**
143
     * Determine wether there is a previous page.
144
     *
145
     * @return bool
146
     */
147
    public function hasPreviousPage(): bool
148
    {
149
        return $this->previousPage() !== null;
150
    }
151
152
    /**
153
     * Get the previous page URL.
154
     *
155
     * @param bool $full Return the full version of the URL in for the first page
156
     *                   Ex. /users/page/1 instead of /users
157
     *
158
     * @return string|void|null
159
     */
160
    public function previousPageUrl($full = false): ?string
161
    {
162
        $previousPage = $this->previousPage();
163
164
        if ($previousPage === null) {
165
            return;
166
        }
167
168
        return $this->pageUrl($previousPage, $full);
169
    }
170
171
    /**
172
     * Get all urls in an array.
173
     *
174
     * @param LengthAwarePaginator $paginator
175
     * @param bool                                                  $full      Return the full version of the URL in for the first page
176
     *                                                                         Ex. /users/page/1 instead of /users
177
     *
178
     * @return array
179
     */
180
    public function allUrls(LengthAwarePaginator $paginator, $full = false): array
181
    {
182
        if (! $paginator->hasPages()) {
183
            return [];
184
        }
185
186
        $urls = [];
187
        $left = $this->getLeftPoint($paginator);
188
        $right = $this->getRightPoint($paginator);
189
        for ($page = $left; $page <= $right; $page++) {
190
            $urls[$page] = $this->pageUrl($page, $full);
191
        }
192
193
        return $urls;
194
    }
195
196
    /**
197
     * Get the left most point in the pagination element.
198
     *
199
     * @param LengthAwarePaginator $paginator
200
     * @return int
201
     */
202
    public function getLeftPoint(LengthAwarePaginator $paginator): int
203
    {
204
        if ($paginator instanceof LengthAwarePaginator) {
205
            $side = $paginator->onEachSide;
206
        }else{
207
            $side = 0;
208
        }
209
        $current = $paginator->currentPage();
210
        $last = $paginator->lastPage();
211
212
        if (! empty($side)) {
213
            $x = $current + $side;
214
            $offset = $x >= $last ? $x - $last : 0;
215
            $left = $current - $side - $offset;
216
        }
217
        if(!isset($left) || $left < 1){
218
            return 1;
219
        }
220
        return $left;
221
    }
222
223
    /**
224
     * Get the right or last point of the pagination element.
225
     *
226
     * @param LengthAwarePaginator $paginator
227
     * @return int
228
     */
229
    public function getRightPoint(LengthAwarePaginator $paginator): int
230
    {
231
        $side = $paginator->onEachSide;
232
        $current = $paginator->currentPage();
233
        $last = $paginator->lastPage();
234
235
        if (! empty($side)) {
236
            $offset = $current <= $side ? $side - $current + 1 : 0;
237
            $right = $current + $side + $offset;
238
        }
239
        if(!isset($right) || $right > $last){
240
            return $last;
241
        }
242
        return $right;
243
    }
244
245
    /**
246
     * Render a plain html list with previous, next and all urls. The current page gets a current class on the list item.
247
     *
248
     * @param LengthAwarePaginator $paginator
249
     * @param bool                                                  $full              Return the full version of the URL in for the first page
250
     *                                                                                 Ex. /users/page/1 instead of /users
251
     * @param string                                                $class             Include class on pagination list
252
     *                                                                                 Ex. <ul class="pagination">
253
     * @param bool                                                  $additionalLinks   Include prev and next links on pagination list
254
     *
255
     * @return string
256
     */
257
258
    public function renderPageList(LengthAwarePaginator $paginator, $full = false, $class = null, $additionalLinks = false)
259
    {
260
        $urls = $this->allUrls($paginator, $full);
261
        if ($class !== null) {
262
            $class = " class=\"$class\"";
263
        }
264
        $listItems = "<ul{$class}>";
265
        if ($this->hasPreviousPage() && $additionalLinks) {
266
            $listItems .= "<li class='page-item'> <a class='page-link' href=\"{$this->previousPageUrl()}\">&laquo;</a></li>";
267
        }
268
        foreach ($urls as $i => $url) {
269
            $pageNum = $i;
270
            $css = ' class="page-item"';
271
            $link = "<a class='page-link' href=\"{$url}\">{$pageNum}</a>";
272
            if ($pageNum === $this->currentPage()) {
273
                $css = ' class="page-item active"';
274
                $link = "<span class='page-link' href=\"{$url}\">{$pageNum}</span>";
275
            }
276
            $listItems .= "<li{$css}>$link</li>";
277
        }
278
        if ($this->hasNextPage($paginator) && $additionalLinks) {
279
            $listItems .= "<li class='page-item'> <a class='page-link' href=\"{$this->nextPageUrl($paginator)}\">&raquo;</a></li>";
280
        }
281
        $listItems .= '</ul>';
282
        return $listItems;
283
    }
284
    /**
285
     * Render html link tags for SEO indication of previous and next page.
286
     *
287
     * @param LengthAwarePaginator $paginator
288
     * @param bool                                                  $full       Return the full version of the URL in for the first page
289
     *                                                                          Ex. /users/page/1 instead of /users
290
     *
291
     * @return string
292
     */
293
    public function renderRelLinks(LengthAwarePaginator $paginator, $full = false): string
294
    {
295
        $urls = $this->allUrls($paginator, $full);
296
297
        $linkItems = '';
298
299
        foreach ($urls as $i => $url) {
300
            $pageNum = $i + 1;
301
302
            switch ($pageNum - $this->currentPage()) {
303
                case -1:
304
                    $linkItems .= "<link rel=\"prev\" href=\"{$url}\" />";
305
                    break;
306
                case 1:
307
                    $linkItems .= "<link rel=\"next\" href=\"{$url}\" />";
308
                    break;
309
            }
310
        }
311
312
        return $linkItems;
313
    }
314
315
    /**
316
     * @param LengthAwarePaginator $paginator
317
     * @param bool $full      Return the full version of the URL in for the first page
318
     *                                                                         Ex. /users/page/1 instead of /users
319
     *
320
     * @return string
321
     *@deprecated in favor of renderPageList.
322
     *
323
     */
324
    public function renderHtml(LengthAwarePaginator $paginator, $full = false): string
325
    {
326
        return $this->renderPageList($paginator, $full);
327
    }
328
329
    /**
330
     * Generate a page URL, based on the request's current URL.
331
     *
332
     * @param int  $page
333
     * @param bool $full Return the full version of the URL in for the first page
334
     *                   Ex. /users/page/1 instead of /users
335
     *
336
     * @return string
337
     */
338
    public function pageUrl($page, $full = false): string
339
    {
340
        $currentPageUrl = $this->router->getCurrentRoute()->uri();
341
342
        $url = $this->addPageQuery(str_replace('{pageQuery?}', '', $currentPageUrl), $page, $full);
343
344
        foreach ((new RouteParameterBinder($this->router->getCurrentRoute()))->parameters(app('request')) as $parameterName => $parameterValue) {
0 ignored issues
show
Bug introduced by
It seems like $this->router->getCurrentRoute() can be null; however, __construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
345
            $url = str_replace(['{'.$parameterName.'}', '{'.$parameterName.'?}'], $parameterValue, $url);
346
        }
347
348
        $query = Request::getQueryString();
349
350
        $query = $query
351
            ? '?'.$query
352
            : '';
353
354
        return $this->urlGenerator->to($url).$query;
355
    }
356
357
    /**
358
     * Append the page query to a URL.
359
     *
360
     * @param string $url
361
     * @param int    $page
362
     * @param bool   $full Return the full version of the URL in for the first page
363
     *                     Ex. /users/page/1 instead of /users
364
     *
365
     * @return string
366
     */
367
    public function addPageQuery($url, $page, $full = false): string
368
    {
369
        // If the first page's URL is requested and $full is set to false, there's nothing to be added.
370
        if ($page === 1 && ! $full) {
371
            return $url;
372
        }
373
374
        return trim($url, '/')."/{$this->pageKeyword}/{$page}";
375
    }
376
377
    /**
378
     * Register the Route::paginate macro.
379
     */
380
    public function registerMacros(): void
381
    {
382
        $pageKeyword = $this->pageKeyword;
383
        $router = $this->router;
384
385
        $router->macro('paginate', function ($uri, $action) use ($pageKeyword, $router) {
386
            $route = null;
387
388
            $router->group(
389
                ['middleware' => 'Vipertecpro\PaginateRoute\SetPageMiddleware'],
390
                function () use ($pageKeyword, $router, $uri, $action, &$route) {
391
                    $route = $router->get($uri.'/{pageQuery?}', $action)->where('pageQuery', $pageKeyword.'/[0-9]+');
392
                });
393
394
            return $route;
395
        });
396
    }
397
}
398