/libraries/joomla/application/component/controllerform.php
https://bitbucket.org/pasamio/jauthentication · PHP · 591 lines · 288 code · 95 blank · 208 comment · 46 complexity · 9b7be36a5b025ab4d272a3aef0bf743a MD5 · raw file
- <?php
- /**
- * @package Joomla.Platform
- * @subpackage Application
- *
- * @copyright Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved.
- * @license GNU General Public License version 2 or later; see LICENSE
- */
- defined('JPATH_PLATFORM') or die;
- jimport('joomla.application.component.controller');
- // @TODO Add ability to set redirect manually to better cope with frontend usage.
- /**
- * Controller tailored to suit most form-based admin operations.
- *
- * @package Joomla.Platform
- * @subpackage Application
- * @since 11.1
- */
- class JControllerForm extends JController
- {
- /**
- * @var string The context for storing internal data, e.g. record.
- * @since 11.1
- */
- protected $context;
- /**
- * @var string The URL option for the component.
- * @since 11.1
- */
- protected $option;
- /**
- * @var string The URL view item variable.
- * @since 11.1
- */
- protected $view_item;
- /**
- * @var string The URL view list variable.
- * @since 11.1
- */
- protected $view_list;
- /**
- * @var string The prefix to use with controller messages.
- * @since 11.1
- */
- protected $text_prefix;
- /**
- * Constructor.
- *
- * @param array An optional associative array of configuration settings.
- *
- * @return JControllerForm
- * @see JController
- * @since 11.1
- */
- public function __construct($config = array())
- {
- parent::__construct($config);
- // Guess the option as com_NameOfController
- if (empty($this->option)) {
- $this->option = 'com_'.strtolower($this->getName());
- }
- // Guess the JText message prefix. Defaults to the option.
- if (empty($this->text_prefix)) {
- $this->text_prefix = strtoupper($this->option);
- }
- // Guess the context as the suffix, eg: OptionControllerContent.
- if (empty($this->context)) {
- $r = null;
- if (!preg_match('/(.*)Controller(.*)/i', get_class($this), $r)) {
- JError::raiseError(500, JText::_('JLIB_APPLICATION_ERROR_CONTROLLER_GET_NAME'));
- }
- $this->context = strtolower($r[2]);
- }
- // Guess the item view as the context.
- if (empty($this->view_item)) {
- $this->view_item = $this->context;
- }
- // Guess the list view as the plural of the item view.
- if (empty($this->view_list)) {
- // @TODO Probably worth moving to an inflector class based on
- // http://kuwamoto.org/2007/12/17/improved-pluralizing-in-php-actionscript-and-ror/
- // Simple pluralisation based on public domain snippet by Paul Osman
- // For more complex types, just manually set the variable in your class.
- $plural = array(
- array( '/(x|ch|ss|sh)$/i', "$1es"),
- array( '/([^aeiouy]|qu)y$/i', "$1ies"),
- array( '/([^aeiouy]|qu)ies$/i', "$1y"),
- array( '/(bu)s$/i', "$1ses"),
- array( '/s$/i', "s"),
- array( '/$/', "s")
- );
- // check for matches using regular expressions
- foreach ($plural as $pattern)
- {
- if (preg_match($pattern[0], $this->view_item)) {
- $this->view_list = preg_replace( $pattern[0], $pattern[1], $this->view_item);
- break;
- }
- }
- }
- // Apply, Save & New, and Save As copy should be standard on forms.
- $this->registerTask('apply', 'save');
- $this->registerTask('save2new', 'save');
- $this->registerTask('save2copy', 'save');
- }
- /**
- * Method to add a new record.
- *
- * @return mixed True if the record can be added, a JError object if not.
- * @since 11.1
- */
- public function add()
- {
- // Initialise variables.
- $app = JFactory::getApplication();
- $context = "$this->option.edit.$this->context";
- // Access check.
- if (!$this->allowAdd()) {
- // Set the internal error and also the redirect error.
- $this->setError(JText::_('JLIB_APPLICATION_ERROR_CREATE_RECORD_NOT_PERMITTED'));
- $this->setMessage($this->getError(), 'error');
- $this->setRedirect(JRoute::_('index.php?option='.$this->option.'&view='.$this->view_list.$this->getRedirectToListAppend(), false));
- return false;
- }
- // Clear the record edit information from the session.
- $app->setUserState($context.'.data', null);
- // Redirect to the edit screen.
- $this->setRedirect(JRoute::_('index.php?option='.$this->option.'&view='.$this->view_item.$this->getRedirectToItemAppend(), false));
- return true;
- }
- /**
- * Method to check if you can add a new record.
- *
- * Extended classes can override this if necessary.
- *
- * @param array An array of input data.
- *
- * @return boolean
- * @since 11.1
- */
- protected function allowAdd($data = array())
- {
- $user = JFactory::getUser();
- return ($user->authorise('core.create', $this->option) ||
- count($user->getAuthorisedCategories($this->option, 'core.create')));
- }
- /**
- * Method to check if you can add a new record.
- *
- * Extended classes can override this if necessary.
- *
- * @param array An array of input data.
- * @param string The name of the key for the primary key.
- *
- * @return boolean
- * @since 11.1
- */
- protected function allowEdit($data = array(), $key = 'id')
- {
- return JFactory::getUser()->authorise('core.edit', $this->option);
- }
- /**
- * Method to check if you can save a new or existing record.
- *
- * Extended classes can override this if necessary.
- *
- * @param array An array of input data.
- * @param string The name of the key for the primary key.
- *
- * @return boolean
- * @since 11.1
- */
- protected function allowSave($data, $key = 'id')
- {
- // Initialise variables.
- $recordId = isset($data[$key]) ? $data[$key] : '0';
- if ($recordId) {
- return $this->allowEdit($data, $key);
- } else {
- return $this->allowAdd($data);
- }
- }
- /**
- * Method to cancel an edit.
- *
- * @param string $key The name of the primary key of the URL variable.
- *
- * @return Boolean True if access level checks pass, false otherwise.
- * @since 11.1
- */
- public function cancel($key = null)
- {
- JRequest::checkToken() or jexit(JText::_('JINVALID_TOKEN'));
- // Initialise variables.
- $app = JFactory::getApplication();
- $model = $this->getModel();
- $table = $model->getTable();
- $checkin = property_exists($table, 'checked_out');
- $context = "$this->option.edit.$this->context";
- if (empty($key)) {
- $key = $table->getKeyName();
- }
- $recordId = JRequest::getInt($key);
- // Attempt to check-in the current record.
- if ($recordId) {
- // Check we are holding the id in the edit list.
- if (!$this->checkEditId($context, $recordId)) {
- // Somehow the person just went to the form - we don't allow that.
- $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $recordId));
- $this->setMessage($this->getError(), 'error');
- $this->setRedirect(JRoute::_('index.php?option='.$this->option.'&view='.$this->view_list.$this->getRedirectToListAppend(), false));
- return false;
- }
- if ($checkin) {
- if ($model->checkin($recordId) === false) {
- // Check-in failed, go back to the record and display a notice.
- $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_CHECKIN_FAILED', $model->getError()));
- $this->setMessage($this->getError(), 'error');
- $this->setRedirect('index.php?option='.$this->option.'&view='.$this->view_item.$this->getRedirectToItemAppend($recordId, $key));
- return false;
- }
- }
- }
- // Clean the session data and redirect.
- $this->releaseEditId($context, $recordId);
- $app->setUserState($context.'.data', null);
- $this->setRedirect(JRoute::_('index.php?option='.$this->option.'&view='.$this->view_list.$this->getRedirectToListAppend(), false));
- return true;
- }
- /**
- * Method to edit an existing record.
- *
- * @param string $key The name of the primary key of the URL variable.
- * @param string $urlVar The name of the URL variable if different from the primary key (sometimes required to avoid router collisions).
- *
- * @return Boolean True if access level check and checkout passes, false otherwise.
- * @since 11.1
- */
- public function edit($key = null, $urlVar = null)
- {
- // Initialise variables.
- $app = JFactory::getApplication(); or was most recently performed
- $model = $this->getModel();
- $table = $model->getTable();
- $cid = JRequest::getVar('cid', array(), 'post', 'array');
- $context = "$this->option.edit.$this->context";
- $append = '';
- // Determine the name of the primary key for the data.
- if (empty($key)) {
- $key = $table->getKeyName();
- }
- // To avoid data collisions the urlVar may be different from the primary key.
- if (empty($urlVar)) {
- $urlVar = $key;
- }
- // Get the previous record id (if any) and the current record id.
- $recordId = (int) (count($cid) ? $cid[0] : JRequest::getInt($urlVar));
- $checkin = property_exists($table, 'checked_out');
- // Access check.
- if (!$this->allowEdit(array($key => $recordId), $key)) {
- $this->setError(JText::_('JLIB_APPLICATION_ERROR_EDIT_NOT_PERMITTED'));
- $this->setMessage($this->getError(), 'error');
- $this->setRedirect(JRoute::_('index.php?option='.$this->option.'&view='.$this->view_list.$this->getRedirectToListAppend(), false));
- return false;
- }
- // Attempt to check-out the new record for editing and redirect.
- if ($checkin && !$model->checkout($recordId)) {
- // Check-out failed, display a notice but allow the user to see the record.
- $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_CHECKOUT_FAILED', $model->getError()));
- $this->setMessage($this->getError(), 'error');
- $this->setRedirect('index.php?option='.$this->option.'&view='.$this->view_item.$this->getRedirectToItemAppend($recordId, $urlVar));
- return false;
- }
- else {
- // Check-out succeeded, push the new record id into the session.
- $this->holdEditId($context, $recordId);
- $app->setUserState($context.'.data', null);
- $this->setRedirect('index.php?option='.$this->option.'&view='.$this->view_item.$this->getRedirectToItemAppend($recordId, $urlVar));
- return true;
- }
- }
- /**
- * Method to get a model object, loading it if required.
- *
- * @param string $name The model name. Optional.
- * @param string $prefix The class prefix. Optional.
- * @param array $config Configuration array for model. Optional.
- *
- * @return object The model.
- * @since 11.1
- */
- public function getModel($name = '', $prefix = '', $config = array('ignore_request' => true))
- {
- if (empty($name)) {
- $name = $this->context;
- }
- return parent::getModel($name, $prefix, $config);
- }
- /**
- * Gets the URL arguments to append to an item redirect.
- *
- * @param int $recordId The primary key id for the item.
- * @param string $urlVar The name of the URL variable for the id.
- *
- * @return string The arguments to append to the redirect URL.
- * @since 11.1
- */
- protected function getRedirectToItemAppend($recordId = null, $urlVar = 'id')
- {
- $tmpl = JRequest::getCmd('tmpl');
- $layout = JRequest::getCmd('layout', 'edit');
- $append = '';
- // Setup redirect info.
- if ($tmpl) {
- $append .= '&tmpl='.$tmpl;
- }
- if ($layout) {
- $append .= '&layout='.$layout;
- }
- if ($recordId) {
- $append .= '&'.$urlVar.'='.$recordId;
- }
- return $append;
- }
- /**
- * Gets the URL arguments to append to a list redirect.
- *
- * @return string The arguments to append to the redirect URL.
- * @since 11.1
- */
- protected function getRedirectToListAppend()
- {
- $tmpl = JRequest::getCmd('tmpl');
- $append = '';
- // Setup redirect info.
- if ($tmpl) {
- $append .= '&tmpl='.$tmpl;
- }
- return $append;
- }
- /**
- * Function that allows child controller access to model data after the data has been saved.
- *
- * @param JModel $model The data model object.
- * @param array $validData The validated data.
- *
- * @return void
- * @since 11.1
- */
- protected function postSaveHook(JModel &$model, $validData = array())
- {
- }
- /**
- * Method to save a record.
- *
- * @param string $key The name of the primary key of the URL variable.
- * @param string $urlVar The name of the URL variable if different from the primary key (sometimes required to avoid router collisions).
- *
- * @return Boolean True if successful, false otherwise.
- * @since 11.1
- */
- public function save($key = null, $urlVar = null)
- {
- // Check for request forgeries.
- JRequest::checkToken() or jexit(JText::_('JINVALID_TOKEN'));
- // Initialise variables.
- $app = JFactory::getApplication();
- $lang = JFactory::getLanguage();
- $model = $this->getModel();
- $table = $model->getTable();
- $data = JRequest::getVar('jform', array(), 'post', 'array');
- $checkin = property_exists($table, 'checked_out');
- $context = "$this->option.edit.$this->context";
- $task = $this->getTask();
- // Determine the name of the primary key for the data.
- if (empty($key)) {
- $key = $table->getKeyName();
- }
- // To avoid data collisions the urlVar may be different from the primary key.
- if (empty($urlVar)) {
- $urlVar = $key;
- }
- $recordId = JRequest::getInt($urlVar);
- $session = JFactory::getSession();
- $registry = $session->get('registry');
- if (!$this->checkEditId($context, $recordId)) {
- // Somehow the person just went to the form and tried to save it. We don't allow that.
- $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $recordId));
- $this->setMessage($this->getError(), 'error');
- $this->setRedirect(JRoute::_('index.php?option='.$this->option.'&view='.$this->view_list.$this->getRedirectToListAppend(), false));
- return false;
- }
- // Populate the row id from the session.
- $data[$key] = $recordId;
- // The save2copy task needs to be handled slightly differently.
- if ($task == 'save2copy') {
- // Check-in the original row.
- if ($checkin && $model->checkin($data[$key]) === false) {
- // Check-in failed. Go back to the item and display a notice.
- $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_CHECKIN_FAILED', $model->getError()));
- $this->setMessage($this->getError(), 'error');
- $this->setRedirect('index.php?option='.$this->option.'&view='.$this->view_item.$this->getRedirectToItemAppend($recordId, $urlVar));
- return false;
- }
- // Reset the ID and then treat the request as for Apply.
- $data[$key] = 0;
- $task = 'apply';
- }
- // Access check.
- if (!$this->allowSave($data)) {
- $this->setError(JText::_('JLIB_APPLICATION_ERROR_SAVE_NOT_PERMITTED'));
- $this->setMessage($this->getError(), 'error');
- $this->setRedirect(JRoute::_('index.php?option='.$this->option.'&view='.$this->view_list.$this->getRedirectToListAppend(), false));
- return false;
- }
- // Validate the posted data.
- // Sometimes the form needs some posted data, such as for plugins and modules.
- $form = $model->getForm($data, false);
- if (!$form) {
- $app->enqueueMessage($model->getError(), 'error');
- return false;
- }
- // Test whether the data is valid.
- $validData = $model->validate($form, $data);
- // Check for validation errors.
- if ($validData === false) {
- // Get the validation messages.
- $errors = $model->getErrors();
- // Push up to three validation messages out to the user.
- for ($i = 0, $n = count($errors); $i < $n && $i < 3; $i++)
- {
- if (JError::isError($errors[$i])) {
- $app->enqueueMessage($errors[$i]->getMessage(), 'warning');
- }
- else {
- $app->enqueueMessage($errors[$i], 'warning');
- }
- }
- // Save the data in the session.
- $app->setUserState($context.'.data', $data);
- // Redirect back to the edit screen.
- $this->setRedirect(JRoute::_('index.php?option='.$this->option.'&view='.$this->view_item.$this->getRedirectToItemAppend($recordId, $key), false));
- return false;
- }
- // Attempt to save the data.
- if (!$model->save($validData)) {
- // Save the data in the session.
- $app->setUserState($context.'.data', $validData);
- // Redirect back to the edit screen.
- $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_SAVE_FAILED', $model->getError()));
- $this->setMessage($this->getError(), 'error');
- $this->setRedirect(JRoute::_('index.php?option='.$this->option.'&view='.$this->view_item.$this->getRedirectToItemAppend($recordId, $key), false));
- return false;
- }
- // Save succeeded, so check-in the record.
- if ($checkin && $model->checkin($validData[$key]) === false) {
- // Save the data in the session.
- $app->setUserState($context.'.data', $validData);
- // Check-in failed, so go back to the record and display a notice.
- $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_CHECKIN_FAILED', $model->getError()));
- $this->setMessage($this->getError(), 'error');
- $this->setRedirect('index.php?option='.$this->option.'&view='.$this->view_item.$this->getRedirectToItemAppend($recordId, $key));
- return false;
- }
- $this->setMessage(JText::_(($lang->hasKey($this->text_prefix.($recordId==0 && $app->isSite() ? '_SUBMIT' : '').'_SAVE_SUCCESS') ? $this->text_prefix : 'JLIB_APPLICATION') . ($recordId==0 && $app->isSite() ? '_SUBMIT' : '') . '_SAVE_SUCCESS'));
- // Redirect the user and adjust session state based on the chosen task.
- switch ($task)
- {
- case 'apply':
- // Set the record data in the session.
- $recordId = $model->getState($this->context.'.id');
- $this->holdEditId($context, $recordId);
- $app->setUserState($context.'.data', null);
- // Redirect back to the edit screen.
- $this->setRedirect(JRoute::_('index.php?option='.$this->option.'&view='.$this->view_item.$this->getRedirectToItemAppend($recordId, $key), false));
- break;
- case 'save2new':
- // Clear the record id and data from the session.
- $this->releaseEditId($context, $recordId);
- $app->setUserState($context.'.data', null);
- // Redirect back to the edit screen.
- $this->setRedirect(JRoute::_('index.php?option='.$this->option.'&view='.$this->view_item.$this->getRedirectToItemAppend(null, $key), false));
- break;
- default:
- // Clear the record id and data from the session.
- $this->releaseEditId($context, $recordId);
- $app->setUserState($context.'.data', null);
- // Redirect to the list screen.
- $this->setRedirect(JRoute::_('index.php?option='.$this->option.'&view='.$this->view_list.$this->getRedirectToListAppend(), false));
- break;
- }
- // Invoke the postSave method to allow for the child class to access the model.
- $this->postSaveHook($model, $validData);
- return true;
- }
- }