/** * Fetch the options for a certain property. * * @param EnvironmentInterface $environment The environment. * * @param ModelInterface $model The model. * * @param PropertyInterface $property The property. * * @return array */ protected function getOptions($environment, $model, $property) { $options = $property->getOptions(); $event = new GetPropertyOptionsEvent($environment, $model); $event->setPropertyName($property->getName()); $event->setOptions($options); $environment->getEventPropagator()->propagate($event::NAME, $event, $environment->getDataDefinition()->getName(), $property->getName()); if ($event->getOptions() !== $options) { $options = $event->getOptions(); } return $options; }
/** * Calculate the label of a property to se in "show" view. * * @param PropertyInterface $property The property for which the label shall be calculated. * * @return string */ protected function getPropertyLabel(PropertyInterface $property) { $environment = $this->getEnvironment(); $definition = $environment->getDataDefinition(); $label = $environment->getTranslator()->translate($property->getLabel(), $definition->getName()); if (!$label) { $label = $environment->getTranslator()->translate('MSC.' . $property->getName()); } if (is_array($label)) { $label = $label[0]; } if (!$label) { $label = $property->getName(); } return $label; }
/** * Append wizard icons. * * @param PropertyInterface $propInfo The property for which the wizards shall be generated. * * @param EnvironmentInterface $environment The environment. * * @return string * * @SuppressWarnings(PHPMD.Superglobals) * @SuppressWarnings(PHPMD.CamelCaseVariableName) */ public static function getWizard($propInfo, EnvironmentInterface $environment) { $wizard = ''; $dispatcher = $environment->getEventDispatcher(); $translator = $environment->getTranslator(); $propExtra = $propInfo->getExtra(); $assetsPath = 'assets/mootools/colorpicker/' . $GLOBALS['TL_ASSETS']['COLORPICKER'] . '/images/'; if (array_key_exists('colorpicker', $propExtra) && $propExtra['colorpicker']) { $pickerText = $translator->translate('colorpicker', 'MSC'); $event = new GenerateHtmlEvent('pickcolor.gif', $pickerText, sprintf('style="%s" title="%s" id="moo_%s"', 'vertical-align:top;cursor:pointer', specialchars($pickerText), $propInfo->getName())); $dispatcher->dispatch(ContaoEvents::IMAGE_GET_HTML, $event); // Support single fields as well (see contao/core#5240) $strKey = $propExtra['multiple'] ? $propInfo->getName() . '_0' : $propInfo->getName(); $wizard .= sprintf(' %1$s <script>var cl;window.addEvent("domready", function() { new MooRainbow("moo_%2$s", {' . 'id: "ctrl_%3$s", startColor: ((cl = $("ctrl_%3$s").value.hexToRgb(true)) ? cl : [255, 0, 0]),' . 'imgPath: "%4$s", onComplete: function(color) {$("ctrl_%3$s").value = color.hex.replace("#", "");}});' . '});</script>', $event->getHtml(), $propInfo->getName(), $strKey, $assetsPath); } return $wizard; }
/** * Fetch the options for a certain property. * * @param EnvironmentInterface $environment The environment. * * @param ModelInterface $model The model. * * @param PropertyInterface $property The property. * * @return array */ protected static function getOptions($environment, $model, $property) { $options = $property->getOptions(); $event = new GetPropertyOptionsEvent($environment, $model); $event->setPropertyName($property->getName()); $event->setOptions($options); $environment->getEventDispatcher()->dispatch(sprintf('%s', $event::NAME), $event); if ($event->getOptions() !== $options) { $options = $event->getOptions(); } return $options; }
/** * Handle a property in a cloned model. * * @param ModelInterface $model The cloned model. * * @param PropertyInterface $property The property to handle. * * @param DataProviderInterface $dataProvider The data provider the model originates from. * * @return void */ private function handleClonedModelProperty(ModelInterface $model, PropertyInterface $property, DataProviderInterface $dataProvider) { $extra = $property->getExtra(); $propName = $property->getName(); // Check doNotCopy. if (isset($extra['doNotCopy']) && $extra['doNotCopy'] === true) { $model->setProperty($propName, null); return; } // Check uniqueness. if (isset($extra['unique']) && $extra['unique'] === true && !$dataProvider->isUniqueValue($propName, $model->getProperty($propName))) { // Implicit "do not copy" unique values, they cannot be unique anymore. $model->setProperty($propName, null); } }
/** * Parse the label of a single property. * * @param PropertyInterface $property The property to parse the label for. * * @param string|array $label The label value. * * @return void */ protected function parseSinglePropertyLabel(PropertyInterface $property, $label) { if (!$property->getLabel()) { if (is_array($label)) { $lang = $label; $label = reset($lang); $description = next($lang); $property->setDescription($description); } $property->setLabel($label); } }
/** * Build a widget for a given property. * * @param PropertyInterface $property The property. * * @param ModelInterface $model The current model. * * @return \Widget * * @throws DcGeneralRuntimeException When not running in TL_MODE BE. * * @SuppressWarnings(PHPMD.Superglobals) * @SuppressWarnings(PHPMD.CamelCaseVariableName) */ public function buildWidget(PropertyInterface $property, ModelInterface $model) { if (TL_MODE !== 'BE') { throw new DcGeneralRuntimeException(sprintf('WidgetBuilder only supports TL_MODE "BE". Running in TL_MODE "%s".', TL_MODE)); } $environment = $this->getEnvironment(); $dispatcher = $environment->getEventDispatcher(); $propertyName = $property->getName(); $propExtra = $property->getExtra(); $defName = $environment->getDataDefinition()->getName(); $strClass = $this->getWidgetClass($property); $event = new DecodePropertyValueForWidgetEvent($environment, $model); $event->setProperty($propertyName)->setValue($model->getProperty($propertyName)); $dispatcher->dispatch($event::NAME, $event); $varValue = $event->getValue(); if (isset($propExtra['rgxp']) && in_array($propExtra['rgxp'], array('date', 'time', 'datim')) && empty($propExtra['mandatory']) && is_numeric($varValue) && $varValue == 0) { $varValue = ''; } $propExtra['required'] = $varValue == '' && !empty($propExtra['mandatory']); $arrConfig = array('inputType' => $property->getWidgetType(), 'label' => array($property->getLabel(), $property->getDescription()), 'options' => $this->getOptionsForWidget($property, $model), 'eval' => $propExtra); if (isset($propExtra['reference'])) { $arrConfig['reference'] = $propExtra['reference']; } $event = new GetAttributesFromDcaEvent($arrConfig, $property->getName(), $varValue, $propertyName, $defName, new DcCompat($environment, $model, $propertyName)); $dispatcher->dispatch(ContaoEvents::WIDGET_GET_ATTRIBUTES_FROM_DCA, $event); $arrPrepared = $event->getResult(); if ($arrConfig['inputType'] == 'checkbox' && isset($GLOBALS['TL_DCA'][$defName]['subpalettes']) && is_array($GLOBALS['TL_DCA'][$defName]['subpalettes']) && in_array($propertyName, array_keys($GLOBALS['TL_DCA'][$defName]['subpalettes'])) && $arrConfig['eval']['submitOnChange']) { // We have to override the onclick, do not append to it as Contao adds it's own code here in // \Widget::getAttributesFromDca() which kills our sub palette handling! $arrPrepared['onclick'] = "Backend.autoSubmit('" . $defName . "');"; } $objWidget = new $strClass($arrPrepared, new DcCompat($environment, $model, $propertyName)); // OH: what is this? source: DataContainer 232. $objWidget->currentRecord = $model->getId(); $objWidget->xlabel .= $this->getXLabel($property); $event = new ManipulateWidgetEvent($environment, $model, $property, $objWidget); $dispatcher->dispatch(ManipulateWidgetEvent::NAME, $event); return $objWidget; }
/** * Get special labels. * * @param PropertyInterface $propInfo The property for which the X label shall be generated. * * @return string */ protected function getXLabel($propInfo) { $strXLabel = ''; $environment = $this->getEnvironment(); $defName = $environment->getDataDefinition()->getName(); $translator = $environment->getTranslator(); // Toggle line wrap (textarea). if ($propInfo->getWidgetType() === 'textarea' && !array_key_exists('rte', $propInfo->getExtra())) { $event = new GenerateHtmlEvent('wrap.gif', $translator->translate('wordWrap', 'MSC'), sprintf('title="%s" class="toggleWrap" onclick="Backend.toggleWrap(\'ctrl_%s\');"', specialchars($translator->translate('wordWrap', 'MSC')), $propInfo->getName())); $environment->getEventPropagator()->propagate(ContaoEvents::IMAGE_GET_HTML, $event); $strXLabel .= ' ' . $event->getHtml(); } // Add the help wizard. if ($propInfo->getExtra() && array_key_exists('helpwizard', $propInfo->getExtra())) { $event = new GenerateHtmlEvent('about.gif', $translator->translate('helpWizard', 'MSC'), 'style="vertical-align:text-bottom;"'); $environment->getEventPropagator()->propagate(ContaoEvents::IMAGE_GET_HTML, $event); $strXLabel .= sprintf(' <a href="contao/help.php?table=%s&field=%s" title="%s" onclick="Backend.openWindow(this, 600, 500); return false;">%s</a>', $defName, $propInfo->getName(), specialchars($translator->translate('helpWizard', 'MSC')), $event->getHtml()); } // Add the popup file manager. if ($propInfo->getWidgetType() === 'fileTree') { // In Contao 3 it is always a file picker - no need for the button. if (version_compare(VERSION, '3.0', '<')) { $event = new GenerateHtmlEvent('filemanager.gif', $translator->translate('fileManager', 'MSC'), 'style="vertical-align:text-bottom;"'); $environment->getEventPropagator()->propagate(ContaoEvents::IMAGE_GET_HTML, $event); $strXLabel .= sprintf(' <a href="contao/files.php" title="%s" onclick="Backend.getScrollOffset(); Backend.openWindow(this, 750, 500); return false;">%s</a>', specialchars($translator->translate('fileManager', 'MSC')), $event->getHtml()); } } elseif ($propInfo->getWidgetType() === 'tableWizard') { $urlEvent = new AddToUrlEvent('key=table'); $importTableEvent = new GenerateHtmlEvent('tablewizard.gif', $translator->translate('importTable.0', $defName), 'style="vertical-align:text-bottom;"'); $shrinkEvent = new GenerateHtmlEvent('demagnify.gif', $translator->translate('shrink.0', $defName), sprintf('title="%s" style="vertical-align:text-bottom; cursor:pointer;" onclick="Backend.tableWizardResize(0.9);"', specialchars($translator->translate('shrink.1', $defName)))); $expandEvent = new GenerateHtmlEvent('magnify.gif', $translator->translate('expand.0', $defName), sprintf('title="%s" style="vertical-align:text-bottom; cursor:pointer;" onclick="Backend.tableWizardResize(1.1);"', specialchars($translator->translate('expand.1', $defName)))); $environment->getEventPropagator()->propagate(ContaoEvents::BACKEND_ADD_TO_URL, $urlEvent); $environment->getEventPropagator()->propagate(ContaoEvents::IMAGE_GET_HTML, $importTableEvent); $environment->getEventPropagator()->propagate(ContaoEvents::IMAGE_GET_HTML, $shrinkEvent); $environment->getEventPropagator()->propagate(ContaoEvents::IMAGE_GET_HTML, $expandEvent); $strXLabel .= sprintf(' <a href="%s" title="%s" onclick="Backend.getScrollOffset();">%s</a> %s%s', ampersand($urlEvent->getUrl()), specialchars($translator->translate('importTable.1', $defName)), $importTableEvent->getHtml(), $shrinkEvent->getHtml(), $expandEvent->getHtml()); } elseif ($propInfo->getWidgetType() === 'listWizard') { $urlEvent = new AddToUrlEvent('key=list'); $importListEvent = new GenerateHtmlEvent('tablewizard.gif', $translator->translate('importList.0', $defName), 'style="vertical-align:text-bottom;"'); $environment->getEventPropagator()->propagate(ContaoEvents::BACKEND_ADD_TO_URL, $urlEvent); $environment->getEventPropagator()->propagate(ContaoEvents::IMAGE_GET_HTML, $importListEvent); $strXLabel .= sprintf(' <a href="%s" title="%s" onclick="Backend.getScrollOffset();">%s</a>', ampersand($urlEvent->getUrl()), specialchars($translator->translate('importList.1', $defName)), $importListEvent->getHtml()); } return $strXLabel; }
/** * Evaluate the contao 2 sorting flag into grouping length. * * @param ListingConfigInterface|PropertyInterface $config The property to evaluate the flag for. * * @param int $flag The flag to be evaluated. * * @return void */ protected function evalFlagGroupingLength($config, $flag) { if ($flag == 1 || $flag == 2) { $config->setGroupingLength(1); } elseif ($flag == 3 || $flag == 4) { $config->setGroupingLength(2); } }
/** * Create a widget for naming contexts. Use the language and translation information from the MetaModel. * * @param EnvironmentInterface $environment The environment. * * @param PropertyInterface $property The property. * * @param IMetaModel $metaModel The MetaModel. * * @param string $languageLabel The label to use for the language indicator. * * @param string $valueLabel The label to use for the input field. * * @param bool $isTextArea If true, the widget will become a textarea, false otherwise. * * @param array $arrValues The values for the widget, needed to highlight the fallback language. * * @return void */ public static function prepareLanguageAwareWidget(EnvironmentInterface $environment, PropertyInterface $property, IMetaModel $metaModel, $languageLabel, $valueLabel, $isTextArea, $arrValues) { if (!$metaModel->isTranslated()) { $extra = $property->getExtra(); $extra['tl_class'] .= 'w50'; $property->setWidgetType('text')->setExtra($extra); return; } $fallback = $metaModel->getFallbackLanguage(); $languages = self::buildLanguageArray($metaModel, $environment->getTranslator()); $neededKeys = array_keys($languages); // Ensure we have values for all languages present. if (array_diff_key(array_keys($arrValues), $neededKeys)) { foreach ($neededKeys as $langCode) { $arrValues[$langCode] = ''; } } $rowClasses = array(); foreach (array_keys($arrValues) as $langCode) { $rowClasses[] = $langCode == $fallback ? 'fallback_language' : 'normal_language'; } $extra = $property->getExtra(); $extra['minCount'] = $extra['maxCount'] = count($languages); $extra['disableSorting'] = true; $extra['tl_class'] = 'clr'; $extra['columnFields'] = array('langcode' => array('label' => $languageLabel, 'exclude' => true, 'inputType' => 'justtextoption', 'options' => $languages, 'eval' => array('rowClasses' => $rowClasses, 'valign' => 'center', 'style' => 'min-width:75px;display:block;')), 'value' => array('label' => $valueLabel, 'exclude' => true, 'inputType' => $isTextArea ? 'textarea' : 'text', 'eval' => array('rowClasses' => $rowClasses, 'style' => 'width:400px;', 'rows' => 3))); $property->setWidgetType('multiColumnWizard')->setExtra($extra); }
/** * Render a property option. * * @param RenderReadablePropertyValueEvent $event The event to store the value to. * @param PropertyInterface $property The property holding the options. * @param mixed $value The value to format. * * @return void */ private static function renderOptionValueReadable(RenderReadablePropertyValueEvent $event, $property, $value) { $options = $property->getOptions(); if (!$options) { $options = self::getOptions($event->getEnvironment(), $event->getModel(), $event->getProperty()); if ($options) { $property->setOptions($options); } } if (array_is_assoc($options)) { $event->setRendered($options[$value]); } }
/** * Get for a field the readable value. * * @param EnvironmentInterface $environment The environment. * * @param PropertyInterface $property The property to be rendered. * * @param ModelInterface $model The model from which the property value shall be retrieved from. * * @return mixed */ public static function getReadableFieldValue(EnvironmentInterface $environment, PropertyInterface $property, ModelInterface $model) { $event = new RenderReadablePropertyValueEvent($environment, $model, $property, $model->getProperty($property->getName())); $environment->getEventDispatcher()->dispatch($event::NAME, $event); if ($event->getRendered() !== null) { return $event->getRendered(); } return $event->getValue(); }
/** * Get for a field the readable value. * * @param PropertyInterface $property The property to be rendered. * * @param ModelInterface $model The model from which the property value shall be retrieved from. * * @param mixed $value The value for the property. * * @return mixed */ public function getReadableFieldValue(PropertyInterface $property, ModelInterface $model, $value) { $event = new RenderReadablePropertyValueEvent($this->getEnvironment(), $model, $property, $value); $this->getEnvironment()->getEventPropagator()->propagate($event::NAME, $event, array($this->getEnvironment()->getDataDefinition()->getName(), $property->getName())); if ($event->getRendered() !== null) { return $event->getRendered(); } return $value; }
/** * Build a widget for a given property. * * @param PropertyInterface $property The property. * * @param ModelInterface $model The current model. * * @return \Widget * * @throws DcGeneralRuntimeException When not running in TL_MODE BE. * * @SuppressWarnings(PHPMD.Superglobals) * @SuppressWarnings(PHPMD.CamelCaseVariableName) */ public function buildWidget(PropertyInterface $property, ModelInterface $model) { if (TL_MODE !== 'BE') { throw new DcGeneralRuntimeException(sprintf('WidgetBuilder only supports TL_MODE "BE". Running in TL_MODE "%s".', TL_MODE)); } $environment = $this->getEnvironment(); $dispatcher = $environment->getEventDispatcher(); $propertyName = $property->getName(); $propExtra = $property->getExtra(); $defName = $environment->getDataDefinition()->getName(); $strClass = $this->getWidgetClass($property); $event = new DecodePropertyValueForWidgetEvent($environment, $model); $event->setProperty($propertyName)->setValue($model->getProperty($propertyName)); $dispatcher->dispatch($event::NAME, $event); $varValue = $event->getValue(); if (isset($propExtra['rgxp']) && in_array($propExtra['rgxp'], array('date', 'time', 'datim')) && empty($propExtra['mandatory']) && is_numeric($varValue) && $varValue == 0) { /* FIXME TEMPORARY WORKAROUND! To be fixed in the core: @see \Widget::getAttributesFromDca() */ $varValue = ''; } // OH: why not $required = $mandatory always? source: DataContainer 226. // OH: the whole prepareForWidget(..) thing is an only mess // Widgets should parse the configuration by themselves, depending on what they need. $propExtra['required'] = $varValue == '' && !empty($propExtra['mandatory']); $arrConfig = array('inputType' => $property->getWidgetType(), 'label' => array($property->getLabel(), $property->getDescription()), 'options' => $this->getOptionsForWidget($property, $model), 'eval' => $propExtra); if (isset($propExtra['reference'])) { $arrConfig['reference'] = $propExtra['reference']; } $event = new GetAttributesFromDcaEvent($arrConfig, $property->getName(), $varValue, $propertyName, $defName, new DcCompat($environment, $model, $propertyName)); $dispatcher->dispatch(ContaoEvents::WIDGET_GET_ATTRIBUTES_FROM_DCA, $event); $arrPrepared = $event->getResult(); // Bugfix CS: ajax subpalettes are really broken. // Therefore we reset to the default checkbox behaviour here and submit the entire form. // This way, the javascript needed by the widget (wizards) will be correctly evaluated. if ($arrConfig['inputType'] == 'checkbox' && isset($GLOBALS['TL_DCA'][$defName]['subpalettes']) && is_array($GLOBALS['TL_DCA'][$defName]['subpalettes']) && in_array($propertyName, array_keys($GLOBALS['TL_DCA'][$defName]['subpalettes'])) && $arrConfig['eval']['submitOnChange']) { // We have to override the onclick, do not append to it as Contao adds it's own code here in // \Widget::getAttributesFromDca() which kills our sub palette handling! $arrPrepared['onclick'] = "Backend.autoSubmit('" . $defName . "');"; } $objWidget = new $strClass($arrPrepared, new DcCompat($environment, $model, $propertyName)); // OH: what is this? source: DataContainer 232. $objWidget->currentRecord = $model->getId(); $objWidget->xlabel .= $this->getXLabel($property); $event = new ManipulateWidgetEvent($environment, $model, $property, $objWidget); $dispatcher->dispatch(ManipulateWidgetEvent::NAME, $event); return $objWidget; }
/** * Get special labels. * * @param EnvironmentInterface $environment The environment. * * @param PropertyInterface $propInfo The property for which the options shall be retrieved. * * @param ModelInterface $model The model. * * @return string */ private function getOptionsForWidget(EnvironmentInterface $environment, PropertyInterface $propInfo, ModelInterface $model) { $dispatcher = $environment->getEventDispatcher(); $options = $propInfo->getOptions(); $event = new GetPropertyOptionsEvent($environment, $model); $event->setPropertyName($propInfo->getName()); $event->setOptions($options); $dispatcher->dispatch(GetPropertyOptionsEvent::NAME, $event); if ($event->getOptions() !== $options) { return $event->getOptions(); } return $options; }