· 9 years ago · Apr 23, 2017, 12:48 AM
1<?php
2/**
3 * PHP grocery CRUD
4 *
5 * A Codeigniter library that creates a CRUD automatically with just few lines of code.
6 *
7 * Copyright (C) 2010 - 2014 John Skoumbourdis.
8 *
9 * LICENSE
10 *
11 * Grocery CRUD is released with dual licensing, using the GPL v3 (license-gpl3.txt) and the MIT license (license-mit.txt).
12 * You don't have to do anything special to choose one license or the other and you don't have to notify anyone which license you are using.
13 * Please see the corresponding license file for details of these licenses.
14 * You are free to use, modify and distribute this software, but all copyright information must remain.
15 *
16 * @package grocery CRUD
17 * @copyright Copyright (c) 2010 through 2014, John Skoumbourdis
18 * @license https://github.com/scoumbourdis/grocery-crud/blob/master/license-grocery-crud.txt
19 * @version 1.5.8
20 * @author John Skoumbourdis <scoumbourdisj@gmail.com>
21 */
22
23// ------------------------------------------------------------------------
24
25/**
26 * grocery Field Types
27 *
28 * The types of the fields and the default reactions
29 *
30 * @package grocery CRUD
31 * @author John Skoumbourdis <scoumbourdisj@gmail.com>
32 * @license https://github.com/scoumbourdis/grocery-crud/blob/master/license-grocery-crud.txt
33 * @link http://www.grocerycrud.com/documentation
34 */
35class grocery_CRUD_Field_Types
36{
37 /**
38 * Gets the field types of the main table.
39 * @return array
40 */
41 public function get_field_types()
42 {
43 if ($this->field_types !== null) {
44 return $this->field_types;
45 }
46
47 $types = array();
48 foreach($this->basic_model->get_field_types_basic_table() as $field_info)
49 {
50 $field_info->required = !empty($this->required_fields) && in_array($field_info->name,$this->required_fields) ? true : false;
51
52 $field_info->display_as =
53 isset($this->display_as[$field_info->name]) ?
54 $this->display_as[$field_info->name] :
55 ucfirst(str_replace("_"," ",$field_info->name));
56
57 if($this->change_field_type !== null && isset($this->change_field_type[$field_info->name]))
58 {
59 $field_type = $this->change_field_type[$field_info->name];
60
61 if (isset($this->relation[$field_info->name])) {
62 $field_info->crud_type = "relation_".$field_type->type;
63 }
64 elseif (isset($this->upload_fields[$field_info->name])) {
65 $field_info->crud_type = "upload_file_".$field_type->type;
66 } else {
67 $field_info->crud_type = $field_type->type;
68 $field_info->extras = $field_type->extras;
69 }
70
71 $real_type = $field_info->crud_type;
72 }
73 elseif(isset($this->relation[$field_info->name]))
74 {
75 $real_type = 'relation';
76 $field_info->crud_type = 'relation';
77 }
78 elseif(isset($this->upload_fields[$field_info->name]))
79 {
80 $real_type = 'upload_file';
81 $field_info->crud_type = 'upload_file';
82 }
83 else
84 {
85 $real_type = $this->get_type($field_info);
86 $field_info->crud_type = $real_type;
87 }
88
89 switch ($real_type) {
90 case 'text':
91 if(!empty($this->unset_texteditor) && in_array($field_info->name,$this->unset_texteditor))
92 $field_info->extras = false;
93 else
94 $field_info->extras = 'text_editor';
95 break;
96
97 case 'relation':
98 case 'relation_readonly':
99 $field_info->extras = $this->relation[$field_info->name];
100 break;
101
102 case 'upload_file':
103 case 'upload_file_readonly':
104 $field_info->extras = $this->upload_fields[$field_info->name];
105 break;
106
107 default:
108 if(empty($field_info->extras))
109 $field_info->extras = false;
110 break;
111 }
112
113 $types[$field_info->name] = $field_info;
114 }
115
116 if(!empty($this->relation_n_n))
117 {
118 foreach($this->relation_n_n as $field_name => $field_extras)
119 {
120 $is_read_only = $this->change_field_type !== null
121 && isset($this->change_field_type[$field_name])
122 && $this->change_field_type[$field_name]->type == 'readonly'
123 ? true : false;
124 $field_info = (object)array();
125 $field_info->name = $field_name;
126 $field_info->crud_type = $is_read_only ? 'readonly' : 'relation_n_n';
127 $field_info->extras = $field_extras;
128 $field_info->required = !empty($this->required_fields) && in_array($field_name,$this->required_fields) ? true : false;;
129 $field_info->display_as =
130 isset($this->display_as[$field_name]) ?
131 $this->display_as[$field_name] :
132 ucfirst(str_replace("_"," ",$field_name));
133
134 $types[$field_name] = $field_info;
135 }
136 }
137
138 if(!empty($this->add_fields))
139 foreach($this->add_fields as $field_object)
140 {
141 $field_name = isset($field_object->field_name) ? $field_object->field_name : $field_object;
142
143 if(!isset($types[$field_name]))//Doesn't exist in the database? Create it for the CRUD
144 {
145 $extras = false;
146 if($this->change_field_type !== null && isset($this->change_field_type[$field_name]))
147 {
148 $field_type = $this->change_field_type[$field_name];
149 $extras = $field_type->extras;
150 }
151
152 $field_info = (object)array(
153 'name' => $field_name,
154 'crud_type' => $this->change_field_type !== null && isset($this->change_field_type[$field_name]) ?
155 $this->change_field_type[$field_name]->type :
156 'string',
157 'display_as' => isset($this->display_as[$field_name]) ?
158 $this->display_as[$field_name] :
159 ucfirst(str_replace("_"," ",$field_name)),
160 'required' => !empty($this->required_fields) && in_array($field_name,$this->required_fields) ? true : false,
161 'extras' => $extras
162 );
163
164 $types[$field_name] = $field_info;
165 }
166 }
167
168 if(!empty($this->edit_fields))
169 foreach($this->edit_fields as $field_object)
170 {
171 $field_name = isset($field_object->field_name) ? $field_object->field_name : $field_object;
172
173 if(!isset($types[$field_name]))//Doesn't exist in the database? Create it for the CRUD
174 {
175 $extras = false;
176 if($this->change_field_type !== null && isset($this->change_field_type[$field_name]))
177 {
178 $field_type = $this->change_field_type[$field_name];
179 $extras = $field_type->extras;
180 }
181
182 $field_info = (object)array(
183 'name' => $field_name,
184 'crud_type' => $this->change_field_type !== null && isset($this->change_field_type[$field_name]) ?
185 $this->change_field_type[$field_name]->type :
186 'string',
187 'display_as' => isset($this->display_as[$field_name]) ?
188 $this->display_as[$field_name] :
189 ucfirst(str_replace("_"," ",$field_name)),
190 'required' => in_array($field_name,$this->required_fields) ? true : false,
191 'extras' => $extras
192 );
193
194 $types[$field_name] = $field_info;
195 }
196 }
197
198 $this->field_types = $types;
199
200 return $this->field_types;
201 }
202
203 public function get_primary_key()
204 {
205 return $this->basic_model->get_primary_key();
206 }
207
208 /**
209 * Get the html input for the specific field with the
210 * current value
211 *
212 * @param object $field_info
213 * @param string $value
214 * @return object
215 */
216 protected function get_field_input($field_info, $value = null)
217 {
218 $real_type = $field_info->crud_type;
219
220 $types_array = array(
221 'integer',
222 'text',
223 'true_false',
224 'string',
225 'date',
226 'datetime',
227 'enum',
228 'set',
229 'relation',
230 'relation_readonly',
231 'relation_n_n',
232 'upload_file',
233 'upload_file_readonly',
234 'hidden',
235 'password',
236 'readonly',
237 'dropdown',
238 'multiselect'
239 );
240
241 if (in_array($real_type,$types_array)) {
242 /* A quick way to go to an internal method of type $this->get_{type}_input .
243 * For example if the real type is integer then we will use the method
244 * $this->get_integer_input
245 * */
246 $field_info->input = $this->{"get_".$real_type."_input"}($field_info,$value);
247 }
248 else
249 {
250 $field_info->input = $this->get_string_input($field_info,$value);
251 }
252
253 return $field_info;
254 }
255
256 protected function change_list_value($field_info, $value = null)
257 {
258 $real_type = $field_info->crud_type;
259
260 switch ($real_type) {
261 case 'hidden':
262 case 'invisible':
263 case 'integer':
264
265 break;
266 case 'true_false':
267 if(is_array($field_info->extras) && array_key_exists($value,$field_info->extras)) {
268 $value = $field_info->extras[$value];
269 } else if(isset($this->default_true_false_text[$value])) {
270 $value = $this->default_true_false_text[$value];
271 }
272 break;
273 case 'string':
274 $value = $this->character_limiter($value,$this->character_limiter,"...");
275 break;
276 case 'text':
277 $value = $this->character_limiter(strip_tags($value),$this->character_limiter,"...");
278 break;
279 case 'date':
280 if(!empty($value) && $value != '0000-00-00' && $value != '1970-01-01')
281 {
282 list($year,$month,$day) = explode("-",$value);
283
284 $value = date($this->php_date_format, mktime (0, 0, 0, (int)$month , (int)$day , (int)$year));
285 }
286 else
287 {
288 $value = '';
289 }
290 break;
291 case 'datetime':
292 if(!empty($value) && $value != '0000-00-00 00:00:00' && $value != '1970-01-01 00:00:00')
293 {
294 list($year,$month,$day) = explode("-",$value);
295 list($hours,$minutes) = explode(":",substr($value,11));
296
297 $value = date($this->php_date_format." - H:i", mktime ((int)$hours , (int)$minutes , 0, (int)$month , (int)$day ,(int)$year));
298 }
299 else
300 {
301 $value = '';
302 }
303 break;
304 case 'enum':
305 $value = $this->character_limiter($value,$this->character_limiter,"...");
306 break;
307
308 case 'multiselect':
309 $value_as_array = array();
310 foreach(explode(",",$value) as $row_value)
311 {
312 $value_as_array[] = array_key_exists($row_value,$field_info->extras) ? $field_info->extras[$row_value] : $row_value;
313 }
314 $value = implode(",",$value_as_array);
315 break;
316
317 case 'relation_n_n':
318 $value = $this->character_limiter(str_replace(',',', ',$value),$this->character_limiter,"...");
319 break;
320
321 case 'password':
322 $value = '******';
323 break;
324
325 case 'dropdown':
326 $value = array_key_exists($value,$field_info->extras) ? $field_info->extras[$value] : $value;
327 break;
328
329 case 'upload_file':
330 if(empty($value))
331 {
332 $value = "";
333 }
334 else
335 {
336 $is_image = !empty($value) &&
337 ( substr($value,-4) == '.jpg'
338 || substr($value,-4) == '.png'
339 || substr($value,-5) == '.jpeg'
340 || substr($value,-4) == '.gif'
341 || substr($value,-5) == '.tiff')
342 ? true : false;
343
344 $file_url = base_url().$field_info->extras->upload_path."/$value";
345
346 $file_url_anchor = '<a href="'.$file_url.'"';
347 if($is_image)
348 {
349 $file_url_anchor .= ' class="image-thumbnail"><img src="'.$file_url.'" height="50px">';
350 }
351 else
352 {
353 $file_url_anchor .= ' target="_blank">'.$this->character_limiter($value,$this->character_limiter,'...',true);
354 }
355 $file_url_anchor .= '</a>';
356
357 $value = $file_url_anchor;
358 }
359 break;
360
361 default:
362 $value = $this->character_limiter($value,$this->character_limiter,"...");
363 break;
364 }
365
366 return $value;
367 }
368
369 /**
370 * Character Limiter of codeigniter (I just don't want to load the helper )
371 *
372 * Limits the string based on the character count. Preserves complete words
373 * so the character count may not be exactly as specified.
374 *
375 * @access public
376 * @param string
377 * @param integer
378 * @param string the end character. Usually an ellipsis
379 * @return string
380 */
381 function character_limiter($str, $n = 500, $end_char = '…')
382 {
383 if (strlen($str) < $n)
384 {
385 return $str;
386 }
387
388 // a bit complicated, but faster than preg_replace with \s+
389 $str = preg_replace('/ {2,}/', ' ', str_replace(array("\r", "\n", "\t", "\x0B", "\x0C"), ' ', $str));
390
391 if (strlen($str) <= $n)
392 {
393 return $str;
394 }
395
396 $out = '';
397 foreach (explode(' ', trim($str)) as $val)
398 {
399 $out .= $val.' ';
400
401 if (strlen($out) >= $n)
402 {
403 $out = trim($out);
404 return (strlen($out) === strlen($str)) ? $out : $out.$end_char;
405 }
406 }
407 }
408
409 protected function get_type($db_type)
410 {
411 $type = false;
412 if(!empty($db_type->type))
413 {
414 switch ($db_type->type) {
415 case '1':
416 case '3':
417 case 'int':
418 case 'tinyint':
419 case 'mediumint':
420 case 'longint':
421 if( $db_type->db_type == 'tinyint' && $db_type->db_max_length == 1)
422 $type = 'true_false';
423 else
424 $type = 'integer';
425 break;
426 case '254':
427 case 'string':
428 case 'enum':
429 if($db_type->db_type != 'enum')
430 $type = 'string';
431 else
432 $type = 'enum';
433 break;
434 case 'set':
435 if($db_type->db_type != 'set')
436 $type = 'string';
437 else
438 $type = 'set';
439 break;
440 case '252':
441 case 'blob':
442 case 'text':
443 case 'mediumtext':
444 case 'longtext':
445 $type = 'text';
446 break;
447 case '10':
448 case 'date':
449 $type = 'date';
450 break;
451 case '12':
452 case 'datetime':
453 case 'timestamp':
454 $type = 'datetime';
455 break;
456 }
457 }
458 return $type;
459 }
460}
461
462// ------------------------------------------------------------------------
463
464/**
465 * Grocery Model Driver
466 *
467 * Drives the model - I'ts so easy like you drive a bicycle :-)
468 *
469 * @package grocery CRUD
470 * @author John Skoumbourdis <scoumbourdisj@gmail.com>
471 * @version 1.5.8
472 * @link http://www.grocerycrud.com/documentation
473 */
474class grocery_CRUD_Model_Driver extends grocery_CRUD_Field_Types
475{
476 /**
477 * @var Grocery_crud_model
478 */
479 public $basic_model = null;
480
481 protected function set_default_Model()
482 {
483 $ci = &get_instance();
484 $ci->load->model('Grocery_crud_model');
485
486 $this->basic_model = new Grocery_crud_model();
487 }
488
489 protected function get_total_results()
490 {
491 if(!empty($this->where))
492 foreach($this->where as $where)
493 $this->basic_model->where($where[0],$where[1],$where[2]);
494
495 if(!empty($this->or_where))
496 foreach($this->or_where as $or_where)
497 $this->basic_model->or_where($or_where[0],$or_where[1],$or_where[2]);
498
499 if(!empty($this->like))
500 foreach($this->like as $like)
501 $this->basic_model->like($like[0],$like[1],$like[2]);
502
503 if(!empty($this->or_like))
504 foreach($this->or_like as $or_like)
505 $this->basic_model->or_like($or_like[0],$or_like[1],$or_like[2]);
506
507 if(!empty($this->having))
508 foreach($this->having as $having)
509 $this->basic_model->having($having[0],$having[1],$having[2]);
510
511 if(!empty($this->or_having))
512 foreach($this->or_having as $or_having)
513 $this->basic_model->or_having($or_having[0],$or_having[1],$or_having[2]);
514
515 if(!empty($this->relation))
516 foreach($this->relation as $relation)
517 $this->basic_model->join_relation($relation[0],$relation[1],$relation[2]);
518
519 if(!empty($this->relation_n_n))
520 {
521 $columns = $this->get_columns();
522 foreach($columns as $column)
523 {
524 //Use the relation_n_n ONLY if the column is called . The set_relation_n_n are slow and it will make the table slower without any reason as we don't need those queries.
525 if(isset($this->relation_n_n[$column->field_name]))
526 {
527 $this->basic_model->set_relation_n_n_field($this->relation_n_n[$column->field_name]);
528 }
529 }
530
531 }
532
533 return $this->basic_model->get_total_results();
534 }
535
536 protected function filter_data_from_xss($post_data) {
537 foreach ($post_data as $field_name => $rawData) {
538 if (!is_array($rawData)) {
539 $post_data[$field_name] = filter_var(strip_tags($rawData));
540 }
541 }
542 return $post_data;
543 }
544
545 public function set_model($model_name)
546 {
547 $ci = &get_instance();
548 $ci->load->model('Grocery_crud_model');
549
550 $ci->load->model($model_name);
551
552 $temp = explode('/',$model_name);
553 krsort($temp);
554 foreach($temp as $t)
555 {
556 $real_model_name = $t;
557 break;
558 }
559
560 $this->basic_model = $ci->$real_model_name;
561 }
562
563 protected function set_ajax_list_queries($state_info = null)
564 {
565 if(!empty($state_info->per_page))
566 {
567 if(empty($state_info->page) || !is_numeric($state_info->page) )
568 $this->limit($state_info->per_page);
569 else
570 {
571 $limit_page = ( ($state_info->page-1) * $state_info->per_page );
572 $this->limit($state_info->per_page, $limit_page);
573 }
574 }
575
576 if(!empty($state_info->order_by))
577 {
578 $this->order_by($state_info->order_by[0],$state_info->order_by[1]);
579 }
580
581 if(!empty($state_info->search))
582 {
583 if (!empty($this->relation)) {
584 foreach ($this->relation as $relation_name => $relation_values) {
585 $temp_relation[$this->_unique_field_name($relation_name)] = $this->_get_field_names_to_search($relation_values);
586 }
587 }
588
589 if (is_array($state_info->search)) {
590 foreach ($state_info->search as $search_field => $search_text) {
591
592
593 if (isset($temp_relation[$search_field])) {
594 if (is_array($temp_relation[$search_field])) {
595 foreach ($temp_relation[$search_field] as $relation_field) {
596 $this->or_like($relation_field , $search_text);
597 }
598 } else {
599 $this->like($temp_relation[$search_field] , $search_text);
600 }
601 } elseif(isset($this->relation_n_n[$search_field])) {
602 $escaped_text = $this->basic_model->escape_str($search_text);
603 $this->having($search_field." LIKE '%".$escaped_text."%'");
604 } else {
605 $this->like($search_field, $search_text);
606 }
607
608
609
610 }
611 } elseif ($state_info->search->field !== null) {
612 if (isset($temp_relation[$state_info->search->field])) {
613 if (is_array($temp_relation[$state_info->search->field])) {
614 foreach ($temp_relation[$state_info->search->field] as $search_field) {
615 $this->or_like($search_field , $state_info->search->text);
616 }
617 } else {
618 $this->like($temp_relation[$state_info->search->field] , $state_info->search->text);
619 }
620 } elseif(isset($this->relation_n_n[$state_info->search->field])) {
621 $escaped_text = $this->basic_model->escape_str($state_info->search->text);
622 $this->having($state_info->search->field." LIKE '%".$escaped_text."%'");
623 } else {
624 $this->like($state_info->search->field , $state_info->search->text);
625 }
626 }
627 else
628 {
629 $columns = $this->get_columns();
630
631 $search_text = $state_info->search->text;
632
633 if(!empty($this->where))
634 foreach($this->where as $where)
635 $this->basic_model->having($where[0],$where[1],$where[2]);
636
637 foreach($columns as $column)
638 {
639 if(isset($temp_relation[$column->field_name]))
640 {
641 if(is_array($temp_relation[$column->field_name]))
642 {
643 foreach($temp_relation[$column->field_name] as $search_field)
644 {
645 $this->or_like($search_field, $search_text);
646 }
647 }
648 else
649 {
650 $this->or_like($temp_relation[$column->field_name], $search_text);
651 }
652 }
653 elseif(isset($this->relation_n_n[$column->field_name]))
654 {
655 //@todo have a where for the relation_n_n statement
656 }
657 else
658 {
659 $this->or_like($column->field_name, $search_text);
660 }
661 }
662 }
663 }
664 }
665
666 protected function table_exists($table_name = null)
667 {
668 if($this->basic_model->db_table_exists($table_name))
669 return true;
670 return false;
671 }
672
673 protected function get_relation_array($relation_info, $primary_key_value = null, $limit = null)
674 {
675 list($field_name , $related_table , $related_field_title, $where_clause, $order_by) = $relation_info;
676
677 if($primary_key_value !== null)
678 {
679 $primary_key = $this->basic_model->get_primary_key($related_table);
680
681 //A where clause with the primary key is enough to take the selected key row
682 $where_clause = array($primary_key => $primary_key_value);
683 }
684
685 $relation_array = $this->basic_model->get_relation_array($field_name , $related_table , $related_field_title, $where_clause, $order_by, $limit);
686
687 return $relation_array;
688 }
689
690 protected function get_relation_total_rows($relation_info)
691 {
692 list($field_name , $related_table , $related_field_title, $where_clause) = $relation_info;
693
694 $relation_array = $this->basic_model->get_relation_total_rows($field_name , $related_table , $related_field_title, $where_clause);
695
696 return $relation_array;
697 }
698
699 protected function db_insert_validation()
700 {
701 $validation_result = (object)array('success'=>false);
702
703 $field_types = $this->get_field_types();
704 $required_fields = $this->required_fields;
705 $unique_fields = $this->_unique_fields;
706 $add_fields = $this->get_add_fields();
707
708 if(!empty($required_fields))
709 {
710 foreach($add_fields as $add_field)
711 {
712 $field_name = $add_field->field_name;
713 if(!isset($this->validation_rules[$field_name]) && in_array( $field_name, $required_fields) )
714 {
715 $this->set_rules( $field_name, $field_types[$field_name]->display_as, 'required');
716 }
717 }
718 }
719
720 /** Checking for unique fields. If the field value is not unique then
721 * return a validation error straight away, if not continue... */
722 if(!empty($unique_fields))
723 {
724 $form_validation = $this->form_validation();
725
726 foreach($add_fields as $add_field)
727 {
728 $field_name = $add_field->field_name;
729 if(in_array( $field_name, $unique_fields) )
730 {
731 $form_validation->set_rules( $field_name,
732 $field_types[$field_name]->display_as,
733 'is_unique['.$this->basic_db_table.'.'.$field_name.']');
734 }
735 }
736
737 if(!$form_validation->run())
738 {
739 $validation_result->error_message = $form_validation->error_string();
740 $validation_result->error_fields = $form_validation->_error_array;
741
742 return $validation_result;
743 }
744 }
745
746 if(!empty($this->validation_rules))
747 {
748 $form_validation = $this->form_validation();
749
750 $add_fields = $this->get_add_fields();
751
752 foreach($add_fields as $add_field)
753 {
754 $field_name = $add_field->field_name;
755 if(isset($this->validation_rules[$field_name]))
756 {
757 $rule = $this->validation_rules[$field_name];
758 $form_validation->set_rules($rule['field'],$rule['label'],$rule['rules'],$rule['errors']);
759 }
760 }
761
762 if($form_validation->run())
763 {
764 $validation_result->success = true;
765 }
766 else
767 {
768 $validation_result->error_message = $form_validation->error_string();
769 $validation_result->error_fields = $form_validation->_error_array;
770 }
771 }
772 else
773 {
774 $validation_result->success = true;
775 }
776
777 return $validation_result;
778 }
779
780 protected function form_validation()
781 {
782 if($this->form_validation === null)
783 {
784 $this->form_validation = new grocery_CRUD_Form_validation();
785 $ci = &get_instance();
786 $ci->load->library('form_validation');
787 $ci->form_validation = $this->form_validation;
788 }
789 return $this->form_validation;
790 }
791
792 protected function db_update_validation()
793 {
794 $validation_result = (object)array('success'=>false);
795
796 $field_types = $this->get_field_types();
797 $required_fields = $this->required_fields;
798 $unique_fields = $this->_unique_fields;
799 $edit_fields = $this->get_edit_fields();
800
801 if(!empty($required_fields))
802 {
803 foreach($edit_fields as $edit_field)
804 {
805 $field_name = $edit_field->field_name;
806 if(!isset($this->validation_rules[$field_name]) && in_array( $field_name, $required_fields) )
807 {
808 $this->set_rules( $field_name, $field_types[$field_name]->display_as, 'required');
809 }
810 }
811 }
812
813
814 /** Checking for unique fields. If the field value is not unique then
815 * return a validation error straight away, if not continue... */
816 if(!empty($unique_fields))
817 {
818 $form_validation = $this->form_validation();
819
820 $form_validation_check = false;
821
822 foreach($edit_fields as $edit_field)
823 {
824 $field_name = $edit_field->field_name;
825 if(in_array( $field_name, $unique_fields) )
826 {
827 $state_info = $this->getStateInfo();
828 $primary_key = $this->get_primary_key();
829 $field_name_value = $_POST[$field_name];
830
831 $this->basic_model->where($primary_key,$state_info->primary_key);
832 $row = $this->basic_model->get_row();
833
834 if(!isset($row->$field_name)) {
835 throw new Exception("The field name doesn't exist in the database. ".
836 "Please use the unique fields only for fields ".
837 "that exist in the database");
838 }
839
840 $previous_field_name_value = $row->$field_name;
841
842 if(!empty($previous_field_name_value) && $previous_field_name_value != $field_name_value) {
843 $form_validation->set_rules( $field_name,
844 $field_types[$field_name]->display_as,
845 'is_unique['.$this->basic_db_table.'.'.$field_name.']');
846
847 $form_validation_check = true;
848 }
849 }
850 }
851
852 if($form_validation_check && !$form_validation->run())
853 {
854 $validation_result->error_message = $form_validation->error_string();
855 $validation_result->error_fields = $form_validation->_error_array;
856
857 return $validation_result;
858 }
859 }
860
861 if(!empty($this->validation_rules))
862 {
863 $form_validation = $this->form_validation();
864
865 $edit_fields = $this->get_edit_fields();
866
867 foreach($edit_fields as $edit_field)
868 {
869 $field_name = $edit_field->field_name;
870 if(isset($this->validation_rules[$field_name]))
871 {
872 $rule = $this->validation_rules[$field_name];
873 $form_validation->set_rules($rule['field'],$rule['label'],$rule['rules'],$rule['errors']);
874 }
875 }
876
877 if($form_validation->run())
878 {
879 $validation_result->success = true;
880 }
881 else
882 {
883 $validation_result->error_message = $form_validation->error_string();
884 $validation_result->error_fields = $form_validation->_error_array;
885 }
886 }
887 else
888 {
889 $validation_result->success = true;
890 }
891
892 return $validation_result;
893 }
894
895 protected function db_insert($state_info)
896 {
897 $validation_result = $this->db_insert_validation();
898
899 if($validation_result->success)
900 {
901 $post_data = $state_info->unwrapped_data;
902
903 if ($this->config->xss_clean) {
904 $post_data = $this->filter_data_from_xss($post_data);
905 }
906
907 $add_fields = $this->get_add_fields();
908
909 if($this->callback_insert === null)
910 {
911 if($this->callback_before_insert !== null)
912 {
913 $callback_return = call_user_func($this->callback_before_insert, $post_data);
914
915 if(!empty($callback_return) && is_array($callback_return))
916 $post_data = $callback_return;
917 elseif($callback_return === false)
918 return false;
919 }
920
921 $insert_data = array();
922 $types = $this->get_field_types();
923 foreach($add_fields as $num_row => $field)
924 {
925 /* If the multiselect or the set is empty then the browser doesn't send an empty array. Instead it sends nothing */
926 if(isset($types[$field->field_name]->crud_type) && ($types[$field->field_name]->crud_type == 'set' || $types[$field->field_name]->crud_type == 'multiselect') && !isset($post_data[$field->field_name]))
927 {
928 $post_data[$field->field_name] = array();
929 }
930
931 if(isset($post_data[$field->field_name]) && !isset($this->relation_n_n[$field->field_name]))
932 {
933 if(isset($types[$field->field_name]->db_null) && $types[$field->field_name]->db_null && is_array($post_data[$field->field_name]) && empty($post_data[$field->field_name]))
934 {
935 $insert_data[$field->field_name] = null;
936 }
937 elseif(isset($types[$field->field_name]->db_null) && $types[$field->field_name]->db_null && $post_data[$field->field_name] === '')
938 {
939 $insert_data[$field->field_name] = null;
940 }
941 elseif(isset($types[$field->field_name]->crud_type) && $types[$field->field_name]->crud_type == 'date')
942 {
943 $insert_data[$field->field_name] = $this->_convert_date_to_sql_date($post_data[$field->field_name]);
944 }
945 elseif(isset($types[$field->field_name]->crud_type) && $types[$field->field_name]->crud_type == 'readonly')
946 {
947 //This empty if statement is to make sure that a readonly field will never inserted/updated
948 }
949 elseif(isset($types[$field->field_name]->crud_type) && ($types[$field->field_name]->crud_type == 'set' || $types[$field->field_name]->crud_type == 'multiselect'))
950 {
951 $insert_data[$field->field_name] = !empty($post_data[$field->field_name]) ? implode(',',$post_data[$field->field_name]) : '';
952 }
953 elseif(isset($types[$field->field_name]->crud_type) && $types[$field->field_name]->crud_type == 'datetime'){
954 $insert_data[$field->field_name] = $this->_convert_date_to_sql_date(substr($post_data[$field->field_name],0,10)).
955 substr($post_data[$field->field_name],10);
956 }
957 else
958 {
959 $insert_data[$field->field_name] = $post_data[$field->field_name];
960 }
961 }
962 }
963
964 $insert_result = $this->basic_model->db_insert($insert_data);
965
966 if($insert_result !== false)
967 {
968 $insert_primary_key = $insert_result;
969 }
970 else
971 {
972 return false;
973 }
974
975 if(!empty($this->relation_n_n))
976 {
977 foreach($this->relation_n_n as $field_name => $field_info)
978 {
979 $relation_data = isset( $post_data[$field_name] ) ? $post_data[$field_name] : array() ;
980 $this->db_relation_n_n_update($field_info, $relation_data ,$insert_primary_key);
981 }
982 }
983
984 if($this->callback_after_insert !== null)
985 {
986 $callback_return = call_user_func($this->callback_after_insert, $post_data, $insert_primary_key);
987
988 if($callback_return === false)
989 {
990 return false;
991 }
992
993 }
994 }else
995 {
996 $callback_return = call_user_func($this->callback_insert, $post_data);
997
998 if($callback_return === false)
999 {
1000 return false;
1001 }
1002 }
1003
1004 if(isset($insert_primary_key))
1005 return $insert_primary_key;
1006 else
1007 return true;
1008 }
1009
1010 return false;
1011
1012 }
1013
1014 protected function db_update($state_info)
1015 {
1016 $validation_result = $this->db_update_validation();
1017
1018 $edit_fields = $this->get_edit_fields();
1019
1020 if($validation_result->success)
1021 {
1022 $post_data = $state_info->unwrapped_data;
1023 $primary_key = $state_info->primary_key;
1024
1025 if ($this->config->xss_clean) {
1026 $post_data = $this->filter_data_from_xss($post_data);
1027 }
1028
1029 if($this->callback_update === null)
1030 {
1031 if($this->callback_before_update !== null)
1032 {
1033 $callback_return = call_user_func($this->callback_before_update, $post_data, $primary_key);
1034
1035 if(!empty($callback_return) && is_array($callback_return))
1036 {
1037 $post_data = $callback_return;
1038 }
1039 elseif($callback_return === false)
1040 {
1041 return false;
1042 }
1043
1044 }
1045
1046 $update_data = array();
1047 $types = $this->get_field_types();
1048 foreach($edit_fields as $num_row => $field)
1049 {
1050 /* If the multiselect or the set is empty then the browser doesn't send an empty array. Instead it sends nothing */
1051 if(isset($types[$field->field_name]->crud_type) && ($types[$field->field_name]->crud_type == 'set' || $types[$field->field_name]->crud_type == 'multiselect') && !isset($post_data[$field->field_name]))
1052 {
1053 $post_data[$field->field_name] = array();
1054 }
1055
1056 if(isset($post_data[$field->field_name]) && !isset($this->relation_n_n[$field->field_name]))
1057 {
1058 if(isset($types[$field->field_name]->db_null) && $types[$field->field_name]->db_null && is_array($post_data[$field->field_name]) && empty($post_data[$field->field_name]))
1059 {
1060 $update_data[$field->field_name] = null;
1061 }
1062 elseif(isset($types[$field->field_name]->db_null) && $types[$field->field_name]->db_null && $post_data[$field->field_name] === '')
1063 {
1064 $update_data[$field->field_name] = null;
1065 }
1066 elseif(isset($types[$field->field_name]->crud_type) && $types[$field->field_name]->crud_type == 'date')
1067 {
1068 $update_data[$field->field_name] = $this->_convert_date_to_sql_date($post_data[$field->field_name]);
1069 }
1070 elseif(isset($types[$field->field_name]->crud_type) && $types[$field->field_name]->crud_type == 'readonly')
1071 {
1072 //This empty if statement is to make sure that a readonly field will never inserted/updated
1073 }
1074 elseif(isset($types[$field->field_name]->crud_type) && ($types[$field->field_name]->crud_type == 'set' || $types[$field->field_name]->crud_type == 'multiselect'))
1075 {
1076 $update_data[$field->field_name] = !empty($post_data[$field->field_name]) ? implode(',',$post_data[$field->field_name]) : '';
1077 }
1078 elseif(isset($types[$field->field_name]->crud_type) && $types[$field->field_name]->crud_type == 'datetime'){
1079 $update_data[$field->field_name] = $this->_convert_date_to_sql_date(substr($post_data[$field->field_name],0,10)).
1080 substr($post_data[$field->field_name],10);
1081 }
1082 else
1083 {
1084 $update_data[$field->field_name] = $post_data[$field->field_name];
1085 }
1086 }
1087 }
1088
1089 if($this->basic_model->db_update($update_data, $primary_key) === false)
1090 {
1091 return false;
1092 }
1093
1094 if(!empty($this->relation_n_n))
1095 {
1096 foreach($this->relation_n_n as $field_name => $field_info)
1097 {
1098 if ( $this->unset_edit_fields !== null
1099 && is_array($this->unset_edit_fields)
1100 && in_array($field_name,$this->unset_edit_fields)
1101 ) {
1102 continue;
1103 }
1104
1105 $relation_data = isset( $post_data[$field_name] ) ? $post_data[$field_name] : array() ;
1106 $this->db_relation_n_n_update($field_info, $relation_data ,$primary_key);
1107 }
1108 }
1109
1110 if($this->callback_after_update !== null)
1111 {
1112 $callback_return = call_user_func($this->callback_after_update, $post_data, $primary_key);
1113
1114 if($callback_return === false)
1115 {
1116 return false;
1117 }
1118
1119 }
1120 }
1121 else
1122 {
1123 $callback_return = call_user_func($this->callback_update, $post_data, $primary_key);
1124
1125 if($callback_return === false)
1126 {
1127 return false;
1128 }
1129 }
1130
1131 return true;
1132 }
1133 else
1134 {
1135 return false;
1136 }
1137 }
1138
1139 protected function _convert_date_to_sql_date($date)
1140 {
1141 $date = substr($date,0,10);
1142 if(preg_match('/\d{4}-\d{2}-\d{2}/',$date))
1143 {
1144 //If it's already a sql-date don't convert it!
1145 return $date;
1146 }elseif(empty($date))
1147 {
1148 return '';
1149 }
1150
1151 $date_array = preg_split( '/[-\.\/ ]/', $date);
1152 if($this->php_date_format == 'd/m/Y')
1153 {
1154 $sql_date = date('Y-m-d',mktime(0,0,0,$date_array[1],$date_array[0],$date_array[2]));
1155 }
1156 elseif($this->php_date_format == 'm/d/Y')
1157 {
1158 $sql_date = date('Y-m-d',mktime(0,0,0,$date_array[0],$date_array[1],$date_array[2]));
1159 }
1160 else
1161 {
1162 $sql_date = $date;
1163 }
1164
1165 return $sql_date;
1166 }
1167
1168 protected function _get_field_names_to_search(array $relation_values)
1169 {
1170 if(!strstr($relation_values[2],'{'))
1171 return $this->_unique_join_name($relation_values[0]).'.'.$relation_values[2];
1172 else
1173 {
1174 $relation_values[2] = ' '.$relation_values[2].' ';
1175 $temp1 = explode('{',$relation_values[2]);
1176 unset($temp1[0]);
1177
1178 $field_names_array = array();
1179 foreach($temp1 as $field)
1180 list($field_names_array[]) = explode('}',$field);
1181
1182 return $field_names_array;
1183 }
1184 }
1185
1186 protected function _unique_join_name($field_name)
1187 {
1188 return 'j'.substr(md5($field_name),0,8); //This j is because is better for a string to begin with a letter and not a number
1189 }
1190
1191 protected function _unique_field_name($field_name)
1192 {
1193 return 's'.substr(md5($field_name),0,8); //This s is because is better for a string to begin with a letter and not a number
1194 }
1195
1196 protected function db_multiple_delete($state_info)
1197 {
1198 foreach ($state_info->ids as $delete_id) {
1199 $result = $this->db_delete((object)array('primary_key' => $delete_id));
1200 if (!$result) {
1201 return false;
1202 }
1203 }
1204
1205 return true;
1206 }
1207
1208 protected function db_delete($state_info)
1209 {
1210 $primary_key_value = $state_info->primary_key;
1211
1212 if($this->callback_delete === null)
1213 {
1214 if($this->callback_before_delete !== null)
1215 {
1216 $callback_return = call_user_func($this->callback_before_delete, $primary_key_value);
1217
1218 if($callback_return === false)
1219 {
1220 return false;
1221 }
1222
1223 }
1224
1225 if(!empty($this->relation_n_n))
1226 {
1227 foreach($this->relation_n_n as $field_name => $field_info)
1228 {
1229 $this->db_relation_n_n_delete( $field_info, $primary_key_value );
1230 }
1231 }
1232
1233 $delete_result = $this->basic_model->db_delete($primary_key_value);
1234
1235 if($delete_result === false)
1236 {
1237 return false;
1238 }
1239
1240 if($this->callback_after_delete !== null)
1241 {
1242 $callback_return = call_user_func($this->callback_after_delete, $primary_key_value);
1243
1244 if($callback_return === false)
1245 {
1246 return false;
1247 }
1248
1249 }
1250 }
1251 else
1252 {
1253 $callback_return = call_user_func($this->callback_delete, $primary_key_value);
1254
1255 if($callback_return === false)
1256 {
1257 return false;
1258 }
1259 }
1260
1261 return true;
1262 }
1263
1264 protected function db_relation_n_n_update($field_info, $post_data , $primary_key_value)
1265 {
1266 $this->basic_model->db_relation_n_n_update($field_info, $post_data , $primary_key_value);
1267 }
1268
1269 protected function db_relation_n_n_delete($field_info, $primary_key_value)
1270 {
1271 $this->basic_model->db_relation_n_n_delete($field_info, $primary_key_value);
1272 }
1273
1274 protected function get_list()
1275 {
1276 if(!empty($this->order_by))
1277 $this->basic_model->order_by($this->order_by[0],$this->order_by[1]);
1278
1279 if(!empty($this->where))
1280 foreach($this->where as $where)
1281 $this->basic_model->where($where[0],$where[1],$where[2]);
1282
1283 if(!empty($this->or_where))
1284 foreach($this->or_where as $or_where)
1285 $this->basic_model->or_where($or_where[0],$or_where[1],$or_where[2]);
1286
1287 if(!empty($this->like))
1288 foreach($this->like as $like)
1289 $this->basic_model->like($like[0],$like[1],$like[2]);
1290
1291 if(!empty($this->or_like))
1292 foreach($this->or_like as $or_like)
1293 $this->basic_model->or_like($or_like[0],$or_like[1],$or_like[2]);
1294
1295 if(!empty($this->having))
1296 foreach($this->having as $having)
1297 $this->basic_model->having($having[0],$having[1],$having[2]);
1298
1299 if(!empty($this->or_having))
1300 foreach($this->or_having as $or_having)
1301 $this->basic_model->or_having($or_having[0],$or_having[1],$or_having[2]);
1302
1303 if(!empty($this->relation))
1304 foreach($this->relation as $relation)
1305 $this->basic_model->join_relation($relation[0],$relation[1],$relation[2]);
1306
1307 if(!empty($this->relation_n_n))
1308 {
1309 $columns = $this->get_columns();
1310 foreach($columns as $column)
1311 {
1312 //Use the relation_n_n ONLY if the column is called . The set_relation_n_n are slow and it will make the table slower without any reason as we don't need those queries.
1313 if(isset($this->relation_n_n[$column->field_name]))
1314 {
1315 $this->basic_model->set_relation_n_n_field($this->relation_n_n[$column->field_name]);
1316 }
1317 }
1318
1319 }
1320
1321 if($this->theme_config['crud_paging'] === true)
1322 {
1323 if($this->limit === null)
1324 {
1325 $default_per_page = $this->config->default_per_page;
1326 if(is_numeric($default_per_page) && $default_per_page >1)
1327 {
1328 $this->basic_model->limit($default_per_page);
1329 }
1330 else
1331 {
1332 $this->basic_model->limit(10);
1333 }
1334 }
1335 else
1336 {
1337 $this->basic_model->limit($this->limit[0],$this->limit[1]);
1338 }
1339 }
1340
1341 $results = $this->basic_model->get_list();
1342
1343 return $results;
1344 }
1345
1346 protected function get_edit_values($primary_key_value)
1347 {
1348 $values = $this->basic_model->get_edit_values($primary_key_value);
1349
1350 if(!empty($this->relation_n_n))
1351 {
1352 foreach($this->relation_n_n as $field_name => $field_info)
1353 {
1354 $values->$field_name = $this->get_relation_n_n_selection_array($primary_key_value, $field_info);
1355 }
1356 }
1357
1358 return $values;
1359 }
1360
1361 protected function get_relation_n_n_selection_array($primary_key_value, $field_info)
1362 {
1363 return $this->basic_model->get_relation_n_n_selection_array($primary_key_value, $field_info);
1364 }
1365
1366 protected function get_relation_n_n_unselected_array($field_info, $selected_values)
1367 {
1368 return $this->basic_model->get_relation_n_n_unselected_array($field_info, $selected_values);
1369 }
1370
1371 protected function set_basic_db_table($table_name = null)
1372 {
1373 $this->basic_model->set_basic_table($table_name);
1374 }
1375
1376 protected function upload_file($state_info)
1377 {
1378 if(isset($this->upload_fields[$state_info->field_name]) )
1379 {
1380 echo "The problem is more complicated than I thought!";
1381 }
1382 else
1383 {
1384 echo "The problem is probably simple!<br/>";
1385 echo $state_info->field_name."<br/>";
1386 echo print_r($this->upload_fields,true);
1387 }
1388
1389 die();
1390
1391 if(isset($this->upload_fields[$state_info->field_name]) )
1392 {
1393 if($this->callback_upload === null)
1394 {
1395 if($this->callback_before_upload !== null)
1396 {
1397 $callback_before_upload_response = call_user_func($this->callback_before_upload, $_FILES, $this->upload_fields[$state_info->field_name]);
1398
1399 if($callback_before_upload_response === false)
1400 return false;
1401 elseif(is_string($callback_before_upload_response))
1402 return $callback_before_upload_response;
1403 }
1404
1405 $upload_info = $this->upload_fields[$state_info->field_name];
1406
1407 header('Pragma: no-cache');
1408 header('Cache-Control: private, no-cache');
1409 header('Content-Disposition: inline; filename="files.json"');
1410 header('X-Content-Type-Options: nosniff');
1411 header('Access-Control-Allow-Origin: *');
1412 header('Access-Control-Allow-Methods: OPTIONS, HEAD, GET, POST, PUT, DELETE');
1413 header('Access-Control-Allow-Headers: X-File-Name, X-File-Type, X-File-Size');
1414
1415 $allowed_files = $this->config->file_upload_allow_file_types;
1416
1417 $reg_exp = '';
1418 if(!empty($upload_info->allowed_file_types)){
1419 $reg_exp = '/(\\.|\\/)('.$upload_info->allowed_file_types.')$/i';
1420 }else{
1421 $reg_exp = '/(\\.|\\/)('.$allowed_files.')$/i';
1422 }
1423
1424 $max_file_size_ui = $this->config->file_upload_max_file_size;
1425 $max_file_size_bytes = $this->_convert_bytes_ui_to_bytes($max_file_size_ui);
1426
1427 $options = array(
1428 'upload_dir' => $upload_info->upload_path.'/',
1429 'param_name' => $this->_unique_field_name($state_info->field_name),
1430 'upload_url' => base_url().$upload_info->upload_path.'/',
1431 'accept_file_types' => $reg_exp,
1432 'max_file_size' => $max_file_size_bytes
1433 );
1434 $upload_handler = new UploadHandler($options);
1435 $upload_handler->default_config_path = $this->default_config_path;
1436 $uploader_response = $upload_handler->post();
1437
1438 if(is_array($uploader_response))
1439 {
1440 foreach($uploader_response as &$response)
1441 {
1442 unset($response->delete_url);
1443 unset($response->delete_type);
1444 }
1445 }
1446
1447 if($this->callback_after_upload !== null)
1448 {
1449 $callback_after_upload_response = call_user_func($this->callback_after_upload, $uploader_response , $this->upload_fields[$state_info->field_name] , $_FILES );
1450
1451 if($callback_after_upload_response === false)
1452 return false;
1453 elseif(is_string($callback_after_upload_response))
1454 return $callback_after_upload_response;
1455 elseif(is_array($callback_after_upload_response))
1456 $uploader_response = $callback_after_upload_response;
1457 }
1458
1459 return $uploader_response;
1460 }
1461 else
1462 {
1463 $upload_response = call_user_func($this->callback_upload, $_FILES, $this->upload_fields[$state_info->field_name] );
1464
1465 if($upload_response === false)
1466 {
1467 return false;
1468 }
1469 else
1470 {
1471 return $upload_response;
1472 }
1473 }
1474 }
1475 else
1476 {
1477 return false;
1478 }
1479 }
1480
1481 protected function delete_file($state_info)
1482 {
1483
1484 if(isset($state_info->field_name) && isset($this->upload_fields[$state_info->field_name]))
1485 {
1486 $upload_info = $this->upload_fields[$state_info->field_name];
1487
1488 if(file_exists("{$upload_info->upload_path}/{$state_info->file_name}"))
1489 {
1490 if( unlink("{$upload_info->upload_path}/{$state_info->file_name}") )
1491 {
1492 $this->basic_model->db_file_delete($state_info->field_name, $state_info->file_name);
1493
1494 return true;
1495 }
1496 else
1497 {
1498 return false;
1499 }
1500 }
1501 else
1502 {
1503 $this->basic_model->db_file_delete($state_info->field_name, $state_info->file_name);
1504 return true;
1505 }
1506 }
1507 else
1508 {
1509 return false;
1510 }
1511 }
1512
1513 protected function ajax_relation($state_info)
1514 {
1515 if(!isset($this->relation[$state_info->field_name]))
1516 return false;
1517
1518 list($field_name, $related_table, $related_field_title, $where_clause, $order_by) = $this->relation[$state_info->field_name];
1519
1520 return $this->basic_model->get_ajax_relation_array($state_info->search, $field_name, $related_table, $related_field_title, $where_clause, $order_by);
1521 }
1522}
1523
1524
1525/**
1526 * PHP grocery CRUD
1527 *
1528 * LICENSE
1529 *
1530 * Grocery CRUD is released with dual licensing, using the GPL v3 (license-gpl3.txt) and the MIT license (license-mit.txt).
1531 * You don't have to do anything special to choose one license or the other and you don't have to notify anyone which license you are using.
1532 * Please see the corresponding license file for details of these licenses.
1533 * You are free to use, modify and distribute this software, but all copyright information must remain.
1534 *
1535 * @package grocery CRUD
1536 * @copyright Copyright (c) 2010 through 2014, John Skoumbourdis
1537 * @license https://github.com/scoumbourdis/grocery-crud/blob/master/license-grocery-crud.txt
1538 * @author John Skoumbourdis <scoumbourdisj@gmail.com>
1539 */
1540
1541// ------------------------------------------------------------------------
1542
1543/**
1544 * PHP grocery Layout
1545 *
1546 * Here you manage all the HTML Layout
1547 *
1548 * @package grocery CRUD
1549 * @author John Skoumbourdis <scoumbourdisj@gmail.com>
1550 * @version 1.5.8
1551 */
1552class grocery_CRUD_Layout extends grocery_CRUD_Model_Driver
1553{
1554 private $theme_path = null;
1555 private $views_as_string = '';
1556 private $echo_and_die = false;
1557 protected $theme = null;
1558 protected $default_true_false_text = array('inactive' , 'active');
1559
1560 protected $css_files = array();
1561 protected $js_files = array();
1562 protected $js_lib_files = array();
1563 protected $js_config_files = array();
1564
1565 protected function set_basic_Layout()
1566 {
1567 if(!file_exists($this->theme_path.$this->theme.'/views/list_template.php'))
1568 {
1569 throw new Exception('The template does not exist. Please check your files and try again.', 12);
1570 die();
1571 }
1572 }
1573
1574 protected function showList($ajax = false, $state_info = null)
1575 {
1576 $data = $this->get_common_data();
1577
1578 $data->order_by = $this->order_by;
1579
1580 $data->types = $this->get_field_types();
1581
1582 $data->list = $this->get_list();
1583 $data->list = $this->change_list($data->list , $data->types);
1584 $data->list = $this->change_list_add_actions($data->list);
1585
1586 $data->total_results = $this->get_total_results();
1587
1588 $data->columns = $this->get_columns();
1589
1590 $data->success_message = $this->get_success_message_at_list($state_info);
1591
1592 $data->primary_key = $this->get_primary_key();
1593 $data->add_url = $this->getAddUrl();
1594 $data->edit_url = $this->getEditUrl();
1595 $data->delete_url = $this->getDeleteUrl();
1596 $data->delete_multiple_url = $this->getDeleteMultipleUrl();
1597 $data->read_url = $this->getReadUrl();
1598 $data->ajax_list_url = $this->getAjaxListUrl();
1599 $data->ajax_list_info_url = $this->getAjaxListInfoUrl();
1600 $data->export_url = $this->getExportToExcelUrl();
1601 $data->print_url = $this->getPrintUrl();
1602 $data->actions = $this->actions;
1603 $data->unique_hash = $this->get_method_hash();
1604 $data->order_by = $this->order_by;
1605
1606 $data->unset_add = $this->unset_add;
1607 $data->unset_edit = $this->unset_edit;
1608 $data->unset_read = $this->unset_read;
1609 $data->unset_delete = $this->unset_delete;
1610 $data->unset_export = $this->unset_export;
1611 $data->unset_print = $this->unset_print;
1612
1613 $default_per_page = $this->config->default_per_page;
1614 $data->paging_options = $this->config->paging_options;
1615 $data->default_per_page = is_numeric($default_per_page) && $default_per_page >1 && in_array($default_per_page,$data->paging_options)? $default_per_page : 25;
1616
1617 if($data->list === false)
1618 {
1619 throw new Exception('It is impossible to get data. Please check your model and try again.', 13);
1620 $data->list = array();
1621 }
1622
1623 foreach($data->list as $num_row => $row)
1624 {
1625 $data->list[$num_row]->primary_key_value = $row->{$data->primary_key};
1626 $data->list[$num_row]->edit_url = $data->edit_url.'/'.$row->{$data->primary_key};
1627 $data->list[$num_row]->delete_url = $data->delete_url.'/'.$row->{$data->primary_key};
1628 $data->list[$num_row]->read_url = $data->read_url.'/'.$row->{$data->primary_key};
1629 }
1630
1631 if(!$ajax)
1632 {
1633 $this->_add_js_vars(array('dialog_forms' => $this->config->dialog_forms));
1634
1635 $data->list_view = $this->_theme_view('list.php',$data,true);
1636 $this->_theme_view('list_template.php',$data);
1637 }
1638 else
1639 {
1640 $this->set_echo_and_die();
1641 $this->_theme_view('list.php',$data);
1642 }
1643 }
1644
1645 protected function exportToExcel($state_info = null)
1646 {
1647 $data = $this->get_common_data();
1648
1649 $data->order_by = $this->order_by;
1650 $data->types = $this->get_field_types();
1651
1652 $data->list = $this->get_list();
1653 $data->list = $this->change_list($data->list , $data->types);
1654 $data->list = $this->change_list_add_actions($data->list);
1655
1656 $data->total_results = $this->get_total_results();
1657
1658 $data->columns = $this->get_columns();
1659 $data->primary_key = $this->get_primary_key();
1660
1661 @ob_end_clean();
1662 $this->_export_to_excel($data);
1663 }
1664
1665 protected function _export_to_excel($data)
1666 {
1667 /**
1668 * No need to use an external library here. The only bad thing without using external library is that Microsoft Excel is complaining
1669 * that the file is in a different format than specified by the file extension. If you press "Yes" everything will be just fine.
1670 * */
1671
1672 $string_to_export = "";
1673 foreach($data->columns as $column){
1674 $string_to_export .= $column->display_as."\t";
1675 }
1676 $string_to_export .= "\n";
1677
1678 foreach($data->list as $num_row => $row){
1679 foreach($data->columns as $column){
1680 $string_to_export .= $this->_trim_export_string($row->{$column->field_name})."\t";
1681 }
1682 $string_to_export .= "\n";
1683 }
1684
1685 // Convert to UTF-16LE and Prepend BOM
1686 $string_to_export = "\xFF\xFE" .mb_convert_encoding($string_to_export, 'UTF-16LE', 'UTF-8');
1687
1688 $filename = "export-".date("Y-m-d_H:i:s").".xls";
1689
1690 header('Content-type: application/vnd.ms-excel;charset=UTF-16LE');
1691 header('Content-Disposition: attachment; filename='.$filename);
1692 header("Cache-Control: no-cache");
1693 echo $string_to_export;
1694 die();
1695 }
1696
1697 protected function print_webpage($state_info = null)
1698 {
1699 $data = $this->get_common_data();
1700
1701 $data->order_by = $this->order_by;
1702 $data->types = $this->get_field_types();
1703
1704 $data->list = $this->get_list();
1705 $data->list = $this->change_list($data->list , $data->types);
1706 $data->list = $this->change_list_add_actions($data->list);
1707
1708 $data->total_results = $this->get_total_results();
1709
1710 $data->columns = $this->get_columns();
1711 $data->primary_key = $this->get_primary_key();
1712
1713 @ob_end_clean();
1714 $this->_print_webpage($data);
1715 }
1716
1717 protected function _print_webpage($data)
1718 {
1719 $string_to_print = "<meta charset=\"utf-8\" /><style type=\"text/css\" >
1720 #print-table{ color: #000; background: #fff; font-family: Verdana,Tahoma,Helvetica,sans-serif; font-size: 13px;}
1721 #print-table table tr td, #print-table table tr th{ border: 1px solid black; border-bottom: none; border-right: none; padding: 4px 8px 4px 4px}
1722 #print-table table{ border-bottom: 1px solid black; border-right: 1px solid black}
1723 #print-table table tr th{text-align: left;background: #ddd}
1724 #print-table table tr:nth-child(odd){background: #eee}
1725 </style>";
1726 $string_to_print .= "<div id='print-table'>";
1727
1728 $string_to_print .= '<table width="100%" cellpadding="0" cellspacing="0" ><tr>';
1729 foreach($data->columns as $column){
1730 $string_to_print .= "<th>".$column->display_as."</th>";
1731 }
1732 $string_to_print .= "</tr>";
1733
1734 foreach($data->list as $num_row => $row){
1735 $string_to_print .= "<tr>";
1736 foreach($data->columns as $column){
1737 $string_to_print .= "<td>".$this->_trim_print_string($row->{$column->field_name})."</td>";
1738 }
1739 $string_to_print .= "</tr>";
1740 }
1741
1742 $string_to_print .= "</table></div>";
1743
1744 echo $string_to_print;
1745 die();
1746 }
1747
1748 protected function _trim_export_string($value)
1749 {
1750 $value = str_replace(array(" ","&",">","<"),array(" ","&",">","<"),$value);
1751 return strip_tags(str_replace(array("\t","\n","\r"),"",$value));
1752 }
1753
1754 protected function _trim_print_string($value)
1755 {
1756 $value = str_replace(array(" ","&",">","<"),array(" ","&",">","<"),$value);
1757
1758 //If the value has only spaces and nothing more then add the whitespace html character
1759 if(str_replace(" ","",$value) == "")
1760 $value = " ";
1761
1762 return strip_tags($value);
1763 }
1764
1765 protected function set_echo_and_die()
1766 {
1767 $this->echo_and_die = true;
1768 }
1769
1770 protected function unset_echo_and_die()
1771 {
1772 $this->echo_and_die = false;
1773 }
1774
1775 protected function showListInfo()
1776 {
1777 $this->set_echo_and_die();
1778
1779 $total_results = (int)$this->get_total_results();
1780 @ob_end_clean();
1781 echo json_encode(array('total_results' => $total_results));
1782 die();
1783 }
1784
1785 protected function change_list_add_actions($list)
1786 {
1787 if(empty($this->actions))
1788 return $list;
1789
1790 $primary_key = $this->get_primary_key();
1791
1792 foreach($list as $num_row => $row)
1793 {
1794 $actions_urls = array();
1795 foreach($this->actions as $unique_id => $action)
1796 {
1797 if(!empty($action->url_callback))
1798 {
1799 $actions_urls[$unique_id] = call_user_func($action->url_callback, $row->$primary_key, $row);
1800 }
1801 else
1802 {
1803 $actions_urls[$unique_id] =
1804 $action->url_has_http ?
1805 $action->link_url.$row->$primary_key :
1806 site_url($action->link_url.'/'.$row->$primary_key);
1807 }
1808 }
1809 $row->action_urls = $actions_urls;
1810 }
1811
1812 return $list;
1813 }
1814
1815 protected function change_list($list,$types)
1816 {
1817 $primary_key = $this->get_primary_key();
1818 $has_callbacks = !empty($this->callback_column) ? true : false;
1819 $output_columns = $this->get_columns();
1820 foreach($list as $num_row => $row)
1821 {
1822 foreach($output_columns as $column)
1823 {
1824 $field_name = $column->field_name;
1825 $field_value = isset( $row->{$column->field_name} ) ? $row->{$column->field_name} : null;
1826 if( $has_callbacks && isset($this->callback_column[$field_name]) )
1827 $list[$num_row]->$field_name = call_user_func($this->callback_column[$field_name], $field_value, $row);
1828 elseif(isset($types[$field_name]))
1829 $list[$num_row]->$field_name = $this->change_list_value($types[$field_name] , $field_value);
1830 else
1831 $list[$num_row]->$field_name = $field_value;
1832 }
1833 }
1834
1835 return $list;
1836 }
1837
1838 protected function showAddForm()
1839 {
1840 $this->set_js_lib($this->default_javascript_path.'/'.grocery_CRUD::JQUERY);
1841
1842 $data = $this->get_common_data();
1843 $data->types = $this->get_field_types();
1844
1845 $data->list_url = $this->getListUrl();
1846 $data->insert_url = $this->getInsertUrl();
1847 $data->validation_url = $this->getValidationInsertUrl();
1848 $data->input_fields = $this->get_add_input_fields();
1849
1850 $data->fields = $this->get_add_fields();
1851 $data->hidden_fields = $this->get_add_hidden_fields();
1852 $data->unset_back_to_list = $this->unset_back_to_list;
1853 $data->unique_hash = $this->get_method_hash();
1854 $data->is_ajax = $this->_is_ajax();
1855
1856 $this->_theme_view('add.php',$data);
1857 $this->_inline_js("var js_date_format = '".$this->js_date_format."';");
1858
1859 $this->_get_ajax_results();
1860 }
1861
1862 protected function showEditForm($state_info)
1863 {
1864 $this->set_js_lib($this->default_javascript_path.'/'.grocery_CRUD::JQUERY);
1865
1866 $data = $this->get_common_data();
1867 $data->types = $this->get_field_types();
1868
1869 $data->field_values = $this->get_edit_values($state_info->primary_key);
1870
1871 $data->add_url = $this->getAddUrl();
1872
1873 $data->list_url = $this->getListUrl();
1874 $data->update_url = $this->getUpdateUrl($state_info);
1875 $data->delete_url = $this->getDeleteUrl($state_info);
1876 $data->read_url = $this->getReadUrl($state_info->primary_key);
1877 $data->input_fields = $this->get_edit_input_fields($data->field_values);
1878 $data->unique_hash = $this->get_method_hash();
1879
1880 $data->fields = $this->get_edit_fields();
1881 $data->hidden_fields = $this->get_edit_hidden_fields();
1882 $data->unset_back_to_list = $this->unset_back_to_list;
1883
1884 $data->validation_url = $this->getValidationUpdateUrl($state_info->primary_key);
1885 $data->is_ajax = $this->_is_ajax();
1886
1887 $this->_theme_view('edit.php',$data);
1888 $this->_inline_js("var js_date_format = '".$this->js_date_format."';");
1889
1890 $this->_get_ajax_results();
1891 }
1892
1893 protected function showReadForm($state_info)
1894 {
1895 $this->set_js_lib($this->default_javascript_path.'/'.grocery_CRUD::JQUERY);
1896
1897 $data = $this->get_common_data();
1898 $data->types = $this->get_field_types();
1899
1900 $data->field_values = $this->get_edit_values($state_info->primary_key);
1901
1902 $data->add_url = $this->getAddUrl();
1903
1904 $data->list_url = $this->getListUrl();
1905 $data->update_url = $this->getUpdateUrl($state_info);
1906 $data->delete_url = $this->getDeleteUrl($state_info);
1907 $data->read_url = $this->getReadUrl($state_info->primary_key);
1908 $data->input_fields = $this->get_read_input_fields($data->field_values);
1909 $data->unique_hash = $this->get_method_hash();
1910
1911 $data->fields = $this->get_read_fields();
1912 $data->hidden_fields = $this->get_edit_hidden_fields();
1913 $data->unset_back_to_list = $this->unset_back_to_list;
1914
1915 $data->validation_url = $this->getValidationUpdateUrl($state_info->primary_key);
1916 $data->is_ajax = $this->_is_ajax();
1917
1918 $this->_theme_view('read.php',$data);
1919 $this->_inline_js("var js_date_format = '".$this->js_date_format."';");
1920
1921 $this->_get_ajax_results();
1922 }
1923
1924 protected function delete_layout($delete_result = true)
1925 {
1926 @ob_end_clean();
1927 if($delete_result === false)
1928 {
1929 $error_message = '<p>'.$this->l('delete_error_message').'</p>';
1930
1931 echo json_encode(array('success' => $delete_result ,'error_message' => $error_message));
1932 }
1933 else
1934 {
1935 $success_message = '<p>'.$this->l('delete_success_message').'</p>';
1936
1937 echo json_encode(array('success' => true , 'success_message' => $success_message));
1938 }
1939 $this->set_echo_and_die();
1940 }
1941
1942 protected function get_success_message_at_list($field_info = null)
1943 {
1944 if($field_info !== null && isset($field_info->success_message) && $field_info->success_message)
1945 {
1946 if(!empty($field_info->primary_key) && !$this->unset_edit)
1947 {
1948 return $this->l('insert_success_message')." <a class='go-to-edit-form' href='".$this->getEditUrl($field_info->primary_key)."'>".$this->l('form_edit')." {$this->subject}</a> ";
1949 }
1950 else
1951 {
1952 return $this->l('insert_success_message');
1953 }
1954 }
1955 else
1956 {
1957 return null;
1958 }
1959 }
1960
1961 protected function insert_layout($insert_result = false)
1962 {
1963 @ob_end_clean();
1964 if($insert_result === false)
1965 {
1966 echo json_encode(array('success' => false));
1967 }
1968 else
1969 {
1970 $success_message = '<p>'.$this->l('insert_success_message');
1971
1972 if(!$this->unset_back_to_list && !empty($insert_result) && !$this->unset_edit)
1973 {
1974 $success_message .= " <a class='go-to-edit-form' href='".$this->getEditUrl($insert_result)."'>".$this->l('form_edit')." {$this->subject}</a> ";
1975
1976 if (!$this->_is_ajax()) {
1977 $success_message .= $this->l('form_or');
1978 }
1979 }
1980
1981 if(!$this->unset_back_to_list && !$this->_is_ajax())
1982 {
1983 $success_message .= " <a href='".$this->getListUrl()."'>".$this->l('form_go_back_to_list')."</a>";
1984 }
1985
1986 $success_message .= '</p>';
1987
1988 echo json_encode(array(
1989 'success' => true ,
1990 'insert_primary_key' => $insert_result,
1991 'success_message' => $success_message,
1992 'success_list_url' => $this->getListSuccessUrl($insert_result)
1993 ));
1994 }
1995 $this->set_echo_and_die();
1996 }
1997
1998 protected function validation_layout($validation_result)
1999 {
2000 @ob_end_clean();
2001 echo json_encode($validation_result);
2002 $this->set_echo_and_die();
2003 }
2004
2005 protected function upload_layout($upload_result, $field_name)
2006 {
2007 @ob_end_clean();
2008 if($upload_result !== false && !is_string($upload_result) && empty($upload_result[0]->error))
2009 {
2010 echo json_encode(
2011 (object)array(
2012 'success' => true,
2013 'files' => $upload_result
2014 ));
2015 }
2016 else
2017 {
2018 $result = (object)array('success' => false);
2019 if(is_string($upload_result))
2020 $result->message = $upload_result;
2021 if(!empty($upload_result[0]->error))
2022 $result->message = $upload_result[0]->error;
2023
2024 echo json_encode($result);
2025 }
2026
2027 $this->set_echo_and_die();
2028 }
2029
2030 protected function delete_file_layout($upload_result)
2031 {
2032 @ob_end_clean();
2033 if($upload_result !== false)
2034 {
2035 echo json_encode( (object)array( 'success' => true ) );
2036 }
2037 else
2038 {
2039 echo json_encode((object)array('success' => false));
2040 }
2041
2042 $this->set_echo_and_die();
2043 }
2044
2045 public function set_css($css_file)
2046 {
2047 $this->css_files[sha1($css_file)] = base_url().$css_file;
2048 }
2049
2050 public function set_js($js_file)
2051 {
2052 $this->js_files[sha1($js_file)] = base_url().$js_file;
2053 }
2054
2055 public function set_js_lib($js_file)
2056 {
2057 $this->js_lib_files[sha1($js_file)] = base_url().$js_file;
2058 $this->js_files[sha1($js_file)] = base_url().$js_file;
2059 }
2060
2061 public function set_js_config($js_file)
2062 {
2063 $this->js_config_files[sha1($js_file)] = base_url().$js_file;
2064 $this->js_files[sha1($js_file)] = base_url().$js_file;
2065 }
2066
2067 public function is_IE7()
2068 {
2069 return isset($_SERVER['HTTP_USER_AGENT'])
2070 && (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE 7') !== false)
2071 ? true : false;
2072 }
2073
2074 public function get_css_files()
2075 {
2076 return $this->css_files;
2077 }
2078
2079 public function get_js_files()
2080 {
2081 return $this->js_files;
2082 }
2083
2084 public function get_js_lib_files()
2085 {
2086 return $this->js_lib_files;
2087 }
2088
2089 public function get_js_config_files()
2090 {
2091 return $this->js_config_files;
2092 }
2093
2094 /**
2095 * Load Javascripts
2096 **/
2097 protected function load_js_fancybox()
2098 {
2099 $this->set_css($this->default_css_path.'/jquery_plugins/fancybox/jquery.fancybox.css');
2100
2101 $this->set_js_lib($this->default_javascript_path.'/jquery_plugins/jquery.fancybox-1.3.4.js');
2102 $this->set_js_lib($this->default_javascript_path.'/jquery_plugins/jquery.easing-1.3.pack.js');
2103 }
2104
2105 protected function load_js_chosen()
2106 {
2107 $this->set_css($this->default_css_path.'/jquery_plugins/chosen/chosen.css');
2108 $this->set_js_lib($this->default_javascript_path.'/jquery_plugins/jquery.chosen.min.js');
2109 }
2110
2111 protected function load_js_jqueryui()
2112 {
2113 $this->set_css($this->default_css_path.'/ui/simple/'.grocery_CRUD::JQUERY_UI_CSS);
2114 $this->set_js_lib($this->default_javascript_path.'/jquery_plugins/ui/'.grocery_CRUD::JQUERY_UI_JS);
2115 }
2116
2117 protected function load_js_uploader()
2118 {
2119 $this->set_css($this->default_css_path.'/ui/simple/'.grocery_CRUD::JQUERY_UI_CSS);
2120 $this->set_css($this->default_css_path.'/jquery_plugins/file_upload/file-uploader.css');
2121 $this->set_css($this->default_css_path.'/jquery_plugins/file_upload/jquery.fileupload-ui.css');
2122
2123 $this->set_js_lib($this->default_javascript_path.'/jquery_plugins/ui/'.grocery_CRUD::JQUERY_UI_JS);
2124 $this->set_js_lib($this->default_javascript_path.'/jquery_plugins/tmpl.min.js');
2125 $this->set_js_lib($this->default_javascript_path.'/jquery_plugins/load-image.min.js');
2126
2127 $this->set_js_lib($this->default_javascript_path.'/jquery_plugins/jquery.iframe-transport.js');
2128 $this->set_js_lib($this->default_javascript_path.'/jquery_plugins/jquery.fileupload.js');
2129 $this->set_js_config($this->default_javascript_path.'/jquery_plugins/config/jquery.fileupload.config.js');
2130 }
2131
2132 protected function get_layout()
2133 {
2134 $js_files = $this->get_js_files();
2135 $css_files = $this->get_css_files();
2136
2137 $js_lib_files = $this->get_js_lib_files();
2138 $js_config_files = $this->get_js_config_files();
2139
2140 if ($this->unset_jquery) {
2141 unset($js_files[sha1($this->default_javascript_path.'/'.grocery_CRUD::JQUERY)]);
2142 }
2143
2144 if ($this->unset_jquery_ui) {
2145 unset($css_files[sha1($this->default_css_path.'/ui/simple/'.grocery_CRUD::JQUERY_UI_CSS)]);
2146 unset($js_files[sha1($this->default_javascript_path.'/jquery_plugins/ui/'.grocery_CRUD::JQUERY_UI_JS)]);
2147 }
2148
2149 if ($this->unset_bootstrap) {
2150 unset($js_files[sha1($this->default_theme_path.'/bootstrap/js/bootstrap/dropdown.js')]);
2151 unset($js_files[sha1($this->default_theme_path.'/bootstrap/js/bootstrap/modal.js')]);
2152 unset($js_files[sha1($this->default_theme_path.'/bootstrap/js/bootstrap/dropdown.min.js')]);
2153 unset($js_files[sha1($this->default_theme_path.'/bootstrap/js/bootstrap/modal.min.js')]);
2154 unset($css_files[sha1($this->default_theme_path.'/bootstrap/css/bootstrap/bootstrap.css')]);
2155 unset($css_files[sha1($this->default_theme_path.'/bootstrap/css/bootstrap/bootstrap.min.css')]);
2156 unset($css_files[sha1($this->default_theme_path.'/bootstrap-v4/css/bootstrap/bootstrap.css')]);
2157 unset($css_files[sha1($this->default_theme_path.'/bootstrap-v4/css/bootstrap/bootstrap.min.css')]);
2158 }
2159
2160 if($this->echo_and_die === false)
2161 {
2162 /** Initialize JavaScript variables */
2163 $js_vars = array(
2164 'default_javascript_path' => base_url().$this->default_javascript_path,
2165 'default_css_path' => base_url().$this->default_css_path,
2166 'default_texteditor_path' => base_url().$this->default_texteditor_path,
2167 'default_theme_path' => base_url().$this->default_theme_path,
2168 'base_url' => base_url()
2169 );
2170 $this->_add_js_vars($js_vars);
2171
2172 return (object)array(
2173 'js_files' => $js_files,
2174 'js_lib_files' => $js_lib_files,
2175 'js_config_files' => $js_config_files,
2176 'css_files' => $css_files,
2177 'output' => $this->views_as_string,
2178 );
2179 }
2180 elseif($this->echo_and_die === true)
2181 {
2182 echo $this->views_as_string;
2183 die();
2184 }
2185 }
2186
2187 protected function update_layout($update_result = false, $state_info = null)
2188 {
2189 @ob_end_clean();
2190 if($update_result === false)
2191 {
2192 echo json_encode(array('success' => $update_result));
2193 }
2194 else
2195 {
2196 $success_message = '<p>'.$this->l('update_success_message');
2197 if(!$this->unset_back_to_list && !$this->_is_ajax())
2198 {
2199 $success_message .= " <a href='".$this->getListUrl()."'>".$this->l('form_go_back_to_list')."</a>";
2200 }
2201 $success_message .= '</p>';
2202
2203 echo json_encode(array(
2204 'success' => true ,
2205 'insert_primary_key' => $update_result,
2206 'success_message' => $success_message,
2207 'success_list_url' => $this->getListSuccessUrl($state_info->primary_key)
2208 ));
2209 }
2210 $this->set_echo_and_die();
2211 }
2212
2213 protected function get_integer_input($field_info,$value)
2214 {
2215 $this->set_js_lib($this->default_javascript_path.'/jquery_plugins/jquery.numeric.min.js');
2216 $this->set_js_config($this->default_javascript_path.'/jquery_plugins/config/jquery.numeric.config.js');
2217 $extra_attributes = '';
2218 if(!empty($field_info->db_max_length))
2219 $extra_attributes .= "maxlength='{$field_info->db_max_length}'";
2220 $input = "<input id='field-{$field_info->name}' name='{$field_info->name}' type='text' value='$value' class='numeric form-control' $extra_attributes />";
2221 return $input;
2222 }
2223
2224 protected function get_true_false_input($field_info,$value)
2225 {
2226 $value_is_null = empty($value) && $value !== '0' && $value !== 0 ? true : false;
2227
2228 $input = "<div class='pretty-radio-buttons'>";
2229
2230 $true_string = is_array($field_info->extras) && array_key_exists(1,$field_info->extras) ? $field_info->extras[1] : $this->default_true_false_text[1];
2231 $checked = $value === '1' || ($value_is_null && $field_info->default === '1') ? "checked = 'checked'" : "";
2232 $input .=
2233 "<div class=\"radio\"><label>
2234 <input id='field-{$field_info->name}-true' type=\"radio\" name=\"{$field_info->name}\" value=\"1\" $checked />
2235 $true_string
2236 </label> </div>";
2237
2238 $false_string = is_array($field_info->extras) && array_key_exists(0,$field_info->extras) ? $field_info->extras[0] : $this->default_true_false_text[0];
2239 $checked = $value === '0' || ($value_is_null && $field_info->default === '0') ? "checked = 'checked'" : "";
2240 $input .=
2241 "<div class=\"radio\"><label>
2242 <input id='field-{$field_info->name}-false' type=\"radio\" name=\"{$field_info->name}\" value=\"0\" $checked />
2243 $false_string
2244 </label> </div>";
2245
2246 $input .= "</div>";
2247
2248 return $input;
2249 }
2250
2251 protected function get_string_input($field_info,$value)
2252 {
2253 $value = !is_string($value) ? '' : str_replace('"',""",$value);
2254
2255 $extra_attributes = '';
2256 if (!empty($field_info->db_max_length)) {
2257
2258 if (in_array($field_info->type, array("decimal", "float"))) {
2259 $decimal_lentgh = explode(",", $field_info->db_max_length);
2260 $decimal_lentgh = ((int)$decimal_lentgh[0]) + 1;
2261
2262 $extra_attributes .= "maxlength='" . $decimal_lentgh . "'";
2263 } else {
2264 $extra_attributes .= "maxlength='{$field_info->db_max_length}'";
2265 }
2266
2267 }
2268 $input = "<input id='field-{$field_info->name}' class='form-control' name='{$field_info->name}' type='text' value=\"$value\" $extra_attributes />";
2269 return $input;
2270 }
2271
2272 protected function get_text_input($field_info,$value)
2273 {
2274 if($field_info->extras == 'text_editor')
2275 {
2276 $editor = $this->config->default_text_editor;
2277 switch ($editor) {
2278 case 'ckeditor':
2279 $this->set_js_lib($this->default_texteditor_path.'/ckeditor/ckeditor.js');
2280 $this->set_js_lib($this->default_texteditor_path.'/ckeditor/adapters/jquery.js');
2281 $this->set_js_config($this->default_javascript_path.'/jquery_plugins/config/jquery.ckeditor.config.js');
2282 break;
2283
2284 case 'tinymce':
2285 $this->set_js_lib($this->default_texteditor_path.'/tiny_mce/jquery.tinymce.js');
2286 $this->set_js_config($this->default_javascript_path.'/jquery_plugins/config/jquery.tine_mce.config.js');
2287 break;
2288
2289 case 'markitup':
2290 $this->set_css($this->default_texteditor_path.'/markitup/skins/markitup/style.css');
2291 $this->set_css($this->default_texteditor_path.'/markitup/sets/default/style.css');
2292
2293 $this->set_js_lib($this->default_texteditor_path.'/markitup/jquery.markitup.js');
2294 $this->set_js_config($this->default_javascript_path.'/jquery_plugins/config/jquery.markitup.config.js');
2295 break;
2296 }
2297
2298 $class_name = $this->config->text_editor_type == 'minimal' ? 'mini-texteditor' : 'texteditor';
2299
2300 $input = "<textarea id='field-{$field_info->name}' name='{$field_info->name}' class='$class_name' >$value</textarea>";
2301 }
2302 else
2303 {
2304 $input = "<textarea id='field-{$field_info->name}' name='{$field_info->name}'>$value</textarea>";
2305 }
2306 return $input;
2307 }
2308
2309 protected function get_datetime_input($field_info,$value)
2310 {
2311 $this->set_css($this->default_css_path.'/ui/simple/'.grocery_CRUD::JQUERY_UI_CSS);
2312 $this->set_css($this->default_css_path.'/jquery_plugins/jquery.ui.datetime.css');
2313 $this->set_css($this->default_css_path.'/jquery_plugins/jquery-ui-timepicker-addon.css');
2314 $this->set_js_lib($this->default_javascript_path.'/jquery_plugins/ui/'.grocery_CRUD::JQUERY_UI_JS);
2315 $this->set_js_lib($this->default_javascript_path.'/jquery_plugins/jquery-ui-timepicker-addon.js');
2316
2317 if($this->language !== 'english')
2318 {
2319 include($this->default_config_path.'/language_alias.php');
2320 if(array_key_exists($this->language, $language_alias))
2321 {
2322 $i18n_date_js_file = $this->default_javascript_path.'/jquery_plugins/ui/i18n/datepicker/jquery.ui.datepicker-'.$language_alias[$this->language].'.js';
2323 if(file_exists($i18n_date_js_file))
2324 {
2325 $this->set_js_lib($i18n_date_js_file);
2326 }
2327
2328 $i18n_datetime_js_file = $this->default_javascript_path.'/jquery_plugins/ui/i18n/timepicker/jquery-ui-timepicker-'.$language_alias[$this->language].'.js';
2329 if(file_exists($i18n_datetime_js_file))
2330 {
2331 $this->set_js_lib($i18n_datetime_js_file);
2332 }
2333 }
2334 }
2335
2336 $this->set_js_config($this->default_javascript_path.'/jquery_plugins/config/jquery-ui-timepicker-addon.config.js');
2337
2338 if(!empty($value) && $value != '0000-00-00 00:00:00' && $value != '1970-01-01 00:00:00'){
2339 list($year,$month,$day) = explode('-',substr($value,0,10));
2340 $date = date($this->php_date_format, mktime(0,0,0,$month,$day,$year));
2341 $datetime = $date.substr($value,10);
2342 }
2343 else
2344 {
2345 $datetime = '';
2346 }
2347 $input = "<input id='field-{$field_info->name}' name='{$field_info->name}' type='text' value='$datetime' maxlength='19' class='datetime-input form-control' />
2348 <a class='datetime-input-clear' tabindex='-1'>".$this->l('form_button_clear')."</a>
2349 ({$this->ui_date_format}) hh:mm:ss";
2350 return $input;
2351 }
2352
2353 protected function get_hidden_input($field_info,$value)
2354 {
2355 if($field_info->extras !== null && $field_info->extras != false)
2356 $value = $field_info->extras;
2357 $input = "<input id='field-{$field_info->name}' type='hidden' name='{$field_info->name}' value='$value' />";
2358 return $input;
2359 }
2360
2361 protected function get_password_input($field_info,$value)
2362 {
2363 $value = !is_string($value) ? '' : $value;
2364
2365 $extra_attributes = '';
2366 if(!empty($field_info->db_max_length))
2367 $extra_attributes .= "maxlength='{$field_info->db_max_length}'";
2368 $input = "<input id='field-{$field_info->name}' class='form-control' name='{$field_info->name}' type='password' value='$value' $extra_attributes />";
2369 return $input;
2370 }
2371
2372 protected function get_date_input($field_info,$value)
2373 {
2374 $this->set_css($this->default_css_path.'/ui/simple/'.grocery_CRUD::JQUERY_UI_CSS);
2375 $this->set_js_lib($this->default_javascript_path.'/jquery_plugins/ui/'.grocery_CRUD::JQUERY_UI_JS);
2376
2377 if($this->language !== 'english')
2378 {
2379 include($this->default_config_path.'/language_alias.php');
2380 if(array_key_exists($this->language, $language_alias))
2381 {
2382 $i18n_date_js_file = $this->default_javascript_path.'/jquery_plugins/ui/i18n/datepicker/jquery.ui.datepicker-'.$language_alias[$this->language].'.js';
2383 if(file_exists($i18n_date_js_file))
2384 {
2385 $this->set_js_lib($i18n_date_js_file);
2386 }
2387 }
2388 }
2389
2390 $this->set_js_config($this->default_javascript_path.'/jquery_plugins/config/jquery.datepicker.config.js');
2391
2392 if(!empty($value) && $value != '0000-00-00' && $value != '1970-01-01')
2393 {
2394 list($year,$month,$day) = explode('-',substr($value,0,10));
2395 $date = date($this->php_date_format, mktime(0,0,0,$month,$day,$year));
2396 }
2397 else
2398 {
2399 $date = '';
2400 }
2401
2402 $input = "<input id='field-{$field_info->name}' name='{$field_info->name}' type='text' value='$date' maxlength='10' class='datepicker-input form-control' />
2403 <a class='datepicker-input-clear' tabindex='-1'>".$this->l('form_button_clear')."</a> (".$this->ui_date_format.")";
2404 return $input;
2405 }
2406
2407 protected function get_dropdown_input($field_info,$value)
2408 {
2409 $this->load_js_chosen();
2410 $this->set_js_config($this->default_javascript_path.'/jquery_plugins/config/jquery.chosen.config.js');
2411
2412 $select_title = str_replace('{field_display_as}',$field_info->display_as,$this->l('set_relation_title'));
2413
2414 $input = "<select id='field-{$field_info->name}' name='{$field_info->name}' class='chosen-select' data-placeholder='".$select_title."'>";
2415 $options = array('' => '') + $field_info->extras;
2416 foreach($options as $option_value => $option_label)
2417 {
2418 $selected = !empty($value) && $value == $option_value ? "selected='selected'" : '';
2419 $input .= "<option value='$option_value' $selected >$option_label</option>";
2420 }
2421
2422 $input .= "</select>";
2423 return $input;
2424 }
2425
2426 protected function get_enum_input($field_info,$value)
2427 {
2428 $this->load_js_chosen();
2429 $this->set_js_config($this->default_javascript_path.'/jquery_plugins/config/jquery.chosen.config.js');
2430
2431 $select_title = str_replace('{field_display_as}',$field_info->display_as,$this->l('set_relation_title'));
2432
2433 $input = "<select id='field-{$field_info->name}' name='{$field_info->name}' class='chosen-select' data-placeholder='".$select_title."'>";
2434 $options_array = $field_info->extras !== false && is_array($field_info->extras)? $field_info->extras : explode("','",substr($field_info->db_max_length,1,-1));
2435 $options_array = array('' => '') + $options_array;
2436
2437 foreach($options_array as $option)
2438 {
2439 $selected = !empty($value) && $value == $option ? "selected='selected'" : '';
2440 $input .= "<option value='$option' $selected >$option</option>";
2441 }
2442
2443 $input .= "</select>";
2444 return $input;
2445 }
2446
2447 protected function get_readonly_input($field_info, $value)
2448 {
2449 $read_only_value = " ";
2450
2451 if (!empty($value) && !is_array($value)) {
2452 $read_only_value = $value;
2453 } elseif (is_array($value)) {
2454 $all_values = array_values($value);
2455 $read_only_value = implode(", ",$all_values);
2456 }
2457
2458 return '<div id="field-'.$field_info->name.'" class="readonly_label">'.$read_only_value.'</div>';
2459 }
2460
2461 protected function get_set_input($field_info,$value)
2462 {
2463 $this->load_js_chosen();
2464 $this->set_js_config($this->default_javascript_path.'/jquery_plugins/config/jquery.chosen.config.js');
2465
2466 $options_array = $field_info->extras !== false && is_array($field_info->extras)? $field_info->extras : explode("','",substr($field_info->db_max_length,1,-1));
2467 $selected_values = !empty($value) ? explode(",",$value) : array();
2468
2469 $select_title = str_replace('{field_display_as}',$field_info->display_as,$this->l('set_relation_title'));
2470 $input = "<select id='field-{$field_info->name}' name='{$field_info->name}[]' multiple='multiple' size='8' class='chosen-multiple-select' data-placeholder='$select_title' style='width:510px;' >";
2471
2472 foreach($options_array as $option)
2473 {
2474 $selected = !empty($value) && in_array($option,$selected_values) ? "selected='selected'" : '';
2475 $input .= "<option value='$option' $selected >$option</option>";
2476 }
2477
2478 $input .= "</select>";
2479
2480 return $input;
2481 }
2482
2483 protected function get_multiselect_input($field_info,$value)
2484 {
2485 $this->load_js_chosen();
2486 $this->set_js_config($this->default_javascript_path.'/jquery_plugins/config/jquery.chosen.config.js');
2487
2488 $options_array = $field_info->extras;
2489 $selected_values = !empty($value) ? explode(",",$value) : array();
2490
2491 $select_title = str_replace('{field_display_as}',$field_info->display_as,$this->l('set_relation_title'));
2492 $input = "<select id='field-{$field_info->name}' name='{$field_info->name}[]' multiple='multiple' size='8' class='chosen-multiple-select' data-placeholder='$select_title' style='width:510px;' >";
2493
2494 foreach($options_array as $option_value => $option_label)
2495 {
2496 $selected = !empty($value) && in_array($option_value,$selected_values) ? "selected='selected'" : '';
2497 $input .= "<option value='$option_value' $selected >$option_label</option>";
2498 }
2499
2500 $input .= "</select>";
2501
2502 return $input;
2503 }
2504
2505 protected function get_relation_input($field_info,$value)
2506 {
2507 $this->load_js_chosen();
2508 $this->set_js_config($this->default_javascript_path.'/jquery_plugins/config/jquery.chosen.config.js');
2509
2510 $ajax_limitation = 10000;
2511 $total_rows = $this->get_relation_total_rows($field_info->extras);
2512
2513
2514 //Check if we will use ajax for our queries or just clien-side javascript
2515 $using_ajax = $total_rows > $ajax_limitation ? true : false;
2516
2517 //We will not use it for now. It is not ready yet. Probably we will have this functionality at version 1.4
2518 $using_ajax = false;
2519
2520 //If total rows are more than the limitation, use the ajax plugin
2521 $ajax_or_not_class = $using_ajax ? 'chosen-select' : 'chosen-select';
2522
2523 $this->_inline_js("var ajax_relation_url = '".$this->getAjaxRelationUrl()."';\n");
2524
2525 $select_title = str_replace('{field_display_as}',$field_info->display_as,$this->l('set_relation_title'));
2526 $input = "<select id='field-{$field_info->name}' name='{$field_info->name}' class='$ajax_or_not_class' data-placeholder='$select_title' style='width:300px'>";
2527 $input .= "<option value=''></option>";
2528
2529 if(!$using_ajax)
2530 {
2531 $options_array = $this->get_relation_array($field_info->extras);
2532 foreach($options_array as $option_value => $option)
2533 {
2534 $selected = !empty($value) && $value == $option_value ? "selected='selected'" : '';
2535 $input .= "<option value='$option_value' $selected >$option</option>";
2536 }
2537 }
2538 elseif(!empty($value) || (is_numeric($value) && $value == '0') ) //If it's ajax then we only need the selected items and not all the items
2539 {
2540 $selected_options_array = $this->get_relation_array($field_info->extras, $value);
2541 foreach($selected_options_array as $option_value => $option)
2542 {
2543 $input .= "<option value='$option_value'selected='selected' >$option</option>";
2544 }
2545 }
2546
2547 $input .= "</select>";
2548 return $input;
2549 }
2550
2551 protected function get_relation_readonly_input($field_info,$value)
2552 {
2553 $options_array = $this->get_relation_array($field_info->extras);
2554
2555 $value = isset($options_array[$value]) ? $options_array[$value] : '';
2556
2557 return $this->get_readonly_input($field_info, $value);
2558 }
2559
2560 protected function get_upload_file_readonly_input($field_info,$value)
2561 {
2562 $file = $file_url = base_url().$field_info->extras->upload_path.'/'.$value;
2563
2564 $value = !empty($value) ? '<a href="'.$file.'" target="_blank">'.$value.'</a>' : '';
2565
2566 return $this->get_readonly_input($field_info, $value);
2567 }
2568
2569 protected function get_relation_n_n_input($field_info_type, $selected_values)
2570 {
2571 $has_priority_field = !empty($field_info_type->extras->priority_field_relation_table) ? true : false;
2572 $is_ie_7 = isset($_SERVER['HTTP_USER_AGENT']) && (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE 7') !== false) ? true : false;
2573
2574 if($has_priority_field || $is_ie_7)
2575 {
2576 $this->set_css($this->default_css_path.'/ui/simple/'.grocery_CRUD::JQUERY_UI_CSS);
2577 $this->set_css($this->default_css_path.'/jquery_plugins/ui.multiselect.css');
2578 $this->set_js_lib($this->default_javascript_path.'/jquery_plugins/ui/'.grocery_CRUD::JQUERY_UI_JS);
2579 $this->set_js_lib($this->default_javascript_path.'/jquery_plugins/ui.multiselect.min.js');
2580 $this->set_js_config($this->default_javascript_path.'/jquery_plugins/config/jquery.multiselect.js');
2581
2582 if($this->language !== 'english')
2583 {
2584 include($this->default_config_path.'/language_alias.php');
2585 if(array_key_exists($this->language, $language_alias))
2586 {
2587 $i18n_date_js_file = $this->default_javascript_path.'/jquery_plugins/ui/i18n/multiselect/ui-multiselect-'.$language_alias[$this->language].'.js';
2588 if(file_exists($i18n_date_js_file))
2589 {
2590 $this->set_js_lib($i18n_date_js_file);
2591 }
2592 }
2593 }
2594 }
2595 else
2596 {
2597 $this->set_css($this->default_css_path.'/jquery_plugins/chosen/chosen.css');
2598 $this->set_js_lib($this->default_javascript_path.'/jquery_plugins/jquery.chosen.min.js');
2599 $this->set_js_config($this->default_javascript_path.'/jquery_plugins/config/jquery.chosen.config.js');
2600 }
2601
2602 $this->_inline_js("var ajax_relation_url = '".$this->getAjaxRelationUrl()."';\n");
2603
2604 $field_info = $this->relation_n_n[$field_info_type->name]; //As we use this function the relation_n_n exists, so don't need to check
2605 $unselected_values = $this->get_relation_n_n_unselected_array($field_info, $selected_values);
2606
2607 if(empty($unselected_values) && empty($selected_values))
2608 {
2609 $input = "Please add {$field_info_type->display_as} first";
2610 }
2611 else
2612 {
2613 $css_class = $has_priority_field || $is_ie_7 ? 'multiselect': 'chosen-multiple-select';
2614 $width_style = $has_priority_field || $is_ie_7 ? '' : 'width:510px;';
2615
2616 $select_title = str_replace('{field_display_as}',$field_info_type->display_as,$this->l('set_relation_title'));
2617 $input = "<select id='field-{$field_info_type->name}' name='{$field_info_type->name}[]' multiple='multiple' size='8' class='$css_class' data-placeholder='$select_title' style='$width_style' >";
2618
2619 if(!empty($unselected_values))
2620 foreach($unselected_values as $id => $name)
2621 {
2622 $input .= "<option value='$id'>$name</option>";
2623 }
2624
2625 if(!empty($selected_values))
2626 foreach($selected_values as $id => $name)
2627 {
2628 $input .= "<option value='$id' selected='selected'>$name</option>";
2629 }
2630
2631 $input .= "</select>";
2632 }
2633
2634 return $input;
2635 }
2636
2637 protected function _convert_bytes_ui_to_bytes($bytes_ui)
2638 {
2639 $bytes_ui = str_replace(' ','',$bytes_ui);
2640 if(strstr($bytes_ui,'MB'))
2641 $bytes = (int)(str_replace('MB','',$bytes_ui))*1024*1024;
2642 elseif(strstr($bytes_ui,'KB'))
2643 $bytes = (int)(str_replace('KB','',$bytes_ui))*1024;
2644 elseif(strstr($bytes_ui,'B'))
2645 $bytes = (int)(str_replace('B','',$bytes_ui));
2646 else
2647 $bytes = (int)($bytes_ui);
2648
2649 return $bytes;
2650 }
2651
2652 protected function get_upload_file_input($field_info, $value)
2653 {
2654 $this->load_js_uploader();
2655
2656 //Fancybox
2657 $this->load_js_fancybox();
2658
2659 $this->set_js_config($this->default_javascript_path.'/jquery_plugins/config/jquery.fancybox.config.js');
2660
2661 $unique = mt_rand();
2662
2663 $allowed_files = $this->config->file_upload_allow_file_types;
2664 $allowed_files_ui = '.'.str_replace('|',',.',$allowed_files);
2665 $max_file_size_ui = $this->config->file_upload_max_file_size;
2666 $max_file_size_bytes = $this->_convert_bytes_ui_to_bytes($max_file_size_ui);
2667
2668 $this->_inline_js('
2669 var upload_info_'.$unique.' = {
2670 accepted_file_types: /(\\.|\\/)('.$allowed_files.')$/i,
2671 accepted_file_types_ui : "'.$allowed_files_ui.'",
2672 max_file_size: '.$max_file_size_bytes.',
2673 max_file_size_ui: "'.$max_file_size_ui.'"
2674 };
2675
2676 var string_upload_file = "'.$this->l('form_upload_a_file').'";
2677 var string_delete_file = "'.$this->l('string_delete_file').'";
2678 var string_progress = "'.$this->l('string_progress').'";
2679 var error_on_uploading = "'.$this->l('error_on_uploading').'";
2680 var message_prompt_delete_file = "'.$this->l('message_prompt_delete_file').'";
2681
2682 var error_max_number_of_files = "'.$this->l('error_max_number_of_files').'";
2683 var error_accept_file_types = "'.$this->l('error_accept_file_types').'";
2684 var error_max_file_size = "'.str_replace("{max_file_size}",$max_file_size_ui,$this->l('error_max_file_size')).'";
2685 var error_min_file_size = "'.$this->l('error_min_file_size').'";
2686
2687 var base_url = "'.base_url().'";
2688 var upload_a_file_string = "'.$this->l('form_upload_a_file').'";
2689 ');
2690
2691 $uploader_display_none = empty($value) ? "" : "display:none;";
2692 $file_display_none = empty($value) ? "display:none;" : "";
2693
2694 $is_image = !empty($value) &&
2695 ( substr($value,-4) == '.jpg'
2696 || substr($value,-4) == '.png'
2697 || substr($value,-5) == '.jpeg'
2698 || substr($value,-4) == '.gif'
2699 || substr($value,-5) == '.tiff')
2700 ? true : false;
2701
2702 $image_class = $is_image ? 'image-thumbnail' : '';
2703
2704 $input = '<span class="fileinput-button qq-upload-button" id="upload-button-'.$unique.'" style="'.$uploader_display_none.'">
2705 <span>'.$this->l('form_upload_a_file').'</span>
2706 <input type="file" name="'.$this->_unique_field_name($field_info->name).'" class="gc-file-upload" rel="'.$this->getUploadUrl($field_info->name).'" id="'.$unique.'">
2707 <input class="hidden-upload-input" type="hidden" name="'.$field_info->name.'" value="'.$value.'" rel="'.$this->_unique_field_name($field_info->name).'" />
2708 </span>';
2709
2710 $this->set_css($this->default_css_path.'/jquery_plugins/file_upload/fileuploader.css');
2711
2712 $file_url = base_url().$field_info->extras->upload_path.'/'.$value;
2713
2714 $input .= "<div id='uploader_$unique' rel='$unique' class='grocery-crud-uploader' style='$uploader_display_none'></div>";
2715 $input .= "<div id='success_$unique' class='upload-success-url' style='$file_display_none padding-top:7px;'>";
2716 $input .= "<a href='".$file_url."' id='file_$unique' class='open-file";
2717 $input .= $is_image ? " $image_class'><img src='".$file_url."' height='50px'>" : "' target='_blank'>$value";
2718 $input .= "</a> ";
2719 $input .= "<a href='javascript:void(0)' id='delete_$unique' class='delete-anchor'>".$this->l('form_upload_delete')."</a> ";
2720 $input .= "</div><div style='clear:both'></div>";
2721 $input .= "<div id='loading-$unique' style='display:none'><span id='upload-state-message-$unique'></span> <span class='qq-upload-spinner'></span> <span id='progress-$unique'></span></div>";
2722 $input .= "<div style='display:none'><a href='".$this->getUploadUrl($field_info->name)."' id='url_$unique'></a></div>";
2723 $input .= "<div style='display:none'><a href='".$this->getFileDeleteUrl($field_info->name)."' id='delete_url_$unique' rel='$value' ></a></div>";
2724
2725 return $input;
2726 }
2727
2728 protected function get_add_hidden_fields()
2729 {
2730 return $this->add_hidden_fields;
2731 }
2732
2733 protected function get_edit_hidden_fields()
2734 {
2735 return $this->edit_hidden_fields;
2736 }
2737
2738 protected function get_add_input_fields($field_values = null)
2739 {
2740 $fields = $this->get_add_fields();
2741 $types = $this->get_field_types();
2742
2743 $input_fields = array();
2744
2745 foreach($fields as $field_num => $field)
2746 {
2747 $field_info = $types[$field->field_name];
2748
2749 $field_value = !empty($field_values) && isset($field_values->{$field->field_name}) ? $field_values->{$field->field_name} : null;
2750
2751 if(!isset($this->callback_add_field[$field->field_name]))
2752 {
2753 $field_input = $this->get_field_input($field_info, $field_value);
2754 }
2755 else
2756 {
2757 $field_input = $field_info;
2758 $field_input->input = call_user_func($this->callback_add_field[$field->field_name], $field_value, null, $field_info);
2759 }
2760
2761 switch ($field_info->crud_type) {
2762 case 'invisible':
2763 unset($this->add_fields[$field_num]);
2764 unset($fields[$field_num]);
2765 continue;
2766 break;
2767 case 'hidden':
2768 $this->add_hidden_fields[] = $field_input;
2769 unset($this->add_fields[$field_num]);
2770 unset($fields[$field_num]);
2771 continue;
2772 break;
2773 }
2774
2775 $input_fields[$field->field_name] = $field_input;
2776 }
2777
2778 return $input_fields;
2779 }
2780
2781 protected function get_edit_input_fields($field_values = null)
2782 {
2783 $fields = $this->get_edit_fields();
2784 $types = $this->get_field_types();
2785
2786 $input_fields = array();
2787
2788 foreach($fields as $field_num => $field)
2789 {
2790 $field_info = $types[$field->field_name];
2791
2792 $field_value = !empty($field_values) && isset($field_values->{$field->field_name}) ? $field_values->{$field->field_name} : null;
2793 if(!isset($this->callback_edit_field[$field->field_name]))
2794 {
2795 $field_input = $this->get_field_input($field_info, $field_value);
2796 }
2797 else
2798 {
2799 $primary_key = $this->getStateInfo()->primary_key;
2800 $field_input = $field_info;
2801 $field_input->input = call_user_func($this->callback_edit_field[$field->field_name], $field_value, $primary_key, $field_info, $field_values);
2802 }
2803
2804 switch ($field_info->crud_type) {
2805 case 'invisible':
2806 unset($this->edit_fields[$field_num]);
2807 unset($fields[$field_num]);
2808 continue;
2809 break;
2810 case 'hidden':
2811 $this->edit_hidden_fields[] = $field_input;
2812 unset($this->edit_fields[$field_num]);
2813 unset($fields[$field_num]);
2814 continue;
2815 break;
2816 }
2817
2818 $input_fields[$field->field_name] = $field_input;
2819 }
2820
2821 return $input_fields;
2822 }
2823
2824 protected function get_read_input_fields($field_values = null)
2825 {
2826 $read_fields = $this->get_read_fields();
2827
2828 $this->field_types = null;
2829 $this->required_fields = null;
2830
2831 $read_inputs = array();
2832 foreach ($read_fields as $field) {
2833 if (!empty($this->change_field_type)
2834 && isset($this->change_field_type[$field->field_name])
2835 && $this->change_field_type[$field->field_name]->type == 'hidden') {
2836 continue;
2837 }
2838 $this->field_type($field->field_name, 'readonly');
2839 }
2840
2841 $fields = $this->get_read_fields();
2842 $types = $this->get_field_types();
2843
2844 $input_fields = array();
2845
2846 foreach($fields as $field_num => $field)
2847 {
2848 $field_info = $types[$field->field_name];
2849
2850 $field_value = !empty($field_values) && isset($field_values->{$field->field_name}) ? $field_values->{$field->field_name} : null;
2851 if(!isset($this->callback_read_field[$field->field_name]))
2852 {
2853 $field_input = $this->get_field_input($field_info, $field_value);
2854 }
2855 else
2856 {
2857 $primary_key = $this->getStateInfo()->primary_key;
2858 $field_input = $field_info;
2859 $field_input->input = call_user_func($this->callback_read_field[$field->field_name], $field_value, $primary_key, $field_info, $field_values);
2860 }
2861
2862 switch ($field_info->crud_type) {
2863 case 'invisible':
2864 unset($this->read_fields[$field_num]);
2865 unset($fields[$field_num]);
2866 continue;
2867 break;
2868 case 'hidden':
2869 $this->read_hidden_fields[] = $field_input;
2870 unset($this->read_fields[$field_num]);
2871 unset($fields[$field_num]);
2872 continue;
2873 break;
2874 }
2875
2876 $input_fields[$field->field_name] = $field_input;
2877 }
2878
2879 return $input_fields;
2880 }
2881
2882 protected function setThemeBasics()
2883 {
2884 $this->theme_path = $this->default_theme_path;
2885 if(substr($this->theme_path,-1) != '/')
2886 $this->theme_path = $this->theme_path.'/';
2887
2888 include($this->theme_path.$this->theme.'/config.php');
2889
2890 $this->theme_config = $config;
2891 }
2892
2893 public function set_theme($theme = null)
2894 {
2895 $this->theme = $theme;
2896
2897 return $this;
2898 }
2899
2900 protected function _get_ajax_results()
2901 {
2902 //This is a $_POST request rather that $_GET request , because
2903 //Codeigniter doesn't like the $_GET requests so much!
2904 if ($this->_is_ajax()) {
2905 @ob_end_clean();
2906 $results= (object)array(
2907 'output' => $this->views_as_string,
2908 'js_files' => array_values($this->get_js_files()),
2909 'js_lib_files' => array_values($this->get_js_lib_files()),
2910 'js_config_files' => array_values($this->get_js_config_files()),
2911 'css_files' => array_values($this->get_css_files())
2912 );
2913
2914 echo json_encode($results);
2915 die;
2916 }
2917 //else just continue
2918 }
2919
2920 protected function _is_ajax()
2921 {
2922 return array_key_exists('is_ajax', $_POST) && $_POST['is_ajax'] == 'true' ? true: false;
2923 }
2924
2925 protected function _theme_view($view, $vars = array(), $return = FALSE)
2926 {
2927 $vars = (is_object($vars)) ? get_object_vars($vars) : $vars;
2928
2929 $file_exists = FALSE;
2930
2931 $ext = pathinfo($view, PATHINFO_EXTENSION);
2932 $file = ($ext == '') ? $view.'.php' : $view;
2933
2934 $view_file = $this->theme_path.$this->theme.'/views/';
2935
2936 if (file_exists($view_file.$file))
2937 {
2938 $path = $view_file.$file;
2939 $file_exists = TRUE;
2940 }
2941
2942 if ( ! $file_exists)
2943 {
2944 throw new Exception('Unable to load the requested file: '.$file, 16);
2945 }
2946
2947 extract($vars);
2948
2949 #region buffering...
2950 ob_start();
2951
2952 include($path);
2953
2954 $buffer = ob_get_contents();
2955 @ob_end_clean();
2956 #endregion
2957
2958 if ($return === TRUE)
2959 {
2960 return $buffer;
2961 }
2962
2963 $this->views_as_string .= $buffer;
2964 }
2965
2966 protected function _inline_js($inline_js = '')
2967 {
2968 $this->views_as_string .= "<script type=\"text/javascript\">\n{$inline_js}\n</script>\n";
2969 }
2970
2971 protected function _add_js_vars($js_vars = array())
2972 {
2973 $javascript_as_string = "<script type=\"text/javascript\">\n";
2974 foreach ($js_vars as $js_var => $js_value) {
2975 $javascript_as_string .= "\tvar $js_var = '$js_value';\n";
2976 }
2977 $javascript_as_string .= "\n</script>\n";
2978 $this->views_as_string .= $javascript_as_string;
2979 }
2980
2981 protected function get_views_as_string()
2982 {
2983 if(!empty($this->views_as_string))
2984 return $this->views_as_string;
2985 else
2986 return null;
2987 }
2988}
2989
2990
2991/**
2992 * PHP grocery CRUD
2993 *
2994 * LICENSE
2995 *
2996 * Grocery CRUD is released with dual licensing, using the GPL v3 (license-gpl3.txt) and the MIT license (license-mit.txt).
2997 * You don't have to do anything special to choose one license or the other and you don't have to notify anyone which license you are using.
2998 * Please see the corresponding license file for details of these licenses.
2999 * You are free to use, modify and distribute this software, but all copyright information must remain.
3000 *
3001 * @package grocery CRUD
3002 * @copyright Copyright (c) 2010 through 2014, John Skoumbourdis
3003 * @license https://github.com/scoumbourdis/grocery-crud/blob/master/license-grocery-crud.txt
3004 * @author John Skoumbourdis <scoumbourdisj@gmail.com>
3005 */
3006
3007// ------------------------------------------------------------------------
3008
3009/**
3010 * PHP grocery States
3011 *
3012 * States of grocery CRUD
3013 *
3014 * @package grocery CRUD
3015 * @author John Skoumbourdis <scoumbourdisj@gmail.com>
3016 * @version 1.5.8
3017 */
3018class grocery_CRUD_States extends grocery_CRUD_Layout
3019{
3020 const STATE_UNKNOWN = 0;
3021 const STATE_LIST = 1;
3022 const STATE_ADD = 2;
3023 const STATE_EDIT = 3;
3024 const STATE_DELETE = 4;
3025 const STATE_INSERT = 5;
3026
3027 const STATE_READ = 18;
3028 const STATE_DELETE_MULTIPLE = '19';
3029
3030 protected $states = array(
3031 0 => 'unknown',
3032 1 => 'list',
3033 2 => 'add',
3034 3 => 'edit',
3035 4 => 'delete',
3036 5 => 'insert',
3037 6 => 'update',
3038 7 => 'ajax_list',
3039 8 => 'ajax_list_info',
3040 9 => 'insert_validation',
3041 10 => 'update_validation',
3042 11 => 'upload_file',
3043 12 => 'delete_file',
3044 13 => 'ajax_relation',
3045 14 => 'ajax_relation_n_n',
3046 15 => 'success',
3047 16 => 'export',
3048 17 => 'print',
3049 18 => 'read',
3050 19 => 'delete_multiple'
3051 );
3052
3053 public function getStateInfo()
3054 {
3055 $state_code = $this->getStateCode();
3056 $segment_object = $this->get_state_info_from_url();
3057
3058 $first_parameter = $segment_object->first_parameter;
3059 $second_parameter = $segment_object->second_parameter;
3060
3061 $state_info = (object)array();
3062
3063 switch ($state_code) {
3064 case self::STATE_LIST:
3065 case self::STATE_ADD:
3066 //for now... do nothing! Keeping this switch here in case we need any information at the future.
3067 break;
3068
3069 case self::STATE_EDIT:
3070 case self::STATE_READ:
3071 if ($first_parameter !== null) {
3072 $state_info = (object) array('primary_key' => $first_parameter);
3073 } else {
3074 throw new Exception('On the state "edit" the Primary key cannot be null', 6);
3075 die();
3076 }
3077 break;
3078
3079 case self::STATE_DELETE:
3080 if ($first_parameter !== null) {
3081 $state_info = (object) array('primary_key' => $first_parameter);
3082 } else {
3083 throw new Exception('On the state "delete" the Primary key cannot be null',7);
3084 die();
3085 }
3086 break;
3087
3088 case self::STATE_DELETE_MULTIPLE:
3089 if (!empty($_POST) && !empty($_POST['ids']) && is_array($_POST['ids'])) {
3090 $state_info = (object) array('ids' => $_POST['ids']);
3091 } else {
3092 throw new Exception('On the state "Delete Multiple" you need send the ids as a post array.');
3093 die();
3094 }
3095 break;
3096
3097 case self::STATE_INSERT:
3098 if(!empty($_POST))
3099 {
3100 $state_info = (object)array('unwrapped_data' => $_POST);
3101 }
3102 else
3103 {
3104 throw new Exception('On the state "insert" you must have post data',8);
3105 die();
3106 }
3107 break;
3108
3109 case 6:
3110 if(!empty($_POST) && $first_parameter !== null)
3111 {
3112 $state_info = (object)array('primary_key' => $first_parameter,'unwrapped_data' => $_POST);
3113 }
3114 elseif(empty($_POST))
3115 {
3116 throw new Exception('On the state "update" you must have post data',9);
3117 die();
3118 }
3119 else
3120 {
3121 throw new Exception('On the state "update" the Primary key cannot be null',10);
3122 die();
3123 }
3124 break;
3125
3126 case 7:
3127 case 8:
3128 case 16: //export to excel
3129 case 17: //print
3130 $state_info = (object)array();
3131 if(!empty($_POST['per_page']))
3132 {
3133 $state_info->per_page = is_numeric($_POST['per_page']) ? $_POST['per_page'] : null;
3134 }
3135 if(!empty($_POST['page']))
3136 {
3137 $state_info->page = is_numeric($_POST['page']) ? $_POST['page'] : null;
3138 }
3139 //If we request an export or a print we don't care about what page we are
3140 if($state_code === 16 || $state_code === 17)
3141 {
3142 $state_info->page = 1;
3143 $state_info->per_page = 1000000; //a very big number!
3144 }
3145 if(!empty($_POST['order_by'][0]))
3146 {
3147 $state_info->order_by = $_POST['order_by'];
3148 }
3149 if(!empty($_POST['search_text']))
3150 {
3151 if(empty($_POST['search_field']))
3152 {
3153 $search_text = strip_tags($_POST['search_field']);
3154 $state_info->search = (object)array('field' => null , 'text' => $_POST['search_text']);
3155 }
3156 else
3157 {
3158 if (is_array($_POST['search_field'])) {
3159 $search_array = array();
3160 foreach ($_POST['search_field'] as $search_key => $search_field_name) {
3161 $search_array[$search_field_name] = !empty($_POST['search_text'][$search_key]) ? $_POST['search_text'][$search_key] : '';
3162 }
3163 $state_info->search = $search_array;
3164 } else {
3165 $state_info->search = (object)array(
3166 'field' => strip_tags($_POST['search_field']) ,
3167 'text' => $_POST['search_text'] );
3168 }
3169 }
3170 }
3171 break;
3172
3173 case 9:
3174
3175 break;
3176
3177 case 10:
3178 if($first_parameter !== null)
3179 {
3180 $state_info = (object)array('primary_key' => $first_parameter);
3181 }
3182 break;
3183
3184 case 11:
3185 $state_info->field_name = $first_parameter;
3186 break;
3187
3188 case 12:
3189 $state_info->field_name = $first_parameter;
3190 $state_info->file_name = $second_parameter;
3191 break;
3192
3193 case 13:
3194 $state_info->field_name = $_POST['field_name'];
3195 $state_info->search = $_POST['term'];
3196 break;
3197
3198 case 14:
3199 $state_info->field_name = $_POST['field_name'];
3200 $state_info->search = $_POST['term'];
3201 break;
3202
3203 case 15:
3204 $state_info = (object)array(
3205 'primary_key' => $first_parameter,
3206 'success_message' => true
3207 );
3208 break;
3209 }
3210
3211 return $state_info;
3212 }
3213
3214 protected function getStateCode()
3215 {
3216 $state_string = $this->get_state_info_from_url()->operation;
3217
3218 if( $state_string != 'unknown' && in_array( $state_string, $this->states ) )
3219 $state_code = array_search($state_string, $this->states);
3220 else
3221 $state_code = 0;
3222
3223 return $state_code;
3224 }
3225
3226 protected function state_url($url = '', $is_list_page = false)
3227 {
3228 //Easy scenario, we had set the crud_url_path
3229 if (!empty($this->crud_url_path)) {
3230 $state_url = !empty($this->list_url_path) && $is_list_page?
3231 $this->list_url_path :
3232 $this->crud_url_path.'/'.$url ;
3233 } else {
3234 //Complicated scenario. The crud_url_path is not specified so we are
3235 //trying to understand what is going on from the URL.
3236 $ci = &get_instance();
3237
3238 $segment_object = $this->get_state_info_from_url();
3239 $method_name = $this->get_method_name();
3240 $segment_position = $segment_object->segment_position;
3241
3242 $state_url_array = array();
3243
3244 if( sizeof($ci->uri->segments) > 0 ) {
3245 foreach($ci->uri->segments as $num => $value)
3246 {
3247 $state_url_array[$num] = $value;
3248 if($num == ($segment_position - 1))
3249 break;
3250 }
3251
3252 if( $method_name == 'index' && !in_array( 'index', $state_url_array ) ) //there is a scenario that you don't have the index to your url
3253 $state_url_array[$num+1] = 'index';
3254 }
3255
3256 $state_url = site_url(implode('/',$state_url_array).'/'.$url);
3257 }
3258
3259 return $state_url;
3260 }
3261
3262 protected function get_state_info_from_url()
3263 {
3264 $ci = &get_instance();
3265
3266 $segment_position = count($ci->uri->segments) + 1;
3267 $operation = 'list';
3268
3269 $segements = $ci->uri->segments;
3270 foreach($segements as $num => $value)
3271 {
3272 if($value != 'unknown' && in_array($value, $this->states))
3273 {
3274 $segment_position = (int)$num;
3275 $operation = $value; //I don't have a "break" here because I want to ensure that is the LAST segment with name that is in the array.
3276 }
3277 }
3278
3279 $function_name = $this->get_method_name();
3280
3281 if($function_name == 'index' && !in_array('index',$ci->uri->segments))
3282 $segment_position++;
3283
3284 $first_parameter = isset($segements[$segment_position+1]) ? $segements[$segment_position+1] : null;
3285 $second_parameter = isset($segements[$segment_position+2]) ? $segements[$segment_position+2] : null;
3286
3287 return (object)array('segment_position' => $segment_position, 'operation' => $operation, 'first_parameter' => $first_parameter, 'second_parameter' => $second_parameter);
3288 }
3289
3290 protected function get_method_hash()
3291 {
3292 $ci = &get_instance();
3293
3294 $state_info = $this->get_state_info_from_url();
3295 $extra_values = $ci->uri->segment($state_info->segment_position - 1) != $this->get_method_name() ? $ci->uri->segment($state_info->segment_position - 1) : '';
3296
3297 return $this->crud_url_path !== null
3298 ? md5($this->crud_url_path)
3299 : md5($this->get_controller_name().$this->get_method_name().$extra_values);
3300 }
3301
3302 protected function get_method_name()
3303 {
3304 $ci = &get_instance();
3305 return $ci->router->method;
3306 }
3307
3308 protected function get_controller_name()
3309 {
3310 $ci = &get_instance();
3311 return $ci->router->class;
3312 }
3313
3314 public function getState()
3315 {
3316 return $this->states[$this->getStateCode()];
3317 }
3318
3319 protected function getListUrl()
3320 {
3321 return $this->state_url('',true);
3322 }
3323
3324 protected function getAjaxListUrl()
3325 {
3326 return $this->state_url('ajax_list');
3327 }
3328
3329 protected function getExportToExcelUrl()
3330 {
3331 return $this->state_url('export');
3332 }
3333
3334 protected function getPrintUrl()
3335 {
3336 return $this->state_url('print');
3337 }
3338
3339 protected function getAjaxListInfoUrl()
3340 {
3341 return $this->state_url('ajax_list_info');
3342 }
3343
3344 protected function getAddUrl()
3345 {
3346 return $this->state_url('add');
3347 }
3348
3349 protected function getInsertUrl()
3350 {
3351 return $this->state_url('insert');
3352 }
3353
3354 protected function getValidationInsertUrl()
3355 {
3356 return $this->state_url('insert_validation');
3357 }
3358
3359 protected function getValidationUpdateUrl($primary_key = null)
3360 {
3361 if($primary_key === null)
3362 return $this->state_url('update_validation');
3363 else
3364 return $this->state_url('update_validation/'.$primary_key);
3365 }
3366
3367 protected function getEditUrl($primary_key = null)
3368 {
3369 if($primary_key === null)
3370 return $this->state_url('edit');
3371 else
3372 return $this->state_url('edit/'.$primary_key);
3373 }
3374
3375 protected function getReadUrl($primary_key = null)
3376 {
3377 if($primary_key === null)
3378 return $this->state_url('read');
3379 else
3380 return $this->state_url('read/'.$primary_key);
3381 }
3382
3383 protected function getUpdateUrl($state_info)
3384 {
3385 return $this->state_url('update/'.$state_info->primary_key);
3386 }
3387
3388 protected function getDeleteUrl($state_info = null)
3389 {
3390 if (empty($state_info)) {
3391 return $this->state_url('delete');
3392 } else {
3393 return $this->state_url('delete/'.$state_info->primary_key);
3394 }
3395 }
3396
3397 protected function getDeleteMultipleUrl()
3398 {
3399 return $this->state_url('delete_multiple');
3400 }
3401
3402 protected function getListSuccessUrl($primary_key = null)
3403 {
3404 if(empty($primary_key))
3405 return $this->state_url('success',true);
3406 else
3407 return $this->state_url('success/'.$primary_key,true);
3408 }
3409
3410 protected function getUploadUrl($field_name)
3411 {
3412 return $this->state_url('upload_file/'.$field_name);
3413 }
3414
3415 protected function getFileDeleteUrl($field_name)
3416 {
3417 return $this->state_url('delete_file/'.$field_name);
3418 }
3419
3420 protected function getAjaxRelationUrl()
3421 {
3422 return $this->state_url('ajax_relation');
3423 }
3424
3425 protected function getAjaxRelationManytoManyUrl()
3426 {
3427 return $this->state_url('ajax_relation_n_n');
3428 }
3429}
3430
3431
3432/**
3433 * PHP grocery CRUD
3434 *
3435 * LICENSE
3436 *
3437 * Grocery CRUD is released with dual licensing, using the GPL v3 (license-gpl3.txt) and the MIT license (license-mit.txt).
3438 * You don't have to do anything special to choose one license or the other and you don't have to notify anyone which license you are using.
3439 * Please see the corresponding license file for details of these licenses.
3440 * You are free to use, modify and distribute this software, but all copyright information must remain.
3441 *
3442 * @package grocery CRUD
3443 * @copyright Copyright (c) 2010 through 2014, John Skoumbourdis
3444 * @license https://github.com/scoumbourdis/grocery-crud/blob/master/license-grocery-crud.txt
3445 * @version 1.5.8
3446 * @author John Skoumbourdis <scoumbourdisj@gmail.com>
3447 */
3448
3449// ------------------------------------------------------------------------
3450
3451/**
3452 * PHP grocery CRUD
3453 *
3454 * Creates a full functional CRUD with few lines of code.
3455 *
3456 * @package grocery CRUD
3457 * @author John Skoumbourdis <scoumbourdisj@gmail.com>
3458 * @license https://github.com/scoumbourdis/grocery-crud/blob/master/license-grocery-crud.txt
3459 * @link http://www.grocerycrud.com/documentation
3460 */
3461class Grocery_CRUD extends grocery_CRUD_States
3462{
3463 /**
3464 * Grocery CRUD version
3465 *
3466 * @var string
3467 */
3468 const VERSION = "1.5.8";
3469
3470 const JQUERY = "jquery-1.11.1.min.js";
3471 const JQUERY_UI_JS = "jquery-ui-1.10.3.custom.min.js";
3472 const JQUERY_UI_CSS = "jquery-ui-1.10.1.custom.min.css";
3473
3474 protected $state_code = null;
3475 protected $state_info = null;
3476 protected $columns = null;
3477
3478 private $basic_db_table_checked = false;
3479 private $columns_checked = false;
3480 private $add_fields_checked = false;
3481 private $edit_fields_checked = false;
3482 private $read_fields_checked = false;
3483
3484 protected $default_theme = 'flexigrid';
3485 protected $language = null;
3486 protected $lang_strings = array();
3487 protected $php_date_format = null;
3488 protected $js_date_format = null;
3489 protected $ui_date_format = null;
3490 protected $character_limiter = null;
3491 protected $config = null;
3492
3493 protected $add_fields = null;
3494 protected $edit_fields = null;
3495 protected $read_fields = null;
3496 protected $add_hidden_fields = array();
3497 protected $edit_hidden_fields = array();
3498 protected $field_types = null;
3499 protected $basic_db_table = null;
3500 protected $theme_config = array();
3501 protected $subject = null;
3502 protected $subject_plural = null;
3503 protected $display_as = array();
3504 protected $order_by = null;
3505 protected $where = array();
3506 protected $like = array();
3507 protected $having = array();
3508 protected $or_having = array();
3509 protected $limit = null;
3510 protected $required_fields = array();
3511 protected $_unique_fields = array();
3512 protected $validation_rules = array();
3513 protected $relation = array();
3514 protected $relation_n_n = array();
3515 protected $upload_fields = array();
3516 protected $actions = array();
3517
3518 protected $form_validation = null;
3519 protected $change_field_type = null;
3520 protected $primary_keys = array();
3521 protected $crud_url_path = null;
3522 protected $list_url_path = null;
3523
3524 /* The unsetters */
3525 protected $unset_texteditor = array();
3526 protected $unset_add = false;
3527 protected $unset_edit = false;
3528 protected $unset_delete = false;
3529 protected $unset_read = false;
3530 protected $unset_jquery = false;
3531 protected $unset_jquery_ui = false;
3532 protected $unset_bootstrap = false;
3533 protected $unset_list = false;
3534 protected $unset_export = false;
3535 protected $unset_print = false;
3536 protected $unset_back_to_list = false;
3537 protected $unset_columns = null;
3538 protected $unset_add_fields = null;
3539 protected $unset_edit_fields = null;
3540 protected $unset_read_fields = null;
3541
3542 /* Callbacks */
3543 protected $callback_before_insert = null;
3544 protected $callback_after_insert = null;
3545 protected $callback_insert = null;
3546 protected $callback_before_update = null;
3547 protected $callback_after_update = null;
3548 protected $callback_update = null;
3549 protected $callback_before_delete = null;
3550 protected $callback_after_delete = null;
3551 protected $callback_delete = null;
3552 protected $callback_column = array();
3553 protected $callback_add_field = array();
3554 protected $callback_edit_field = array();
3555 protected $callback_upload = null;
3556 protected $callback_before_upload = null;
3557 protected $callback_after_upload = null;
3558
3559 protected $default_javascript_path = null; //autogenerate, please do not modify
3560 protected $default_css_path = null; //autogenerate, please do not modify
3561 protected $default_texteditor_path = null; //autogenerate, please do not modify
3562 protected $default_theme_path = null; //autogenerate, please do not modify
3563 protected $default_language_path = 'assets/grocery_crud/languages';
3564 protected $default_config_path = 'assets/grocery_crud/config';
3565 protected $default_assets_path = 'assets/grocery_crud';
3566
3567 /**
3568 *
3569 * Constructor
3570 *
3571 * @access public
3572 */
3573 public function __construct()
3574 {
3575
3576 }
3577
3578 /**
3579 * The displayed columns that user see
3580 *
3581 * @access public
3582 * @param string
3583 * @param array
3584 * @return void
3585 */
3586 public function columns()
3587 {
3588 $args = func_get_args();
3589
3590 if(isset($args[0]) && is_array($args[0]))
3591 {
3592 $args = $args[0];
3593 }
3594
3595 $this->columns = $args;
3596
3597 return $this;
3598 }
3599
3600
3601 /**
3602 * Set Validation Rules
3603 *
3604 * Important note: If the $field is an array then no automated crud fields will take apart
3605 *
3606 * @access public
3607 * @param mixed
3608 * @param string
3609 * @oaram array
3610 * @return void
3611 */
3612 function set_rules($field, $label = '', $rules = '', $errors = array())
3613 {
3614 if(is_string($field))
3615 {
3616 $this->validation_rules[$field] = array('field' => $field, 'label' => $label, 'rules' => $rules, 'errors' => $errors);
3617 }elseif(is_array($field))
3618 {
3619 foreach($field as $num_field => $field_array)
3620 {
3621 $this->validation_rules[$field_array['field']] = $field_array;
3622 }
3623 }
3624 return $this;
3625 }
3626
3627 /**
3628 *
3629 * Changes the default field type
3630 * @param string $field
3631 * @param string $type
3632 * @param array|string $extras
3633 */
3634 public function change_field_type($field , $type, $extras = null)
3635 {
3636 $field_type = (object)array('type' => $type);
3637
3638 $field_type->extras = $extras;
3639
3640 $this->change_field_type[$field] = $field_type;
3641
3642 return $this;
3643 }
3644
3645 /**
3646 *
3647 * Just an alias to the change_field_type method
3648 * @param string $field
3649 * @param string $type
3650 * @param array|string $extras
3651 */
3652 public function field_type($field , $type, $extras = null)
3653 {
3654 return $this->change_field_type($field , $type, $extras);
3655 }
3656
3657 /**
3658 * Change the default primary key for a specific table.
3659 * If the $table_name is NULL then the primary key is for the default table name that we added at the set_table method
3660 *
3661 * @param string $primary_key_field
3662 * @param string $table_name
3663 */
3664 public function set_primary_key($primary_key_field, $table_name = null)
3665 {
3666 $this->primary_keys[] = array('field_name' => $primary_key_field, 'table_name' => $table_name);
3667
3668 return $this;
3669 }
3670
3671 /**
3672 * Unsets the texteditor of the selected fields
3673 *
3674 * @access public
3675 * @param string
3676 * @param array
3677 * @return void
3678 */
3679 public function unset_texteditor()
3680 {
3681 $args = func_get_args();
3682
3683 if(isset($args[0]) && is_array($args[0]))
3684 {
3685 $args = $args[0];
3686 }
3687 foreach($args as $arg)
3688 {
3689 $this->unset_texteditor[] = $arg;
3690 }
3691
3692 return $this;
3693 }
3694
3695 /**
3696 * Unsets just the jquery library from the js. This function can be used if there is already a jquery included
3697 * in the main template. This will avoid all jquery conflicts.
3698 *
3699 * @return void
3700 */
3701 public function unset_jquery()
3702 {
3703 $this->unset_jquery = true;
3704
3705 return $this;
3706 }
3707
3708 /**
3709 * Unsets the jquery UI Javascript and CSS. This function is really useful
3710 * when the jquery UI JavaScript and CSS are already included in the main template.
3711 * This will avoid all jquery UI conflicts.
3712 *
3713 * @return void
3714 */
3715 public function unset_jquery_ui()
3716 {
3717 $this->unset_jquery_ui = true;
3718
3719 return $this;
3720 }
3721
3722 /**
3723 * Unsets just the twitter bootstrap libraries from the js and css. This function can be used if there is already twitter bootstrap files included
3724 * in the main template. If you are already using a bootstrap template then it's not necessary to load the files again.
3725 *
3726 * @return void
3727 */
3728 public function unset_bootstrap()
3729 {
3730 $this->unset_bootstrap = true;
3731
3732 return $this;
3733 }
3734
3735 /**
3736 * Unsets the add operation from the list
3737 *
3738 * @return void
3739 */
3740 public function unset_add()
3741 {
3742 $this->unset_add = true;
3743
3744 return $this;
3745 }
3746
3747 /**
3748 * Unsets the edit operation from the list
3749 *
3750 * @return void
3751 */
3752 public function unset_edit()
3753 {
3754 $this->unset_edit = true;
3755
3756 return $this;
3757 }
3758
3759 /**
3760 * Unsets the delete operation from the list
3761 *
3762 * @return void
3763 */
3764 public function unset_delete()
3765 {
3766 $this->unset_delete = true;
3767
3768 return $this;
3769 }
3770
3771 /**
3772 * Unsets the read operation from the list
3773 *
3774 * @return void
3775 */
3776 public function unset_read()
3777 {
3778 $this->unset_read = true;
3779
3780 return $this;
3781 }
3782
3783 /**
3784 * Just an alias to unset_read
3785 *
3786 * @return void
3787 * */
3788 public function unset_view()
3789 {
3790 return unset_read();
3791 }
3792
3793 /**
3794 * Unsets the export button and functionality from the list
3795 *
3796 * @return void
3797 */
3798 public function unset_export()
3799 {
3800 $this->unset_export = true;
3801
3802 return $this;
3803 }
3804
3805
3806 /**
3807 * Unsets the print button and functionality from the list
3808 *
3809 * @return void
3810 */
3811 public function unset_print()
3812 {
3813 $this->unset_print = true;
3814
3815 return $this;
3816 }
3817
3818 /**
3819 * Unsets all the operations from the list
3820 *
3821 * @return void
3822 */
3823 public function unset_operations()
3824 {
3825 $this->unset_add = true;
3826 $this->unset_edit = true;
3827 $this->unset_delete = true;
3828 $this->unset_read = true;
3829 $this->unset_export = true;
3830 $this->unset_print = true;
3831
3832 return $this;
3833 }
3834
3835 /**
3836 * Unsets a column from the list
3837 *
3838 * @return void.
3839 */
3840 public function unset_columns()
3841 {
3842 $args = func_get_args();
3843
3844 if(isset($args[0]) && is_array($args[0]))
3845 {
3846 $args = $args[0];
3847 }
3848
3849 $this->unset_columns = $args;
3850
3851 return $this;
3852 }
3853
3854 public function unset_list()
3855 {
3856 $this->unset_list = true;
3857
3858 return $this;
3859 }
3860
3861 public function unset_fields()
3862 {
3863 $args = func_get_args();
3864
3865 if(isset($args[0]) && is_array($args[0]))
3866 {
3867 $args = $args[0];
3868 }
3869
3870 $this->unset_add_fields = $args;
3871 $this->unset_edit_fields = $args;
3872 $this->unset_read_fields = $args;
3873
3874 return $this;
3875 }
3876
3877 public function unset_add_fields()
3878 {
3879 $args = func_get_args();
3880
3881 if(isset($args[0]) && is_array($args[0]))
3882 {
3883 $args = $args[0];
3884 }
3885
3886 $this->unset_add_fields = $args;
3887
3888 return $this;
3889 }
3890
3891 public function unset_edit_fields()
3892 {
3893 $args = func_get_args();
3894
3895 if(isset($args[0]) && is_array($args[0]))
3896 {
3897 $args = $args[0];
3898 }
3899
3900 $this->unset_edit_fields = $args;
3901
3902 return $this;
3903 }
3904
3905 public function unset_read_fields()
3906 {
3907 $args = func_get_args();
3908
3909 if(isset($args[0]) && is_array($args[0]))
3910 {
3911 $args = $args[0];
3912 }
3913
3914 $this->unset_read_fields = $args;
3915
3916 return $this;
3917 }
3918
3919
3920 /**
3921 * Unsets everything that has to do with buttons or links with go back to list message
3922 * @access public
3923 * @return void
3924 */
3925 public function unset_back_to_list()
3926 {
3927 $this->unset_back_to_list = true;
3928
3929 return $this;
3930 }
3931
3932 /**
3933 *
3934 * The fields that user will see on add/edit
3935 *
3936 * @access public
3937 * @param string
3938 * @param array
3939 * @return void
3940 */
3941 public function fields()
3942 {
3943 $args = func_get_args();
3944
3945 if(isset($args[0]) && is_array($args[0]))
3946 {
3947 $args = $args[0];
3948 }
3949
3950 $this->add_fields = $args;
3951 $this->edit_fields = $args;
3952
3953 return $this;
3954 }
3955
3956 /**
3957 *
3958 * The fields that user can see . It is only for the add form
3959 */
3960 public function add_fields()
3961 {
3962 $args = func_get_args();
3963
3964 if(isset($args[0]) && is_array($args[0]))
3965 {
3966 $args = $args[0];
3967 }
3968
3969 $this->add_fields = $args;
3970
3971 return $this;
3972 }
3973
3974 /**
3975 *
3976 * The fields that user can see . It is only for the edit form
3977 */
3978 public function edit_fields()
3979 {
3980 $args = func_get_args();
3981
3982 if(isset($args[0]) && is_array($args[0]))
3983 {
3984 $args = $args[0];
3985 }
3986
3987 $this->edit_fields = $args;
3988
3989 return $this;
3990 }
3991
3992 public function set_read_fields()
3993 {
3994 $args = func_get_args();
3995
3996 if(isset($args[0]) && is_array($args[0])) {
3997 $args = $args[0];
3998 }
3999
4000 $this->read_fields = $args;
4001
4002 return $this;
4003 }
4004
4005 /**
4006 *
4007 * Changes the displaying label of the field
4008 * @param $field_name
4009 * @param $display_as
4010 * @return void
4011 */
4012 public function display_as($field_name, $display_as = null)
4013 {
4014 if(is_array($field_name))
4015 {
4016 foreach($field_name as $field => $display_as)
4017 {
4018 $this->display_as[$field] = $display_as;
4019 }
4020 }
4021 elseif($display_as !== null)
4022 {
4023 $this->display_as[$field_name] = $display_as;
4024 }
4025 return $this;
4026 }
4027
4028 /**
4029 *
4030 * Load the language strings array from the language file
4031 */
4032 protected function _load_language()
4033 {
4034 if($this->language === null)
4035 {
4036 $this->language = strtolower($this->config->default_language);
4037 }
4038 include($this->default_language_path.'/'.$this->language.'.php');
4039
4040 foreach($lang as $handle => $lang_string)
4041 if(!isset($this->lang_strings[$handle]))
4042 $this->lang_strings[$handle] = $lang_string;
4043
4044 $this->default_true_false_text = array( $this->l('form_inactive') , $this->l('form_active'));
4045 $this->subject = $this->subject === null ? $this->l('list_record') : $this->subject;
4046
4047 }
4048
4049 protected function _load_date_format()
4050 {
4051 list($php_day, $php_month, $php_year) = array('d','m','Y');
4052 list($js_day, $js_month, $js_year) = array('dd','mm','yy');
4053 list($ui_day, $ui_month, $ui_year) = array($this->l('ui_day'), $this->l('ui_month'), $this->l('ui_year'));
4054
4055 $date_format = $this->config->date_format;
4056 switch ($date_format) {
4057 case 'uk-date':
4058 $this->php_date_format = "$php_day/$php_month/$php_year";
4059 $this->js_date_format = "$js_day/$js_month/$js_year";
4060 $this->ui_date_format = "$ui_day/$ui_month/$ui_year";
4061 break;
4062
4063 case 'us-date':
4064 $this->php_date_format = "$php_month/$php_day/$php_year";
4065 $this->js_date_format = "$js_month/$js_day/$js_year";
4066 $this->ui_date_format = "$ui_month/$ui_day/$ui_year";
4067 break;
4068
4069 case 'sql-date':
4070 default:
4071 $this->php_date_format = "$php_year-$php_month-$php_day";
4072 $this->js_date_format = "$js_year-$js_month-$js_day";
4073 $this->ui_date_format = "$ui_year-$ui_month-$ui_day";
4074 break;
4075 }
4076 }
4077
4078 /**
4079 *
4080 * Set a language string directly
4081 * @param string $handle
4082 * @param string $string
4083 */
4084 public function set_lang_string($handle, $lang_string){
4085 $this->lang_strings[$handle] = $lang_string;
4086
4087 return $this;
4088 }
4089
4090 /**
4091 *
4092 * Just an alias to get_lang_string method
4093 * @param string $handle
4094 */
4095 public function l($handle)
4096 {
4097 return $this->get_lang_string($handle);
4098 }
4099
4100 /**
4101 *
4102 * Get the language string of the inserted string handle
4103 * @param string $handle
4104 */
4105 public function get_lang_string($handle)
4106 {
4107 return $this->lang_strings[$handle];
4108 }
4109
4110 /**
4111 *
4112 * Simply set the language
4113 * @example english
4114 * @param string $language
4115 */
4116 public function set_language($language)
4117 {
4118 $this->language = $language;
4119
4120 return $this;
4121 }
4122
4123 /**
4124 *
4125 * Enter description here ...
4126 */
4127 protected function get_columns()
4128 {
4129 if($this->columns_checked === false)
4130 {
4131 $field_types = $this->get_field_types();
4132 if(empty($this->columns))
4133 {
4134 $this->columns = array();
4135 foreach($field_types as $field)
4136 {
4137 if( !isset($field->db_extra) || $field->db_extra != 'auto_increment' )
4138 $this->columns[] = $field->name;
4139 }
4140 }
4141
4142 foreach($this->columns as $col_num => $column)
4143 {
4144
4145 if(isset($this->relation[$column]))
4146 {
4147
4148 $new_column = $this->_unique_field_name($this->relation[$column][0]);
4149 $this->columns[$col_num] = $new_column;
4150
4151 if(isset($this->display_as[$column]))
4152 {
4153 $display_as = $this->display_as[$column];
4154 unset($this->display_as[$column]);
4155 $this->display_as[$new_column] = $display_as;
4156 }
4157 else
4158 {
4159 $this->display_as[$new_column] = ucfirst(str_replace('_',' ',$column));
4160 }
4161
4162 $column = $new_column;
4163 $this->columns[$col_num] = $new_column;
4164 }
4165 else
4166 {
4167 if(!empty($this->relation))
4168 {
4169 $table_name = $this->get_table();
4170 foreach($this->relation as $relation)
4171 {
4172 if( $relation[2] == $column )
4173 {
4174 $new_column = $table_name.'.'.$column;
4175 if(isset($this->display_as[$column]))
4176 {
4177 $display_as = $this->display_as[$column];
4178 unset($this->display_as[$column]);
4179 $this->display_as[$new_column] = $display_as;
4180 }
4181 else
4182 {
4183 $this->display_as[$new_column] = ucfirst(str_replace('_',' ',$column));
4184 }
4185
4186 $column = $new_column;
4187 $this->columns[$col_num] = $new_column;
4188 }
4189 }
4190 }
4191
4192 }
4193
4194 if(isset($this->display_as[$column]))
4195 $this->columns[$col_num] = (object)array('field_name' => $column, 'display_as' => $this->display_as[$column]);
4196 elseif(isset($field_types[$column]))
4197 $this->columns[$col_num] = (object)array('field_name' => $column, 'display_as' => $field_types[$column]->display_as);
4198 else
4199 $this->columns[$col_num] = (object)array('field_name' => $column, 'display_as' =>
4200 ucfirst(str_replace('_',' ',$column)));
4201
4202 if(!empty($this->unset_columns) && in_array($column,$this->unset_columns))
4203 {
4204 unset($this->columns[$col_num]);
4205 }
4206 }
4207
4208 $this->columns_checked = true;
4209
4210 }
4211
4212 return $this->columns;
4213 }
4214
4215 /**
4216 *
4217 * Enter description here ...
4218 */
4219 protected function get_add_fields()
4220 {
4221 if($this->add_fields_checked === false)
4222 {
4223 $field_types = $this->get_field_types();
4224 if(!empty($this->add_fields))
4225 {
4226 foreach($this->add_fields as $field_num => $field)
4227 {
4228 if(isset($this->display_as[$field]))
4229 $this->add_fields[$field_num] = (object)array('field_name' => $field, 'display_as' => $this->display_as[$field]);
4230 elseif(isset($field_types[$field]->display_as))
4231 $this->add_fields[$field_num] = (object)array('field_name' => $field, 'display_as' => $field_types[$field]->display_as);
4232 else
4233 $this->add_fields[$field_num] = (object)array('field_name' => $field, 'display_as' => ucfirst(str_replace('_',' ',$field)));
4234 }
4235 }
4236 else
4237 {
4238 $this->add_fields = array();
4239 foreach($field_types as $field)
4240 {
4241 //Check if an unset_add_field is initialize for this field name
4242 if($this->unset_add_fields !== null && is_array($this->unset_add_fields) && in_array($field->name,$this->unset_add_fields))
4243 continue;
4244
4245 if( (!isset($field->db_extra) || $field->db_extra != 'auto_increment') )
4246 {
4247 if(isset($this->display_as[$field->name]))
4248 $this->add_fields[] = (object)array('field_name' => $field->name, 'display_as' => $this->display_as[$field->name]);
4249 else
4250 $this->add_fields[] = (object)array('field_name' => $field->name, 'display_as' => $field->display_as);
4251 }
4252 }
4253 }
4254
4255 $this->add_fields_checked = true;
4256 }
4257 return $this->add_fields;
4258 }
4259
4260 /**
4261 *
4262 * Enter description here ...
4263 */
4264 protected function get_edit_fields()
4265 {
4266 if($this->edit_fields_checked === false)
4267 {
4268 $field_types = $this->get_field_types();
4269 if(!empty($this->edit_fields))
4270 {
4271 foreach($this->edit_fields as $field_num => $field)
4272 {
4273 if(isset($this->display_as[$field]))
4274 $this->edit_fields[$field_num] = (object)array('field_name' => $field, 'display_as' => $this->display_as[$field]);
4275 else
4276 $this->edit_fields[$field_num] = (object)array('field_name' => $field, 'display_as' => $field_types[$field]->display_as);
4277 }
4278 }
4279 else
4280 {
4281 $this->edit_fields = array();
4282 foreach($field_types as $field)
4283 {
4284 //Check if an unset_edit_field is initialize for this field name
4285 if($this->unset_edit_fields !== null && is_array($this->unset_edit_fields) && in_array($field->name,$this->unset_edit_fields))
4286 continue;
4287
4288 if(!isset($field->db_extra) || $field->db_extra != 'auto_increment')
4289 {
4290 if(isset($this->display_as[$field->name]))
4291 $this->edit_fields[] = (object)array('field_name' => $field->name, 'display_as' => $this->display_as[$field->name]);
4292 else
4293 $this->edit_fields[] = (object)array('field_name' => $field->name, 'display_as' => $field->display_as);
4294 }
4295 }
4296 }
4297
4298 $this->edit_fields_checked = true;
4299 }
4300 return $this->edit_fields;
4301 }
4302
4303 /**
4304 *
4305 * Enter description here ...
4306 */
4307 protected function get_read_fields()
4308 {
4309 if($this->read_fields_checked === false)
4310 {
4311 $field_types = $this->get_field_types();
4312 if(!empty($this->read_fields))
4313 {
4314 foreach($this->read_fields as $field_num => $field)
4315 {
4316 if(isset($this->display_as[$field]))
4317 $this->read_fields[$field_num] = (object)array('field_name' => $field, 'display_as' => $this->display_as[$field]);
4318 else
4319 $this->read_fields[$field_num] = (object)array('field_name' => $field, 'display_as' => $field_types[$field]->display_as);
4320 }
4321 }
4322 else
4323 {
4324 $this->read_fields = array();
4325 foreach($field_types as $field)
4326 {
4327 //Check if an unset_read_field is initialize for this field name
4328 if($this->unset_read_fields !== null && is_array($this->unset_read_fields) && in_array($field->name,$this->unset_read_fields))
4329 continue;
4330
4331 if(!isset($field->db_extra) || $field->db_extra != 'auto_increment')
4332 {
4333 if(isset($this->display_as[$field->name]))
4334 $this->read_fields[] = (object)array('field_name' => $field->name, 'display_as' => $this->display_as[$field->name]);
4335 else
4336 $this->read_fields[] = (object)array('field_name' => $field->name, 'display_as' => $field->display_as);
4337 }
4338 }
4339 }
4340
4341 $this->read_fields_checked = true;
4342 }
4343 return $this->read_fields;
4344 }
4345
4346 public function order_by($order_by, $direction = 'asc')
4347 {
4348 $this->order_by = array($order_by,$direction);
4349
4350 return $this;
4351 }
4352
4353 public function where($key, $value = NULL, $escape = TRUE)
4354 {
4355 $this->where[] = array($key,$value,$escape);
4356
4357 return $this;
4358 }
4359
4360 public function or_where($key, $value = NULL, $escape = TRUE)
4361 {
4362 $this->or_where[] = array($key,$value,$escape);
4363
4364 return $this;
4365 }
4366
4367 public function like($field, $match = '', $side = 'both')
4368 {
4369 $this->like[] = array($field, $match, $side);
4370
4371 return $this;
4372 }
4373
4374 protected function having($key, $value = '', $escape = TRUE)
4375 {
4376 $this->having[] = array($key, $value, $escape);
4377
4378 return $this;
4379 }
4380
4381 protected function or_having($key, $value = '', $escape = TRUE)
4382 {
4383 $this->or_having[] = array($key, $value, $escape);
4384
4385 return $this;
4386 }
4387
4388 public function or_like($field, $match = '', $side = 'both')
4389 {
4390 $this->or_like[] = array($field, $match, $side);
4391
4392 return $this;
4393 }
4394
4395 public function limit($limit, $offset = '')
4396 {
4397 $this->limit = array($limit,$offset);
4398
4399 return $this;
4400 }
4401
4402 protected function _initialize_helpers()
4403 {
4404 $ci = &get_instance();
4405
4406 $ci->load->helper('url');
4407 $ci->load->helper('form');
4408 }
4409
4410 protected function _initialize_variables()
4411 {
4412 $ci = &get_instance();
4413 $ci->load->config('grocery_crud');
4414
4415 $this->config = (object)array();
4416
4417 /** Initialize all the config variables into this object */
4418 $this->config->default_language = $ci->config->item('grocery_crud_default_language');
4419 $this->config->date_format = $ci->config->item('grocery_crud_date_format');
4420 $this->config->default_per_page = $ci->config->item('grocery_crud_default_per_page');
4421 $this->config->file_upload_allow_file_types = $ci->config->item('grocery_crud_file_upload_allow_file_types');
4422 $this->config->file_upload_max_file_size = $ci->config->item('grocery_crud_file_upload_max_file_size');
4423 $this->config->default_text_editor = $ci->config->item('grocery_crud_default_text_editor');
4424 $this->config->text_editor_type = $ci->config->item('grocery_crud_text_editor_type');
4425 $this->config->character_limiter = $ci->config->item('grocery_crud_character_limiter');
4426 $this->config->dialog_forms = $ci->config->item('grocery_crud_dialog_forms');
4427 $this->config->paging_options = $ci->config->item('grocery_crud_paging_options');
4428 $this->config->default_theme = $ci->config->item('grocery_crud_default_theme');
4429 $this->config->environment = $ci->config->item('grocery_crud_environment');
4430 $this->config->xss_clean = $ci->config->item('grocery_crud_xss_clean');
4431
4432 /** Initialize default paths */
4433 $this->default_javascript_path = $this->default_assets_path.'/js';
4434 $this->default_css_path = $this->default_assets_path.'/css';
4435 $this->default_texteditor_path = $this->default_assets_path.'/texteditor';
4436 $this->default_theme_path = $this->default_assets_path.'/themes';
4437
4438 $this->character_limiter = $this->config->character_limiter;
4439
4440 if ($this->character_limiter === 0 || $this->character_limiter === '0') {
4441 $this->character_limiter = 1000000; //a very big number
4442 } elseif($this->character_limiter === null || $this->character_limiter === false) {
4443 $this->character_limiter = 30; //is better to have the number 30 rather than the 0 value
4444 }
4445
4446 if ($this->theme === null && !empty($this->config->default_theme)) {
4447 $this->set_theme($this->config->default_theme);
4448 }
4449 }
4450
4451 protected function _set_primary_keys_to_model()
4452 {
4453 if(!empty($this->primary_keys))
4454 {
4455 foreach($this->primary_keys as $primary_key)
4456 {
4457 $this->basic_model->set_primary_key($primary_key['field_name'],$primary_key['table_name']);
4458 }
4459 }
4460 }
4461
4462 /**
4463 * Initialize all the required libraries and variables before rendering
4464 */
4465 protected function pre_render()
4466 {
4467 $this->_initialize_variables();
4468 $this->_initialize_helpers();
4469 $this->_load_language();
4470 $this->state_code = $this->getStateCode();
4471
4472 if($this->basic_model === null)
4473 $this->set_default_Model();
4474
4475 $this->set_basic_db_table($this->get_table());
4476
4477 $this->_load_date_format();
4478
4479 $this->_set_primary_keys_to_model();
4480 }
4481
4482 /**
4483 *
4484 * Or else ... make it work! The web application takes decision of what to do and show it to the final user.
4485 * Without this function nothing works. Here is the core of grocery CRUD project.
4486 *
4487 * @access public
4488 */
4489 public function render()
4490 {
4491 $this->pre_render();
4492
4493 if( $this->state_code != 0 )
4494 {
4495 $this->state_info = $this->getStateInfo();
4496 }
4497 else
4498 {
4499 throw new Exception('The state is unknown , I don\'t know what I will do with your data!', 4);
4500 die();
4501 }
4502
4503 switch ($this->state_code) {
4504 case 15://success
4505 case 1://list
4506 if($this->unset_list)
4507 {
4508 throw new Exception('You don\'t have permissions for this operation', 14);
4509 die();
4510 }
4511
4512 if($this->theme === null)
4513 $this->set_theme($this->default_theme);
4514 $this->setThemeBasics();
4515
4516 $this->set_basic_Layout();
4517
4518 $state_info = $this->getStateInfo();
4519
4520 $this->showList(false,$state_info);
4521
4522 break;
4523
4524 case 2://add
4525 if($this->unset_add)
4526 {
4527 throw new Exception('You don\'t have permissions for this operation', 14);
4528 die();
4529 }
4530
4531 if($this->theme === null)
4532 $this->set_theme($this->default_theme);
4533 $this->setThemeBasics();
4534
4535 $this->set_basic_Layout();
4536
4537 $this->showAddForm();
4538
4539 break;
4540
4541 case 3://edit
4542 if($this->unset_edit)
4543 {
4544 throw new Exception('You don\'t have permissions for this operation', 14);
4545 die();
4546 }
4547
4548 if($this->theme === null)
4549 $this->set_theme($this->default_theme);
4550 $this->setThemeBasics();
4551
4552 $this->set_basic_Layout();
4553
4554 $state_info = $this->getStateInfo();
4555
4556 $this->showEditForm($state_info);
4557
4558 break;
4559
4560 case 4://delete
4561 if($this->unset_delete)
4562 {
4563 throw new Exception('This user is not allowed to do this operation', 14);
4564 die();
4565 }
4566
4567 $state_info = $this->getStateInfo();
4568 $delete_result = $this->db_delete($state_info);
4569
4570 $this->delete_layout( $delete_result );
4571 break;
4572
4573 case 5://insert
4574 if($this->unset_add)
4575 {
4576 throw new Exception('This user is not allowed to do this operation', 14);
4577 die();
4578 }
4579
4580 $state_info = $this->getStateInfo();
4581 $insert_result = $this->db_insert($state_info);
4582
4583 $this->insert_layout($insert_result);
4584 break;
4585
4586 case 6://update
4587 if($this->unset_edit)
4588 {
4589 throw new Exception('This user is not allowed to do this operation', 14);
4590 die();
4591 }
4592
4593 $state_info = $this->getStateInfo();
4594 $update_result = $this->db_update($state_info);
4595
4596 $this->update_layout( $update_result,$state_info);
4597 break;
4598
4599 case 7://ajax_list
4600
4601 if($this->unset_list)
4602 {
4603 throw new Exception('You don\'t have permissions for this operation', 14);
4604 die();
4605 }
4606
4607 if($this->theme === null)
4608 $this->set_theme($this->default_theme);
4609 $this->setThemeBasics();
4610
4611 $this->set_basic_Layout();
4612
4613 $state_info = $this->getStateInfo();
4614 $this->set_ajax_list_queries($state_info);
4615
4616 $this->showList(true);
4617
4618 break;
4619
4620 case 8://ajax_list_info
4621
4622 if($this->theme === null)
4623 $this->set_theme($this->default_theme);
4624 $this->setThemeBasics();
4625
4626 $this->set_basic_Layout();
4627
4628 $state_info = $this->getStateInfo();
4629 $this->set_ajax_list_queries($state_info);
4630
4631 $this->showListInfo();
4632 break;
4633
4634 case 9://insert_validation
4635
4636 $validation_result = $this->db_insert_validation();
4637
4638 $this->validation_layout($validation_result);
4639 break;
4640
4641 case 10://update_validation
4642
4643 $validation_result = $this->db_update_validation();
4644
4645 $this->validation_layout($validation_result);
4646 break;
4647
4648 case 11://upload_file
4649
4650 $state_info = $this->getStateInfo();
4651
4652 $upload_result = $this->upload_file($state_info);
4653
4654 $this->upload_layout($upload_result, $state_info->field_name);
4655 break;
4656
4657 case 12://delete_file
4658 $state_info = $this->getStateInfo();
4659
4660 $delete_file_result = $this->delete_file($state_info);
4661
4662 $this->delete_file_layout($delete_file_result);
4663 break;
4664 /*
4665 case 13: //ajax_relation
4666 $state_info = $this->getStateInfo();
4667
4668 $ajax_relation_result = $this->ajax_relation($state_info);
4669
4670 $ajax_relation_result[""] = "";
4671
4672 echo json_encode($ajax_relation_result);
4673 die();
4674 break;
4675
4676 case 14: //ajax_relation_n_n
4677 echo json_encode(array("34" => 'Johnny' , "78" => "Test"));
4678 die();
4679 break;
4680 */
4681 case 16: //export to excel
4682 //a big number just to ensure that the table characters will not be cutted.
4683 $this->character_limiter = 1000000;
4684
4685 if($this->unset_export)
4686 {
4687 throw new Exception('You don\'t have permissions for this operation', 15);
4688 die();
4689 }
4690
4691 if($this->theme === null)
4692 $this->set_theme($this->default_theme);
4693 $this->setThemeBasics();
4694
4695 $this->set_basic_Layout();
4696
4697 $state_info = $this->getStateInfo();
4698 $this->set_ajax_list_queries($state_info);
4699 $this->exportToExcel($state_info);
4700 break;
4701
4702 case 17: //print
4703 //a big number just to ensure that the table characters will not be cutted.
4704 $this->character_limiter = 1000000;
4705
4706 if($this->unset_print)
4707 {
4708 throw new Exception('You don\'t have permissions for this operation', 15);
4709 die();
4710 }
4711
4712 if($this->theme === null)
4713 $this->set_theme($this->default_theme);
4714 $this->setThemeBasics();
4715
4716 $this->set_basic_Layout();
4717
4718 $state_info = $this->getStateInfo();
4719 $this->set_ajax_list_queries($state_info);
4720 $this->print_webpage($state_info);
4721 break;
4722
4723 case grocery_CRUD_States::STATE_READ:
4724 if($this->unset_read)
4725 {
4726 throw new Exception('You don\'t have permissions for this operation', 14);
4727 die();
4728 }
4729
4730 if($this->theme === null)
4731 $this->set_theme($this->default_theme);
4732 $this->setThemeBasics();
4733
4734 $this->set_basic_Layout();
4735
4736 $state_info = $this->getStateInfo();
4737
4738 $this->showReadForm($state_info);
4739
4740 break;
4741
4742 case grocery_CRUD_States::STATE_DELETE_MULTIPLE:
4743
4744 if($this->unset_delete)
4745 {
4746 throw new Exception('This user is not allowed to do this operation');
4747 die();
4748 }
4749
4750 $state_info = $this->getStateInfo();
4751 $delete_result = $this->db_multiple_delete($state_info);
4752
4753 $this->delete_layout($delete_result);
4754
4755 break;
4756
4757 }
4758
4759 return $this->get_layout();
4760 }
4761
4762 protected function get_common_data()
4763 {
4764 $data = (object)array();
4765
4766 $data->subject = $this->subject;
4767 $data->subject_plural = $this->subject_plural;
4768
4769 return $data;
4770 }
4771
4772 /**
4773 *
4774 * Enter description here ...
4775 */
4776 public function callback_before_insert($callback = null)
4777 {
4778 $this->callback_before_insert = $callback;
4779
4780 return $this;
4781 }
4782
4783 /**
4784 *
4785 * Enter description here ...
4786 */
4787 public function callback_after_insert($callback = null)
4788 {
4789 $this->callback_after_insert = $callback;
4790
4791 return $this;
4792 }
4793
4794 /**
4795 *
4796 * Enter description here ...
4797 */
4798 public function callback_insert($callback = null)
4799 {
4800 $this->callback_insert = $callback;
4801
4802 return $this;
4803 }
4804
4805
4806 /**
4807 *
4808 * Enter description here ...
4809 */
4810 public function callback_before_update($callback = null)
4811 {
4812 $this->callback_before_update = $callback;
4813
4814 return $this;
4815 }
4816
4817 /**
4818 *
4819 * Enter description here ...
4820 */
4821 public function callback_after_update($callback = null)
4822 {
4823 $this->callback_after_update = $callback;
4824
4825 return $this;
4826 }
4827
4828
4829 /**
4830 *
4831 * Enter description here ...
4832 * @param mixed $callback
4833 */
4834 public function callback_update($callback = null)
4835 {
4836 $this->callback_update = $callback;
4837
4838 return $this;
4839 }
4840
4841 /**
4842 *
4843 * Enter description here ...
4844 */
4845 public function callback_before_delete($callback = null)
4846 {
4847 $this->callback_before_delete = $callback;
4848
4849 return $this;
4850 }
4851
4852 /**
4853 *
4854 * Enter description here ...
4855 */
4856 public function callback_after_delete($callback = null)
4857 {
4858 $this->callback_after_delete = $callback;
4859
4860 return $this;
4861 }
4862
4863 /**
4864 *
4865 * Enter description here ...
4866 */
4867 public function callback_delete($callback = null)
4868 {
4869 $this->callback_delete = $callback;
4870
4871 return $this;
4872 }
4873
4874 /**
4875 *
4876 * Enter description here ...
4877 * @param string $column
4878 * @param mixed $callback
4879 */
4880 public function callback_column($column ,$callback = null)
4881 {
4882 $this->callback_column[$column] = $callback;
4883
4884 return $this;
4885 }
4886
4887 /**
4888 *
4889 * Enter description here ...
4890 * @param string $field
4891 * @param mixed $callback
4892 */
4893 public function callback_field($field, $callback = null)
4894 {
4895 $this->callback_add_field[$field] = $callback;
4896 $this->callback_edit_field[$field] = $callback;
4897
4898 return $this;
4899 }
4900
4901 /**
4902 *
4903 * Enter description here ...
4904 * @param string $field
4905 * @param mixed $callback
4906 */
4907 public function callback_add_field($field, $callback = null)
4908 {
4909 $this->callback_add_field[$field] = $callback;
4910
4911 return $this;
4912 }
4913
4914 /**
4915 *
4916 * Enter description here ...
4917 * @param string $field
4918 * @param mixed $callback
4919 */
4920 public function callback_edit_field($field, $callback = null)
4921 {
4922 $this->callback_edit_field[$field] = $callback;
4923
4924 return $this;
4925 }
4926
4927 /**
4928 *
4929 * Callback that replace the default auto uploader
4930 *
4931 * @param mixed $callback
4932 * @return grocery_CRUD
4933 */
4934 public function callback_upload($callback = null)
4935 {
4936 $this->callback_upload = $callback;
4937
4938 return $this;
4939 }
4940
4941 /**
4942 *
4943 * A callback that triggered before the upload functionality. This callback is suggested for validation checks
4944 * @param mixed $callback
4945 * @return grocery_CRUD
4946 */
4947 public function callback_before_upload($callback = null)
4948 {
4949 $this->callback_before_upload = $callback;
4950
4951 return $this;
4952 }
4953
4954 /**
4955 *
4956 * A callback that triggered after the upload functionality
4957 * @param mixed $callback
4958 * @return grocery_CRUD
4959 */
4960 public function callback_after_upload($callback = null)
4961 {
4962 $this->callback_after_upload = $callback;
4963
4964 return $this;
4965
4966 }
4967
4968 /**
4969 *
4970 * Gets the basic database table of our crud.
4971 * @return string
4972 */
4973 public function get_table()
4974 {
4975 if($this->basic_db_table_checked)
4976 {
4977 return $this->basic_db_table;
4978 }
4979 elseif( $this->basic_db_table !== null )
4980 {
4981 if(!$this->table_exists($this->basic_db_table))
4982 {
4983 throw new Exception('The table name does not exist. Please check you database and try again.',11);
4984 die();
4985 }
4986 $this->basic_db_table_checked = true;
4987 return $this->basic_db_table;
4988 }
4989 else
4990 {
4991 //Last try , try to find the table from your view / function name!!! Not suggested but it works .
4992 $last_chance_table_name = $this->get_method_name();
4993 if($this->table_exists($last_chance_table_name))
4994 {
4995 $this->set_table($last_chance_table_name);
4996 }
4997 $this->basic_db_table_checked = true;
4998 return $this->basic_db_table;
4999
5000 }
5001
5002 return false;
5003 }
5004
5005 /**
5006 *
5007 * The field names of the required fields
5008 */
5009 public function required_fields()
5010 {
5011 $args = func_get_args();
5012
5013 if(isset($args[0]) && is_array($args[0]))
5014 {
5015 $args = $args[0];
5016 }
5017
5018 $this->required_fields = $args;
5019
5020 return $this;
5021 }
5022
5023 /**
5024 * Add the fields that they are as UNIQUE in the database structure
5025 *
5026 * @return grocery_CRUD
5027 */
5028 public function unique_fields()
5029 {
5030 $args = func_get_args();
5031
5032 if(isset($args[0]) && is_array($args[0]))
5033 {
5034 $args = $args[0];
5035 }
5036
5037 $this->_unique_fields = $args;
5038
5039 return $this;
5040 }
5041
5042 /**
5043 *
5044 * Sets the basic database table that we will get our data.
5045 * @param string $table_name
5046 * @return grocery_CRUD
5047 */
5048 public function set_table($table_name)
5049 {
5050 if(!empty($table_name) && $this->basic_db_table === null)
5051 {
5052 $this->basic_db_table = $table_name;
5053 }
5054 elseif(!empty($table_name))
5055 {
5056 throw new Exception('You have already insert a table name once...', 1);
5057 }
5058 else
5059 {
5060 throw new Exception('The table name cannot be empty.', 2);
5061 die();
5062 }
5063
5064 return $this;
5065 }
5066
5067 /**
5068 * Set a full URL path to this method.
5069 *
5070 * This method is useful when the path is not specified correctly.
5071 * Especially when we are using routes.
5072 * For example:
5073 * Let's say we have the path http://www.example.com/ however the original url path is
5074 * http://www.example.com/example/index . We have to specify the url so we can have
5075 * all the CRUD operations correctly.
5076 * The url path has to be set from this method like this:
5077 * <code>
5078 * $crud->set_crud_url_path(site_url('example/index'));
5079 * </code>
5080 *
5081 * @param string $crud_url_path
5082 * @param string $list_url_path
5083 * @return grocery_CRUD
5084 */
5085 public function set_crud_url_path($crud_url_path, $list_url_path = null)
5086 {
5087 $this->crud_url_path = $crud_url_path;
5088
5089 //If the list_url_path is empty so we are guessing that the list_url_path
5090 //will be the same with crud_url_path
5091 $this->list_url_path = !empty($list_url_path) ? $list_url_path : $crud_url_path;
5092
5093 return $this;
5094 }
5095
5096 /**
5097 *
5098 * Set a subject to understand what type of CRUD you use.
5099 * ----------------------------------------------------------------------------------------------
5100 * Subject_plural: Sets the subject to its plural form. For example the plural
5101 * of "Customer" is "Customers", "Product" is "Products"... e.t.c.
5102 * @example In this CRUD we work with the table db_categories. The $subject will be the 'Category'
5103 * and the $subject_plural will be 'Categories'
5104 * @param string $subject
5105 * @param string $subject_plural
5106 * @return grocery_CRUD
5107 */
5108 public function set_subject($subject, $subject_plural = null)
5109 {
5110 $this->subject = $subject;
5111 $this->subject_plural = $subject_plural === null ? $subject : $subject_plural;
5112
5113 return $this;
5114 }
5115
5116 /**
5117 *
5118 * Enter description here ...
5119 * @param $title
5120 * @param $image_url
5121 * @param $url
5122 * @param $css_class
5123 * @param $url_callback
5124 */
5125 public function add_action( $label, $image_url = '', $link_url = '', $css_class = '', $url_callback = null)
5126 {
5127 $unique_id = substr($label,0,1).substr(md5($label.$link_url),-8); //The unique id is used for class name so it must begin with a string
5128
5129 $this->actions[$unique_id] = (object)array(
5130 'label' => $label,
5131 'image_url' => $image_url,
5132 'link_url' => $link_url,
5133 'css_class' => $css_class,
5134 'url_callback' => $url_callback,
5135 'url_has_http' => substr($link_url,0,7) == 'http://' || substr($link_url,0,8) == 'https://' ? true : false
5136 );
5137
5138 return $this;
5139 }
5140
5141 /**
5142 *
5143 * Set a simple 1-n foreign key relation
5144 * @param string $field_name
5145 * @param string $related_table
5146 * @param string $related_title_field
5147 * @param mixed $where_clause
5148 * @param string $order_by
5149 * @return Grocery_CRUD
5150 */
5151 public function set_relation($field_name , $related_table, $related_title_field, $where_clause = null, $order_by = null)
5152 {
5153 $this->relation[$field_name] = array($field_name, $related_table,$related_title_field, $where_clause, $order_by);
5154 return $this;
5155 }
5156
5157 /**
5158 *
5159 * Sets a relation with n-n relationship.
5160 * @param string $field_name
5161 * @param string $relation_table
5162 * @param string $selection_table
5163 * @param string $primary_key_alias_to_this_table
5164 * @param string $primary_key_alias_to_selection_table
5165 * @param string $title_field_selection_table
5166 * @param string $priority_field_relation_table
5167 * @param mixed $where_clause
5168 * @return Grocery_CRUD
5169 */
5170 public function set_relation_n_n($field_name, $relation_table, $selection_table, $primary_key_alias_to_this_table, $primary_key_alias_to_selection_table , $title_field_selection_table , $priority_field_relation_table = null, $where_clause = null)
5171 {
5172 $this->relation_n_n[$field_name] =
5173 (object)array(
5174 'field_name' => $field_name,
5175 'relation_table' => $relation_table,
5176 'selection_table' => $selection_table,
5177 'primary_key_alias_to_this_table' => $primary_key_alias_to_this_table,
5178 'primary_key_alias_to_selection_table' => $primary_key_alias_to_selection_table ,
5179 'title_field_selection_table' => $title_field_selection_table ,
5180 'priority_field_relation_table' => $priority_field_relation_table,
5181 'where_clause' => $where_clause
5182 );
5183
5184 return $this;
5185 }
5186
5187 /**
5188 *
5189 * Transform a field to an upload field
5190 *
5191 * @param string $field_name
5192 * @param string $upload_path
5193 * @return Grocery_CRUD
5194 */
5195 public function set_field_upload($field_name, $upload_dir = '', $allowed_file_types = '')
5196 {
5197 $upload_dir = !empty($upload_dir) && substr($upload_dir,-1,1) == '/'
5198 ? substr($upload_dir,0,-1)
5199 : $upload_dir;
5200 $upload_dir = !empty($upload_dir) ? $upload_dir : 'assets/uploads/files';
5201
5202 /** Check if the upload Url folder exists. If not then throw an exception **/
5203 if (!is_dir(FCPATH.$upload_dir)) {
5204 throw new Exception("It seems that the folder \"".FCPATH.$upload_dir."\" for the field name
5205 \"".$field_name."\" doesn't exists. Please create the folder and try again.");
5206 }
5207
5208 $this->upload_fields[$field_name] = (object) array(
5209 'field_name' => $field_name,
5210 'upload_path' => $upload_dir,
5211 'allowed_file_types' => $allowed_file_types,
5212 'encrypted_field_name' => $this->_unique_field_name($field_name));
5213 return $this;
5214 }
5215}
5216
5217if(defined('CI_VERSION'))
5218{
5219 $ci = &get_instance();
5220 $ci->load->library('Form_validation');
5221
5222 class grocery_CRUD_Form_validation extends CI_Form_validation{
5223
5224 public $CI;
5225 public $_field_data = array();
5226 public $_config_rules = array();
5227 public $_error_array = array();
5228 public $_error_messages = array();
5229 public $_error_prefix = '<p>';
5230 public $_error_suffix = '</p>';
5231 public $error_string = '';
5232 public $_safe_form_data = FALSE;
5233 }
5234}
5235
5236/*
5237 * jQuery File Upload Plugin PHP Example 5.5
5238 * https://github.com/blueimp/jQuery-File-Upload
5239 *
5240 * Copyright 2010, Sebastian Tschan
5241 * https://blueimp.net
5242 *
5243 * Licensed under the MIT license:
5244 * http://www.opensource.org/licenses/MIT
5245 */
5246
5247class UploadHandler
5248{
5249 private $options;
5250 public $default_config_path = null;
5251
5252 function __construct($options=null) {
5253 $this->options = array(
5254 'script_url' => $this->getFullUrl().'/'.basename(__FILE__),
5255 'upload_dir' => dirname(__FILE__).'/files/',
5256 'upload_url' => $this->getFullUrl().'/files/',
5257 'param_name' => 'files',
5258 // The php.ini settings upload_max_filesize and post_max_size
5259 // take precedence over the following max_file_size setting:
5260 'max_file_size' => null,
5261 'min_file_size' => 1,
5262 'accept_file_types' => '/.+$/i',
5263 'max_number_of_files' => null,
5264 // Set the following option to false to enable non-multipart uploads:
5265 'discard_aborted_uploads' => true,
5266 // Set to true to rotate images based on EXIF meta data, if available:
5267 'orient_image' => false,
5268 'image_versions' => array(
5269 // Uncomment the following version to restrict the size of
5270 // uploaded images. You can also add additional versions with
5271 // their own upload directories:
5272 /*
5273 'large' => array(
5274 'upload_dir' => dirname(__FILE__).'/files/',
5275 'upload_url' => dirname($_SERVER['PHP_SELF']).'/files/',
5276 'max_width' => 1920,
5277 'max_height' => 1200
5278 ),
5279
5280 'thumbnail' => array(
5281 'upload_dir' => dirname(__FILE__).'/thumbnails/',
5282 'upload_url' => $this->getFullUrl().'/thumbnails/',
5283 'max_width' => 80,
5284 'max_height' => 80
5285 )
5286 */
5287 )
5288 );
5289 if ($options) {
5290 // Or else for PHP >= 5.3.0 use: $this->options = array_replace_recursive($this->options, $options);
5291 foreach($options as $option_name => $option)
5292 {
5293 $this->options[$option_name] = $option;
5294 }
5295 }
5296 }
5297
5298 function getFullUrl() {
5299 return
5300 (isset($_SERVER['HTTPS']) ? 'https://' : 'http://').
5301 (isset($_SERVER['REMOTE_USER']) ? $_SERVER['REMOTE_USER'].'@' : '').
5302 (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : ($_SERVER['SERVER_NAME'].
5303 (isset($_SERVER['HTTPS']) && $_SERVER['SERVER_PORT'] === 443 ||
5304 $_SERVER['SERVER_PORT'] === 80 ? '' : ':'.$_SERVER['SERVER_PORT']))).
5305 substr($_SERVER['SCRIPT_NAME'],0, strrpos($_SERVER['SCRIPT_NAME'], '/'));
5306 }
5307
5308 private function get_file_object($file_name) {
5309 $file_path = $this->options['upload_dir'].$file_name;
5310 if (is_file($file_path) && $file_name[0] !== '.') {
5311 $file = new stdClass();
5312 $file->name = $file_name;
5313 $file->size = filesize($file_path);
5314 $file->url = $this->options['upload_url'].rawurlencode($file->name);
5315 foreach($this->options['image_versions'] as $version => $options) {
5316 if (is_file($options['upload_dir'].$file_name)) {
5317 $file->{$version.'_url'} = $options['upload_url']
5318 .rawurlencode($file->name);
5319 }
5320 }
5321 $file->delete_url = $this->options['script_url']
5322 .'?file='.rawurlencode($file->name);
5323 $file->delete_type = 'DELETE';
5324 return $file;
5325 }
5326 return null;
5327 }
5328
5329 private function get_file_objects() {
5330 return array_values(array_filter(array_map(
5331 array($this, 'get_file_object'),
5332 scandir($this->options['upload_dir'])
5333 )));
5334 }
5335
5336 private function create_scaled_image($file_name, $options) {
5337 $file_path = $this->options['upload_dir'].$file_name;
5338 $new_file_path = $options['upload_dir'].$file_name;
5339 list($img_width, $img_height) = @getimagesize($file_path);
5340 if (!$img_width || !$img_height) {
5341 return false;
5342 }
5343 $scale = min(
5344 $options['max_width'] / $img_width,
5345 $options['max_height'] / $img_height
5346 );
5347 if ($scale > 1) {
5348 $scale = 1;
5349 }
5350 $new_width = $img_width * $scale;
5351 $new_height = $img_height * $scale;
5352 $new_img = @imagecreatetruecolor($new_width, $new_height);
5353 switch (strtolower(substr(strrchr($file_name, '.'), 1))) {
5354 case 'jpg':
5355 case 'jpeg':
5356 $src_img = @imagecreatefromjpeg($file_path);
5357 $write_image = 'imagejpeg';
5358 break;
5359 case 'gif':
5360 @imagecolortransparent($new_img, @imagecolorallocate($new_img, 0, 0, 0));
5361 $src_img = @imagecreatefromgif($file_path);
5362 $write_image = 'imagegif';
5363 break;
5364 case 'png':
5365 @imagecolortransparent($new_img, @imagecolorallocate($new_img, 0, 0, 0));
5366 @imagealphablending($new_img, false);
5367 @imagesavealpha($new_img, true);
5368 $src_img = @imagecreatefrompng($file_path);
5369 $write_image = 'imagepng';
5370 break;
5371 default:
5372 $src_img = $image_method = null;
5373 }
5374 $success = $src_img && @imagecopyresampled(
5375 $new_img,
5376 $src_img,
5377 0, 0, 0, 0,
5378 $new_width,
5379 $new_height,
5380 $img_width,
5381 $img_height
5382 ) && $write_image($new_img, $new_file_path);
5383 // Free up memory (imagedestroy does not delete files):
5384 @imagedestroy($src_img);
5385 @imagedestroy($new_img);
5386 return $success;
5387 }
5388
5389 private function has_error($uploaded_file, $file, $error) {
5390 if ($error) {
5391 switch($error) {
5392 case UPLOAD_ERR_INI_SIZE:
5393 return 'The uploaded file exceeds the upload_max_filesize directive in php.ini.';
5394 break;
5395 case UPLOAD_ERR_PARTIAL:
5396 return 'The uploaded file was only partially uploaded.';
5397 break;
5398 case UPLOAD_ERR_NO_FILE:
5399 return 'No file was uploaded.';
5400 break;
5401 case UPLOAD_ERR_CANT_WRITE:
5402 return 'Failed to write file to disk.';
5403 break;
5404 case UPLOAD_ERR_EXTENSION:
5405 return 'File upload stopped by extension.';
5406 break;
5407 default:
5408 return $error;
5409 break;
5410 }
5411 }
5412 if (!preg_match($this->options['accept_file_types'], $file->name)) {
5413 return 'acceptFileTypes';
5414 }
5415 if ($uploaded_file && is_uploaded_file($uploaded_file)) {
5416 $file_size = filesize($uploaded_file);
5417 } else {
5418 $file_size = $_SERVER['CONTENT_LENGTH'];
5419 }
5420
5421 if ($this->options['max_file_size'] && (
5422 $file_size > $this->options['max_file_size'] ||
5423 $file->size > $this->options['max_file_size'])
5424 ) {
5425 return 'maxFileSize';
5426 }
5427 if ($this->options['min_file_size'] &&
5428 $file_size < $this->options['min_file_size']) {
5429 return 'minFileSize';
5430 }
5431 if (is_int($this->options['max_number_of_files']) && (
5432 count($this->get_file_objects()) >= $this->options['max_number_of_files'])
5433 ) {
5434 return 'maxNumberOfFiles';
5435 }
5436 return $error;
5437 }
5438
5439 private function trim_file_name($name, $type) {
5440 // Remove path information and dots around the filename, to prevent uploading
5441 // into different directories or replacing hidden system files.
5442 // Also remove control characters and spaces (\x00..\x20) around the filename:
5443 $file_name = trim(basename(stripslashes($name)), ".\x00..\x20");
5444 // Add missing file extension for known image types:
5445 if (strpos($file_name, '.') === false &&
5446 preg_match('/^image\/(gif|jpe?g|png)/', $type, $matches)) {
5447 $file_name .= '.'.$matches[1];
5448 }
5449
5450 //Ensure that we don't have disallowed characters and add a unique id just to ensure that the file name will be unique
5451 $file_name = substr(uniqid(),-5).'-'.$this->_transliterate_characters($file_name);
5452
5453 //all the characters has to be lowercase
5454 $file_name = strtolower($file_name);
5455
5456 return $file_name;
5457 }
5458
5459 private function _transliterate_characters($file_name)
5460 {
5461 include($this->default_config_path.'/translit_chars.php');
5462 if ( isset($translit_characters))
5463 {
5464 $file_name = preg_replace(array_keys($translit_characters), array_values($translit_characters), $file_name);
5465 }
5466
5467 $file_name = preg_replace("/([^a-zA-Z0-9\.\-\_]+?){1}/i", '-', $file_name);
5468 $file_name = str_replace(" ", "-", $file_name);
5469
5470 return preg_replace('/\-+/', '-', trim($file_name, '-'));
5471 }
5472
5473 private function orient_image($file_path) {
5474 $exif = exif_read_data($file_path);
5475 $orientation = intval(@$exif['Orientation']);
5476 if (!in_array($orientation, array(3, 6, 8))) {
5477 return false;
5478 }
5479 $image = @imagecreatefromjpeg($file_path);
5480 switch ($orientation) {
5481 case 3:
5482 $image = @imagerotate($image, 180, 0);
5483 break;
5484 case 6:
5485 $image = @imagerotate($image, 270, 0);
5486 break;
5487 case 8:
5488 $image = @imagerotate($image, 90, 0);
5489 break;
5490 default:
5491 return false;
5492 }
5493 $success = imagejpeg($image, $file_path);
5494 // Free up memory (imagedestroy does not delete files):
5495 @imagedestroy($image);
5496 return $success;
5497 }
5498
5499 private function handle_file_upload($uploaded_file, $name, $size, $type, $error) {
5500 $file = new stdClass();
5501 $file->name = $this->trim_file_name($name, $type);
5502 $file->size = intval($size);
5503 $file->type = $type;
5504 $error = $this->has_error($uploaded_file, $file, $error);
5505 if (!$error && $file->name) {
5506 $file_path = $this->options['upload_dir'].$file->name;
5507 $append_file = !$this->options['discard_aborted_uploads'] &&
5508 is_file($file_path) && $file->size > filesize($file_path);
5509 clearstatcache();
5510 if ($uploaded_file && is_uploaded_file($uploaded_file)) {
5511 // multipart/formdata uploads (POST method uploads)
5512 if ($append_file) {
5513 file_put_contents(
5514 $file_path,
5515 fopen($uploaded_file, 'r'),
5516 FILE_APPEND
5517 );
5518 } else {
5519 move_uploaded_file($uploaded_file, $file_path);
5520 }
5521 } else {
5522 // Non-multipart uploads (PUT method support)
5523 file_put_contents(
5524 $file_path,
5525 fopen('php://input', 'r'),
5526 $append_file ? FILE_APPEND : 0
5527 );
5528 }
5529 $file_size = filesize($file_path);
5530 if ($file_size === $file->size) {
5531 if ($this->options['orient_image']) {
5532 $this->orient_image($file_path);
5533 }
5534 $file->url = $this->options['upload_url'].rawurlencode($file->name);
5535 foreach($this->options['image_versions'] as $version => $options) {
5536 if ($this->create_scaled_image($file->name, $options)) {
5537 $file->{$version.'_url'} = $options['upload_url']
5538 .rawurlencode($file->name);
5539 }
5540 }
5541 } else if ($this->options['discard_aborted_uploads']) {
5542 unlink($file_path);
5543 $file->error = "It seems that this user doesn't have permissions to upload to this folder";
5544 }
5545 $file->size = $file_size;
5546 $file->delete_url = $this->options['script_url']
5547 .'?file='.rawurlencode($file->name);
5548 $file->delete_type = 'DELETE';
5549 } else {
5550 $file->error = $error;
5551 }
5552 return $file;
5553 }
5554
5555 public function get() {
5556 $file_name = isset($_REQUEST['file']) ?
5557 basename(stripslashes($_REQUEST['file'])) : null;
5558 if ($file_name) {
5559 $info = $this->get_file_object($file_name);
5560 } else {
5561 $info = $this->get_file_objects();
5562 }
5563 header('Content-type: application/json');
5564 echo json_encode($info);
5565 }
5566
5567 public function post() {
5568 if (isset($_REQUEST['_method']) && $_REQUEST['_method'] === 'DELETE') {
5569 return $this->delete();
5570 }
5571 $upload = isset($_FILES[$this->options['param_name']]) ?
5572 $_FILES[$this->options['param_name']] : null;
5573 $info = array();
5574 if ($upload && is_array($upload['tmp_name'])) {
5575 foreach ($upload['tmp_name'] as $index => $value) {
5576 $info[] = $this->handle_file_upload(
5577 $upload['tmp_name'][$index],
5578 isset($_SERVER['HTTP_X_FILE_NAME']) ?
5579 $_SERVER['HTTP_X_FILE_NAME'] : $upload['name'][$index],
5580 isset($_SERVER['HTTP_X_FILE_SIZE']) ?
5581 $_SERVER['HTTP_X_FILE_SIZE'] : $upload['size'][$index],
5582 isset($_SERVER['HTTP_X_FILE_TYPE']) ?
5583 $_SERVER['HTTP_X_FILE_TYPE'] : $upload['type'][$index],
5584 $upload['error'][$index]
5585 );
5586 }
5587 } elseif ($upload || isset($_SERVER['HTTP_X_FILE_NAME'])) {
5588 $info[] = $this->handle_file_upload(
5589 isset($upload['tmp_name']) ? $upload['tmp_name'] : null,
5590 isset($_SERVER['HTTP_X_FILE_NAME']) ?
5591 $_SERVER['HTTP_X_FILE_NAME'] : $upload['name'],
5592 isset($_SERVER['HTTP_X_FILE_SIZE']) ?
5593 $_SERVER['HTTP_X_FILE_SIZE'] : $upload['size'],
5594 isset($_SERVER['HTTP_X_FILE_TYPE']) ?
5595 $_SERVER['HTTP_X_FILE_TYPE'] : $upload['type'],
5596 isset($upload['error']) ? $upload['error'] : null
5597 );
5598 }
5599 header('Vary: Accept');
5600
5601 $redirect = isset($_REQUEST['redirect']) ?
5602 stripslashes($_REQUEST['redirect']) : null;
5603 if ($redirect) {
5604 header('Location: '.sprintf($redirect, rawurlencode($json)));
5605 return;
5606 }
5607 if (isset($_SERVER['HTTP_ACCEPT']) &&
5608 (strpos($_SERVER['HTTP_ACCEPT'], 'application/json') !== false)) {
5609 header('Content-type: application/json');
5610 } else {
5611 header('Content-type: text/plain');
5612 }
5613 return $info;
5614 }
5615
5616 public function delete() {
5617 $file_name = isset($_REQUEST['file']) ?
5618 basename(stripslashes($_REQUEST['file'])) : null;
5619 $file_path = $this->options['upload_dir'].$file_name;
5620 $success = is_file($file_path) && $file_name[0] !== '.' && unlink($file_path);
5621 if ($success) {
5622 foreach($this->options['image_versions'] as $version => $options) {
5623 $file = $options['upload_dir'].$file_name;
5624 if (is_file($file)) {
5625 unlink($file);
5626 }
5627 }
5628 }
5629 header('Content-type: application/json');
5630 echo json_encode($success);
5631 }
5632
5633}