PageRenderTime 55ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://github.com/asalem/pyrocms
PHP | 1807 lines | 770 code | 336 blank | 701 comment | 231 complexity | 6ce625599562677fdbc4433c24f9499e MD5 | raw file
Possible License(s): CC-BY-3.0, BSD-3-Clause, CC0-1.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, MIT

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

  1. <?php defined('BASEPATH') or exit('No direct script access allowed');
  2. /**
  3. * PyroStreams Row 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 Row_m extends MY_Model
  12. {
  13. /**
  14. * Field Types to Ignore
  15. *
  16. * An array of the default columns
  17. * that are created in every stream table
  18. * that we don't need to include in
  19. * some processes.
  20. *
  21. * @var array
  22. */
  23. public $ignore = array('id', 'created', 'updated', 'created_by');
  24. // --------------------------------------------------------------------------
  25. /**
  26. * Cycle Select String
  27. *
  28. * @var string
  29. */
  30. public $data;
  31. // --------------------------------------------------------------------------
  32. /**
  33. * Base Prefix
  34. *
  35. * Convenience Var
  36. *
  37. * @var string
  38. */
  39. public $base_prefix;
  40. // --------------------------------------------------------------------------
  41. /**
  42. * Cycle Select String
  43. *
  44. * Each of the arrays can also be a string,
  45. * in which case they will not be imploded.
  46. *
  47. * @var string
  48. */
  49. public $sql = array(
  50. 'select' => array(), // will be joined by ','
  51. 'where' => array(), // will be joined by 'AND'
  52. 'from' => array(), // array of tables
  53. 'join' => array(), // array of joins
  54. 'order_by' => array(), // will be joined by ','
  55. 'misc' => array() // will be joined by line breaks
  56. );
  57. // --------------------------------------------------------------------------
  58. /**
  59. * All fields (so we don't have)
  60. * to keep grabbing them from
  61. * the database.
  62. *
  63. * @var obj
  64. */
  65. public $all_fields = array();
  66. // --------------------------------------------------------------------------
  67. /**
  68. * Streams structure
  69. *
  70. * @var array
  71. */
  72. public $structure;
  73. // --------------------------------------------------------------------------
  74. /**
  75. * Array of IDs called, by stream.
  76. * Used to exclude IDs already called.
  77. * @since 2.1
  78. */
  79. public $called;
  80. // --------------------------------------------------------------------------
  81. /**
  82. * Hook for get_rows
  83. *
  84. * @param public
  85. * @var array($obj, $method_name)
  86. */
  87. public $get_rows_hook = array();
  88. // --------------------------------------------------------------------------
  89. /**
  90. * Data to send to the function
  91. *
  92. * @var obj
  93. */
  94. public $get_rows_hook_data;
  95. // --------------------------------------------------------------------------
  96. /**
  97. * Runtime cache for gather_structure()
  98. *
  99. * @var obj
  100. */
  101. public $gather_structure_cache;
  102. // --------------------------------------------------------------------------
  103. /**
  104. * Set Fields
  105. *
  106. * Grab the fields for a stream
  107. *
  108. * @param stream object
  109. * @return void
  110. */
  111. private function set_fields($stream_namespace)
  112. {
  113. // If our stream namespace doesn't exist
  114. if ( ! isset($this->all_fields[$stream_namespace])) {
  115. $this->all_fields[$stream_namespace] = $this->fields_m->get_all_fields($stream_namespace);
  116. }
  117. }
  118. // --------------------------------------------------------------------------
  119. /**
  120. * Get Rows
  121. *
  122. * Get rows from a stream
  123. *
  124. * @return array
  125. * @param array
  126. * @param obj
  127. * @param obj
  128. * @return array
  129. */
  130. public function get_rows($params, $field = null, $stream)
  131. {
  132. $return = array();
  133. // Set our fields for formatting.
  134. $this->set_fields($stream->stream_namespace);
  135. // First, let's get all out fields. That's
  136. // right. All of them.
  137. $this->all_fields[] = $this->fields_m->get_all_fields();
  138. // Now the structure. We will need this as well.
  139. $this->structure = $this->gather_structure();
  140. // So we don't get things confused
  141. if (isset($params['stream'])) {
  142. unset($params['stream']);
  143. }
  144. // -------------------------------------
  145. // Get Our Stream Fields
  146. // -------------------------------------
  147. $stream_fields = $this->streams_m->get_stream_fields($stream->id);
  148. // -------------------------------------
  149. // Extract Our Params
  150. // -------------------------------------
  151. extract($params, EXTR_OVERWRITE);
  152. // -------------------------------------
  153. // Set the site_ref
  154. // -------------------------------------
  155. // Allows you to use streams from other
  156. // sites on a multi-site managed site.
  157. // -------------------------------------
  158. if ( ! isset($site_ref)) $site_ref = SITE_REF;
  159. $this->db->set_dbprefix($site_ref.'_');
  160. // -------------------------------------
  161. // Convenience Vars
  162. // -------------------------------------
  163. $this->data = new stdClass();
  164. $this->data->stream = $stream;
  165. $this->select_prefix = $this->db->protect_identifiers($stream->stream_prefix.$stream->stream_slug, true).'.';
  166. // -------------------------------------
  167. // Start Query Build
  168. // -------------------------------------
  169. // We may build on this.
  170. $this->sql['select'][] = $this->db->protect_identifiers($stream->stream_prefix.$stream->stream_slug, true).'.*';
  171. // -------------------------------------
  172. // From
  173. // -------------------------------------
  174. $this->sql['from'][] = $this->db->protect_identifiers($stream->stream_prefix.$stream->stream_slug, true);
  175. // -------------------------------------
  176. // Get the day.
  177. // For calendars and stuff
  178. // -------------------------------------
  179. if (isset($get_day) and $get_day == true) {
  180. $this->sql['select'][] = 'DAY('.$this->format_mysql_date($date_by, $stream->stream_namespace).') as pyrostreams_cal_day';
  181. }
  182. // -------------------------------------
  183. // Filter API
  184. // -------------------------------------
  185. $filter_api = array();
  186. if ($this->input->get('filter-'.$stream->stream_slug)) {
  187. // Get all URL variables
  188. $url_variables = $this->input->get();
  189. $processed = array();
  190. // Loop and process
  191. foreach ($url_variables as $filter => $value) {
  192. // -------------------------------------
  193. // Filter API Params
  194. // -------------------------------------
  195. // They all start with f-
  196. // No value? No soup for you!
  197. // -------------------------------------
  198. if (substr($filter, 0, 2) != 'f-') continue; // Not a filter API parameter
  199. if (strlen($value) == 0) continue; // No value.. boo
  200. $filter = substr($filter, 2); // Remove identifier
  201. // -------------------------------------
  202. // Not
  203. // -------------------------------------
  204. // Default: false
  205. // -------------------------------------
  206. $not = substr($filter, 0, 4) == 'not-';
  207. if ($not) $filter = substr($filter, 4); // Remove identifier
  208. // -------------------------------------
  209. // Exact
  210. // -------------------------------------
  211. // Default: false
  212. // -------------------------------------
  213. $exact = substr($filter, 0, 6) == 'exact-';
  214. if ($exact) $filter = substr($filter, 6); // Remove identifier
  215. // -------------------------------------
  216. // Construct the where segment
  217. // -------------------------------------
  218. if ($exact) {
  219. if ($not) {
  220. $filter_api[] = $this->db->protect_identifiers($stream->stream_prefix.$stream->stream_slug.'.'.$filter).' != "'.urldecode($value).'"';
  221. } else {
  222. $filter_api[] = $this->db->protect_identifiers($stream->stream_prefix.$stream->stream_slug.'.'.$filter).' = "'.urldecode($value).'"';
  223. }
  224. } else {
  225. if ($not) {
  226. $filter_api[] = $this->db->protect_identifiers($stream->stream_prefix.$stream->stream_slug.'.'.$filter).' NOT LIKE "%'.urldecode($value).'%"';
  227. } else {
  228. $filter_api[] = $this->db->protect_identifiers($stream->stream_prefix.$stream->stream_slug.'.'.$filter).' LIKE "%'.urldecode($value).'%"';
  229. }
  230. }
  231. }
  232. }
  233. // -------------------------------------
  234. // Disable
  235. // -------------------------------------
  236. // Allows users to turn off relationships
  237. // and created_by to save some queries
  238. // -------------------------------------
  239. if (isset($disable) and $disable) {
  240. // Can be pre-processed
  241. if ( ! is_array($disable)) {
  242. $disable = explode('|', $disable);
  243. }
  244. } else {
  245. $disable = array();
  246. }
  247. // -------------------------------------
  248. // Created By
  249. // -------------------------------------
  250. // We are grabbing several user variables
  251. // as part of the main query.
  252. // -------------------------------------
  253. if ( ! in_array('created_by', $disable)) {
  254. $this->sql['select'][] = '`cb_users`.`id` as `created_by||user_id`';
  255. $this->sql['select'][] = '`cb_users`.`email` as `created_by||email`';
  256. $this->sql['select'][] = '`cb_users`.`username` as `created_by||username`';
  257. $this->sql['select'][] = '`profiles`.`display_name` as `created_by||display_name`';
  258. $this->sql['join'][] = 'LEFT JOIN '.$this->db->protect_identifiers('users', true).' as `cb_users` ON `cb_users`.`id`='.$this->db->protect_identifiers($stream->stream_prefix.$stream->stream_slug.'.created_by', true);
  259. $this->sql['join'][] = 'LEFT JOIN '.$this->db->protect_identifiers('profiles', true).' as `profiles` ON `profiles`.`user_id`='.$this->db->protect_identifiers($stream->stream_prefix.$stream->stream_slug.'.created_by', true);
  260. }
  261. // -------------------------------------
  262. // Field Type Hooks
  263. // -------------------------------------
  264. // By adding a query_build_hook() function,
  265. // field types can affect the sql array
  266. // at this time.
  267. // -------------------------------------
  268. if ($stream_fields) {
  269. foreach ($stream_fields as $field_slug => $stream_field) {
  270. if ( ! in_array($field_slug, $disable)
  271. and isset($this->type->types->{$stream_field->field_type})
  272. and method_exists($this->type->types->{$stream_field->field_type}, 'query_build_hook'))
  273. {
  274. $this->type->types->{$stream_field->field_type}->query_build_hook($this->sql, $stream_field, $stream);
  275. }
  276. }
  277. }
  278. // -------------------------------------
  279. // Ordering and Sorting
  280. // -------------------------------------
  281. if (isset($sort) and $sort == 'random') {
  282. // If we are doing sort by random,
  283. // it is a string since it is the only one
  284. $this->sql['order_by'] = 'RAND()';
  285. } else {
  286. // Query string API overrides all
  287. // Check if there is one now
  288. if ($this->input->get('sort-'.$stream->stream_slug)) {
  289. $sort = $this->input->get('sort-'.$stream->stream_slug);
  290. }
  291. // Default Sort. This should be set beforehand,
  292. // but setting it here is a last resort
  293. elseif ( ! isset($sort) or $sort == '') {
  294. $sort = 'DESC';
  295. }
  296. // Query string API overrides all
  297. // Check if there is one now
  298. if ($this->input->get('order-'.$stream->stream_slug)) {
  299. $this->sql['order_by'][] = $this->select_prefix.$this->db->protect_identifiers($this->input->get('order-'.$stream->stream_slug)).' '.strtoupper($sort);
  300. }
  301. // Other sorting options
  302. elseif ( ! isset($order_by) or $order_by == '') {
  303. // Let's go with the stream setting now
  304. // since there isn't an override
  305. if ($stream->sorting == 'title' and $stream->title_column) {
  306. $this->sql['order_by'][] = $this->select_prefix.$this->db->protect_identifiers($stream->title_column).' '.strtoupper($sort);
  307. } elseif ($stream->sorting == 'custom') {
  308. $this->sql['order_by'][] = $this->select_prefix.$this->db->protect_identifiers('ordering_count').' '.strtoupper($sort);
  309. }
  310. } else {
  311. $this->sql['order_by'][] = $this->select_prefix.$this->db->protect_identifiers($order_by).' '.strtoupper($sort);
  312. }
  313. }
  314. // -------------------------------------
  315. // Exclude
  316. // -------------------------------------
  317. // Do we have anything in the excludes that we can add?
  318. if (isset($exclude_called) and $exclude_called == 'yes' and
  319. isset($this->called[$stream->stream_slug]) and ! empty($this->called[$stream->stream_slug]))
  320. {
  321. $exclude .= '|'.implode('|', $this->called[$stream->stream_slug]);
  322. }
  323. if (isset($exclude) and $exclude) {
  324. $exclusions = explode('|', $exclude);
  325. foreach ($exclusions as $exclude_id) {
  326. $this->sql['where'][] = $this->select_prefix.$this->db->protect_identifiers($exclude_by).' !='.$this->db->escape($exclude_id);
  327. }
  328. }
  329. // -------------------------------------
  330. // Include
  331. // -------------------------------------
  332. if (isset($include) and $include) {
  333. $inclusions = explode('|', $include);
  334. $includes = array();
  335. foreach ($inclusions as $include_id) {
  336. $includes[] = $this->select_prefix.$this->db->protect_identifiers($include_by).'='.$this->db->escape($include_id);
  337. }
  338. $this->sql['where'][] = '('.implode(' OR ', $includes).')';
  339. }
  340. // -------------------------------------
  341. // Where (Legacy)
  342. // -------------------------------------
  343. if (isset($where_legacy) and $where_legacy) {
  344. // Replace the segs
  345. $seg_markers = array('seg_1', 'seg_2', 'seg_3', 'seg_4', 'seg_5', 'seg_6', 'seg_7');
  346. $seg_values = array($this->uri->segment(1), $this->uri->segment(2), $this->uri->segment(3), $this->uri->segment(4), $this->uri->segment(5), $this->uri->segment(6), $this->uri->segment(7));
  347. $where_legacy = str_replace($seg_markers, $seg_values, $where_legacy);
  348. $vals = explode('==', trim($where_legacy));
  349. if (count($vals) == 2) {
  350. $this->sql['where'][] = $this->select_prefix.$this->db->protect_identifiers($vals[0]).' ='.$this->db->escape($vals[1]);
  351. }
  352. }
  353. // -------------------------------------
  354. // Where (Current)
  355. // -------------------------------------
  356. if (isset($where) and $where) {
  357. if (is_string($where)) {
  358. $this->sql['where'][] = $this->process_where($where);
  359. } else {
  360. foreach($where as $where_item) {
  361. $this->sql['where'][] = $this->process_where($where_item);
  362. }
  363. }
  364. }
  365. $this->sql['where'] = array_merge($this->sql['where'], $filter_api);
  366. // -------------------------------------
  367. // Show Upcoming
  368. // -------------------------------------
  369. if (isset($show_upcoming) and $show_upcoming == 'no') {
  370. $this->sql['where'][] = $this->format_mysql_date($date_by, $stream->stream_namespace).' <= CURDATE()';
  371. }
  372. // -------------------------------------
  373. // Show Past
  374. // -------------------------------------
  375. if (isset($show_past) and $show_past == 'no') {
  376. $this->sql['where'][] = $this->format_mysql_date($date_by, $stream->stream_namespace).' >= CURDATE()';
  377. }
  378. // -------------------------------------
  379. // Month / Day / Year
  380. // -------------------------------------
  381. if (isset($year) and is_numeric($year)) {
  382. $this->sql['where'][] = 'YEAR('.$this->format_mysql_date($date_by, $stream->stream_namespace).')='.$this->db->escape($year);
  383. }
  384. if (isset($month) and is_numeric($month)) {
  385. $this->sql['where'][] = 'MONTH('.$this->format_mysql_date($date_by, $stream->stream_namespace).')='.$this->db->escape($month);
  386. }
  387. if (isset($day) and is_numeric($day)) {
  388. $this->sql['where'][] = 'DAY('.$this->format_mysql_date($date_by, $stream->stream_namespace).')='.$this->db->escape($day);
  389. }
  390. // -------------------------------------
  391. // Restrict User
  392. // -------------------------------------
  393. // This allows us to restrict returned
  394. // entries by created_by. $restrict_user
  395. // Could have the following values:
  396. // - 'current'
  397. // - a user id
  398. // - a username
  399. // -------------------------------------
  400. if (isset($restrict_user) and $restrict_user) {
  401. $restrict_user_id = null;
  402. if ($restrict_user != 'no') {
  403. // Should we restrict to the current user?
  404. if ($restrict_user == 'current') {
  405. // Check and see if a user is logged in
  406. // and then set the param
  407. if (isset($this->current_user->id) and is_numeric($this->current_user->id)) {
  408. $restrict_user_id = $this->current_user->id;
  409. }
  410. } elseif (is_numeric($restrict_user)) {
  411. // It's numeric, meaning we can just
  412. // use it below easy!
  413. $restrict_user_id = $restrict_user;
  414. } else {
  415. // Looks like they might have put in a user's handle
  416. $user = $this->db
  417. ->select('id')
  418. ->limit(1)
  419. ->where('username', $restrict_user)
  420. ->get('users')->row();
  421. if ($user) {
  422. $restrict_user_id = $user->id;
  423. }
  424. }
  425. }
  426. // Did we get a restrict user value from the
  427. // options above? If so, let's filter by it!
  428. if ($restrict_user_id) {
  429. $this->sql['where'][] = $this->select_prefix.$this->db->protect_identifiers('created_by').'='.$restrict_user_id;
  430. }
  431. }
  432. // -------------------------------------
  433. // Get by ID
  434. // -------------------------------------
  435. if (isset($id) and is_numeric($id)) {
  436. $this->sql['where'][] = $this->select_prefix.$this->db->protect_identifiers('id').'='.$id;
  437. $limit = 1;
  438. $offset = 0;
  439. }
  440. // -------------------------------------
  441. // Single
  442. // -------------------------------------
  443. // I don't even know why this exists
  444. // really, but it does make sure that
  445. // limit is set to one.
  446. // -------------------------------------
  447. if (isset($single) and $single == 'yes') {
  448. $limit = 1;
  449. }
  450. // -------------------------------------
  451. // Hook
  452. // -------------------------------------
  453. // This hook can be used by fields
  454. // to add to the query
  455. // -------------------------------------
  456. if ($this->get_rows_hook) {
  457. if (method_exists($this->get_rows_hook[0], $this->get_rows_hook[1])) {
  458. $this->get_rows_hook[0]->{$this->get_rows_hook[1]}($this->get_rows_hook_data, $this);
  459. }
  460. }
  461. // -------------------------------------
  462. // Run Our Select
  463. // -------------------------------------
  464. $sql = $this->build_query($this->sql);
  465. // -------------------------------------
  466. // Pagination
  467. // -------------------------------------
  468. if (isset($paginate) and $paginate == 'yes') {
  469. $count_sql = $this->build_count_query($this->sql);
  470. // Run the query as is. It does not
  471. // have limit/offset, so we can get the
  472. // total num rows with the current
  473. // parameters we have applied.
  474. $return['pag_count'] = $this->db->query($count_sql)->row()->count;
  475. // Get the number.
  476. if (isset($pag_uri_method) and $pag_uri_method == 'query_string') {
  477. // Get the query string var
  478. if ( ! isset($pag_query_var) or $pag_query_var) {
  479. $pag_query_var = 'page';
  480. }
  481. $pag_id = $this->input->get($pag_query_var);
  482. // We, at the very least, need to be on page 1.
  483. if ( ! $pag_id or ! is_numeric($pag_id) or $pag_id < 1) {
  484. $pag_id = 1;
  485. }
  486. } else {
  487. $pag_id = $this->uri->segment($pag_segment, 0);
  488. }
  489. if (isset($pag_method)) {
  490. if ($pag_method == 'page') {
  491. $offset = $limit*($pag_id-1);
  492. } else {
  493. // Default is 'offset',
  494. // our segment holds the offset
  495. $offset = $pag_id;
  496. }
  497. } else {
  498. // If there is no pag_method set, we will
  499. // just use $pag_id as the offset.
  500. $offset = $pag_id;
  501. }
  502. }
  503. // -------------------------------------
  504. // Offset
  505. // -------------------------------------
  506. // Normalize offset to 0 just in case.
  507. // -------------------------------------
  508. if ( ! isset($offset) or ! is_numeric($offset) or ! $offset or $offset < 0) {
  509. $offset = 0;
  510. }
  511. // -------------------------------------
  512. // Limit & Offset
  513. // -------------------------------------
  514. if (isset($limit) and is_numeric($limit)) {
  515. $sql .= ' LIMIT '.$limit;
  516. }
  517. if (isset($offset) and is_numeric($offset) and $offset != 0) {
  518. $sql .= ' OFFSET '.$offset;
  519. }
  520. // -------------------------------------
  521. // Run the Get
  522. // -------------------------------------
  523. $rows = $this->db->query($sql)->result_array();
  524. // -------------------------------------
  525. // Reset SQL
  526. // We no longer need any of the SQL data.
  527. // If anything goes wrong with the items
  528. // below, we want to make sure we cleared
  529. // the SQL.
  530. // -------------------------------------
  531. $this->reset_sql();
  532. // -------------------------------------
  533. // Partials
  534. // -------------------------------------
  535. // Paritals are done after the data grab
  536. // so we can still partials outsider of
  537. // limits/offsets in queries.
  538. // -------------------------------------
  539. if (isset($partial) and ! is_null($partial)) {
  540. if (count($partials = explode('of', $partial)) == 2 and is_numeric($partials[1])) {
  541. // Break the array into how many pieces
  542. // we want.
  543. $chunks = array_chunk($rows, ceil(count($rows)/$partials[1]), true);
  544. if (isset($chunks[$partials[0]-1])) {
  545. $rows =& $chunks[$partials[0]-1];
  546. }
  547. }
  548. }
  549. // -------------------------------------
  550. // Run formatting
  551. // -------------------------------------
  552. $return['rows'] = $this->format_rows($rows, $stream, $disable, $stream_fields);
  553. // Reset
  554. $this->get_rows_hook = array();
  555. $this->db->set_dbprefix(SITE_REF.'_');
  556. return $return;
  557. }
  558. // --------------------------------------------------------------------------
  559. /**
  560. * Format MySQL Date
  561. *
  562. * Dates in streams can either be in UNIX or MYSQL format.
  563. * This formats any MySQL dates so we can do our date functions as
  564. * UNIX time stamps.
  565. *
  566. * @access public
  567. * @param string $data_by
  568. * @param string $stream_namespace
  569. * @return string
  570. */
  571. public function format_mysql_date($date_by, $stream_namespace)
  572. {
  573. $return = $date_by;
  574. // Get the field and see if it has a preference for UNIX vs. MySQL
  575. if (array_key_exists($date_by, $this->all_fields[$stream_namespace]) and ($date_by != 'created' and $date_by != 'updated')) {
  576. if (isset($this->all_fields[$stream_namespace][$date_by]['field_data']['storage']) and $this->all_fields[$stream_namespace][$date_by]['field_data']['storage'] == 'unix') {
  577. return 'FROM_UNIXTIME('.$this->select_prefix.$this->db->protect_identifiers($date_by).')';
  578. }
  579. }
  580. return $this->select_prefix.$this->db->protect_identifiers($date_by);
  581. }
  582. // --------------------------------------------------------------------------
  583. /**
  584. * Build Query
  585. *
  586. * Does not do LIMIT/OFFSET since that will
  587. * be taken care of after pagination is
  588. * calculated.
  589. *
  590. * @param array [$sql] an array of sql elements to parse
  591. * into a sql string.
  592. * @return string the compiled query
  593. */
  594. public function build_query(array $sql = array())
  595. {
  596. // -------------------------------------
  597. // Select
  598. // -------------------------------------
  599. if (is_string($sql['select'])) {
  600. $select = $sql['select'];
  601. } else {
  602. $select = implode(', ', $sql['select']);
  603. }
  604. // -------------------------------------
  605. // From
  606. // -------------------------------------
  607. if (isset($this->sql['from']) and is_string($sql['from'])) {
  608. $from = $this->sql['from'];
  609. } else {
  610. $from = implode(', ', $sql['from']);
  611. }
  612. // -------------------------------------
  613. // Join
  614. // -------------------------------------
  615. if (isset($sql['join']) and is_string($sql['join'])) {
  616. $join = $sql['join'];
  617. } else {
  618. (isset($sql['join'])) ? $join = implode(' ', $sql['join']) : $join = null;
  619. }
  620. // -------------------------------------
  621. // Where
  622. // -------------------------------------
  623. if (isset($sql['where']) and is_string($sql['where'])) {
  624. $where = $sql['where'];
  625. } else {
  626. (isset($sql['where'])) ? $where = implode(' AND ', $sql['where']) : $where = null;
  627. }
  628. if ($where != '') {
  629. $where = 'WHERE '.$where;
  630. }
  631. // -------------------------------------
  632. // Order By
  633. // -------------------------------------
  634. // If there is a RAND, make sure it
  635. // is the only order by segment
  636. // -------------------------------------
  637. if (isset($sql['order_by']) and is_string($sql['order_by'])) {
  638. $order_by = $sql['order_by'];
  639. } else {
  640. (isset($sql['order_by'])) ? $order_by = implode(', ', $sql['order_by']) : $order_by = null;
  641. }
  642. if ($order_by) {
  643. $order_by = 'ORDER BY '.$order_by;
  644. }
  645. // -------------------------------------
  646. // Misc
  647. // -------------------------------------
  648. if (isset($sql['misc']) && is_string($sql['misc'])) {
  649. $misc = $sql['misc'];
  650. } else {
  651. (isset($sql['misc'])) ? $misc = implode(' ', $sql['misc']) : $misc = null;
  652. }
  653. // -------------------------------------
  654. // Return Built Query
  655. // -------------------------------------
  656. return "SELECT {$select}
  657. FROM {$from}
  658. {$join}
  659. {$where}
  660. {$misc}
  661. {$order_by} ";
  662. }
  663. // --------------------------------------------------------------------------
  664. /**
  665. * Build Count Query
  666. *
  667. * Run a count with the same critera as the main query
  668. *
  669. * @param array [$sql] an array of sql elements to parse
  670. * into a sql string.
  671. * @return string the compiled query
  672. */
  673. public function build_count_query(array $sql = array())
  674. {
  675. // -------------------------------------
  676. // From
  677. // -------------------------------------
  678. if (isset($this->sql['from']) and is_string($sql['from'])) {
  679. $from = $this->sql['from'];
  680. } else {
  681. $from = implode(', ', $sql['from']);
  682. }
  683. // -------------------------------------
  684. // Join
  685. // -------------------------------------
  686. if (isset($sql['join']) and is_string($sql['join'])) {
  687. $join = $sql['join'];
  688. } else {
  689. (isset($sql['join'])) ? $join = implode(' ', $sql['join']) : $join = null;
  690. }
  691. // -------------------------------------
  692. // Where
  693. // -------------------------------------
  694. if (isset($sql['where']) and is_string($sql['where'])) {
  695. $where = $sql['where'];
  696. } else {
  697. $where = (isset($sql['where'])) ? implode(' AND ', $sql['where']) : null;
  698. }
  699. if ($where != '') {
  700. $where = 'WHERE '.$where;
  701. }
  702. // -------------------------------------
  703. // Misc
  704. // -------------------------------------
  705. if (isset($sql['misc']) && is_string($sql['misc'])) {
  706. $misc = $sql['misc'];
  707. } else {
  708. (isset($sql['misc'])) ? $misc = implode(' ', $sql['misc']) : $misc = null;
  709. }
  710. // -------------------------------------
  711. // Return Built Query
  712. // -------------------------------------
  713. return "SELECT count(*) as `count`
  714. FROM {$from}
  715. {$join}
  716. {$where}
  717. {$misc}";
  718. }
  719. // --------------------------------------------------------------------------
  720. /**
  721. * Reset SQL query
  722. *
  723. * @access public
  724. * @return void
  725. */
  726. public function reset_sql()
  727. {
  728. $this->sql = array(
  729. 'select' => array(),
  730. 'where' => array(),
  731. 'from' => array(),
  732. 'order_by' => array(),
  733. 'misc' => array()
  734. );
  735. }
  736. // --------------------------------------------------------------------------
  737. /**
  738. * Process the where string. Anything in backticks
  739. * is considered a table name and has a table prefix
  740. * added onto it.
  741. *
  742. * @access private
  743. * @param string - where string
  744. * @return string
  745. */
  746. private function process_where($where)
  747. {
  748. // Get rid of where ()
  749. if ($where[0] == '(' and $where[strlen($where)-1] == ')') {
  750. $where = ltrim('(');
  751. $where = rtrim(')');
  752. }
  753. // Does this already have a specific table
  754. // that we are calling out for this where statement?
  755. // If so, then let's just forget about and return
  756. // the statement as is.
  757. if (strpos($where, '`.`') !== false) {
  758. return '('.$where.')';
  759. }
  760. // Find the fields between the backticks
  761. preg_match_all('/`[a-zA-Z0-9_]+`/', $where, $matches);
  762. if (isset($matches[0]) and is_array($matches[0])) {
  763. $matches[0] = array_unique($matches[0]);
  764. foreach ($matches[0] as $match) {
  765. $where = preg_replace('/(^.|)'.$match.'/', $this->select_prefix.$match, $where);
  766. }
  767. }
  768. return '('.$where.')';
  769. }
  770. // --------------------------------------------------------------------------
  771. /**
  772. * Format Rows
  773. *
  774. * Takes raw array of data
  775. * from the DB and formats it. Adds
  776. * things like count and odd/even.
  777. *
  778. * @access public
  779. * @param array - rows from db
  780. * @param obj - stream
  781. * @param [array - disables]
  782. * @return array
  783. */
  784. public function format_rows($data, $stream, $disable = array(), $stream_fields = null)
  785. {
  786. $count = 1;
  787. // We are keepig the option to get stream fields in the function
  788. // purely for legacy. We should be passing this in the format rows
  789. // so we can check for functions in the field types that need
  790. // to change the main query.
  791. if ( ! $stream_fields) {
  792. $stream_fields = $this->streams_m->get_stream_fields($stream->id);
  793. }
  794. $total = count($data);
  795. foreach ($data as $id => $item) {
  796. // Log the ID called
  797. $this->called[$stream->stream_slug][] = $item['id'];
  798. $this->extract_arrays($item);
  799. $data[$id] = $this->format_row($item, $stream_fields, $stream, false, true, $disable);
  800. // Give some info on if it is the last element
  801. $data[$id]['last'] = ($count == $total) ? '1' : '0';
  802. // Odd/Even
  803. $data[$id]['odd_even'] = ($count%2 == 0) ? 'even' : 'odd';
  804. // Count
  805. $data[$id]['count'] = $count;
  806. $count++;
  807. }
  808. return $data;
  809. }
  810. // --------------------------------------------------------------------------
  811. /**
  812. * Extract Arrays
  813. *
  814. * Takes a row array, and takes any ||'s as an
  815. * array split. This means that we can do joins and then
  816. * have them formatted in a way that the Lex parser
  817. * will be able to work with.
  818. *
  819. * @access public
  820. * @param array &$item
  821. * @return void
  822. */
  823. public function extract_arrays(&$item)
  824. {
  825. foreach ($item as $row_slug => $data) {
  826. if (strpos($row_slug, '||') !== false) {
  827. $pieces = explode('||', $row_slug, 2);
  828. unset($item[$row_slug]);
  829. if (isset($item[$pieces[0]]) and ! is_array($item[$pieces[0]])) {
  830. unset($item[$pieces[0]]);
  831. }
  832. $item[$pieces[0]][$pieces[1]] = $data;
  833. }
  834. }
  835. }
  836. // --------------------------------------------------------------------------
  837. /**
  838. * Get a row. Also has the option
  839. * to format that data before returning it.
  840. *
  841. * @access public
  842. * @param int
  843. * @param obj
  844. * @param [bool]
  845. * @return mixed
  846. */
  847. public function get_row($id, $stream, $format_output = true, $plugin_call = false)
  848. {
  849. // Now the structure. We will need this as well.
  850. if ( ! $this->structure) {
  851. $this->structure = $this->gather_structure();
  852. }
  853. $stream_fields = $this->streams_m->get_stream_fields($stream->id);
  854. // Created By
  855. $this->db->select($stream->stream_prefix.$stream->stream_slug.'.*, '.$this->db->dbprefix('users').'.username as created_by_username, '.$this->db->dbprefix('users').'.id as created_by_user_id, '.$this->db->dbprefix('users').'.email as created_by_email');
  856. $this->db->join('users', 'users.id = '.$stream->stream_prefix.$stream->stream_slug.'.created_by', 'left');
  857. $obj = $this->db
  858. ->limit(1)
  859. ->where($stream->stream_prefix.$stream->stream_slug.'.id', $id)
  860. ->get($stream->stream_prefix.$stream->stream_slug);
  861. if ($obj->num_rows() == 0) {
  862. return false;
  863. } else {
  864. $row = $obj->row();
  865. if ($format_output) {
  866. return $this->format_row($row , $stream_fields, $stream, true, $plugin_call);
  867. } else {
  868. return $row;
  869. }
  870. }
  871. }
  872. // --------------------------------------------------------------------------
  873. /**
  874. * Format Row
  875. *
  876. * Formats a row based on format profile
  877. *
  878. * @access public
  879. * @param array or obj
  880. * @param array
  881. * @param obj
  882. * @param [bool]
  883. * @param [bool]
  884. * @param [array - things to disable]
  885. */
  886. public function format_row($row, $stream_fields, $stream, $return_object = true, $plugin_call = false, $disable = array())
  887. {
  888. // Set our fields for formatting.
  889. $this->set_fields($stream->stream_namespace);
  890. // This is dumb and wil be refactored in 2.2 (I hope)
  891. $all_fields =& $this->all_fields[$stream->stream_namespace];
  892. // Now the structure. We will need this as well.
  893. if ( ! $this->structure) {
  894. $this->structure = $this->gather_structure();
  895. }
  896. // -------------------------------------
  897. // Format Rows
  898. // -------------------------------------
  899. // Go through each row and
  900. // get the data from the plugin or
  901. // format it
  902. // -------------------------------------
  903. if ($row and (is_array($row) or is_object($row))) {
  904. foreach ($row as $row_slug => $data) {
  905. // Easy out for our non-formattables and
  906. // fields we are disabling.
  907. if (in_array($row_slug, array('id', 'created_by')) or in_array($row_slug, $disable) or in_array('*', $disable)) {
  908. continue;
  909. }
  910. // -------------------------------------
  911. // Format Dates
  912. // -------------------------------------
  913. // We simply want these to be UNIX stamps
  914. // -------------------------------------
  915. if ($row_slug == 'created' or $row_slug == 'updated') {
  916. if ($return_object) {
  917. $row->$row_slug = strtotime($row->$row_slug);
  918. } else {
  919. $row[$row_slug] = strtotime($row[$row_slug]);
  920. }
  921. }
  922. // -------------------------------------
  923. // Format Columns
  924. // -------------------------------------
  925. if (array_key_exists($row_slug, $all_fields)) {
  926. if ($return_object) {
  927. $row->$row_slug = $this->format_column($row_slug,
  928. $row->$row_slug, $row->id, $stream_fields->$row_slug->field_type, array_merge((array) $stream_fields->$row_slug->field_data, (array) $stream_fields->$row_slug), $stream, $plugin_call);
  929. } else {
  930. $row[$row_slug] = $this->format_column($row_slug,
  931. $row[$row_slug], $row['id'], $stream_fields->$row_slug->field_type, array_merge((array) $stream_fields->$row_slug->field_data, (array) $stream_fields->$row_slug), $stream, $plugin_call);
  932. }
  933. }
  934. }
  935. }
  936. // -------------------------------------
  937. // Run through alt processes
  938. // -------------------------------------
  939. // If this is not a plugin call, we just
  940. // need to get the alt processes and
  941. // add them to the row for display
  942. // -------------------------------------
  943. if ( ! $plugin_call) {
  944. if ($stream_fields) {
  945. foreach ($stream_fields as $row_slug => $f) {
  946. if (isset($f->field_type, $this->ignore)) {
  947. if(
  948. isset($this->type->types->{$f->field_type}->alt_process) and
  949. $this->type->types->{$f->field_type}->alt_process === true and
  950. method_exists($this->type->types->{$f->field_type}, 'alt_pre_output')
  951. )
  952. {
  953. $out = $this->type->types->{$f->field_type}->alt_pre_output($row->id, $all_fields[$row_slug]['field_data'], $f->field_type, $stream);
  954. ($return_object) ? $row->$row_slug = $out : $row[$row_slug] = $out;
  955. }
  956. }
  957. }
  958. }
  959. }
  960. return $row;
  961. }
  962. // --------------------------------------------------------------------------
  963. /**
  964. * Format a single column
  965. *
  966. * @access public
  967. * @params
  968. */
  969. public function format_column($column_slug, $column_data, $row_id, $type_slug, $field_data, $stream, $plugin = true)
  970. {
  971. // Does our type exist?
  972. if ( ! isset($this->type->types->{$type_slug})) {
  973. return null;
  974. }
  975. $plugin_call = null;
  976. // Is this an alt process type?
  977. if (isset($this->type->types->{$type_slug}->alt_process) and $this->type->types->{$type_slug}->alt_process === true) {
  978. if ( ! $plugin_call and method_exists($this->type->types->{$type_slug}, 'alt_pre_output')) {
  979. return $this->type->types->{$type_slug}->alt_pre_output($row_id, $field_data, $this->type->types->{$type_slug}, $stream);
  980. }
  981. return $column_data;
  982. } else {
  983. // If not, check and see if there is a method
  984. // for pre output or pre_output_plugin
  985. if ($plugin and method_exists($this->type->types->{$type_slug}, 'pre_output_plugin')) {
  986. return $this->type->types->{$type_slug}->pre_output_plugin($column_data, $field_data, $column_slug);
  987. } elseif (method_exists($this->type->types->{$type_slug}, 'pre_output')) {
  988. return $this->type->types->{$type_slug}->pre_output($column_data, $field_data);
  989. }
  990. }
  991. return $column_data;
  992. }
  993. // --------------------------------------------------------------------------
  994. /**
  995. * Gather Structure
  996. *
  997. * Get the structure of the streams down. We never know
  998. * when we are going to need this for formatting or
  999. * reference.
  1000. *
  1001. * @access public
  1002. * @return array
  1003. */
  1004. public function gather_structure()
  1005. {
  1006. if (empty($this->gather_structure_cache)) {
  1007. $obj = $this->db->query('
  1008. SELECT '.PYROSTREAMS_DB_PRE.STREAMS_TABLE.'.*, '.PYROSTREAMS_DB_PRE.STREAMS_TABLE.'.id as stream_id, '.PYROSTREAMS_DB_PRE.FIELDS_TABLE.'.*
  1009. FROM '.PYROSTREAMS_DB_PRE.STREAMS_TABLE.', '.PYROSTREAMS_DB_PRE.ASSIGN_TABLE.', '.PYROSTREAMS_DB_PRE.FIELDS_TABLE.'
  1010. WHERE '.PYROSTREAMS_DB_PRE.STREAMS_TABLE.'.id='.PYROSTREAMS_DB_PRE.ASSIGN_TABLE.'.stream_id and
  1011. '.PYROSTREAMS_DB_PRE.FIELDS_TABLE.'.id='.PYROSTREAMS_DB_PRE.ASSIGN_TABLE.'.field_id');
  1012. $fields = $obj->result();
  1013. $struct = array();
  1014. foreach ($this->streams_m->streams_cache as $stream_id => $stream) {
  1015. if ($stream_id == 'ns') continue;
  1016. $struct[$stream_id]['stream'] = $stream;
  1017. foreach ($fields as $field) {
  1018. if ($field->stream_slug == $stream->stream_slug) {
  1019. $struct[$stream_id]['fields'][] = $field;
  1020. }
  1021. }
  1022. }
  1023. $this->gather_structure_cache = $struct;
  1024. } else {
  1025. $struct = $this->gather_structure_cache;
  1026. }
  1027. return $struct;
  1028. }
  1029. // --------------------------------------------------------------------------
  1030. /**
  1031. * Update a row in a stream
  1032. *
  1033. * @param obj
  1034. * @param string
  1035. * @param int
  1036. * @param array update data
  1037. * @param array skips - optional array of skips
  1038. * @param array extra - optional assoc array of data to exclude from processing, but to
  1039. * include in saving to the database.
  1040. * @param bool Should we only update those passed?
  1041. * @return bool
  1042. */
  1043. public function update_entry($fields, $stream, $row_id, $form_data, $skips = array(), $extra = array(), $include_only_passed = true)
  1044. {
  1045. $this->load->helper('text');
  1046. // -------------------------------------
  1047. // Include Only Passed
  1048. // -------------------------------------
  1049. // If we include only the passed vars,
  1050. // then we skip everyhing else.
  1051. // -------------------------------------
  1052. if ($include_only_passed && $fields) {
  1053. foreach ($fields as $field) {
  1054. // If we haven't passed it, then we
  1055. // want to skip it.
  1056. if ( ! isset($form_data[$field->field_slug])) {
  1057. $skips[] = $field->field_slug;
  1058. }
  1059. }
  1060. // If we are including only the passed,
  1061. // then we are simply going to process the fields that
  1062. // we have passed without creating null
  1063. // values for missing fields. This variable allows
  1064. // run_field_pre_processes to do that.
  1065. $set_missing_to_null = false;
  1066. } else {
  1067. $set_missing_to_null = true;
  1068. }
  1069. // -------------------------------------
  1070. // Run through fields
  1071. // -------------------------------------
  1072. $update_data = $this->run_field_pre_processes($fields, $stream, $row_id, $form_data, $skips, $set_missing_to_null);
  1073. // -------------------------------------
  1074. // Set Updated Date
  1075. // -------------------------------------
  1076. if ( ! in_array('updated', $skips) and ! isset($extra['updated'])) {
  1077. $update_data['updated'] = date('Y-m-d H:i:s');
  1078. }
  1079. // -------------------------------------
  1080. // Add Extra Data
  1081. // -------------------------------------
  1082. if ($extra) {
  1083. $update_data = array_merge($update_data, $extra);
  1084. }
  1085. // -------------------------------------
  1086. // Update data
  1087. // -------------------------------------
  1088. // Is there any logic to complete before updating?
  1089. if ( Events::trigger('streams_pre_update_entry', array('stream' => $stream, 'entry_id' => $row_id, 'update_data' => $update_data)) === false ) return false;
  1090. if ($update_data) {
  1091. $this->db->where('id', $row_id);
  1092. if ( ! $this->db->update($stream->stream_prefix.$stream->stream_slug, $update_data) ) {
  1093. return false;
  1094. } else {
  1095. // -------------------------------------
  1096. // Event: Post Update Entry
  1097. // -------------------------------------
  1098. $trigger_data = array(
  1099. 'entry_id' => $row_id,
  1100. 'stream' => $stream,
  1101. 'update_data' => $update_data,
  1102. );
  1103. Events::trigger('streams_post_update_entry', $trigger_data);
  1104. // -------------------------------------
  1105. return $row_id;
  1106. }
  1107. }
  1108. }
  1109. // --------------------------------------------------------------------------
  1110. /**
  1111. * Run fields through their pre-process
  1112. *
  1113. * Just used for updating right now
  1114. *
  1115. * @access public
  1116. * @param obj
  1117. * @param string
  1118. * @param int
  1119. * @param array - update data
  1120. * @param skips - optional array of skips
  1121. * @param bool - set_missing_to_null. Should we set missing pieces of data to null
  1122. * for the database?
  1123. * @return bool
  1124. */
  1125. public function run_field_pre_processes($fields, $stream, $row_id, $form_data, $skips = array(), $set_missing_to_null = true)
  1126. {
  1127. $return_data = array();
  1128. if ($fields) {
  1129. foreach ($fields as $field) {
  1130. // If we don't have a post item for this field,
  1131. // then simply set the value to null. This is necessary
  1132. // for fields that want to run a pre_save but may have
  1133. // a situation where no post data is sent (like a single checkbox)
  1134. if ( ! isset($form_data[$field->field_slug]) and $set_missing_to_null) {
  1135. $form_data[$field->field_slug] = null;
  1136. }
  1137. // If this is not in our skips list, process it.
  1138. if ( ! in_array($field->field_slug, $skips)) {
  1139. $type = $this->type->types->{$field->field_type};
  1140. if ( ! isset($type->alt_process) or ! $type->alt_process) {
  1141. // If a pre_save function exists, go ahead and run it
  1142. if (method_exists($type, 'pre_save')) {
  1143. $return_data[$field->field_slug] = $type->pre_save(
  1144. $form_data[$field->field_slug],
  1145. $field,
  1146. $stream,
  1147. $row_id,
  1148. $form_data);
  1149. // We are unsetting the null values to as to
  1150. // not upset db can be null rules.
  1151. if (is_null($return_data[$field->field_slug])) {
  1152. unset($return_data[$field->field_slug]);
  1153. } else {
  1154. $return_data[$field->field_slug] = $return_data[$field->field_slug];
  1155. }
  1156. } else {
  1157. $return_data[$field->field_slug] = $form_data[$field->field_slug];

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