/**
  * Given an array of all the Datasources for this page, sort them into the
  * correct execution order and append the Datasource results to the
  * page XML. If the Datasource provides any parameters, they will be
  * added to the `$env` pool for use by other Datasources and eventual
  * inclusion into the page parameters.
  *
  * @param string $datasources
  *  A string of Datasource's attached to this page, comma separated.
  * @param XMLElement $wrapper
  *  The XMLElement to append the Datasource results to. Datasource
  *  results are contained in a root XMLElement that is the handlised
  *  version of their name.
  * @param array $params
  *  Any params to automatically add to the `$env` pool, by default this
  *  is an empty array. It looks like Symphony does not utilise this parameter
  *  at all
  */
 public function processDatasources($datasources, XMLElement &$wrapper, array $params = array())
 {
     if (trim($datasources) == '') {
         return;
     }
     $datasources = preg_split('/,\\s*/i', $datasources, -1, PREG_SPLIT_NO_EMPTY);
     $datasources = array_map('trim', $datasources);
     if (!is_array($datasources) || empty($datasources)) {
         return;
     }
     $this->_env['pool'] = $params;
     $pool = $params;
     $dependencies = array();
     foreach ($datasources as $handle) {
         Symphony::Profiler()->seed();
         $pool[$handle] =& DatasourceManager::create($handle, array(), false);
         $dependencies[$handle] = $pool[$handle]->getDependencies();
     }
     $dsOrder = $this->__findDatasourceOrder($dependencies);
     foreach ($dsOrder as $handle) {
         Symphony::Profiler()->seed();
         $queries = Symphony::Database()->queryCount();
         $ds = $pool[$handle];
         $ds->processParameters(array('env' => $this->_env, 'param' => $this->_param));
         // default to no XML
         $xml = NULL;
         /**
          * Allows extensions to execute the data source themselves (e.g. for caching)
          * and providing their own output XML instead
          *
          * @since Symphony 2.3
          * @delegate DataSourcePreExecute
          * @param string $context
          * '/frontend/'
          * @param boolean $datasource
          *  The Datasource object
          * @param mixed $xml
          *  The XML output of the data source. Can be an XMLElement or string.
          * @param mixed $paral_pool
          *  The existing param pool including output parameters of any previous data sources
          */
         Symphony::ExtensionManager()->notifyMembers('DataSourcePreExecute', '/frontend/', array('datasource' => &$ds, 'xml' => &$xml, 'param_pool' => &$this->_env['pool']));
         // if the XML is still null, an extension has not run the data source, so run normally
         if (is_null($xml)) {
             $xml = $ds->grab($this->_env['pool']);
         }
         if ($xml) {
             if (is_object($xml)) {
                 $wrapper->appendChild($xml);
             } else {
                 $wrapper->setValue($wrapper->getValue() . PHP_EOL . '    ' . trim($xml));
             }
         }
         $queries = Symphony::Database()->queryCount() - $queries;
         Symphony::Profiler()->sample($handle, PROFILE_LAP, 'Datasource', $queries);
         unset($ds);
     }
 }
 /**
  * Given an array of all the Datasources for this page, sort them into the
  * correct execution order and append the Datasource results to the
  * page XML. If the Datasource provides any parameters, they will be
  * added to the `$env` pool for use by other Datasources and eventual
  * inclusion into the page parameters.
  *
  * @param string $datasources
  *  A string of Datasource's attached to this page, comma separated.
  * @param XMLElement $wrapper
  *  The XMLElement to append the Datasource results to. Datasource
  *  results are contained in a root XMLElement that is the handlised
  *  version of their name.
  * @param array $params
  *  Any params to automatically add to the `$env` pool, by default this
  *  is an empty array. It looks like Symphony does not utilise this parameter
  *  at all
  */
 public function processDatasources($datasources, XMLElement &$wrapper, array $params = array())
 {
     if (trim($datasources) == '') {
         return;
     }
     $datasources = preg_split('/,\\s*/i', $datasources, -1, PREG_SPLIT_NO_EMPTY);
     $datasources = array_map('trim', $datasources);
     if (!is_array($datasources) || empty($datasources)) {
         return;
     }
     $this->_env['pool'] = $params;
     $pool = $params;
     $dependencies = array();
     foreach ($datasources as $handle) {
         $pool[$handle] = DatasourceManager::create($handle, array(), false);
         $dependencies[$handle] = $pool[$handle]->getDependencies();
     }
     $dsOrder = $this->__findDatasourceOrder($dependencies);
     foreach ($dsOrder as $handle) {
         Symphony::Profiler()->seed();
         $queries = Symphony::Database()->queryCount();
         // default to no XML
         $xml = null;
         $ds = $pool[$handle];
         // Handle redirect on empty setting correctly RE: #1539
         try {
             $ds->processParameters(array('env' => $this->_env, 'param' => $this->_param));
         } catch (FrontendPageNotFoundException $e) {
             // Work around. This ensures the 404 page is displayed and
             // is not picked up by the default catch() statement below
             FrontendPageNotFoundExceptionHandler::render($e);
         }
         /**
          * Allows extensions to execute the data source themselves (e.g. for caching)
          * and providing their own output XML instead
          *
          * @since Symphony 2.3
          * @delegate DataSourcePreExecute
          * @param string $context
          * '/frontend/'
          * @param DataSource $datasource
          *  The Datasource object
          * @param mixed $xml
          *  The XML output of the data source. Can be an `XMLElement` or string.
          * @param array $param_pool
          *  The existing param pool including output parameters of any previous data sources
          */
         Symphony::ExtensionManager()->notifyMembers('DataSourcePreExecute', '/frontend/', array('datasource' => &$ds, 'xml' => &$xml, 'param_pool' => &$this->_env['pool']));
         // if the XML is still null, an extension has not run the data source, so run normally
         if (is_null($xml)) {
             $xml = $ds->grab($this->_env['pool']);
         }
         if ($xml) {
             /**
              * After the datasource has executed, either by itself or via the
              * `DataSourcePreExecute` delegate, and if the `$xml` variable is truthy,
              * this delegate allows extensions to modify the output XML and parameter pool
              *
              * @since Symphony 2.3
              * @delegate DataSourcePostExecute
              * @param string $context
              * '/frontend/'
              * @param DataSource $datasource
              *  The Datasource object
              * @param mixed $xml
              *  The XML output of the data source. Can be an `XMLElement` or string.
              * @param array $param_pool
              *  The existing param pool including output parameters of any previous data sources
              */
             Symphony::ExtensionManager()->notifyMembers('DataSourcePostExecute', '/frontend/', array('datasource' => $ds, 'xml' => &$xml, 'param_pool' => &$this->_env['pool']));
             if ($xml instanceof XMLElement) {
                 $wrapper->appendChild($xml);
             } else {
                 $wrapper->setValue($wrapper->getValue() . PHP_EOL . '	  ' . trim($xml));
             }
         }
         $queries = Symphony::Database()->queryCount() - $queries;
         Symphony::Profiler()->sample($handle, PROFILE_LAP, 'Datasource', $queries);
         unset($ds);
     }
 }
 public function prepareTableValue($data, XMLElement $link = null, $entry_id = null)
 {
     $sectionManager = new SectionManager(Symphony::Engine());
     $section = $sectionManager->fetch($this->get('linked_section_id'));
     $entryManager = new EntryManager(Symphony::Engine());
     $fieldManager = new FieldManager(Symphony::Engine());
     $linked = $fieldManager->fetch($this->get('linked_field_id'));
     $custom_link = null;
     $more_link = null;
     // Not setup correctly:
     if (!$section instanceof Section or !$linked) {
         return parent::prepareTableValue(array(), $link, $entry_id);
     }
     if (!empty($data['linked_entry_id'])) {
         $field = current($section->fetchVisibleColumns());
         $data = $this->prepareData($data);
         if (!is_null($field) && $data['linked_entry_id']) {
             if ($this->get('column_mode') != 'count') {
                 if ($this->get('column_mode') == 'last-item') {
                     $data['linked_entry_id'] = array_reverse($data['linked_entry_id']);
                 }
                 $entries = $entryManager->fetch(current($data['linked_entry_id']), $this->get('linked_section_id'), 1);
                 if (is_array($entries) and !empty($entries)) {
                     $entry = current($entries);
                     $value = $field->prepareTableValue($entry->getData($field->get('id')), new XMLElement('span'));
                     $custom_link = new XMLElement('a');
                     $custom_link->setAttribute('href', sprintf('%s/symphony/publish/%s/edit/%s/', URL, $section->get('handle'), $entry->get('id')));
                     if ($value instanceof XMLElement) {
                         $value = $value->generate();
                     }
                     $custom_link->setValue(strip_tags($value));
                     $more_link = new XMLElement('a');
                     $more_link->setValue(__('more →'));
                     $more_link->setAttribute('href', sprintf('%s/symphony/publish/%s/?filter=%s:%s', URL, $section->get('handle'), $linked->get('element_name'), $entry_id));
                 }
             } else {
                 $joins = null;
                 $where = null;
                 $linked->buildDSRetrivalSQL(array($entry_id), $joins, $where, false);
                 $count = $entryManager->fetchCount($this->get('linked_section_id'), $where, $joins);
                 if ($count > 0) {
                     $custom_link = new XMLElement('a');
                     $custom_link->setValue($count . __(' →'));
                     $custom_link->setAttribute('href', sprintf('%s/symphony/publish/%s/?filter=%s:%s', URL, $section->get('handle'), $linked->get('element_name'), $entry_id));
                 }
             }
         }
     }
     if (is_null($custom_link)) {
         $custom_link = new XMLElement('a');
         $custom_link->setValue(__('0 →'));
         $custom_link->setAttribute('href', sprintf('%s/symphony/publish/%s/?filter=%s:%s', URL, $section->get('handle'), $linked->get('element_name'), $entry_id));
         if ($this->get('column_mode') != 'count') {
             $more_link = $custom_link;
             $more_link->setValue(__('more →'));
             $custom_link = new XMLElement('span');
             $custom_link->setAttribute('class', 'inactive');
             $custom_link->setValue(__('None'));
         }
     }
     if ($link) {
         $link->setValue($custom_link->getValue());
         return $link->generate();
     }
     if ($this->get('column_mode') != 'count') {
         $wrapper = new XMLElement('span');
         $wrapper->setValue(sprintf('%s, %s', $custom_link->generate(), $more_link->generate()));
         return $wrapper;
     }
     return $custom_link;
 }
 /**
  * Given an array of all the Datasources for this page, sort them into the
  * correct execution order and append the Datasource results to the
  * page XML. If the Datasource provides any parameters, they will be
  * added to the `$env` pool for use by other Datasources and eventual
  * inclusion into the page parameters.
  *
  * @param string $datasources
  *  A string of Datasource's attached to this page, comma separated.
  * @param XMLElement $wrapper
  *  The XMLElement to append the Datasource results to. Datasource
  *  results are contained in a root XMLElement that is the handlised
  *  version of their name.
  * @param array $params
  *  Any params to automatically add to the `$env` pool, by default this
  *  is an empty array. It looks like Symphony does not utilise this parameter
  *  at all
  */
 public function processDatasources($datasources, XMLElement &$wrapper, array $params = array())
 {
     if (trim($datasources) == '') {
         return;
     }
     $datasources = preg_split('/,\\s*/i', $datasources, -1, PREG_SPLIT_NO_EMPTY);
     $datasources = array_map('trim', $datasources);
     if (!is_array($datasources) || empty($datasources)) {
         return;
     }
     $this->_env['pool'] = $params;
     $pool = $params;
     $dependencies = array();
     foreach ($datasources as $handle) {
         Frontend::instance()->Profiler->seed();
         $pool[$handle] =& $this->DatasourceManager->create($handle, NULL, false);
         $dependencies[$handle] = $pool[$handle]->getDependencies();
     }
     $dsOrder = $this->__findDatasourceOrder($dependencies);
     foreach ($dsOrder as $handle) {
         Frontend::instance()->Profiler->seed();
         $queries = Symphony::Database()->queryCount();
         $ds = $pool[$handle];
         $ds->processParameters(array('env' => $this->_env, 'param' => $this->_param));
         if ($xml = $ds->grab($this->_env['pool'])) {
             if (is_object($xml)) {
                 $wrapper->appendChild($xml);
             } else {
                 $wrapper->setValue($wrapper->getValue() . self::CRLF . '	' . trim($xml));
             }
         }
         $queries = Symphony::Database()->queryCount() - $queries;
         Frontend::instance()->Profiler->sample($handle, PROFILE_LAP, 'Datasource', $queries);
         unset($ds);
     }
 }
 /**
  * The processEvents function executes all Events attached to the resolved
  * page in the correct order determined by `__findEventOrder()`. The results
  * from the Events are appended to the page's XML. Events execute first,
  * before Datasources.
  *
  * @uses FrontendProcessEvents
  * @uses FrontendEventPostProcess
  * @param string $events
  *  A string of all the Events attached to this page, comma separated.
  * @param XMLElement $wrapper
  *  The XMLElement to append the Events results to. Event results are
  *  contained in a root XMLElement that is the handlised version of
  *  their name.
  * @throws Exception
  */
 private function processEvents($events, XMLElement &$wrapper)
 {
     /**
      * Manipulate the events array and event element wrapper
      * @delegate FrontendProcessEvents
      * @param string $context
      * '/frontend/'
      * @param array $env
      * @param string $events
      *  A string of all the Events attached to this page, comma separated.
      * @param XMLElement $wrapper
      *  The XMLElement to append the Events results to. Event results are
      *  contained in a root XMLElement that is the handlised version of
      *  their name.
      * @param array $page_data
      *  An associative array of page meta data
      */
     Symphony::ExtensionManager()->notifyMembers('FrontendProcessEvents', '/frontend/', array('env' => $this->_env, 'events' => &$events, 'wrapper' => &$wrapper, 'page_data' => $this->_pageData));
     if (strlen(trim($events)) > 0) {
         $events = preg_split('/,\\s*/i', $events, -1, PREG_SPLIT_NO_EMPTY);
         $events = array_map('trim', $events);
         if (!is_array($events) || empty($events)) {
             return;
         }
         $pool = array();
         foreach ($events as $handle) {
             $pool[$handle] = EventManager::create($handle, array('env' => $this->_env, 'param' => $this->_param));
         }
         uasort($pool, array($this, '__findEventOrder'));
         foreach ($pool as $handle => $event) {
             Symphony::Profiler()->seed();
             $queries = Symphony::Database()->queryCount();
             if ($xml = $event->load()) {
                 if (is_object($xml)) {
                     $wrapper->appendChild($xml);
                 } else {
                     $wrapper->setValue($wrapper->getValue() . PHP_EOL . '    ' . trim($xml));
                 }
             }
             $queries = Symphony::Database()->queryCount() - $queries;
             Symphony::Profiler()->sample($handle, PROFILE_LAP, 'Event', $queries);
         }
     }
     /**
      * Just after the page events have triggered. Provided with the XML object
      * @delegate FrontendEventPostProcess
      * @param string $context
      * '/frontend/'
      * @param XMLElement $xml
      *  The XMLElement to append the Events results to. Event results are
      *  contained in a root XMLElement that is the handlised version of
      *  their name.
      */
     Symphony::ExtensionManager()->notifyMembers('FrontendEventPostProcess', '/frontend/', array('xml' => &$wrapper));
 }
 public function prepareTableValue($data, XMLElement $link = null, $entry_id = null)
 {
     if ($this->get('use_timeago') == 'yes') {
         $row = $this->dateFromEntryID($entry_id);
         if (!$link) {
             $link = new XMLElement('span');
         }
         $date = $this->parseDate($row);
         $link->setAttribute('class', 'js-systemdate-timeago');
         $time = new XMLElement('time', $this->formatDate($date));
         $time->setAttributeArray(array('utc' => $date->format('U'), 'datetime' => $date->format(DateTime::ISO8601), 'title' => $time->getValue()));
         $link->appendChild($time);
         return $link->generate();
     }
     return parent::prepareTableValue($data, $link, $entry_id);
 }