public function processTag($tag, $processUncacheable = true)
 {
     // We need only # placeholders
     if ($tag[1][0] !== '#' && strpos($tag[1], '!#') === false) {
         return parent::processTag($tag, $processUncacheable);
     }
     $this->_processingTag = true;
     $element = null;
     $elementOutput = null;
     $outerTag = $tag[0];
     $innerTag = $tag[1];
     /* collect any nested element tags in the innerTag and process them */
     $this->processElementTags($outerTag, $innerTag, $processUncacheable);
     $this->_processingTag = true;
     $outerTag = '[[' . $innerTag . ']]';
     $tagParts = xPDO::escSplit('?', $innerTag, '`', 2);
     $tagName = trim($tagParts[0]);
     $tagPropString = null;
     if (isset($tagParts[1])) {
         $tagPropString = trim($tagParts[1]);
     }
     $token = substr($tagName, 0, 1);
     $tokenOffset = 0;
     $cacheable = true;
     if ($token === '!') {
         if (!$processUncacheable) {
             $this->_processingTag = false;
             return $outerTag;
         }
         $cacheable = false;
         $tokenOffset++;
         $token = substr($tagName, $tokenOffset, 1);
     }
     if ($cacheable && $token !== '+') {
         $elementOutput = $this->loadFromCache($outerTag);
     }
     if ($elementOutput === null) {
         switch ($token) {
             case '#':
                 include_once $this->modx->getOption('core_path') . 'components/fastfield/model/fastfield/fastfield.php';
                 $tagName = substr($tagName, 1 + $tokenOffset);
                 $element = new modResourceFieldTag($this->modx);
                 $element->set('name', $tagName);
                 $element->setTag($outerTag);
                 $element->setCacheable($cacheable);
                 $elementOutput = $element->process($tagPropString);
                 break;
         }
     }
     if (($elementOutput === null || $elementOutput === false) && $outerTag !== $tag[0]) {
         $elementOutput = $outerTag;
     }
     if ($this->modx->getDebug() === true) {
         $this->modx->log(xPDO::LOG_LEVEL_DEBUG, "Processing {$outerTag} as {$innerTag} using tagname {$tagName}:\n" . print_r($elementOutput, 1) . "\n\n");
     }
     $this->_processingTag = false;
     return $elementOutput;
 }
 /** {inheritDoc} */
 public function processTag($tag, $processUncacheable = true)
 {
     $hash = sha1($tag[0]);
     $parse_time_start = microtime(true);
     $query_time_start = $this->modx->queryTime;
     $queries_start = $this->modx->executedQueries;
     // Call processTag method from real parser
     $result = $this->parser && $this->parser instanceof modParser ? $this->parser->processTag($tag, $processUncacheable) : parent::processTag($tag, $processUncacheable);
     $parse_time = number_format(round(microtime(true) - $parse_time_start, 7), 7);
     $query_time = number_format(round($this->modx->queryTime - $query_time_start, 7), 7);
     $queries = $this->modx->executedQueries - $queries_start;
     if (isset($this->tags[$hash])) {
         $this->tags[$hash]['attempts']++;
         $this->tags[$hash]['queries'] += $queries;
         $this->tags[$hash]['queries_time'] += $query_time;
         $this->tags[$hash]['parse_time'] += $parse_time;
     } else {
         $this->tags[$hash] = array('tag' => htmlentities(trim($tag[0]), ENT_QUOTES, 'UTF-8'), 'attempts' => 1, 'queries' => $queries, 'queries_time' => $query_time, 'parse_time' => $parse_time);
     }
     return $result;
 }
 /**
  * Quickly processes a simple tag and returns the result.
  *
  * @param string $tag A full tag string parsed from content.
  * @param boolean $processUncacheable
  *
  * @return mixed The output of the processed element represented by the specified tag.
  */
 public function processTag($tag, $processUncacheable = true)
 {
     $outerTag = $tag[0];
     $innerTag = $tag[1];
     $processed = false;
     $output = $token = '';
     // Disabled tag
     if (empty($innerTag[0]) || $innerTag[0] == '-') {
         return '';
     } elseif ($innerTag[0] == '!' && !$processUncacheable) {
         $this->processElementTags($outerTag, $innerTag, $processUncacheable);
         $outerTag = '[[' . $innerTag . ']]';
         return $outerTag;
     } elseif (strpos($innerTag, '?') === false && preg_match('/^(?:!|)[-|%|~|+|*|#]+/', $innerTag, $matches)) {
         if (strpos($innerTag, '[[') !== false) {
             $this->processElementTags($outerTag, $innerTag, $processUncacheable);
             $outerTag = '[[' . $innerTag . ']]';
         }
         $innerTag = ltrim($this->realname($innerTag), '!');
         $token = $innerTag[0];
         $innerTag = substr($innerTag, 1);
         switch ($token) {
             // Lexicon tag
             case '%':
                 $tmp = $this->modx->lexicon($innerTag);
                 if ($tmp != $innerTag) {
                     $output = $tmp;
                     $processed = true;
                 }
                 break;
                 // Link tag
             // Link tag
             case '~':
                 if (is_numeric($innerTag)) {
                     if ($tmp = $this->modx->makeUrl($innerTag, '', '', $this->modx->getOption('link_tag_scheme', null, -1, true))) {
                         $output = $tmp;
                         $processed = true;
                     }
                 }
                 break;
                 // Usual placeholder
                 // and
                 // System setting
             // Usual placeholder
             // and
             // System setting
             case '+':
                 if (isset($this->modx->placeholders[$innerTag])) {
                     $output = $this->modx->placeholders[$innerTag];
                     $processed = true;
                 }
                 break;
                 // Resource tag and TVs
             // Resource tag and TVs
             case '*':
                 if (is_object($this->modx->resource) && $this->modx->resource instanceof modResource) {
                     if ($innerTag == 'content') {
                         $output = $this->modx->resource->getContent();
                     } elseif (is_array($this->modx->resource->_fieldMeta) && isset($this->modx->resource->_fieldMeta[$innerTag])) {
                         $output = $this->modx->resource->get($innerTag);
                     } else {
                         $output = $this->modx->resource->getTVValue($innerTag);
                     }
                     $processed = true;
                 }
                 break;
                 // FastField tag
                 // Thank to Argnist and Dimlight Studio (http://dimlight.ru) for the original idea
             // FastField tag
             // Thank to Argnist and Dimlight Studio (http://dimlight.ru) for the original idea
             case '#':
                 $tmp = array_map('trim', explode('.', $innerTag));
                 $length = count($tmp);
                 // Resource tag
                 if (is_numeric($tmp[0])) {
                     /** @var modResource $resource */
                     if (!($resource = $this->pdoTools->getStore($tmp[0], 'resource'))) {
                         $resource = $this->modx->getObject('modResource', $tmp[0]);
                         $this->pdoTools->setStore($tmp[0], $resource, 'resource');
                     }
                     $output = '';
                     if (!empty($resource)) {
                         // Field specified
                         if (!empty($tmp[1])) {
                             $tmp[1] = strtolower($tmp[1]);
                             if ($tmp[1] == 'content') {
                                 $output = $resource->getContent();
                             } elseif ($field = $resource->get($tmp[1])) {
                                 $output = $field;
                                 if (is_array($field)) {
                                     if ($length > 2) {
                                         foreach ($tmp as $k => $v) {
                                             if ($k === 0) {
                                                 continue;
                                             }
                                             if (isset($field[$v])) {
                                                 $output = $field[$v];
                                             }
                                         }
                                     }
                                 }
                             } elseif ($field === null) {
                                 unset($tmp[0]);
                                 $tmp = preg_replace('/^tv\\./', '', implode('.', $tmp));
                                 $output = $resource->getTVValue($tmp);
                             }
                         } else {
                             $output = $resource->toArray();
                         }
                     }
                 } else {
                     switch (strtolower($tmp[0])) {
                         case 'post':
                             $array = $_POST;
                             break;
                         case 'get':
                             $array = $_GET;
                             break;
                         case 'request':
                             $array = $_REQUEST;
                             break;
                         case 'server':
                             $array = $_SERVER;
                             break;
                         case 'files':
                             $array = $_FILES;
                             break;
                         case 'cookie':
                             $array = $_COOKIE;
                             break;
                         case 'session':
                             $array = $_SESSION;
                             break;
                         default:
                             $array = array();
                             break;
                     }
                     // Field specified
                     if (!empty($tmp[1])) {
                         $field = isset($array[$tmp[1]]) ? $array[$tmp[1]] : '';
                         $output = $field;
                         if (is_array($field)) {
                             if ($length > 2) {
                                 foreach ($tmp as $k => $v) {
                                     if ($k === 0) {
                                         continue;
                                     }
                                     if (isset($field[$v])) {
                                         $output = $field[$v];
                                     }
                                 }
                             }
                         }
                     } else {
                         $output = $array;
                     }
                     if (is_string($output)) {
                         $output = $this->modx->stripTags($output);
                     }
                 }
                 $processed = true;
                 break;
         }
     }
     // Processing output filters
     if ($processed) {
         if (strpos($outerTag, ':') !== false) {
             /** @var pdoTag $object */
             $tag = new pdoTag($this->modx);
             $tag->_content = $output;
             $tag->setTag($outerTag);
             $tag->setToken($token);
             $tag->setContent(ltrim(rtrim($outerTag, ']'), '[!' . $token));
             $tag->setCacheable(!$processUncacheable);
             $tag->process();
             $output = $tag->_output;
         }
         if ($this->modx->getDebug() === true) {
             $this->modx->log(xPDO::LOG_LEVEL_DEBUG, "Processing {$outerTag} as {$innerTag}:\n" . print_r($output, 1) . "\n\n");
         }
         // Print array
         if (is_array($output)) {
             $output = htmlentities(print_r($output, true), ENT_QUOTES, 'UTF-8');
         }
     } else {
         $output = parent::processTag($tag, $processUncacheable);
     }
     return $output;
 }