/** * Duplicate all child records of a duplicated record * * @param string $table * @param integer $insertID * @param integer $id * @param integer $parentId */ protected function copyChilds($table, $insertID, $id, $parentId) { $time = time(); $copy = array(); $cctable = array(); $ctable = $GLOBALS['TL_DCA'][$table]['config']['ctable']; if (!$GLOBALS['TL_DCA'][$table]['config']['ptable'] && strlen(\Input::get('childs')) && $this->Database->fieldExists('pid', $table) && $this->Database->fieldExists('sorting', $table)) { $ctable[] = $table; } if (!is_array($ctable)) { return; } // Walk through each child table foreach ($ctable as $v) { $this->loadDataContainer($v); $cctable[$v] = $GLOBALS['TL_DCA'][$v]['config']['ctable']; if (!$GLOBALS['TL_DCA'][$v]['config']['doNotCopyRecords'] && strlen($v)) { // Consider the dynamic parent table (see #4867) if ($GLOBALS['TL_DCA'][$v]['config']['dynamicPtable']) { $ptable = $GLOBALS['TL_DCA'][$v]['config']['ptable']; $cond = $ptable == 'tl_article' ? "(ptable=? OR ptable='')" : "ptable=?"; $objCTable = $this->Database->prepare("SELECT * FROM {$v} WHERE pid=? AND {$cond}" . ($this->Database->fieldExists('sorting', $v) ? " ORDER BY sorting" : ""))->execute($id, $ptable); } else { $objCTable = $this->Database->prepare("SELECT * FROM {$v} WHERE pid=?" . ($this->Database->fieldExists('sorting', $v) ? " ORDER BY sorting" : ""))->execute($id); } while ($objCTable->next()) { // Exclude the duplicated record itself if ($v == $table && $objCTable->id == $parentId) { continue; } foreach ($objCTable->row() as $kk => $vv) { if ($kk == 'id') { continue; } // Never copy passwords if ($GLOBALS['TL_DCA'][$v]['fields'][$kk]['inputType'] == 'password') { $vv = \Widget::getEmptyValueByFieldType($GLOBALS['TL_DCA'][$v]['fields'][$kk]['sql']); } elseif ($GLOBALS['TL_DCA'][$v]['fields'][$kk]['eval']['unique']) { $vv = \Input::get('act') == 'copyAll' ? $vv . '-' . substr(md5(uniqid(mt_rand(), true)), 0, 8) : \Widget::getEmptyValueByFieldType($GLOBALS['TL_DCA'][$v]['fields'][$kk]['sql']); } elseif ($GLOBALS['TL_DCA'][$v]['fields'][$kk]['eval']['doNotCopy'] || $GLOBALS['TL_DCA'][$v]['fields'][$kk]['eval']['fallback']) { $vv = ''; // Use array_key_exists to allow NULL (see #5252) if (array_key_exists('default', $GLOBALS['TL_DCA'][$v]['fields'][$kk])) { $vv = is_array($GLOBALS['TL_DCA'][$v]['fields'][$kk]['default']) ? serialize($GLOBALS['TL_DCA'][$v]['fields'][$kk]['default']) : $GLOBALS['TL_DCA'][$v]['fields'][$kk]['default']; } // Encrypt the default value (see #3740) if ($GLOBALS['TL_DCA'][$v]['fields'][$kk]['eval']['encrypt']) { $vv = \Encryption::encrypt($vv); } } $copy[$v][$objCTable->id][$kk] = $vv; } $copy[$v][$objCTable->id]['pid'] = $insertID; $copy[$v][$objCTable->id]['tstamp'] = $time; } } } // Duplicate the child records foreach ($copy as $k => $v) { if (!empty($v)) { foreach ($v as $kk => $vv) { $objInsertStmt = $this->Database->prepare("INSERT INTO " . $k . " %s")->set($vv)->execute(); if ($objInsertStmt->affectedRows) { $insertID = $objInsertStmt->insertId; if ((!empty($cctable[$k]) || $GLOBALS['TL_DCA'][$k]['list']['sorting']['mode'] == 5) && $kk != $parentId) { $this->copyChilds($k, $insertID, $kk, $parentId); } } } } } }
/** * Generate the module */ protected function compile() { /** @var PageModel $objPage */ global $objPage; $GLOBALS['TL_LANGUAGE'] = $objPage->language; \System::loadLanguageFile('tl_member'); $this->loadDataContainer('tl_member'); // Call onload_callback (e.g. to check permissions) if (is_array($GLOBALS['TL_DCA']['tl_member']['config']['onload_callback'])) { foreach ($GLOBALS['TL_DCA']['tl_member']['config']['onload_callback'] as $callback) { if (is_array($callback)) { $this->import($callback[0]); $this->{$callback[0]}->{$callback[1]}(); } elseif (is_callable($callback)) { $callback(); } } } // Activate account if (\Input::get('token') != '') { $this->activateAcount(); return; } if ($this->memberTpl != '') { /** @var FrontendTemplate|object $objTemplate */ $objTemplate = new \FrontendTemplate($this->memberTpl); $this->Template = $objTemplate; $this->Template->setData($this->arrData); } $this->Template->fields = ''; $objCaptcha = null; $doNotSubmit = false; $strFormId = 'tl_registration_' . $this->id; // Predefine the group order (other groups will be appended automatically) $arrGroups = array('personal' => array(), 'address' => array(), 'contact' => array(), 'login' => array(), 'profile' => array()); // Captcha if (!$this->disableCaptcha) { $arrCaptcha = array('id' => 'registration', 'label' => $GLOBALS['TL_LANG']['MSC']['securityQuestion'], 'type' => 'captcha', 'mandatory' => true, 'required' => true); /** @var FormCaptcha $strClass */ $strClass = $GLOBALS['TL_FFL']['captcha']; // Fallback to default if the class is not defined if (!class_exists($strClass)) { $strClass = 'FormCaptcha'; } /** @var FormCaptcha $objCaptcha */ $objCaptcha = new $strClass($arrCaptcha); if (\Input::post('FORM_SUBMIT') == $strFormId) { $objCaptcha->validate(); if ($objCaptcha->hasErrors()) { $doNotSubmit = true; } } } $objMember = null; // Check for a follow-up registration (see #7992) if (\Input::post('email', true) != '' && ($objMember = \MemberModel::findUnactivatedByEmail(\Input::post('email', true))) !== null) { $this->resendActivationMail($objMember); return; } $arrUser = array(); $arrFields = array(); $hasUpload = false; $i = 0; // Build form foreach ($this->editable as $field) { $arrData = $GLOBALS['TL_DCA']['tl_member']['fields'][$field]; // Map checkboxWizards to regular checkbox widgets if ($arrData['inputType'] == 'checkboxWizard') { $arrData['inputType'] = 'checkbox'; } // Map fileTrees to upload widgets (see #8091) if ($arrData['inputType'] == 'fileTree') { $arrData['inputType'] = 'upload'; } /** @var Widget $strClass */ $strClass = $GLOBALS['TL_FFL'][$arrData['inputType']]; // Continue if the class is not defined if (!class_exists($strClass)) { continue; } $arrData['eval']['required'] = $arrData['eval']['mandatory']; // Unset the unique field check upon follow-up registrations if ($objMember !== null && $arrData['eval']['unique'] && \Input::post($field) == $objMember->{$field}) { $arrData['eval']['unique'] = false; } $objWidget = new $strClass($strClass::getAttributesFromDca($arrData, $field, $arrData['default'], '', '', $this)); $objWidget->storeValues = true; $objWidget->rowClass = 'row_' . $i . ($i == 0 ? ' row_first' : '') . ($i % 2 == 0 ? ' even' : ' odd'); // Increase the row count if its a password field if ($objWidget instanceof FormPassword) { $objWidget->rowClassConfirm = 'row_' . ++$i . ($i % 2 == 0 ? ' even' : ' odd'); } // Validate input if (\Input::post('FORM_SUBMIT') == $strFormId) { $objWidget->validate(); $varValue = $objWidget->value; // Check whether the password matches the username if ($objWidget instanceof FormPassword && \Encryption::verify(\Input::post('username'), $varValue)) { $objWidget->addError($GLOBALS['TL_LANG']['ERR']['passwordName']); } $rgxp = $arrData['eval']['rgxp']; // Convert date formats into timestamps (check the eval setting first -> #3063) if ($varValue != '' && in_array($rgxp, array('date', 'time', 'datim'))) { try { $objDate = new \Date($varValue, \Date::getFormatFromRgxp($rgxp)); $varValue = $objDate->tstamp; } catch (\OutOfBoundsException $e) { $objWidget->addError(sprintf($GLOBALS['TL_LANG']['ERR']['invalidDate'], $varValue)); } } // Make sure that unique fields are unique (check the eval setting first -> #3063) if ($arrData['eval']['unique'] && $varValue != '' && !$this->Database->isUniqueValue('tl_member', $field, $varValue)) { $objWidget->addError(sprintf($GLOBALS['TL_LANG']['ERR']['unique'], $arrData['label'][0] ?: $field)); } // Save callback if ($objWidget->submitInput() && !$objWidget->hasErrors() && is_array($arrData['save_callback'])) { foreach ($arrData['save_callback'] as $callback) { try { if (is_array($callback)) { $this->import($callback[0]); $varValue = $this->{$callback[0]}->{$callback[1]}($varValue, null); } elseif (is_callable($callback)) { $varValue = $callback($varValue, null); } } catch (\Exception $e) { $objWidget->class = 'error'; $objWidget->addError($e->getMessage()); } } } // Store the current value if ($objWidget->hasErrors()) { $doNotSubmit = true; } elseif ($objWidget->submitInput()) { // Set the correct empty value (see #6284, #6373) if ($varValue === '') { $varValue = $objWidget->getEmptyValue(); } // Encrypt the value (see #7815) if ($arrData['eval']['encrypt']) { $varValue = \Encryption::encrypt($varValue); } // Set the new value $arrUser[$field] = $varValue; } } if ($objWidget instanceof \uploadable) { $hasUpload = true; } $temp = $objWidget->parse(); $this->Template->fields .= $temp; $arrFields[$arrData['eval']['feGroup']][$field] .= $temp; ++$i; } // Captcha if (!$this->disableCaptcha) { $objCaptcha->rowClass = 'row_' . $i . ($i == 0 ? ' row_first' : '') . ($i % 2 == 0 ? ' even' : ' odd'); $strCaptcha = $objCaptcha->parse(); $this->Template->fields .= $strCaptcha; $arrFields['captcha']['captcha'] .= $strCaptcha; } $this->Template->rowLast = 'row_' . ++$i . ($i % 2 == 0 ? ' even' : ' odd'); $this->Template->enctype = $hasUpload ? 'multipart/form-data' : 'application/x-www-form-urlencoded'; $this->Template->hasError = $doNotSubmit; // Create new user if there are no errors if (\Input::post('FORM_SUBMIT') == $strFormId && !$doNotSubmit) { $this->createNewUser($arrUser); } $this->Template->loginDetails = $GLOBALS['TL_LANG']['tl_member']['loginDetails']; $this->Template->addressDetails = $GLOBALS['TL_LANG']['tl_member']['addressDetails']; $this->Template->contactDetails = $GLOBALS['TL_LANG']['tl_member']['contactDetails']; $this->Template->personalData = $GLOBALS['TL_LANG']['tl_member']['personalData']; $this->Template->captchaDetails = $GLOBALS['TL_LANG']['MSC']['securityQuestion']; // Add the groups foreach ($arrFields as $k => $v) { // Deprecated since Contao 4.0, to be removed in Contao 5.0 $this->Template->{$k} = $v; $key = $k . ($k == 'personal' ? 'Data' : 'Details'); $arrGroups[$GLOBALS['TL_LANG']['tl_member'][$key]] = $v; } $this->Template->categories = $arrGroups; $this->Template->formId = $strFormId; $this->Template->slabel = \StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['register']); $this->Template->action = \Environment::get('indexFreeRequest'); // Deprecated since Contao 4.0, to be removed in Contao 5.0 $this->Template->captcha = $arrFields['captcha']['captcha']; }
/** * Return an object property * * @param string $strKey The property name * * @return string The property value */ public function __get($strKey) { switch ($strKey) { case 'id': return $this->strId; break; case 'name': return $this->strName; break; case 'label': return $this->strLabel; break; case 'value': // Encrypt the value if ($this->arrConfiguration['encrypt']) { return \Encryption::encrypt($this->varValue); } elseif ($this->varValue == '') { return $this->getEmptyStringOrNull(); } return $this->varValue; break; case 'class': return $this->strClass; break; case 'prefix': return $this->strPrefix; break; case 'template': return $this->strTemplate; break; case 'wizard': return $this->strWizard; break; case 'required': return $this->arrConfiguration[$strKey]; break; case 'forAttribute': return $this->blnForAttribute; break; case 'dataContainer': return $this->objDca; break; case 'activeRecord': return $this->objDca->activeRecord; break; default: if (isset($this->arrAttributes[$strKey])) { return $this->arrAttributes[$strKey]; } elseif (isset($this->arrConfiguration[$strKey])) { return $this->arrConfiguration[$strKey]; } break; } return parent::__get($strKey); }
/** * Generate the module */ protected function compile() { /** @var PageModel $objPage */ global $objPage; $this->import('FrontendUser', 'User'); $GLOBALS['TL_LANGUAGE'] = $objPage->language; \System::loadLanguageFile('tl_member'); $this->loadDataContainer('tl_member'); // Call onload_callback (e.g. to check permissions) if (is_array($GLOBALS['TL_DCA']['tl_member']['config']['onload_callback'])) { foreach ($GLOBALS['TL_DCA']['tl_member']['config']['onload_callback'] as $callback) { if (is_array($callback)) { $this->import($callback[0]); $this->{$callback[0]}->{$callback[1]}(); } elseif (is_callable($callback)) { $callback(); } } } $this->Template->fields = ''; $arrFields = array(); $doNotSubmit = false; $hasUpload = false; $row = 0; // Predefine the group order (other groups will be appended automatically) $arrGroups = array('personal' => array(), 'address' => array(), 'contact' => array(), 'login' => array(), 'profile' => array()); $blnModified = false; $objMember = \MemberModel::findByPk($this->User->id); $strTable = $objMember->getTable(); $strFormId = 'tl_member_' . $this->id; $flashBag = \System::getContainer()->get('session')->getFlashBag(); // Initialize the versioning (see #7415) $objVersions = new \Versions($strTable, $objMember->id); $objVersions->setUsername($objMember->username); $objVersions->setUserId(0); $objVersions->setEditUrl('contao/main.php?do=member&act=edit&id=%s&rt=1'); $objVersions->initialize(); // Build the form foreach ($this->editable as $field) { $arrData =& $GLOBALS['TL_DCA']['tl_member']['fields'][$field]; // Map checkboxWizards to regular checkbox widgets if ($arrData['inputType'] == 'checkboxWizard') { $arrData['inputType'] = 'checkbox'; } // Map fileTrees to upload widgets (see #8091) if ($arrData['inputType'] == 'fileTree') { $arrData['inputType'] = 'upload'; } /** @var Widget $strClass */ $strClass = $GLOBALS['TL_FFL'][$arrData['inputType']]; // Continue if the class does not exist if (!$arrData['eval']['feEditable'] || !class_exists($strClass)) { continue; } $strGroup = $arrData['eval']['feGroup']; $arrData['eval']['required'] = false; // Use strlen() here (see #3277) if ($arrData['eval']['mandatory']) { if (is_array($this->User->{$field})) { if (empty($this->User->{$field})) { $arrData['eval']['required'] = true; } } else { if (!strlen($this->User->{$field})) { $arrData['eval']['required'] = true; } } } $varValue = $this->User->{$field}; // Call the load_callback if (isset($arrData['load_callback']) && is_array($arrData['load_callback'])) { foreach ($arrData['load_callback'] as $callback) { if (is_array($callback)) { $this->import($callback[0]); $varValue = $this->{$callback[0]}->{$callback[1]}($varValue, $this->User, $this); } elseif (is_callable($callback)) { $varValue = $callback($varValue, $this->User, $this); } } } /** @var Widget $objWidget */ $objWidget = new $strClass($strClass::getAttributesFromDca($arrData, $field, $varValue, '', '', $this)); $objWidget->storeValues = true; $objWidget->rowClass = 'row_' . $row . ($row == 0 ? ' row_first' : '') . ($row % 2 == 0 ? ' even' : ' odd'); // Increase the row count if it is a password field if ($objWidget instanceof FormPassword) { if ($objMember->password != '') { $objWidget->mandatory = false; } $objWidget->rowClassConfirm = 'row_' . ++$row . ($row % 2 == 0 ? ' even' : ' odd'); } // Validate the form data if (\Input::post('FORM_SUBMIT') == $strFormId) { $objWidget->validate(); $varValue = $objWidget->value; $rgxp = $arrData['eval']['rgxp']; // Convert date formats into timestamps (check the eval setting first -> #3063) if ($varValue != '' && in_array($rgxp, array('date', 'time', 'datim'))) { try { $objDate = new \Date($varValue, \Date::getFormatFromRgxp($rgxp)); $varValue = $objDate->tstamp; } catch (\OutOfBoundsException $e) { $objWidget->addError(sprintf($GLOBALS['TL_LANG']['ERR']['invalidDate'], $varValue)); } } // Make sure that unique fields are unique (check the eval setting first -> #3063) if ($arrData['eval']['unique'] && $varValue != '' && !$this->Database->isUniqueValue('tl_member', $field, $varValue, $this->User->id)) { $objWidget->addError(sprintf($GLOBALS['TL_LANG']['ERR']['unique'], $arrData['label'][0] ?: $field)); } // Trigger the save_callback (see #5247) if ($objWidget->submitInput() && !$objWidget->hasErrors() && is_array($arrData['save_callback'])) { foreach ($arrData['save_callback'] as $callback) { try { if (is_array($callback)) { $this->import($callback[0]); $varValue = $this->{$callback[0]}->{$callback[1]}($varValue, $this->User, $this); } elseif (is_callable($callback)) { $varValue = $callback($varValue, $this->User, $this); } } catch (\Exception $e) { $objWidget->class = 'error'; $objWidget->addError($e->getMessage()); } } } // Do not submit the field if there are errors if ($objWidget->hasErrors()) { $doNotSubmit = true; } elseif ($objWidget->submitInput()) { // Store the form data $_SESSION['FORM_DATA'][$field] = $varValue; // Set the correct empty value (see #6284, #6373) if ($varValue === '') { $varValue = $objWidget->getEmptyValue(); } // Encrypt the value (see #7815) if ($arrData['eval']['encrypt']) { $varValue = \Encryption::encrypt($varValue); } // Set the new value if ($varValue !== $this->User->{$field}) { $this->User->{$field} = $varValue; // Set the new field in the member model $blnModified = true; $objMember->{$field} = $varValue; } } } if ($objWidget instanceof \uploadable) { $hasUpload = true; } $temp = $objWidget->parse(); $this->Template->fields .= $temp; $arrFields[$strGroup][$field] .= $temp; ++$row; } // Save the model if ($blnModified) { $objMember->tstamp = time(); $objMember->save(); // Create a new version if ($GLOBALS['TL_DCA'][$strTable]['config']['enableVersioning']) { $objVersions->create(); $this->log('A new version of record "' . $strTable . '.id=' . $objMember->id . '" has been created' . $this->getParentEntries($strTable, $objMember->id), __METHOD__, TL_GENERAL); } } $this->Template->hasError = $doNotSubmit; // Redirect or reload if there was no error if (\Input::post('FORM_SUBMIT') == $strFormId && !$doNotSubmit) { // HOOK: updated personal data if (isset($GLOBALS['TL_HOOKS']['updatePersonalData']) && is_array($GLOBALS['TL_HOOKS']['updatePersonalData'])) { foreach ($GLOBALS['TL_HOOKS']['updatePersonalData'] as $callback) { $this->import($callback[0]); $this->{$callback[0]}->{$callback[1]}($this->User, $_SESSION['FORM_DATA'], $this); } } // Call the onsubmit_callback if (is_array($GLOBALS['TL_DCA']['tl_member']['config']['onsubmit_callback'])) { foreach ($GLOBALS['TL_DCA']['tl_member']['config']['onsubmit_callback'] as $callback) { if (is_array($callback)) { $this->import($callback[0]); $this->{$callback[0]}->{$callback[1]}($this->User, $this); } elseif (is_callable($callback)) { $callback($this->User, $this); } } } // Check whether there is a jumpTo page if (($objJumpTo = $this->objModel->getRelated('jumpTo')) !== null) { $this->jumpToOrReload($objJumpTo->row()); } $flashBag->set('mod_personal_data_confirm', $GLOBALS['TL_LANG']['MSC']['savedData']); $this->reload(); } $this->Template->loginDetails = $GLOBALS['TL_LANG']['tl_member']['loginDetails']; $this->Template->addressDetails = $GLOBALS['TL_LANG']['tl_member']['addressDetails']; $this->Template->contactDetails = $GLOBALS['TL_LANG']['tl_member']['contactDetails']; $this->Template->personalData = $GLOBALS['TL_LANG']['tl_member']['personalData']; // Add the groups foreach ($arrFields as $k => $v) { // Deprecated since Contao 4.0, to be removed in Contao 5.0 $this->Template->{$k} = $v; $key = $k . ($k == 'personal' ? 'Data' : 'Details'); $arrGroups[$GLOBALS['TL_LANG']['tl_member'][$key]] = $v; } // Confirmation message if ($flashBag->has('mod_personal_data_confirm')) { $arrMessages = $flashBag->get('mod_personal_data_confirm'); $this->Template->message = $arrMessages[0]; } $this->Template->categories = $arrGroups; $this->Template->formId = $strFormId; $this->Template->slabel = specialchars($GLOBALS['TL_LANG']['MSC']['saveData']); $this->Template->action = \Environment::get('indexFreeRequest'); $this->Template->enctype = $hasUpload ? 'multipart/form-data' : 'application/x-www-form-urlencoded'; $this->Template->rowLast = 'row_' . $row . ($row % 2 == 0 ? ' even' : ' odd'); }