PageRenderTime 72ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/fuel/modules/fuel/controllers/module.php

https://github.com/jamiegrand/FUEL-CMS
PHP | 2196 lines | 1570 code | 352 blank | 274 comment | 215 complexity | 3bd821c5ec692350b17014ffd41530ad MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. require_once(FUEL_PATH.'/libraries/Fuel_base_controller.php');
  3. class Module extends Fuel_base_controller {
  4. public $module_obj; // the module object
  5. public $module = ''; // the name of the module
  6. public $uploaded_data = array(); // reference to the uploaded data
  7. protected $_orig_post = array(); // used for reference
  8. function __construct($validate = TRUE)
  9. {
  10. parent::__construct($validate);
  11. $this->load->module_model(FUEL_FOLDER, 'fuel_archives_model');
  12. if (empty($this->module))
  13. {
  14. $this->module = fuel_uri_segment(1);
  15. }
  16. if (empty($this->module))
  17. {
  18. show_error(lang('cannot_determine_module'));
  19. }
  20. $params = array();
  21. if ($this->fuel->modules->exists($this->module, FALSE))
  22. {
  23. $this->module_obj = $this->fuel->modules->get($this->module, FALSE);
  24. $params = $this->module_obj->info();
  25. }
  26. else if ($this->fuel->modules->exists($this->module.'_'.fuel_uri_segment(2), FALSE))
  27. {
  28. // if it is a module with multiple controllers, then we'll check first and second FUEL segment with an underscore'
  29. $this->module = $this->module.'_'.fuel_uri_segment(2);
  30. if ($this->fuel->modules->exists($this->module, FALSE))
  31. {
  32. $this->module_obj = $this->fuel->modules->get($this->module, FALSE);
  33. $params = $this->module_obj->info();
  34. }
  35. }
  36. else if ($this->fuel->modules->exists(fuel_uri_segment(2), FALSE))
  37. {
  38. $this->module = fuel_uri_segment(2);
  39. $this->module_obj = $this->fuel->modules->get($this->module, FALSE);
  40. if ($this->module_obj)
  41. {
  42. $mod_name = $this->module_obj->name();
  43. }
  44. if (empty($mod_name))
  45. {
  46. show_error(lang('error_missing_module', fuel_uri_segment(1)));
  47. }
  48. unset($mod_name);
  49. $params = $this->module_obj->info();
  50. }
  51. // stop here if the module is disabled
  52. if ($params['disabled'] === TRUE)
  53. {
  54. show_404();
  55. }
  56. foreach($params as $key => $val)
  57. {
  58. $this->$key = $val;
  59. }
  60. // load any configuration
  61. if (!empty($this->configuration))
  62. {
  63. if (is_array($this->configuration))
  64. {
  65. $config_module = key($this->configuration);
  66. $config_file = current($this->configuration);
  67. $this->config->module_load($config_module, $config_file);
  68. }
  69. else
  70. {
  71. $this->config->load($this->configuration);
  72. }
  73. }
  74. // load any language
  75. if (!empty($this->language))
  76. {
  77. if (is_array($this->language))
  78. {
  79. $lang_module = key($this->language);
  80. $lang_file = current($this->language);
  81. // now check to see if we need to load the language file or not...
  82. // we load the main language file automatically with the Fuel_base_controller.php
  83. $this->load->module_language($lang_module, $lang_file, $this->fuel->auth->user_lang());
  84. }
  85. else
  86. {
  87. $this->load->language($this->language);
  88. }
  89. }
  90. // load the model
  91. if (!empty($this->model_location))
  92. {
  93. $this->load->module_model($this->model_location, $this->model_name);
  94. }
  95. else
  96. {
  97. $this->load->model($this->model_name);
  98. }
  99. // get the model name
  100. $model_parts = explode('/', $this->model_name);
  101. $model = end($model_parts);
  102. // set the module_uri
  103. if (empty($this->module_uri)) $this->module_uri = $this->module;
  104. $this->js_controller_params['module'] = $this->module_uri;
  105. if (!empty($model))
  106. {
  107. $this->model =& $this->$model;
  108. }
  109. else
  110. {
  111. show_error(lang('incorrect_route_to_module'));
  112. }
  113. // global variables
  114. $vars = array();
  115. if (!empty($params['js']))
  116. {
  117. if (is_string($params['js']))
  118. {
  119. $params['js'] = preg_split("/,\s*/", $params['js']);
  120. }
  121. $vars['js'] = $params['js'];
  122. }
  123. if (!empty($this->nav_selected)) $vars['nav_selected'] = $this->nav_selected;
  124. $this->load->vars($vars);
  125. $this->fuel->admin->load_js_localized($params['js_localized']);
  126. if (!empty($this->permission) AND $validate)
  127. {
  128. $this->_validate_user($this->permission);
  129. }
  130. }
  131. // --------------------------------------------------------------------
  132. /**
  133. * Displays the list (table) view
  134. *
  135. * @access public
  136. * @return void
  137. */
  138. function index()
  139. {
  140. $this->items();
  141. }
  142. // --------------------------------------------------------------------
  143. /**
  144. * Displays the list (table) view
  145. *
  146. * @access public
  147. * @return void
  148. */
  149. function items()
  150. {
  151. $this->load->library('data_table');
  152. // check the model for a filters method as well and merge it with the property value
  153. // added per http://www.getfuelcms.com/forums/discussion/760/filter-dropdown/#Item_2
  154. if (method_exists($this->model, 'filters'))
  155. {
  156. $this->filters = array_merge($this->filters, $this->model->filters($this->filters));
  157. }
  158. // set the language dropdown if there is a language column
  159. if ($this->fuel->language->has_multiple() AND !empty($this->language_col) AND method_exists($this->model, 'get_languages'))
  160. {
  161. $languages = $this->model->get_languages($this->language_col);
  162. $first_option = current($languages);
  163. if (!empty($languages) AND (is_string($first_option) OR (is_array($first_option)) AND count($first_option) > 1))
  164. {
  165. $lang_filter = array('type' => 'select', 'options' => $languages, 'label' => lang('label_language'), 'first_option' => lang('label_select_a_language'));
  166. $this->filters[$this->language_col.'_equal'] = $lang_filter;
  167. $this->model->add_filter_join($this->language_col.'_equal', 'and');
  168. }
  169. }
  170. $params = $this->_list_process();
  171. // save page state
  172. $this->fuel->admin->save_page_state($params);
  173. // create search filter
  174. $filters[$this->display_field] = trim($params['search_term']);
  175. // sort of hacky here... to make it easy for the model to just filter on the search term (like the users model)
  176. $this->model->filter_value = trim($params['search_term']);
  177. foreach($this->filters as $key => $val)
  178. {
  179. $filters[$key] = $params[$key];
  180. if (!empty($val['filter_join']))
  181. {
  182. if (!is_array($this->model->filter_join[$key]))
  183. {
  184. settype($this->model->filter_join, 'array');
  185. }
  186. $this->model->filter_join[$key] = $val['filter_join'];
  187. }
  188. }
  189. // set model filters before pagination and setting table data
  190. if (method_exists($this->model, 'add_filters'))
  191. {
  192. $this->model->add_filters($filters);
  193. }
  194. // to prevent it from being called unecessarility with ajax
  195. if (!is_ajax())
  196. {
  197. $this->config->set_item('enable_query_strings', FALSE);
  198. // pagination
  199. $query_str_arr = $this->input->get(NULL, TRUE);
  200. unset($query_str_arr['offset']);
  201. $query_str = (!empty($query_str_arr)) ? http_build_query($query_str_arr) : '';
  202. $config['base_url'] = fuel_url($this->module_uri).'/items/?'.$query_str;
  203. $uri_segment = 4 + (count(explode('/', $this->module_uri)) - 1);
  204. $config['total_rows'] = $this->model->list_items_total();
  205. $config['uri_segment'] = fuel_uri_index($uri_segment);
  206. $config['per_page'] = (int) $params['limit'];
  207. $config['query_string_segment'] = 'offset';
  208. $config['page_query_string'] = TRUE;
  209. $config['num_links'] = 5;
  210. $config['prev_link'] = lang('pagination_prev_page');
  211. $config['next_link'] = lang('pagination_next_page');
  212. $config['first_link'] = lang('pagination_first_link');
  213. $config['last_link'] = lang('pagination_last_link');
  214. // must reset these in case a config file has something different
  215. $config['full_tag_open'] = NULL;
  216. $config['full_tag_close'] = NULL;
  217. $config['full_tag_close'] = NULL;
  218. $config['num_tag_open'] = '&nbsp;';
  219. $config['num_tag_close'] = NULL;
  220. $config['cur_tag_open'] = '&nbsp;<strong>';
  221. $config['cur_tag_close'] = '</strong>';
  222. $config['next_tag_open'] = '&nbsp;';
  223. $config['next_tag_close'] = '&nbsp;';
  224. $config['prev_tag_open'] = '&nbsp;';
  225. $config['prev_tag_close'] = NULL;
  226. $config['first_tag_open'] = '&nbsp;';
  227. $config['first_tag_close'] = '&nbsp;';
  228. $config['last_tag_open'] = NULL;
  229. $config['last_tag_close'] = NULL;
  230. $this->pagination->initialize($config);
  231. if (method_exists($this->model, 'tree'))
  232. {
  233. //$vars['tree'] = "Loading...\n<ul></ul>\n";
  234. $vars['tree'] = "\n<ul></ul>\n";
  235. }
  236. // reset offset if total rows is less then limit
  237. if ($config['total_rows'] < $params['limit'])
  238. {
  239. $params['offset'] = 0;
  240. }
  241. }
  242. // set vars
  243. $vars['params'] = $params;
  244. $vars['table'] = '';
  245. // reload table
  246. if (is_ajax())
  247. {
  248. // data table items... check col value to know if we want to send sorting parameter
  249. if (empty($params['col']) OR empty($params['order']))
  250. {
  251. $items = $this->model->list_items($params['limit'], $params['offset']);
  252. }
  253. else
  254. {
  255. $items = $this->model->list_items($params['limit'], $params['offset'], $params['col'], $params['order']);
  256. $this->data_table->set_sorting($params['col'], $params['order']);
  257. }
  258. $has_edit_permission = $this->fuel->auth->has_permission($this->permission, "edit") ? '1' : '0';
  259. $has_delete_permission = $this->fuel->auth->has_permission($this->permission, "delete") ? '1' : '0';
  260. // set data table actions... look first for item_actions set in the fuel_modules
  261. $edit_func = '
  262. $CI =& get_instance();
  263. $link = "";';
  264. if ($has_edit_permission)
  265. {
  266. $edit_func .= 'if (isset($cols[$CI->model->key_field()]))
  267. {
  268. $url = fuel_url("'.$this->module_uri.'/edit/".$cols[$CI->model->key_field()]);
  269. $link = "<a href=\"".$url."\" class=\"action_delete\">".lang("table_action_delete")."</a>";
  270. $link .= " <input type=\"checkbox\" name=\"delete[".$cols[$CI->model->key_field()]."]\" value=\"1\" id=\"delete_".$cols[$CI->model->key_field()]."\" class=\"multi_delete\"/>";
  271. }';
  272. }
  273. $edit_func .= 'return $link;';
  274. $edit_func = create_function('$cols', $edit_func);
  275. // set data table actions... look first for item_actions set in the fuel_modules
  276. $delete_func = '
  277. $CI =& get_instance();
  278. $link = "";';
  279. if ($has_delete_permission)
  280. {
  281. $delete_func .= 'if (isset($cols[$CI->model->key_field()]))
  282. {
  283. $url = fuel_url("'.$this->module_uri.'/delete/".$cols[$CI->model->key_field()]);
  284. $link = "<a href=\"".$url."\" class=\"action_delete\">".lang("table_action_delete")."</a>";
  285. $link .= " <input type=\"checkbox\" name=\"delete[".$cols[$CI->model->key_field()]."]\" value=\"1\" id=\"delete_".$cols[$CI->model->key_field()]."\" class=\"multi_delete\"/>";
  286. }';
  287. }
  288. $delete_func .= 'return $link;';
  289. $delete_func = create_function('$cols', $delete_func);
  290. foreach($this->table_actions as $key => $val)
  291. {
  292. if (!is_int($key))
  293. {
  294. $action_type = 'url';
  295. $action_val = $this->table_actions[$key];
  296. $attrs = array();
  297. if (is_array($val))
  298. {
  299. if (isset($val['url']))
  300. {
  301. $action_type = 'url';
  302. $action_val = $val['url'];
  303. if (isset($val['attrs']))
  304. {
  305. $attrs = $val['attrs'];
  306. }
  307. }
  308. else
  309. {
  310. $action_type = key($val);
  311. $action_val = current($val);
  312. }
  313. $attrs = (isset($val['attrs'])) ? $val['attrs'] : array();
  314. }
  315. $this->data_table->add_action($key, $action_val, $action_type, $attrs);
  316. }
  317. else if (strtoupper($val) == 'EDIT')
  318. {
  319. if ($this->fuel->auth->has_permission($this->permission, "edit"))
  320. {
  321. $action_url = fuel_url($this->module_uri.'/edit/{'.$this->model->key_field().'}');
  322. $this->data_table->add_action(lang('table_action_edit'), $action_url, 'url');
  323. }
  324. }
  325. else if (strtoupper($val) == 'DELETE')
  326. {
  327. $this->data_table->add_action($val, $delete_func, 'func');
  328. }
  329. else
  330. {
  331. if (strtoupper($val) != 'VIEW' OR (!empty($this->preview_path) AND strtoupper($val) == 'VIEW'))
  332. {
  333. $action_name = lang('table_action_'.strtolower($val));
  334. if (empty($action_name)) $action_name = $val;
  335. $action_url = fuel_url($this->module_uri.'/'.strtolower($val).'/{'.$this->model->key_field().'}');
  336. $this->data_table->add_action($action_name, $action_url, 'url');
  337. }
  338. }
  339. }
  340. if (!$this->rows_selectable)
  341. {
  342. $this->data_table->id = 'data_table_noselect';
  343. $this->data_table->row_action = FALSE;
  344. }
  345. else
  346. {
  347. $this->data_table->row_action = TRUE;
  348. }
  349. $this->data_table->row_alt_class = 'alt';
  350. $this->data_table->only_data_fields = array($this->model->key_field());
  351. // Key and boolean fields are data only
  352. // $this->data_table->only_data_fields = array_merge(array($this->model->key_field()), $this->model->boolean_fields);
  353. $this->data_table->auto_sort = TRUE;
  354. $this->data_table->actions_field = 'last';
  355. $this->data_table->no_data_str = lang('no_data');
  356. $this->data_table->lang_prefix = 'form_label_';
  357. $this->data_table->row_id_key = $this->model->key_field();
  358. $boolean_fields = $this->model->boolean_fields;
  359. if (!in_array('published', $boolean_fields)) $boolean_fields[] = 'published';
  360. if (!in_array('active', $boolean_fields)) $boolean_fields[] = 'active';
  361. $has_publish_permission = ($this->fuel->auth->has_permission($this->permission, 'publish')) ? '1' : '0';
  362. $has_edit_permission = $this->fuel->auth->has_permission($this->permission, 'edit') ? '1' : '0';
  363. $no = lang("form_enum_option_no");
  364. $yes = lang("form_enum_option_yes");
  365. $col_txt = lang('click_to_toggle');
  366. $key_field = $this->model->key_field();
  367. $_publish_toggle_callback = '
  368. $can_publish = (($heading == "published" OR $heading == "active") AND '.$has_publish_permission.' OR
  369. (($heading != "published" AND $heading != "active") AND '.$has_edit_permission.'));
  370. $no = "'.$no.'";
  371. $yes = "'.$yes.'";
  372. $col_txt = "'.$col_txt.'";
  373. // boolean fields
  374. if (is_null($cols[$heading]) OR $cols[$heading] == "")
  375. {
  376. return "";
  377. }
  378. else if (!is_true_val($cols[$heading]))
  379. {
  380. $text_class = ($can_publish) ? "publish_text unpublished toggle_on" : "unpublished";
  381. $action_class = ($can_publish) ? "publish_action unpublished hidden" : "unpublished hidden";
  382. return \'<span class="publish_hover"><span class="\'.$text_class.\'" id="row_published_\'.$cols["'.$key_field.'"].\'" data-field="\'.$heading.\'">\'.$no.\'</span><span class="\'.$action_class.\'">\'.$col_txt.\'</span></span>\';
  383. }
  384. else
  385. {
  386. $text_class = ($can_publish) ? "publish_text published toggle_off" : "published";
  387. $action_class = ($can_publish) ? "publish_action published hidden" : "published hidden";
  388. return \'<span class="publish_hover"><span class="\'.$text_class.\'" id="row_published_\'.$cols["'.$key_field.'"].\'" data-field="\'.$heading.\'">\'.$yes.\'</span><span class="\'.$action_class.\'">\'.$col_txt.\'</span></span>\';
  389. }';
  390. $_publish_toggle_callback = create_function('$cols, $heading', $_publish_toggle_callback);
  391. foreach($boolean_fields as $bool)
  392. {
  393. $this->data_table->add_field_formatter($bool, $_publish_toggle_callback);
  394. }
  395. $this->data_table->auto_sort = TRUE;
  396. $heading_sort_func = (isset($this->disable_heading_sort) AND $this->disable_heading_sort) ? '' : 'fuel.sortList';
  397. $this->data_table->sort_js_func = $heading_sort_func;
  398. $this->data_table->assign_data($items, $this->table_headers);
  399. $vars['table'] = $this->data_table->render();
  400. if (!empty($items[0]) AND (!empty($this->precedence_col) AND isset($items[0][$this->precedence_col])))
  401. {
  402. $vars['params']['precedence'] = 1;
  403. }
  404. $this->load->module_view(FUEL_FOLDER, '_blocks/module_list_table', $vars);
  405. return;
  406. }
  407. else
  408. {
  409. $this->load->library('form_builder');
  410. $this->js_controller_params['method'] = 'items';
  411. $this->js_controller_params['precedence_col'] = $this->precedence_col;
  412. $vars['table'] = $this->load->module_view(FUEL_FOLDER, '_blocks/module_list_table', $vars, TRUE);
  413. $vars['pagination'] = $this->pagination->create_links();
  414. // for extra module 'filters'
  415. $field_values = array();
  416. foreach($this->filters as $key => $val)
  417. {
  418. $field_values[$key] = $params[$key];
  419. }
  420. $this->form_builder->question_keys = array();
  421. //$this->form_builder->hidden = (array) $this->model->key_field();
  422. $this->form_builder->label_layout = 'left';
  423. $this->form_builder->load_custom_fields(APPPATH.'config/custom_fields.php');
  424. $this->form_builder->set_validator($this->model->get_validation());
  425. $this->form_builder->submit_value = NULL;
  426. $this->form_builder->use_form_tag = FALSE;
  427. $this->form_builder->set_fields($this->filters);
  428. $this->form_builder->display_errors = FALSE;
  429. $this->form_builder->css_class = 'more_filters';
  430. if ($this->config->item('date_format'))
  431. {
  432. $this->form_builder->date_format = $this->config->item('date_format');
  433. }
  434. $this->form_builder->set_field_values($field_values);
  435. if (method_exists($this->model, 'friendly_filter_info'))
  436. {
  437. $friendly_filter_info = $this->model->friendly_filter_info($field_values);
  438. if ( ! empty($friendly_filter_info)) {
  439. $vars['info'] = $friendly_filter_info;
  440. }
  441. }
  442. // keycheck is already put in place by $this->form->close() in module_list layout
  443. $this->form_builder->key_check = FALSE;
  444. $vars['more_filters'] = $this->form_builder->render_divs();
  445. $vars['actions'] = $this->load->module_view(FUEL_FOLDER, '_blocks/module_list_actions', $vars, TRUE);
  446. $vars['form_action'] = $this->module_uri.'/items';
  447. $vars['form_method'] = 'get';
  448. $vars['query_string'] = $query_str;
  449. $vars['description'] = $this->description;
  450. $crumbs = array($this->module_uri => $this->module_name);
  451. $this->fuel->admin->set_titlebar($crumbs);
  452. $inline = $this->input->get('inline', TRUE);
  453. $this->fuel->admin->set_inline($inline);
  454. if ($inline === TRUE)
  455. {
  456. $this->fuel->admin->set_display_mode(Fuel_admin::DISPLAY_COMPACT_TITLEBAR);
  457. }
  458. $this->fuel->admin->render($this->views['list'], $vars);
  459. }
  460. }
  461. // --------------------------------------------------------------------
  462. /**
  463. * Displays the list (table) view but inline without the left menu
  464. *
  465. * @access public
  466. * @return void
  467. */
  468. function inline_items()
  469. {
  470. $this->items(TRUE);
  471. }
  472. // --------------------------------------------------------------------
  473. /**
  474. * Processes the list view filters and returns an array of parameters
  475. *
  476. * @access protected
  477. * @return array
  478. */
  479. protected function _list_process()
  480. {
  481. $this->load->library('pagination');
  482. $this->load->helper('convert');
  483. $this->load->helper('cookie');
  484. /* PROCESS PARAMS BEGIN */
  485. $filters = array();
  486. $page_state = $this->fuel->admin->get_page_state($this->module_uri);
  487. unset($page_state['offset']);
  488. $defaults = array();
  489. $defaults['col'] = (!empty($this->default_col)) ? $this->default_col : $this->display_field;
  490. $defaults['order'] = (!empty($this->default_order)) ? $this->default_order : 'asc';
  491. $defaults['offset'] = 0;
  492. $defaults['limit'] = key($this->limit_options);
  493. $defaults['search_term'] = '';
  494. $defaults['view_type'] = 'list';
  495. $defaults['extra_filters'] = array();
  496. $defaults['precedence'] = 0;
  497. //$defaults['language'] = '';
  498. // custom module filters defaults
  499. foreach($this->filters as $key => $val)
  500. {
  501. $defaults[$key] = (isset($val['default'])) ? $val['default'] : NULL;
  502. }
  503. $posted = array();
  504. if (!empty($_POST) OR !empty($_GET))
  505. {
  506. $posted['search_term'] = $this->input->get_post('search_term', TRUE);
  507. $posted_vars = array('col', 'order', 'limit', 'offset', 'precedence', 'view_type');
  508. foreach($posted_vars as $val)
  509. {
  510. if ($this->input->get_post($val)) $posted[$val] = $this->input->get_post($val, TRUE);
  511. }
  512. // custom module filters
  513. $extra_filters = array();
  514. foreach($this->filters as $key => $val)
  515. {
  516. if (isset($_POST[$key]) OR isset($_GET[$key]))
  517. {
  518. $posted[$key] = $this->input->get_post($key, TRUE);
  519. // get the raw key without the comparison operators that the model uses
  520. $raw_key = preg_replace(array('#_from$#', '#_fromequal$#', '#_to$#', '#_toequal$#', '#_equal$#'), '', $key);
  521. // manipulate the value if it's a date time field
  522. if (method_exists($this->model, 'field_type'))
  523. {
  524. $field_type = $this->model->field_type($raw_key);
  525. if (is_date_format($posted[$key]) AND $field_type == 'datetime' OR $field_type == 'date')
  526. {
  527. $date = ($this->input->get_post($key) AND is_date_format($this->input->get_post($key))) ? current(explode(" ", $this->input->get_post($key))) : "";
  528. $hr = ($this->input->get_post($key.'_hour') AND (int)$this->input->get_post($key.'_hour') > 0 AND (int)$this->input->get_post($key.'_hour') < 24) ? $this->input->get_post($key.'_hour') : "";
  529. $min = ($this->input->get_post($key.'_min') AND is_numeric($this->input->get_post($key.'_min'))) ? $this->input->get_post($key.'_min') : "00";
  530. $ampm = ($this->input->get_post($key.'_am_pm') AND $hr AND $min) ? $this->input->get_post($key.'_am_pm') : "";
  531. if (!empty($ampm) AND !empty($hr) AND $hr > 12)
  532. {
  533. if ($hr > 24)
  534. {
  535. $hr = "00";
  536. }
  537. else
  538. {
  539. $hr = (int) $hr - 12;
  540. $ampm = "pm";
  541. }
  542. }
  543. $posted[$key] = $date;
  544. if (!empty($hr)) $posted[$key] .= " ".$hr.":".$min.$ampm;
  545. $posted[$key] = date('Y-m-d H:i:s', strtotime($posted[$key]));
  546. }
  547. }
  548. $this->filters[$key]['value'] = $posted[$key];
  549. $extra_filters[$key] = $posted[$key];
  550. }
  551. }
  552. $posted['extra_filters'] = $extra_filters;
  553. }
  554. $params = array_merge($defaults, $page_state, $posted);
  555. //$params = array_merge($defaults, $uri_params, $posted);
  556. if ($params['search_term'] == lang('label_search')) $params['search_term'] = NULL;
  557. /* PROCESS PARAMS END */
  558. return $params;
  559. }
  560. // --------------------------------------------------------------------
  561. /**
  562. * Displays the tree view
  563. *
  564. * @access public
  565. * @return void
  566. */
  567. function items_tree()
  568. {
  569. // tree
  570. if (method_exists($this->model, 'tree') AND is_ajax())
  571. {
  572. $params = $this->_list_process();
  573. $this->load->library('menu');
  574. $this->menu->depth = NULL; // as deep as it goes
  575. $this->menu->use_titles = FALSE;
  576. $this->menu->root_value = 0;
  577. $this->model->add_filters($params['extra_filters']);
  578. $menu_items = $this->model->tree();
  579. if (!empty($menu_items))
  580. {
  581. $output = $this->menu->render($menu_items);
  582. }
  583. else
  584. {
  585. $output = '<div>'.lang('no_data').'</div>';
  586. }
  587. $this->output->set_output($output);
  588. }
  589. }
  590. // --------------------------------------------------------------------
  591. /**
  592. * Saves the precedence of fields
  593. *
  594. * @access public
  595. * @return void
  596. */
  597. function items_precedence()
  598. {
  599. if (is_ajax() AND !empty($_POST['data_table']) AND !empty($this->precedence_col))
  600. {
  601. if (is_array($_POST['data_table']))
  602. {
  603. $i = 0;
  604. foreach($_POST['data_table'] as $row)
  605. {
  606. if (!empty($row))
  607. {
  608. $values = array($this->precedence_col => $i);
  609. $where = array($this->model->key_field() => $row);
  610. $this->model->update($values, $where);
  611. }
  612. $i++;
  613. }
  614. // clear cache
  615. $this->_clear_cache();
  616. }
  617. }
  618. }
  619. // --------------------------------------------------------------------
  620. /**
  621. * Displays the fields to create a record (form view)
  622. *
  623. * @access public
  624. * @param string The name of a field, or fields spearated by colon to display in the form (optional)
  625. * @param string Determines whether to redirect the page after save or not
  626. * @return void
  627. */
  628. function create($field = NULL, $redirect = TRUE)
  629. {
  630. $id = NULL;
  631. // check that the action even exists and if not, show a 404
  632. if (!$this->fuel->auth->module_has_action('save'))
  633. {
  634. show_404();
  635. }
  636. // check permissions
  637. if (!$this->fuel->auth->has_permission($this->module_obj->permission, 'create'))
  638. {
  639. show_error(lang('error_no_permissions'));
  640. }
  641. $inline = $this->fuel->admin->is_inline();
  642. if (isset($_POST[$this->model->key_field()])) // check for dupes
  643. {
  644. if ($id = $this->_process_create() AND !has_errors())
  645. {
  646. if ($inline === TRUE)
  647. {
  648. $url = fuel_uri($this->module_uri.'/inline_edit/'.$id);
  649. }
  650. else
  651. {
  652. $url = fuel_uri($this->module_uri.'/edit/'.$id);
  653. }
  654. // save any tab states
  655. $this->_save_tab_state($id);
  656. if ($redirect)
  657. {
  658. if (!$this->fuel->admin->has_notification(Fuel_admin::NOTIFICATION_SUCCESS))
  659. {
  660. $this->fuel->admin->set_notification(lang('data_saved'), Fuel_admin::NOTIFICATION_SUCCESS);
  661. }
  662. redirect($url);
  663. }
  664. }
  665. }
  666. $shell_vars = $this->_shell_vars($id);
  667. $passed_init_vars = ($this->input->get(NULL, TRUE)) ? $this->input->get(NULL, TRUE) : array();
  668. $form_vars = $this->_form_vars($id, $passed_init_vars, FALSE, $inline);
  669. $vars = array_merge($shell_vars, $form_vars);
  670. $vars['action'] = 'create';
  671. $crumbs = array($this->module_uri => $this->module_name, lang('action_create'));
  672. $this->fuel->admin->set_titlebar($crumbs);
  673. $this->fuel->admin->set_inline($inline);
  674. if ($inline === TRUE)
  675. {
  676. $this->fuel->admin->set_display_mode(Fuel_admin::DISPLAY_COMPACT);
  677. }
  678. $vars['actions'] = $this->load->module_view(FUEL_FOLDER, '_blocks/module_inline_actions', $vars, TRUE);
  679. $this->fuel->admin->render($this->views['create_edit'], $vars);
  680. return $id;
  681. }
  682. // --------------------------------------------------------------------
  683. /**
  684. * The same as the create method but does not show the left menu
  685. *
  686. * @access public
  687. * @param string The name of a field, or fields spearated by colon to display in the form (optional)
  688. * @param string Determines whether to redirect the page after save or not
  689. * @return void
  690. */
  691. function inline_create($field = NULL)
  692. {
  693. $this->fuel->admin->set_inline(TRUE);
  694. $this->create($field);
  695. }
  696. // --------------------------------------------------------------------
  697. /**
  698. * Duplicates a record. Similar to edit but without the record ID attached.
  699. *
  700. * @access public
  701. * @return void
  702. */
  703. function duplicate()
  704. {
  705. $_POST[$this->model->key_field()] = 'dup';
  706. $this->create();
  707. }
  708. protected function _process_create()
  709. {
  710. // reset dup id
  711. if ($_POST[$this->model->key_field()] == 'dup')
  712. {
  713. $_POST[$this->model->key_field()] = '';
  714. // alter duplicate information if there is a hook
  715. $_POST = $this->model->on_duplicate($_POST);
  716. $this->load->library('form_builder');
  717. $fb = new Form_builder();
  718. $fb->load_custom_fields(APPPATH.'config/custom_fields.php');
  719. $fields = $this->model->form_fields($_POST);
  720. $fb->set_fields($fields);
  721. $fb->post_process_field_values();// manipulates the $_POST values directly
  722. }
  723. else
  724. {
  725. $this->model->on_before_post($this->input->post());
  726. $posted = $this->_process();
  727. // set publish status to no if you do not have the ability to publish
  728. if (!$this->fuel->auth->has_permission($this->permission, 'publish'))
  729. {
  730. $posted['published'] = 'no';
  731. $posted['active'] = 'no';
  732. }
  733. $model = $this->model;
  734. // run before_create hook
  735. $this->_run_hook('before_create', $posted);
  736. // run before_save hook
  737. $this->_run_hook('before_save', $posted);
  738. // save the data
  739. $id = $this->model->save($posted);
  740. if (empty($id))
  741. {
  742. add_error(lang('error_invalid_id'));
  743. return FALSE;
  744. }
  745. // add id value to the posted array
  746. if (!is_array($this->model->key_field()))
  747. {
  748. $posted[$this->model->key_field()] = $id;
  749. }
  750. // process $_FILES
  751. if (!$this->_process_uploads($posted))
  752. {
  753. return FALSE;
  754. }
  755. $this->model->on_after_post($posted);
  756. if (!$this->model->is_valid())
  757. {
  758. add_errors($this->model->get_errors());
  759. }
  760. else
  761. {
  762. // archive data
  763. $archive_data = $this->model->cleaned_data();
  764. $archive_data[$this->model->key_field()] = $id;
  765. if ($this->archivable) $this->model->archive($id, $archive_data);
  766. $data = $this->model->find_one_array(array($this->model->table_name().'.'.$this->model->key_field() => $id));
  767. // run after_create hook
  768. $this->_run_hook('after_create', $data);
  769. // run after_save hook
  770. $this->_run_hook('after_save', $data);
  771. if (!empty($data))
  772. {
  773. $msg = lang('module_edited', $this->module_name, $data[$this->display_field]);
  774. $this->fuel->logs->write($msg);
  775. $this->_clear_cache();
  776. return $id;
  777. }
  778. }
  779. }
  780. }
  781. // --------------------------------------------------------------------
  782. /**
  783. * Displays the fields to edit a record (form view)
  784. *
  785. * @access public
  786. * @param int The ID value of the record to edit
  787. * @param string The name of a field, or fields spearated by colon to display in the form (optional)
  788. * @param string Determines whether to redirect the page after save or not
  789. * @return void
  790. */
  791. function edit($id = NULL, $field = NULL, $redirect = TRUE)
  792. {
  793. // check that the action even exists and if not, show a 404
  794. if (!$this->fuel->auth->module_has_action('save') AND $this->displayonly === FALSE)
  795. {
  796. show_404();
  797. }
  798. // check permissions
  799. if (!$this->fuel->auth->has_permission($this->module_obj->permission, 'edit') AND !$this->fuel->auth->has_permission($this->module_obj->permission, 'create'))
  800. {
  801. show_error(lang('error_no_permissions'));
  802. }
  803. $inline = $this->fuel->admin->is_inline();
  804. if ($this->input->post($this->model->key_field()))
  805. {
  806. if ($this->_process_edit($id) AND !has_errors())
  807. {
  808. if ($inline === TRUE)
  809. {
  810. $url = fuel_uri($this->module_uri.'/inline_edit/'.$id.'/'.$field);
  811. }
  812. else
  813. {
  814. $url = fuel_uri($this->module_uri.'/edit/'.$id.'/'.$field);
  815. }
  816. if ($redirect)
  817. {
  818. if (!$this->fuel->admin->has_notification(Fuel_admin::NOTIFICATION_SUCCESS))
  819. {
  820. $this->fuel->admin->set_notification(lang('data_saved'), Fuel_admin::NOTIFICATION_SUCCESS);
  821. }
  822. redirect($url);
  823. }
  824. }
  825. }
  826. //$vars = $this->_form($id);
  827. $data = $this->_saved_data($id);
  828. $action = (!empty($data[$this->model->key_field()])) ? 'edit' : 'create';
  829. // substitute data values into preview path
  830. $this->preview_path = $this->module_obj->url($data);
  831. $shell_vars = $this->_shell_vars($id, $action);
  832. $form_vars = $this->_form_vars($id, $data, $field, $inline);
  833. $vars = array_merge($shell_vars, $form_vars);
  834. $vars['data'] = $data;
  835. $vars['action'] = $action;
  836. $vars['related_items'] = $this->model->related_items($data);
  837. // active or publish fields
  838. if (isset($data['published']))
  839. {
  840. $vars['publish'] = (!empty($data['published']) AND is_true_val($data['published'])) ? 'unpublish' : 'publish';
  841. }
  842. if (isset($data['active']))
  843. {
  844. $vars['activate'] = (!empty($data['active']) AND is_true_val($data['active'])) ? 'deactivate' : 'activate';
  845. }
  846. if (!empty($field))
  847. {
  848. $this->fuel->admin->set_display_mode(Fuel_admin::DISPLAY_COMPACT_NO_ACTION);
  849. }
  850. else if ($inline === TRUE)
  851. {
  852. $this->fuel->admin->set_display_mode(Fuel_admin::DISPLAY_COMPACT);
  853. }
  854. $crumbs = array($this->module_uri => $this->module_name);
  855. if (!empty($data[$this->display_field]))
  856. {
  857. $crumbs[''] = character_limiter(strip_tags($data[$this->display_field]), 50);
  858. }
  859. $this->fuel->admin->set_titlebar($crumbs);
  860. $vars['actions'] = $this->load->module_view(FUEL_FOLDER, '_blocks/module_create_edit_actions', $vars, TRUE);
  861. $this->fuel->admin->render($this->views['create_edit'], $vars);
  862. // do this after rendering so it doesn't render current page'
  863. if (!empty($data[$this->display_field]) AND $inline !== TRUE)
  864. {
  865. $this->fuel->admin->add_recent_page($this->uri->uri_string(), $this->module_name.': '.$data[$this->display_field], $this->module);
  866. }
  867. }
  868. // --------------------------------------------------------------------
  869. /**
  870. * The same as the edit method but does not show the left menu
  871. *
  872. * @access public
  873. * @param int The ID value of the record to edit
  874. * @param string The name of a field, or fields spearated by colon to display in the form (optional)
  875. * @return void
  876. */
  877. function inline_edit($id = NULL, $field = NULL)
  878. {
  879. if (empty($id))
  880. {
  881. show_404();
  882. }
  883. $this->fuel->admin->set_inline(TRUE);
  884. $this->edit($id, $field);
  885. }
  886. // --------------------------------------------------------------------
  887. /**
  888. * Processes the form data to save
  889. *
  890. * @access protected
  891. * @param int The ID value of the record to edit
  892. * @return boolean
  893. */
  894. protected function _process_edit($id)
  895. {
  896. $this->model->on_before_post($this->input->post());
  897. $posted = $this->_process();
  898. // run before_edit hook
  899. $this->_run_hook('before_edit', $posted);
  900. // run before_save hook
  901. $this->_run_hook('before_save', $posted);
  902. if ($this->model->save($posted))
  903. {
  904. // process $_FILES...
  905. if (!$this->_process_uploads($posted))
  906. {
  907. return FALSE;
  908. }
  909. $this->model->on_after_post($posted);
  910. if (!$this->model->is_valid())
  911. {
  912. add_errors($this->model->get_errors());
  913. }
  914. else
  915. {
  916. // archive data
  917. $archive_data = $this->model->cleaned_data();
  918. if ($this->archivable) $this->model->archive($id, $archive_data);
  919. $data = $this->model->find_one_array(array($this->model->table_name().'.'.$this->model->key_field() => $id));
  920. // run after_edit hook
  921. $this->_run_hook('after_edit', $data);
  922. // run after_save hook
  923. $this->_run_hook('after_save', $data);
  924. $msg = lang('module_edited', $this->module_name, $data[$this->display_field]);
  925. $this->fuel->logs->write($msg);
  926. $this->_clear_cache();
  927. return TRUE;
  928. }
  929. }
  930. return FALSE;
  931. }
  932. // --------------------------------------------------------------------
  933. /**
  934. * Sanitizes the input based on the module's settings
  935. *
  936. * @access protected
  937. * @param array The array of posted data to sanitize
  938. * @return array
  939. */
  940. protected function _sanitize($data)
  941. {
  942. $posted = $data;
  943. if (!empty($this->sanitize_input))
  944. {
  945. // functions that are valid for sanitizing
  946. $valid_funcs = $this->fuel->config('module_sanitize_funcs');
  947. if ($this->sanitize_input === TRUE)
  948. {
  949. foreach($data as $key => $val)
  950. {
  951. if (!empty($val))
  952. {
  953. $posted[$key] = xss_clean($val);
  954. }
  955. }
  956. }
  957. else
  958. {
  959. // force to array to normalize
  960. $sanitize_input = (array) $this->sanitize_input;
  961. if (is_array($data))
  962. {
  963. foreach($data as $key => $post)
  964. {
  965. if (is_array($post))
  966. {
  967. $posted[$key] = $this->_sanitize($data[$key]);
  968. }
  969. else
  970. {
  971. // loop through sanitzation functions
  972. foreach($sanitize_input as $func)
  973. {
  974. $func = (isset($valid_funcs[$func])) ? $valid_funcs[$func] : FALSE;
  975. if ($func)
  976. {
  977. $posted[$key] = $func($posted[$key]);
  978. }
  979. }
  980. }
  981. }
  982. }
  983. else
  984. {
  985. // loop through sanitzation functions
  986. foreach($sanitize_input as $key => $val)
  987. {
  988. $func = (isset($valid_funcs[$val])) ? $valid_funcs[$val] : FALSE;
  989. if ($func)
  990. {
  991. $posted = $func($posted);
  992. }
  993. }
  994. }
  995. }
  996. }
  997. return $posted;
  998. }
  999. // --------------------------------------------------------------------
  1000. /**
  1001. * Returns an array of shell variables to apply to the main area of the page
  1002. *
  1003. * @access protected
  1004. * @param int The ID value of the record to edit
  1005. * @param string The name of the action to apply to the main form element
  1006. * @return array
  1007. */
  1008. protected function _shell_vars($id = NULL, $action = 'create')
  1009. {
  1010. $model = $this->model;
  1011. $this->js_controller_params['method'] = 'add_edit';
  1012. $this->js_controller_params['linked_fields'] = $this->model->linked_fields;
  1013. // other variables
  1014. $vars['id'] = $id;
  1015. $vars['versions'] = ($this->displayonly === FALSE) ? $this->fuel_archives_model->options_list($id, $this->model->table_name()) : array();
  1016. $vars['others'] = $this->model->get_others($this->display_field, $id);
  1017. $vars['action'] = $action;
  1018. $vars['module'] = $this->module;
  1019. $vars['notifications'] = $this->load->module_view(FUEL_FOLDER, '_blocks/notifications', $vars, TRUE);
  1020. return $vars;
  1021. }
  1022. // --------------------------------------------------------------------
  1023. /**
  1024. * Returns an array of saved data based on the id value passed
  1025. *
  1026. * @access protected
  1027. * @param int The ID value of the record to edit
  1028. * @return array
  1029. */
  1030. protected function _saved_data($id)
  1031. {
  1032. if (empty($id)) return array();
  1033. $edit_method = $this->edit_method;
  1034. if ($edit_method != 'find_one_array')
  1035. {
  1036. $saved = $this->model->$edit_method($id);
  1037. }
  1038. else
  1039. {
  1040. $saved = $this->model->$edit_method(array($this->model->table_name().'.'.$this->model->key_field() => $id));
  1041. }
  1042. return $saved;
  1043. }
  1044. // seperated to make it easier in subclasses to use the form without rendering the page
  1045. protected function _form_vars($id = NULL, $values = array(), $field = NULL, $inline = FALSE)
  1046. {
  1047. $this->load->library('form_builder');
  1048. // load custom fields
  1049. $this->form_builder->load_custom_fields(APPPATH.'config/custom_fields.php');
  1050. $model = $this->model;
  1051. $this->js_controller_params['method'] = 'add_edit';
  1052. $action = (!empty($values[$this->model->key_field()])) ? 'edit' : 'create';
  1053. // create fields... start with the table info and go from there
  1054. $fields = (!empty($values)) ? $this->model->form_fields($values) : $this->model->form_fields($_POST);
  1055. // if field parameter is set, then we just display a single field
  1056. if (!empty($field))
  1057. {
  1058. // added per pierlo in Forum (http://www.getfuelcms.com/forums/discussion/673/fuel_helper-fuel_edit-markers)
  1059. $columns = explode(':', $field);
  1060. // special case if you use the word required
  1061. if (in_array('required', $columns))
  1062. {
  1063. $columns = array_merge($columns, $this->model->required);
  1064. }
  1065. // set them to hidden... just in case model hooks require the values to be passed on save
  1066. foreach($fields as $k => $f)
  1067. {
  1068. if (!in_array($k, $columns))
  1069. {
  1070. $fields[$k]['type'] = 'hidden';
  1071. }
  1072. if (count($columns) <= 1)
  1073. {
  1074. $fields[$k]['display_label'] = FALSE;
  1075. $fields[$k]['required'] = FALSE;
  1076. }
  1077. }
  1078. }
  1079. // set published/active to hidden since setting this is an buttton/action instead of a form field
  1080. $form = '';
  1081. if (is_array($fields))
  1082. {
  1083. $field_values = (!empty($_POST)) ? $_POST : $values;
  1084. $published_active = array(
  1085. 'publish' => 'published',
  1086. 'active' => 'activate'
  1087. );
  1088. foreach($published_active as $k => $v)
  1089. {
  1090. if (!$this->fuel->auth->has_permission($this->permission, $k))
  1091. {
  1092. unset($fields[$v]);
  1093. }
  1094. if (isset($fields[$v]) AND !empty($values[$v]))
  1095. {
  1096. $fields['published']['value'] = $values[$v];
  1097. }
  1098. }
  1099. $this->form_builder->set_validator($this->model->get_validation());
  1100. // add hidden field with the module name for convenience
  1101. $common_fields = $this->_common_fields($field_values);
  1102. $fields = array_merge($fields, $common_fields);
  1103. $fields['__fuel_inline_action__'] = array('type' => 'hidden');
  1104. $fields['__fuel_inline_action__']['class'] = '__fuel_inline_action__';
  1105. $fields['__fuel_inline_action__']['value'] = (empty($id)) ? 'create' : 'edit';
  1106. $fields['__fuel_inline__'] = array('type' => 'hidden');
  1107. $fields['__fuel_inline__']['value'] = ($inline) ? 1 : 0;
  1108. $this->form_builder->submit_value = lang('btn_save');
  1109. $this->form_builder->question_keys = array();
  1110. $this->form_builder->use_form_tag = FALSE;
  1111. $this->form_builder->hidden = (array) $this->model->key_field();
  1112. $this->form_builder->set_fields($fields);
  1113. $this->form_builder->display_errors = FALSE;
  1114. $this->form_builder->set_field_values($field_values);
  1115. if ($this->config->item('date_format'))
  1116. {
  1117. $this->form_builder->date_format = $this->config->item('date_format');
  1118. }
  1119. if ($inline)
  1120. {
  1121. $this->form_builder->cancel_value = lang('viewpage_close');
  1122. }
  1123. else
  1124. {
  1125. $this->form_builder->cancel_value = lang('btn_cancel');
  1126. }
  1127. // we will set this in the BaseFuelController.js file so that the jqx page variable is available upon execution of any form field js
  1128. //$this->form_builder->auto_execute_js = FALSE;
  1129. if (!isset($fields['__FORM_BUILDER__'], $fields['__FORM_BUILDER__']['displayonly']))
  1130. {
  1131. $this->form_builder->displayonly = $this->displayonly;
  1132. }
  1133. $form = $this->form_builder->render();
  1134. }
  1135. $action_uri = $action.'/'.$id.'/'.$field;
  1136. $vars['form_action'] = ($inline) ? $this->module_uri.'/inline_'.$action_uri : $this->module_uri.'/'.$action_uri;
  1137. $vars['form'] = $form;
  1138. $vars['data'] = $values;
  1139. $vars['error'] = $this->model->get_errors();
  1140. $vars['notifications'] = $this->load->module_view(FUEL_FOLDER, '_blocks/notifications', $vars, TRUE);
  1141. $vars['instructions'] = (empty($field)) ? $this->instructions : '';
  1142. $vars['field'] = (!empty($field));
  1143. return $vars;
  1144. }
  1145. protected function _process()
  1146. {
  1147. $this->load->helper('security');
  1148. $this->_orig_post = $_POST;
  1149. // filter placeholder $_POST values
  1150. $callback = create_function('$matches', '
  1151. if (isset($_POST[$matches["2"]]))
  1152. {
  1153. $str = $matches[1].$_POST[$matches["2"]].$matches[3];
  1154. }
  1155. else
  1156. {
  1157. $str = $matches[0];
  1158. }
  1159. return $str;
  1160. ');
  1161. // first loop through and create simple non-namespaced $_POST values if they don't exist for convenience'
  1162. foreach($_POST as $key => $val)
  1163. {
  1164. $tmp_key = end(explode('--', $key));
  1165. $_POST[$tmp_key] = $val;
  1166. }
  1167. // now loop through and do any substitution
  1168. foreach($_POST as $key => $val)
  1169. {
  1170. if (is_string($val))
  1171. {
  1172. $_POST[$key] = preg_replace_callback('#(.*)\{(.+)\}(.*)#U', $callback, $val);
  1173. }
  1174. }
  1175. // set boolean fields
  1176. if (!empty($this->model->boolean_fields) AND is_array($this->model->boolean_fields))
  1177. {
  1178. foreach($this->model->boolean_fields as $val)
  1179. {
  1180. $_POST[$val] = (isset($_POST[$val])) ? $_POST[$val] : 0;
  1181. }
  1182. }
  1183. // if no permission to publish, then we revoke
  1184. if (!$this->fuel->auth->has_permission($this->permission, 'publish'))
  1185. {
  1186. unset($_POST['published']);
  1187. }
  1188. // set key_field if it is not id
  1189. if (!empty($_POST['id']) AND $this->model->key_field() != 'id')
  1190. {
  1191. $_POST[$this->model->key_field()] = $_POST['id'];
  1192. }
  1193. // run any form field post processing hooks
  1194. $this->load->library('form_builder');
  1195. // use a new instance to prevent problems when duplicating
  1196. $fb = new Form_builder();
  1197. $fb->load_custom_fields(APPPATH.'config/custom_fields.php');
  1198. $fields = $this->model->form_fields($_POST);
  1199. $fb->set_fields($fields);
  1200. $fb->post_process_field_values();// manipulates the $_POST values directly
  1201. // sanitize input if set in module configuration
  1202. $posted = $this->_sanitize($_POST);
  1203. return $posted;
  1204. }
  1205. function form($id = NULL, $field = NULL)
  1206. {
  1207. $saved = $this->_saved_data($id);
  1208. $vars = $this->_form_vars($id, $saved, $field);
  1209. $this->load->module_view(FUEL_FOLDER, '_layouts/module_form', $vars);
  1210. }
  1211. function delete($id = NULL)
  1212. {
  1213. // check that the action even exists and if not, show a 404
  1214. if (!$this->fuel->auth->module_has_action('delete'))
  1215. {
  1216. show_404();
  1217. }
  1218. if (!$this->fuel->auth->has_permission($this->permission, 'delete'))
  1219. {
  1220. show_error(lang('error_no_permissions'));
  1221. }
  1222. $inline = $this->fuel->admin->is_inline();
  1223. if (!empty($_POST['id']))
  1224. {
  1225. $posted = explode('|', $this->input->post('id', TRUE));
  1226. // run before_delete hook
  1227. $this->_run_hook('before_delete', $posted);
  1228. // Flags
  1229. $any_success = $any_failure = FALSE;
  1230. foreach ($posted as $id)
  1231. {
  1232. if ($this->model->delete(array($this->model->key_field() => $id)))
  1233. {
  1234. $any_success = TRUE;
  1235. }
  1236. else
  1237. {
  1238. $any_failure = TRUE;
  1239. }
  1240. }
  1241. // run after_delete hook
  1242. $this->_run_hook('after_delete', $posted);
  1243. $this->_clear_cache();
  1244. if (count($posted) > 1)
  1245. {
  1246. $this->fuel->logs->write(lang('module_multiple_deleted', $this->module));
  1247. }
  1248. else
  1249. {
  1250. $this->fuel->logs->write(lang('module_deleted', count($posted), $this->module));
  1251. }
  1252. if ($inline)
  1253. {
  1254. $vars['title'] = '';
  1255. $vars['id'] = '';
  1256. $vars['back_action'] = '';
  1257. $this->fuel->admin->render('modules/module_close_modal', $vars);
  1258. $this->fuel->admin->set_display_mode(Fuel_admin::DISPLAY_COMPACT_TITLEBAR);
  1259. $this->fuel->admin->render($this->views['delete'], $vars);
  1260. }
  1261. else
  1262. {
  1263. // set a success delete message
  1264. if ($any_success)
  1265. {
  1266. if (!$this->session->flashdata('success'))
  1267. {
  1268. $this->fuel->admin->set_notification(lang('data_deleted'), Fuel_admin::NOTIFICATION_SUCCESS);
  1269. }
  1270. }
  1271. // set an error delete message
  1272. if ($any_failure)
  1273. {
  1274. // first try to get an error added in model by $this->add_error('...')
  1275. $msg = $this->model->get_validation()->get_last_error();
  1276. // if there is none like that, lets use default message
  1277. if (is_null($msg))
  1278. {
  1279. $msg = lang('data_not_deleted');
  1280. }
  1281. $this->fuel->admin->set_notification($msg, Fuel_admin::NOTIFICATION_ERROR);
  1282. }
  1283. $url = fuel_uri($this->module_uri);
  1284. redirect($url);
  1285. }
  1286. }
  1287. else
  1288. {
  1289. $this->js_controller_params['method'] = 'deleteItem';
  1290. $vars = array();
  1291. if (!empty($_POST['delete']) AND is_array($_POST['delete']))
  1292. {
  1293. $data = array();
  1294. foreach($this->input->post('delete') as $key => $val)
  1295. {
  1296. $d = $this->model->find_by_key($key, 'array');
  1297. if (!empty($d)) $data[] = $d[$this->display_field];
  1298. }
  1299. $vars['id'] = implode('|', array_keys($_POST['delete']));
  1300. $vars['title'] = implode(', ', $data);
  1301. }
  1302. else
  1303. {
  1304. $data = $this->model->find_by_key($id, 'array');
  1305. $vars['id'] = $id;
  1306. if (isset($data[$this->display_field]))
  1307. {
  1308. $vars['title'] = $data[$this->display_field];
  1309. }
  1310. }
  1311. if (empty($data))
  1312. {
  1313. show_404();
  1314. }
  1315. $vars['error'] = $this->model->get_errors();
  1316. $crumbs = array($this->module_uri => $this->module_name);
  1317. $crumbs[''] = character_limiter(strip_tags(lang('action_delete').' '.$vars['title']), 50);
  1318. $this->fuel->admin->set_titlebar($crumbs);
  1319. if ($inline)
  1320. {
  1321. $this->fuel->admin->set_display_mode(Fuel_admin::DISPLAY_COMPACT_NO_ACTION);
  1322. $vars['back_action'] = fuel_url($this->module_uri.'/inline_edit/'.$id);
  1323. }
  1324. else
  1325. {
  1326. $this->fuel->admin->set_display_mode(Fuel_admin::DISPLAY_NO_ACTION);
  1327. $vars['back_action'] = fuel_url($this->module_uri.'/');
  1328. }
  1329. $action_uri = 'delete/'.$id;
  1330. $vars['form_action'] = ($inline) ? $this->module_uri.'/inline_'.$action_uri : $this->module_uri.'/'.$action_uri;
  1331. $this->fuel->admin->render($this->views['delete'], $vars);
  1332. }
  1333. }
  1334. function inline_delete($id)
  1335. {
  1336. $this->fuel->admin->set_inline(TRUE);
  1337. $this->delete($id);
  1338. }
  1339. function restore()
  1340. {
  1341. if (!$this->fuel->auth->has_permission($this->permission, 'edit'))
  1342. {
  1343. show_error(lang('error_no_permissions'));
  1344. }
  1345. if (!empty($_POST['fuel_restore_version']) AND !empty($_POST['fuel_restore_ref_id']))
  1346. {
  1347. if (!$this->model->restore($this->input->post('fuel_restore_ref_id'), $this->input->post('fuel_restore_version')))
  1348. {
  1349. $msg = lang('module_restored', $this->module_name);
  1350. $this->fuel->logs->write($msg);
  1351. $this->fuel->admin->set_notification($this->model->get_validation()->get_last_error(), Fuel_admin::NOTIFICATION_ERROR);
  1352. }
  1353. else
  1354. {
  1355. if (!$this->session->flashdata('success'))
  1356. {
  1357. $this->fuel->admin->set_notification(lang('module_restored_success'), Fuel_admin::NOTIFICATION_SUCCESS);
  1358. }
  1359. $this->_clear_cache();
  1360. }
  1361. redirect(fuel_uri($this->module_uri.'/edit/'.$this->input->post('fuel_restore_ref_id', TRUE)));
  1362. }
  1363. else
  1364. {
  1365. show_404();
  1366. }
  1367. }
  1368. function replace($id = NULL)
  1369. {
  1370. if (empty($id))
  1371. {
  1372. show_404();
  1373. }
  1374. if (!$this->fuel->auth->has_permission($this->permission, 'edit') OR !$this->fuel->auth->has_permission($this->permission, 'delete'))
  1375. {
  1376. show_error(lang('error_no_permissions'));
  1377. }
  1378. $success = FALSE;
  1379. if (!empty($_POST))
  1380. {
  1381. if (!empty($_POST['fuel_replace_id']))
  1382. {
  1383. $replace_id = $this->input->post('fuel_replace_id');
  1384. //$delete = is_true_val($this->input->post('fuel_delete_replacement'));
  1385. $delete = TRUE;
  1386. if (!$this->model->replace($replace_id, $id, $delete))
  1387. {
  1388. add_error($this->model->get_validation()->get_last_error());
  1389. }
  1390. else
  1391. {
  1392. $this->fuel->admin->set_notification(lang('module_replaced_success'), Fuel_admin::NOTIFICATION_SUCCESS);
  1393. $success = TRUE;
  1394. $this->_clear_cache();
  1395. }
  1396. }
  1397. else
  1398. {
  1399. add_error(lang('error_select_replacement'));
  1400. }
  1401. //redirect(fuel_uri($this->module_uri.'/edit/'.$id));
  1402. }
  1403. $this->load->library('form_builder');
  1404. $fields = array();
  1405. $other_options = $this->model->get_others($this->display_field, $id);
  1406. $fields['fuel_replace_id'] = array('label' => 'Replace record:', 'type' => 'select', 'options' => $other_options, 'first_option' => 'Select record to replace...', 'style' => 'max-width: 400px', 'disabled_options' => array($id));
  1407. //$fields['fuel_delete_replacement'] = array('label' => 'Delete replacement', 'type' => 'checkbox', 'value' => 'yes');
  1408. if ($success)
  1409. {
  1410. $fields['new_fuel_replace_id'] = array('type' => 'hidden', 'value' => $replace_id);
  1411. }
  1412. //$this->form_builder->use_form_tag = FALSE;
  1413. $this->form_builder->set_fields($fields);
  1414. $this->form_builder->display_errors = FALSE;
  1415. //$this->form_builder->submit_value = NULL;
  1416. $vars['form'] = $this->form_builder->render();
  1417. $this->fuel->admin->set_inline(TRUE);
  1418. $crumbs = array('' => $this->module_name, lang('action_replace'));
  1419. $this->fuel->admin->set_titlebar($crumbs);
  1420. $this->fuel->admin->render('modules/module_replace', $vars);
  1421. }
  1422. // displays the module's designated view'
  1423. function view($id = NULL)
  1424. {
  1425. if (!empty($this->preview_path) AND !empty($id))
  1426. {
  1427. $data = $this->model->find_one_array(array($this->model->table_name().'.'.$this->model->key_field() => $id));
  1428. $url = $this->module_obj->url($data);
  1429. // change the last page to be the referrer
  1430. $last_page = (isset($_SERVER['HTTP_REFERER'])) ? substr($_SERVER['HTTP_REFERER'], strlen(site_url())) : NULL;
  1431. $this->fuel->admin->set_last_page($last_page);
  1432. redirect($url);
  1433. }
  1434. else
  1435. {
  1436. show_error(lang('no_preview_path'));
  1437. }
  1438. }
  1439. // refreshes a single field
  1440. function refresh_field()
  1441. {
  1442. if (!empty($_POST))
  1443. {
  1444. $fields = $this->model->form_fields();
  1445. $field = $this->input->post('field', TRUE);
  1446. if (!isset($fields[$field])) return;
  1447. $field_id = $this->input->post('field_id', TRUE);
  1448. $values = $this->input->post('values', TRUE);
  1449. $selected = $this->input->post('selected', TRUE);
  1450. $field_key = end(explode('vars--', $field));
  1451. $this->load->library('form_builder');
  1452. $this->form_builder->load_custom_fields(APPPATH.'config/custom_fields.php');
  1453. // for multi select
  1454. if (is_array($values))
  1455. {
  1456. $selected = (array) $selected;
  1457. foreach($values as $v)
  1458. {
  1459. if (!in_array($v, $selected))
  1460. {
  1461. $selected[] = $v;
  1462. }
  1463. }
  1464. }
  1465. if (!empty($selected)) $fields[$field]['value'] = $selected;
  1466. $fields[$field]['name'] = $field_id;
  1467. $output = '';
  1468. // if template/nested field types, then we need to look at the sub field
  1469. if ($fields[$field_key]['type'] == 'template')
  1470. {
  1471. //$fields['return_fields'] = TRUE;
  1472. require_once(FUEL_PATH.'libraries/Fuel_custom_fields.php');
  1473. $fuel_cf = new Fuel_custom_fields();
  1474. $index = $this->input->get_post('index', TRUE);
  1475. $key = $this->input->get_post('key', TRUE);
  1476. $field_name = $this->input->get_post('field_name', TRUE);
  1477. $params = $fields[$field_key];
  1478. $params['index'] = $index;
  1479. $params['name'] = $field_name;
  1480. $params['key'] = $field_name;
  1481. $params['value'] = array();
  1482. $params['value'][0] = $selected;
  1483. $this->form_builder->name_array = $field_name;
  1484. //$fb->set_field_values();
  1485. $params['instance'] =& $this->form_builder;
  1486. $sub_fields = $fuel_cf->template($params, TRUE);
  1487. if (!empty($sub_fields[0][$key]))
  1488. {
  1489. $output = $sub_fields[0][$key];
  1490. }
  1491. }
  1492. else
  1493. {
  1494. if (!empty($selected)) $fields[$field_key]['value'] = $selected;
  1495. $fields[$field_key]['name'] = $field_id;
  1496. // if the field is an ID, then we will do a select instead of a text field
  1497. if (isset($fields[$this->model->key_field()]))
  1498. {
  1499. $fields[$this->model->key_field()]['type'] = 'select';
  1500. $fields[$this->model->key_field()]['options'] = $this->model->options_list();
  1501. }
  1502. $output = $this->form_builder->create_field($fields[$field_key]);
  1503. }
  1504. $this->output->set_output($output);
  1505. }
  1506. }
  1507. // processes linked fields
  1508. function process_linked()
  1509. {
  1510. if (!empty($_POST))
  1511. {
  1512. $master_field = $this->input->post('master_field', FALSE);
  1513. $master_value = $this->input->post('master_value', FALSE);
  1514. $slave_field = $this->input->post('slave_field', FALSE);
  1515. $values = array(
  1516. $master_field => $master_value,
  1517. $slave_field => '' // blank so we can process
  1518. );
  1519. $processed = $this->model->process_linked($values);
  1520. if (!empty($processed[$slave_field]))
  1521. {
  1522. $this->output->set_output($processed[$slave_field]);
  1523. }
  1524. }
  1525. }
  1526. // automatically calls ajax methods on the model
  1527. function ajax($method = NULL)
  1528. {
  1529. // must not be empty and must start with find_ (... don't want to access methods like delete)
  1530. if (is_ajax())
  1531. {
  1532. // append ajax to the method name... to prevent any conflicts with default methods
  1533. $method = 'ajax_'.$method;
  1534. $params = $this->input->get_post(NULL, TRUE);
  1535. if (!method_exists($this->model, $method))
  1536. {
  1537. show_error(lang('error_invalid_method'));
  1538. }
  1539. $results = $this->model->$method($params);
  1540. if (is_string($results))
  1541. {
  1542. $this->output->set_output($results);
  1543. }
  1544. else
  1545. {
  1546. $this->output->set_header('Cache-Control: no-cache, must-revalidate');
  1547. $this->output->set_header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
  1548. $this->output->set_header('Last-Modified: '. gmdate('D, d M Y H:i:s').'GMT');
  1549. $this->output->set_header('Content-type: application/json');
  1550. $output = json_encode($results);
  1551. print($output);
  1552. }
  1553. }
  1554. }
  1555. // exports data to CSV
  1556. function export()
  1557. {
  1558. if (empty($this->exportable))
  1559. {
  1560. show_404();
  1561. }
  1562. if (!$this->fuel->auth->has_permission($this->permission, 'export'))
  1563. {
  1564. show_error(lang('error_no_permissions'));
  1565. }
  1566. if (!empty($_POST))
  1567. {
  1568. // load dbutils for convenience to use in custom methods on model
  1569. $this->load->dbutil();
  1570. $this->load->helper('download');
  1571. $filename = $this->module.'_'.date('Y-m-d').'.csv';
  1572. $params = $this->_list_process();
  1573. $data = $this->model->export_data($params);
  1574. force_download($filename, $data);
  1575. }
  1576. }
  1577. // used in list view to quickly unpublish (if they have permisison)
  1578. function toggle_on($id = NULL, $field = 'published')
  1579. {
  1580. $this->_toggle($id, $field, 'on');
  1581. }
  1582. // used in list view to quickly publish (if they have permisison)
  1583. function toggle_off($id = NULL, $field = 'published')
  1584. {
  1585. $this->_toggle($id, $field, 'off');
  1586. }
  1587. // reduce code by creating this shortcut function for the unpublish/publish
  1588. function _toggle($id, $field, $toggle)
  1589. {
  1590. if (!$this->fuel->auth->module_has_action('save') OR ($field == 'publish' AND !$this->fuel->auth->has_permission($this->permission, 'publish')))
  1591. {
  1592. return FALSE;
  1593. }
  1594. if (empty($id))
  1595. {
  1596. $id = $this->input->post($this->model->key_field());
  1597. }
  1598. if ($id)
  1599. {
  1600. $save = $this->model->find_by_key($id, 'array');
  1601. $field_info = $this->model->field_info($field);
  1602. if (!empty($save))
  1603. {
  1604. if ($toggle == 'on')
  1605. {
  1606. $save[$field] = ($field_info['type'] != 'enum') ? 1 : 'yes';
  1607. }
  1608. else
  1609. {
  1610. $save[$field] = ($field_info['type'] != 'enum') ? 0 : 'no';
  1611. }
  1612. // run before_edit hook
  1613. $this->_run_hook('before_edit', $save);
  1614. // run before_save hook
  1615. $this->_run_hook('before_save', $save);
  1616. $save = $this->model->clean($save);
  1617. $where[$this->model->key_field()] = $id;
  1618. // use update instead of save to avoid issue with has_many and belongs_to being removed
  1619. if ($this->model->update($save, $where))
  1620. {
  1621. // clear cache
  1622. $this->_clear_cache();
  1623. // log it
  1624. $data = $this->model->find_by_key($id, 'array');
  1625. // run after_edit hook
  1626. $this->_run_hook('after_edit', $data);
  1627. // run after_save hook
  1628. $this->_run_hook('after_save', $data);
  1629. $msg = lang('module_edited', $this->module_name, $data[$this->display_field]);
  1630. $this->fuel->logs->write($msg);
  1631. }
  1632. else
  1633. {
  1634. $this->output->set_output(lang('error_saving'));
  1635. }
  1636. }
  1637. }
  1638. if (is_ajax())
  1639. {
  1640. $this->output->set_output($toggle);
  1641. }
  1642. else
  1643. {
  1644. $this->items();
  1645. }
  1646. }
  1647. protected function _clear_cache()
  1648. {
  1649. // reset cache for that page only
  1650. if ($this->clear_cache_on_save)
  1651. {
  1652. $this->fuel->cache->clear_pages();
  1653. }
  1654. }
  1655. protected function _allow_action($action)
  1656. {
  1657. return in_array($action, $this->item_actions);
  1658. }
  1659. protected function _common_fields($values)
  1660. {
  1661. $fields['__fuel_module__'] = array('type' => 'hidden');
  1662. $fields['__fuel_module__']['value'] = $this->module;
  1663. $fields['__fuel_module__']['class'] = '__fuel_module__';
  1664. $fields['__fuel_module_uri__'] = array('type' => 'hidden');
  1665. $fields['__fuel_module_uri__']['value'] = $this->module_uri;
  1666. $fields['__fuel_module_uri__']['class'] = '__fuel_module_uri__';
  1667. $fields['__fuel_id__'] = array('type' => 'hidden');
  1668. $fields['__fuel_id__']['value'] = (!empty($values[$this->model->key_field()])) ? $values[$this->model->key_field()] : '';
  1669. $fields['__fuel_id__']['class'] = '__fuel_id__';
  1670. return $fields;
  1671. }
  1672. protected function _save_tab_state($id)
  1673. {
  1674. // set tab
  1675. if (isset($_POST['__fuel_selected_tab__']))
  1676. {
  1677. if (!empty($_COOKIE['fuel_tabs']))
  1678. {
  1679. $tab_cookie = json_decode(urldecode($_COOKIE['fuel_tabs']), TRUE);
  1680. if (!empty($tab_cookie))
  1681. {
  1682. $tab_cookie[$this->module.'_edit_'.$id] = $_POST['__fuel_selected_tab__'];
  1683. $cookie_val = urlencode(json_encode($tab_cookie));
  1684. // set the cookie for viewing the live site with added FUEL capabilities
  1685. $config = array(
  1686. 'name' => 'fuel_tabs',
  1687. 'value' => $cookie_val,
  1688. 'expire' => 0,
  1689. //'path' => WEB_PATH
  1690. 'path' => $this->fuel->config('fuel_cookie_path')
  1691. );
  1692. set_cookie($config);
  1693. }
  1694. }
  1695. }
  1696. }
  1697. protected function _process_uploads($posted = NULL)
  1698. {
  1699. if (empty($posted)) $posted = $_POST;
  1700. $errors = FALSE;
  1701. if (!empty($_FILES))
  1702. {
  1703. // loop through uploaded files
  1704. foreach ($_FILES as $file => $file_info)
  1705. {
  1706. if ($file_info['error'] == 0)
  1707. {
  1708. $posted[$file] = $file_info['name'];
  1709. $file_tmp = current(explode('___', $file));
  1710. $field_name = $file_tmp;
  1711. // if there is a field with the suffix of _upload, then we will overwrite that posted value with this value
  1712. if (substr($file_tmp, ($file_tmp - 7)) == '_upload')
  1713. {
  1714. $field_name = substr($file_tmp, 0, ($file_tmp - 7));
  1715. }
  1716. if (isset($posted[$file_tmp.'_file_name']))
  1717. {
  1718. // get file extension
  1719. $path_info = pathinfo($file_info['name']);
  1720. $field_value = $this->_orig_post[$file_tmp.'_file_name'].'.'.$path_info['extension'];
  1721. }
  1722. else
  1723. {
  1724. $field_value = $file_info['name'];
  1725. }
  1726. // look for repeatable values that match
  1727. if (preg_match('#(.+)_(\d+)_(.+)#', $file_tmp, $matches))
  1728. {
  1729. if (isset($posted[$matches[1]][$matches[2]][$matches[3]]))
  1730. {
  1731. $posted[$matches[1]][$matches[2]][$matches[3]] = $posted[$file];
  1732. }
  1733. }
  1734. if (strpos($field_value, '{') !== FALSE )
  1735. {
  1736. //e modifier is deprecated so we have to do this
  1737. $callback = create_function('$match', '
  1738. $return = "";
  1739. if (!empty($match[2]))
  1740. {
  1741. $return = $match[1].$GLOBALS["__tmp_transient_posted__"][$match[2]].$match[3];
  1742. }
  1743. return $return;');
  1744. // hacky but avoids 5.3 function syntax (which is nicer but doesn't work with 5.2)
  1745. $GLOBALS['__tmp_transient_posted__'] = $posted;
  1746. $field_value = preg_replace_callback('#^(.*)\{(.+)\}(.*)$#', $callback, $field_value);
  1747. }
  1748. // set both values for the namespaced and non-namespaced... make them underscored and lower cased
  1749. $tmp_field_name = end(explode('--', $field_name));
  1750. $file_name = pathinfo($field_value, PATHINFO_FILENAME);
  1751. $file_ext = pathinfo($field_value, PATHINFO_EXTENSION);
  1752. $file_val = url_title($file_name, 'underscore', FALSE).'.'.$file_ext;
  1753. $posted[$tmp_field_name] = $file_val;
  1754. $posted[$field_name] = $file_val;
  1755. $posted[$file_tmp.'_file_name'] = $file_val;
  1756. }
  1757. }
  1758. // hacky cleanup to avoid using 5.3 syntax
  1759. if (isset($GLOBALS["__tmp_transient_posted__"]))
  1760. {
  1761. unset($GLOBALS["__tmp_transient_posted__"]);
  1762. }
  1763. $params['xss_clean'] = $this->sanitize_files;
  1764. $params['posted'] = $posted;
  1765. // UPLOAD!!!
  1766. if (!$this->fuel->assets->upload($params))
  1767. {
  1768. $errors = TRUE;
  1769. $msg = $this->fuel->assets->last_error();
  1770. add_error($msg);
  1771. $this->fuel->admin->set_notification($msg, Fuel_admin::NOTIFICATION_ERROR);
  1772. }
  1773. else
  1774. {
  1775. // do post processing of updating field values if they changed during upload due to overwrite being FALSE
  1776. $uploaded_data = $this->fuel->assets->uploaded_data();
  1777. // transfer uploaded data info to the model
  1778. $this->model->upload_data =& $uploaded_data;
  1779. // transfer uploaded data the controller object as well
  1780. $this->upload_data =& $uploaded_data;
  1781. // now process the data related to upload a file including translated path names
  1782. if (!isset($field_name))
  1783. {
  1784. $field_name = '';
  1785. }
  1786. $this->_process_upload_data($field_name, $uploaded_data, $posted);
  1787. }
  1788. }
  1789. return !$errors;
  1790. }
  1791. protected function _process_upload_data($field_name, $uploaded_data, $posted)
  1792. {
  1793. $field_name = end(explode('--', $field_name));
  1794. foreach($uploaded_data as $key => $val)
  1795. {
  1796. $file_tmp = current(explode('___', $key));
  1797. // get the file name field
  1798. // if the file name field exists AND there is no specified hidden filename field to assign to it AND...
  1799. // the model does not have an array key field AND there is a key field value posted
  1800. if (isset($field_name) AND !is_array($this->model->key_field()) AND isset($posted[$this->model->key_field()]))
  1801. {
  1802. $id = $posted[$this->model->key_field()];
  1803. $data = $this->model->find_one_array(array($this->model->table_name().'.'.$this->model->key_field() => $id));
  1804. // if there is a field with the suffix of _upload, then we will overwrite that posted value with this value
  1805. if (substr($file_tmp, ($file_tmp - 7)) == '_upload')
  1806. {
  1807. $field_name = substr($file_tmp, 0, ($file_tmp - 7));
  1808. }
  1809. if (isset($posted[$field_name]))
  1810. {
  1811. $save = TRUE;
  1812. }
  1813. // look for repeatable values that match
  1814. if (preg_match('#(.+)_(\d+)_(.+)#', $file_tmp, $matches))
  1815. {
  1816. if (isset($posted[$matches[1]][$matches[2]][$matches[3]]) AND isset($data[$matches[1]][$matches[2]][$matches[3]]))
  1817. {
  1818. $data[$matches[1]][$matches[2]][$matches[3]] = $posted[$file_tmp];
  1819. $save = TRUE;
  1820. }
  1821. }
  1822. if ($save)
  1823. {
  1824. $data[$field_name] = $val['file_name'];
  1825. // reset any validation to prevent issues with saving again (e.g. unique fields and the is_new function is problematic)
  1826. $this->model->remove_all_validation($data);
  1827. $this->model->save($data);
  1828. }
  1829. }
  1830. }
  1831. }
  1832. protected function _run_hook($hook, $params = array())
  1833. {
  1834. // call module specific hook
  1835. $hook_name = $hook.'_'.$this->module;
  1836. $GLOBALS['EXT']->_call_hook($hook_name, $params);
  1837. // call global module hook if any
  1838. $hook_name = $hook.'_module';
  1839. $GLOBALS['EXT']->_call_hook($hook_name, $params);
  1840. }
  1841. }