1 <?php
2
3 4 5 6 7 8 9 10
11
12 namespace Grido\DataSources;
13
14 use Grido\Components\Filters\Condition;
15
16 17 18 19 20 21 22 23 24 25 26
27 class ArraySource extends \Nette\Object implements IDataSource
28 {
29
30 protected $data;
31
32 33 34
35 public function __construct(array $data)
36 {
37 $this->data = $data;
38 }
39
40 41 42 43 44
45 protected function makeWhere(Condition $condition, array $data = NULL)
46 {
47 $data = $data === NULL
48 ? $this->data
49 : $data;
50
51 $that = $this;
52 return array_filter($data, function ($row) use ($condition, $that) {
53 if ($condition->callback) {
54 return callback($condition->callback)->invokeArgs(array($condition->value, $row));
55 }
56
57 $i = 0;
58 $results = array();
59 foreach ($condition->column as $column) {
60 if (Condition::isOperator($column)) {
61 $results[] = " $column ";
62
63 } else {
64 $i = count($condition->condition) > 1 ? $i : 0;
65 $results[] = (int) $that->compare(
66 $row[$column],
67 $condition->condition[$i],
68 isset($condition->value[$i]) ? $condition->value[$i] : NULL
69 );
70
71 $i++;
72 }
73 }
74
75 $result = implode('', $results);
76 return count($condition->column) === 1
77 ? (bool) $result
78 : eval("return $result;");
79 });
80 }
81
82 83 84 85 86 87 88
89 public function compare($actual, $condition, $expected)
90 {
91 $expected = (array) $expected;
92 $expected = current($expected);
93 $cond = str_replace(' ?', '', $condition);
94
95 if ($cond === 'LIKE') {
96 $pattern = str_replace('%', '(.|\s)*', preg_quote($expected, '/'));
97 return (bool) preg_match("/^{$pattern}$/i", $actual);
98
99 } elseif ($cond === '=') {
100 return $actual == $expected;
101
102 } elseif ($cond === '<>') {
103 return $actual != $expected;
104
105 } elseif ($cond === 'IS NULL') {
106 return $actual === NULL;
107
108 } elseif ($cond === 'IS NOT NULL') {
109 return $actual !== NULL;
110
111 } elseif (in_array($cond, array('<', '<=', '>', '>='))) {
112 return eval("return {$actual} {$cond} {$expected};");
113
114 } else {
115 throw new \InvalidArgumentException("Condition '$condition' not implemented yet.");
116 }
117 }
118
119
120
121 122 123
124 public function getCount()
125 {
126 return count($this->data);
127 }
128
129 130 131
132 public function getData()
133 {
134 return $this->data;
135 }
136
137 138 139
140 public function filter(array $conditions)
141 {
142 foreach ($conditions as $condition) {
143 $this->data = $this->makeWhere($condition);
144 }
145 }
146
147 148 149 150
151 public function limit($offset, $limit)
152 {
153 $this->data = array_slice($this->data, $offset, $limit);
154 }
155
156 157 158 159
160 public function sort(array $sorting)
161 {
162 if (count($sorting) > 1) {
163 throw new \Exception('Multi-column sorting is not implemented yet.');
164 }
165
166 foreach ($sorting as $column => $sort) {
167 $data = array();
168 foreach ($this->data as $item) {
169 $sorter = (string) $item[$column];
170 $data[$sorter][] = $item;
171 }
172
173 if ($sort === 'ASC') {
174 ksort($data);
175 } else {
176 krsort($data);
177 }
178
179 $this->data = array();
180 foreach ($data as $i) {
181 foreach ($i as $item) {
182 $this->data[] = $item;
183 }
184 }
185 }
186 }
187
188 189 190 191 192 193 194
195 public function suggest($column, array $conditions, $limit)
196 {
197 $data = $this->data;
198 foreach ($conditions as $condition) {
199 $data = $this->makeWhere($condition, $data);
200 }
201
202 array_slice($data, 1, $limit);
203
204 $items = array();
205 foreach ($data as $row) {
206 if (is_string($column)) {
207 $value = (string) $row[$column];
208 } elseif (is_callable($column)) {
209 $value = (string) $column($row);
210 } else {
211 $type = gettype($column);
212 throw new \InvalidArgumentException("Column of suggestion must be string or callback, $type given.");
213 }
214
215 $items[$value] = \Nette\Templating\Helpers::escapeHtml($value);
216 }
217
218 return array_values($items);
219 }
220 }
221