requiredLocale = $requiredLocale; if ($supportedLocales === null) $supportedLocales = AppLocale::getSupportedFormLocales(); $this->supportedLocales = $supportedLocales; $this->defaultLocale = AppLocale::getLocale(); $this->_template = $template; $this->_data = array(); $this->_checks = array(); $this->_errors = array(); $this->errorsArray = array(); $this->errorFields = array(); $this->formSectionErrors = array(); if ($callHooks === true) { // Call hooks based on the calling entity, assuming // this method is only called by a subclass. Results // in hook calls named e.g. "papergalleyform::Constructor" // Note that class names are always lower case. HookRegistry::call(strtolower_codesafe(get_class($this)) . '::Constructor', array($this, &$template)); } } // // Setters and Getters // /** * Set the template * @param $template string */ function setTemplate($template) { $this->_template = $template; } /** * Get the template * @return string */ function getTemplate() { return $this->_template; } /** * Get the required locale for this form (i.e. the locale for which * required fields must be set, all others being optional) * @return string */ function getRequiredLocale() { return $this->requiredLocale; } // // Public Methods // /** * Display the form. * @param $request PKPRequest * @param $template string the template to be rendered, mandatory * if no template has been specified on class instantiation. */ function display($request = null, $template = null) { $this->fetch($request, $template, true); } /** * Returns a string of the rendered form * @param $request PKPRequest * @param $template string the template to be rendered, mandatory * if no template has been specified on class instantiation. * @param $display boolean * @return string the rendered form */ function fetch($request, $template = null, $display = false) { // Set custom template. if (!is_null($template)) $this->_template = $template; // Call hooks based on the calling entity, assuming // this method is only called by a subclass. Results // in hook calls named e.g. "papergalleyform::display" // Note that class names are always lower case. $returner = null; if (HookRegistry::call(strtolower_codesafe(get_class($this)) . '::display', array($this, &$returner))) { return $returner; } $templateMgr = TemplateManager::getManager($request); $templateMgr->setCacheability(CACHEABILITY_NO_STORE); // Attach this form object to the Form Builder Vocabulary for validation to work $fbv = $templateMgr->getFBV(); $fbv->setForm($this); $templateMgr->assign(array_merge( $this->_data, array( 'isError' => !$this->isValid(), 'errors' => $this->getErrorsArray(), 'formLocales' => $this->supportedLocales, 'formLocale' => $this->getFormLocale(), ) )); $templateMgr->register_function('form_language_chooser', array($this, 'smartyFormLanguageChooser')); if ($display) { $templateMgr->display($this->_template); $returner = null; } else { $returner = $templateMgr->fetch($this->_template); } // Reset the FBV's form in case template manager fetches another template not within a form. $fbv->setForm(null); return $returner; } /** * Get the value of a form field. * @param $key string * @return mixed */ function getData($key) { return isset($this->_data[$key]) ? $this->_data[$key] : null; } /** * Set the value of one or several form fields. * @param $key string|array If a string, then set a single field. If an associative array, then set many. * @param $value mixed */ function setData($key, $value = null) { if (is_array($key)) foreach($key as $aKey => $aValue) { $this->setData($aKey, $aValue); } else { if (is_string($value)) $value = Core::cleanVar($value); $this->_data[$key] = $value; } } /** * Initialize form data for a new form. */ function initData() { // Call hooks based on the calling entity, assuming // this method is only called by a subclass. Results // in hook calls named e.g. "papergalleyform::initData" // Note that class and function names are always lower // case. HookRegistry::call(strtolower_codesafe(get_class($this) . '::initData'), array($this)); } /** * Assign form data to user-submitted data. * Can be overridden from subclasses. */ function readInputData() { // Default implementation does nothing. } /** * Validate form data. */ function validate($callHooks = true) { if (!isset($this->errorsArray)) { $this->getErrorsArray(); } foreach ($this->_checks as $check) { if (!isset($this->errorsArray[$check->getField()]) && !$check->isValid()) { if (method_exists($check, 'getErrorFields') && method_exists($check, 'isArray') && call_user_func(array(&$check, 'isArray'))) { $errorFields = call_user_func(array(&$check, 'getErrorFields')); for ($i=0, $count=count($errorFields); $i < $count; $i++) { $this->addError($errorFields[$i], $check->getMessage()); $this->errorFields[$errorFields[$i]] = 1; } } else { $this->addError($check->getField(), $check->getMessage()); $this->errorFields[$check->getField()] = 1; } } } if ($callHooks === true) { // Call hooks based on the calling entity, assuming // this method is only called by a subclass. Results // in hook calls named e.g. "papergalleyform::validate" // Note that class and function names are always lower // case. $value = null; if (HookRegistry::call(strtolower_codesafe(get_class($this) . '::validate'), array($this, &$value))) { return $value; } } if (!defined('SESSION_DISABLE_INIT')) { $application = PKPApplication::getApplication(); $request = $application->getRequest(); $user = $request->getUser(); if (!$this->isValid() && $user) { // Create a form error notification. import('classes.notification.NotificationManager'); $notificationManager = new NotificationManager(); $notificationManager->createTrivialNotification( $user->getId(), NOTIFICATION_TYPE_FORM_ERROR, array('contents' => $this->getErrorsArray()) ); } } return $this->isValid(); } /** * Execute the form's action. * (Note that it is assumed that the form has already been validated.) */ function execute() { // Call hooks based on the calling entity, assuming // this method is only called by a subclass. Results // in hook calls named e.g. "papergalleyform::execute" // Note that class and function names are always lower // case. $returner = null; HookRegistry::call(strtolower_codesafe(get_class($this) . '::execute'), array_merge(array($this), func_get_args(), array(&$returner))); return $returner; } /** * Get the list of field names that need to support multiple locales * @return array */ function getLocaleFieldNames() { // Call hooks based on the calling entity, assuming // this method is only called by a subclass. Results // in hook calls named e.g. "papergalleyform::getLocaleFieldNames" // Note that class and function names are always lower // case. $returner = array(); HookRegistry::call(strtolower_codesafe(get_class($this) . '::getLocaleFieldNames'), array($this, &$returner)); return $returner; } /** * Determine whether or not the current request results from a resubmit * of locale data resulting from a form language change. * @return boolean */ function isLocaleResubmit() { $formLocale = Request::getUserVar('formLocale'); return (!empty($formLocale)); } /** * Get the default form locale. * @return string */ function getDefaultFormLocale() { $formLocale = $this->defaultLocale; if (!isset($this->supportedLocales[$formLocale])) $formLocale = $this->requiredLocale; return $formLocale; } /** * Set the default form locale. * @param $defaultLocale string */ function setDefaultFormLocale($defaultLocale) { $this->defaultLocale = $defaultLocale; } /** * Get the current form locale. * @return string */ function getFormLocale() { $formLocale = Request::getUserVar('formLocale'); if (!$formLocale || !isset($this->supportedLocales[$formLocale])) { $formLocale = $this->getDefaultFormLocale(); } return $formLocale; } /** * Adds specified user variables to input data. * @param $vars array the names of the variables to read */ function readUserVars($vars) { // Call hooks based on the calling entity, assuming // this method is only called by a subclass. Results // in hook calls named e.g. "papergalleyform::readUserVars" // Note that class and function names are always lower // case. HookRegistry::call(strtolower_codesafe(get_class($this) . '::readUserVars'), array($this, &$vars)); foreach ($vars as $k) { $this->setData($k, Request::getUserVar($k)); } } /** * Add a validation check to the form. * @param $formValidator FormValidator */ function addCheck($formValidator) { $this->_checks[] =& $formValidator; } /** * Add an error to the form. * Errors are typically assigned as the form is validated. * @param $field string the name of the field where the error occurred */ function addError($field, $message) { $this->_errors[] = new FormError($field, $message); } /** * Add an error field for highlighting on form * @param $field string the name of the field where the error occurred */ function addErrorField($field) { $this->errorFields[$field] = 1; } /** * Check if form passes all validation checks. * @return boolean */ function isValid() { return empty($this->_errors); } /** * Return set of errors that occurred in form validation. * If multiple errors occurred processing a single field, only the first error is included. * @return array erroneous fields and associated error messages */ function getErrorsArray() { $this->errorsArray = array(); foreach ($this->_errors as $error) { if (!isset($this->errorsArray[$error->getField()])) { $this->errorsArray[$error->getField()] = $error->getMessage(); } } return $this->errorsArray; } /** * Add hidden form parameters for the localized fields for this form * and display the language chooser field * @param $params array * @param $smarty object */ function smartyFormLanguageChooser($params, &$smarty) { $returner = ''; // Print back all non-current language field values so that they // are not lost. $formLocale = $this->getFormLocale(); foreach ($this->getLocaleFieldNames() as $field) { $values = $this->getData($field); if (!is_array($values)) continue; foreach ($values as $locale => $value) { if ($locale != $formLocale) $returner .= $this->_decomposeArray($field, $value, array($locale)); } } // Display the language selector widget. $returner .= '
'; return $returner; } // // Private helper methods // /** * Convert PHP variable (literals or arrays) into HTML containing * hidden input fields. * @param $name string Name of variable * @param $value mixed Value of variable * @param $stack array Names of array keys (for recursive calling) * @return string HTML hidden form elements describing the parameters. */ function _decomposeArray($name, $value, $stack) { $returner = ''; if (is_array($value)) { foreach ($value as $key => $subValue) { $newStack = $stack; $newStack[] = $key; $returner .= $this->_decomposeArray($name, $subValue, $newStack); } } else { $name = htmlentities($name, ENT_COMPAT, LOCALE_ENCODING); $value = htmlentities($value, ENT_COMPAT, LOCALE_ENCODING); $returner .= '\n"; } return $returner; } } ?>