PageRenderTime 1352ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/system/expressionengine/libraries/api/Api_channel_entries.php

https://bitbucket.org/tdevonshire/hoolux
PHP | 2219 lines | 1356 code | 397 blank | 466 comment | 279 complexity | 5c2d8af4fe970b7ca40f65f7ae978991 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php if (!defined('BASEPATH')) exit('No direct script access allowed');
  2. /**
  3. * ExpressionEngine - by EllisLab
  4. *
  5. * @package ExpressionEngine
  6. * @author EllisLab Dev Team
  7. * @copyright Copyright (c) 2003 - 2012, EllisLab, Inc.
  8. * @license http://ellislab.com/expressionengine/user-guide/license.html
  9. * @link http://ellislab.com
  10. * @since Version 2.0
  11. * @filesource
  12. */
  13. // ------------------------------------------------------------------------
  14. /**
  15. * ExpressionEngine Channel Entries API Class
  16. *
  17. * @package ExpressionEngine
  18. * @subpackage Core
  19. * @category Core
  20. * @author EllisLab Dev Team
  21. * @link http://ellislab.com
  22. */
  23. class Api_channel_entries extends Api {
  24. var $entry_data = array();
  25. var $channel_id;
  26. var $entry_id = 0;
  27. var $autosave = FALSE;
  28. var $data = array();
  29. var $meta = array();
  30. var $c_prefs = array();
  31. var $_cache = array();
  32. var $autosave_entry_id = 0;
  33. /**
  34. * Constructor
  35. *
  36. */
  37. function __construct()
  38. {
  39. parent::__construct();
  40. $this->EE->load->model('channel_entries_model');
  41. }
  42. // --------------------------------------------------------------------
  43. /**
  44. * Initialize
  45. *
  46. * Reset our caching arrays and any other config values
  47. *
  48. * @access private
  49. * @param array
  50. * @return void
  51. */
  52. protected function initialize($params = array())
  53. {
  54. $this->c_prefs = array();
  55. $this->_cache = array();
  56. parent::initialize($params);
  57. }
  58. // --------------------------------------------------------------------
  59. /**
  60. * Submit New Entry
  61. *
  62. * Handles entry submission from an arbitrary, authenticated source
  63. *
  64. * @access public
  65. * @param int
  66. * @param array
  67. * @return mixed
  68. */
  69. function submit_new_entry($channel_id, $data, $autosave = FALSE)
  70. {
  71. $this->entry_id = 0;
  72. $this->autosave_entry_id = isset($data['autosave_entry_id']) ? $data['autosave_entry_id'] : 0;
  73. // yoost incase
  74. $data['channel_id'] = $channel_id;
  75. $this->data =& $data;
  76. $mod_data = array();
  77. $this->initialize(array('channel_id' => $channel_id, 'entry_id' => 0, 'autosave' => $autosave));
  78. if ( ! $this->_base_prep($data))
  79. {
  80. return FALSE;
  81. }
  82. if ($this->trigger_hook('entry_submission_start') === TRUE)
  83. {
  84. return TRUE;
  85. }
  86. // Data cached by base_prep is only needed for updates - toss it
  87. $this->_cache = array();
  88. $this->_fetch_channel_preferences();
  89. $this->_do_channel_switch($data);
  90. // We break out the third party data here
  91. $this->_fetch_module_data($data, $mod_data);
  92. $this->_check_for_data_errors($data);
  93. // Lets make sure those went smoothly
  94. if (count($this->errors) > 0)
  95. {
  96. return ($this->autosave) ? $this->errors : FALSE;
  97. }
  98. $this->_prepare_data($data, $mod_data, $autosave);
  99. $this->_build_relationships($data);
  100. $meta = array(
  101. 'channel_id' => $this->channel_id,
  102. 'author_id' => $data['author_id'],
  103. 'site_id' => $this->EE->config->item('site_id'),
  104. 'ip_address' => $this->EE->input->ip_address(),
  105. 'title' => ($this->EE->config->item('auto_convert_high_ascii') == 'y') ? ascii_to_entities($data['title']) : $data['title'],
  106. 'url_title' => $data['url_title'],
  107. 'entry_date' => $data['entry_date'],
  108. 'edit_date' => $this->EE->localize->decode_date('%Y%m%d%H%i%s', $data['entry_date'], TRUE),
  109. 'versioning_enabled' => $data['versioning_enabled'],
  110. 'year' => $this->EE->localize->decode_date('%Y', $data['entry_date'], TRUE),
  111. 'month' => $this->EE->localize->decode_date('%m', $data['entry_date'], TRUE),
  112. 'day' => $this->EE->localize->decode_date('%d', $data['entry_date'], TRUE),
  113. 'expiration_date' => $data['expiration_date'],
  114. 'comment_expiration_date' => $data['comment_expiration_date'],
  115. 'recent_comment_date' => (isset($data['recent_comment_date']) && $data['recent_comment_date']) ? $data['recent_comment_date'] : 0,
  116. 'sticky' => (isset($data['sticky']) && $data['sticky'] == 'y') ? 'y' : 'n',
  117. 'status' => $data['status'],
  118. 'allow_comments' => $data['allow_comments'],
  119. );
  120. $this->meta =& $meta;
  121. $meta_keys = array_keys($meta);
  122. $meta_keys = array_diff($meta_keys, array('channel_id', 'entry_id', 'site_id'));
  123. foreach($meta_keys as $k)
  124. {
  125. unset($data[$k]);
  126. }
  127. if ($this->trigger_hook('entry_submission_ready') === TRUE)
  128. {
  129. return TRUE;
  130. }
  131. if ($this->autosave)
  132. {
  133. // autosave is done at this point, title and custom field insertion.
  134. // no revisions, stat updating or cache clearing needed.
  135. return $this->_insert_entry($meta, $data, $mod_data);
  136. }
  137. $this->_insert_entry($meta, $data, $mod_data);
  138. if (count($mod_data) > 0)
  139. {
  140. $this->_set_mod_data($meta, $data, $mod_data);
  141. }
  142. $this->_sync_related($meta, $data);
  143. if (isset($data['save_revision']) && $data['save_revision'])
  144. {
  145. return TRUE;
  146. }
  147. if (isset($data['ping_servers']) && count($data['ping_servers']) > 0)
  148. {
  149. $this->send_pings($data['ping_servers'], $channel_id, $this->entry_id);
  150. }
  151. $this->EE->stats->update_channel_stats($channel_id);
  152. if ($this->EE->config->item('new_posts_clear_caches') == 'y')
  153. {
  154. $this->EE->functions->clear_caching('all');
  155. }
  156. else
  157. {
  158. $this->EE->functions->clear_caching('sql');
  159. }
  160. // I know this looks redundant in July of 2009, but if the code moves
  161. // around, putting this return here now will ensure it doesn't get
  162. // forgotten in the future. -dj
  163. if ($this->trigger_hook('entry_submission_end') === TRUE)
  164. {
  165. return TRUE;
  166. }
  167. return TRUE;
  168. }
  169. // --------------------------------------------------------------------
  170. /**
  171. * Update entry
  172. *
  173. * Handles updating of existing entries from arbitrary, authenticated source
  174. *
  175. * @access public
  176. * @param int
  177. * @param array
  178. * @return mixed
  179. */
  180. function update_entry($entry_id, $data, $autosave = FALSE)
  181. {
  182. $this->data =& $data;
  183. $mod_data = array();
  184. $this->initialize(array('entry_id' => $entry_id, 'autosave' => $autosave));
  185. if ( ! $this->entry_exists($this->entry_id))
  186. {
  187. return $this->_set_error('no_entry_to_update');
  188. }
  189. if ( ! $this->_base_prep($data))
  190. {
  191. return FALSE;
  192. }
  193. if ($this->trigger_hook('entry_submission_start') === TRUE)
  194. {
  195. return TRUE;
  196. }
  197. $this->_fetch_channel_preferences();
  198. $this->_do_channel_switch($data);
  199. // We break out the third party data here
  200. $this->_fetch_module_data($data, $mod_data);
  201. $this->_check_for_data_errors($data);
  202. // Lets make sure those went smoothly
  203. if (count($this->errors) > 0)
  204. {
  205. return ($this->autosave) ? $this->errors : FALSE;
  206. }
  207. $this->_prepare_data($data, $mod_data, $autosave);
  208. $this->_build_relationships($data);
  209. $meta = array(
  210. 'channel_id' => $this->channel_id,
  211. 'author_id' => $data['author_id'],
  212. 'site_id' => $this->EE->config->item('site_id'),
  213. 'ip_address' => $this->EE->input->ip_address(),
  214. 'title' => ($this->EE->config->item('auto_convert_high_ascii') == 'y') ? ascii_to_entities($data['title']) : $data['title'],
  215. 'url_title' => $data['url_title'],
  216. 'entry_date' => $data['entry_date'],
  217. 'edit_date' => $this->EE->localize->decode_date('%Y%m%d%H%i%s', $this->EE->localize->now, FALSE),
  218. 'versioning_enabled' => $data['versioning_enabled'],
  219. 'year' => $this->EE->localize->decode_date('%Y', $data['entry_date'], TRUE),
  220. 'month' => $this->EE->localize->decode_date('%m', $data['entry_date'], TRUE),
  221. 'day' => $this->EE->localize->decode_date('%d', $data['entry_date'], TRUE),
  222. 'expiration_date' => $data['expiration_date'],
  223. 'comment_expiration_date' => $data['comment_expiration_date'],
  224. 'sticky' => (isset($data['sticky']) && $data['sticky'] == 'y') ? 'y' : 'n',
  225. 'status' => $data['status'],
  226. 'allow_comments' => $data['allow_comments'],
  227. );
  228. if (isset($data['recent_comment_date']))
  229. {
  230. $meta['recent_comment_date'] = $data['recent_comment_date'];
  231. }
  232. $this->meta =& $meta;
  233. $meta_keys = array_keys($meta);
  234. $meta_keys = array_diff($meta_keys, array('channel_id', 'entry_id', 'site_id'));
  235. foreach($meta_keys as $k)
  236. {
  237. unset($data[$k]);
  238. }
  239. if ($this->trigger_hook('entry_submission_ready') === TRUE)
  240. {
  241. return TRUE;
  242. }
  243. if ($this->autosave)
  244. {
  245. // autosave is done at this point, title and custom field insertion.
  246. // no revisions, stat updating or cache clearing needed.
  247. return $this->_update_entry($meta, $data, $mod_data);
  248. }
  249. $this->_update_entry($meta, $data, $mod_data);
  250. if (count($mod_data) > 0)
  251. {
  252. $this->_set_mod_data($meta, $data, $mod_data);
  253. }
  254. $this->_sync_related($meta, $data);
  255. if (isset($data['save_revision']) && $data['save_revision'])
  256. {
  257. return TRUE;
  258. }
  259. if (isset($data['ping_servers']) && count($data['ping_servers']) > 0)
  260. {
  261. $this->send_pings($data['ping_servers'], $this->channel_id, $entry_id);
  262. }
  263. $this->EE->stats->update_channel_stats($this->channel_id);
  264. if (isset($data['old_channel']))
  265. {
  266. $this->EE->stats->update_channel_stats($data['old_channel']);
  267. }
  268. if ($this->EE->config->item('new_posts_clear_caches') == 'y')
  269. {
  270. $this->EE->functions->clear_caching('all');
  271. }
  272. else
  273. {
  274. $this->EE->functions->clear_caching('sql');
  275. }
  276. // I know this looks redundant in July of 2009, but if the code moves
  277. // around, putting this return here now will ensure it doesn't get
  278. // forgotten in the future. -dj
  279. if ($this->trigger_hook('entry_submission_end') === TRUE)
  280. {
  281. return TRUE;
  282. }
  283. return TRUE;
  284. }
  285. // --------------------------------------------------------------------
  286. /**
  287. * Autosave Entry
  288. *
  289. * Handles deleting of existing entries from arbitrary, authenticated source
  290. *
  291. * @access public
  292. * @param int
  293. * @return bool
  294. */
  295. function autosave_entry($data)
  296. {
  297. $this->autosave_entry_id = 0;
  298. if (isset($data['autosave_entry_id']))
  299. {
  300. $this->autosave_entry_id = $data['autosave_entry_id'];
  301. }
  302. if ( ! isset($data['entry_id']) OR ! $data['entry_id'])
  303. {
  304. // new entry
  305. if ( ! $data['title'])
  306. {
  307. $data['title'] = 'autosave_'.$this->EE->localize->now;
  308. }
  309. return $this->submit_new_entry($data['channel_id'], $data, TRUE);
  310. }
  311. return $this->update_entry($data['entry_id'], $data, TRUE);
  312. }
  313. // --------------------------------------------------------------------
  314. /**
  315. * Delete entry
  316. *
  317. * Handles deleting of existing entries from arbitrary, authenticated source
  318. *
  319. * @access public
  320. * @param int
  321. * @return bool
  322. */
  323. function delete_entry($entry_ids)
  324. {
  325. $this->EE->load->library('api');
  326. $this->EE->load->library('addons');
  327. $this->EE->api->instantiate('channel_fields');
  328. if ( ! is_array($entry_ids))
  329. {
  330. $entry_ids = array($entry_ids);
  331. }
  332. if (array_key_exists('comment', $this->EE->addons->get_installed('modules')))
  333. {
  334. $comments_installed = TRUE;
  335. }
  336. else
  337. {
  338. $comments_installed = FALSE;
  339. }
  340. // grab entry meta data
  341. $this->EE->db->select('channel_id, author_id, entry_id');
  342. $this->EE->db->from('channel_titles');
  343. $this->EE->db->where_in('entry_id', $entry_ids);
  344. $query = $this->EE->db->get();
  345. // Check permissions
  346. $allowed_channels = $this->EE->functions->fetch_assigned_channels();
  347. $authors = array();
  348. foreach ($query->result_array() as $row)
  349. {
  350. if ($this->EE->session->userdata('group_id') != 1)
  351. {
  352. if ( ! in_array($row['channel_id'], $allowed_channels))
  353. {
  354. return $this->_set_error('unauthorized_for_this_channel');
  355. }
  356. }
  357. if ($row['author_id'] == $this->EE->session->userdata('member_id'))
  358. {
  359. if ($this->EE->session->userdata('can_delete_self_entries') != 'y')
  360. {
  361. return $this->_set_error('unauthorized_to_delete_self');
  362. }
  363. }
  364. else
  365. {
  366. if ($this->EE->session->userdata('can_delete_all_entries') != 'y')
  367. {
  368. return $this->_set_error('unauthorized_to_delete_others');
  369. }
  370. }
  371. $authors[$row['entry_id']] = $row['author_id'];
  372. }
  373. // grab channel field groups
  374. $this->EE->db->select('channel_id, field_group');
  375. $cquery = $this->EE->db->get('channels');
  376. $channel_groups = array();
  377. foreach($cquery->result_array() as $row)
  378. {
  379. $channel_groups[$row['channel_id']] = $row['field_group'];
  380. }
  381. // grab fields and order by group
  382. $this->EE->db->select('field_id, field_type, group_id');
  383. $fquery = $this->EE->db->get('channel_fields');
  384. $group_fields = array();
  385. foreach($fquery->result_array() as $row)
  386. {
  387. $group_fields[$row['group_id']][] = $row['field_type'];
  388. }
  389. // Delete primary data
  390. $this->EE->db->where_in('entry_id', $entry_ids);
  391. $this->EE->db->delete(array('channel_titles', 'channel_data', 'category_posts'));
  392. $entries = array();
  393. $ft_to_ids = array();
  394. foreach($query->result_array() as $row)
  395. {
  396. $val = $row['entry_id'];
  397. $channel_id = $row['channel_id'];
  398. // No field group- skip this bit
  399. if ( ! isset($channel_groups[$channel_id]) OR ! isset($group_fields[$channel_groups[$channel_id]]))
  400. {
  401. continue;
  402. }
  403. // Map entry id to fieldtype
  404. $group_id = $channel_groups[$channel_id];
  405. $field_type = $group_fields[$group_id];
  406. foreach($field_type as $ft)
  407. {
  408. if ( ! isset($ft_to_ids[$ft]))
  409. {
  410. $ft_to_ids[$ft] = array($val);
  411. }
  412. else if ( ! in_array($val, $ft_to_ids[$ft]))
  413. {
  414. $ft_to_ids[$ft][] = $val;
  415. }
  416. }
  417. // Check for silly relationship children
  418. // We do the regular relationship data in the relationship
  419. // fieldtype, but we have no way of knowing that a child
  420. // exists until we check. So it happens here.
  421. $this->EE->db->select('rel_id');
  422. $child_results = $this->EE->db->get_where('relationships', array('rel_child_id' => $val));
  423. if ($child_results->num_rows() > 0)
  424. {
  425. // We have children, so we need to do a bit of housekeeping
  426. // so parent entries don't continue to try to reference them
  427. $cids = array();
  428. foreach ($child_results->result_array() as $row)
  429. {
  430. $cids[] = $row['rel_id'];
  431. }
  432. foreach($fquery->result_array() as $row)
  433. {
  434. $field = 'field_id_'.$row['field_id'];
  435. $this->EE->db->where_in($field, $cids);
  436. $this->EE->db->update('channel_data', array($field => '0'));
  437. }
  438. $this->EE->db->delete('relationships', array('rel_child_id' => $val));
  439. }
  440. // Correct member post count
  441. $this->EE->db->select('total_entries');
  442. $mquery = $this->EE->db->get_where('members', array('member_id' => $authors[$val]));
  443. $tot = $mquery->row('total_entries');
  444. if ($tot > 0)
  445. {
  446. $tot -= 1;
  447. }
  448. $this->EE->db->where('member_id', $authors[$val]);
  449. $this->EE->db->update('members', array('total_entries' => $tot));
  450. if ($comments_installed)
  451. {
  452. $this->EE->db->where('status', 'o');
  453. $this->EE->db->where('entry_id', $val);
  454. $this->EE->db->where('author_id', $authors[$val]);
  455. $count = $this->EE->db->count_all_results('comments');
  456. if ($count > 0)
  457. {
  458. $this->EE->db->select('total_comments');
  459. $mc_query = $this->EE->db->get_where('members', array('member_id' => $authors[$val]));
  460. $this->EE->db->where('member_id', $authors[$val]);
  461. $this->EE->db->update('members', array('total_comments' => ($mc_query->row('total_comments') - $count)));
  462. }
  463. $this->EE->db->delete('comments', array('entry_id' => $val));
  464. $this->EE->db->delete('comment_subscriptions', array('entry_id' => $val));
  465. }
  466. // Delete entries in the channel_entries_autosave table
  467. $this->EE->db->where('original_entry_id', $val)
  468. ->delete('channel_entries_autosave');
  469. // Delete entries from the versions table
  470. $this->EE->db->where('entry_id', $val)
  471. ->delete('entry_versioning');
  472. // -------------------------------------------
  473. // 'delete_entries_loop' hook.
  474. // - Add additional processing for entry deletion in loop
  475. // - Added: 1.4.1
  476. //
  477. $edata = $this->EE->extensions->call('delete_entries_loop', $val, $channel_id);
  478. if ($this->EE->extensions->end_script === TRUE) return;
  479. //
  480. // -------------------------------------------
  481. // Update statistics
  482. $this->EE->stats->update_channel_stats($channel_id);
  483. if ($comments_installed)
  484. {
  485. $this->EE->stats->update_comment_stats($channel_id);
  486. }
  487. $entries[] = $val;
  488. }
  489. $fts = $this->EE->api_channel_fields->fetch_installed_fieldtypes();
  490. // Pass to custom fields
  491. foreach($ft_to_ids as $fieldtype => $ids)
  492. {
  493. $this->EE->api_channel_fields->setup_handler($fieldtype);
  494. $this->EE->api_channel_fields->apply('delete', array($ids));
  495. }
  496. // Pass to module defined fields
  497. $methods = array('publish_data_delete_db');
  498. $params = array('publish_data_delete_db' => array('entry_ids' => $entry_ids));
  499. $this->EE->api_channel_fields->get_module_methods($methods, $params);
  500. // Clear caches
  501. $this->EE->functions->clear_caching('all', '', TRUE);
  502. // -------------------------------------------
  503. // 'delete_entries_end' hook.
  504. // - Add additional processing for entry deletion
  505. //
  506. $edata = $this->EE->extensions->call('delete_entries_end');
  507. if ($this->EE->extensions->end_script === TRUE) return TRUE;
  508. //
  509. // -------------------------------------------
  510. return TRUE;
  511. }
  512. // --------------------------------------------------------------------
  513. /**
  514. * Entry exists
  515. *
  516. * Checks if an entry exists and is editable by the user
  517. *
  518. * @access public
  519. * @param int
  520. * @return bool
  521. */
  522. function entry_exists($entry_id)
  523. {
  524. if ( ! is_numeric($entry_id))
  525. {
  526. return FALSE;
  527. }
  528. $query = $this->EE->channel_entries_model->get_entry($entry_id);
  529. if ($query->num_rows() == 0)
  530. {
  531. return FALSE;
  532. }
  533. $this->_cache['orig_author_id'] = $query->row('author_id');
  534. return TRUE;
  535. }
  536. // --------------------------------------------------------------------
  537. /**
  538. * Update Relationship Cache
  539. *
  540. * Updates the relationship cache
  541. *
  542. * @access public
  543. * @param int
  544. * @return void
  545. */
  546. function update_related_cache($entry_id)
  547. {
  548. // Is this entry a child of another parent?
  549. //
  550. // If the entry being submitted is a "child" of another parent
  551. // we need to re-compile and cache the data. Confused? Me too...
  552. $this->EE->db->where('rel_type', 'channel');
  553. $this->EE->db->where('rel_child_id', $entry_id);
  554. $count = $this->EE->db->count_all_results('relationships');
  555. if ($count > 0)
  556. {
  557. $reldata = array(
  558. 'type' => 'channel',
  559. 'child_id' => $entry_id
  560. );
  561. $this->EE->functions->compile_relationship($reldata, FALSE);
  562. }
  563. // Is this entry a parent of a child?
  564. $this->EE->db->where('rel_parent_id', $entry_id);
  565. $this->EE->db->where('reverse_rel_data !=', '');
  566. $count = $this->EE->db->count_all_results('relationships');
  567. if ($count > 0)
  568. {
  569. $reldata = array(
  570. 'type' => 'channel',
  571. 'parent_id' => $entry_id
  572. );
  573. $this->EE->functions->compile_relationship($reldata, FALSE, TRUE);
  574. }
  575. }
  576. // --------------------------------------------------------------------
  577. /**
  578. * Send Pings
  579. *
  580. * Send xml-rpc pings
  581. *
  582. * @access public
  583. * @param string
  584. * @param int
  585. * @param bool
  586. * @return void
  587. */
  588. function send_pings($ping_servers, $channel_id, $entry_id, $send_now = TRUE)
  589. {
  590. if ( ! $ping_servers)
  591. {
  592. return FALSE;
  593. }
  594. $result = TRUE;
  595. if ( ! isset($this->c_prefs['rss_url']))
  596. {
  597. $this->_fetch_channel_preferences($channel_id);
  598. }
  599. // We only ping entries that are posted now, not in the future
  600. if ($send_now == TRUE)
  601. {
  602. $ping_result = $this->_process_pings($ping_servers, $this->c_prefs['channel_title'], $this->c_prefs['ping_url'], $this->c_prefs['rss_url']);
  603. if (is_array($ping_result) AND count($ping_result) > 0)
  604. {
  605. $this->_set_error($ping_result, 'pings');
  606. $result = FALSE;
  607. }
  608. }
  609. // Save ping button state
  610. $this->EE->db->delete('entry_ping_status', array('entry_id' => $entry_id));
  611. foreach ($ping_servers as $val)
  612. {
  613. $ping_data['entry_id'] = $entry_id;
  614. $ping_data['ping_id'] = $val;
  615. $this->EE->db->insert('entry_ping_status', $ping_data);
  616. }
  617. return $result;
  618. }
  619. // --------------------------------------------------------------------
  620. /**
  621. * Get errors
  622. *
  623. * Convenience function to access errors
  624. *
  625. * @access public
  626. * @param string optional field name
  627. * @return mixed
  628. */
  629. function get_errors($field = FALSE)
  630. {
  631. if ($field)
  632. {
  633. return isset($this->errors[$field]) ? $this->errors[$field] : FALSE;
  634. }
  635. return (count($this->errors) > 0) ? $this->errors : FALSE;
  636. }
  637. // --------------------------------------------------------------------
  638. /**
  639. * Trigger Hook
  640. *
  641. * Trigger an entry related hook. Use the second parameter to pass a
  642. * variable that the hook would otherwise erroneously reassign. This
  643. * replaces the active_hook() check. last_call?
  644. *
  645. *
  646. * @access public
  647. * @param mixed variable that gets assigned by the hook
  648. * @return mixed
  649. */
  650. function trigger_hook($hook, $orig_var = NULL)
  651. {
  652. // For hooks that modify a variable, we need to check if they're active
  653. if ($orig_var !== NULL)
  654. {
  655. if ($this->EE->extensions->active_hook($hook) !== TRUE)
  656. {
  657. return $orig_var;
  658. }
  659. }
  660. $cp_call = (REQ == 'CP') ? TRUE : FALSE;
  661. switch($hook)
  662. {
  663. case 'entry_submission_start':
  664. $this->EE->extensions->call('entry_submission_start', $this->channel_id, $this->autosave);
  665. break;
  666. case 'entry_submission_ready':
  667. $this->EE->extensions->call('entry_submission_ready', $this->meta, $this->data, $this->autosave);
  668. break;
  669. case 'entry_submission_redirect':
  670. $loc = $this->EE->extensions->call('entry_submission_redirect', $this->entry_id, $this->meta, $this->data, $cp_call, $orig_var);
  671. if ($this->EE->extensions->end_script === TRUE)
  672. {
  673. return $loc;
  674. }
  675. return $loc;
  676. break;
  677. case 'entry_submission_absolute_end':
  678. $this->EE->extensions->call('entry_submission_absolute_end', $this->entry_id, $this->meta, $this->data, $orig_var);
  679. break;
  680. case 'entry_submission_end':
  681. $this->EE->extensions->call('entry_submission_end', $this->entry_id, $this->meta, $this->data);
  682. break;
  683. default:
  684. return FALSE;
  685. }
  686. if ($this->EE->extensions->end_script === TRUE)
  687. {
  688. return TRUE;
  689. }
  690. }
  691. // --------------------------------------------------------------------
  692. /**
  693. * Set errors
  694. *
  695. * Sets error using a language key and optional field name
  696. *
  697. * @access private
  698. * @param string optional field name
  699. * @return mixed
  700. */
  701. function _set_error($err, $field = '')
  702. {
  703. if ($field != '')
  704. {
  705. if (is_array($err))
  706. {
  707. $this->errors[$field] = $err;
  708. }
  709. else
  710. {
  711. $this->errors[$field] = $this->EE->lang->line($err);
  712. }
  713. }
  714. else
  715. {
  716. if (is_array($err))
  717. {
  718. $this->errors[] = $err;
  719. }
  720. else
  721. {
  722. $this->errors[] = $this->EE->lang->line($err);
  723. }
  724. }
  725. return FALSE;
  726. }
  727. // --------------------------------------------------------------------
  728. /**
  729. * Base Prep
  730. *
  731. * Do basic sanity checks, and grab prerequisites
  732. *
  733. * @access private
  734. * @param string optional field name
  735. * @return mixed
  736. */
  737. function _base_prep(&$data)
  738. {
  739. $this->EE->lang->loadfile('admin_content');
  740. // Sanity Check
  741. if ( ! is_array($data) OR ! isset($data['channel_id']) OR ! is_numeric($data['channel_id']))
  742. {
  743. show_error($this->EE->lang->line('invalid_api_parameter'));
  744. }
  745. $this->channel_id = $data['channel_id'];
  746. // Is this user allowed to post here?
  747. $this->_cache['assigned_channels'] = $this->EE->functions->fetch_assigned_channels();
  748. if ($this->EE->session->userdata('group_id') != 1)
  749. {
  750. if ( ! in_array($this->channel_id, $this->_cache['assigned_channels']))
  751. {
  752. show_error($this->EE->lang->line('unauthorized_for_this_channel'));
  753. }
  754. }
  755. // Make sure all the fields have a key in our data array even
  756. // if no data was sent
  757. if ($this->autosave === FALSE)
  758. {
  759. if ( ! isset($this->EE->api_channel_fields) OR ! isset($this->EE->api_channel_fields->settings))
  760. {
  761. $this->instantiate('channel_fields');
  762. $this->EE->api_channel_fields->fetch_custom_channel_fields();
  763. }
  764. $field_ids = array_keys($this->EE->api_channel_fields->settings);
  765. foreach($field_ids as $id)
  766. {
  767. if (is_numeric($id))
  768. {
  769. $nid = $id;
  770. $id = 'field_id_'.$id;
  771. if ($this->entry_id == 0 && ! isset($data['field_ft_'.$nid]))
  772. {
  773. $data['field_ft_'.$nid] = $this->EE->api_channel_fields->settings[$nid]['field_fmt'];
  774. }
  775. }
  776. if ( ! isset($data[$id]))
  777. {
  778. $data[$id] = '';
  779. }
  780. }
  781. }
  782. // Helpers
  783. $this->EE->load->helper('text');
  784. $this->EE->load->helper('custom_field');
  785. return TRUE;
  786. }
  787. // --------------------------------------------------------------------
  788. /**
  789. * Fetch Channel Preferences
  790. *
  791. * Grabs required channel information and preps a few fields
  792. *
  793. * @access private
  794. * @param int
  795. * @return bool
  796. */
  797. function _fetch_channel_preferences($channel_id = FALSE)
  798. {
  799. // Add another api
  800. $this->instantiate('channel_structure');
  801. if ( ! $channel_id)
  802. {
  803. $channel_id = $this->channel_id;
  804. }
  805. $query = $this->EE->api_channel_structure->get_channel_info($channel_id);
  806. foreach(array('channel_url', 'rss_url', 'deft_status', 'comment_url', 'comment_system_enabled', 'enable_versioning', 'max_revisions') as $key)
  807. {
  808. $this->c_prefs[$key] = $query->row($key);
  809. }
  810. $this->c_prefs['channel_title'] = ascii_to_entities($query->row('channel_title'));
  811. $this->c_prefs['ping_url'] = ($query->row('ping_return_url') == '') ? $query->row('channel_url') : $query->row('ping_return_url') ;
  812. $this->c_prefs['notify_address'] = ($query->row('channel_notify') == 'y' AND $query->row('channel_notify_emails') != '') ? $query->row('channel_notify_emails') : '';
  813. }
  814. // --------------------------------------------------------------------
  815. /**
  816. * Channel Switch
  817. *
  818. * Checks if the channel was changed and verifies if the switch is valid
  819. *
  820. * @access private
  821. * @param int
  822. * @return bool
  823. */
  824. function _do_channel_switch(&$data)
  825. {
  826. if (isset($data['new_channel']) && $data['new_channel'] && $data['new_channel'] != $this->channel_id)
  827. {
  828. $this->EE->db->select('status_group, cat_group, field_group, channel_id');
  829. $this->EE->db->where_in('channel_id', array($this->channel_id, $data['new_channel']));
  830. $query = $this->EE->db->get('channels');
  831. if ($query->num_rows() == 2)
  832. {
  833. $result_zero = $query->row(0);
  834. $result_one = $query->row(1);
  835. if ($result_zero->status_group == $result_one->status_group &&
  836. $result_zero->cat_group == $result_one->cat_group &&
  837. $result_zero->field_group == $result_one->field_group)
  838. {
  839. if ($this->EE->session->userdata('group_id') == 1 OR in_array($data['new_channel'], $this->_cache['assigned_channels']))
  840. {
  841. $data['old_channel'] = $this->channel_id;
  842. $this->channel_id = $data['new_channel'];
  843. }
  844. }
  845. }
  846. }
  847. }
  848. // --------------------------------------------------------------------
  849. /**
  850. * Get module data
  851. *
  852. * Get module information
  853. *
  854. * @access private
  855. * @param mixed
  856. * @return void
  857. */
  858. function _fetch_module_data(&$data, &$mod_data)
  859. {
  860. //$errors = $this->EE->api_channel_fields->get_module_methods('validate_publish', array('data' => $data));
  861. // Note coming from cp- return
  862. if ( ! isset($data['cp_call']) OR $data['cp_call'] !== TRUE)
  863. {
  864. return;
  865. }
  866. $methods = array('validate_publish', 'publish_tabs');
  867. $params = array('validate_publish' => array($data), 'publish_tabs' => array($data['channel_id'], $this->entry_id));
  868. $this->instantiate('channel_fields');
  869. $module_data = $this->EE->api_channel_fields->get_module_methods($methods, $params);
  870. if ($module_data !== FALSE)
  871. {
  872. foreach ($module_data as $class => $m)
  873. {
  874. if (is_array($m['validate_publish']))
  875. {
  876. foreach($m['validate_publish'] as $msg => $field)
  877. {
  878. $this->_set_error($msg, $class.'__'.$field);
  879. }
  880. }
  881. if (is_array($m['publish_tabs']))
  882. {
  883. foreach($m['publish_tabs'] as $tab => $v)
  884. {
  885. //foreach ($v as $val)
  886. //{
  887. $name = $class.'__'.$v['field_id'];
  888. //print_r($v);
  889. //}
  890. // Break out module fields here
  891. $mod_data[$name] = (isset($data[$name])) ? $data[$name] : '';
  892. unset($data[$name]);
  893. }
  894. }
  895. }
  896. }
  897. }
  898. // --------------------------------------------------------------------
  899. /**
  900. * Check for data errors
  901. *
  902. * Error trapping function
  903. *
  904. * @access private
  905. * @param mixed
  906. * @return void
  907. */
  908. function _check_for_data_errors(&$data)
  909. {
  910. // Always required fields
  911. $required = array(
  912. 'title' => 'missing_title',
  913. 'entry_date' => 'missing_date'
  914. );
  915. if ( ! isset($data['title']) OR ! $data['title'] = strip_tags(trim($data['title'])))
  916. {
  917. $data['title'] = '';
  918. $this->_set_error('missing_title', 'title');
  919. }
  920. // Convert built-in date fields to UNIX timestamps
  921. $dates = array('entry_date');
  922. foreach(array('expiration_date', 'comment_expiration_date') as $date)
  923. {
  924. if ( ! isset($data[$date]) OR ! $data[$date])
  925. {
  926. $data[$date] = 0;
  927. }
  928. else
  929. {
  930. $dates[] = $date;
  931. }
  932. }
  933. foreach($dates as $date)
  934. {
  935. if ( ! is_numeric($data[$date]) && trim($data[$date]))
  936. {
  937. $data[$date] = $this->EE->localize->string_to_timestamp($data[$date]);
  938. }
  939. if ($data[$date] === FALSE)
  940. {
  941. $this->_set_error('invalid_date', $date);
  942. }
  943. if (isset($data['revision_post'][$date]))
  944. {
  945. $data['revision_post'][$date] = $data[$date];
  946. }
  947. }
  948. // Required and custom fields
  949. $result_array = $this->_get_custom_fields();
  950. foreach ($result_array as $row)
  951. {
  952. // Required field?
  953. if ($row['field_required'] == 'y')
  954. {
  955. if ($row['field_type'] == "file" AND isset($data['field_id_'.$row['field_id'].'_hidden']) AND $data['field_id_'.$row['field_id'].'_hidden'] == '')
  956. {
  957. $this->_set_error('custom_field_empty', $row['field_label']);
  958. continue;
  959. }
  960. if (isset($data['field_id_'.$row['field_id']]) AND $data['field_id_'.$row['field_id']] === '')
  961. {
  962. $this->_set_error('custom_field_empty', $row['field_label']);
  963. continue;
  964. }
  965. }
  966. elseif ( ! isset($data['field_id_'.$row['field_id']]))
  967. {
  968. // fields that aren't required should still be set
  969. $data['field_id_'.$row['field_id']] = '';
  970. }
  971. // Custom fields that need processing
  972. if ($row['field_type'] == 'file')
  973. {
  974. if ($this->autosave && isset($data['field_id_'.$row['field_id'].'_hidden']))
  975. {
  976. $directory = $data['field_id_'.$row['field_id'].'_directory'];
  977. $data['field_id_'.$row['field_id']] = '{filedir_'.$directory.'}'.$data['field_id_'.$row['field_id'].'_hidden'];
  978. unset($data['field_id_'.$row['field_id'].'_hidden']);
  979. }
  980. unset($data['field_id_'.$row['field_id'].'_directory']);
  981. }
  982. elseif ($row['field_type'] == 'date')
  983. {
  984. $func = '_prep_'.$row['field_type'].'_field';
  985. $this->$func($data, $row);
  986. }
  987. elseif ($row['field_type'] == 'multi_select' OR $row['field_type'] == 'checkboxes')
  988. {
  989. $this->_prep_multi_field($data, $row);
  990. }
  991. }
  992. // Channel data present for pings?
  993. if (isset($data['ping_servers']) && count($data['ping_servers']) > 0)
  994. {
  995. if ($this->c_prefs['channel_title'] == '')
  996. {
  997. $this->_set_error('missing_channel_data_for_pings');
  998. }
  999. }
  1000. // Clean / create the url title
  1001. $data['url_title'] = isset($data['url_title']) ? $data['url_title'] : '';
  1002. $data['url_title'] = $this->_validate_url_title($data['url_title'], $data['title'], (bool) $this->entry_id);
  1003. // Validate author id
  1004. $data['author_id'] = ( ! isset($data['author_id']) OR ! $data['author_id']) ? $this->EE->session->userdata('member_id'): $data['author_id'];
  1005. if ($data['author_id'] != $this->EE->session->userdata('member_id') && $this->EE->session->userdata('can_edit_other_entries') != 'y')
  1006. {
  1007. $this->_set_error('not_authorized');
  1008. }
  1009. if (isset($this->_cache['orig_author_id']) && $data['author_id'] != $this->_cache['orig_author_id'] && ($this->EE->session->userdata('can_edit_other_entries') != 'y' OR $this->EE->session->userdata('can_assign_post_authors') != 'y'))
  1010. {
  1011. $this->_set_error('not_authorized');
  1012. }
  1013. if ($data['author_id'] != $this->EE->session->userdata('member_id') && $this->EE->session->userdata('group_id') != 1)
  1014. {
  1015. if ( ! isset($this->_cache['orig_author_id']) OR $data['author_id'] != $this->_cache['orig_author_id'])
  1016. {
  1017. if ($this->EE->session->userdata('can_assign_post_authors') != 'y')
  1018. {
  1019. $this->_set_error('not_authorized', 'author');
  1020. }
  1021. else
  1022. {
  1023. $allowed_authors = array();
  1024. $this->EE->load->model('member_model');
  1025. $query = $this->EE->member_model->get_authors();
  1026. if ($query->num_rows() > 0)
  1027. {
  1028. foreach($query->result_array() as $row)
  1029. {
  1030. $allowed_authors[] = $row['member_id'];
  1031. }
  1032. }
  1033. if ( ! in_array($data['author_id'], $allowed_authors))
  1034. {
  1035. $this->_set_error('invalid_author', 'author');
  1036. }
  1037. }
  1038. }
  1039. }
  1040. // Validate Status
  1041. $data['status'] = ( ! isset($data['status']) OR $data['status'] === FALSE) ? $this->c_prefs['deft_status'] : $data['status'];
  1042. if ($this->EE->session->userdata('group_id') != 1)
  1043. {
  1044. $disallowed_statuses = array();
  1045. $valid_statuses = array();
  1046. $this->EE->load->model('status_model');
  1047. $query = $this->EE->status_model->get_statuses('', $this->channel_id);
  1048. if ($query->num_rows() > 0)
  1049. {
  1050. foreach ($query->result_array() as $row)
  1051. {
  1052. $valid_statuses[$row['status_id']] = strtolower($row['status']); // lower case to match MySQL's case-insensitivity
  1053. }
  1054. }
  1055. $query = $this->EE->status_model->get_disallowed_statuses($this->EE->session->userdata('group_id'));
  1056. if ($query->num_rows() > 0)
  1057. {
  1058. foreach ($query->result_array() as $row)
  1059. {
  1060. $disallowed_statuses[$row['status_id']] = strtolower($row['status']); // lower case to match MySQL's case-insensitivity
  1061. }
  1062. $valid_statuses = array_diff_assoc($valid_statuses, $disallowed_statuses);
  1063. }
  1064. if ( ! in_array(strtolower($data['status']), $valid_statuses))
  1065. {
  1066. // if there are no valid statuses, set to closed
  1067. $data['status'] = 'closed';
  1068. }
  1069. }
  1070. }
  1071. // --------------------------------------------------------------------
  1072. /**
  1073. * Validate url title
  1074. *
  1075. * Checks url title and regenerates if it's invalid
  1076. *
  1077. * @access private
  1078. * @param string
  1079. * @return string
  1080. */
  1081. function _validate_url_title($url_title = '', $title = '', $update = FALSE)
  1082. {
  1083. $word_separator = $this->EE->config->item('word_separator');
  1084. $this->EE->load->helper('url');
  1085. if ( ! trim($url_title))
  1086. {
  1087. $url_title = url_title($title, $word_separator, TRUE);
  1088. }
  1089. // Remove extraneous characters
  1090. if ($update)
  1091. {
  1092. $this->EE->db->select('url_title');
  1093. $url_query = $this->EE->db->get_where('channel_titles', array('entry_id' => $this->entry_id));
  1094. if ($url_query->row('url_title') != $url_title)
  1095. {
  1096. $url_title = url_title($url_title, $word_separator);
  1097. }
  1098. }
  1099. else
  1100. {
  1101. $url_title = url_title($url_title, $word_separator);
  1102. }
  1103. // URL title cannot be a number
  1104. if (is_numeric($url_title))
  1105. {
  1106. $this->_set_error('url_title_is_numeric', 'url_title');
  1107. }
  1108. // It also cannot be empty
  1109. if ( ! trim($url_title))
  1110. {
  1111. $this->_set_error('unable_to_create_url_title', 'url_title');
  1112. }
  1113. // And now we need to make sure it's unique
  1114. if ($update)
  1115. {
  1116. $url_title = $this->_unique_url_title($url_title, $this->entry_id, $this->channel_id);
  1117. }
  1118. else
  1119. {
  1120. $url_title = $this->_unique_url_title($url_title, '', $this->channel_id);
  1121. }
  1122. // One more safety
  1123. if ( ! $url_title)
  1124. {
  1125. $this->_set_error('unable_to_create_url_title', 'url_title');
  1126. }
  1127. // And lastly, we prevent this potentially problematic case
  1128. if ($url_title == 'index')
  1129. {
  1130. $this->_set_error('url_title_is_index', 'url_title');
  1131. }
  1132. return $url_title;
  1133. }
  1134. // --------------------------------------------------------------------
  1135. /**
  1136. * Prep date field
  1137. *
  1138. * Prepare custom date fields
  1139. *
  1140. * @access private
  1141. * @param mixed
  1142. * @param mixed
  1143. * @return void
  1144. */
  1145. function _prep_date_field(&$data, $row)
  1146. {
  1147. if ( ! isset($data['field_id_'.$row['field_id']]))
  1148. {
  1149. return;
  1150. }
  1151. // Should prevent non-integers from going into the field
  1152. if ( ! trim($data['field_id_'.$row['field_id']]))
  1153. {
  1154. $data['field_id_'.$row['field_id']] = 0;
  1155. return;
  1156. }
  1157. // Date might already be numeric format- so we check
  1158. if ( ! is_numeric($data['field_id_'.$row['field_id']]))
  1159. {
  1160. $data['field_id_'.$row['field_id']] = $this->EE->localize->string_to_timestamp($data['field_id_'.$row['field_id']]);
  1161. }
  1162. if ($data['field_id_'.$row['field_id']] === FALSE)
  1163. {
  1164. $this->_set_error('invalid_date', $row['field_label']);
  1165. }
  1166. else
  1167. {
  1168. $this->_cache['dst_enabled'] = 'n';
  1169. if ( ! isset($data['field_offset_'.$row['field_id']]))
  1170. {
  1171. $data['field_dt_'.$row['field_id']] = '';
  1172. }
  1173. elseif ($data['field_offset_'.$row['field_id']] == 'y')
  1174. {
  1175. $data['field_dt_'.$row['field_id']] = '';
  1176. }
  1177. else
  1178. {
  1179. $data['field_dt_'.$row['field_id']] = $this->EE->session->userdata('timezone');
  1180. }
  1181. }
  1182. }
  1183. // --------------------------------------------------------------------
  1184. /**
  1185. * Prep multi field
  1186. *
  1187. * Prepare multi_select and option_group fields
  1188. *
  1189. * @access private
  1190. * @param mixed
  1191. * @param mixed
  1192. * @return void
  1193. */
  1194. function _prep_multi_field(&$data, $row)
  1195. {
  1196. if (isset($data['field_id_'.$row['field_id']]))
  1197. {
  1198. if (is_array($data['field_id_'.$row['field_id']]))
  1199. {
  1200. $data['field_id_'.$row['field_id']] = encode_multi_field($data['field_id_'.$row['field_id']]);
  1201. return;
  1202. }
  1203. }
  1204. //unset($data['field_id_'.$row['field_id']]);
  1205. }
  1206. // --------------------------------------------------------------------
  1207. /**
  1208. * Prep data
  1209. *
  1210. * Prep all data we need to create an entry
  1211. *
  1212. * @access private
  1213. * @param mixed
  1214. * @param mixed
  1215. * @return void
  1216. */
  1217. function _prepare_data(&$data, &$mod_data, $autosave = FALSE)
  1218. {
  1219. $this->instantiate('channel_categories');
  1220. $this->EE->api_channel_categories->initialize(array(
  1221. 'categories' => array(),
  1222. 'cat_parents' => array(),
  1223. 'cat_array' => array()
  1224. ));
  1225. // Category parents - we toss the rest
  1226. if (isset($data['category']) AND is_array($data['category']))
  1227. {
  1228. foreach ($data['category'] as $cat_id)
  1229. {
  1230. $this->EE->api_channel_categories->cat_parents[] = $cat_id;
  1231. }
  1232. if ($this->EE->api_channel_categories->assign_cat_parent == TRUE)
  1233. {
  1234. $this->EE->api_channel_categories->fetch_category_parents($data['category']);
  1235. }
  1236. }
  1237. // Remove invisible characters from entry title
  1238. if (isset($data['title']))
  1239. {
  1240. $data['title'] = remove_invisible_characters($data['title']);
  1241. }
  1242. unset($data['category']);
  1243. // Prep y / n values
  1244. $data['allow_comments'] = (isset($data['allow_comments']) && $data['allow_comments'] == 'y') ? 'y' : 'n';
  1245. if (isset($data['cp_call']) && $data['cp_call'] == TRUE)
  1246. {
  1247. $data['allow_comments'] = ($data['allow_comments'] !== 'y' OR $this->c_prefs['comment_system_enabled'] == 'n') ? 'n' : 'y';
  1248. }
  1249. if ($this->c_prefs['enable_versioning'] == 'n')
  1250. {
  1251. $data['versioning_enabled'] = 'y';
  1252. }
  1253. else
  1254. {
  1255. if (isset($data['versioning_enabled']))
  1256. {
  1257. $data['versioning_enabled'] = 'y';
  1258. }
  1259. else
  1260. {
  1261. $data['versioning_enabled'] = 'n';
  1262. // In 1.6, this happened right before inserting new revisions,
  1263. // but it makes more sense here.
  1264. $this->c_prefs['enable_versioning'] = 'n';
  1265. }
  1266. }
  1267. $this->_cache['dst_enabled'] = 'n';
  1268. $this->instantiate('channel_fields');
  1269. $result_array = $this->_get_custom_fields();
  1270. foreach ($result_array as $row)
  1271. {
  1272. $field_name = 'field_id_'.$row['field_id'];
  1273. // @todo remove in 2.1.2
  1274. // backwards compatible for some incorrect code noticed in a few third party modules.
  1275. // Will be removed in 2.1.2, and a note to that effect is in the 2.1.1 update notes
  1276. // $this->field_id should be used instead as documented
  1277. // http://ellislab.com/expressionengine/user-guide/development/fieldtypes.html#class-variables
  1278. $this->EE->api_channel_fields->settings[$row['field_id']]['field_id'] = $row['field_id'];
  1279. if (isset($data[$field_name]) OR isset($mod_data[$field_name]))
  1280. {
  1281. $this->EE->api_channel_fields->setup_handler($row['field_id']);
  1282. // Break out module fields here
  1283. if (isset($data[$field_name]))
  1284. {
  1285. if ( ! $autosave)
  1286. {
  1287. $data[$field_name] = $this->EE->api_channel_fields->apply('save', array($data[$field_name]));
  1288. }
  1289. if (isset($data['revision_post'][$field_name]))
  1290. {
  1291. $data['revision_post'][$field_name] = $data[$field_name];
  1292. }
  1293. }
  1294. elseif (isset($mod_data[$field_name]))
  1295. {
  1296. if ( ! $autosave)
  1297. {
  1298. $mod_data[$field_name] = $this->EE->api_channel_fields->apply('save', array($mod_data[$field_name]));
  1299. }
  1300. if (isset($data['revision_post'][$field_name]))
  1301. {
  1302. $data['revision_post'][$field_name] = $mod_data[$field_name];
  1303. }
  1304. }
  1305. }
  1306. }
  1307. }
  1308. // --------------------------------------------------------------------
  1309. /**
  1310. * Build Relationships
  1311. *
  1312. * Build the relationships for our entry
  1313. *
  1314. * @access private
  1315. * @param mixed
  1316. * @return void
  1317. */
  1318. function _build_relationships(&$data)
  1319. {
  1320. if ($this->autosave)
  1321. {
  1322. return;
  1323. }
  1324. $this->EE->db->select('field_id, field_related_to, field_related_id');
  1325. $query = $this->EE->db->get_where('channel_fields', array('field_type' => 'rel'));
  1326. // No results, bail out early
  1327. if ( ! $query->num_rows())
  1328. {
  1329. $this->_cache['rel_updates'] = array();
  1330. return;
  1331. }
  1332. $rel_updates = array();
  1333. foreach ($query->result_array() as $row)
  1334. {
  1335. $field_id = $row['field_id'];
  1336. // No field - skip
  1337. if ( ! isset($data['field_id_'.$field_id]))
  1338. {
  1339. continue;
  1340. }
  1341. $data['field_ft_'.$field_id] = 'none';
  1342. $rel_exists = FALSE;
  1343. // If editing an existing entry....
  1344. // Does an existing relationship exist? If so, we may not need to recompile the data
  1345. if ($this->entry_id)
  1346. {
  1347. // First we fetch the previously stored related child id.
  1348. $this->EE->db->select('field_id_'.$field_id.', rel_child_id, rel_id');
  1349. $this->EE->db->from('channel_data');
  1350. $this->EE->db->join('relationships', 'field_id_'.$field_id.' = rel_id', 'left');
  1351. $this->EE->db->where('entry_id', $this->entry_id);
  1352. $rel_data = $this->EE->db->get();
  1353. $current_related = FALSE;
  1354. $rel_id = FALSE;
  1355. if ($rel_data->num_rows() > 0)
  1356. {
  1357. foreach ($rel_data->result() as $r)
  1358. {
  1359. $current_related = $r->rel_child_id;
  1360. $rel_id = $r->rel_id;
  1361. }
  1362. }
  1363. // If the previous ID matches the current ID being submitted it means that
  1364. // the existing relationship has not changed so there's no need to recompile.
  1365. // If it has changed we'll clear the old relationship.
  1366. if ($current_related == $data['field_id_'.$field_id])
  1367. {
  1368. $rel_exists = TRUE;
  1369. $data['field_id_'.$field_id] = $rel_id;
  1370. }
  1371. elseif ($rel_id)
  1372. {
  1373. $this->EE->db->where('rel_id', $rel_id);
  1374. $this->EE->db->delete('relationships');
  1375. }
  1376. }
  1377. if (is_numeric($data['field_id_'.$field_id]) && $data['field_id_'.$field_id] != '0' && $rel_exists == FALSE)
  1378. {
  1379. $reldata = array(
  1380. 'type' => $row['field_related_to'],
  1381. 'parent_id' => $this->entry_id, // we may have an empty entry_id at this point, if so, zero for now, gets updated below
  1382. 'child_id' => $data['field_id_'.$field_id]
  1383. );
  1384. $data['field_id_'.$field_id] = $this->EE->functions->compile_relationship($reldata, TRUE);
  1385. $rel_updates[] = $data['field_id_'.$field_id];
  1386. }
  1387. elseif($data['field_id_'.$field_id] == '')
  1388. {
  1389. $data['field_id_'.$field_id] = 0;
  1390. }
  1391. }
  1392. $this->_cache['rel_updates'] = $rel_updates;
  1393. }
  1394. // --------------------------------------------------------------------
  1395. /**
  1396. * Insert Entry
  1397. *
  1398. * Creates primary data for a new entry
  1399. *
  1400. * @access private
  1401. * @param mixed
  1402. * @param mixed
  1403. * @return void
  1404. */
  1405. function _insert_entry($meta, &$data, &$mod_data)
  1406. {
  1407. $meta['dst_enabled'] = $this->_cache['dst_enabled'];
  1408. if ($this->autosave)
  1409. {
  1410. if ($this->autosave_entry_id)
  1411. {
  1412. $this->EE->db->where('entry_id', $this->autosave_entry_id);
  1413. $this->EE->db->update('channel_entries_autosave', $meta);
  1414. $this->entry_id = $this->autosave_entry_id;
  1415. }
  1416. else
  1417. {
  1418. // In the event there's no original_entry_id assign it to 0
  1419. if ( ! isset($meta['original_entry_id']))
  1420. {
  1421. $meta['original_entry_id'] = 0;
  1422. }
  1423. $this->EE->db->insert('channel_entries_autosave', $meta);
  1424. $this->entry_id = $this->EE->db->insert_id();
  1425. }
  1426. }
  1427. else
  1428. {
  1429. $this->EE->db->insert('channel_titles', $meta);
  1430. $this->entry_id = $this->EE->db->insert_id();
  1431. }
  1432. // Update Relationships (autosave skips this)
  1433. if ( ! $this->autosave && count($this->_cache['rel_updates']) > 0)
  1434. {
  1435. $this->EE->db->set('rel_parent_id', $this->entry_id);
  1436. $this->EE->db->where_in('rel_id', $this->_cache['rel_updates']);
  1437. $this->EE->db->update('relationships');
  1438. }
  1439. // Insert custom field data
  1440. $cust_fields = array('entry_id' => $this->entry_id, 'channel_id' => $this->channel_id, 'site_id' => $this->EE->config->item('site_id'));
  1441. foreach($data as $key => $val)
  1442. {
  1443. if (strncmp($key, 'field_offset_', 13) == 0)
  1444. {
  1445. unset($data[$key]);
  1446. continue;
  1447. }
  1448. if (strncmp($key, 'field', 5) == 0)
  1449. {
  1450. if (strncmp($key, 'field_id_', 9) == 0 && ! is_numeric($val))
  1451. {
  1452. if ($this->EE->config->item('auto_convert_high_ascii') == 'y')
  1453. {
  1454. $cust_fields[$key] = (is_array($val)) ? $this->_recursive_ascii_to_entities($val) : $val;
  1455. }
  1456. else
  1457. {
  1458. $cust_fields[$key] = $val;
  1459. }
  1460. }
  1461. else
  1462. {
  1463. $cust_fields[$key] = $val;
  1464. }
  1465. // set missing defaults here. $data['field_ft_'.$row['field_id']] = 'none';
  1466. }
  1467. }
  1468. // Check that data complies with mysql strict mode rules
  1469. $all_fields = $this->EE->db->field_data('channel_data');
  1470. foreach ($all_fields as $field)
  1471. {
  1472. if (strncmp($field->name, 'field_id_', 9) == 0)
  1473. {
  1474. if ($field->type == 'text' OR $field->type == 'blob')
  1475. {
  1476. if ( ! isset($cust_fields[$field->name]) OR is_null($cust_fields[$field->name]))
  1477. {
  1478. $cust_fields[$field->name] = '';
  1479. }
  1480. }
  1481. elseif ($field->type == 'int' && isset($cust_fields[$field->name]) && $cust_fields[$field->name] === '')
  1482. {
  1483. unset($cust_fields[$field->name]);
  1484. }
  1485. }
  1486. }
  1487. if ($this->autosave)
  1488. {
  1489. // Entry for this was made earlier, now its an update not an insert
  1490. $cust_fields['entry_id'] = $this->entry_id;
  1491. $cust_fields['original_entry_id'] = 0;
  1492. $this->EE->db->where('entry_id', $this->entry_id);
  1493. $this->EE->db->set('entry_data', serialize(array_merge($cust_fields, $mod_data)));
  1494. $this->EE->db->update('channel_entries_autosave'); // reinsert
  1495. return $this->entry_id;
  1496. }
  1497. $this->EE->db->insert('channel_data', $cust_fields);
  1498. // If remove old autosave data
  1499. if ($this->autosave_entry_id)
  1500. {
  1501. $this->EE->db->delete('channel_entries_autosave', array('entry_id' => $this->autosave_entry_id));
  1502. }
  1503. // Update member stats
  1504. if ($meta['author_id'] == $this->EE->session->userdata('member_id'))
  1505. {
  1506. $total_entries = $this->EE->session->userdata('total_entries') + 1;
  1507. }
  1508. else
  1509. {
  1510. $this->EE->db->select('total_entries');
  1511. $query = $this->EE->db->get_where('members', array('member_id' => $meta['author_id']));
  1512. $total_entries = $query->row('total_entries') + 1;
  1513. }
  1514. $this->EE->db->set(array('total_entries' => $total_entries, 'last_entry_date' => $this->EE->localize->now));
  1515. $this->EE->db->where('member_id', $meta['author_id']);
  1516. $this->EE->db->update('members');
  1517. // Send admin notification
  1518. if ($this->c_prefs['notify_address'] != '')
  1519. {
  1520. $this->EE->load->library('notifications');
  1521. $this->EE->notifications->send_admin_notification($this->c_prefs['notify_address'], $this->channel_id, $this->entry_id);
  1522. }
  1523. }
  1524. // --------------------------------------------------------------------
  1525. /**
  1526. * Update Entry
  1527. *
  1528. * Updates primary data for an entry
  1529. *
  1530. * @access private
  1531. * @param mixed
  1532. * @param mixed
  1533. * @return void
  1534. */
  1535. function _update_entry($meta, &$data, &$mod_data)
  1536. {
  1537. $meta['dst_enabled'] = $this->_cache['dst_enabled'];
  1538. // See if the author changed and store the old author ID for updating stats later
  1539. $this->EE->db->select('author_id');
  1540. $query = $this->EE->db->get_where('channel_titles', array('entry_id' => $this->entry_id));
  1541. $old_author = $query->row('author_id');
  1542. // Update the entry data
  1543. unset($meta['entry_id']);
  1544. if ($this->autosave)
  1545. {
  1546. $this->EE->db->delete('channel_entries_autosave', array('original_entry_id' => $this->entry_id)); // remove all entries for this
  1547. $meta['original_entry_id'] = $this->entry_id;
  1548. $this->EE->db->insert('channel_entries_autosave', $meta); // reinsert
  1549. $autosave_entry_id = $this->EE->db->insert_id();
  1550. }
  1551. else
  1552. {
  1553. $this->EE->db->where('entry_id', $this->entry_id);
  1554. $this->EE->db->update('channel_titles', $meta);
  1555. }
  1556. // Update Custom fields
  1557. $cust_fields = array('channel_id' => $this->channel_id);
  1558. foreach ($data as $key => $val)
  1559. {
  1560. if (strncmp($key, 'field_offset_', 13) == 0)
  1561. {
  1562. unset($data[$key]);
  1563. continue;
  1564. }
  1565. if (strncmp($key, 'field', 5) == 0)
  1566. {
  1567. if (strncmp($key, 'field_id_', 9) == 0 && ! is_numeric($val))
  1568. {
  1569. if ($this->EE->config->item('auto_convert_high_ascii') == 'y')
  1570. {
  1571. $cust_fields[$key] = (is_array($val)) ? $this->_recursive_ascii_to_entities($val) : $val;
  1572. }
  1573. else
  1574. {
  1575. $cust_fields[$key] = $val;
  1576. }
  1577. }
  1578. else
  1579. {
  1580. $cust_fields[$key] = $val;
  1581. }
  1582. }
  1583. }
  1584. if (count($cust_fields) > 0)
  1585. {
  1586. if ($this->autosave)
  1587. {
  1588. // Need to add to our custom fields array
  1589. $t

Large files files are truncated, but you can click here to view the full file