1 <?php
2
3 namespace Docolight\Support;
4
5 use Iterator;
6 use CActiveRecord;
7
8 /**
9 * Iterate your active record in a page. Usefull to make a paging report.
10 *
11 * ```php
12 *
13 * $model = MyModel::model()->findByPk(1);
14 *
15 * $pager = new IterablePager($model, 20);
16 *
17 *
18 * foreach($pager as $stack)
19 * {
20 * // $stack = array with 20 length, contains MyModel implementation
21 * // next loop will be the next 20 and so on until the last of your
22 * // data. it respects your criteria also.
23 * }
24 * ```
25 */
26 abstract class IterablePager implements Iterator
27 {
28 /**
29 * Total data.
30 *
31 * @var int
32 */
33 protected $total;
34
35 /**
36 * Current data.
37 *
38 * @var array
39 */
40 protected $current;
41
42 /**
43 * Model.
44 *
45 * @var CActiveRecord
46 */
47 protected $model;
48
49 /**
50 * Criteria.
51 *
52 * @var CDbCriteria
53 */
54 protected $criteria;
55
56 /**
57 * Class constructor.
58 *
59 * @param CActiveRecord $model
60 * @param int $limit
61 */
62 public function __construct(CActiveRecord $model, $limit = 10)
63 {
64 // Property assignment
65 $this->model = $model;
66 $this->criteria = clone $model->getDbCriteria();
67
68 // Count data
69 // Make sure it has no limit
70 $this->criteria->limit = null;
71 $model->setDbCriteria($this->criteria);
72 $this->total = $model->count();
73
74 // Start from zero
75 $this->criteria->offset = 0;
76
77 // Set limit
78 $this->criteria->limit = $limit;
79
80 // Set criteria
81 $this->model->setDbCriteria($this->criteria);
82
83 // Fetch first collection
84 $this->current = $this->prepare($this->model->findAll($this->criteria));
85 }
86
87 /**
88 * Rewind cursor.
89 */
90 public function rewind()
91 {
92 $this->criteria->offset = 0;
93 }
94
95 /**
96 * Get current cursor.
97 *
98 * @return array
99 */
100 public function current()
101 {
102 // Fetch new collection
103 $this->current = $this->prepare($this->model->findAll($this->criteria));
104
105 return $this->current;
106 }
107
108 /**
109 * Fetch next page.
110 */
111 public function next()
112 {
113 $this->criteria->offset = $this->criteria->offset + $this->criteria->limit;
114
115 // Set new criteria of offset
116 $this->model->setDbCriteria($this->criteria);
117 }
118
119 /**
120 * Determine whether next page exists.
121 *
122 * @return bool
123 */
124 public function valid()
125 {
126 return ($this->criteria->offset) <= ($this->total);
127 }
128
129 /**
130 * Get current offset.
131 *
132 * @return int
133 */
134 public function key()
135 {
136 return $this->criteria->offset;
137 }
138
139 /**
140 * Prepare the data before we store them in $current property.
141 *
142 * @param array $items
143 *
144 * @return mixed
145 */
146 abstract protected function prepare(array $items);
147 }
148