PageRenderTime 52ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/pdf/code/trunk/administrator/components/com_artofpdf/libraries/joomla/application/component/controller.php

https://bitbucket.org/eddieajau/the-art-of-joomla-archive
PHP | 827 lines | 377 code | 105 blank | 345 comment | 73 complexity | eb624c85de0452fe248e6f742cced50e MD5 | raw file
  1. <?php
  2. /**
  3. * @version $Id: controller.php 271 2010-09-09 08:35:10Z eddieajau $
  4. * @package Joomla.Framework
  5. * @subpackage Application
  6. * @copyright Copyright (C) 2005 - 2010 Open Source Matters, Inc. All rights reserved.
  7. * @license GNU General Public License version 2 or later; see LICENSE.txt
  8. */
  9. // No direct access.
  10. defined('JPATH_BASE') or die;
  11. /**
  12. * Base class for a Joomla Controller
  13. *
  14. * Controller (controllers are where you put all the actual code) Provides basic
  15. * functionality, such as rendering views (aka displaying templates).
  16. *
  17. * @abstract
  18. * @package Joomla.Framework
  19. * @subpackage Application
  20. * @since 1.5
  21. */
  22. class JController extends JObject
  23. {
  24. /**
  25. * ACO Section for the controller.
  26. *
  27. * @var string
  28. * @deprecated 1.6 - Apr 5, 2010
  29. */
  30. protected $_acoSection;
  31. /**
  32. * Default ACO Section value for the controller.
  33. *
  34. * @var string
  35. * @deprecated 1.6 - Apr 5, 2010
  36. */
  37. protected $_acoSectionValue;
  38. /**
  39. * The base path of the controller
  40. *
  41. * @var string
  42. * @since 1.6 Replaces _basePath.
  43. */
  44. protected $basePath;
  45. /**
  46. * @var string The default view for the display method.
  47. * @since 1.6
  48. */
  49. protected $default_view;
  50. /**
  51. * The mapped task that was performed.
  52. *
  53. * @var string
  54. * @since 1.6 Replaces _doTask.
  55. */
  56. protected $doTask;
  57. /**
  58. * Redirect message.
  59. *
  60. * @var string
  61. * @since 1.6 Replaces _message.
  62. */
  63. protected $message;
  64. /**
  65. * Redirect message type.
  66. *
  67. * @var string
  68. * @since 1.6 Replaces _messageType.
  69. */
  70. protected $messageType;
  71. /**
  72. * Array of class methods
  73. *
  74. * @var array
  75. * @since 1.6 Replaces _methods.
  76. */
  77. protected $methods;
  78. /**
  79. * The name of the controller
  80. *
  81. * @var array
  82. * @since 1.6 Replaces _name.
  83. */
  84. protected $name;
  85. /**
  86. * The set of search directories for resources (views).
  87. *
  88. * @var array
  89. * @since 1.6 Replaces _path.
  90. */
  91. protected $paths;
  92. /**
  93. * URL for redirection.
  94. *
  95. * @var string
  96. * @since 1.6 Replaces _redirect.
  97. */
  98. protected $redirect;
  99. /**
  100. * Current or most recent task to be performed.
  101. *
  102. * @var string
  103. * @since 1.6 Replaces _task.
  104. */
  105. protected $task;
  106. /**
  107. * Array of class methods to call for a given task.
  108. *
  109. * @var array
  110. * @since 1.6 Replaces _taskMap.
  111. */
  112. protected $taskMap;
  113. /**
  114. * Adds to the stack of model paths in LIFO order.
  115. *
  116. * @param string|array The directory (string), or list of directories (array) to add.
  117. * @return void
  118. */
  119. public static function addModelPath($path)
  120. {
  121. jimport('joomla.application.component.model');
  122. JModel::addIncludePath($path);
  123. }
  124. /**
  125. * Create the filename for a resource.
  126. *
  127. * @param string The resource type to create the filename for.
  128. * @param array An associative array of filename information. Optional.
  129. * @return string The filename.
  130. * @since 1.6 Replaced _createFileName.
  131. */
  132. protected static function createFileName($type, $parts = array())
  133. {
  134. $filename = '';
  135. switch ($type) {
  136. case 'controller':
  137. if (!empty($parts['format'])) {
  138. if ($parts['format'] == 'html') {
  139. $parts['format'] = '';
  140. } else {
  141. $parts['format'] = '.'.$parts['format'];
  142. }
  143. } else {
  144. $parts['format'] = '';
  145. }
  146. $filename = strtolower($parts['name']).$parts['format'].'.php';
  147. break;
  148. case 'view':
  149. if (!empty($parts['type'])) {
  150. $parts['type'] = '.'.$parts['type'];
  151. }
  152. $filename = strtolower($parts['name']).'/view'.$parts['type'].'.php';
  153. break;
  154. }
  155. return $filename;
  156. }
  157. /**
  158. * Method to get a singleton controller instance.
  159. *
  160. * @param string The prefix for the controller.
  161. * @param array An array of optional constructor options.
  162. * @return mixed JController derivative class or JException on error.
  163. * @since 1.6
  164. */
  165. public static function getInstance($prefix, $config = array())
  166. {
  167. static $instance;
  168. if (!empty($instance)) {
  169. return $instance;
  170. }
  171. // Get the environment configuration.
  172. $basePath = array_key_exists('base_path', $config) ? $config['base_path'] : JPATH_COMPONENT;
  173. $format = JRequest::getWord('format');
  174. $command = JRequest::getVar('task', 'display');
  175. // Check for array format.
  176. $filter = JFilterInput::getInstance();
  177. if (is_array($command)) {
  178. $command = $filter->clean(array_pop(array_keys($command)), 'cmd');
  179. } else {
  180. $command = $filter->clean($command, 'cmd');
  181. }
  182. // Check for a controller.task command.
  183. if (strpos($command, '.') !== false) {
  184. // Explode the controller.task command.
  185. list($type, $task) = explode('.', $command);
  186. // Define the controller filename and path.
  187. $file = self::createFileName('controller', array('name' => $type, 'format' => $format));
  188. $path = $basePath.'/controllers/'.$file;
  189. // Reset the task without the contoller context.
  190. JRequest::setVar('task', $task);
  191. } else {
  192. // Base controller.
  193. $type = null;
  194. $task = $command;
  195. // Define the controller filename and path.
  196. $file = self::createFileName('controller', array('name' => 'controller'));
  197. $path = $basePath.'/'.$file;
  198. }
  199. // Get the controller class name.
  200. $class = ucfirst($prefix).'Controller'.ucfirst($type);
  201. // Include the class if not present.
  202. if (!class_exists($class)) {
  203. // If the controller file path exists, include it.
  204. if (file_exists($path)) {
  205. require_once $path;
  206. } else {
  207. throw new JException(JText::sprintf('JLIB_APPLICATION_ERROR_INVALID_CONTROLLER', $type, $format), 1056, E_ERROR, $type, true);
  208. }
  209. }
  210. // Instantiate the class.
  211. if (class_exists($class)) {
  212. $instance = new $class($config);
  213. } else {
  214. throw new JException(JText::sprintf('JLIB_APPLICATION_ERROR_INVALID_CONTROLLER_CLASS', $class), 1057, E_ERROR, $class, true);
  215. }
  216. return $instance;
  217. }
  218. /**
  219. * Constructor.
  220. *
  221. * @param array An optional associative array of configuration settings.
  222. * Recognized key values include 'name', 'default_task', 'model_path', and
  223. * 'view_path' (this list is not meant to be comprehensive).
  224. * @since 1.5
  225. */
  226. public function __construct($config = array())
  227. {
  228. // Initialise variables.
  229. $this->methods = array();
  230. $this->message = null;
  231. $this->messageType = 'message';
  232. $this->paths = array();
  233. $this->redirect = null;
  234. $this->taskMap = array();
  235. // Determine the methods to exclude from the base class.
  236. $xMethods = get_class_methods('JController');
  237. // Get the public methods in this class using reflection.
  238. $r = new ReflectionClass($this);
  239. $rName = $r->getName();
  240. $rMethods = $r->getMethods(ReflectionMethod::IS_PUBLIC);
  241. $methods = array();
  242. foreach ($rMethods as $rMethod) {
  243. $mName = $rMethod->getName();
  244. // Add default display method if not explicitly declared.
  245. if (!in_array($mName, $xMethods) || $mName == 'display') {
  246. $this->methods[] = strtolower($mName);
  247. // Auto register the methods as tasks.
  248. $this->taskMap[strtolower($mName)] = $mName;
  249. }
  250. }
  251. //set the view name
  252. if (empty($this->name)) {
  253. if (array_key_exists('name', $config)) {
  254. $this->name = $config['name'];
  255. } else {
  256. $this->name = $this->getName();
  257. }
  258. }
  259. // Set a base path for use by the controller
  260. if (array_key_exists('base_path', $config)) {
  261. $this->basePath = $config['base_path'];
  262. } else {
  263. $this->basePath = JPATH_COMPONENT;
  264. }
  265. // If the default task is set, register it as such
  266. if (array_key_exists('default_task', $config)) {
  267. $this->registerDefaultTask($config['default_task']);
  268. } else {
  269. $this->registerDefaultTask('display');
  270. }
  271. // set the default model search path
  272. if (array_key_exists('model_path', $config)) {
  273. // user-defined dirs
  274. $this->addModelPath($config['model_path']);
  275. } else {
  276. $this->addModelPath($this->basePath.'/models');
  277. }
  278. // set the default view search path
  279. if (array_key_exists('view_path', $config)) {
  280. // user-defined dirs
  281. $this->setPath('view', $config['view_path']);
  282. } else {
  283. $this->setPath('view', $this->basePath.'/views');
  284. }
  285. // Set the default view.
  286. if (array_key_exists('default_view', $config)) {
  287. $this->default_view = $config['default_view'];
  288. } else if (empty($this->default_view)) {
  289. $this->default_view = $this->getName();
  290. }
  291. }
  292. /**
  293. * Adds to the search path for templates and resources.
  294. *
  295. * @param string The path type (e.g. 'model', 'view'.
  296. * @param string|array The directory or stream to search.
  297. * @return JController This object to support chaining.
  298. * @since 1.6 Replaces _addPath.
  299. */
  300. protected function addPath($type, $path)
  301. {
  302. // just force path to array
  303. settype($path, 'array');
  304. if (!isset($this->paths[$type])) {
  305. $this->paths[$type] = array();
  306. }
  307. // loop through the path directories
  308. foreach ($path as $dir) {
  309. // no surrounding spaces allowed!
  310. // J1.5 Compatibility
  311. JPath::check($dir);
  312. $dir = rtrim(JPath::clean($dir, '/'), '/').'/';
  313. //$dir = rtrim(JPath::check($dir, '/'), '/').'/';
  314. // add to the top of the search dirs
  315. array_unshift($this->paths[$type], $dir);
  316. }
  317. return $this;
  318. }
  319. /**
  320. * Add one or more view paths to the controller's stack, in LIFO order.
  321. *
  322. * @param string|array The directory (string), or list of directories (array) to add.
  323. * @return JController This object to support chaining.
  324. */
  325. public function addViewPath($path)
  326. {
  327. $this->addPath('view', $path);
  328. return $this;
  329. }
  330. /**
  331. * Authorization check
  332. *
  333. * @param string $task The ACO Section Value to check access on
  334. * @return boolean True if authorized
  335. * @since 1.5
  336. * @deprecated 1.6 - Apr 5, 2010
  337. */
  338. public function authorize($task)
  339. {
  340. $this->authorise($task);
  341. }
  342. /**
  343. * Authorisation check
  344. *
  345. * @param string $task The ACO Section Value to check access on
  346. * @return boolean True if authorised
  347. * @since 1.6
  348. */
  349. public function authorise($task)
  350. {
  351. // Only do access check if the aco section is set
  352. if ($this->_acoSection) {
  353. // If we have a section value set that trumps the passed task ???
  354. if ($this->_acoSectionValue) {
  355. // We have one, so set it and lets do the check
  356. $task = $this->_acoSectionValue;
  357. }
  358. // Get the JUser object for the current user and return the authorization boolean
  359. $user = JFactory::getUser();
  360. return $user->authorise($this->_acoSection, $task);
  361. } else {
  362. // Nothing set, nothing to check... so obviously its ok :)
  363. return true;
  364. }
  365. }
  366. /**
  367. * Method to load and return a model object.
  368. *
  369. * @param string The name of the model.
  370. * @param string Optional model prefix.
  371. * @param array Configuration array for the model. Optional.
  372. * @return mixed Model object on success; otherwise null failure.
  373. * @since 1.6 Replaces _createModel.
  374. */
  375. protected function createModel($name, $prefix = '', $config = array())
  376. {
  377. // Clean the model name
  378. $modelName = preg_replace('/[^A-Z0-9_]/i', '', $name);
  379. $classPrefix = preg_replace('/[^A-Z0-9_]/i', '', $prefix);
  380. $result = JModel::getInstance($modelName, $classPrefix, $config);
  381. return $result;
  382. }
  383. /**
  384. * Method to load and return a view object. This method first looks in the
  385. * current template directory for a match, and failing that uses a default
  386. * set path to load the view class file.
  387. *
  388. * Note the "name, prefix, type" order of parameters, which differs from the
  389. * "name, type, prefix" order used in related public methods.
  390. *
  391. * @param string The name of the view.
  392. * @param string Optional prefix for the view class name.
  393. * @param string The type of view.
  394. * @param array Configuration array for the view. Optional.
  395. * @return mixed View object on success; null or error result on failure.
  396. * @since 1.6 Replaces _createView.
  397. */
  398. protected function createView($name, $prefix = '', $type = '', $config = array())
  399. {
  400. // Clean the view name
  401. $viewName = preg_replace('/[^A-Z0-9_]/i', '', $name);
  402. $classPrefix = preg_replace('/[^A-Z0-9_]/i', '', $prefix);
  403. $viewType = preg_replace('/[^A-Z0-9_]/i', '', $type);
  404. // Build the view class name
  405. $viewClass = $classPrefix . $viewName;
  406. if (!class_exists($viewClass)) {
  407. jimport('joomla.filesystem.path');
  408. $path = JPath::find(
  409. $this->paths['view'],
  410. $this->createFileName('view', array('name' => $viewName, 'type' => $viewType))
  411. );
  412. if ($path) {
  413. require_once $path;
  414. if (!class_exists($viewClass)) {
  415. $result = JError::raiseError(
  416. 500, JText::sprintf('JLIB_APPLICATION_ERROR_VIEW_CLASS_NOT_FOUND', $viewClass, $path));
  417. return null;
  418. }
  419. } else {
  420. return null;
  421. }
  422. }
  423. return new $viewClass($config);
  424. }
  425. /**
  426. * Typical view method for MVC based architecture
  427. *
  428. * This function is provide as a default implementation, in most cases
  429. * you will need to override it in your own controllers.
  430. *
  431. * @param boolean If true, the view output will be cached
  432. * @param array An array of safe url parameters and their variable types, for valid values see {@link JFilterInput::clean()}.
  433. *
  434. * @return JController This object to support chaining.
  435. * @since 1.5
  436. */
  437. public function display($cachable = false, $urlparams = false)
  438. {
  439. $document = JFactory::getDocument();
  440. $viewType = $document->getType();
  441. $viewName = JRequest::getCmd('view', $this->default_view);
  442. $viewLayout = JRequest::getCmd('layout', 'default');
  443. $view = $this->getView($viewName, $viewType, '', array('base_path' => $this->basePath));
  444. // Get/Create the model
  445. if ($model = $this->getModel($viewName)) {
  446. // Push the model into the view (as default)
  447. $view->setModel($model, true);
  448. }
  449. // Set the layout
  450. $view->setLayout($viewLayout);
  451. $view->assignRef('document', $document);
  452. $conf = JFactory::getConfig();
  453. // Display the view
  454. if ($cachable && $viewType != 'feed' && $conf->get('caching') >= 1) {
  455. $option = JRequest::getCmd('option');
  456. $cache = JFactory::getCache($option, 'view');
  457. if (is_array($urlparams)) {
  458. $app = JFactory::getApplication();
  459. $registeredurlparams = $app->get('registeredurlparams');
  460. if (empty($registeredurlparams)) {
  461. $registeredurlparams = new stdClass();
  462. }
  463. foreach ($urlparams AS $key => $value) {
  464. // add your safe url parameters with variable type as value {@see JFilterInput::clean()}.
  465. $registeredurlparams->$key = $value;
  466. }
  467. $app->set('registeredurlparams', $registeredurlparams);
  468. }
  469. $cache->get($view, 'display');
  470. } else {
  471. $view->display();
  472. }
  473. return $this;
  474. }
  475. /**
  476. * Execute a task by triggering a method in the derived class.
  477. *
  478. * @param string The task to perform. If no matching task is found, the '__default' task is executed, if defined.
  479. * @return mixed|false The value returned by the called method, false in error case.
  480. * @since 1.5
  481. */
  482. public function execute($task)
  483. {
  484. $this->task = $task;
  485. $task = strtolower($task);
  486. if (isset($this->taskMap[$task])) {
  487. $doTask = $this->taskMap[$task];
  488. } elseif (isset($this->taskMap['__default'])) {
  489. $doTask = $this->taskMap['__default'];
  490. } else {
  491. return JError::raiseError(404, JText::sprintf('JLIB_APPLICATION_ERROR_TASK_NOT_FOUND', $task));
  492. }
  493. // Record the actual task being fired
  494. $this->doTask = $doTask;
  495. // Make sure we have access
  496. if ($this->authorise($doTask)) {
  497. $retval = $this->$doTask();
  498. return $retval;
  499. } else {
  500. return JError::raiseError(403, JText::_('JLIB_APPLICATION_ERROR_ACCESS_FORBIDDEN'));
  501. }
  502. }
  503. /**
  504. * Method to get a model object, loading it if required.
  505. *
  506. * @param string The model name. Optional.
  507. * @param string The class prefix. Optional.
  508. * @param array Configuration array for model. Optional.
  509. * @return object The model.
  510. * @since 1.5
  511. */
  512. public function getModel($name = '', $prefix = '', $config = array())
  513. {
  514. if (empty($name)) {
  515. $name = $this->getName();
  516. }
  517. if (empty($prefix)) {
  518. $prefix = $this->getName() . 'Model';
  519. }
  520. if ($model = $this->createModel($name, $prefix, $config)) {
  521. // task is a reserved state
  522. $model->setState('task', $this->task);
  523. // Lets get the application object and set menu information if its available
  524. $app = JFactory::getApplication();
  525. $menu = $app->getMenu();
  526. if (is_object($menu)) {
  527. if ($item = $menu->getActive()) {
  528. $params = $menu->getParams($item->id);
  529. // Set Default State Data
  530. $model->setState('parameters.menu', $params);
  531. }
  532. }
  533. }
  534. return $model;
  535. }
  536. /**
  537. * Method to get the controller name
  538. *
  539. * The dispatcher name by default parsed using the classname, or it can be set
  540. * by passing a $config['name'] in the class constructor
  541. *
  542. * @return string The name of the dispatcher
  543. * @since 1.5
  544. */
  545. public function getName()
  546. {
  547. $name = $this->name;
  548. if (empty($name)) {
  549. $r = null;
  550. if (!preg_match('/(.*)Controller/i', get_class($this), $r)) {
  551. JError::raiseError(500, JText::_('JLIB_APPLICATION_ERROR_CONTROLLER_GET_NAME'));
  552. }
  553. $name = strtolower($r[1]);
  554. }
  555. return $name;
  556. }
  557. /**
  558. * Get the last task that is or was to be performed.
  559. *
  560. * @return string The task that was or is being performed.
  561. * @since 1.5
  562. */
  563. public function getTask()
  564. {
  565. return $this->task;
  566. }
  567. /**
  568. * Gets the available tasks in the controller.
  569. *
  570. * @return array Array[i] of task names.
  571. * @since 1.5
  572. */
  573. public function getTasks()
  574. {
  575. return $this->methods;
  576. }
  577. /**
  578. * Method to get a reference to the current view and load it if necessary.
  579. *
  580. * @param string The view name. Optional, defaults to the controller name.
  581. * @param string The view type. Optional.
  582. * @param string The class prefix. Optional.
  583. * @param array Configuration array for view. Optional.
  584. * @return object Reference to the view or an error.
  585. * @since 1.5
  586. */
  587. public function getView($name = '', $type = '', $prefix = '', $config = array())
  588. {
  589. static $views;
  590. if (!isset($views)) {
  591. $views = array();
  592. }
  593. if (empty($name)) {
  594. $name = $this->getName();
  595. }
  596. if (empty($prefix)) {
  597. $prefix = $this->getName() . 'View';
  598. }
  599. if (empty($views[$name])) {
  600. if ($view = $this->createView($name, $prefix, $type, $config)) {
  601. $views[$name] = & $view;
  602. } else {
  603. $result = JError::raiseError(
  604. 500, JText::sprintf('JLIB_APPLICATION_ERROR_VIEW_NOT_FOUND', $name, $type, $prefix));
  605. return $result;
  606. }
  607. }
  608. return $views[$name];
  609. }
  610. /**
  611. * Redirects the browser or returns false if no redirect is set.
  612. *
  613. * @return boolean False if no redirect exists.
  614. * @since 1.5
  615. */
  616. public function redirect()
  617. {
  618. if ($this->redirect) {
  619. $app = JFactory::getApplication();
  620. $app->redirect($this->redirect, $this->message, $this->messageType);
  621. }
  622. return false;
  623. }
  624. /**
  625. * Register the default task to perform if a mapping is not found.
  626. *
  627. * @param string The name of the method in the derived class to perform if a named task is not found.
  628. * @return JController This object to support chaining.
  629. * @since 1.5
  630. */
  631. public function registerDefaultTask($method)
  632. {
  633. $this->registerTask('__default', $method);
  634. return $this;
  635. }
  636. /**
  637. * Register (map) a task to a method in the class.
  638. *
  639. * @param string The task.
  640. * @param string The name of the method in the derived class to perform for this task.
  641. * @return JController This object to support chaining.
  642. * @since 1.5
  643. */
  644. public function registerTask($task, $method)
  645. {
  646. if (in_array(strtolower($method), $this->methods)) {
  647. $this->taskMap[strtolower($task)] = $method;
  648. }
  649. return $this;
  650. }
  651. /**
  652. * Sets the access control levels.
  653. *
  654. * @param string The ACO section (eg, the component).
  655. * @param string The ACO section value (if using a constant value).
  656. * @return void
  657. * @since 1.5
  658. * @deprecated 1.6 - Apr 5, 2010
  659. */
  660. public function setAccessControl($section, $value = null)
  661. {
  662. $this->_acoSection = $section;
  663. $this->_acoSectionValue = $value;
  664. }
  665. /**
  666. * Sets the internal message that is passed with a redirect
  667. *
  668. * @param string Message to display on redirect.
  669. * @param string Message type (since 1.6). Optional, defaults to 'message'.
  670. * @return string Previous message
  671. * @since 1.5
  672. */
  673. public function setMessage($text, $type = 'message')
  674. {
  675. $previous = $this->message;
  676. $this->message = $text;
  677. $this->messageType = $type;
  678. return $previous;
  679. }
  680. /**
  681. * Sets an entire array of search paths for resources.
  682. *
  683. * @param string The type of path to set, typically 'view' or 'model'.
  684. * @param string|array The new set of search paths. If null or false, resets to the current directory only.
  685. * @since 1.6 Replaces _setPath.
  686. */
  687. protected function setPath($type, $path)
  688. {
  689. // clear out the prior search dirs
  690. $this->paths[$type] = array();
  691. // actually add the user-specified directories
  692. $this->addPath($type, $path);
  693. }
  694. /**
  695. * Set a URL for browser redirection.
  696. *
  697. * @param string URL to redirect to.
  698. * @param string Message to display on redirect. Optional, defaults to value set internally by controller, if any.
  699. * @param string Message type. Optional, defaults to 'message'.
  700. * @return JController This object to support chaining.
  701. * @since 1.5
  702. */
  703. public function setRedirect($url, $msg = null, $type = null)
  704. {
  705. $this->redirect = $url;
  706. if ($msg !== null) {
  707. // controller may have set this directly
  708. $this->message = $msg;
  709. }
  710. // Ensure the type is not overwritten by a previous call to setMessage.
  711. if (empty($type)) {
  712. if (empty($this->messageType)) {
  713. $this->messageType = 'message';
  714. }
  715. }
  716. // If the type is explicitly set, set it.
  717. else {
  718. $this->messageType = $type;
  719. }
  720. return $this;
  721. }
  722. }