/** * Create the edit mask. * * @return string * * @throws DcGeneralRuntimeException If the data container is not editable, closed. * * @throws DcGeneralInvalidArgumentException If an unknown property is encountered in the palette. */ public function execute() { $inputProvider = $this->environment->getInputProvider(); $palettesDefinition = $this->definition->getPalettesDefinition(); $isSubmitted = $inputProvider->getValue('FORM_SUBMIT') === $this->definition->getName(); $isAutoSubmit = $inputProvider->getValue('SUBMIT_TYPE') === 'auto'; $widgetManager = new WidgetManager($this->environment, $this->model); $this->dispatcher->dispatch(PreEditModelEvent::NAME, new PreEditModelEvent($this->environment, $this->model)); $this->enforceModelRelationship(); // Pass 1: Get the palette for the values stored in the model. $palette = $palettesDefinition->findPalette($this->model); $propertyValues = $this->processInput($widgetManager); if ($isSubmitted && $propertyValues) { // Pass 2: Determine the real palette we want to work on if we have some data submitted. $palette = $palettesDefinition->findPalette($this->model, $propertyValues); // Update the model - the model might add some more errors to the propertyValueBag via exceptions. $this->environment->getController()->updateModelFromPropertyBag($this->model, $propertyValues); } $fieldSets = $this->buildFieldSet($widgetManager, $palette, $propertyValues); $buttons = $this->getEditButtons(); if (!$isAutoSubmit && $isSubmitted && empty($this->errors)) { $this->doPersist(); $this->handleSubmit($buttons); } $template = new ViewTemplate('dcfe_general_edit'); $template->setData(array('fieldsets' => $fieldSets, 'subHeadline' => $this->getHeadline(), 'table' => $this->definition->getName(), 'enctype' => 'multipart/form-data', 'error' => $this->errors, 'editButtons' => $buttons)); return $template->parse(); }
/** * Create a controller instance in the environment if none has been defined yet. * * @param EnvironmentInterface $environment The environment to populate. * * @return void * * @internal */ public function populateController(EnvironmentInterface $environment) { // Already populated, get out then. if ($environment->getController()) { return; } $controller = new DefaultController(); $controller->setEnvironment($environment); $environment->setController($controller); }
/** * Retrieve the instance of a widget for the given property. * * @param string $property Name of the property for which the widget shall be retrieved. * * @param PropertyValueBag $valueBag The input values to use (optional). * * @return \Widget * * @throws DcGeneralRuntimeException When No widget could be build. * @throws DcGeneralInvalidArgumentException When property is not defined in the property definitions. */ public function getWidget($property, PropertyValueBag $valueBag = null) { $environment = $this->getEnvironment(); $dispatcher = $environment->getEventDispatcher(); $propertyDefinitions = $environment->getDataDefinition()->getPropertiesDefinition(); if (!$propertyDefinitions->hasProperty($property)) { throw new DcGeneralInvalidArgumentException('Property ' . $property . ' is not defined in propertyDefinitions.'); } $model = clone $this->model; $model->setId($this->model->getId()); if ($valueBag) { $values = new PropertyValueBag($valueBag->getArrayCopy()); $this->environment->getController()->updateModelFromPropertyBag($model, $values); } $propertyDefinition = $propertyDefinitions->getProperty($property); $event = new BuildWidgetEvent($environment, $model, $propertyDefinition); $dispatcher->dispatch(DcGeneralFrontendEvents::BUILD_WIDGET, $event); if (!$event->getWidget()) { throw new DcGeneralRuntimeException(sprintf('Widget was not build for property %s::%s.', $this->model->getProviderName(), $property)); } return $event->getWidget(); }
/** * Create a controller instance in the environment if none has been defined yet. * * @param EnvironmentInterface $environment The environment to populate. * * @return void * * @internal */ public function populateController(EnvironmentInterface $environment) { // Already populated, get out then. if ($environment->getController()) { return; } $definition = $environment->getDataDefinition(); // If we encounter an extended definition, that one may override. if (!$definition->hasDefinition(ExtendedDca::NAME)) { return; } /** @var ExtendedDca $extendedDefinition */ $extendedDefinition = $definition->getDefinition(ExtendedDca::NAME); $class = $extendedDefinition->getControllerClass(); if (!$class) { return; } $controllerClass = new \ReflectionClass($class); /** @var ControllerInterface $controller */ $controller = $controllerClass->newInstance(); $controller->setEnvironment($environment); $environment->setController($controller); }
/** * Retrieve the instance of a widget for the given property. * * @param string $property Name of the property for which the widget shall be retrieved. * * @param PropertyValueBag $inputValues The input values to use (optional). * * @throws DcGeneralInvalidArgumentException When an unknown property has been passed. * * @return \Widget */ public function getWidget($property, PropertyValueBag $inputValues = null) { $environment = $this->getEnvironment(); $defName = $environment->getDataDefinition()->getName(); $propertyDefinitions = $environment->getDataDefinition()->getPropertiesDefinition(); if (!$propertyDefinitions->hasProperty($property)) { throw new DcGeneralInvalidArgumentException('Property ' . $property . ' is not defined in propertyDefinitions.'); } $event = new BuildWidgetEvent($environment, $this->model, $propertyDefinitions->getProperty($property)); $environment->getEventPropagator()->propagate($event::NAME, $event, array($defName, $property)); if ($event->getWidget()) { return $event->getWidget(); } $propInfo = $propertyDefinitions->getProperty($property); $propExtra = $propInfo->getExtra(); $varValue = $this->decodeValue($property, $this->model->getProperty($property)); $xLabel = $this->getXLabel($propInfo); $strClass = $GLOBALS['BE_FFL'][$propInfo->getWidgetType()]; if (!class_exists($strClass)) { return null; } // FIXME TEMPORARY WORKAROUND! To be fixed in the core: Controller::prepareForWidget(..). if (in_array($propExtra['rgxp'], array('date', 'time', 'datim')) && !$propExtra['mandatory'] && is_numeric($varValue) && $varValue == 0) { $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 == '' && $propExtra['mandatory']; if ($inputValues) { $model = clone $this->model; $model->setId($this->model->getId()); $this->environment->getController()->updateModelFromPropertyBag($model, $inputValues); } else { $model = $this->model; } $options = $propInfo->getOptions(); $event = new GetPropertyOptionsEvent($environment, $model); $event->setPropertyName($property); $event->setOptions($options); $environment->getEventPropagator()->propagate($event::NAME, $event, $environment->getDataDefinition()->getName(), $property); if ($event->getOptions() !== $options) { $options = $event->getOptions(); } $arrConfig = array('inputType' => $propInfo->getWidgetType(), 'label' => array($propInfo->getLabel(), $propInfo->getDescription()), 'options' => $options, 'eval' => $propExtra); if (isset($propExtra['reference'])) { $arrConfig['reference'] = $propExtra['reference']; } $event = new GetAttributesFromDcaEvent($arrConfig, $propInfo->getName(), $varValue, $property, $defName, new DcCompat($environment, $this->model, $property)); $environment->getEventPropagator()->propagate(ContaoEvents::WIDGET_GET_ATTRIBUTES_FROM_DCA, $event, $environment->getDataDefinition()->getName(), $property); $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' && is_array($GLOBALS['TL_DCA'][$defName]['subpalettes']) && in_array($property, array_keys($GLOBALS['TL_DCA'][$defName]['subpalettes'])) && $arrConfig['eval']['submitOnChange']) { $arrPrepared['onclick'] = $arrConfig['eval']['submitOnChange'] ? "Backend.autoSubmit('" . $defName . "')" : ''; } $objWidget = new $strClass($arrPrepared); // OH: what is this? source: DataContainer 232. $objWidget->currentRecord = $this->model->getId(); $objWidget->wizard .= $xLabel; $event = new ManipulateWidgetEvent($environment, $this->model, $propInfo, $objWidget); $environment->getEventPropagator()->propagate($event::NAME, $event, array($defName, $property)); return $objWidget; }
/** * Create a new instance. * * @param EnvironmentInterface $environment The environment. */ public function __construct(EnvironmentInterface $environment) { $this->environment = $environment; $this->translator = $environment->getTranslator(); $this->eventDispatcher = $environment->getEventDispatcher(); $this->clipboardItems = $this->calculateClipboardItems(); $dataDefinition = $environment->getDataDefinition(); $basicDefinition = $dataDefinition->getBasicDefinition(); $this->isHierarchical = $basicDefinition::MODE_HIERARCHICAL === $basicDefinition->getMode(); $this->commands = $dataDefinition->getDefinition(Contao2BackendViewDefinitionInterface::NAME)->getModelCommands(); $controller = $environment->getController(); $this->clipboardModels = $controller->getModelsFromClipboardItems($this->clipboardItems); $this->circularModelIds = array(); // We must only check for CUT operation here as pasting copy'ed parents is allowed. $cutItems = array_filter($this->clipboardItems, function ($item) { /** @var ItemInterface $item */ return $item->getAction() === $item::CUT; }); $cutModels = $controller->getModelsFromClipboardItems($cutItems); foreach ($cutModels as $model) { $providerName = $model->getProviderName(); foreach ($controller->assembleAllChildrenFrom($model) as $subModel) { $this->circularModelIds[] = ModelId::fromValues($providerName, $subModel)->getSerialized(); } } if (null !== ViewHelpers::getManualSortingProperty($environment)) { $this->hasPasteButtons = !empty($this->clipboardItems); $this->hasPasteNewButton = empty($this->clipboardItems) && !$this->isHierarchical; } else { $this->hasPasteButtons = false; $this->hasPasteNewButton = false; } }
/** * Check if the language has been switched. * * If so, the value in the session will be updated and the page reloaded. * * @param EnvironmentInterface $environment The environment. * * @return void */ private function checkLanguageSubmit($environment) { $sessionStorage = $environment->getSessionStorage(); $inputProvider = $environment->getInputProvider(); if ($inputProvider->getValue('FORM_SUBMIT') !== 'language_switch') { return; } $modelId = $inputProvider->getParameter('id') && $inputProvider->getParameter('id') ? IdSerializer::fromSerialized($inputProvider->getParameter('id'))->getId() : null; $languages = $environment->getController()->getSupportedLanguages($modelId); $providerName = $environment->getDataDefinition()->getName(); // Get/Check the new language. if ($inputProvider->hasValue('language') && array_key_exists($inputProvider->getValue('language'), $languages)) { $session['ml_support'][$providerName][$modelId] = $inputProvider->getValue('language'); $sessionStorage->set('dc_general', $session); } $environment->getEventDispatcher()->dispatch(ContaoEvents::CONTROLLER_RELOAD, new ReloadEvent()); }
/** * Create an empty model using the default values from the definition. * * @return ModelInterface * * @deprecated Use Controller::createEmptyModelWithDefaults() instead! */ protected function createEmptyModelWithDefaults() { return $this->environment->getController()->createEmptyModelWithDefaults(); }