├── .gitignore
├── tests
├── bootstrap.php
├── Strana
│ ├── MakeSureTest.php
│ ├── EloquentTest.php
│ ├── PixieTest.php
│ ├── DoctrineDbalTest.php
│ └── PaginatorTest.php
└── TestCase.php
├── src
└── Strana
│ ├── Exceptions
│ ├── Exception.php
│ └── InvalidArgumentException.php
│ ├── Interfaces
│ └── CollectionAdapter.php
│ ├── Views
│ └── infiniteScroll.php
│ ├── InfiniteScroll.php
│ ├── Adapters
│ ├── ArrayAdapter.php
│ ├── EloquentAdapter.php
│ ├── PixieAdapter.php
│ └── DoctrineDbalAdapter.php
│ ├── ViewLoader.php
│ ├── ConfigHelper.php
│ ├── RecordSet.php
│ ├── LinkCreator.php
│ └── Paginator.php
├── .travis.yml
├── phpunit.xml
├── composer.json
├── LICENSE
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | vendor
2 | composer.phar
3 | composer.lock
4 | *~
--------------------------------------------------------------------------------
/tests/bootstrap.php:
--------------------------------------------------------------------------------
1 | assertTrue(true);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/Strana/Interfaces/CollectionAdapter.php:
--------------------------------------------------------------------------------
1 |
2 | !window.jQuery && document.write('
4 |
5 |
--------------------------------------------------------------------------------
/tests/TestCase.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
14 |
15 | tests/Strana/
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "usmanhalalit/strana",
3 | "description": "Pagination library for PHP, framework agnostic, with built-in adapters for Doctrine, Eloquent, Pixie and PHP Array.",
4 | "homepage": "https://github.com/usmanhalalit/strana",
5 | "keywords": ["paginator", "pagination", "page"],
6 | "license": "MIT",
7 | "minimum-stability": "dev",
8 | "authors":
9 | [
10 | {
11 | "name": "Muhammad Usman",
12 | "email": "hi@usman.it",
13 | "role": "Developer"
14 | }
15 | ],
16 |
17 | "require": {
18 | "php": ">=5.3.0"
19 | },
20 |
21 | "require-dev": {
22 | "phpunit/phpunit": "3.7.*",
23 | "usmanhalalit/pixie": "1.*@dev",
24 | "illuminate/database": "4.1.*@dev",
25 | "doctrine/dbal": "2.3.4"
26 | },
27 |
28 | "autoload": {
29 | "psr-0": {
30 | "Strana": "src/"
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 Muhammad Usman
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/src/Strana/InfiniteScroll.php:
--------------------------------------------------------------------------------
1 | viewLoader = $viewLoader;
22 | $this->configHelper = $configHelper;
23 | }
24 |
25 | /**
26 | * @param array $config
27 | * @return mixed
28 | *
29 | * Prepare infinite scroll JavaScript
30 | */
31 | public function getJs(Array $config = array())
32 | {
33 | $default = array(
34 | 'container' => '.container',
35 | 'item' => '.item',
36 | 'pagination' => '.pagination',
37 | 'next' => '.next a',
38 | 'loader' => 'Loading ...',
39 | 'triggerPageThreshold' => 5,
40 | );
41 |
42 | $data['config'] = array_merge($default, $config);
43 |
44 | return $this->viewLoader->load('infiniteScroll.php', $data);
45 | }
46 | }
--------------------------------------------------------------------------------
/src/Strana/Adapters/ArrayAdapter.php:
--------------------------------------------------------------------------------
1 | records = $records;
31 | $this->configHelper = $configHelper;
32 | }
33 |
34 | /**
35 | * @return array
36 | */
37 | public function slice()
38 | {
39 | $limit = $this->configHelper->getLimit();
40 | $offset = $this->configHelper->getOffset();
41 | return array_slice($this->records, $offset, $limit);
42 | }
43 |
44 | /**
45 | * @return int
46 | */
47 | public function total()
48 | {
49 | return count($this->records);
50 | }
51 | }
--------------------------------------------------------------------------------
/src/Strana/ViewLoader.php:
--------------------------------------------------------------------------------
1 | records = $records;
32 | $this->configHelper = $configHelper;
33 | }
34 |
35 | /**
36 | * @return array|static[]
37 | */
38 | public function slice()
39 | {
40 | $records = clone($this->records);
41 | $limit = $this->configHelper->getLimit();
42 | $offset = $this->configHelper->getOffset();
43 | return $records->limit($limit)->offset($offset)->get();
44 | }
45 |
46 | /**
47 | * @return int
48 | */
49 | public function total()
50 | {
51 | $records = clone($this->records);
52 | return $records->count();
53 | }
54 | }
--------------------------------------------------------------------------------
/tests/Strana/EloquentTest.php:
--------------------------------------------------------------------------------
1 | addConnection(array(
13 | 'driver' => 'sqlite',
14 | 'database' => ':memory:',
15 | ));
16 | $capsule->setAsGlobal();
17 | $capsule->bootEloquent();
18 |
19 | Capsule::statement("CREATE TABLE sample(
20 | t_key TEXT NOT NULL,
21 | t_value TEXT NOT NULL
22 | );");
23 |
24 | for ($i = 1; $i <= 100; $i++) {
25 | $record = array(
26 | 't_key' => 'Key ' . $i,
27 | 't_value' => 'Value ' . $i,
28 | );
29 |
30 | Capsule::table('sample')->insert($record);
31 | }
32 | }
33 |
34 | public function testPaginationWithLaravelAdapter()
35 | {
36 | $records = Capsule::table('sample');
37 | $expected = Capsule::table('sample')->limit(20)->offset(60)->get();
38 | $paginatorClass = new Paginator();
39 |
40 | $paginator = $paginatorClass->page(4)->perPage(20)->make($records);
41 |
42 | $this->assertEquals(100, $paginator->total(), 'Failed asserting pagination total.');
43 | $this->assertEquals($expected, $paginator->records(), 'Failed asserting pagination records.');
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/Strana/Adapters/PixieAdapter.php:
--------------------------------------------------------------------------------
1 | records = $records;
32 | $this->configHelper = $configHelper;
33 | }
34 |
35 | /**
36 | * @return null|\stdClass
37 | */
38 | public function slice()
39 | {
40 | $records = clone($this->records);
41 | $limit = $this->configHelper->getLimit();
42 | $offset = $this->configHelper->getOffset();
43 | return $records->limit($limit)->offset($offset)->get();
44 | }
45 |
46 | /**
47 | * @return int
48 | */
49 | public function total()
50 | {
51 | $records = clone($this->records);
52 | return $records->count();
53 | }
54 | }
--------------------------------------------------------------------------------
/tests/Strana/PixieTest.php:
--------------------------------------------------------------------------------
1 | 'sqlite', 'database' => ':memory:'));
17 | $this->qb = new QueryBuilderHandler($connection);
18 |
19 | $this->qb->query("CREATE TABLE sample(
20 | t_key TEXT NOT NULL,
21 | t_value TEXT NOT NULL
22 | );");
23 |
24 | for ($i = 1; $i <= 100; $i++) {
25 | $record = array(
26 | 't_key' => 'Key ' . $i,
27 | 't_value' => 'Value ' . $i,
28 | );
29 |
30 | $this->qb->table('sample')->insert($record);
31 | }
32 | }
33 |
34 | public function testPaginatorGenerateWithPixieAdapter()
35 | {
36 | $records = $this->qb->table('sample')->select('t_value');
37 | $expected = $this->qb->table('sample')->select('t_value')->limit(10)->offset(10)->get();
38 | $paginatorClass = new Paginator();
39 |
40 | $paginator = $paginatorClass->page(2)->perPage(10)->make($records);
41 |
42 | $this->assertEquals(100, $paginator->total(), 'Failed asserting pagination total.');
43 | $this->assertEquals($expected, $paginator->records(), 'Failed asserting pagination records.');
44 |
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/Strana/Adapters/DoctrineDbalAdapter.php:
--------------------------------------------------------------------------------
1 | records = $records;
32 | $this->configHelper = $configHelper;
33 | }
34 |
35 | /**
36 | * @return mixed|array
37 | */
38 | public function slice()
39 | {
40 | $records = clone($this->records);
41 | $limit = $this->configHelper->getLimit();
42 | $offset = $this->configHelper->getOffset();
43 | return $records->setMaxResults($limit)
44 | ->setFirstResult($offset)
45 | ->execute()
46 | ->fetchAll();
47 | }
48 |
49 | /**
50 | * @return mixed
51 | */
52 | public function total()
53 | {
54 | $records = clone($this->records);
55 | $records->select('count(*) as cnt');
56 | $count = $records->execute()->fetchColumn();
57 | return $count;
58 | }
59 | }
--------------------------------------------------------------------------------
/tests/Strana/DoctrineDbalTest.php:
--------------------------------------------------------------------------------
1 | ':memory:',
21 | 'driver' => 'pdo_sqlite',
22 | );
23 | $conn = DriverManager::getConnection($connectionParams, $config);
24 | $this->qb = $conn->createQueryBuilder();
25 |
26 | $sql = "CREATE TABLE sample(
27 | t_key TEXT NOT NULL,
28 | t_value TEXT NOT NULL
29 | );";
30 | $conn->query($sql);
31 |
32 | for ($i = 1; $i <= 90; $i++) {
33 | $conn->query("INSERT INTO SAMPLE VALUES ('Key$i', 'Value$i')");
34 | }
35 | }
36 |
37 | public function testPaginationWithDoctrineDbalAdapter()
38 | {
39 | $cqb = clone($this->qb);
40 | $records = $this->qb->select('*')->from('sample', 'sample');
41 |
42 | $cqb->select('*')->from('sample', 'sample')->setMaxResults(20)->setFirstResult(60);
43 | $expected = $cqb->execute()->fetchAll();
44 | /*var_dump($this->qb->execute()->fetchAll());
45 | exit;*/
46 | $paginatorClass = new Paginator();
47 | $paginator = $paginatorClass->page(4)->perPage(20)->make($records);
48 |
49 | $this->assertEquals(90, $paginator->total(), 'Failed asserting pagination total.');
50 | $this->assertEquals($expected, $paginator->records(), 'Failed asserting pagination records.');
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/Strana/ConfigHelper.php:
--------------------------------------------------------------------------------
1 | config = $config;
15 | $this->setDefaults();
16 | }
17 |
18 | /**
19 | * Set default config values
20 | */
21 | protected function setDefaults()
22 | {
23 | $get = $_GET;
24 | $page = isset($get['page']) ? (int) $get['page'] : 1;
25 | $defaults = array(
26 | 'perPage' => 20,
27 | 'page' => $page,
28 | 'maximumPages' => 5,
29 | 'infiniteScroll' => false,
30 | );
31 |
32 | $this->config = array_merge($defaults, $this->config);
33 | }
34 |
35 | /**
36 | * @return mixed
37 | */
38 | public function getCurrentPage()
39 | {
40 | return $this->config['page'];
41 | }
42 |
43 | /**
44 | * @return mixed
45 | */
46 | public function getOffset()
47 | {
48 | return $this->config['perPage'] * ($this->config['page'] - 1);
49 | }
50 |
51 | /**
52 | * @return mixed
53 | */
54 | public function getLimit()
55 | {
56 | return $this->config['perPage'];
57 | }
58 |
59 | /**
60 | * @return mixed
61 | */
62 | public function getMaximumPages()
63 | {
64 | return $this->config['maximumPages'];
65 | }
66 |
67 | /**
68 | * @return mixed
69 | */
70 | public function getInfiniteScroll()
71 | {
72 | return $this->config['infiniteScroll'];
73 | }
74 |
75 | /**
76 | * @param $totalRecords
77 | * @return float
78 | */
79 | public function getTotalPages($totalRecords)
80 | {
81 | $pages = $totalRecords / $this->getLimit();
82 | // If we have decimal value like 2.2 then we need 3 pages, ceil it.
83 | $pages = ceil($pages);
84 | return $pages;
85 | }
86 |
87 | }
--------------------------------------------------------------------------------
/src/Strana/RecordSet.php:
--------------------------------------------------------------------------------
1 | records = $records;
34 | $this->total = $total;
35 | $this->links = $links;
36 | }
37 |
38 | /**
39 | * @return array
40 | */
41 | public function records()
42 | {
43 | return $this->records;
44 | }
45 |
46 | /**
47 | * @return int
48 | */
49 | public function total()
50 | {
51 | return $this->total;
52 | }
53 |
54 | /**
55 | * @return mixed|void
56 | */
57 | public function rewind()
58 | {
59 | return reset($this->records);
60 | }
61 |
62 | /**
63 | * @return mixed
64 | */
65 | public function current()
66 | {
67 | return current($this->records);
68 | }
69 |
70 | /**
71 | * @return mixed
72 | */
73 | public function key()
74 | {
75 | return key($this->records);
76 | }
77 |
78 | /**
79 | * @return mixed|void
80 | */
81 | public function next()
82 | {
83 | return next($this->records);
84 | }
85 |
86 | /**
87 | * @return bool
88 | */
89 | public function valid()
90 | {
91 | return key($this->records) !== null;
92 | }
93 |
94 | /**
95 | * @param $links
96 | */
97 | public function setLinks($links)
98 | {
99 | $this->links = $links;
100 | }
101 |
102 | /**
103 | * @return null|string
104 | */
105 | public function links()
106 | {
107 | return $this->links;
108 | }
109 |
110 |
111 | /**
112 | * @return null|string
113 | */
114 | public function __toString()
115 | {
116 | return $this->links();
117 | }
118 | }
--------------------------------------------------------------------------------
/tests/Strana/PaginatorTest.php:
--------------------------------------------------------------------------------
1 | make($records, 'Array');
15 |
16 | $expected = array();
17 | for ($i = 1; $i <= 20; $i++) {
18 | $expected['Key ' . $i] = 'Value ' . $i;
19 | }
20 |
21 | $this->assertSame($expected, $paginator->records(), 'Failed asserting pagination records.');
22 | $this->assertEquals(100, $paginator->total(), 'Failed asserting pagination total.');
23 | }
24 |
25 | public function testPaginatorGenerateWithArrayAdapter()
26 | {
27 | $paginatorClass = new Paginator();
28 | $records = array();
29 | for ($i = 1; $i <= 100; $i++) {
30 | $records['Key ' . $i] = 'Value ' . $i;
31 | }
32 |
33 | $config = array(
34 | 'perPage' => 10,
35 | 'page' => 2,
36 | );
37 | $iasConfig = array('loaderDelay' => 800);
38 | $paginator = $paginatorClass->infiniteScroll($iasConfig)->make($records, 'Array', $config);
39 |
40 | $expected = array();
41 | for ($i = 11; $i <= 20; $i++) {
42 | $expected['Key ' . $i] = 'Value ' . $i;
43 | }
44 |
45 | $this->assertSame($expected, $paginator->records(), 'Failed asserting pagination records.');
46 | $this->assertEquals(100, $paginator->total(), 'Failed asserting pagination total.');
47 | }
48 |
49 | public function testHTMLOutput()
50 | {
51 | $paginatorClass = new Paginator();
52 | $records = array();
53 | for ($i = 1; $i <= 100; $i++) {
54 | $records['Key ' . $i] = 'Value ' . $i;
55 | }
56 |
57 | $paginator = $paginatorClass->page(4)->perPage(10)->make($records, 'Array');
58 |
59 | // Cover foreach, iterator
60 | foreach($paginator as $item) {
61 |
62 | }
63 |
64 | $expected = '
';
65 | $this->assertEquals($expected, (string)$paginator);
66 | }
67 |
68 | /**
69 | * @expectedException Strana\Exceptions\InvalidArgumentException
70 | */
71 | public function testAdapterNotFoundException()
72 | {
73 | $paginatorClass = new Paginator();
74 | $paginatorClass->make(array(), 'Foo');
75 | }
76 |
77 | /**
78 | * @expectedException Strana\Exceptions\InvalidArgumentException
79 | */
80 | public function testWithInvalidAdapter()
81 | {
82 | $paginatorClass = new Paginator();
83 | $paginatorClass->make(array(), new \stdClass());
84 | }
85 | }
--------------------------------------------------------------------------------
/src/Strana/LinkCreator.php:
--------------------------------------------------------------------------------
1 | configHelper = $configHelper;
22 | $this->infiniteScroll = $infiniteScroll;
23 | }
24 |
25 | /**
26 | * @param $totalRecords
27 | * @return string
28 | */
29 | public function createLinks($totalRecords)
30 | {
31 | $currentPage = $this->configHelper->getCurrentPage();
32 | $totalPages = $this->configHelper->getTotalPages($totalRecords);
33 | $pages = $this->getPages($totalRecords, $this->configHelper->getLimit(), $currentPage, $this->configHelper->getMaximumPages());
34 |
35 | $prevLiClass = 'prev';
36 | $prevLinkHref = 'javascript:void(0)';
37 | if ($currentPage == 1) {
38 | $prevLiClass = 'disabled';
39 | } else {
40 | $prevLinkHref = $this->buildQueryString($currentPage - 1);
41 | }
42 |
43 | $nextLiClass = 'next';
44 | $nextLinkHref = 'javascript:void(0)';
45 | if ($currentPage == $totalPages) {
46 | $nextLiClass = 'disabled';
47 | } else {
48 | $nextLinkHref = $this->buildQueryString($currentPage + 1);
49 | }
50 |
51 | $output = '';
59 |
60 | return $this->addInfiniteScroll($output);
61 | }
62 |
63 | protected function buildQueryString($page)
64 | {
65 | $get = $_GET;
66 | $get['page'] = $page;
67 | $queryString = http_build_query($get);
68 | return $queryString = '?' . $queryString;
69 | }
70 |
71 | /**
72 | * @param $output
73 | * @return string
74 | */
75 | protected function addInfiniteScroll($output)
76 | {
77 | if (($config = $this->configHelper->getInfiniteScroll()) !== false) {
78 | $output = $output . $this->infiniteScroll->getJs($config);
79 | }
80 |
81 | return $output;
82 | }
83 |
84 | /**
85 | * @param $total
86 | * @param null $limit
87 | * @param null $current
88 | * @param null $adjacents
89 | * @return array
90 | *
91 | * Credit: http://stackoverflow.com/a/7562895/656489
92 | */
93 | protected function getPages($total, $limit = null, $current = null, $adjacents = null)
94 | {
95 | $result = array();
96 |
97 | if (isset($total, $limit) === true)
98 | {
99 | $result = range(1, ceil($total / $limit));
100 |
101 | if (isset($current, $adjacents) === true)
102 | {
103 | if (($adjacents = floor($adjacents / 2) * 2 + 1) >= 1)
104 | {
105 | $result = array_slice($result, max(0, min(count($result) - $adjacents, intval($current) - ceil($adjacents / 2))), $adjacents);
106 | }
107 | }
108 | }
109 |
110 | return $result;
111 | }
112 | }
--------------------------------------------------------------------------------
/src/Strana/Paginator.php:
--------------------------------------------------------------------------------
1 | getConfig(), $config);
33 | $this->setConfig($config);
34 | $configHelper = new ConfigHelper($this->getConfig());
35 |
36 | if ($adapter) {
37 | $this->setAdapter($adapter);
38 | }
39 |
40 | $recordSet = $this->generate($records,$configHelper);
41 | $infiniteScroll = new InfiniteScroll(new ViewLoader(), $configHelper);
42 |
43 | $linkCreator = new LinkCreator($configHelper, $infiniteScroll);
44 | $links = $linkCreator->createLinks($recordSet->total());
45 | $recordSet->setLinks($links);
46 | return $recordSet;
47 | }
48 |
49 | /**
50 | * @param $currentPage
51 | * @return $this
52 | *
53 | * Set current page
54 | */
55 | public function page($currentPage)
56 | {
57 | $this->config['page'] = $currentPage;
58 | return $this;
59 | }
60 |
61 | /**
62 | * @param $perPage
63 | * @return $this
64 | *
65 | * Set items to be shown per page
66 | */
67 | public function perPage($perPage)
68 | {
69 | $this->config['perPage'] = $perPage;
70 | return $this;
71 | }
72 |
73 | /**
74 | * @param array $config
75 | * @return $this
76 | *
77 | * Enable infinite scroll and set config
78 | */
79 | public function infiniteScroll(Array $config = array())
80 | {
81 | $this->config['infiniteScroll'] = $config;
82 | return $this;
83 | }
84 |
85 | /**
86 | * @param array $config
87 | */
88 | public function setConfig(Array $config)
89 | {
90 | $this->config = $config;
91 | }
92 |
93 | /**
94 | * @return array
95 | */
96 | public function getConfig()
97 | {
98 | return $this->config;
99 | }
100 |
101 | /**
102 | * @param $adapter
103 | * @return $this
104 | */
105 | public function setAdapter($adapter)
106 | {
107 | $this->adapter = $adapter;
108 | return $this;
109 | }
110 |
111 | /**
112 | * @return mixed
113 | */
114 | public function getAdapter()
115 | {
116 | return $this->adapter;
117 | }
118 |
119 | /**
120 | * @param $records
121 | * @param ConfigHelper $configHelper
122 | * @return RecordSet
123 | */
124 | protected function generate($records, ConfigHelper $configHelper)
125 | {
126 | $adapterInstance = $this->makeAdapterInstance($this->getAdapter(), $records, $configHelper);
127 |
128 | $total = $adapterInstance->total();
129 | $slicedRecords = $adapterInstance->slice();
130 | $recordSet = new RecordSet($slicedRecords, $total);
131 |
132 | return $recordSet;
133 | }
134 |
135 | protected function makeAdapterInstance($adapter, $records, $configHelper)
136 | {
137 | if (is_object($adapter)) {
138 | // User defined custom adapter
139 | if (!$adapter instanceof CollectionAdapter) {
140 | throw new InvalidArgumentException('Adapter must implement Strana\Interfaces\CollectionAdapter.');
141 | }
142 | $adapterInstance = $adapter;
143 | } else {
144 | if (!$adapter || !is_string($adapter)) {
145 | // Auto detect
146 | $adapter = $this->detectAdapter($records);
147 | }
148 |
149 | $adapter = '\\Strana\\Adapters\\' . $adapter . 'Adapter';
150 | if (!class_exists($adapter)) {
151 | throw new InvalidArgumentException('Adapter not found ' . $adapter . '.' );
152 | }
153 |
154 | $adapterInstance = new $adapter($records, $configHelper);
155 | }
156 |
157 | return $adapterInstance;
158 | }
159 |
160 | /**
161 | * @param $records
162 | * @return string
163 | */
164 | protected function detectAdapter($records)
165 | {
166 | if (is_array($records)) {
167 | return 'Array';
168 | } elseif($records instanceof PixieQB) {
169 | return 'Pixie';
170 | } elseif($records instanceof DoctrineDbalQB) {
171 | return 'DoctrineDbal';
172 | } elseif($records instanceof EloquentQB) {
173 | return 'Eloquent';
174 | } else {
175 | return 'Undefined';
176 | }
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Strana
2 | ### Smart Pagination Library for PHP
3 |
4 | [](https://travis-ci.org/usmanhalalit/strana) [](https://insight.sensiolabs.com/projects/49091284-bd4e-455d-b821-ad6b33d25d37 "This project passes all Insight checks successfully. This is very rare, and is worthy of the Platinum medal. Congratulations to all the contributors to this project for such a high quality.") [](https://scrutinizer-ci.com/g/usmanhalalit/strana/) [](https://bitdeli.com/free "Bitdeli Badge") [](http://www.versioneye.com/php/usmanhalalit:strana/dev-master)
5 | ___
6 |
7 | A framework agnostic, smart pagination library for PHP. Just a few lines of code and fully functional pagination is ready.
8 |
9 | Paginate your records with Strana. Strana will slice(limit and offset) these records, generate pagination links for you and reads page number from them, all automatically.
10 |
11 | #### Features:
12 |
13 | - Built-in adapters for [Doctrine](http://www.doctrine-project.org/projects/dbal.html), [Eloquent (Laravel)](https://github.com/illuminate/database), [Pixie](https://github.com/usmanhalalit/pixie), PHP Array and you can do it manually.
14 | - Readable syntax
15 | - Add Infinite Scroll with one line
16 | - It automatically detects which DBAL you are using.
17 | - Styles automatically with Twitter Bootstrap, Zurb Foundation and most of other CSS frameworks.
18 |
19 |
20 | #### Screenshot:
21 |
22 | 
23 |
24 | ## Example
25 | Basically Strana makes it very easy, like the code below:
26 | ```PHP
27 | $paginator = $strana->perPage(10)->make($records);
28 | ```
29 | **That's basically it.**
30 |
31 | ### Full Usage Example
32 | ```PHP
33 | // Make sure you have Composer's autoload file included
34 | require 'vendor/autoload.php';
35 |
36 | $strana = new \Strana\Paginator();
37 | $records = array(1, 2, 3, .... 100);
38 | $paginator = $strana->perPage(10)->make($records);
39 |
40 | // Loop paginated items
41 | foreach ($paginator as $item) {
42 | echo $item['field_name'] . '
';
43 | }
44 |
45 | // Print pagination links
46 | echo '
' . $paginator;
47 | ```
48 |
49 |
50 | There are some advanced options which are documented below. Sold? Lets install.
51 |
52 | ## Installation
53 |
54 | Strana uses [Composer](http://getcomposer.org/doc/00-intro.md#installation-nix) to make things easy, its a requirement.
55 |
56 | Learn to use composer and add this to require section (in your composer.json):
57 |
58 | "usmanhalalit/strana": "1.*@dev"
59 |
60 | And run:
61 |
62 | composer update
63 |
64 | Library on [Packagist](https://packagist.org/packages/usmanhalalit/strana).
65 |
66 |
67 |
68 | ## Full Walkthrough
69 |
70 | Strana has built in adapters for Doctrine Dbal, Laravel Eloquent, Pixie and PHP native arrays. If you want to paginate from any of these then you're in luck. More adapters will come according to feedback.
71 |
72 | ### Step 1:
73 | Prepare your database or array records:
74 |
75 | **Doctrine Dbal Example:**
76 |
77 | ```PHP
78 | $records = $qb->select('*')->from('sample', 'sample');
79 | ```
80 | **Laravel Eloquent (or Query Builder) Example:**
81 |
82 | ```PHP
83 | $records = Capsule::select('*')->from('sample');
84 | ```
85 | **Pixie Example:**
86 |
87 | ```PHP
88 | $records = QB::select('*')->from('sample');
89 | ```
90 | **Array Example:**
91 |
92 | ```PHP
93 | $records = array(1, 2, 3, 4, 5);
94 | ```
95 |
96 | ### Step 2:
97 | Paginate your records with Strana. Strana will slice(limit and offset) these records, generate pagination links for you and reads page number from them, all automatically.
98 |
99 | ```PHP
100 | $strana = new \Strana\Paginator();
101 | $paginator = $strana->perPage(10)->make($records);
102 | ```
103 |
104 | ### Step 3:
105 | Loop paginated records to display:
106 |
107 | ```PHP
108 | foreach ($paginator as $item) {
109 | echo $item['field'] . '
';
110 | }
111 | ```
112 |
113 | ### Step 4:
114 | Print your pagination links:
115 | ```PHP
116 | echo $paginator;
117 | ```
118 |
119 | It will produce something like this:
120 |
121 | 
122 |
123 |
124 | ## Infinite Scroll
125 | Strana comes with out of the box Infinite Scrolling, enable it with just one method.
126 |
127 | ```PHP
128 | $strana->infiniteScroll()->perPage(10)->make($records);
129 | ```
130 | And then wrap all your pagination items and pagination links with certain CSS classes, like the example below.
131 |
132 | #### Example
133 |
134 | ```PHP
135 | echo '';
136 | foreach ($paginator as $item) {
137 | print('
' . $item['t_value'] . '
');
138 | }
139 |
140 |
141 | echo '
' . $paginator;
142 | echo '
';
143 | ```
144 |
145 | **That's it**, you're done with infinite scrolling.
146 | ___
147 |
148 | Strana uses the awesome [Infinite Ajax Scroll](https://github.com/webcreate/Infinite-Ajax-Scroll) jQuery plugin. All config options supported by this plugin can be passed with Strana.
149 |
150 | ```PHP
151 | $iasConfig = array(
152 | 'loaderDelay' => 600,
153 | 'loader' => '
',
154 | );
155 |
156 | $strana->infiniteScroll($iasConfig)->perPage(10)->make($records);
157 | ```
158 |
159 | Cool, yeah?
160 |
161 | ## Usage API
162 | #### perPage($perPage)
163 | Number of items on per page, default 10.
164 |
165 |
166 | #### page($page)
167 | Which page to show, default is read from query string else 1.
168 |
169 |
170 | #### infiniteScroll(Array $config = array())
171 | Enable Infinite Scrolling using Ajax. Options can be passed using `$config`.
172 |
173 | #### make($records, $adapter = null, $config = array())
174 | Make and return paginator object.
175 |
176 | `$records` = records to be paginated.
177 |
178 | `$adapter` = which adapter you want to use as string, `DoctrineDbal`, `Eloquent`, `Pixie`, `Array` and so. If omitted or a falsy value is given then Strana is smart enough to detect the adapter itself.
179 | If you want to use your own(custom) adapter then pass the object/instance here. Your custom adapter must implement ` Strana\Interfaces\CollectionAdapter` interface.
180 |
181 | `$config` = all Strana config can be passed here too, as an array. like `$config = array('maximumPages' => 7)`
182 |
183 | ## The Recordset Object
184 |
185 | `make()` method returns an instance of `Strana\RecordSet` class. Its a **polymorphic** object, for example:
186 | ```PHP
187 | $paginator = $strana->make($records);
188 | ```
189 | Here, if you loop `$paginator` with `foreach` then it will work like an array and iterate through paginated items, if you `echo` `$paginator` it will work like a string and print the pagination links. And of course you can use like a class object.
190 | `$paginator->records()` will return paginated records.
191 | `$paginator->total()` will return total records count.
192 | `$paginator->links()` will return pagination links.
193 |
194 |
195 | ## Developing Your Own Adapter
196 |
197 | If you are not using the database tool whose adapter ships with Strana then you can build your own adapter with ease. Create your class which must implement `Strana\Interfaces\CollectionAdapter`.
198 |
199 | Example adapter, please read comments to understand.
200 |
201 |
202 | ```PHP
203 | records = $records;
224 | $this->configHelper = $configHelper;
225 | }
226 |
227 | /**
228 | * This method should limit and offset your records and return.
229 | */
230 | public function slice()
231 | {
232 | // Here you will get the database object passed to Strana.
233 | // Clone it.
234 | $records = clone($this->records);
235 |
236 | // Get the limit number from Strana config
237 | $limit = $this->configHelper->getLimit();
238 |
239 | // Get the offset number from Strana config
240 | $offset = $this->configHelper->getOffset();
241 |
242 | // Limit your records
243 | $records->limit($limit);
244 | // Offset your records
245 | $records->offset($offset);
246 |
247 | // Return your sliced records
248 | return $records->get();
249 | }
250 |
251 | /**
252 | * This method should return total count of all of your records.
253 | */
254 | public function total()
255 | {
256 | // Here you will get the database object passed to Strana.
257 | // Clone it.
258 | $records = clone($this->records);
259 |
260 | // Return your total records count, unsliced.
261 | return $records->count();
262 | }
263 | }
264 | ```
265 |
266 | Please also look at the `ArrayAdapter` to get more idea.
267 |
268 | #### Using Your Adapter
269 |
270 |
271 | ```PHP
272 | $strana = new \Strana\Paginator();
273 | $configHelper = new \Strana\ConfigHelper($strana->getConfig());
274 | $adapter = new CustomAdapter($yourRecords, $configHelper);
275 | $paginator = $paginatorClass->make($yourRecords, $adapter);
276 | ```
277 |
278 | ___
279 | © 2013 [Muhammad Usman](http://usman.it/). Licensed under MIT license.
280 |
--------------------------------------------------------------------------------