public function validateBlockType(SuperTable_BlockTypeModel $blockType, $validateUniques = true) { $validates = true; $blockTypeRecord = $this->_getBlockTypeRecord($blockType); $blockTypeRecord->fieldId = $blockType->fieldId; // Can't validate multiple new rows at once so we'll need to give these temporary context to avoid false unique // handle validation errors, and just validate those manually. Also apply the future fieldColumnPrefix so that // field handle validation takes its length into account. $contentService = craft()->content; $originalFieldContext = $contentService->fieldContext; $originalFieldColumnPrefix = $contentService->fieldColumnPrefix; $contentService->fieldContext = StringHelper::randomString(10); $contentService->fieldColumnPrefix = 'field_'; foreach ($blockType->getFields() as $field) { // Hack to allow blank field names if (!$field->name) { $field->name = '__blank__'; } craft()->fields->validateField($field); // Make sure the block type handle + field handle combo is unique for the whole field. This prevents us from // worrying about content column conflicts like "a" + "b_c" == "a_b" + "c". if ($field->hasErrors()) { $blockType->hasFieldErrors = true; $validates = false; } } $contentService->fieldContext = $originalFieldContext; $contentService->fieldColumnPrefix = $originalFieldColumnPrefix; return $validates; }
/** * @param \Twig_Compiler $compiler * * @return null */ public function compile(\Twig_Compiler $compiler) { $n = static::$_cacheCount++; $conditions = $this->getNode('conditions'); $ignoreConditions = $this->getNode('ignoreConditions'); $key = $this->getNode('key'); $durationNum = $this->getAttribute('durationNum'); $durationUnit = $this->getAttribute('durationUnit'); $expiration = $this->getNode('expiration'); $global = $this->getAttribute('global') ? 'true' : 'false'; $flags = $this->getNode('flags'); $compiler->addDebugInfo($this)->write("\$cacheService = \\Craft\\craft()->templateCache;\n")->write("\$cacheFlagService = \\Craft\\craft()->cacheFlag_cache;\n")->write("\$ignoreCacheTag{$n} = (\\Craft\\craft()->request->isLivePreview() || \\Craft\\craft()->request->getToken()"); if ($conditions) { $compiler->raw(' || !(')->subcompile($conditions)->raw(')'); } else { if ($ignoreConditions) { $compiler->raw(' || (')->subcompile($ignoreConditions)->raw(')'); } } $compiler->raw(");\n")->write("if (!\$ignoreCacheTag{$n}) {\n")->indent()->write("\$cacheKey{$n} = "); if ($key) { $compiler->subcompile($key); } else { $compiler->raw('"' . StringHelper::randomString() . '"'); } $compiler->raw(";\n")->write("\$cacheBody{$n} = \$cacheService->getTemplateCache(\$cacheKey{$n}, {$global});\n")->outdent()->write("}\n")->write("if (empty(\$cacheBody{$n})) {\n")->indent()->write("ob_start();\n")->subcompile($this->getNode('body'))->write("\$cacheBody{$n} = ob_get_clean();\n")->write("if (!\$ignoreCacheTag{$n}) {\n")->indent()->write("\$cacheService->startTemplateCache(\$cacheKey{$n});\n")->write("\$cacheService->endTemplateCache(\$cacheKey{$n}, {$global}, "); if ($durationNum) { // So silly that PHP doesn't support "+1 week" http://www.php.net/manual/en/datetime.formats.relative.php if ($durationUnit == 'week') { if ($durationNum == 1) { $durationNum = 7; $durationUnit = 'days'; } else { $durationUnit = 'weeks'; } } $compiler->raw("'+{$durationNum} {$durationUnit}'"); } else { $compiler->raw('null'); } $compiler->raw(', '); if ($expiration) { $compiler->subcompile($expiration); } else { $compiler->raw('null'); } $compiler->raw(", \$cacheBody{$n});\n")->outdent()->write("}\n")->outdent(); if ($flags) { $compiler->write("\$cacheFlagService->addCacheByKey(\$cacheKey{$n}, "); $compiler->subcompile($flags); $compiler->write(");\n"); } $compiler->write("}\n")->write("echo \$cacheBody{$n};\n"); }
public function validateBlockType(SuperTable_BlockTypeModel $blockType, $validateUniques = true) { $validates = true; $blockTypeRecord = $this->_getBlockTypeRecord($blockType); $blockTypeRecord->fieldId = $blockType->fieldId; if (!$blockTypeRecord->validate()) { $validates = false; $blockType->addErrors($blockTypeRecord->getErrors()); } // Can't validate multiple new rows at once so we'll need to give these temporary context to avoid false unique // handle validation errors, and just validate those manually. Also apply the future fieldColumnPrefix so that // field handle validation takes its length into account. $contentService = craft()->content; $originalFieldContext = $contentService->fieldContext; $originalFieldColumnPrefix = $contentService->fieldColumnPrefix; $contentService->fieldContext = StringHelper::randomString(10); $contentService->fieldColumnPrefix = 'field_'; foreach ($blockType->getFields() as $field) { craft()->fields->validateField($field); // Make sure the block type handle + field handle combo is unique for the whole field. This prevents us from // worrying about content column conflicts like "a" + "b_c" == "a_b" + "c". if ($field->hasErrors()) { $blockType->hasFieldErrors = true; $validates = false; $blockType->addErrors($field->getErrors()); } if ($field->hasSettingErrors()) { $blockType->hasFieldErrors = true; $validates = false; $blockType->addErrors($field->getSettingErrors()); } // Special-case for validating child Matrix fields if ($field->type == 'Matrix') { $fieldType = $field->getFieldType(); $matrixBlockTypes = $fieldType->getSettings()->getBlockTypes(); foreach ($matrixBlockTypes as $matrixBlockType) { if ($matrixBlockType->hasFieldErrors) { $blockType->hasFieldErrors = true; $validates = false; // Store a generic error for our parent Super Table field to show a nested error exists $field->addErrors(array('field' => 'general')); } } } } $contentService->fieldContext = $originalFieldContext; $contentService->fieldColumnPrefix = $originalFieldColumnPrefix; return $validates; }
/** * Returns a resource URL. * * @param string $path * @param array|string|null $params * @param string|null $protocol The protocol to use (e.g. http, https). If empty, the protocol used for the * current request will be used. * * @return string */ public static function getResourceUrl($path = '', $params = null, $protocol = '') { $path = trim($path, '/'); if ($path) { // If we've served this resource before, we should have a cached copy of the server path already. Use that // to get its timestamp, and add timestamp to the resource URL so ResourcesService sends it with // a Pragma: Cache header. $dateParam = craft()->resources->dateParam; if (!isset($params[$dateParam])) { $realPath = craft()->resources->getCachedResourcePath($path); if ($realPath) { if (!is_array($params)) { $params = array($params); } $timeModified = IOHelper::getLastTimeModified($realPath); $params[$dateParam] = $timeModified->getTimestamp(); } else { // Just set a random query string param on there, so even if the browser decides to cache it, // the next time this happens, the cache won't be used. // Use a consistent param for all resource requests with uncached paths, in case the same resource // URL is requested multiple times in the same request if (!isset(static::$_x)) { static::$_x = StringHelper::randomString(9); } $params['x'] = static::$_x; } } } return static::getUrl(craft()->config->getResourceTrigger() . '/' . $path, $params, $protocol); }
/** * Returns the editor HTML for a given element. * * @param BaseElementModel $element * @param bool $includeLocales * * @throws HttpException * @return null */ private function _returnEditorHtml(BaseElementModel $element, $includeLocales) { $localeIds = ElementHelper::getEditableLocaleIdsForElement($element); if (!$localeIds) { throw new HttpException(403); } if ($includeLocales) { if (count($localeIds) > 1) { $response['locales'] = array(); foreach ($localeIds as $localeId) { $locale = craft()->i18n->getLocaleById($localeId); $response['locales'][] = array('id' => $localeId, 'name' => $locale->getName()); } } else { $response['locales'] = null; } } $response['locale'] = $element->locale; $elementType = craft()->elements->getElementType($element->elementType); $namespace = 'editor_' . StringHelper::randomString(10); craft()->templates->setNamespace($namespace); $response['html'] = '<input type="hidden" name="namespace" value="' . $namespace . '">'; if ($element->id) { $response['html'] .= '<input type="hidden" name="elementId" value="' . $element->id . '">'; } if ($element->locale) { $response['html'] .= '<input type="hidden" name="locale" value="' . $element->locale . '">'; } $response['html'] .= '<div class="meta">' . craft()->templates->namespaceInputs($elementType->getEditorHtml($element)) . '</div>'; $response['headHtml'] = craft()->templates->getHeadHtml(); $response['footHtml'] = craft()->templates->getFootHtml(); $this->returnJson($response); }
/** * Replaces textarea contents with a marker. * * @param array $matches * * @return string */ private function _createTextareaMarker($matches) { $marker = '{marker:' . StringHelper::randomString() . '}'; $this->_textareaMarkers[$marker] = $matches[2]; return $matches[1] . $marker . $matches[3]; }
/** * Display a form. * * @param AmForms_FormModel $form * * @return string */ public function displayForm(AmForms_FormModel $form) { // Get submission model $submission = craft()->amForms_submissions->getActiveSubmission($form); // Set namespace $namespace = 'form_' . StringHelper::randomString(10); craft()->templates->setNamespace($namespace); // Build field HTML $tabs = array(); $supportedFields = craft()->amForms_fields->getSupportedFieldTypes(); $fieldTemplateInfo = craft()->amForms->getDisplayTemplateInfo('field', $form->fieldTemplate); $templatePath = $fieldTemplateInfo['path']; // Get the current templates path so we can restore it at the end of this function $siteTemplatesPath = method_exists(craft()->templates, 'getTemplatesPath') ? craft()->templates->getTemplatesPath() : craft()->path->getTemplatesPath(); $pluginTemplatePath = craft()->path->getPluginsPath() . 'amforms/templates/_display/templates/'; foreach ($form->getFieldLayout()->getTabs() as $tab) { // Tab information $tabs[$tab->id] = array('info' => $tab, 'fields' => array()); // Tab fields $fields = $tab->getFields(); foreach ($fields as $layoutField) { // Get actual field $field = $layoutField->getField(); if (!in_array($field->type, $supportedFields)) { // We don't display unsupported fields continue; } // Reset templates path for input and get field input method_exists(craft()->templates, 'setTemplatesPath') ? craft()->templates->setTemplatesPath($pluginTemplatePath) : craft()->path->setTemplatesPath($pluginTemplatePath); $fieldInfo = craft()->fields->populateFieldType($field, $submission); craft()->templates->getTwig(null, array('safe_mode' => false))->addGlobal('required', $layoutField->required); $input = $fieldInfo->getInputHtml($field->handle, $submission->getFieldValue($field->handle)); craft()->templates->getTwig(null, array('safe_mode' => false))->addGlobal('required', null); // Get field HTML method_exists(craft()->templates, 'setTemplatesPath') ? craft()->templates->setTemplatesPath($fieldTemplateInfo['path']) : craft()->path->setTemplatesPath($fieldTemplateInfo['path']); $fieldHtml = craft()->templates->render($fieldTemplateInfo['template'], array('form' => $form, 'field' => $field, 'input' => $input, 'required' => $layoutField->required, 'element' => $submission, 'namespace' => $namespace)); $fieldHtml = craft()->templates->namespaceInputs($fieldHtml); // Add to tabs $tabs[$tab->id]['fields'][] = $fieldHtml; } } // Restore the templates path variable to it's original value method_exists(craft()->templates, 'setTemplatesPath') ? craft()->templates->setTemplatesPath($siteTemplatesPath) : craft()->path->setTemplatesPath($siteTemplatesPath); // Build tab HTML $variables = array('form' => $form, 'tabs' => $tabs, 'element' => $submission); $bodyHtml = craft()->amForms->renderDisplayTemplate('tab', $form->tabTemplate, $variables); // Use AntiSpam? $antispamHtml = craft()->amForms_antispam->render(); // Use reCAPTCHA? $recaptchaHtml = craft()->amForms_recaptcha->render(); // Build our complete form $variables = array('form' => $form, 'body' => $bodyHtml, 'antispam' => $antispamHtml, 'recaptcha' => $recaptchaHtml, 'element' => $submission, 'namespace' => $namespace); $formHtml = craft()->amForms->renderDisplayTemplate('form', $form->formTemplate, $variables); // Reset namespace craft()->templates->setNamespace(null); // Parse form return new \Twig_Markup($formHtml, craft()->templates->getTwig()->getCharset()); }
/** * Validates a block type. * * If the block type doesn’t validate, any validation errors will be stored on the block type. * * @param MatrixBlockTypeModel $blockType The block type. * @param bool $validateUniques Whether the Name and Handle attributes should be validated to * ensure they’re unique. Defaults to `true`. * * @return bool Whether the block type validated. */ public function validateBlockType(MatrixBlockTypeModel $blockType, $validateUniques = true) { $validates = true; $blockTypeRecord = $this->_getBlockTypeRecord($blockType); $blockTypeRecord->fieldId = $blockType->fieldId; $blockTypeRecord->name = $blockType->name; $blockTypeRecord->handle = $blockType->handle; $blockTypeRecord->validateUniques = $validateUniques; if (!$blockTypeRecord->validate()) { $validates = false; $blockType->addErrors($blockTypeRecord->getErrors()); } $blockTypeRecord->validateUniques = true; // Can't validate multiple new rows at once so we'll need to give these temporary context to avoid false unique // handle validation errors, and just validate those manually. Also apply the future fieldColumnPrefix so that // field handle validation takes its length into account. $contentService = craft()->content; $originalFieldContext = $contentService->fieldContext; $originalFieldColumnPrefix = $contentService->fieldColumnPrefix; $contentService->fieldContext = StringHelper::randomString(10); $contentService->fieldColumnPrefix = 'field_' . $blockType->handle . '_'; foreach ($blockType->getFields() as $field) { // Hack to allow blank field names if (!$field->name) { $field->name = '__blank__'; } craft()->fields->validateField($field); // Make sure the block type handle + field handle combo is unique for the whole field. This prevents us from // worrying about content column conflicts like "a" + "b_c" == "a_b" + "c". if ($blockType->handle && $field->handle) { $blockTypeAndFieldHandle = $blockType->handle . '_' . $field->handle; if (in_array($blockTypeAndFieldHandle, $this->_uniqueBlockTypeAndFieldHandles)) { // This error *might* not be entirely accurate, but it's such an edge case that it's probably better // for the error to be worded for the common problem (two duplicate handles within the same block // type). $error = Craft::t('{attribute} "{value}" has already been taken.', array('attribute' => Craft::t('Handle'), 'value' => $field->handle)); $field->addError('handle', $error); } else { $this->_uniqueBlockTypeAndFieldHandles[] = $blockTypeAndFieldHandle; } } if ($field->hasErrors() || $field->hasSettingErrors()) { $blockType->hasFieldErrors = true; $validates = false; } } $contentService->fieldContext = $originalFieldContext; $contentService->fieldColumnPrefix = $originalFieldColumnPrefix; return $validates; }
/** * @inheritDoc IFieldType::modifyElementsQuery() * * @param DbCommand $query * @param mixed $value * * @return null|false */ public function modifyElementsQuery(DbCommand $query, $value) { if ($value == 'not :empty:') { $value = ':notempty:'; } if ($value == ':notempty:' || $value == ':empty:') { $alias = 'relations_' . $this->model->handle; $operator = $value == ':notempty:' ? '!=' : '='; $paramHandle = ':fieldId' . StringHelper::randomString(8); $query->andWhere("(select count({$alias}.id) from {{relations}} {$alias} where {$alias}.sourceId = elements.id and {$alias}.fieldId = {$paramHandle}) {$operator} 0", array($paramHandle => $this->model->id)); } else { if ($value !== null) { return false; } } }
/** * Returns whether a given URL format has a proper {slug} tag. * * @param string $urlFormat * * @return bool */ public static function doesUrlFormatHaveSlugTag($urlFormat) { $element = (object) array('slug' => StringHelper::randomString()); $uri = craft()->templates->renderObjectTemplate($urlFormat, $element); return strpos($uri, $element->slug) !== false; }
/** * @inheritDoc IFieldType::getStaticHtml() * * @param mixed $value * * @return string */ public function getStaticHtml($value) { return $this->_getInputHtml(StringHelper::randomString(), $value, true); }
/** * Builds the HTML for the non-editable input field. * * @param array $value * @return string */ public function getStaticHtml($value) { if ($value) { $settings = $this->getSettings(); $field = $settings->getField(); $translatable = $field ? (bool) $field->translatable : false; $id = StringHelper::randomString(); $html = craft()->templates->render('neo/_fieldtype/input', ['id' => $id, 'name' => $id, 'field' => $field, 'blockTypes' => $settings->getBlockTypes(), 'blocks' => $value, 'static' => true, 'translatable' => $translatable]); $this->_prepareInputHtml($id, $id, $settings, $value, true); return $html; } else { return '<p class="light">' . Craft::t("No blocks.") . '</p>'; } }
public function create($makeDefault = true, $extraData = array()) { if (!is_bool($makeDefault)) { $makeDefault = true; } $settings = craft()->plugins->getPlugin('shortlist')->getSettings(); $listModel = new Shortlist_ListModel(); $listModel->shareSlug = strtolower(StringHelper::randomString(18)); $listModel->ownerId = $this->user->id; $listModel->ownerType = $this->user->type; // Assign the extra data if possible $assignable = array('listTitle' => 'title', 'listSlug' => 'slug'); $extra = array(); $extra['title'] = $settings->defaultListTitle; foreach ($assignable as $key => $val) { if (isset($extraData[$key]) && $extraData[$key] != '') { $extra[$val] = $extraData[$key]; } } $listModel->setContent($extra); if ($listModel->validate()) { // Create the element if (craft()->elements->saveElement($listModel, false)) { $record = new Shortlist_ListRecord(); $record->setAttributes($listModel->getAttributes()); $record->id = $listModel->id; $record->insert(); } else { $listModel->addError('general', 'There was a problem creating the list'); } craft()->search->indexElementAttributes($listModel); if ($makeDefault) { // We need to unset all other lists for this to be valid $this->makeDefault($listModel->id); } return $listModel; } else { $listModel->addError('general', 'There was a problem with creating the list'); return false; } return null; }
/** * @inheritDoc ISavableComponentType::getSettingsHtml() * * @return string */ public function getSettingsHtml() { craft()->templates->includeJsResource('analytics/js/Analytics.js'); craft()->templates->includeJsResource('analytics/js/ReportWidgetSettings.js'); craft()->templates->includeCssResource('analytics/css/ReportWidgetSettings.css'); $id = 'analytics-settings-' . StringHelper::randomString(); $namespaceId = craft()->templates->namespaceInputId($id); craft()->templates->includeJs("new Analytics.ReportWidgetSettings('" . $namespaceId . "');"); $settings = $this->getSettings(); // select options $chartTypes = ['area', 'counter', 'pie', 'table', 'geo']; $selectOptions = []; foreach ($chartTypes as $chartType) { $selectOptions[$chartType] = $this->_getOptions($chartType); } return craft()->templates->render('analytics/_components/widgets/Report/settings', array('id' => $id, 'settings' => $settings, 'selectOptions' => $selectOptions)); }
/** * Parses a string for element [reference tags](http://buildwithcraft.com/docs/reference-tags). * * @param string $str The string to parse. * * @return string The parsed string. */ public function parseRefs($str) { if (strpos($str, '{') !== false) { global $refTagsByElementType; $refTagsByElementType = array(); $str = preg_replace_callback('/\\{(\\w+)\\:([^\\:\\}]+)(?:\\:([^\\:\\}]+))?\\}/', function ($matches) { global $refTagsByElementType; $elementTypeHandle = ucfirst($matches[1]); $token = '{' . StringHelper::randomString(9) . '}'; $refTagsByElementType[$elementTypeHandle][] = array('token' => $token, 'matches' => $matches); return $token; }, $str); if ($refTagsByElementType) { $search = array(); $replace = array(); $things = array('id', 'ref'); foreach ($refTagsByElementType as $elementTypeHandle => $refTags) { $elementType = craft()->elements->getElementType($elementTypeHandle); if (!$elementType) { // Just put the ref tags back the way they were foreach ($refTags as $refTag) { $search[] = $refTag['token']; $replace[] = $refTag['matches'][0]; } } else { $refTagsById = array(); $refTagsByRef = array(); foreach ($refTags as $refTag) { // Searching by ID? if (is_numeric($refTag['matches'][2])) { $refTagsById[$refTag['matches'][2]][] = $refTag; } else { $refTagsByRef[$refTag['matches'][2]][] = $refTag; } } // Things are about to get silly... foreach ($things as $thing) { $refTagsByThing = ${'refTagsBy' . ucfirst($thing)}; if ($refTagsByThing) { $criteria = craft()->elements->getCriteria($elementTypeHandle); $criteria->status = null; $criteria->{$thing} = array_keys($refTagsByThing); $elements = $criteria->find(); $elementsByThing = array(); foreach ($elements as $element) { $elementsByThing[$element->{$thing}] = $element; } foreach ($refTagsByThing as $thingVal => $refTags) { if (isset($elementsByThing[$thingVal])) { $element = $elementsByThing[$thingVal]; } else { $element = false; } foreach ($refTags as $refTag) { $search[] = $refTag['token']; if ($element) { if (!empty($refTag['matches'][3]) && isset($element->{$refTag['matches'][3]})) { $value = (string) $element->{$refTag['matches'][3]}; $replace[] = $this->parseRefs($value); } else { // Default to the URL $replace[] = $element->getUrl(); } } else { $replace[] = $refTag['matches'][0]; } } } } } } } $str = str_replace($search, $replace, $str); } unset($refTagsByElementType); } return $str; }
/** * Adds support for array('column' => 'value') conditional syntax. Supports nested conditionals, e.g. * array('or', array('column' => 'value'), array('column2' => 'value2')) * * @param mixed $conditions * @param array &$params * * @return mixed */ private function _normalizeConditions($conditions, &$params = array()) { if (!is_array($conditions)) { return $conditions; } else { if ($conditions === array()) { return ''; } } $normalizedConditions = array(); // Find any key/value pairs and convert them to the CDbCommand's conditional syntax foreach ($conditions as $key => $value) { if (!is_numeric($key)) { $param = ':p' . StringHelper::randomString(9); $normalizedConditions[] = $this->getConnection()->quoteColumnName($key) . '=' . $param; $params[$param] = $value; unset($conditions[$key]); } else { $conditions[$key] = $this->_normalizeConditions($value, $params); } } if ($normalizedConditions) { // Were there normal conditions in there as well? if ($conditions) { // Is this already an AND conditional? if (StringHelper::toLowerCase($conditions[0]) == 'and') { // Just merge our normalized conditions into the $conditions $conditions = array_merge($conditions, $normalizedConditions); } else { // Append the normalized conditions as nested AND conditions array_unshift($normalizedConditions, 'and'); $conditions[] = $normalizedConditions; } } else { if (count($normalizedConditions) == 1) { $conditions = $normalizedConditions[0]; } else { array_unshift($normalizedConditions, 'and'); $conditions = $normalizedConditions; } } } return $conditions; }
/** * Generates a random string of a given length. * * @param int $length * @param bool $extendedChars * * @return string */ public function randomString($length = 36, $extendedChars = false) { return StringHelper::randomString($length, $extendedChars); }
/** * Returns static HTML for the field's value. * * @param mixed $value * * @return string */ public function getStaticHtml($value) { // Just return the input HTML with disabled inputs by default craft()->templates->startJsBuffer(); $inputHtml = $this->getInputHtml(StringHelper::randomString(), $value); $inputHtml = preg_replace('/<(?:input|textarea|select)\\s[^>]*/i', '$0 disabled', $inputHtml); craft()->templates->clearJsBuffer(); return $inputHtml; }
/** * Parses a date param value to a DbCommand where condition. * * @param string $key * @param string $operator * @param string|array|DateTime $dates * @param array &$params * @return mixed */ public static function parseDateParam($key, $operator, $dates, &$params) { $conditions = array(); $dates = ArrayHelper::stringToArray($dates); foreach ($dates as $date) { if (!$date instanceof \DateTime) { $date = DateTime::createFromString($date, Craft::getTimezone()); } $param = ':p' . StringHelper::randomString(9); $params[$param] = DateTimeHelper::formatTimeForDb($date->getTimestamp()); $conditions[] = $key . $operator . $param; } if (count($conditions) == 1) { return $conditions[0]; } else { array_unshift($conditions, 'or'); return $conditions; } }
/** * @inheritDoc BaseFieldType::getStaticHtml() * * @param mixed $value * * @return string */ public function getStaticHtml($value) { if ($value) { $settings = $this->getSettings(); $id = StringHelper::randomString(); return craft()->templates->render('_components/fieldtypes/Matrix/input', array('id' => $id, 'name' => $id, 'blockTypes' => $settings->getBlockTypes(), 'blocks' => $value, 'static' => true)); } else { return '<p class="light">' . Craft::t('No blocks.') . '</p>'; } }
/** * Parses a string for element [reference tags](http://craftcms.com/docs/reference-tags). * * @param string $str The string to parse. * * @return string The parsed string. */ public function parseRefs($str) { if (strpos($str, '{') !== false) { global $refTagsByElementType; $refTagsByElementType = array(); $str = preg_replace_callback('/\\{(\\w+)\\:([^\\:\\}]+)(?:\\:([^\\:\\}]+))?\\}/', function ($matches) { global $refTagsByElementType; if (strpos($matches[1], '_') === false) { $elementTypeHandle = ucfirst($matches[1]); } else { $elementTypeHandle = preg_replace_callback('/^\\w|_\\w/', function ($matches) { return strtoupper($matches[0]); }, $matches[1]); } $token = '{' . StringHelper::randomString(9) . '}'; $refTagsByElementType[$elementTypeHandle][] = array('token' => $token, 'matches' => $matches); return $token; }, $str); if ($refTagsByElementType) { $search = array(); $replace = array(); $things = array('id', 'ref'); foreach ($refTagsByElementType as $elementTypeHandle => $refTags) { $elementType = craft()->elements->getElementType($elementTypeHandle); if (!$elementType) { // Just put the ref tags back the way they were foreach ($refTags as $refTag) { $search[] = $refTag['token']; $replace[] = $refTag['matches'][0]; } } else { $refTagsById = array(); $refTagsByRef = array(); foreach ($refTags as $refTag) { // Searching by ID? if (is_numeric($refTag['matches'][2])) { $refTagsById[$refTag['matches'][2]][] = $refTag; } else { $refTagsByRef[$refTag['matches'][2]][] = $refTag; } } // Things are about to get silly... foreach ($things as $thing) { $refTagsByThing = ${'refTagsBy' . ucfirst($thing)}; if ($refTagsByThing) { $criteria = craft()->elements->getCriteria($elementTypeHandle); $criteria->status = null; $criteria->limit = null; $criteria->{$thing} = array_keys($refTagsByThing); $elements = $criteria->find(); $elementsByThing = array(); foreach ($elements as $element) { $elementsByThing[$element->{$thing}] = $element; } foreach ($refTagsByThing as $thingVal => $refTags) { if (isset($elementsByThing[$thingVal])) { $element = $elementsByThing[$thingVal]; } else { $element = false; } foreach ($refTags as $refTag) { $search[] = $refTag['token']; if ($element) { if (!empty($refTag['matches'][3]) && isset($element->{$refTag['matches'][3]})) { try { $value = $element->{$refTag['matches'][3]}; if (is_object($value) && !method_exists($value, '__toString')) { throw new Exception('Object of class ' . get_class($value) . ' could not be converted to string'); } $replace[] = $this->parseRefs((string) $value); } catch (\Exception $e) { // Log it Craft::log('An exception was thrown when parsing the ref tag "' . $refTag['matches'][0] . "\":\n" . $e->getMessage(), LogLevel::Error); // Replace the token with the original ref tag $replace[] = $refTag['matches'][0]; } } else { // Default to the URL $replace[] = $element->getUrl(); } } else { $replace[] = $refTag['matches'][0]; } } } } } } } $str = str_replace($search, $replace, $str); } unset($refTagsByElementType); } return $str; }