1
2/**
3 * This file is part of the Phalcon Framework.
4 *
5 * (c) Phalcon Team <team@phalcon.io>
6 *
7 * For the full copyright and license information, please view the LICENSE.txt
8 * file that was distributed with this source code.
9 */
10
11namespace Phalcon\Paginator\Adapter;
12
13use Phalcon\Helper\Arr;
14use Phalcon\Mvc\ModelInterface;
15use Phalcon\Mvc\Model\ResultsetInterface;
16use Phalcon\Paginator\Exception;
17use Phalcon\Paginator\RepositoryInterface;
18
19/**
20 * Phalcon\Paginator\Adapter\Model
21 *
22 * This adapter allows to paginate data using a Phalcon\Mvc\Model resultset as a
23 * base.
24 *
25 * ```php
26 * use Phalcon\Paginator\Adapter\Model;
27 *
28 * $paginator = new Model(
29 *     [
30 *         "model" => Robots::class,
31 *         "limit" => 25,
32 *         "page"  => $currentPage,
33 *     ]
34 * );
35 *
36 *
37 * $paginator = new Model(
38 *     [
39 *         "model" => Robots::class,
40 *         "parameters" => [
41 *              "columns" => "id, name"
42 *         ],
43 *         "limit" => 12,
44 *         "page"  => $currentPage,
45 *     ]
46 * );
47 *
48 *
49 * $paginator = new Model(
50 *     [
51 *         "model" => Robots::class,
52 *         "parameters" => [
53 *              "type = :type:",
54 *              "bind" => [
55 *                  "type" => "mechanical"
56 *              ],
57 *              "order" => "name"
58 *         ],
59 *         "limit" => 16,
60 *         "page"  => $currentPage,
61 *     ]
62 * );
63 *
64 * $paginator = new Model(
65 *     [
66 *         "model" => Robots::class,
67 *         "parameters" => "(id % 2) = 0",
68 *         "limit" => 8,
69 *         "page"  => $currentPage,
70 *     ]
71 * );
72 *
73 *
74 * $paginator = new Model(
75 *     [
76 *         "model" => Robots::class,
77 *         "parameters" => [ "(id % 2) = 0" ],
78 *         "limit" => 8,
79 *         "page"  => $currentPage,
80 *     ]
81 * );
82 *
83 * $paginate = $paginator->paginate();
84 *```
85 */
86class Model extends AbstractAdapter
87{
88    /**
89     * Returns a slice of the resultset to show in the pagination
90     */
91    public function paginate() -> <RepositoryInterface>
92    {
93        var config, items, pageItems, modelClass, parameters;
94        int pageNumber, limit, rowcount, next, totalPages,
95            previous;
96
97        let limit      = (int) this->limitRows,
98            config     = this->config,
99            pageNumber = (int) this->page,
100            modelClass = <ModelInterface> config["model"],
101            parameters = Arr::get(config, "parameters", [], "array");
102
103        //Prevents 0 or negative page numbers
104        if pageNumber <= 0 {
105            let pageNumber = 1;
106        }
107
108        let rowcount  = (int) call_user_func([modelClass, "count"], parameters),
109            pageItems = [];
110
111        if rowcount % limit != 0 {
112            let totalPages = (int) (rowcount / limit + 1);
113        } else {
114            let totalPages = (int) (rowcount / limit);
115        }
116
117        if rowcount > 0 {
118            let parameters["limit"]  = limit,
119                parameters["offset"] = limit * (pageNumber - 1);
120
121            let items = <ResultsetInterface> call_user_func(
122                [modelClass, "find"],
123                parameters
124            );
125            let pageItems = items->toArray();
126        }
127
128        //Fix next
129        let next = pageNumber + 1;
130
131        if next > totalPages {
132            let next = totalPages;
133        }
134
135        if pageNumber > 1 {
136            let previous = pageNumber - 1;
137        } else {
138            let previous = 1;
139        }
140
141        return this->getRepository(
142            [
143                RepositoryInterface::PROPERTY_ITEMS         : pageItems,
144                RepositoryInterface::PROPERTY_TOTAL_ITEMS   : rowcount,
145                RepositoryInterface::PROPERTY_LIMIT         : this->limitRows,
146                RepositoryInterface::PROPERTY_FIRST_PAGE    : 1,
147                RepositoryInterface::PROPERTY_PREVIOUS_PAGE : previous,
148                RepositoryInterface::PROPERTY_CURRENT_PAGE  : pageNumber,
149                RepositoryInterface::PROPERTY_NEXT_PAGE     : next,
150                RepositoryInterface::PROPERTY_LAST_PAGE     : totalPages
151            ]
152        );
153    }
154}
155