Overview

Packages

  • Onion::Controllers
  • Onion::Core
  • Onion::UI
  • Onion::Utils

Classes

  • Form
  • Grid
  • Html
  • IconsGrid
  • Paginator
  • Template
  • Widget
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: 
  3: /**
  4:  * Onion Framework - Zobrazenie dát pomocou ikon v tabuľľke s možnosťou radenia a filtrovania
  5:  *
  6:  * Copyright (c) 2011 Jano Gašpar (http://webstranky.net)
  7:  *
  8:  * @author    Jano Gašpar
  9:  * @copyright Copyright (c) 2011 Jano Gašpar
 10:  * @package   Onion::UI
 11:  **/
 12: class IconsGrid
 13: {
 14:     private $auth;
 15: 
 16: 
 17:     /**
 18:      * @var string id na identifikáciu gridu
 19:      */
 20:     private $id;
 21: 
 22: 
 23:     /**
 24:      * @var string token na identifikáciu gridu
 25:      */
 26:     private $token;
 27: 
 28: 
 29:     /**
 30:      * @var string metóda na získavanie
 31:      */
 32:     private $model;
 33: 
 34: 
 35:     /**
 36:      * @var array stĺpce
 37:      */
 38:     private $fields = array();
 39: 
 40: 
 41:     /**
 42:      * @var array aktuálny sĺpec
 43:      */
 44:     private $current_field = array();
 45: 
 46: 
 47:     /**
 48:      * @var array akcie
 49:      */
 50:     private $actions = array();
 51: 
 52: 
 53:     /**
 54:      * @var array akcie na hromadné spracovanie dát
 55:      */
 56:     private $multi_actions = array();
 57: 
 58: 
 59:     /**
 60:      * @var int počet riadkov v gride, NULL zakáže stránkovanie
 61:      */
 62:     public $rows = 5;
 63: 
 64: 
 65:     /**
 66:      * @var int počet stĺpcov v gride, NULL zakáže stránkovanie
 67:      */
 68:     public $columns = 5;
 69: 
 70: 
 71:     /**
 72:      * @var int meno routy podľa ktorej sa generujú odkazy
 73:      */
 74:     public $route_name = NULL;
 75: 
 76: 
 77:     /**
 78:      * @var array stĺpec a smer radenia
 79:      */
 80:     public $default_order = array('id', 'ASC');
 81: 
 82: 
 83:     /**
 84:      * @var array texty
 85:      */
 86:     public $strings = array(
 87:         'page' => 'Page: ',
 88:         'selected items' => 'Selected items: ',
 89:         'search' => 'Search',
 90:         'show all' => 'Show all'
 91:         );
 92: 
 93: 
 94:     /**
 95:      * @var string CSS ID
 96:      */
 97:     public $css_id;
 98: 
 99: 
100: 
101:     public $cell_render_func;
102: 
103: 
104: 
105:     /**
106:      * Konštruktor
107:      *
108:      * @param  string $form_id identifikátor gridu
109:      * @param  object $model   inštancia modelu na manipuláciu s dátami
110:      * @return object grid instance
111:      */
112:     public function __construct($app, $grid_id, $model)
113:     {
114:         $this->app = $app;
115: 
116:         $this->id = $grid_id;
117: 
118:         //token sa generuje nanovo pre každú reláciu (session)
119:         $token = md5(uniqid('', TRUE));
120:         if (isset($_SESSION['grid'][$grid_id]['token']) === TRUE) {
121:             $token = $_SESSION['grid'][$grid_id]['token'];
122:         }
123:         $this->token = $_SESSION['grid'][$grid_id]['token'] = $token;
124: 
125:         $this->model = $model;
126: 
127:         return $this;
128:     }
129: 
130: 
131:     /**
132:      * Nastavovanie atribútov stĺpcov gridu pomocuu preťažovania
133:      *
134:      * @param string            $atribute meno atribútu
135:      * @param string|array|bool $value    hodnota atribútu
136:      */
137:     final public function __call($attribute, $value)
138:     {
139:         if (isset($value[0]) === FALSE) {
140:             $value = '';
141: 
142:         } else {
143:             $value = $value[0];
144:         }
145: 
146:         $this->current_field[$attribute] = $value;
147: 
148:         return $this;
149:     }
150: 
151: 
152:     /**
153:      * Metóda volaná pri prístupe k objektu ako k reťazcu
154:      */
155:     final public function __tostring()
156:     {
157:         return $this->render();
158:     }
159: 
160: 
161:     /**
162:      * Metóda na pridanie stĺpca
163:      *
164:      * @param  string meno stĺpca v databáze
165:      * @param  string meno stĺpca zobrazené v gride
166:      * @param  int    orezať na počet znakov
167:      * @return object grid instance
168:      */
169:     public function add_field($field, $title, $only_db = FALSE)
170:     {
171:         $this->save_prev_field();
172: 
173:         $this->current_field = array(
174:             'field' => $field,
175:             'title' => $title,
176:             'filter' => NULL,
177:             'only_db' => $only_db,
178:             );
179: 
180:         return $this;
181:     }
182: 
183: 
184:     /**
185:      * Metóda na uloženie stĺpca a vytvorenie nového
186:      *
187:      * @param  string identifikátor gridu
188:      * @return object grid instance
189:      */
190:     private function save_prev_field()
191:     {
192:         if (empty($this->current_field) === TRUE) {
193:             return;
194:         }
195: 
196:         if (isset($this->current_field['field']) === FALSE) {
197:             ob_clean(); var_dump($this->current_field); exit;
198:         }
199: 
200:         $alias = $this->current_field['field'];
201: 
202:         list($alias) = preg_split('/( as )/i', $alias);
203:         $alias = str_replace('.', '_', $alias);
204:         $this->current_field['alias'] = $alias;
205: 
206:         $this->fields[$alias] = $this->current_field;
207:         $this->current_field = array();
208:     }
209: 
210: 
211:     /**
212:      * Metóda na pridanie akcie
213:      *
214:      * @param  string meno akcie
215:      * @param  string meno routy ktorá sa použije na vygenerovanie uri
216:      * @param  string cesta k ikone, ak je NULL použije sa iba text
217:      * @return object grid instance
218:      */
219:     public function add_action($title, $route_name, $class = NULL)
220:     {
221:         $this->actions[] = array(
222:             'title' => $title,
223:             'route_name' => $route_name,
224:             'class' => $class
225:             );
226: 
227:         return $this;
228:     }
229: 
230: 
231:     /**
232:      * Metóda na pridanie akcie na hromadné spracovanie
233:      *
234:      * @param  string meno akcie
235:      * @param  string meno funkcie ktorá má vykonať hromadnú akciu
236:      * @return object grid instance
237:      */
238:     public function add_multi_action($title, $callback, $class = NULL)
239:     {
240:         $this->multi_actions[] = array(
241:             'title' => $title,
242:             'callback' => $callback,
243:             'class' => $class
244:             );
245: 
246:         return $this;
247:     }
248: 
249: 
250:     /**
251:      * Metóda na priradenie filtra k stĺpcu
252:      *
253:      * @param  string       typ filtra
254:      * @param  string|array parametre filtra
255:      * @return object grid instance
256:      */
257:     public function add_filter($type = 'text', $parameters = NULL)
258:     {
259:         $this->current_field['filter'] = array(
260:             'type' => $type,
261:             'parameters' => $parameters
262:             );
263: 
264:         return $this;
265:     }
266: 
267: 
268:     /**
269:      * Metóda na priradenie formátovania k stĺpcu
270:      *
271:      * @param  string|array metóda, pole = externá metóda, reťazec = interná metóda
272:      * @param  string|array parametre formátovania
273:      * @return object grid instance
274:      */
275:     public function format()
276:     {
277:         $arguments = func_get_args();
278: 
279:         $this->current_field['format']['callback'] = array_shift($arguments);
280:         $this->current_field['format']['arguments'] = $arguments;
281: 
282:         return $this;
283:     }
284: 
285: 
286:     /**
287:      * Metóda na vykreslenie gridu
288:      */
289:     public function render()
290:     {
291:         $this->save_prev_field();
292: 
293:         $uri_data = $this->app->request->get;
294:         $uri = $this->app->create_uri($this->route_name, array(), $uri_data);
295: 
296:         $grid = Html::element('form')
297:             ->method('get')
298:             ->action($uri)
299:             ->id($this->css_id)
300:             ->class('icon-grid');
301: 
302:         $hiddens = $grid->create('p')
303:             ->class('hiddens');
304: 
305:         $hiddens->create('input')
306:             ->type('hidden')
307:             ->name('token')
308:             ->value($this->token);
309: 
310:         $table  = $grid->create('table');
311:         $header = $table->create('thead');
312:         $body   = $table->create('tbody');
313: 
314:         $tr_titles  = $header->create('tr')
315:             ->class('headers');
316:         $tr_filters = Html::element('tr')
317:             ->class('filters');
318: 
319:         $uri_data = array();
320:         $uri_data['filters'] = array();
321:         $uri_data['order'] = array($this->default_order[0] => $this->default_order[1]);
322:         $uri_data['page'] = 1;
323:         $uri_data['token'] = $this->token;
324: 
325:         if ($this->is_submitted() === TRUE) {
326:             if (isset($this->app->request->get['filters_reset']) === FALSE) {
327:                 if (isset($this->app->request->get['filters']) === TRUE) {
328:                     $uri_data['filters'] = $this->app->request->get['filters'];
329:                 }
330: 
331:                 if (isset($this->app->request->get['order']) === TRUE) {
332:                     $uri_data['order'] = $this->app->request->get['order'];
333:                 }
334: 
335:                 $uri_data['page'] = max(Arrays::get_value($this->app->request->get, 'page'), 1);
336: 
337:             } else {
338:                 $uri = $this->app->create_uri($this->route_name, array(), $uri_data);
339:                 $this->app->response->redirect($uri, 303);
340:             }
341: 
342:         } elseif (isset($_SESSION['grid'][$this->id]['uri_data']) === TRUE) {
343:             $this->app->keep_flash();
344: 
345:             $uri_data = $_SESSION['grid'][$this->id]['uri_data'];
346:             $uri = $this->app->create_uri($this->route_name, array(), $uri_data);
347:             $this->app->response->redirect($uri, 303);
348:         }
349: 
350:         $_SESSION['grid'][$this->id]['uri_data'] = $uri_data;
351: 
352:         if (empty($uri_data['filters']) === FALSE) {
353:             foreach ($uri_data['filters'] as $field_name => $value) {
354:                 if (Validate::is_empty($value) === TRUE) {
355:                     continue;
356:                 }
357: 
358:                 if ($value == -1) {
359:                     continue;
360:                 }
361: 
362:                 $db_field = $this->fields[$field_name]['field'];
363: 
364:                 if ($this->fields[$field_name]['filter']['type'] === 'text') {
365:                     $this->model->where($db_field, '%' . $value . '%', 'LIKE');
366: 
367:                 } else {
368:                     $this->model->where($db_field, $value);
369:                 }
370:             }
371:         }
372: 
373:         if (empty($uri_data['order']) === FALSE) {
374:             foreach ($uri_data['order'] as $col => $dir) {
375:                 $this->model->order($col, $dir);
376:             }
377:         }
378: 
379:         $fields = array();
380: 
381:         // Príznak na vloženie filtrov
382:         // zabezpečuje vykreslenie filtrov iba v prípade že sú definované
383:         $add_filters = FALSE;
384: 
385:         // Vykreslenie hlavičiek
386:         foreach ($this->fields as $alias => $field) {
387:             $fields[] = $field['field'];
388: 
389:             if ($field['only_db'] === TRUE) {
390:                 continue;
391:             }
392: 
393:             $uri_data_tmp = $uri_data;
394:             $uri_data_tmp['order'] = array($alias => 'ASC');
395:             $uri_data_tmp['page'] = 1;
396: 
397:             // Vytvorenie adresy na nastavenie radenia
398:             // Ak sa triedi podľa tohoto stĺpca, je treba v adrese prehodiť smer radenia
399:             if (isset($uri_data['order'][$alias]) === TRUE
400:                 AND $uri_data['order'][$alias] === 'ASC') {
401: 
402:                 $uri_data_tmp['order'] = array($alias => 'DESC');
403:             }
404: 
405:             $uri = $this->app->create_uri($this->route_name, array(), $uri_data_tmp);
406: 
407:             // Názov
408:             $title = $tr_titles->create('th');
409:             $title->class[] = $field['field'];
410:             $title->create('a')
411:                     ->href($uri)
412:                     ->set_text($field['title']);
413: 
414:             if (isset($order[$alias]) === TRUE) {
415:                 $title->class[] = 'order-field';
416: 
417:                 if ($order[$alias] === 'ASC') {
418:                     $title->class[] = 'order-asc';
419: 
420:                 } else {
421:                     $title->class[] = 'order-desc';
422:                 }
423:             }
424: 
425:             // Ak stĺpec nemá filter vloží sa iba &nbsp;
426:             if ($field['filter'] === NULL) {
427:                 $tr_filters->create('th')
428:                     ->class($field['field'])
429:                     ->set_text('&nbsp;', TRUE);
430: 
431:             } else {
432:             // v opačnom prípade sa vykreslí pole filtra
433:                 $value = NULL;
434: 
435:                 if (isset($uri_data['filters'][$field['alias']]) === TRUE) {
436:                     $value = $uri_data['filters'][$field['alias']];
437:                 }
438: 
439:                 $add_filters = TRUE;
440:                 $tr_filters->create('th')
441:                     ->class($field['alias'])
442:                     ->add($this->filter_item($field, $value));
443:             }
444:         }
445: 
446:         // Ak sú nadefinované akcie pre jednotlivé položky
447:         // je treba vložiť stĺpce aby sedeli počty stĺpcov
448:         if (empty($this->actions) === FALSE) {
449:             // do hlavičiek
450:             $tr_titles->create('th')
451:                 ->set_text('&nbsp;', TRUE);
452: 
453:             if ($add_filters === TRUE) {
454:                 $buttons = $tr_filters->create('th')
455:                     ->class('grid_actions');
456:             }
457:         }
458: 
459:         // Filtre sú definované, je treba ich vykresliť
460:         if ($add_filters === TRUE) {
461:             $header->add($tr_filters);
462: 
463:             if (isset($buttons) === FALSE) {
464:                 $colspan = $tr_filters->count();
465:                 $buttons = $header->create('tr')
466:                     ->create('td')
467:                         ->colspan($colspan);
468:             }
469: 
470:             // a pridať tlačidlá na odoslanie filtra
471:             $buttons->create('input')
472:                 ->type('submit')
473:                 ->name('filters_submit')
474:                 ->value($this->strings['search']);
475: 
476:             // a reset filtra
477:             $buttons->create('input')
478:                 ->type('submit')
479:                 ->name('filters_reset')
480:                 ->value($this->strings['show all']);
481:         }
482: 
483:         // Na vykreslenie je nutné vedieť aj ID položiek, preto sa pole ID pridá
484:         // do zoznamu polí ktoré sa berú z databázy
485:         $db_fields = array_merge(array($this->model->table . '.id as id'), $fields);
486:         $db_fields = array_unique($db_fields);
487: 
488:         // Vytvorenie stránkovača
489:         $paginator = new Paginator($this->app, $uri_data['page'], $this->model->count(), ($this->rows * $this->columns));
490:         $paginator->route_name = $this->app->route['name'];
491:         $paginator->uri_parameter_name = 'page';
492: 
493:         $hiddens->create('input')
494:             ->type('hidden')
495:             ->name('page')
496:             ->value($uri_data['page']);
497: 
498:         if ($this->rows !== NULL) {
499:             // Limit pre model sa berie zo stránkovača, kde sa vypočítajú správne čísla
500:             $this->model->limit($paginator->limit);
501:         }
502: 
503:         $table  = $grid->create('table')
504:             ->class('cells');
505:         $body   = $table->create('tbody');
506: 
507:         // Samotné vykreslenie riadkov
508:         foreach ($this->model->get_rows($db_fields) as $index => $cell_data) {
509:             if (($index % $this->columns) === 0) {
510:                 $tr = $body->create('tr');
511:             }
512: 
513:             $cell = $tr->create('td');
514: 
515:             $cell->add(call_user_func($this->cell_render_func, $cell_data));
516: 
517:             $cell_footer = $cell->create('div')
518:                 ->class('cell_footer');
519: 
520:             // Ak sú definované hromadné akcie je treba pridať checkboxy
521:             if (empty($this->multi_actions) === FALSE) {
522:                 $cell_footer->create('input')
523:                     ->type('checkbox')
524:                     ->name('items[' . $cell_data['id'] . ']');
525:             }
526: 
527:             // Vykreslenie akcií na jednotlivých položkách ak sú definované
528:             if (empty($this->actions) === FALSE) {
529:                 $uri_data = $this->app->request->get;
530: 
531:                 foreach ($this->actions as $action) {
532:                     $uri = $this->app->create_uri($action['route_name'], array('id' => $cell_data['id']), $uri_data);
533: 
534:                     $cell_footer->create('a')
535:                         ->href($uri)
536:                         ->set_text($action['title'])
537:                         ->title($action['title'])
538:                         ->class($action['class']);
539: 
540:                     $cell_footer->add('&nbsp;', TRUE);
541:                 }
542:             }
543:         }
544: 
545:         // Vykreslenie tlačidiel hromadných akcií
546:         $footer = $grid->create('div')
547:             ->class('footer');
548: 
549:         if (empty($this->multi_actions) === FALSE) {
550:             $buttons = $footer->create('div');
551:             $buttons->add($this->strings['selected items']);
552: 
553:             foreach($this->multi_actions as $key => $multi_action) {
554:                 if ($this->is_submitted() === TRUE
555:                     AND isset($this->app->request->get['multi_action'][$key]) === TRUE
556:                     AND isset($this->app->request->get['items']) === TRUE) {
557: 
558:                     call_user_func($multi_action['callback'], array_keys($this->app->request->get['items']));
559:                 }
560: 
561:                 $buttons->create('input')
562:                     ->type('submit')
563:                     ->value($multi_action['title'])
564:                     ->class($multi_action['class'])
565:                     ->name('multi_action[' . $key . ']');
566:             }
567:         }
568: 
569:         // Vykreslenie stránkovačov
570:         $p = $footer->create('div')
571:             ->class('paginator')
572:             ->set_text($this->strings['page'])
573:             ->add($paginator);
574: 
575:         $grid->insert(0, $p);
576: 
577:         return $grid->render();
578:     }
579: 
580: 
581:     /**
582:      * Rozhodovacia metóda na rozhodnutie aké filtrovacie pole sa vykreslí
583:      *
584:      * @param array  stĺpec ktorému je treba vykresliť filtrovacie pole
585:      * @param string aktuálna hodnota vyhľadávacieho poľa
586:      */
587:     private function filter_item($field, $value)
588:     {
589:         if (is_string($field['filter']['type']) === TRUE) {
590:             if ($field['filter']['type'] === 'select') {
591:                 return $this->filter_item_select($field, $value);
592: 
593:             } elseif ($field['filter']['type'] === 'text') {
594:                 return $this->filter_item_text($field, $value);
595:             }
596:         }
597: 
598:         return call_user_func($field['filter']['type'], $field, $value);
599:     }
600: 
601: 
602:     /**
603:      * Metóda na vykreslenie textového filtra
604:      *
605:      * @param array  stĺpec ktorému je treba vykresliť filtrovacie pole
606:      * @param string aktuálna hodnota vyhľadávacieho poľa
607:      */
608:     private function filter_item_text($field, $value)
609:     {
610:         $filter = Html::element('input')
611:             ->name('filters[' . $field['field'] . ']')
612:             ->type('text')
613:             ->value($value);
614: 
615:         return $filter;
616:     }
617: 
618: 
619:     /**
620:      * Metóda na vykreslenie výberového filtra
621:      *
622:      * @param array  stĺpec ktorému je treba vykresliť filtrovacie pole
623:      * @param string aktuálna hodnota vyhľadávacieho poľa
624:      */
625:     private function filter_item_select($field, $value)
626:     {
627:         if ($value === NULL) {
628:             $value = -1;
629:         }
630: 
631:         $options = $field['filter']['parameters'];
632: 
633:         if ($options === NULL) {
634:             preg_match('/(.*)\.([^\ ]*)/i', $field['field'], $matches);
635:             if (empty($matches) === FALSE) {
636:                 $table = $matches[1];
637:                 $field_name = $matches[2];
638: 
639:             } else {
640:                 $table = $this->model->table;
641:                 $field_name = $field['field'];
642:             }
643: 
644:             $relations = $this->model->current_table_relations;
645:             if (isset($relations[$table]) === TRUE) {
646:                 $table = $relations[$table];
647:             }
648: 
649:             $table = $this->model->prefix . $table;
650: 
651:             $result = Database::query('SELECT `' . $field_name . '`, `' . $field_name . '` as `value` FROM `' . $table . '` ORDER BY `' . $field_name . '`');
652:             $options = $result->fetch_pairs('value', $field_name);
653:             $options = array('-1' => $this->strings['show all']) + $options;
654:         }
655: 
656:         $name = 'filters[' . $field['alias'] . ']';
657:         $filter = Html::element('select')
658:             ->name($name);
659: 
660:         foreach ($options as $option_value => $text) {
661:             $option = $filter->create('option')
662:                 ->value($option_value)
663:                 ->set_text($text);
664: 
665:                 if ($value == $option_value) {
666:                     $option->selected('selected');
667:                 }
668:         }
669: 
670:         return $filter;
671:     }
672: 
673: 
674:     /**
675:      * Metóda na zistenie či prijaté dáta patria aktuálnemu gridu
676:      */
677:     public function is_submitted()
678:     {
679:         return (Arrays::get_value($this->app->request->get, 'token') === $this->token);
680:     }
681: 
682: 
683:     /**
684:      * Metóda na formátovanie hodnoty ako adresy - web, alebo mail
685:      *
686:      * @param string $uri adresa
687:      */
688:     private function format_uri($uri)
689:     {
690:         $uri_html = Html::element('a')
691:             ->set_text($uri);
692: 
693:         if (strpos($uri, '@') == TRUE) {
694:             $uri_html->href('mailto: ' . $uri);
695: 
696:         } else {
697:             if (substr($uri, 0, 4) !== 'http') {
698:                 $uri = 'http://' . $uri;
699:             }
700: 
701:             $uri_html->href($uri);
702:         }
703: 
704:         return $uri_html;
705:     }
706: 
707: 
708:     /**
709:      * Metóda na formátovanie hodnoty funkciou date
710:      *
711:      * @param string dátum a čas
712:      * @param string formátovací reťazec pre funkciu date
713:      */
714:     private function format_datetime($datetime, $format = 'd. m. Y / H:i')
715:     {
716:         return date($format, strtotime($datetime));
717:     }
718: 
719: 
720:     /**
721:      * Metóda na prevod boolean hodnoty na reťazec
722:      *
723:      * @param bool   dátum a čas
724:      * @param string reťazec ktorý sa má vrátiť pri FALSE
725:      * @param string reťazec ktorý sa má vrátiť pri TRUE
726:      */
727:     private function format_bool($value, $no = 'No', $yes = 'Yes')
728:     {
729:         if ($value == TRUE) {
730:             return $yes;
731:         }
732: 
733:         return $no;
734:     }
735: }
Onion API documentation generated by ApiGen.
Generated using the TokenReflection library.