PageRenderTime 74ms CodeModel.GetById 25ms RepoModel.GetById 7ms app.codeStats 0ms

/system/cms/modules/streams_core/models/fields_m.php

https://github.com/gsake/pyrocms
PHP | 811 lines | 430 code | 147 blank | 234 comment | 84 complexity | 894b3c42db2bf30f6b2a924fb9745993 MD5 | raw file
Possible License(s): CC-BY-3.0, BSD-3-Clause, CC0-1.0, MIT
  1. <?php defined('BASEPATH') or exit('No direct script access allowed');
  2. /**
  3. * PyroStreams Fields Model
  4. *
  5. * @package PyroCMS\Core\Modules\Streams Core\Models
  6. * @author Parse19
  7. * @copyright Copyright (c) 2011 - 2012, Parse19
  8. * @license http://parse19.com/pyrostreams/docs/license
  9. * @link http://parse19.com/pyrostreams
  10. */
  11. class Fields_m extends CI_Model {
  12. public $table;
  13. // --------------------------------------------------------------------------
  14. /**
  15. * Fields Validation
  16. */
  17. public $fields_validation = array(
  18. array(
  19. 'field' => 'field_name',
  20. 'label' => 'lang:streams.label.field_name',
  21. 'rules' => 'trim|required|max_length[60]'
  22. ),
  23. array(
  24. 'field' => 'field_slug',
  25. 'label' => 'lang:streams.label.field_slug',
  26. 'rules' => 'trim|required|max_length[60]|slug_safe'
  27. ),
  28. array(
  29. 'field' => 'field_type',
  30. 'label' => 'lang:streams.label.field_type',
  31. 'rules' => 'trim|required|max_length[50]|type_valid'
  32. )
  33. );
  34. // --------------------------------------------------------------------------
  35. public $fields_cache;
  36. // --------------------------------------------------------------------------
  37. function __construct()
  38. {
  39. $this->table = FIELDS_TABLE;
  40. }
  41. // --------------------------------------------------------------------------
  42. /**
  43. * Get some fields
  44. *
  45. * @access public
  46. * @param [string - field namespace]
  47. * @param [int limit]
  48. * @param [int offset]
  49. * @return obj
  50. */
  51. public function get_fields($namespace = NULL, $limit = FALSE, $offset = 0, $skips = array())
  52. {
  53. if (!empty($skips)) $this->db->or_where_not_in('field_slug', $skips);
  54. if ($namespace) $this->db->where('field_namespace', $namespace);
  55. if ($offset) $this->db->offset($offset);
  56. if ($limit) $this->db->limit($limit);
  57. $query = $this->db->order_by('field_name', 'asc')->get($this->table);
  58. return $query->result();
  59. }
  60. // --------------------------------------------------------------------------
  61. /**
  62. * Get all fields with extra field info
  63. *
  64. * @access public
  65. * @param int limit
  66. * @param int offset
  67. * @return obj
  68. */
  69. public function get_all_fields()
  70. {
  71. $obj = $this->db->order_by('field_name', 'asc')->get($this->table);
  72. $fields = $obj->result_array();
  73. $return_fields = array();
  74. foreach($fields as $key => $field)
  75. {
  76. $return_fields[$field['field_slug']] = $field;
  77. $return_fields[$field['field_slug']]['field_data'] = unserialize($field['field_data']);
  78. }
  79. return $return_fields;
  80. }
  81. // --------------------------------------------------------------------------
  82. /**
  83. * Count fields
  84. *
  85. * @access public
  86. * @return int
  87. */
  88. public function count_fields($namespace)
  89. {
  90. if ( ! $namespace) return 0;
  91. return $this->db
  92. ->where('field_namespace', $namespace)
  93. ->from($this->table)
  94. ->count_all_results();
  95. }
  96. // --------------------------------------------------------------------------
  97. /**
  98. * Insert a field
  99. *
  100. * @access public
  101. * @param string - the field name
  102. * @param string - the field slug
  103. * @param string - the field type
  104. * @param [array - any extra data]
  105. * @return bool
  106. */
  107. public function insert_field($field_name, $field_slug, $field_type, $field_namespace, $extra = array(), $locked = 'no')
  108. {
  109. if ( ! $locked)
  110. {
  111. $locked = 'no';
  112. }
  113. if ($locked != 'yes' and $locked != 'no')
  114. {
  115. $locked = 'no';
  116. }
  117. $insert_data = array(
  118. 'field_name' => $field_name,
  119. 'field_slug' => $field_slug,
  120. 'field_namespace' => $field_namespace,
  121. 'field_type' => $field_type,
  122. 'is_locked' => $locked
  123. );
  124. // Load the type to see if there are other fields
  125. $field_type = $this->type->types->$field_type;
  126. if (isset($field_type->custom_parameters))
  127. {
  128. $extra_data = array();
  129. foreach ($field_type->custom_parameters as $param)
  130. {
  131. if (method_exists($field_type, 'param_'.$param.'_pre_save'))
  132. {
  133. $extra_data[$param] = $field_type->{'param_'.$param.'_pre_save'}($insert_data);
  134. }
  135. elseif(isset($extra[$param]))
  136. {
  137. $extra_data[$param] = $extra[$param];
  138. }
  139. }
  140. $insert_data['field_data'] = serialize($extra_data);
  141. }
  142. return $this->db->insert($this->table, $insert_data);
  143. }
  144. // --------------------------------------------------------------------------
  145. /**
  146. * Take field data and parse it into an array
  147. * the the DB forge class can use
  148. *
  149. * @access public
  150. * @param obj
  151. * @param array
  152. * @param string
  153. * @return array
  154. */
  155. public function field_data_to_col_data($type, $field_data, $method = 'add')
  156. {
  157. $col_data = array();
  158. // -------------------------------------
  159. // Name
  160. // -------------------------------------
  161. if ($method == 'edit')
  162. {
  163. $col_data['name'] = $field_data['field_slug'];
  164. }
  165. // -------------------------------------
  166. // Col Type
  167. // -------------------------------------
  168. $col_data['type'] = strtoupper($type->db_col_type);
  169. // -------------------------------------
  170. // Constraint
  171. // -------------------------------------
  172. // First we check and see if a constraint has been added
  173. if (isset($type->col_constraint) and $type->col_constraint)
  174. {
  175. $col_data['constraint'] = $type->col_constraint;
  176. }
  177. // Otherwise, we'll check for a max_length field
  178. elseif (isset($field_data['max_length']) and is_numeric($field_data['max_length']))
  179. {
  180. $col_data['constraint'] = $field_data['max_length'];
  181. }
  182. // -------------------------------------
  183. // Text field varchar change
  184. // -------------------------------------
  185. if ($type->field_type_slug == 'text')
  186. {
  187. if (isset($col_data['constraint']) and $col_data['constraint'] > 255)
  188. {
  189. $col_data['type'] = 'TEXT';
  190. // Don't need a constraint no more
  191. unset($col_data['constraint']);
  192. }
  193. else
  194. {
  195. $col_data['type'] = 'VARCHAR';
  196. }
  197. }
  198. // -------------------------------------
  199. // Default
  200. // -------------------------------------
  201. if (isset($field_data['default_value']) and $field_data['default_value'] != '')
  202. {
  203. $col_data['default'] = $field_data['default_value'];
  204. }
  205. // -------------------------------------
  206. // Remove Default for some col types:
  207. // -------------------------------------
  208. // * TEXT
  209. // * LONGTEXT
  210. // -------------------------------------
  211. $no_default = array('TEXT', 'LONGTEXT');
  212. if (in_array($col_data['type'], $no_default))
  213. {
  214. unset($col_data['default']);
  215. }
  216. // -------------------------------------
  217. // Default to allow null
  218. // -------------------------------------
  219. $col_data['null'] = true;
  220. // -------------------------------------
  221. // Check for varchar with no constraint
  222. // -------------------------------------
  223. // Catch it and default to 255
  224. // -------------------------------------
  225. if ($col_data['type'] == 'VARCHAR' and ( ! isset($col_data['constraint']) || !is_numeric($col_data['constraint']) || $col_data['constraint'] == ''))
  226. {
  227. $col_data['constraint'] = 255;
  228. }
  229. // -------------------------------------
  230. return $col_data;
  231. }
  232. // --------------------------------------------------------------------------
  233. /**
  234. * Update field
  235. *
  236. * @access public
  237. * @param obj
  238. * @param array - data
  239. * @param int
  240. */
  241. public function update_field($field, $data)
  242. {
  243. $type = $this->type->types->{$data['field_type']};
  244. // -------------------------------------
  245. // Alter Columns
  246. // -------------------------------------
  247. // We want to change columns if the
  248. // following change:
  249. //
  250. // * Field Type
  251. // * Field Slug
  252. // * Max Length
  253. // * Default Value
  254. // -------------------------------------
  255. $assignments = $this->get_assignments($field->id);
  256. if(
  257. $field->field_type != $data['field_type'] or
  258. $field->field_slug != $data['field_slug'] or
  259. ( isset( $field->field_data['max_length'] ) and $field->field_data['max_length'] != $data['max_length'] ) or
  260. ( isset( $field->field_data['default_value'] ) and $field->field_data['default_value'] != $data['default_value'] )
  261. )
  262. {
  263. // If so, we need to update some table columns
  264. // Get the field assignments and change the table names
  265. // Check first to see if there are any assignments
  266. if ($assignments)
  267. {
  268. // Alter the table names and types
  269. $this->load->dbforge();
  270. foreach ($assignments as $assignment)
  271. {
  272. if ( ! method_exists($type, 'alt_rename_column'))
  273. {
  274. if ( ! $this->dbforge->modify_column($assignment->stream_prefix.$assignment->stream_slug, array($field->field_slug => $this->field_data_to_col_data($type, $data, 'edit'))))
  275. {
  276. return false;
  277. }
  278. }
  279. // Update the view options
  280. $view_options = unserialize($assignment->stream_view_options);
  281. if (is_array($view_options))
  282. {
  283. foreach ($view_options as $key => $option)
  284. {
  285. if ($option == $field->field_slug)
  286. {
  287. // Replace with the new field slug so nothing goes apeshit
  288. $view_options[$key] = $data['field_slug'];
  289. }
  290. }
  291. }
  292. else
  293. {
  294. $view_options = array();
  295. }
  296. $vo_update_data['view_options'] = serialize($view_options);
  297. $this->db->where('id', $assignment->stream_id)->update(STREAMS_TABLE, $vo_update_data);
  298. $vo_update_data = array();
  299. $view_options = array();
  300. }
  301. }
  302. // Run though alt rename column routines. Needs to be done
  303. // after the above loop through assignments.
  304. if ($assignments)
  305. {
  306. foreach ($assignments as $assignment)
  307. {
  308. if (method_exists($type, 'alt_rename_column'))
  309. {
  310. // We run a different function for alt_process
  311. $type->alt_rename_column($field, $this->streams_m->get_stream($assignment->stream_slug), $assignment);
  312. }
  313. }
  314. }
  315. }
  316. // Run edit field update hook
  317. if (method_exists($type, 'update_field'))
  318. {
  319. $type->update_field($field, $assignments);
  320. }
  321. // Update field information
  322. if (isset($data['field_name'])) $update_data['field_name'] = $data['field_name'];
  323. if (isset($data['field_slug'])) $update_data['field_slug'] = $data['field_slug'];
  324. if (isset($data['field_namespace'])) $update_data['field_namespace'] = $data['field_namespace'];
  325. if (isset($data['field_type'])) $update_data['field_type'] = $data['field_type'];
  326. if (isset($data['is_locked']))
  327. {
  328. if ( ! $data['is_locked'])
  329. {
  330. $data['is_locked'] = 'no';
  331. }
  332. if ($data['is_locked'] != 'yes' and $data['is_locked']!= 'no')
  333. {
  334. $data['is_locked'] = 'no';
  335. }
  336. }
  337. // Gather extra data
  338. if ( ! isset($type->custom_parameters) or $type->custom_parameters == '')
  339. {
  340. $update_data['field_data'] = null;
  341. }
  342. else
  343. {
  344. $custom_params = array();
  345. foreach ($type->custom_parameters as $param)
  346. {
  347. if (method_exists($type, 'param_'.$param.'_pre_save'))
  348. {
  349. $custom_params[$param] = $type->{'param_'.$param.'_pre_save'}($update_data);
  350. }
  351. elseif(isset($data[$param]))
  352. {
  353. $custom_params[$param] = $data[$param];
  354. }
  355. }
  356. if ( ! empty($custom_params))
  357. {
  358. $update_data['field_data'] = serialize($custom_params);
  359. }
  360. }
  361. $this->db->where('id', $field->id);
  362. if ($this->db->update('data_fields', $update_data))
  363. {
  364. $tc_update['title_column'] = $data['field_slug'];
  365. // Success. Now let's update the title column.
  366. $this->db->where('title_column', $field->field_slug);
  367. return $this->db->update(STREAMS_TABLE, $tc_update);
  368. }
  369. else
  370. {
  371. // Boo.
  372. return false;
  373. }
  374. }
  375. // --------------------------------------------------------------------------
  376. /**
  377. * Count assignments
  378. *
  379. * @access public
  380. * @return int
  381. */
  382. public function count_assignments($field_id)
  383. {
  384. if ( ! $field_id) return 0;
  385. return $this->db
  386. ->where('field_id', $field_id)
  387. ->from($this->db->dbprefix(ASSIGN_TABLE))
  388. ->count_all_results();
  389. }
  390. // --------------------------------------------------------------------------
  391. /**
  392. * Get assignments for a field
  393. *
  394. * @access public
  395. * @param int
  396. * @return mixed
  397. */
  398. public function get_assignments($field_id)
  399. {
  400. $this->db->select(STREAMS_TABLE.'.*, '.STREAMS_TABLE.'.view_options as stream_view_options, '.STREAMS_TABLE.'.id as stream_id, '.FIELDS_TABLE.'.id as field_id, '.FIELDS_TABLE.'.*, '.FIELDS_TABLE.'.view_options as field_view_options');
  401. $this->db->from(STREAMS_TABLE.', '.ASSIGN_TABLE.', '.FIELDS_TABLE);
  402. $this->db->where($this->db->dbprefix(STREAMS_TABLE).'.id', $this->db->dbprefix(ASSIGN_TABLE).'.stream_id', FALSE);
  403. $this->db->where($this->db->dbprefix(FIELDS_TABLE).'.id', $this->db->dbprefix(ASSIGN_TABLE).'.field_id', FALSE);
  404. $this->db->where($this->db->dbprefix(ASSIGN_TABLE).'.field_id', $field_id, FALSE);
  405. $obj = $this->db->get();
  406. if ($obj->num_rows() == 0)
  407. {
  408. return false;
  409. }
  410. return $obj->result();
  411. }
  412. // --------------------------------------------------------------------------
  413. /**
  414. * Get assignments for a stream
  415. *
  416. * @access public
  417. * @param int
  418. * @return mixed
  419. */
  420. public function get_assignments_for_stream($stream_id)
  421. {
  422. $this->db->select(STREAMS_TABLE.'.*, '.STREAMS_TABLE.'.view_options as stream_view_options, '.ASSIGN_TABLE.'.id as assign_id, '.STREAMS_TABLE.'.id as stream_id, '.FIELDS_TABLE.'.id as field_id, '.FIELDS_TABLE.'.*, '.FIELDS_TABLE.'.view_options as field_view_options, '.ASSIGN_TABLE.'.instructions, '.ASSIGN_TABLE.'.is_required, '.ASSIGN_TABLE.'.is_unique');
  423. $this->db->from(STREAMS_TABLE.', '.ASSIGN_TABLE.', '.FIELDS_TABLE);
  424. $this->db->where($this->db->dbprefix(STREAMS_TABLE).'.id', $this->db->dbprefix(ASSIGN_TABLE).'.stream_id', FALSE);
  425. $this->db->where($this->db->dbprefix(FIELDS_TABLE).'.id', $this->db->dbprefix(ASSIGN_TABLE).'.field_id', FALSE);
  426. $this->db->where($this->db->dbprefix(ASSIGN_TABLE).'.stream_id', $stream_id, FALSE);
  427. $this->db->order_by('sort_order', 'ASC');
  428. $obj = $this->db->get();
  429. if ($obj->num_rows() == 0)
  430. {
  431. return false;
  432. }
  433. return $obj->result();
  434. }
  435. // --------------------------------------------------------------------------
  436. /**
  437. * Delete a field
  438. *
  439. * @access public
  440. * @param int
  441. * @return bool
  442. */
  443. public function delete_field($field_id)
  444. {
  445. // Make sure field exists
  446. if ( ! $field = $this->get_field($field_id))
  447. {
  448. return false;
  449. }
  450. // Find assignments, and delete rows from table
  451. $assignments = $this->get_assignments($field_id);
  452. if ($assignments)
  453. {
  454. $this->load->dbforge();
  455. $outcome = true;
  456. // Cycle and delete columns
  457. foreach ($assignments as $assignment)
  458. {
  459. $this->cleanup_assignment($assignment);
  460. }
  461. if ( ! $outcome) return $outcome;
  462. }
  463. // Delete field assignments
  464. $this->db->where('field_id', $field->id);
  465. if ( ! $this->db->delete(ASSIGN_TABLE))
  466. {
  467. return false;
  468. }
  469. // Reset instances where the title column
  470. // is the field we are deleting. PyroStreams will
  471. // always just use the ID in place of the field.
  472. $this->db->where('title_column', $field->field_slug);
  473. $this->db->update(STREAMS_TABLE, array('title_column' => null));
  474. // Delete from actual fields table
  475. $this->db->where('id', $field->id);
  476. if ( ! $this->db->delete(FIELDS_TABLE))
  477. {
  478. return false;
  479. }
  480. return true;
  481. }
  482. // --------------------------------------------------------------------------
  483. /**
  484. * Field garbage cleanup
  485. *
  486. * @access public
  487. * @param obj - the assignment
  488. * @return void
  489. */
  490. function cleanup_assignment($assignment)
  491. {
  492. // Drop the column if it exists
  493. if ($this->db->field_exists($assignment->field_slug, $assignment->stream_prefix.$assignment->stream_slug))
  494. {
  495. if ( ! $this->dbforge->drop_column($assignment->stream_prefix.$assignment->stream_slug, $assignment->field_slug) )
  496. {
  497. $outcome = false;
  498. }
  499. }
  500. // Run the destruct
  501. if (method_exists($this->type->types->{$assignment->field_type}, 'field_assignment_destruct'))
  502. {
  503. $this->type->types->{$assignment->field_type}->field_assignment_destruct($this->get_field($assignment->field_id), $this->streams_m->get_stream($assignment->stream_slug, true));
  504. }
  505. // Update that stream's view options
  506. $view_options = unserialize($assignment->stream_view_options);
  507. if (is_array($view_options))
  508. {
  509. foreach ($view_options as $key => $option)
  510. {
  511. if ($option == $assignment->field_slug)
  512. {
  513. unset($view_options[$key]);
  514. }
  515. }
  516. }
  517. else
  518. {
  519. $view_options = array();
  520. }
  521. $update_data['view_options'] = serialize($view_options);
  522. $this->db->where('id', $assignment->stream_id)->update(STREAMS_TABLE, $update_data);
  523. unset($update_data);
  524. unset($view_options);
  525. }
  526. // --------------------------------------------------------------------------
  527. /**
  528. * Get a single field
  529. *
  530. * @access public
  531. * @param int
  532. * @return obj
  533. */
  534. public function get_field($field_id)
  535. {
  536. // Check for already cached value
  537. if (isset($this->fields_cache['by_id'][$field_id]))
  538. {
  539. return $this->fields_cache['by_id'][$field_id];
  540. }
  541. $this->db->limit(1)->where('id', $field_id);
  542. $obj = $this->db->get($this->table);
  543. if ($obj->num_rows() == 0)
  544. {
  545. return false;
  546. }
  547. $field = $obj->row();
  548. $field->field_data = unserialize($field->field_data);
  549. // Save for later use
  550. $this->fields_cache['by_id'][$field_id] = $field;
  551. return $field;
  552. }
  553. // --------------------------------------------------------------------------
  554. /**
  555. * Get a single field by the field slug
  556. *
  557. * @access public
  558. * @param string - field slug
  559. * @param string - field namespace
  560. * @return obj
  561. */
  562. public function get_field_by_slug($field_slug, $field_namespace)
  563. {
  564. // Check for already cached value
  565. if (isset($this->fields_cache['by_slug'][$field_slug]))
  566. {
  567. return $this->fields_cache['by_slug'][$field_slug];
  568. }
  569. $obj = $this->db
  570. ->limit(1)
  571. ->where('field_namespace', $field_namespace)
  572. ->where('field_slug', $field_slug)
  573. ->get($this->table);
  574. if ($obj->num_rows() == 0)
  575. {
  576. return false;
  577. }
  578. $field = $obj->row();
  579. $field->field_data = unserialize($field->field_data);
  580. // Save for later use
  581. $this->fields_cache['by_slug'][$field_slug] = $field;
  582. return $field;
  583. }
  584. // --------------------------------------------------------------------------
  585. /**
  586. * Assignment Exists
  587. *
  588. * @access public
  589. * @param int - stream ID
  590. * @param int - field ID
  591. * @return bool
  592. */
  593. public function assignment_exists($stream_id, $field_id)
  594. {
  595. if ($this->db->select('id')->where('stream_id', $stream_id)->where('field_id', $field_id)->get(ASSIGN_TABLE)->num_rows() > 0)
  596. {
  597. return true;
  598. }
  599. else
  600. {
  601. return false;
  602. }
  603. }
  604. // --------------------------------------------------------------------------
  605. /**
  606. * Edit Assignment
  607. *
  608. * @access public
  609. * @param int
  610. * @param obj
  611. * @param obj
  612. * @param [string - instructions]
  613. * return bool
  614. */
  615. public function edit_assignment($assignment_id, $stream, $field, $data)
  616. {
  617. // -------------------------------------
  618. // Title Column
  619. // -------------------------------------
  620. // Scenario A: The title column is the field slug, and we
  621. // have it unchecked.
  622. if (
  623. $stream->title_column == $field->field_slug and
  624. ( ! isset($data['title_column']) or $data['title_column'] == 'no' or ! $data['title_column'])
  625. )
  626. {
  627. // In this case, they don't want this to
  628. // be the title column anymore, so we wipe it out
  629. $this->db
  630. ->limit(1)
  631. ->where('id', $stream->id)
  632. ->update('data_streams', array('title_column' => null));
  633. }
  634. elseif (
  635. isset($data['title_column']) and
  636. ($data['title_column'] == 'yes' or $data['title_column'] === true) and
  637. $stream->title_column != $field->field_slug
  638. )
  639. {
  640. // Scenario B: They have checked the title column
  641. // and this field it not the current field.
  642. $this->db
  643. ->limit(1)
  644. ->where('id', $stream->id)
  645. ->update('data_streams', array('title_column' => $field->field_slug));
  646. }
  647. // Is required
  648. if( isset($data['is_required']) and $data['is_required'] == 'yes' ):
  649. $update_data['is_required'] = 'yes';
  650. else:
  651. $update_data['is_required'] = 'no';
  652. endif;
  653. // Is unique
  654. if( isset($data['is_unique']) and $data['is_unique'] == 'yes' ):
  655. $update_data['is_unique'] = 'yes';
  656. else:
  657. $update_data['is_unique'] = 'no';
  658. endif;
  659. // Add in instructions
  660. $update_data['instructions'] = $data['instructions'];
  661. $this->db->where('id', $assignment_id);
  662. return $this->db->update(ASSIGN_TABLE, $update_data);
  663. }
  664. }