Esempio n. 1
0
 /**
  * Trigger a valid ajax action
  * @param $strGroup
  * @param $strAction
  * @param $objContext
  */
 public static function runActiveAction($strGroup, $strAction, $objContext)
 {
     if (Request::getInstance()->isXmlHttpRequest()) {
         /** @var AjaxAction */
         $objAction = Ajax::getActiveAction($strGroup, $strAction);
         if ($objAction === AJAX_ERROR_INVALID_GROUP) {
             header('HTTP/1.1 400 Bad Request');
             die('Invalid ajax group.');
         } else {
             if ($objAction === AJAX_ERROR_NO_AVAILABLE_ACTIONS) {
                 header('HTTP/1.1 400 Bad Request');
                 die('No available ajax actions within given group.');
             } else {
                 if ($objAction === AJAX_ERROR_INVALID_ACTION) {
                     header('HTTP/1.1 400 Bad Request');
                     die('Invalid ajax act.');
                 } else {
                     if ($objAction !== null) {
                         $objResponse = $objAction->call($objContext);
                         /** @var Response */
                         if ($objResponse instanceof Response) {
                             $objResponse->output();
                         }
                     }
                 }
             }
         }
     }
 }
 public function __construct($arrAttributes = null)
 {
     // check against arrAttributes, as 'onsubmit_callback' => 'multifileupload_moveFiles' does not provide valid attributes
     if ($arrAttributes !== null && !$arrAttributes['uploadFolder']) {
         throw new \Exception(sprintf($GLOBALS['TL_LANG']['ERR']['noUploadFolderDeclared'], $this->name));
     }
     $arrAttributes['uploadAction'] = static::$uploadAction;
     if (TL_MODE == 'FE') {
         $arrAttributes['uploadActionParams'] = http_build_query(AjaxAction::getParams(MultiFileUpload::NAME, static::$uploadAction));
     }
     $arrAttributes['addRemoveLinks'] = isset($arrAttributes['addRemoveLinks']) ? $arrAttributes['addRemoveLinks'] : true;
     if (!is_array($arrAttributes['value']) && !Validator::isBinaryUuid($arrAttributes['value'])) {
         $arrAttributes['value'] = json_decode($arrAttributes['value']);
     }
     // bin to string -> never pass binary to the widget!!
     if ($arrAttributes['value']) {
         if (is_array($arrAttributes['value'])) {
             $arrAttributes['value'] = array_map(function ($val) {
                 return \Validator::isBinaryUuid($val) ? \StringUtil::binToUuid($val) : $val;
             }, $arrAttributes['value']);
         } else {
             $arrAttributes['value'] = array(\Validator::isBinaryUuid($arrAttributes['value']) ? \StringUtil::binToUuid($arrAttributes['value']) : $arrAttributes['value']);
         }
     }
     parent::__construct($arrAttributes);
     $this->objUploader = new MultiFileUpload($arrAttributes);
     // add onsubmit_callback: move files after form submission
     $GLOBALS['TL_DCA'][$this->strTable]['config']['onsubmit_callback']['multifileupload_moveFiles'] = array('HeimrichHannot\\MultiFileUpload\\FormMultiFileUpload', 'moveFiles');
     Ajax::runActiveAction(MultiFileUpload::NAME, MultiFileUpload::ACTION_UPLOAD, $this);
 }
 protected function generateField($strName, $arrData, $skipValidation = false)
 {
     $strClass = $GLOBALS['TL_FFL'][$arrData['inputType']];
     // overwrite the widget in readonly mode
     if ($this->viewMode == FORMHYBRID_VIEW_MODE_READONLY || $this->viewMode == FORMHYBRID_VIEW_MODE_DEFAULT && $this->addReadOnly && in_array($strName, $this->arrReadOnly)) {
         $strClass = 'HeimrichHannot\\FormHybrid\\FormReadonlyField';
         $skipValidation = true;
     }
     $strInputMethod = $this->strInputMethod;
     // Continue if the class is not defined
     if (!class_exists($strClass)) {
         return false;
     }
     $arrWidgetErrors = array();
     // contains the load_callback!
     $varDefault = $this->getDefaultFieldValue($strName, $arrData);
     $varValue = $varDefault;
     if ($this->isSubmitted && !$skipValidation) {
         $varValue = \Input::$strInputMethod($strName) !== null ? \Input::$strInputMethod($strName) : $varValue;
         $varValue = FormSubmission::prepareSpecialValueForSave($varValue, $arrData, $this->strTable, $this->intId, $varDefault, $arrWidgetErrors);
     }
     // overwrite required fields
     if ($this->overwriteRequired) {
         // set mandatory to false
         $arrData['eval']['mandatory'] = false;
         // overwrite mandatory by config
         if (!$arrData['eval']['mandatory'] && in_array($strName, $this->arrRequired)) {
             $arrData['eval']['mandatory'] = true;
         }
     }
     // prevent name for GET and submit widget, otherwise url will have submit name in
     if ($this->strMethod == FORMHYBRID_METHOD_GET && $arrData['inputType'] == 'submit') {
         $strName = '';
     }
     $arrData['eval']['tagTable'] = $this->strTable;
     // always disable validation for filter form
     if ($this->isFilterForm) {
         $arrData['eval']['mandatory'] = false;
     }
     // to make captcha form related, add the form id without entity id
     if ($arrData['inputType'] == 'captcha') {
         $strName .= '_' . $this->getFormId(false);
     }
     $this->strField = $strName;
     $this->strInputName = $strName;
     $this->varValue = is_array($varValue) ? $varValue : \Controller::replaceInsertTags($varValue);
     $arrWidget = \Widget::getAttributesFromDca($arrData, $strName, is_array($varValue) ? $varValue : \Controller::replaceInsertTags($varValue), $strName, $this->strTable, $this);
     $this->updateWidget($arrWidget, $arrData);
     list($blnActive, $strSubPalette, $arrFields, $arrSubPaletteFields, $blnAutoSubmit, $blnToggleSubpalette) = $this->retrieveSubpaletteWithState($strName, array_keys($this->arrFields));
     // support submitOnChange as form submission
     if ($arrData['eval']['submitOnChange'] && $blnToggleSubpalette) {
         if ($blnAutoSubmit) {
             $arrWidget['onchange'] = $this->async ? 'FormhybridAjaxRequest.asyncSubmit(this.form);' : "this.form.submit();";
         } else {
             $strEvent = 'onclick';
             switch ($arrData['inputType']) {
                 case 'select':
                     $strEvent = 'onchange';
                     break;
             }
             $arrWidget[$strEvent] = "FormhybridAjaxRequest.toggleSubpalette(this, 'sub_" . $strName . "', '" . $strName . "', '" . AjaxAction::generateUrl(Form::FORMHYBRID_NAME, 'toggleSubpalette') . "')";
             unset($arrWidget['submitOnChange']);
         }
     } else {
         if ($arrWidget['submitOnChange']) {
             $strEvent = null;
             if ($arrWidget['onchange']) {
                 $strEvent = 'onchange';
             } else {
                 if ($arrWidget['onclick']) {
                     $strEvent = 'onclick';
                 }
             }
             if ($strEvent !== null) {
                 $arrWidget[$strEvent] = "FormhybridAjaxRequest.reload('" . $this->getFormId() . "', '" . AjaxAction::generateUrl(Form::FORMHYBRID_NAME, 'reload') . "')";
                 unset($arrWidget['submitOnChange']);
             }
         }
     }
     $objWidget = new $strClass($arrWidget);
     if (isset($arrData['formHybridOptions'])) {
         $arrFormHybridOptions = $arrData['formHybridOptions'];
         $this->import($arrFormHybridOptions[0]);
         $objWidget->options = $this->{$arrFormHybridOptions}[0]->{$arrFormHybridOptions}[1]();
     }
     if ($objWidget instanceof \uploadable) {
         $this->hasUpload = true;
     }
     // always xss clean the user input (also if filter, non-model submission, ...) -> done another time
     // FrontendWidget::validateGetAndPost() in
     $objWidget->value = FormHelper::xssClean($objWidget->value, $arrData['eval']['allowHtml']);
     if ($this->isSubmitted) {
         // add filter class if filter is active
         if ($objWidget->value && $this->isFilterForm) {
             $objWidget->class = 'filtered';
         }
         // do not validate fields if not submitted or skipvalidation issset
         // do not submit if ajax request and group is not formhybrid, for example multifileupload (otherwise captcha fields will be validated does not match visible one)
         if (!($this->isSkipValidation() || $skipValidation) && Ajax::isRelated(Form::FORMHYBRID_NAME) !== false) {
             FrontendWidget::validateGetAndPost($objWidget, $this->strMethod, $this->getFormId(), $arrData);
             if (is_array($arrWidgetErrors)) {
                 foreach ($arrWidgetErrors as $strError) {
                     $objWidget->addError($strError);
                 }
             }
             // Make sure unique fields are unique
             if ($arrData['eval']['unique'] && $varValue != '' && !\Database::getInstance()->isUniqueValue($this->strTable, $strName, $varValue, $this->intId > 0 ? $this->intId : null)) {
                 $objWidget->addError(sprintf($GLOBALS['TL_LANG']['ERR']['unique'], $arrData['label'][0] ?: $strName));
             }
             // trigger save_callbacks before assertion of the new value to objActiveRecord
             if (is_array($arrData['save_callback'])) {
                 foreach ($arrData['save_callback'] as $callback) {
                     if (is_array($callback)) {
                         $this->import($callback[0]);
                         $varValue = $this->{$callback}[0]->{$callback}[1]($varValue, $this);
                     } elseif (is_callable($callback)) {
                         $varValue = $callback($varValue, $this);
                     }
                 }
             }
             if ($objWidget->hasErrors()) {
                 $this->doNotSubmit = true;
                 $this->arrInvalidFields[] = $strName;
             } elseif ($arrData['inputType'] == 'tag' && in_array('tags_plus', \ModuleLoader::getActive())) {
                 $varValue = deserialize($objWidget->value);
                 if (!is_array($varValue)) {
                     $varValue = array($varValue);
                 }
                 if ($this->intId) {
                     \HeimrichHannot\TagsPlus\TagsPlus::saveTags($this->strTable, $this->intId, array_map('urldecode', $varValue));
                 }
             } elseif ($objWidget->submitInput()) {
                 // save non escaped to database
                 if (is_array($objWidget->value)) {
                     $this->objActiveRecord->{$strName} = array_map(function ($varVal) use($arrData) {
                         $varVal = FormSubmission::prepareSpecialValueForSave($varVal, $arrData, $this->strTable, $this->intId);
                         if (is_array($varVal)) {
                             foreach ($varVal as $key => $val) {
                                 $varVal[$key] = html_entity_decode($val);
                             }
                         } else {
                             $varVal = html_entity_decode($varVal);
                         }
                         return $varVal;
                     }, $objWidget->value);
                 } else {
                     $this->objActiveRecord->{$strName} = html_entity_decode(FormSubmission::prepareSpecialValueForSave($objWidget->value, $arrData, $this->strTable, $this->intId));
                 }
             } elseif ($objWidget instanceof \uploadable && $arrData['inputType'] == 'multifileupload') {
                 $strMethod = strtolower($this->strMethod);
                 if (\Input::$strMethod($strName)) {
                     $arrValue = json_decode(\Input::$strMethod($strName));
                     if (!empty($arrValue)) {
                         $arrValue = array_map(function ($val) {
                             return \String::uuidToBin($val);
                         }, $arrValue);
                         $this->objActiveRecord->{$strName} = serialize($arrValue);
                     } else {
                         $this->objActiveRecord->{$strName} = serialize($arrValue);
                     }
                 }
                 // delete the files scheduled for deletion
                 $objWidget->deleteScheduledFiles(json_decode(\Input::$strMethod('deleted_' . $strName)));
             } elseif ($objWidget instanceof \uploadable && isset($_SESSION['FILES'][$strName]) && \Validator::isUuid($_SESSION['FILES'][$strName]['uuid'])) {
                 $this->objActiveRecord->{$strName} = $_SESSION['FILES'][$strName]['uuid'];
             }
         }
     }
     return $objWidget;
 }
 /**
  * Get config value from transformed arrData and add logic to modify the value here
  * @param $strKey
  *
  * @return mixed|string
  */
 public function __get($strKey)
 {
     $varValue = $this->arrData[$strKey];
     switch ($strKey) {
         case 'strAction':
             if ($varValue && ($objActionPage = \PageModel::findWithDetails($varValue)) !== null) {
                 $varValue = \Controller::generateFrontendUrl($objActionPage->row(), null, null, true);
             } else {
                 $varValue = Url::removeQueryString(array('file'), \Environment::get('uri'));
                 // remove all query parameters within ajax request
                 if (Ajax::isRelated(Form::FORMHYBRID_NAME) !== false) {
                     $varValue = AjaxAction::removeAjaxParametersFromUrl($varValue);
                 }
             }
             // async form
             if ($this->async) {
                 $varValue = AjaxAction::generateUrl(Form::FORMHYBRID_NAME, 'asyncFormSubmit');
             }
             // add hash
             if ($this->addHashToAction) {
                 $varValue .= '#' . ($this->customHash ?: $this->strFormId);
             }
             break;
         case 'arrDefaultValues':
             $varValue = FormHelper::getAssocMultiColumnWizardList($varValue, 'field');
             break;
     }
     return $varValue;
 }
 protected function compile()
 {
     $this->Template->headline = $this->headline;
     $this->Template->hl = $this->hl;
     $this->Template->wrapperClass = $this->strWrapperClass;
     $this->Template->wrapperId = $this->strWrapperId;
     $this->strFormId = $this->formHybridDataContainer . '_' . $this->id;
     $strAction = $this->defaultAction ?: \Input::get('act');
     $this->arrEditable = deserialize($this->formHybridEditable, true);
     $this->strToken = $this->strToken ?: \Input::get('token');
     // Do not change this order (see #6191)
     $this->Template->style = !empty($this->arrStyle) ? implode(' ', $this->arrStyle) : '';
     $this->Template->class = trim('mod_' . $this->type . ' ' . $this->cssID[1]);
     $this->Template->cssID = $this->cssID[0] != '' ? ' id="' . $this->cssID[0] . '"' : '';
     $this->Template->inColumn = $this->strColumn;
     if ($this->Template->headline == '') {
         $this->Template->headline = $this->headline;
     }
     if ($this->Template->hl == '') {
         $this->Template->hl = $this->hl;
     }
     if (!empty($this->classes) && is_array($this->classes)) {
         $this->Template->class .= ' ' . implode(' ', $this->classes);
     }
     $this->addDefaultArchive();
     // at first check for the correct request token to be set
     if (!$this->deactivateTokens && !\RequestToken::validate($this->strToken)) {
         if (!$this->blnSilentMode) {
             StatusMessage::addError(sprintf($GLOBALS['TL_LANG']['frontendedit']['requestTokenExpired'], Url::replaceParameterInUri(Url::getUrl(), 'token', \RequestToken::get())), $this->id, 'requestTokenExpired');
         }
         return;
     }
     if ($this->formHybridAllowIdAsGetParameter) {
         $intId = \Input::get($this->formHybridIdGetParameter);
         if (is_numeric($intId)) {
             $this->intId = $intId;
         }
     }
     $strItemClass = \Model::getClassFromTable($this->formHybridDataContainer);
     // get id from share
     if ($strShare = \Input::get('share')) {
         if (($objItem = $strItemClass::findByShareToken($strShare)) !== null && !FormHybridList::shareTokenExpiredOrEmpty($objItem, time())) {
             $this->intId = $objItem->id;
         }
     }
     if (!$this->intId) {
         if (isset($GLOBALS['TL_HOOKS']['frontendEditAddNoIdBehavior']) && is_array($GLOBALS['TL_HOOKS']['frontendEditAddNoIdBehavior'])) {
             foreach ($GLOBALS['TL_HOOKS']['frontendEditAddNoIdBehavior'] as $arrCallback) {
                 $this->import($arrCallback[0]);
                 if ($this->{$arrCallback}[0]->{$arrCallback}[1]($this) === false) {
                     return;
                 }
             }
         }
         if ($this->noIdBehavior == 'error') {
             if (!$this->blnSilentMode) {
                 StatusMessage::addError($GLOBALS['TL_LANG']['frontendedit']['noIdFound'], $this->id, 'noidfound');
             }
             return;
         } elseif ($this->noIdBehavior == 'redirect' || $this->noIdBehavior == 'create_until') {
             $arrConditions = deserialize($this->existanceConditions, true);
             if ($this->existanceConditions && !empty($arrConditions)) {
                 $arrColumns = array();
                 $arrValues = array();
                 foreach ($arrConditions as $arrCondition) {
                     if (!$arrCondition['field']) {
                         continue;
                     }
                     $arrColumns[] = $arrCondition['field'] . '=?';
                     $arrValues[] = $this->replaceInsertTags($arrCondition['value']);
                 }
                 if (!empty($arrColumns) && ($objItem = $strItemClass::findOneBy($arrColumns, $arrValues)) !== null) {
                     $this->intId = $objItem->id;
                 }
             }
         }
         if (!$this->intId) {
             if ($this->noIdBehavior == 'redirect') {
                 if (!$this->blnSilentMode) {
                     StatusMessage::addError($GLOBALS['TL_LANG']['frontendedit']['noIdFound'], $this->id, 'noidfound');
                 }
                 return;
             } else {
                 $strFormId = FormHelper::getFormId($this->formHybridDataContainer, $this->id);
                 // get id from FormSession
                 if ($_POST) {
                     if ($intId = FormSession::getSubmissionId($strFormId)) {
                         $this->intId = $intId;
                     }
                 }
                 if (!$this->intId) {
                     // if no id is given a new instance is initiated
                     $objConfiguration = new FormConfiguration($this->arrData);
                     // ajax handling, required in this manor, as we have no real ajax controller in contao and ajax request not related to this module
                     // might trigger this module beforhand and new submission will be created after the submission was transfered to the user and id wont match any more
                     if (Ajax::isRelated(Form::FORMHYBRID_NAME) !== null) {
                         if ($intId = FormSession::getSubmissionId($strFormId)) {
                             $this->intId = $intId;
                         } else {
                             $objConfiguration->forceCreate = true;
                         }
                     }
                     $this->objForm = new $this->strFormClass($objConfiguration, $this->arrSubmitCallbacks, $this->intId ?: 0, $this);
                     if ($intId = $this->objForm->getId()) {
                         $this->intId = $intId;
                     }
                 }
             }
         }
     }
     // intId is set at this point!
     if (!$this->checkEntityExists($this->intId)) {
         if (!$this->blnSilentMode) {
             StatusMessage::addError($GLOBALS['TL_LANG']['formhybrid_list']['noPermission'], $this->id, 'nopermission');
         }
         if (Ajax::isRelated(Form::FORMHYBRID_NAME)) {
             $objResponse = new ResponseError();
             $objResponse->setResult(StatusMessage::generate($this->id));
             $objResponse->output();
         }
         return;
     }
     // page title
     if ($this->setPageTitle) {
         global $objPage;
         if (($objItem = General::getModelInstance($this->formHybridDataContainer, $this->intId)) !== null) {
             $objPage->pageTitle = $objItem->{$this->pageTitleField};
         }
     }
     if ($strAction == FRONTENDEDIT_ACT_DELETE) {
         if ($this->checkDeletePermission($this->intId)) {
             $blnResult = $this->deleteItem($this->intId);
             if (\Environment::get('isAjaxRequest')) {
                 die($blnResult);
             }
             // return to the list
             \Controller::redirect(Url::removeQueryString(array('act', 'id', 'token'), Url::getUrl()));
         } else {
             if (!$this->blnSilentMode) {
                 StatusMessage::addError($GLOBALS['TL_LANG']['formhybrid_list']['noPermission'], $this->id, 'nopermission');
             }
             return;
         }
     } else {
         if ($this->checkUpdatePermission($this->intId)) {
             // create a new lock if necessary
             if (in_array('entity_lock', \ModuleLoader::getActive()) && $this->addEntityLock) {
                 if (\HeimrichHannot\EntityLock\EntityLockModel::isLocked($this->formHybridDataContainer, $this->intId, $this)) {
                     $objLock = \HeimrichHannot\EntityLock\EntityLockModel::findActiveLock($this->formHybridDataContainer, $this->intId, $this);
                     $objItem = General::getModelInstance($this->formHybridDataContainer, $this->intId);
                     if (!$this->blnSilentMode) {
                         $strMessage = \HeimrichHannot\EntityLock\EntityLock::generateErrorMessage($this->formHybridDataContainer, $this->intId, $this);
                         if ($this->allowLockDeletion) {
                             $strUnlockForm = $this->generateUnlockForm($objItem, $objLock);
                             $strMessage .= $strUnlockForm;
                         }
                         StatusMessage::addError($strMessage, $this->id, 'locked');
                     }
                     if ($this->readOnlyOnLocked) {
                         $this->formHybridViewMode = FORMHYBRID_VIEW_MODE_READONLY;
                         $this->formHybridReadonlyTemplate = 'formhybridreadonly_default';
                     } else {
                         return;
                     }
                 } else {
                     \HeimrichHannot\EntityLock\EntityLockModel::create($this->formHybridDataContainer, $this->intId, $this);
                 }
             }
             if ($this->objForm === null) {
                 $this->objForm = new $this->strFormClass(new FormConfiguration($this->arrData), $this->arrSubmitCallbacks, $this->intId, $this);
             }
             $this->Template->form = $this->objForm->generate();
             $this->Template->item = $this->objForm->activeRecord;
             if (\Environment::get('isAjaxRequest') && \Input::get('scope') == 'modal') {
                 $objItem = General::getModelInstance($this->formHybridDataContainer, $this->intId);
                 $objModalWrapper = new \FrontendTemplate($this->modalTpl ?: 'formhybrid_reader_modal_bootstrap');
                 if ($objItem !== null) {
                     $objModalWrapper->setData($objItem->row());
                 }
                 $objModalWrapper->module = Arrays::arrayToObject($this->arrData);
                 $objModalWrapper->item = $this->replaceInsertTags($this->Template->parse());
                 die($objModalWrapper->parse());
             }
         } else {
             if (!$this->blnSilentMode) {
                 StatusMessage::addError($GLOBALS['TL_LANG']['formhybrid_list']['noPermission'], $this->id, 'nopermission');
             }
             return;
         }
     }
 }
 /**
  * Hook upon PageRegular to register modal and render them
  *
  * @param $objPage
  * @param $objLayout
  * @param $objPageRegular
  *
  * @return void
  */
 public function generatePageWithModal($objPage, $objLayout, &$objPageRegular)
 {
     // Do not handle the page if no modal item has been specified or page is no regular
     if (!\Input::get('modals') || $objPage->type != 'regular') {
         return;
     }
     $objModel = ModalModel::findPublishedByIdOrAliasWithoutLinkedPage(\Input::get('modals'));
     if ($objModel === null && $objPage->linkModal) {
         $objModel = ModalModel::findPublishedByIdOrAlias($objPage->modal);
     }
     $blnCheck = true;
     if ($objModel === null) {
         $blnCheck = false;
     }
     $objModel = $objModel->current();
     $arrConfig = static::getModalConfig($objModel, $objLayout, $objPage);
     Ajax::runActiveAction(Modal::MODAL_NAME, 'redirect', new ModalAjax($objModel->current(), $arrConfig));
     Ajax::runActiveAction(Modal::MODAL_NAME, 'show', new ModalAjax($objModel->current(), $arrConfig));
     if (empty($arrConfig)) {
         $blnCheck = false;
     }
     if (!$blnCheck) {
         /** @var \PageError404 $objHandler */
         $objHandler = new $GLOBALS['TL_PTY']['error_404']();
         $objHandler->generate($objPage->id);
     }
     $back = \Controller::generateFrontendUrl($objPage->row(), null, null, true);
     $objModal = new Modal($objModel, $arrConfig);
     $objModal->setBackLink($back);
     // render modal within main, as it is the most commonly used region and enabled within contao by default
     $strBuffer = $objModal->generate();
     $objPageRegular->Template->main .= $strBuffer;
 }