1 <?php
2
3 4 5 6 7 8 9 10
11
12 namespace Icybee\ManageBlock;
13
14 use ICanBoogie\ActiveRecord\Query;
15
16 use Brickrouge\DropdownMenu;
17 use Brickrouge\Element;
18
19 20 21 22 23 24 25 26 27
28 class Column extends \ICanBoogie\Object
29 {
30 const ORDER_ASC = 1;
31 const ORDER_DESC = -1;
32
33 public $id;
34
35 public $title;
36 public $class;
37 public $filters;
38 public $reset;
39 public $orderable = false;
40 public $order;
41 public $default_order = self::ORDER_ASC;
42 public $discreet = true;
43
44 protected = 'Icybee\ManageBlock\HeaderRenderer';
45 protected $cell_renderer = 'Icybee\ManageBlock\CellRenderer';
46
47 public $manager;
48
49 public function __construct(\Icybee\ManageBlock $manager, $id, array $options=array())
50 {
51
52
53 if (method_exists($this, 'update_filters'))
54 {
55 throw new \Exception("The <q>update_filters()</q> method is deprecated, please use the <q>alter_filters()</q> method.");
56 }
57
58 if (method_exists($this, 'alter_query'))
59 {
60 throw new \Exception("The <q>alter_query()</q> method is deprecated, please use the <q>alter_query_with_filter()</q> method.");
61 }
62
63
64
65 $this->manager = $manager;
66 $this->id = $id;
67
68 $this->modify_options($options + $this->resolve_default_values());
69 }
70
71
72 protected function set_filtering()
73 {
74 throw new \InvalidArgumentException("The <q>filtering</q> property is deprecated. Use <q>is_filtering</q> or <q>filter_value</q>");
75 }
76
77 protected function set_label($value)
78 {
79 trigger_error("The <q>label</q> property is deprecated, use <q>title</q> instead.");
80
81 $this->title = $value;
82 }
83
84 protected function get_label()
85 {
86 trigger_error("The <q>label</q> property is deprecated, use <q>title</q> instead.");
87
88 return $this->title;
89 }
90
91 92 93 94 95
96 protected function get_is_filtering()
97 {
98 return $this->manager->is_filtering($this->id);
99 }
100
101 102 103 104 105
106 protected function get_filter_value()
107 {
108 return $this->is_filtering ? $this->manager->options->filters[$this->id] : null;
109 }
110
111 112 113 114 115 116 117 118 119
120 public function t($native, array $args=array(), array $options=array())
121 {
122 return $this->manager->t($native, $args, $options);
123 }
124
125 126 127 128 129
130 protected function resolve_default_values()
131 {
132 $id = $this->id;
133 $fields = $this->manager->model->extended_schema['fields'];
134 $field = isset($fields[$id]) ? $fields[$id] : null;
135
136 $orderable = true;
137 $default_order = 1;
138 $discreet = false;
139
140 if ($field)
141 {
142 if (($field['type'] == 'integer' && (!empty($field['primary']) || !empty($field['indexed']))) || $field['type'] == 'boolean')
143 {
144 $orderable = false;
145
146 if (!empty($field['indexed']))
147 {
148 $discreet = true;
149 }
150 }
151
152 if (in_array($field['type'], array('date', 'datetime', 'timestamp')))
153 {
154 $default_order = -1;
155 }
156 }
157 else
158 {
159 $orderable = false;
160 }
161
162 return array
163 (
164 'title' => $id,
165 'reset' => "?$id=",
166 'orderable' => $orderable,
167 'default_order' => $default_order
168 );
169 }
170
171 172 173 174 175 176 177
178 public function modify_options(array $options)
179 {
180 foreach ($options as $option => $value)
181 {
182 switch ($option)
183 {
184 case 'label':
185 case 'title':
186 case 'class':
187 case 'filters':
188 case 'reset':
189 case 'orderable':
190 case 'order':
191 case 'default_order':
192 case 'discreet':
193 case 'filtering':
194 case 'header_renderer':
195 case 'cell_renderer':
196 $this->$option = $value;
197 break;
198
199 case 'hook':
200
201 break;
202 }
203 }
204
205 return $this;
206 }
207
208 209 210 211 212 213 214 215 216 217 218
219 public function alter_filters(array $filters, array $modifiers)
220 {
221 return $filters;
222 }
223
224 225 226 227 228 229 230 231 232 233 234
235 public function alter_query_with_filter(Query $query, $filter_value)
236 {
237 if ($filter_value)
238 {
239 $query->and(array($this->id => $filter_value));
240 }
241
242 return $query;
243 }
244
245 246 247 248 249 250 251 252 253 254 255 256
257 public function alter_query_with_order(Query $query, $order_direction)
258 {
259 return $query->order("`$this->id` " . ($order_direction < 0 ? 'desc' : 'asc'));
260 }
261
262 263 264 265 266 267 268 269 270 271
272 public function alter_records(array $records)
273 {
274 return $records;
275 }
276
277 278 279 280 281
282 protected function get_options()
283 {
284 if (empty($this->filters['options']))
285 {
286 return;
287 }
288
289 $options = array();
290
291 foreach ($this->filters['options'] as $qs => $label)
292 {
293 if ($qs[0] == '=')
294 {
295 $qs = $this->id . $qs;
296 }
297
298 $options['?' . $qs] = $this->manager->t($label);
299 }
300
301 return $options;
302 }
303
304 305 306
307 public function render_options()
308 {
309 $options = $this->get_options();
310
311 if (!$options)
312 {
313 return;
314 }
315
316 if ($this->is_filtering)
317 {
318 $options = array_merge
319 (
320 array
321 (
322 $this->reset => $this->t('Display all'),
323 false
324 ),
325
326 $options
327 );
328 }
329
330 $menu = new DropdownMenu
331 (
332 array
333 (
334 DropdownMenu::OPTIONS => $options,
335
336 'value' => $this->filter_value
337 )
338 );
339
340 return <<<EOT
341 <div class="dropdown navbar"><a href="#" data-toggle="dropdown"><i class="icon-cog"></i></a>$menu</div>
342 EOT;
343 }
344
345 346 347 348 349
350 public function ()
351 {
352 $renderer = $this->header_renderer;
353
354 if (!($renderer instanceof HeaderRenderer))
355 {
356 $this->header_renderer = $renderer = new $renderer($this);
357 }
358
359 return $renderer();
360 }
361
362 363 364 365 366 367 368
369 public function render_cell($record)
370 {
371 $renderer = $this->cell_renderer;
372
373 if (!($renderer instanceof CellRenderer))
374 {
375 $this->cell_renderer = $renderer = new $renderer($this);
376 }
377
378 return $renderer($record, $this->id);
379 }
380
381 382 383 384 385 386 387
388 public function add_assets(\Brickrouge\Document $document)
389 {
390
391 }
392 }
393
394 395 396
397 class
398 {
399 protected $column;
400
401 public function __construct(Column $column)
402 {
403 $this->column = $column;
404 }
405
406 public function __invoke()
407 {
408 $column = $this->column;
409 $module = $this->column->manager->module;
410 $id = $column->id;
411 $title = $column->title;
412 $t = $this->column->manager->t;
413
414 if ($title)
415 {
416 $title = $t($id, array(), array('scope' => 'column', 'default' => $title));
417 }
418
419 if ($column->is_filtering)
420 {
421 $a_title = $t('View all');
422 $title = $title ?: ' ';
423
424 return <<<EOT
425 <a href="{$column->reset}" title="{$a_title}"><span class="title">{$title}</span></a>
426 EOT;
427 }
428
429 if ($title && $column->orderable)
430 {
431 $order = $column->order;
432 $order_reverse = ($order === null) ? $column->default_order : -$order;
433
434 return new Element
435 (
436 'a', array
437 (
438 Element::INNER_HTML => '<span class="title">' . $title . '</span>',
439
440 'title' => $t('Sort by: :identifier', array(':identifier' => $title)),
441 'href' => "?order=$id:" . ($order_reverse < 0 ? 'desc' : 'asc'),
442 'class' => $order ? ($order < 0 ? 'desc' : 'asc') : null
443 )
444 );
445 }
446
447 return $title;
448 }
449 }
450
451 452 453
454 class CellRenderer
455 {
456 protected $column;
457
458 public function __construct(Column $column)
459 {
460 $this->column = $column;
461 }
462
463 public function __invoke($record, $property)
464 {
465 return \Brickrouge\escape($record->$property);
466 }
467
468 public function t($str, array $args=array(), array $options=array())
469 {
470 return $this->column->t($str, $args, $options);
471 }
472 }