1 <?php
2
3 4 5 6 7 8 9 10
11
12 namespace Grido\DataSources;
13
14 use Doctrine\ORM\Tools\Pagination\Paginator;
15 use Grido\Components\Filters\Condition;
16 use Nette\Utils\Strings;
17
18 19 20 21 22 23 24 25 26 27 28 29 30 31
32 class Doctrine extends \Nette\Object implements IDataSource
33 {
34
35 protected $qb;
36
37
38 protected $filterMapping;
39
40
41 protected $sortMapping;
42
43
44 protected $useOutputWalkers;
45
46
47 protected $fetchJoinCollection = TRUE;
48
49
50 protected $rand;
51
52 53 54 55 56 57 58
59 public function __construct(\Doctrine\ORM\QueryBuilder $qb, $filterMapping = NULL, $sortMapping = NULL)
60 {
61 $this->qb = $qb;
62 $this->filterMapping = $filterMapping;
63 $this->sortMapping = $sortMapping;
64
65 if (!$this->sortMapping && $this->filterMapping) {
66 $this->sortMapping = $this->filterMapping;
67 }
68 }
69
70 71 72 73
74 public function setUseOutputWalkers($useOutputWalkers)
75 {
76 $this->useOutputWalkers = $useOutputWalkers;
77 return $this;
78 }
79
80 81 82 83
84 public function setFetchJoinCollection($fetchJoinCollection)
85 {
86 $this->fetchJoinCollection = $fetchJoinCollection;
87 return $this;
88 }
89
90 91 92
93 public function getQuery()
94 {
95 return $this->qb->getQuery();
96 }
97
98 99 100
101 public function getQb()
102 {
103 return $this->qb;
104 }
105
106 107 108
109 public function getFilterMapping()
110 {
111 return $this->filterMapping;
112 }
113
114 115 116
117 public function getSortMapping()
118 {
119 return $this->sortMapping;
120 }
121
122 123 124 125
126 protected function makeWhere(Condition $condition, \Doctrine\ORM\QueryBuilder $qb = NULL)
127 {
128 $qb = $qb === NULL
129 ? $this->qb
130 : $qb;
131
132 if ($condition->callback) {
133 return callback($condition->callback)->invokeArgs(array($condition->value, $qb));
134 }
135
136 $columns = $condition->column;
137 foreach ($columns as $key => $column) {
138 if (!Condition::isOperator($column)) {
139 $columns[$key] = (isset($this->filterMapping[$column])
140 ? $this->filterMapping[$column]
141 : (Strings::contains($column, ".") ? $column : $this->qb->getRootAlias() . '.' . $column));
142 }
143 }
144
145 $condition->setColumn($columns);
146 list($where) = $condition->__toArray(NULL, NULL, FALSE);
147
148 $rand = $this->getRand();
149 $where = preg_replace_callback('/\?/', function() use ($rand) {
150 static $i = -1;
151 $i++;
152 return ":$rand{$i}";
153 }, $where);
154
155 $qb->andWhere($where);
156
157 foreach ($condition->getValueForColumn() as $i => $val) {
158 $qb->setParameter("$rand{$i}", $val);
159 }
160 }
161
162 163 164
165 protected function getRand()
166 {
167 do {
168 $rand = \Nette\Utils\Strings::random(4, 'a-z');
169 } while (isset($this->rand[$rand]));
170
171 $this->rand[$rand] = $rand;
172 return $rand;
173 }
174
175
176
177 178 179
180 public function getCount()
181 {
182 $paginator = new Paginator($this->getQuery(), $this->fetchJoinCollection);
183 $paginator->setUseOutputWalkers($this->useOutputWalkers);
184
185 return $paginator->count();
186 }
187
188 189 190 191 192 193
194 public function getData()
195 {
196
197 $usePaginator = $this->qb->getMaxResults() !== NULL || $this->qb->getFirstResult() !== NULL;
198 $data = array();
199
200 if ($usePaginator) {
201 $paginator = new Paginator($this->getQuery());
202
203
204 foreach ($paginator as $result) {
205
206 $data[] = is_array($result)
207 ? $result[0]
208 : $result;
209 }
210 } else {
211
212 foreach ($this->qb->getQuery()->getResult() as $result) {
213
214 $data[] = is_array($result)
215 ? $result[0]
216 : $result;
217 }
218 }
219
220 return $data;
221 }
222
223 224 225 226
227 public function filter(array $conditions)
228 {
229 foreach ($conditions as $condition) {
230 $this->makeWhere($condition);
231 }
232 }
233
234 235 236 237 238
239 public function limit($offset, $limit)
240 {
241 $this->qb->setFirstResult($offset)
242 ->setMaxResults($limit);
243 }
244
245 246 247 248
249 public function sort(array $sorting)
250 {
251 foreach ($sorting as $key => $value) {
252 $column = isset($this->sortMapping[$key])
253 ? $this->sortMapping[$key]
254 : $this->qb->getRootAlias() . '.' . $key;
255
256 $this->qb->addOrderBy($column, $value);
257 }
258 }
259
260 261 262 263 264 265 266
267 public function suggest($column, array $conditions, $limit)
268 {
269 $qb = clone $this->qb;
270 $qb->setMaxResults($limit);
271
272 if (is_string($column)) {
273 $mapping = isset($this->filterMapping[$column])
274 ? $this->filterMapping[$column]
275 : $qb->getRootAlias() . '.' . $column;
276
277 $qb->select($mapping)->distinct();
278 }
279
280 foreach ($conditions as $condition) {
281 $this->makeWhere($condition, $qb);
282 }
283
284 $items = array();
285 $data = $qb->getQuery()->getScalarResult();
286 foreach ($data as $row) {
287 if (is_string($column)) {
288 $value = (string) current($row);
289 } elseif (is_callable($column)) {
290 $value = (string) $column($row);
291 } else {
292 $type = gettype($column);
293 throw new \InvalidArgumentException("Column of suggestion must be string or callback, $type given.");
294 }
295
296 $items[$value] = \Nette\Templating\Helpers::escapeHtml($value);
297 }
298
299 return array_values($items);
300 }
301 }
302