PageRenderTime 63ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/system/cms/modules/streams_core/plugin.php

https://github.com/asalem/pyrocms
PHP | 1641 lines | 793 code | 312 blank | 536 comment | 103 complexity | 7c21a808281c052f07b1a135c53af729 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
  1. <?php
  2. use Illuminate\Support\Str;
  3. use Pyro\Module\Streams\Entry\EntryModel;
  4. use Pyro\Module\Streams\Field\FieldModel;
  5. use Pyro\Module\Streams\Stream\StreamModel;
  6. use Pyro\Module\Streams\Ui\EntryUi;
  7. /**
  8. * Streams Plugin
  9. *
  10. * @package Streams
  11. * @author Ryan Thompson - PyroCMS
  12. * @copyright Copyright (c) 2008 - 2013, Ryan Thompson - PyroCMS
  13. * @license http://www.aiwebsystems.com/docs/streams
  14. * @link http://www.aiwebsystems.com/streams
  15. */
  16. class Plugin_Streams_core extends Plugin
  17. {
  18. /**
  19. * Cache Vars
  20. * These variables control the cache of
  21. * PyroStreams tags.
  22. */
  23. public $cache_type = 'query'; // tag or query
  24. public $cache_time_format = 'minutes'; // minutes or seconds
  25. public $cache_ttl = null; // num of seconds or minutes
  26. public $cache_hash = null;
  27. public $write_tag_cache = false; // Whether or not we need
  28. public $runtime_cache = array();
  29. /**
  30. * Possible entries parameters
  31. *
  32. * @var array
  33. */
  34. public $entries_parameters = array(
  35. 'stream' => null,
  36. 'namespace' => null,
  37. 'select' => '*',
  38. 'load' => null,
  39. 'limit' => null,
  40. 'date_by' => 'created_at',
  41. 'where' => null,
  42. 'exclude' => null,
  43. 'exclude_by' => 'id',
  44. 'include' => null,
  45. 'include_by' => 'id',
  46. 'order_by' => 'created_at',
  47. 'sort' => 'desc',
  48. 'debug' => 'no',
  49. );
  50. /**
  51. * Possible form parameters
  52. *
  53. * @var array
  54. */
  55. public $form_parameters = array(
  56. 'stream' => null,
  57. 'namespace' => null,
  58. 'entry_id' => null,
  59. 'id' => null,
  60. 'use_recaptcha' => 'no',
  61. 'save_success_message' => 'lang:streams:new_entry_success',
  62. 'save_error_message' => 'lang:streams:new_entry_error',
  63. 'update_success_message' => 'lang:streams:edit_entry_success',
  64. 'update_error_message' => 'lang:streams:edit_entry_error',
  65. 'skips' => null,
  66. 'include' => null,
  67. 'exclude' => null,
  68. 'hidden' => null,
  69. 'order' => null,
  70. 'class' => null,
  71. 'redirect' => null,
  72. 'exit_redirect' => null,
  73. 'continue_redirect' => null,
  74. 'create_redirect' => null,
  75. 'cancel_uri' => null,
  76. );
  77. /**
  78. * Possible pagination configuration parameters
  79. *
  80. * @var array
  81. */
  82. public $pagination_configuration = array(
  83. 'num_links',
  84. 'full_tag_open',
  85. 'full_tag_close',
  86. 'first_link',
  87. 'first_tag_open',
  88. 'first_tag_close',
  89. 'prev_link',
  90. 'prev_tag_open',
  91. 'prev_tag_close',
  92. 'cur_tag_open',
  93. 'cur_tag_close',
  94. 'num_tag_open',
  95. 'num_tag_close',
  96. 'next_link',
  97. 'next_tag_open',
  98. 'next_tag_close',
  99. 'last_link',
  100. 'last_tag_open',
  101. 'last_tag_close',
  102. 'suffix',
  103. 'first_url',
  104. 'reuse_query_string'
  105. );
  106. /**
  107. * Default Calendar Template
  108. *
  109. * @access public
  110. * @var string
  111. */
  112. public $calendar_template = '
  113. {table_open}<table border="0" cellpadding="0" cellspacing="0">{/table_open}
  114. {heading_row_start}<tr>{/heading_row_start}
  115. {heading_previous_cell}<th><a href="{previous_url}">&lt;&lt;</a></th>{/heading_previous_cell}
  116. {heading_title_cell}<th colspan="{colspan}">{heading}</th>{/heading_title_cell}
  117. {heading_next_cell}<th><a href="{next_url}">&gt;&gt;</a></th>{/heading_next_cell}
  118. {heading_row_end}</tr>{/heading_row_end}
  119. {week_row_start}<tr>{/week_row_start}
  120. {week_day_cell}<td>{week_day}</td>{/week_day_cell}
  121. {week_row_end}</tr>{/week_row_end}
  122. {cal_row_start}<tr>{/cal_row_start}
  123. {cal_cell_start}<td>{/cal_cell_start}
  124. {cal_cell_content}{day}{content}{/cal_cell_content}
  125. {cal_cell_content_today}<div class="highlight">{day}{content}</div>{/cal_cell_content_today}
  126. {cal_cell_no_content}{day}{/cal_cell_no_content}
  127. {cal_cell_no_content_today}<div class="highlight">{day}</div>{/cal_cell_no_content_today}
  128. {cal_cell_blank}&nbsp;{/cal_cell_blank}
  129. {cal_cell_end}</td>{/cal_cell_end}
  130. {cal_row_end}</tr>{/cal_row_end}
  131. {table_close}</table>{/table_close}
  132. ';
  133. ///////////////////////////////////////////////////////////////////////////////
  134. // -------------------------- METHODS ------------------------------ //
  135. ///////////////////////////////////////////////////////////////////////////////
  136. /**
  137. * PyroStreams Plugin Construct
  138. * Just a bunch of loads and prep
  139. *
  140. * @access public
  141. * @return void
  142. */
  143. public function __construct()
  144. {
  145. }
  146. /**
  147. * _call
  148. * Fun little method to call a stream without
  149. * using cycle. Like:
  150. * {{ streams:stream }}
  151. *
  152. * @access public
  153. *
  154. * @param string
  155. * @param string
  156. *
  157. * @return void
  158. */
  159. public function __call($stream, $data)
  160. {
  161. return $this->entries($stream);
  162. }
  163. /**
  164. * Entries
  165. * Get entries in a stream.
  166. *
  167. * @access public
  168. *
  169. * @param string [$stream] Option stream slug to pass.
  170. *
  171. * @return string
  172. */
  173. public function entries($stream = null)
  174. {
  175. // Toggle debug mode
  176. $this->debug_status = $this->getAttribute('debug', 'on');
  177. // Load languages desired
  178. self::loadLanguages();
  179. // -------------------------------------
  180. // Get Plugin Attributes
  181. // -------------------------------------
  182. $parameters = array();
  183. foreach ($this->entries_parameters as $parameter => $parameter_default) {
  184. $parameters[$parameter] = $this->getAttribute($parameter, $parameter_default);
  185. }
  186. // -------------------------------------
  187. // Stream Slug Override
  188. // -------------------------------------
  189. // If we have a stream slug that has been
  190. // passed, we will take that value over
  191. // the passed $parameters value. This is so
  192. // if we have {{ streams:stream stream="another" }}
  193. // We will ignore "another" in favor of "stream"
  194. // -------------------------------------
  195. if ($stream) {
  196. $parameters['stream'] = $stream;
  197. }
  198. // -------------------------------------
  199. // Cache
  200. // -------------------------------------
  201. // Setup cache. If we have a full tag cache,
  202. // we will just go ahead and return that.
  203. // -------------------------------------
  204. $this->setupCache();
  205. if (!is_null($tag_cache = $this->getTagCache())) {
  206. return $tag_cache;
  207. }
  208. // -------------------------------------
  209. // Set Namespace
  210. // -------------------------------------
  211. // We can manually set the namespace
  212. // via a namespce="" parameter.
  213. // -------------------------------------
  214. $parameters['namespace'] = ($parameters['namespace']) ? $parameters['namespace'] : 'streams';
  215. // -------------------------------------
  216. // Stream Data Check
  217. // -------------------------------------
  218. // Check for a retrieve our stream.
  219. // -------------------------------------
  220. if (!isset($parameters['stream']) and $parameters['debug'] == 'yes') {
  221. $this->error(lang('streams:no_stream_provided'));
  222. }
  223. $stream = StreamModel::getStream($parameters['stream'], $parameters['namespace']);
  224. if (!$stream and $parameters['debug'] == 'yes') {
  225. $this->error(lang('streams:invalid_stream'));
  226. }
  227. // -------------------------------------
  228. // Get Entries
  229. // -------------------------------------
  230. if ($this->cache_type == 'query' and is_numeric($this->cache_ttl)) {
  231. // Try cache
  232. if (!$entries = ci()->cache->get($this->cache_hash)) {
  233. // Nothin.. Get entries
  234. $entries = self::get($stream, $parameters);
  235. // Save to cache
  236. ci()->cache->put($this->cache_hash, $entries, $this->cache_ttl);
  237. }
  238. } else {
  239. $entries = self::get($stream, $parameters);
  240. }
  241. // -------------------------------------
  242. // Rename
  243. // -------------------------------------
  244. // Allows us to rename variables in our
  245. // parameters. So, rename:old_name="new_name"
  246. // -------------------------------------
  247. $renames = array();
  248. foreach ($this->getAttributes() as $key => $to) {
  249. if (substr($key, 0, 7) == 'rename:' and strlen($key) > 7) {
  250. $pieces = explode(':', $key);
  251. $renames[$pieces[1]] = $to;
  252. }
  253. }
  254. if ($renames) {
  255. foreach ($entries as $k => &$entry) {
  256. foreach ($renames as $from => $to) {
  257. if (isset($entry->{$from})) {
  258. $entry->{$to} = $entry->$from;
  259. unset($entry->{$from});
  260. }
  261. }
  262. }
  263. }
  264. // -------------------------------------
  265. // Cache End Procedures
  266. // -------------------------------------
  267. $this->writeTagCache($entries);
  268. //$this->clearCacheVariables();
  269. // -------------------------------------
  270. //print_r($entries);die;
  271. return $entries;
  272. }
  273. /**
  274. * Loop through attributes and load
  275. * languages like foo_lang="foo/foo"
  276. *
  277. * @return void
  278. */
  279. private function loadLanguages()
  280. {
  281. // Load languages
  282. foreach ($this->getAttributes() as $key => $lang) {
  283. if (substr($key, -5) == '_lang') {
  284. ci()->lang->load($lang);
  285. }
  286. }
  287. }
  288. /**
  289. * Setup the Cache Vars
  290. * Set cache type, time format, and hash
  291. *
  292. * @access private
  293. * @return void
  294. */
  295. private function setupCache()
  296. {
  297. // 'tag' or 'query'
  298. $this->cache_type = $this->getAttribute('cache_type', 'query');
  299. // 'minutes' or 'seconds' or 'hours'
  300. $this->cache_time_format = $this->getAttribute('cache_time_format', 'minutes');
  301. // num of seconds / minutes / hours
  302. $this->cache_ttl = $this->getAttribute('cache_ttl', null);
  303. // Format the cache time.
  304. if (is_numeric($this->cache_ttl)) {
  305. // Seconds (do nothing)
  306. // Use minutes?
  307. if ($this->cache_time_format == 'minutes') {
  308. $this->cache_ttl = $this->cache_ttl * 60;
  309. }
  310. // Use hours?
  311. if ($this->cache_time_format == 'hours') {
  312. $this->cache_ttl = $this->cache_ttl * 3600;
  313. }
  314. }
  315. $this->setupCacheHash();
  316. }
  317. /**
  318. * Set the cache hash
  319. * This creates a unique cache hash based on the
  320. * unique set of tag parameters.
  321. *
  322. * @access private
  323. * @return void
  324. */
  325. private function setupCacheHash()
  326. {
  327. $this->cache_hash = md5(
  328. 'streams_core' . implode('-', $this->getAttributes()) . (is_string($this->content()) ? $this->content(
  329. ) : null) . $_SERVER['QUERY_STRING']
  330. );
  331. }
  332. /**
  333. * Full tag cache
  334. *
  335. * @access private
  336. * @return mixed - null or string
  337. */
  338. private function getTagCache()
  339. {
  340. if (!$this->cache_hash) {
  341. $this->setupCacheHash();
  342. }
  343. // Check to see if we have a tag cache.
  344. if ($this->cache_type == 'tag' and !is_null($this->cache_ttl)) {
  345. if (!$tag_cache_content = ci()->cache->get($this->cache_hash)) {
  346. // Set this so functions know to write the
  347. // cache when necesary.
  348. $this->write_tag_cache = true;
  349. } else {
  350. return $tag_cache_content;
  351. }
  352. }
  353. return null;
  354. }
  355. /**
  356. * Output debug message or just
  357. * return false.
  358. *
  359. * @access private
  360. *
  361. * @param string
  362. *
  363. * @return mixed
  364. */
  365. private function error($msg)
  366. {
  367. return ($this->debug_status == 'on') ? show_error($msg) : false;
  368. }
  369. /**
  370. * Get entries
  371. *
  372. * @return array
  373. */
  374. public function get($stream, $parameters)
  375. {
  376. // Build the runtime hash
  377. $hash = md5($stream . implode('', $parameters));
  378. // Does the runtime cache result exist?
  379. if (!isset($this->runtime_cache[$hash])) {
  380. /**
  381. * Get everything started
  382. */
  383. $entries = EntryModel::stream($stream)->select(explode('|', $parameters['select']));
  384. /**
  385. * Where statement
  386. */
  387. if ($parameters['where']) {
  388. $entries->whereRaw($parameters['where']);
  389. }
  390. /**
  391. * Process joins
  392. */
  393. foreach ($this->getAttributes() as $attribute => $value) {
  394. // Prefixed with "join_"?
  395. if (substr($attribute, 0, 5) == 'join_') {
  396. // Grab the arguments
  397. list($arg1, $condition, $arg2) = explode('|', $value);
  398. // Execute it
  399. $entries->join(substr($attribute, 5), $arg1, $condition, $arg2);
  400. }
  401. }
  402. /**
  403. * Lazy load (expiramental)
  404. */
  405. if ($parameters['load']) {
  406. $entries->with(explode('|', $parameters['load']));
  407. }
  408. /**
  409. * Limit
  410. */
  411. $entries->limit($parameters['limit']);
  412. /**
  413. * Order by
  414. */
  415. $entries->orderBy($parameters['order_by'], $parameters['sort']);
  416. /**
  417. * Debug
  418. */
  419. if ($parameters['debug'] == 'yes') {
  420. echo $entries->toSql();
  421. }
  422. /**
  423. * Get entries
  424. */
  425. $entries = $entries->enableAutoEagerLoading(true)->remember(10)->get()->getPresenter('plugin');
  426. /**
  427. * Process entries
  428. */
  429. foreach ($entries as $k => &$entry) {
  430. // Add the count
  431. $entry['count'] = $k;
  432. $entry['human_count'] = $k + 1;
  433. }
  434. $this->runtime_cache[$hash] = $entries;
  435. } else {
  436. $entries = $this->runtime_cache[$hash];
  437. }
  438. return $entries;
  439. }
  440. /**
  441. * Write tag cache if we need to
  442. *
  443. * @access private
  444. *
  445. * @param string - the content to write
  446. *
  447. * @return void
  448. */
  449. private function writeTagCache($content)
  450. {
  451. if ($this->write_tag_cache === true) {
  452. ci()->cache->put($this->cache_hash, $content, $this->cache_ttl);
  453. }
  454. }
  455. /**
  456. * Field Function
  457. * Calls the plugin override function
  458. */
  459. public function field()
  460. {
  461. // Get the stream
  462. $stream = StreamModel::findBySlugAndNamespace($this->getAttribute('stream'), $this->getAttribute('namespace'));
  463. // Get the field type
  464. $field = FieldModel::findBySlugAndNamespace(
  465. $this->getAttribute('field_slug'),
  466. $this->getAttribute('namespace')
  467. );
  468. // Do we have a stream?
  469. if ($entry = EntryModel::stream($stream)) {
  470. // Do we have an entry?
  471. if ($this->getAttribute('entry_id') and $entry = $entry::find($this->getAttribute('entry_id'))) {
  472. // Sweet Jesus we do - get the bootstrapped type
  473. $type = $entry->getFieldType($field->field_slug);
  474. } else {
  475. // We don't - but we have what we need
  476. $type = $entry->getFieldType($field->field_slug);
  477. }
  478. }
  479. // Set the plugin
  480. $type->setPlugin($this);
  481. // Pattern the method name
  482. $method = 'plugin' . Str::studly($this->getAttribute('method'));
  483. // If the method exists - go for it
  484. // No reason for testing if plugin_override here..
  485. // Rage of motion is pretty limited already
  486. if (method_exists($type, $method)) {
  487. $arguments = array();
  488. foreach ($this->getAttributes() as $attribute => $value) {
  489. if (substr($attribute, 0, 4) == 'arg_') {
  490. $arguments[substr($attribute, 4)] = $value;
  491. }
  492. }
  493. return call_user_func_array(array($type, $method), $arguments);
  494. }
  495. }
  496. /**
  497. * Return a shuffled array of entries
  498. *
  499. * @return array
  500. */
  501. public function shuffle()
  502. {
  503. $entries = self::entries();
  504. shuffle($entries);
  505. return $entries;
  506. }
  507. /**
  508. * Entry
  509. * Show a single stream entry.
  510. *
  511. * @access public
  512. * @return array
  513. */
  514. public function entry()
  515. {
  516. $this->setAttribute('limit', 1);
  517. $return = $this->entries();
  518. return empty($return) ? false : ci()->parser->parse_string(
  519. $this->content(),
  520. $return[0],
  521. true,
  522. false,
  523. null,
  524. false
  525. );
  526. }
  527. /**
  528. * Pagination
  529. *
  530. * @return string
  531. */
  532. public function pagination()
  533. {
  534. // Get a total
  535. $total = self::total();
  536. // Whip it up
  537. $pagination = create_pagination(
  538. $pag_uri = $this->getAttribute('pag_uri', uri_string()),
  539. $total,
  540. $limit = $this->getAttribute('limit', $this->entries_parameters['limit']),
  541. $offset_uri = 2
  542. );
  543. // Do whatever this is
  544. $pagination['links'] = str_replace('-1', '1', $pagination['links']);
  545. return $pagination;
  546. }
  547. /**
  548. * Get total entries
  549. *
  550. * @return integer
  551. */
  552. public function total()
  553. {
  554. // -------------------------------------
  555. // Get Plugin Attributes
  556. // -------------------------------------
  557. $parameters = array();
  558. foreach ($this->entries_parameters as $parameter => $parameter_default) {
  559. $parameters[$parameter] = $this->getAttribute($parameter, $parameter_default);
  560. }
  561. // Boom. Stream.
  562. $stream = StreamModel::getStream($parameters['stream'], $parameters['namespace']);
  563. // Start up the query
  564. $entries = EntryModel::stream($stream)
  565. ->select('id')
  566. ->whereRaw($parameters['where'])
  567. ->limit($parameters['limit'])
  568. ->orderBy($parameters['order_by'], $parameters['sort']);
  569. // Check for joins
  570. foreach ($this->getAttributes() as $attribute => $value) {
  571. // Prefixed with "join_"?
  572. if (substr($attribute, 0, 5) == 'join_') {
  573. // Grab the arguments
  574. list($arg1, $condition, $arg2) = explode('|', $value);
  575. // Execute it
  576. $entries->join(substr($attribute, 5), $arg1, $condition, $arg2);
  577. }
  578. }
  579. return $entries = $entries->count();
  580. }
  581. /**
  582. * Output an input form for a stream
  583. *
  584. * @access public
  585. * @return array
  586. */
  587. public function form()
  588. {
  589. // Load languages desired
  590. self::loadLanguages();
  591. // -------------------------------------
  592. // Get Plugin Attributes / Paramaters
  593. // -------------------------------------
  594. $attributes = $this->getAttributes();
  595. $parameters = array();
  596. foreach ($this->form_parameters as $parameter => $parameter_default) {
  597. $parameters[$parameter] = $this->getAttribute($parameter, $parameter_default);
  598. }
  599. $parameters = array_merge($attributes, $parameters);
  600. // -------------------------------------
  601. // Fire up EntryUi
  602. // -------------------------------------
  603. $form = new EntryUi;
  604. $form = $form->form($parameters['stream'], $parameters['namespace'], $parameters['entry_id']);
  605. /**
  606. * Set default values
  607. */
  608. // Get em!
  609. $defaults = array();
  610. foreach ($this->getAttributes() as $key => $default) {
  611. if (substr($key, -8) == '_default') {
  612. $defaults[substr($key, 0, -8)] = $default;
  613. }
  614. }
  615. $form = $form->defaults($defaults);
  616. /**
  617. * Skip fields
  618. */
  619. // Determine initial skips from the include / exclude params
  620. $skips = $this->getSkipsFromSkipsIncludeExclude(
  621. $parameters['skips'],
  622. $parameters['include'],
  623. $parameters['exclude'],
  624. $form->model->getStream()
  625. );
  626. if (!empty($skips)) {
  627. $form = $form->skips($skips);
  628. }
  629. /**
  630. * Hide these fields
  631. */
  632. if ($parameters['hidden']) {
  633. $form = $form->hidden(explode('|', $parameters['hidden']));
  634. }
  635. /**
  636. * Set some redirects
  637. */
  638. if ($parameters['redirect']) {
  639. $form = $form->redirectSave($parameters['redirect']);
  640. } else {
  641. $form = $form->redirectSave(ci()->uri->uri_string());
  642. }
  643. /*if ($parameters['redirect_exit'])
  644. $form = $form->redirectExit($parameters['redirect_exit']);*/
  645. /*if ($parameters['redirect_continue'])
  646. $form = $form->redirectContinue($parameters['redirect_continue']);*/
  647. /*if ($parameters['redirect_create'])
  648. $form = $form->redirectCreate($parameters['redirect_create']);*/
  649. /*if ($parameters['uri_cancel'])
  650. $form = $form->uriCancel($parameters['uri_cancel']);*/
  651. /**
  652. * Set success and error messages
  653. */
  654. /*if (! $parameters['entry_id'])
  655. $form = $form->messages(array(
  656. 'success' => $parameters['save_message_success'],
  657. 'error' => $parameters['save_message_error'],
  658. ));
  659. else
  660. $form = $form->messages(array(
  661. 'success' => $parameters['update_message_success'],
  662. 'error' => $parameters['update_message_error'],
  663. ));*/
  664. /**
  665. * DONE = Fetch the object
  666. */
  667. $fields = $form->getUi()->fields->toArray();
  668. /**
  669. * Override any labels
  670. */
  671. foreach ($fields as $k => $field) {
  672. if (isset($parameters[$field['field']['field_slug'] . '_label'])) {
  673. $fields[$k]['field_name'] = $parameters[$field['field']['field_slug'] . '_label'];
  674. }
  675. }
  676. /**
  677. * Override form order
  678. */
  679. if ($parameters['order']) {
  680. $fields = $this->reorderFormFields($fields, $parameters['order']);
  681. }
  682. /**
  683. * Build our return
  684. */
  685. $return = array(
  686. 'fields' => $fields,
  687. 'form_open' => form_open_multipart(ci()->uri->uri_string(), array('class' => $parameters['class'])),
  688. 'form_close' => '</form>',
  689. );
  690. foreach ($fields as $k => $field) {
  691. // Copy it
  692. $return[$field['field']['field_slug']] = $field;
  693. }
  694. // Return our goodness
  695. return array($return);
  696. }
  697. /**
  698. * Get all the skips from skips, includes and excludes
  699. *
  700. * @param mixed $skips
  701. * @param mixed $include
  702. * @param mixed $exclude
  703. * @param object $stream
  704. *
  705. * @return array
  706. */
  707. private function getSkipsFromSkipsIncludeExclude($skips, $include, $exclude, $stream)
  708. {
  709. // Make sure these are arrays
  710. $skips = is_string($skips) ? explode('|', $skips) : $skips;
  711. $include = is_string($include) ? explode('|', $include) : $include;
  712. $exclude = is_string($exclude) ? explode('|', $exclude) : $exclude;
  713. // Get the streams assignments first
  714. $assignments = $stream->assignments->toArray();
  715. // Manually set skips first
  716. $skips = $skips;
  717. // Are we using include?
  718. if (!empty($include)) {
  719. // Skip unless they're in the include
  720. foreach ($assignments as $assignment) {
  721. // Is it included?
  722. if (!in_array($assignment['field']['field_slug'], $include)) {
  723. // Nope.. Seeya
  724. $skips[] = $assignment['field']['field_slug'];
  725. }
  726. }
  727. }
  728. // Skip excludes
  729. foreach ((array)$exclude as $skip) {
  730. $skips[] = $skip;
  731. }
  732. // Return unique
  733. return array_unique($skips);
  734. }
  735. ///////////////////////////////////////////////////////////////////////////////
  736. // -------------------------- UTILITIES ------------------------------ //
  737. ///////////////////////////////////////////////////////////////////////////////
  738. /**
  739. * Reorder the form inputs
  740. *
  741. * @param array $fields
  742. * @param string $order Pipe delimited field slugs
  743. *
  744. * @return array
  745. */
  746. private function reorderFormFields($fields, $order)
  747. {
  748. $order = explode('|', $order);
  749. $sorted = array();
  750. // Loop and save fields as sorted
  751. foreach ($order as $field_slug) {
  752. foreach ($fields as $k => $field) {
  753. if ($field['field']['field_slug'] == $field_slug) {
  754. $sorted[] = $field;
  755. unset($fields[$k]);
  756. }
  757. }
  758. }
  759. // Add the rest
  760. foreach ($fields as $field) {
  761. $sorted[] = $field;
  762. }
  763. return $sorted;
  764. }
  765. /**
  766. * Form assets
  767. *
  768. * @access public
  769. * @return string
  770. */
  771. public function form_assets()
  772. {
  773. if (!empty($this->type->assets)) {
  774. // Weird fix that seems to work for fixing WYSIWYG
  775. // since it is throwing missing variable errors
  776. $html = '<script type="text/javascript">var SITE_URL = "' . $this->config->item('base_url') . '";</script>';
  777. foreach ($this->type->assets as $asset) {
  778. $html .= $asset . "\n";
  779. }
  780. return $html;
  781. }
  782. }
  783. /**
  784. * Form CSRF input
  785. * You might need this if you are not using the {{ form_open }} variable.
  786. *
  787. * @access public
  788. * @return mixed - null or string
  789. */
  790. public function form_csrf()
  791. {
  792. if ($this->config->item('csrf_protection')) {
  793. return form_hidden($this->security->get_csrf_token_name(), $this->security->get_csrf_hash());
  794. }
  795. }
  796. /**
  797. * Form Fields
  798. * Allows you to simple show form fields without
  799. */
  800. public function form_fields()
  801. {
  802. $this->load->library(array('form_validation', 'streams_core/Fields'));
  803. $mode = $this->getAttribute('mode', 'new');
  804. $edit_id = $this->getAttribute('edit_id', false);
  805. $stream = $this->getAttribute('stream');
  806. $namespace = $this->getAttribute('namespace', $this->core_namespace);
  807. $include = $this->getAttribute('include');
  808. $exclude = $this->getAttribute('exclude');
  809. $required = $this->getAttribute('required', '<span class="required">* required</span>');
  810. // -------------------------------------
  811. // Get Stream Data
  812. // -------------------------------------
  813. $data->stream = $this->streams_m->get_stream($stream, true, $namespace);
  814. if (!$data->stream) {
  815. return lang('streams:invalid_stream');
  816. }
  817. $data->stream_id = $data->stream->id;
  818. $vars = array();
  819. // -------------------------------------
  820. // Get the row in edit mode
  821. // -------------------------------------
  822. $entry = false;
  823. if ($mode == 'edit') {
  824. $entry = $this->row_m->get_row($edit_id, $data->stream, false);
  825. }
  826. // -------------------------------------
  827. // Set up skips & values
  828. // -------------------------------------
  829. $stream_fields = $this->streams_m->get_stream_fields($data->stream_id);
  830. $skips = $this->determine_skips($include, $exclude, $data->stream_id, $stream_fields);
  831. $values = $this->fields->set_values($stream_fields, $entry, $mode, $skips);
  832. // -------------------------------------
  833. // Get & Return Fields
  834. // -------------------------------------
  835. $vars['fields'] = $this->fields->build_fields($stream_fields, $values, $entry, $mode, $skips, $required);
  836. // -------------------------------------
  837. // Individual Field Access
  838. // -------------------------------------
  839. // For greater form control, this allows
  840. // users to access each form item
  841. // individually.
  842. // -------------------------------------
  843. foreach ($vars['fields'] as $field) {
  844. $vars[$field['input_slug']]['label'] = $field['input_title'];
  845. $vars[$field['input_slug']]['slug'] = $field['input_slug'];
  846. $vars[$field['input_slug']]['value'] = $field['value'];
  847. if ($field['input_parts'] !== false) {
  848. $vars[$field['input_slug']]['input'] = $field['input_parts'];
  849. $vars[$field['input_slug']]['input_built'] = $field['input'];
  850. } else {
  851. $vars[$field['input_slug']]['input'] = $field['input'];
  852. $vars[$field['input_slug']]['input_built'] = $field['input'];
  853. }
  854. $vars[$field['input_slug']]['error_raw'] = $field['error_raw'];
  855. $vars[$field['input_slug']]['error'] = $field['error'];
  856. $vars[$field['input_slug']]['required'] = ($field['required']) ? true : false;
  857. $vars[$field['input_slug']]['required'] = $field['required'];
  858. $vars[$field['input_slug']]['odd_even'] = $field['odd_even'];
  859. }
  860. return array($vars);
  861. }
  862. /**
  863. * Determine the fields to skip
  864. * based on include/exclude
  865. */
  866. private function determine_skips($include, $exclude, $stream_id, $stream_fields = null)
  867. {
  868. $skips = array();
  869. if ($include) {
  870. $includes = explode('|', $include);
  871. if (is_null($stream_fields)) {
  872. $stream_fields = $this->streams_m->get_stream_fields($stream_id);
  873. }
  874. // We need to skip everything else
  875. foreach ($stream_fields as $field) {
  876. if (!in_array($field->field_slug, $includes)) {
  877. $skips[] = $field->field_slug;
  878. }
  879. }
  880. }
  881. if ($exclude) {
  882. // Exlcudes are just our skips
  883. $excludes = explode('|', $exclude);
  884. $skips = array_merge($excludes, $skips);
  885. }
  886. return $skips;
  887. }
  888. /**
  889. * Delete a row field
  890. *
  891. * @access public
  892. * @return mixed
  893. */
  894. public function delete_entry()
  895. {
  896. // -------------------------------------
  897. // General Loads
  898. // -------------------------------------
  899. $this->load->library(array('form_validation', 'streams_core/Fields'));
  900. // -------------------------------------
  901. // Get vars
  902. // -------------------------------------
  903. $stream = $this->getAttribute('stream');
  904. $namespace = $this->getAttribute('namespace', $this->core_namespace);
  905. $entry_id = $this->getAttribute('entry_id', false);
  906. $return = $this->getAttribute('return', '');
  907. $vars = array();
  908. // -------------------------------------
  909. // Create Hidden Hash
  910. // -------------------------------------
  911. $hidden['delete_id'] = md5($stream . $entry_id);
  912. // -------------------------------------
  913. // Get Stream Data
  914. // -------------------------------------
  915. $stream = $this->streams_m->get_stream($stream, true, $namespace);
  916. if (!$stream) {
  917. show_error(lang('streams:invalid_stream'));
  918. }
  919. // -------------------------------------
  920. // Check Delete
  921. // -------------------------------------
  922. if (
  923. $this->input->post('delete_confirm')
  924. and $this->input->post('delete_id') == $hidden['delete_id']
  925. ) {
  926. $this->db->where('id', $entry_id)->delete($stream->stream_prefix . $stream->stream);
  927. $this->load->helper('url');
  928. redirect(str_replace('-id-', $entry_id, $return));
  929. } else {
  930. // -------------------------------------
  931. // Get stream fields
  932. // -------------------------------------
  933. $this->fields = $this->streams_m->get_stream_fields($stream->id);
  934. // -------------------------------------
  935. // Get entry data
  936. // -------------------------------------
  937. // We may want to display it
  938. // -------------------------------------
  939. $parameters = array(
  940. 'stream' => $stream->stream,
  941. 'namespace' => $namespace,
  942. 'id' => $entry_id,
  943. 'limit' => 1,
  944. 'offset' => 0,
  945. 'order_by' => false,
  946. 'exclude' => false,
  947. 'show_upcoming' => null,
  948. 'show_past' => null,
  949. 'where' => null,
  950. 'disable' => array(),
  951. 'year' => null,
  952. 'month' => null,
  953. 'day' => null,
  954. 'restrict_user' => 'no',
  955. 'single' => 'yes'
  956. );
  957. $entries = $this->row_m->get_rows($parameters, $this->fields, $stream);
  958. if (!isset($entries['rows'][0])) {
  959. return $this->getAttribute('no_entry', lang('streams:no_entry'));
  960. }
  961. $vars['entry'][0] = $entries['rows'][0];
  962. // -------------------------------------
  963. // Parse other vars
  964. // -------------------------------------
  965. $vars['form_open'] = form_open($this->uri->uri_string(), null, $hidden);
  966. $vars['form_close'] = '</form>';
  967. $vars['delete_confirm'] = '<input type="submit" name="delete_confirm" value="' . lang(
  968. 'streams:delete'
  969. ) . '" />';
  970. $entries = null;
  971. return array($vars);
  972. }
  973. }
  974. ///////////////////////////////////////////////////////////////////////////////
  975. // -------------------------- UTILITIES ------------------------------ //
  976. ///////////////////////////////////////////////////////////////////////////////
  977. /**
  978. * Calendar
  979. *
  980. * @access public
  981. * @return string
  982. */
  983. public function calendar()
  984. {
  985. // -------------------------------------
  986. // Cache
  987. // -------------------------------------
  988. $this->setupCache();
  989. if (!is_null($tag_cache = $this->getTagCache())) {
  990. return $tag_cache;
  991. }
  992. // -------------------------------------
  993. // Get vars
  994. // -------------------------------------
  995. $passed_streams = $this->getAttribute('stream');
  996. $date_fields_passed = $this->getAttribute('date_field', 'created');
  997. $year = $this->getAttribute('year', date('Y'));
  998. $year_segment = $this->getAttribute('year_segment');
  999. $month = $this->getAttribute('month', date('n'));
  1000. $month_segment = $this->getAttribute('month_segment');
  1001. $passed_display = $this->getAttribute('display', '<strong>[id]</strong>');
  1002. $passed_link = $this->getAttribute('link', '');
  1003. $title_col = $this->getAttribute('title_col', 'id');
  1004. $template = $this->getAttribute('template', false);
  1005. // -------------------------------------
  1006. // Figure out year & month
  1007. // -------------------------------------
  1008. if (is_numeric($year_segment) AND is_numeric($this->uri->segment($year_segment))) {
  1009. $year = $this->uri->segment($year_segment);
  1010. }
  1011. if (is_numeric($month_segment) and is_numeric($this->uri->segment($month_segment))) {
  1012. $month = $this->uri->segment($month_segment);
  1013. }
  1014. // Default to current
  1015. if (!is_numeric($year)) {
  1016. $year = date('Y');
  1017. }
  1018. if (!is_numeric($month)) {
  1019. $month = date('n');
  1020. }
  1021. // -------------------------------------
  1022. // Run through streams & create
  1023. // calendar data
  1024. // -------------------------------------
  1025. $calendar = array();
  1026. $displays = explode("|", $passed_display);
  1027. $links = explode("|", $passed_link);
  1028. $streams = explode("|", $passed_streams);
  1029. $date_fields = explode("|", $date_fields_passed);
  1030. $count = 0;
  1031. foreach ($streams as $stream) {
  1032. $date_field = $date_fields[$count];
  1033. $stream = $this->streams_m->get_stream($stream, true, $this->core_namespace);
  1034. $this->fields = $this->streams_m->get_stream_fields($stream->id);
  1035. $parameters = array(
  1036. 'date_by' => $date_field,
  1037. 'get_day' => true,
  1038. 'year' => $year,
  1039. 'month' => $month
  1040. );
  1041. // -------------------------------------
  1042. // Get rows
  1043. // -------------------------------------
  1044. if ($this->cache_type == 'query' and !is_null($this->cache_ttl)) {
  1045. $entries = $this->pyrocache->model(
  1046. 'row_m',
  1047. 'get_rows',
  1048. array($parameters, $this->fields, $stream),
  1049. $this->cache_ttl
  1050. );
  1051. } else {
  1052. $entries = $this->row_m->get_rows($parameters, $this->fields, $stream);
  1053. }
  1054. $this->clearCacheVariables();
  1055. // -------------------------------------
  1056. // Format Calendar Data
  1057. // -------------------------------------
  1058. foreach ($entries as $above) {
  1059. foreach ($above as $entry) {
  1060. if (isset($displays[$count])) {
  1061. // Replace fields
  1062. $display_content = $displays[$count];
  1063. $link_content = $links[$count];
  1064. $parser = new Lex\Parser;
  1065. $parser->scopeGlue(':');
  1066. $display_content = str_replace(array('[', ']'), array('{{ ', ' }}'), $display_content);
  1067. $link_content = str_replace(array('[', ']'), array('{{ ', ' }}'), $link_content);
  1068. $display_content = $parser->parse(
  1069. $display_content,
  1070. $entry,
  1071. array($this->parser, 'parser_callback')
  1072. );
  1073. $link_content = $parser->parse(
  1074. $link_content,
  1075. $entry,
  1076. array($this->parser, 'parser_callback')
  1077. );
  1078. // Link
  1079. if ($link_content != '') {
  1080. $display_content = '<a href="' . site_url(
  1081. $link_content
  1082. ) . '" class="' . $stream . '_link">' . $display_content . '</a>';
  1083. }
  1084. // Adding to the array
  1085. if (isset($calendar[$entry['pyrostreams_cal_day']])) {
  1086. $calendar[$entry['pyrostreams_cal_day']] .= $display_content . '<br />';
  1087. } else {
  1088. $calendar[$entry['pyrostreams_cal_day']] = $display_content . '<br />';
  1089. }
  1090. }
  1091. }
  1092. }
  1093. $count++;
  1094. }
  1095. // -------------------------------------
  1096. // Get Template
  1097. // -------------------------------------
  1098. if ($template) {
  1099. $this->db->limit(1)->select('body')->where('title', $template);
  1100. $db_obj = $this->db->get('page_layouts');
  1101. if ($db_obj->num_rows() > 0) {
  1102. $layout = $db_obj->row();
  1103. $this->calendar_template = $layout->body;
  1104. }
  1105. }
  1106. // -------------------------------------
  1107. // Generate Calendar
  1108. // -------------------------------------
  1109. $calendar_prefs['template'] = $this->calendar_template;
  1110. $calendar_prefs['start_day'] = strtolower($this->getAttribute('start_day', 'sunday'));
  1111. $calendar_prefs['month_type'] = $this->getAttribute('month_type', 'long');
  1112. $calendar_prefs['day_type'] = $this->getAttribute('day_type', 'abr');
  1113. $calendar_prefs['show_next_prev'] = $this->getAttribute('show_next_prev', 'yes');
  1114. $calendar_prefs['next_prev_url'] = $this->getAttribute('next_prev_uri', '');
  1115. if ($calendar_prefs['show_next_prev'] == 'yes') {
  1116. $calendar_prefs['show_next_prev'] = true;
  1117. } else {
  1118. $calendar_prefs['show_next_prev'] = false;
  1119. }
  1120. $this->load->library('calendar', $calendar_prefs);
  1121. $return_content = $this->calendar->generate($year, $month, $calendar);
  1122. // -------------------------------------
  1123. // Cache End Procedures
  1124. // -------------------------------------
  1125. $this->writeTagCache($return_content);
  1126. $this->clearCacheVariables();
  1127. // -------------------------------------
  1128. return $return_content;
  1129. }
  1130. /**
  1131. * Reset the cache vars to their defaults
  1132. *
  1133. * @access private
  1134. * @return void
  1135. */
  1136. private function clearCacheVariables()
  1137. {
  1138. $this->cache_type = 'query';
  1139. $this->cache_time_format = 'minutes';
  1140. $this->cache_ttl = null;
  1141. $this->cache_hash = null;
  1142. $this->write_tag_cache = false;
  1143. }
  1144. /**
  1145. * Seach Form
  1146. *
  1147. * @access public
  1148. * @return string
  1149. */
  1150. public function search_form()
  1151. {
  1152. $this->load->helper('form');
  1153. $stream = $this->getAttribute('stream');
  1154. $namespace = $this->getAttribute('namespace', $this->core_namespace);
  1155. $fields = $this->getAttribute('fields');
  1156. $search_types = array('keywords', 'full_phrase');
  1157. $search_type = strtolower($this->getAttribute('search_type', 'full_phrase'));
  1158. $results_page = $this->getAttribute('results_page');
  1159. $variables = array();
  1160. // -------------------------------------
  1161. // Check our search type
  1162. // -------------------------------------
  1163. if (!in_array($search_type, $search_types)) {
  1164. show_error($search_type . ' ' . lang('streams:invalid_search_type'));
  1165. }
  1166. // -------------------------------------
  1167. // Check for our search term
  1168. // -------------------------------------
  1169. if (isset($_POST['search_term'])) {
  1170. $this->load->model('streams/search_m');
  1171. // Write cache
  1172. $cache_id = $this->search_m->perform_search(
  1173. $this->input->post('search_term'),
  1174. $search_type,
  1175. $stream,
  1176. $fields,
  1177. $this->core_namespace
  1178. );
  1179. // Redirect
  1180. $this->load->helper('url');
  1181. redirect($results_page . '/' . $cache_id);
  1182. }
  1183. // -------------------------------------
  1184. // Build Form
  1185. // -------------------------------------
  1186. $vars['form_open'] = form_open($this->uri->uri_string());
  1187. $search_input = array(
  1188. 'name' => 'search_term',
  1189. 'id' => 'search_term'
  1190. );
  1191. $vars['search_input'] = form_input($search_input);
  1192. $vars['form_submit'] = form_submit('search_submit', lang('streams:search'));
  1193. $vars['form_close'] = '</form>';
  1194. return array($vars);
  1195. }
  1196. /**
  1197. * Search Results
  1198. *
  1199. * @access public
  1200. * @return string
  1201. */
  1202. public function search_results()
  1203. {
  1204. $paginate = $this->getAttribute('paginate', 'yes');
  1205. $cache_segment = $this->getAttribute('cache_segment', 3);
  1206. $per_page = $this->getAttribute('per_page', 25);
  1207. $variables = array();
  1208. // Pagination segment is always right after the cache hash segment
  1209. $pag_segment = $cache_segment + 1;
  1210. // -------------------------------------
  1211. // Check for Cached Search Query
  1212. // -------------------------------------
  1213. $this->load->model('streams/search_m');
  1214. if (!$cache = $this->search_m->get_cache($this->uri->segment($cache_segment))) {
  1215. // Invalid search
  1216. show_error(lang('streams:search_not_found'));
  1217. }
  1218. $stream = $this->streams_m->get_stream($cache->stream, true, $cache->stream_namespace);
  1219. $this->fields = $this->streams_m->get_stream_fields($stream->id);
  1220. // Easy out for no results
  1221. if ($cache->total_results == 0) {
  1222. return array(
  1223. 'no_results' => $this->getAttribute('no_results', lang('streams:no_results')),
  1224. 'results_exist' => false,
  1225. 'results' => array(),
  1226. 'pagination' => null,
  1227. 'search_term' => $this->getAttribute('search_term', $cache->search_term),
  1228. 'total_results' => (string)'0'
  1229. );
  1230. }
  1231. // -------------------------------------
  1232. // Pagination
  1233. // -------------------------------------
  1234. $return = array();
  1235. $return['total'] = $cache->total_results;
  1236. if ($paginate == 'yes') {
  1237. // Add in our pagination config
  1238. // override varaibles.
  1239. foreach ($this->pagination_config as $key => $var) {
  1240. $this->pagination_config[$key] = $this->attribute($key, $this->pagination_config[$key]);
  1241. // Make sure we obey the false parameters
  1242. if ($this->pagination_config[$key] == 'false') {
  1243. $this->pagination_config[$key] = false;
  1244. }
  1245. }
  1246. $return['pagination'] = $this->row_m->build_pagination(
  1247. $pag_segment,
  1248. $per_page,
  1249. $return['total'],
  1250. $this->pagination_config
  1251. );
  1252. $offset = $this->uri->segment($pag_segment, 0);
  1253. $query_string = $cache->query_string . " LIMIT $offset, $per_page";
  1254. } else {
  1255. $return['pagination'] = null;
  1256. $query_string = $cache->query_string;
  1257. }
  1258. // -------------------------------------
  1259. // Get & Format Results
  1260. // -------------------------------------
  1261. $return['results'] = $this->row_m->format_rows(
  1262. $this->db->query($query_string)->result_array(),
  1263. $stream
  1264. );
  1265. // -------------------------------------
  1266. // Extra Data
  1267. // -------------------------------------
  1268. $return['no_results'] = '';
  1269. $return['total_results'] = $cache->total_results;
  1270. $return['results_exist'] = true;
  1271. $return['search_term'] = $cache->search_term;
  1272. return $this->streams_content_parse($this->content(), $return, $cache->stream);
  1273. }
  1274. ///////////////////////////////////////////////////////////////////////////////
  1275. // -------------------------- LEGACY ------------------------------ //
  1276. ///////////////////////////////////////////////////////////////////////////////
  1277. /**
  1278. * Format date variables
  1279. * Legacy. This is now done by the date helper
  1280. * or in the datetime field type.
  1281. *
  1282. * @access public
  1283. * @return string - formatted date
  1284. */
  1285. public function date()
  1286. {
  1287. $date_formats = array(
  1288. 'DATE_ATOM',
  1289. 'DATE_COOKIE',
  1290. 'DATE_ISO8601',
  1291. 'DATE_RFC822',
  1292. 'DATE_RFC850',
  1293. 'DATE_RFC1036',
  1294. 'DATE_RFC1123',
  1295. 'DATE_RFC2822',
  1296. 'DATE_RSS',
  1297. 'DATE_W3C'
  1298. );
  1299. $date = $this->attribute('date');
  1300. $format = $this->attribute('format');
  1301. // No sense in trying to get down
  1302. // with somedata that isn't there
  1303. if (!$date or !$format) {
  1304. return null;
  1305. }
  1306. $this->load->helper('date');
  1307. // Make sure we have a UNIX date
  1308. if (!is_numeric($date)) {
  1309. $date = mysql_to_unix($date);
  1310. }
  1311. // Is this a preset?
  1312. if (in_array($format, $date_formats)) {
  1313. return standard_date($format, $date);
  1314. }
  1315. // Default is PHP date
  1316. return date($format, $date);
  1317. }
  1318. }