PageRenderTime 57ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/application/libraries/Extended_Grocery_CRUD.php

https://github.com/coderkid/No-CMS
PHP | 815 lines | 748 code | 35 blank | 32 comment | 29 complexity | ebc25f4b76001d67091a785b3897e879 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, GPL-2.0
  1. <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
  2. /**
  3. * Extension of grocery_CRUD
  4. *
  5. * A proper way of extending Grocery CRUD
  6. *
  7. * @package Extension of grocery_CRUD
  8. * @copyright -
  9. * @license -
  10. * @version 1.0
  11. * @author -
  12. */
  13. class Extended_Grocery_CRUD extends Grocery_CRUD{
  14. public $form_validation;
  15. protected $_ci = null;
  16. protected $extension_extras=array();
  17. protected $callback_before_insert_ext=array();
  18. protected $callback_after_insert_ext=array();
  19. protected $callback_insert_ext=array();
  20. protected $callback_before_update_ext=array();
  21. protected $callback_after_update_ext=array();
  22. protected $callback_update_ext=array();
  23. protected $callback_before_delete_ext=array();
  24. protected $callback_after_delete_ext=array();
  25. protected $callback_delete_ext=array();
  26. protected $callback_post_render=array();
  27. // fix issue http://www.grocerycrud.com/forums/topic/1975-bug-in-the-search/
  28. protected $unsearchable_field = array();
  29. public function __construct(){
  30. parent::__construct();
  31. $this->_ci = &get_instance();
  32. }
  33. /* Extra field types Functions
  34. */
  35. public function field_type_ext($field , $type, $extras = null){
  36. if($field && $type){
  37. switch ($type) {
  38. case 'yes_no':
  39. $this->field_type($field,'dropdown', array('1' => 'Yes', '0' => 'No'));
  40. break;
  41. /*
  42. * If you want to add another field type
  43. * you just set the name in the case and
  44. * the functions inside it
  45. */
  46. default:
  47. # code...
  48. break;
  49. }
  50. }
  51. }
  52. // fix issue http://www.grocerycrud.com/forums/topic/1975-bug-in-the-search/
  53. public function unset_search_field($field){
  54. $this->unsearchable_field[] = $field;
  55. }
  56. public function get_actual_columns(){
  57. $field_types = $this->get_field_types();
  58. $actual_columns = array();
  59. foreach($field_types as $field) {
  60. if( isset($field->db_extra) && $field->db_extra != 'auto_increment' ){
  61. if(!in_array($field->name, $this->unsearchable_field)){
  62. $actual_columns[] = $field->name;
  63. }
  64. }
  65. }
  66. return $actual_columns;
  67. }
  68. protected function set_ajax_list_queries($state_info = null){
  69. if(!empty($state_info->per_page))
  70. {
  71. if(empty($state_info->page) || !is_numeric($state_info->page) )
  72. $this->limit($state_info->per_page);
  73. else
  74. {
  75. $limit_page = ( ($state_info->page-1) * $state_info->per_page );
  76. $this->limit($state_info->per_page, $limit_page);
  77. }
  78. }
  79. if(!empty($state_info->order_by))
  80. {
  81. $this->order_by($state_info->order_by[0],$state_info->order_by[1]);
  82. }
  83. if(!empty($state_info->search))
  84. {
  85. //Get the list of actual columns and then before adding it to search ..
  86. //compare it with the field ... does it exists? .. if yes.. great ..
  87. //go ahead and add it to search list.. if not.. just ignore it
  88. $actual_columns = $this->get_actual_columns();
  89. if(!empty($this->relation))
  90. foreach($this->relation as $relation_name => $relation_values)
  91. $temp_relation[$this->_unique_field_name($relation_name)] = $this->_get_field_names_to_search($relation_values);
  92. // get basic table name (added by gofrendi)
  93. $basic_table = $this->basic_db_table;
  94. if($state_info->search->field !== null)
  95. {
  96. if(isset($temp_relation[$state_info->search->field]))
  97. {
  98. if(is_array($temp_relation[$state_info->search->field]))
  99. foreach($temp_relation[$state_info->search->field] as $search_field)
  100. $this->or_like($search_field , $state_info->search->text);
  101. else
  102. $this->like($temp_relation[$state_info->search->field] , $state_info->search->text);
  103. }
  104. elseif(isset($this->relation_n_n[$state_info->search->field]))
  105. {
  106. $escaped_text = $this->basic_model->escape_str($state_info->search->text);
  107. $this->having($state_info->search->field." LIKE '%".$escaped_text."%'");
  108. }
  109. else
  110. {
  111. // added by gofrendi, to skip non actual column search
  112. if(array_search($state_info->search->field, $actual_columns) !== false) {
  113. $this->like($basic_table.'.'.$state_info->search->field , $state_info->search->text);
  114. }
  115. }
  116. }
  117. else
  118. {
  119. $columns = $this->get_columns();
  120. $search_text = $state_info->search->text;
  121. if(!empty($this->where))
  122. foreach($this->where as $where){
  123. $this->basic_model->having($where[0],$where[1],$where[2]);
  124. }
  125. foreach($columns as $column)
  126. {
  127. if(isset($temp_relation[$column->field_name]))
  128. {
  129. if(is_array($temp_relation[$column->field_name]))
  130. {
  131. foreach($temp_relation[$column->field_name] as $search_field)
  132. {
  133. $this->or_like($search_field, $search_text);
  134. }
  135. }
  136. else
  137. {
  138. $this->or_like($temp_relation[$column->field_name], $search_text);
  139. }
  140. }
  141. elseif(isset($this->relation_n_n[$column->field_name]))
  142. {
  143. //@todo have a where for the relation_n_n statement
  144. $escaped_text = $this->basic_model->escape_str($state_info->search->text);
  145. list($field_name, $relation_table, $selection_table, $primary_key_alias_to_this_table,
  146. $primary_key_alias_to_selection_table, $title_field_selection_table, $priority_field_relation_table) = array_values((array)$this->relation_n_n[$column->field_name]);
  147. $primary_key_selection_table = $this->basic_model->get_primary_key($selection_table);
  148. $field = "";
  149. $use_template = strpos($title_field_selection_table,'{') !== false;
  150. $field_name_hash = $this->_unique_field_name($title_field_selection_table);
  151. if($use_template)
  152. {
  153. $title_field_selection_table = str_replace(" ", "&nbsp;", $title_field_selection_table);
  154. $field .= $this->basic_model->build_concat_from_template($this->protect_identifiers($title_field_selection_table));
  155. //$field .= "CONCAT('".str_replace(array('{','}'),array("',COALESCE(",", ''),'"),str_replace("'","\\'",$this->protect_identifiers($title_field_selection_table)))."')";
  156. }
  157. else
  158. {
  159. $field .= $this->basic_model->protect_identifiers($selection_table.'.'.$title_field_selection_table);
  160. }
  161. //$subquery = $this->basic_model->build_relation_n_n_subquery($field, $selection_table, $relation_table, $primary_key_alias_to_selection_table, $primary_key_selection_table, $primary_key_alias_to_this_table, $field_name);
  162. $subquery = "(SELECT GROUP_CONCAT(DISTINCT ".$this->basic_model->protect_identifiers($field).") FROM ".$this->basic_model->protect_identifiers($selection_table)
  163. ." LEFT JOIN ".$this->basic_model->protect_identifiers($relation_table)
  164. ." ON ".$this->basic_model->protect_identifiers($relation_table.".".$primary_key_alias_to_selection_table)." = ".$this->basic_model->protect_identifiers($selection_table.".".$primary_key_selection_table)
  165. ." WHERE ".$this->basic_model->protect_identifiers($relation_table.".".$primary_key_alias_to_this_table)." = ".$this->basic_model->protect_identifiers($this->basic_db_table.".".$this->basic_model->get_primary_key($this->basic_db_table))
  166. ." GROUP BY ".$this->basic_model->protect_identifiers($relation_table.".".$primary_key_alias_to_this_table).") ";
  167. $this->or_where($subquery." LIKE '%".$escaped_text."%'", NULL, FALSE);
  168. }
  169. else
  170. {
  171. if(array_search($column->field_name, $actual_columns) === false) {
  172. continue;
  173. }
  174. $this->or_like($basic_table.'.'.$column->field_name, $search_text);
  175. }
  176. }
  177. }
  178. }
  179. }
  180. // fix issue of NULL unique field (it is possible). The property_exists function is more robbust than isset
  181. protected function db_update_validation()
  182. {
  183. $validation_result = (object)array('success'=>false);
  184. $field_types = $this->get_field_types();
  185. $required_fields = $this->required_fields;
  186. $unique_fields = $this->_unique_fields;
  187. $edit_fields = $this->get_edit_fields();
  188. if(!empty($required_fields))
  189. {
  190. foreach($edit_fields as $edit_field)
  191. {
  192. $field_name = $edit_field->field_name;
  193. if(!isset($this->validation_rules[$field_name]) && in_array( $field_name, $required_fields) )
  194. {
  195. $this->set_rules( $field_name, $field_types[$field_name]->display_as, 'required');
  196. }
  197. }
  198. }
  199. /** Checking for unique fields. If the field value is not unique then
  200. * return a validation error straight away, if not continue... */
  201. if(!empty($unique_fields))
  202. {
  203. $form_validation = $this->form_validation();
  204. $form_validation_check = false;
  205. foreach($edit_fields as $edit_field)
  206. {
  207. $field_name = $edit_field->field_name;
  208. if(in_array( $field_name, $unique_fields) )
  209. {
  210. $state_info = $this->getStateInfo();
  211. $primary_key = $this->get_primary_key();
  212. $field_name_value = $_POST[$field_name];
  213. $this->basic_model->where($primary_key,$state_info->primary_key);
  214. $row = $this->basic_model->get_row();
  215. if(!property_exists($row, $field_name)) {
  216. throw new Exception("The field name doesn't exist in the database. ".
  217. "Please use the unique fields only for fields ".
  218. "that exist in the database");
  219. }
  220. $previous_field_name_value = $row->$field_name;
  221. if(!empty($previous_field_name_value) && $previous_field_name_value != $field_name_value) {
  222. $form_validation->set_rules( $field_name,
  223. $field_types[$field_name]->display_as,
  224. 'is_unique['.$this->basic_db_table.'.'.$field_name.']');
  225. $form_validation_check = true;
  226. }
  227. }
  228. }
  229. if($form_validation_check && !$form_validation->run())
  230. {
  231. $validation_result->error_message = $form_validation->error_string();
  232. $validation_result->error_fields = $form_validation->_error_array;
  233. return $validation_result;
  234. }
  235. }
  236. if(!empty($this->validation_rules))
  237. {
  238. $form_validation = $this->form_validation();
  239. $edit_fields = $this->get_edit_fields();
  240. foreach($edit_fields as $edit_field)
  241. {
  242. $field_name = $edit_field->field_name;
  243. if(isset($this->validation_rules[$field_name]))
  244. {
  245. $rule = $this->validation_rules[$field_name];
  246. $form_validation->set_rules($rule['field'],$rule['label'],$rule['rules']);
  247. }
  248. }
  249. if($form_validation->run())
  250. {
  251. $validation_result->success = true;
  252. }
  253. else
  254. {
  255. $validation_result->error_message = $form_validation->error_string();
  256. $validation_result->error_fields = $form_validation->_error_array;
  257. }
  258. }
  259. else
  260. {
  261. $validation_result->success = true;
  262. }
  263. return $validation_result;
  264. }
  265. /**********************/
  266. /* Soft Delete Setter
  267. * When is called, overrides the default delete function with another that only sets a field named 'deleted' to 1.
  268. */
  269. public function set_soft_delete($field='deleted', $deleted_value=1){
  270. if(!$field){
  271. $field='deleted';
  272. }
  273. $this->extension_extras['soft_delete']['field']=$field;
  274. $this->extension_extras['soft_delete']['deleted_value']=$deleted_value;
  275. $this->callback_delete(array($this,'soft_delete_me'));
  276. }
  277. public function soft_delete_me($primary_key){
  278. $field=$this->extension_extras['soft_delete']['field'];
  279. $value=$this->extension_extras['soft_delete']['deleted_value'];
  280. return $this->_ci->db->update($this->basic_db_table,array($field => $value),array($this->get_primary_key() => $primary_key));
  281. }
  282. /************************************************/
  283. /* APPEND FIELD Functions
  284. * Append at the End. Eliminate repetitions.
  285. */
  286. public function append_fields(){
  287. $args = func_get_args();
  288. if(isset($args[0]) && is_array($args[0]))
  289. {
  290. $args = $args[0];
  291. }
  292. $this->add_fields = array_unique(array_merge($this->add_fields,$args));
  293. $this->edit_fields = array_unique(array_merge($this->edit_fields,$args));
  294. return $this;
  295. }
  296. public function append_add_fields() {
  297. $args = func_get_args();
  298. if(isset($args[0]) && is_array($args[0]))
  299. {
  300. $args = $args[0];
  301. }
  302. $this->add_fields = array_unique(array_merge($this->add_fields,$args));
  303. return $this;
  304. }
  305. public function append_edit_fields(){
  306. $args = func_get_args();
  307. if(isset($args[0]) && is_array($args[0]))
  308. {
  309. $args = $args[0];
  310. }
  311. $this->edit_fields = array_unique(array_merge($this->edit_fields,$args));
  312. return $this;
  313. }
  314. /********************************************************/
  315. /* Prepend FIELD Functions
  316. * Append at the Beginning. Eliminate repetitions.
  317. */
  318. public function prepend_fields(){
  319. $args = func_get_args();
  320. if(isset($args[0]) && is_array($args[0]))
  321. {
  322. $args = $args[0];
  323. }
  324. $this->add_fields = array_unique(array_merge($args,$this->add_fields));
  325. $this->edit_fields = array_unique(array_merge($args,$this->edit_fields));
  326. return $this;
  327. }
  328. public function prepend_add_fields(){
  329. $args = func_get_args();
  330. if(isset($args[0]) && is_array($args[0]))
  331. {
  332. $args = $args[0];
  333. }
  334. $this->add_fields = array_unique(array_merge($args,$this->add_fields));
  335. return $this;
  336. }
  337. public function prepend_edit_fields(){
  338. $args = func_get_args();
  339. if(isset($args[0]) && is_array($args[0]))
  340. {
  341. $args = $args[0];
  342. }
  343. $this->edit_fields = array_unique(array_merge($args,$this->edit_fields));
  344. return $this;
  345. }
  346. /********************************************************/
  347. /* Append After FIELD Functions
  348. * Append after first field in parameters. Eliminate repetitions.
  349. */
  350. public function append_fields_after(){
  351. $args = func_get_args();
  352. if(func_num_args ()>1){
  353. $after_field=$args[0];
  354. if(isset($args[1]) && is_array($args[1])){
  355. $args = $args[1];
  356. }else{
  357. unset($args[0]);
  358. }
  359. $this->append_add_fields_after($after_field,$args);
  360. $this->append_edit_fields_after($after_field,$args);
  361. }
  362. return $this;
  363. }
  364. public function append_add_fields_after(){
  365. $args = func_get_args();
  366. if(func_num_args ()>1){
  367. $after_field=$args[0];
  368. if(isset($args[1]) && is_array($args[1])){
  369. $args = $args[1];
  370. }else{
  371. unset($args[0]);
  372. }
  373. $split_key=array_search($after_field, $this->add_fields);
  374. if($split_key!==FALSE){
  375. $add_fields_array=array_diff($this->add_fields, $args);
  376. $first_fields_list = array_slice($add_fields_array, 0, $split_key+1);
  377. $middle_fields_list = $args;
  378. $last_fields_list = array_slice($add_fields_array, $split_key);
  379. $this->add_fields = array_unique(array_merge($first_fields_list,$middle_fields_list,$last_fields_list));
  380. }else{
  381. $this->append_add_fields($args);
  382. }
  383. }
  384. return $this;
  385. }
  386. public function append_edit_fields_after(){
  387. $args = func_get_args();
  388. if(func_num_args ()>1){
  389. $after_field=$args[0];
  390. if(isset($args[1]) && is_array($args[1])){
  391. $args = $args[1];
  392. }else{
  393. unset($args[0]);
  394. }
  395. $split_key=array_search($after_field, $this->edit_fields);
  396. if($split_key!==FALSE){
  397. $edit_fields_array=array_diff($this->edit_fields, $args);
  398. $first_fields_list = array_slice($edit_fields_array, 0, $split_key+1);
  399. $middle_fields_list = $args;
  400. $last_fields_list = array_slice($edit_fields_array, $split_key);
  401. $this->edit_fields = array_unique(array_merge($first_fields_list,$middle_fields_list,$last_fields_list));
  402. }else{
  403. $this->append_edit_fields($args);
  404. }
  405. }
  406. return $this;
  407. }
  408. /********************************************************/
  409. /* APPEND COLUMNS Function
  410. * Append at the End. Eliminate repetitions.
  411. */
  412. public function append_columns(){
  413. $args = func_get_args();
  414. if(isset($args[0]) && is_array($args[0])){
  415. $args = $args[0];
  416. }
  417. $this->columns = array_unique(array_merge($this->columns,$args));
  418. return $this;
  419. }
  420. /* APPEND COLUMNS Function
  421. * Append at the Beginning. Eliminate repetitions.
  422. */
  423. public function prepend_columns(){
  424. $args = func_get_args();
  425. if(isset($args[0]) && is_array($args[0])){
  426. $args = $args[0];
  427. }
  428. $this->columns = array_unique(array_merge($args,$this->columns));
  429. return $this;
  430. }
  431. /***************************************/
  432. /* REMOVE FIELD Functions
  433. * Removes the fields passed as parameters from the actual field list
  434. */
  435. public function remove_fields(){
  436. $args = func_get_args();
  437. if(isset($args[0]) && is_array($args[0]))
  438. {
  439. $args = $args[0];
  440. }
  441. $this->add_fields = array_unique(array_diff($this->add_fields,$args));
  442. $this->edit_fields = array_unique(array_diff($this->edit_fields,$args));
  443. return $this;
  444. }
  445. public function remove_add_fields(){
  446. $args = func_get_args();
  447. if(isset($args[0]) && is_array($args[0]))
  448. {
  449. $args = $args[0];
  450. }
  451. $this->add_fields = array_unique(array_diff($this->add_fields,$args));
  452. return $this;
  453. }
  454. public function remove_edit_fields(){
  455. $args = func_get_args();
  456. if(isset($args[0]) && is_array($args[0]))
  457. {
  458. $args = $args[0];
  459. }
  460. $this->edit_fields = array_unique(array_diff($this->edit_fields,$args));
  461. return $this;
  462. }
  463. /********************************************************/
  464. /* REMOVE COLUMNS Function
  465. * Removes the columns passed as parameters from the actual columns list
  466. */
  467. public function remove_columns(){
  468. $args = func_get_args();
  469. if(isset($args[0]) && is_array($args[0])){
  470. $args = $args[0];
  471. }
  472. $this->columns = array_unique(array_diff($this->columns,$args));
  473. return $this;
  474. }
  475. /***************************************/
  476. /* Extended Callback Functions
  477. * Replace the standar callbacks so you can queue many of them
  478. */
  479. /***** INSERT ******/
  480. public function callback_before_insert($callback = null,$override_all=0){
  481. if(!$override_all){
  482. $this->callback_before_insert_ext[] = $callback;
  483. if($this->callback_before_insert == null){
  484. $this->callback_before_insert = array($this,'extended_callback_before_insert');
  485. }
  486. }else{
  487. parent::callback_before_insert($callback);
  488. }
  489. return $this;
  490. }
  491. protected function extended_callback_before_insert($post_array){
  492. foreach ($this->callback_before_insert_ext as $key => $callback) {
  493. if(is_array($post_array)){
  494. $post_array = call_user_func($callback, $post_array);
  495. }
  496. }
  497. return $post_array;
  498. }
  499. public function callback_after_insert($callback = null,$override_all=0){
  500. if(!$override_all){
  501. $this->callback_after_insert_ext[] = $callback;
  502. if($this->callback_after_insert == null){
  503. $this->callback_after_insert = array($this,'extended_callback_after_insert');
  504. }
  505. }else{
  506. parent::callback_after_insert($callback);
  507. }
  508. return $this;
  509. }
  510. protected function extended_callback_after_insert($post_array,$primary_key){
  511. $continue=1;
  512. foreach ($this->callback_after_insert_ext as $key => $callback) {
  513. if($continue){
  514. $continue = call_user_func($callback, $post_array,$primary_key);
  515. }
  516. }
  517. return $post_array;
  518. }
  519. /***** UPDATE ******/
  520. public function callback_before_update($callback = null,$override_all=0){
  521. if(!$override_all){
  522. $this->callback_before_update_ext[] = $callback;
  523. if($this->callback_before_update == null){
  524. $this->callback_before_update = array($this,'extended_callback_before_update');
  525. }
  526. }else{
  527. parent::callback_before_update($callback);
  528. }
  529. return $this;
  530. }
  531. protected function extended_callback_before_update($post_array, $primary_key){
  532. foreach ($this->callback_before_update_ext as $key => $callback) {
  533. if(is_array($post_array)){
  534. $post_array = call_user_func($callback, $post_array, $primary_key);
  535. }
  536. }
  537. return $post_array;
  538. }
  539. public function callback_after_update($callback = null,$override_all=0){
  540. if(!$override_all){
  541. $this->callback_after_update_ext[] = $callback;
  542. if($this->callback_after_update == null){
  543. $this->callback_after_update = array($this,'extended_callback_after_update');
  544. }
  545. }else{
  546. parent::callback_after_update($callback);
  547. }
  548. return $this;
  549. }
  550. protected function extended_callback_after_update($post_array,$primary_key){
  551. $continue=1;
  552. foreach ($this->callback_after_update_ext as $key => $callback) {
  553. if($continue){
  554. $continue = call_user_func($callback, $post_array,$primary_key);
  555. }
  556. }
  557. return $continue;
  558. }
  559. /***** DELETE ******/
  560. public function callback_before_delete($callback = null,$override_all=0){
  561. if(!$override_all){
  562. $this->callback_before_delete_ext[] = $callback;
  563. if($this->callback_before_delete == null){
  564. $this->callback_before_delete = array($this,'extended_callback_before_delete');
  565. }
  566. }else{
  567. parent::callback_before_delete($callback);
  568. }
  569. return $this;
  570. }
  571. protected function extended_callback_before_delete($primary_key){
  572. $continue=1;
  573. foreach ($this->callback_before_delete_ext as $key => $callback) {
  574. if($continue){
  575. $continue = call_user_func($callback, $primary_key);
  576. }
  577. }
  578. return $continue;
  579. }
  580. public function callback_after_delete($callback = null,$override_all=0){
  581. if(!$override_all){
  582. $this->callback_after_delete_ext[] = $callback;
  583. if($this->callback_after_delete == null){
  584. $this->callback_after_delete = array($this,'extended_callback_after_delete');
  585. }
  586. }else{
  587. parent::callback_after_delete($callback);
  588. }
  589. return $this;
  590. }
  591. protected function extended_callback_after_delete($primary_key){
  592. $continue=1;
  593. foreach ($this->callback_after_delete_ext as $key => $callback) {
  594. if($continue){
  595. $continue = call_user_func($callback, $primary_key);
  596. }
  597. }
  598. return $continue;
  599. }
  600. public function callback_post_render($callback = null,$override_all=0){
  601. if(!$override_all){
  602. $this->callback_post_render[] = $callback;
  603. }else{
  604. $this->callback_post_render = array();
  605. $this->callback_post_render[] = $callback;
  606. }
  607. return $this;
  608. }
  609. protected function post_render(){
  610. $output=$this->get_layout();
  611. if(count($this->callback_post_render)){
  612. foreach ($this->callback_post_render as $key => $callback) {
  613. $output = call_user_func($callback, $output);
  614. }
  615. }
  616. return $output;
  617. }
  618. public function render(){
  619. parent::render();
  620. return $this->post_render();
  621. }
  622. /***************************************/
  623. /***************************************/
  624. /***************************************/
  625. /* EXAMPLE OF BASIC SETUPS USE*/
  626. public function basic_gc_config($table_name, $content_public_name, $template='twitter-bootstrap'){
  627. $this->set_theme($template);
  628. $this->set_table($table_name)
  629. ->set_subject($content_public_name);
  630. $this->set_soft_delete();
  631. $this->columns('name','created','public');
  632. $this->field_type_ext('public','yes_no');
  633. $this->required_fields('name');
  634. $this->fields(
  635. 'name',
  636. 'public'
  637. );
  638. }
  639. }