PageRenderTime 54ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/libraries/joomla/application/component/view.php

https://github.com/joebushi/joomla
PHP | 682 lines | 277 code | 77 blank | 328 comment | 48 complexity | 237e791663521272ddc811144490b301 MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0
  1. <?php
  2. /**
  3. * @version $Id$
  4. * @package Joomla.Framework
  5. * @subpackage Application
  6. * @copyright Copyright Copyright (C) 2005 - 2010 Open Source Matters. 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 View
  13. *
  14. * Class holding methods for displaying presentation data.
  15. *
  16. * @abstract
  17. * @package Joomla.Framework
  18. * @subpackage Application
  19. * @since 1.5
  20. */
  21. class JView extends JObject
  22. {
  23. /**
  24. * The name of the view
  25. *
  26. * @var array
  27. * @access protected
  28. */
  29. var $_name = null;
  30. /**
  31. * Registered models
  32. *
  33. * @var array
  34. * @access protected
  35. */
  36. var $_models = array();
  37. /**
  38. * The base path of the view
  39. *
  40. * @var string
  41. * @access protected
  42. */
  43. var $_basePath = null;
  44. /**
  45. * The default model
  46. *
  47. * @var string
  48. * @access protected
  49. */
  50. var $_defaultModel = null;
  51. /**
  52. * Layout name
  53. *
  54. * @var string
  55. * @access protected
  56. */
  57. var $_layout = 'default';
  58. /**
  59. * Layout extension
  60. *
  61. * @var string
  62. * @access protected
  63. */
  64. var $_layoutExt = 'php';
  65. /**
  66. * The set of search directories for resources (templates)
  67. *
  68. * @var array
  69. * @access protected
  70. */
  71. var $_path = array(
  72. 'template' => array(),
  73. 'helper' => array()
  74. );
  75. /**
  76. * The name of the default template source file.
  77. *
  78. * @var string
  79. * @access private
  80. */
  81. var $_template = null;
  82. /**
  83. * The output of the template script.
  84. *
  85. * @var string
  86. * @access private
  87. */
  88. var $_output = null;
  89. /**
  90. * Callback for escaping.
  91. *
  92. * @var string
  93. * @access private
  94. */
  95. var $_escape = 'htmlspecialchars';
  96. /**
  97. * Charset to use in escaping mechanisms; defaults to urf8 (UTF-8)
  98. *
  99. * @var string
  100. * @access private
  101. */
  102. var $_charset = 'UTF-8';
  103. /**
  104. * Constructor
  105. *
  106. * @access protected
  107. */
  108. function __construct($config = array())
  109. {
  110. //set the view name
  111. if (empty($this->_name))
  112. {
  113. if (array_key_exists('name', $config)) {
  114. $this->_name = $config['name'];
  115. } else {
  116. $this->_name = $this->getName();
  117. }
  118. }
  119. // set the charset (used by the variable escaping functions)
  120. if (array_key_exists('charset', $config)) {
  121. $this->_charset = $config['charset'];
  122. }
  123. // user-defined escaping callback
  124. if (array_key_exists('escape', $config)) {
  125. $this->setEscape($config['escape']);
  126. }
  127. // Set a base path for use by the view
  128. if (array_key_exists('base_path', $config)) {
  129. $this->_basePath = $config['base_path'];
  130. } else {
  131. $this->_basePath = JPATH_COMPONENT;
  132. }
  133. // set the default template search path
  134. if (array_key_exists('template_path', $config)) {
  135. // user-defined dirs
  136. $this->_setPath('template', $config['template_path']);
  137. } else {
  138. $this->_setPath('template', $this->_basePath.DS.'views'.DS.$this->getName().DS.'tmpl');
  139. }
  140. // set the default helper search path
  141. if (array_key_exists('helper_path', $config)) {
  142. // user-defined dirs
  143. $this->_setPath('helper', $config['helper_path']);
  144. } else {
  145. $this->_setPath('helper', $this->_basePath.DS.'helpers');
  146. }
  147. // set the layout
  148. if (array_key_exists('layout', $config)) {
  149. $this->setLayout($config['layout']);
  150. } else {
  151. $this->setLayout('default');
  152. }
  153. $this->baseurl = JURI::base(true);
  154. }
  155. /**
  156. * Execute and display a template script.
  157. *
  158. * @param string $tpl The name of the template file to parse;
  159. * automatically searches through the template paths.
  160. *
  161. * @throws object An JError object.
  162. * @see fetch()
  163. */
  164. function display($tpl = null)
  165. {
  166. $result = $this->loadTemplate($tpl);
  167. if (JError::isError($result)) {
  168. return $result;
  169. }
  170. echo $result;
  171. }
  172. /**
  173. * Assigns variables to the view script via differing strategies.
  174. *
  175. * This method is overloaded; you can assign all the properties of
  176. * an object, an associative array, or a single value by name.
  177. *
  178. * You are not allowed to set variables that begin with an underscore;
  179. * these are either private properties for JView or private variables
  180. * within the template script itself.
  181. *
  182. * <code>
  183. * $view = new JView();
  184. *
  185. * // assign directly
  186. * $view->var1 = 'something';
  187. * $view->var2 = 'else';
  188. *
  189. * // assign by name and value
  190. * $view->assign('var1', 'something');
  191. * $view->assign('var2', 'else');
  192. *
  193. * // assign by assoc-array
  194. * $ary = array('var1' => 'something', 'var2' => 'else');
  195. * $view->assign($obj);
  196. *
  197. * // assign by object
  198. * $obj = new stdClass;
  199. * $obj->var1 = 'something';
  200. * $obj->var2 = 'else';
  201. * $view->assign($obj);
  202. *
  203. * </code>
  204. *
  205. * @access public
  206. * @return bool True on success, false on failure.
  207. */
  208. function assign()
  209. {
  210. // get the arguments; there may be 1 or 2.
  211. $arg0 = @func_get_arg(0);
  212. $arg1 = @func_get_arg(1);
  213. // assign by object
  214. if (is_object($arg0))
  215. {
  216. // assign public properties
  217. foreach (get_object_vars($arg0) as $key => $val)
  218. {
  219. if (substr($key, 0, 1) != '_') {
  220. $this->$key = $val;
  221. }
  222. }
  223. return true;
  224. }
  225. // assign by associative array
  226. if (is_array($arg0))
  227. {
  228. foreach ($arg0 as $key => $val)
  229. {
  230. if (substr($key, 0, 1) != '_') {
  231. $this->$key = $val;
  232. }
  233. }
  234. return true;
  235. }
  236. // assign by string name and mixed value.
  237. // we use array_key_exists() instead of isset() becuase isset()
  238. // fails if the value is set to null.
  239. if (is_string($arg0) && substr($arg0, 0, 1) != '_' && func_num_args() > 1)
  240. {
  241. $this->$arg0 = $arg1;
  242. return true;
  243. }
  244. // $arg0 was not object, array, or string.
  245. return false;
  246. }
  247. /**
  248. * Assign variable for the view (by reference).
  249. *
  250. * You are not allowed to set variables that begin with an underscore;
  251. * these are either private properties for JView or private variables
  252. * within the template script itself.
  253. *
  254. * <code>
  255. * $view = new JView();
  256. *
  257. * // assign by name and value
  258. * $view->assignRef('var1', $ref);
  259. *
  260. * // assign directly
  261. * $view->ref = &$var1;
  262. * </code>
  263. *
  264. * @access public
  265. *
  266. * @param string $key The name for the reference in the view.
  267. * @param mixed &$val The referenced variable.
  268. *
  269. * @return bool True on success, false on failure.
  270. */
  271. function assignRef($key, &$val)
  272. {
  273. if (is_string($key) && substr($key, 0, 1) != '_')
  274. {
  275. $this->$key = &$val;
  276. return true;
  277. }
  278. return false;
  279. }
  280. /**
  281. * Escapes a value for output in a view script.
  282. *
  283. * If escaping mechanism is one of htmlspecialchars or htmlentities, uses
  284. * {@link $_encoding} setting.
  285. *
  286. * @param mixed $var The output to escape.
  287. * @return mixed The escaped value.
  288. */
  289. function escape($var)
  290. {
  291. if (in_array($this->_escape, array('htmlspecialchars', 'htmlentities'))) {
  292. return call_user_func($this->_escape, $var, ENT_COMPAT, $this->_charset);
  293. }
  294. return call_user_func($this->_escape, $var);
  295. }
  296. /**
  297. * Method to get data from a registered model or a property of the view
  298. *
  299. * @param string The name of the method to call on the model, or the property to get
  300. * @param string The name of the model to reference, or the default value [optional]
  301. * @return mixed The return value of the method
  302. */
  303. public function get($property, $default = null)
  304. {
  305. // If $model is null we use the default model
  306. if (is_null($default)) {
  307. $model = $this->_defaultModel;
  308. } else {
  309. $model = strtolower($default);
  310. }
  311. // First check to make sure the model requested exists
  312. if (isset($this->_models[$model]))
  313. {
  314. // Model exists, lets build the method name
  315. $method = 'get'.ucfirst($property);
  316. // Does the method exist?
  317. if (method_exists($this->_models[$model], $method))
  318. {
  319. // The method exists, lets call it and return what we get
  320. $result = $this->_models[$model]->$method();
  321. return $result;
  322. }
  323. }
  324. // degrade to JObject::get
  325. $result = parent::get($property, $default);
  326. return $result;
  327. }
  328. /**
  329. * Method to get the model object
  330. *
  331. * @access public
  332. * @param string $name The name of the model (optional)
  333. * @return mixed JModel object
  334. */
  335. function getModel($name = null)
  336. {
  337. if ($name === null) {
  338. $name = $this->_defaultModel;
  339. }
  340. return $this->_models[strtolower($name)];
  341. }
  342. /**
  343. * Get the layout.
  344. *
  345. * @access public
  346. * @return string The layout name
  347. */
  348. function getLayout()
  349. {
  350. return $this->_layout;
  351. }
  352. /**
  353. * Method to get the view name
  354. *
  355. * The model name by default parsed using the classname, or it can be set
  356. * by passing a $config['name'] in the class constructor
  357. *
  358. * @access public
  359. * @return string The name of the model
  360. * @since 1.5
  361. */
  362. function getName()
  363. {
  364. $name = $this->_name;
  365. if (empty($name))
  366. {
  367. $r = null;
  368. if (!preg_match('/View((view)*(.*(view)?.*))$/i', get_class($this), $r)) {
  369. JError::raiseError (500, "JView::getName() : Cannot get or parse class name.");
  370. }
  371. if (strpos($r[3], "view"))
  372. {
  373. JError::raiseWarning('SOME_ERROR_CODE',"JView::getName() : Your classname contains the substring 'view'. ".
  374. "This causes problems when extracting the classname from the name of your objects view. " .
  375. "Avoid Object names with the substring 'view'.");
  376. }
  377. $name = strtolower($r[3]);
  378. }
  379. return $name;
  380. }
  381. /**
  382. * Method to add a model to the view. We support a multiple model single
  383. * view system by which models are referenced by classname. A caveat to the
  384. * classname referencing is that any classname prepended by JModel will be
  385. * referenced by the name without JModel, eg. JModelCategory is just
  386. * Category.
  387. *
  388. * @access public
  389. * @param object $model The model to add to the view.
  390. * @param boolean $default Is this the default model?
  391. * @return object The added model
  392. */
  393. function setModel(&$model, $default = false)
  394. {
  395. $name = strtolower($model->getName());
  396. $this->_models[$name] = &$model;
  397. if ($default) {
  398. $this->_defaultModel = $name;
  399. }
  400. return $model;
  401. }
  402. /**
  403. * Sets the layout name to use
  404. *
  405. * @access public
  406. * @param string $template The template name.
  407. * @return string Previous value
  408. * @since 1.5
  409. */
  410. function setLayout($layout)
  411. {
  412. $previous = $this->_layout;
  413. $this->_layout = $layout;
  414. return $previous;
  415. }
  416. /**
  417. * Allows a different extension for the layout files to be used
  418. *
  419. * @access public
  420. * @param string The extension
  421. * @return string Previous value
  422. * @since 1.5
  423. */
  424. function setLayoutExt($value)
  425. {
  426. $previous = $this->_layoutExt;
  427. if ($value = preg_replace('#[^A-Za-z0-9]#', '', trim($value))) {
  428. $this->_layoutExt = $value;
  429. }
  430. return $previous;
  431. }
  432. /**
  433. * Sets the _escape() callback.
  434. *
  435. * @param mixed $spec The callback for _escape() to use.
  436. */
  437. function setEscape($spec)
  438. {
  439. $this->_escape = $spec;
  440. }
  441. /**
  442. * Adds to the stack of view script paths in LIFO order.
  443. *
  444. * @param string|array The directory (-ies) to add.
  445. * @return void
  446. */
  447. function addTemplatePath($path)
  448. {
  449. $this->_addPath('template', $path);
  450. }
  451. /**
  452. * Adds to the stack of helper script paths in LIFO order.
  453. *
  454. * @param string|array The directory (-ies) to add.
  455. * @return void
  456. */
  457. function addHelperPath($path)
  458. {
  459. $this->_addPath('helper', $path);
  460. }
  461. /**
  462. * Load a template file -- first look in the templates folder for an override
  463. *
  464. * @access public
  465. * @param string $tpl The name of the template source file ...
  466. * automatically searches the template paths and compiles as needed.
  467. * @return string The output of the the template script.
  468. */
  469. function loadTemplate($tpl = null)
  470. {
  471. // clear prior output
  472. $this->_output = null;
  473. //create the template file name based on the layout
  474. $file = isset($tpl) ? $this->_layout.'_'.$tpl : $this->_layout;
  475. // clean the file name
  476. $file = preg_replace('/[^A-Z0-9_\.-]/i', '', $file);
  477. $tpl = preg_replace('/[^A-Z0-9_\.-]/i', '', $tpl);
  478. // load the template script
  479. jimport('joomla.filesystem.path');
  480. $filetofind = $this->_createFileName('template', array('name' => $file));
  481. $this->_template = JPath::find($this->_path['template'], $filetofind);
  482. if ($this->_template != false)
  483. {
  484. // unset so as not to introduce into template scope
  485. unset($tpl);
  486. unset($file);
  487. // never allow a 'this' property
  488. if (isset($this->this)) {
  489. unset($this->this);
  490. }
  491. // start capturing output into a buffer
  492. ob_start();
  493. // include the requested template filename in the local scope
  494. // (this will execute the view logic).
  495. include $this->_template;
  496. // done with the requested template; get the buffer and
  497. // clear it.
  498. $this->_output = ob_get_contents();
  499. ob_end_clean();
  500. return $this->_output;
  501. }
  502. else {
  503. return JError::raiseError(500, 'Layout "' . $file . '" not found');
  504. }
  505. }
  506. /**
  507. * Load a helper file
  508. *
  509. * @access public
  510. * @param string $tpl The name of the helper source file ...
  511. * automatically searches the helper paths and compiles as needed.
  512. * @return boolean Returns true if the file was loaded
  513. */
  514. function loadHelper($hlp = null)
  515. {
  516. // clean the file name
  517. $file = preg_replace('/[^A-Z0-9_\.-]/i', '', $hlp);
  518. // load the template script
  519. jimport('joomla.filesystem.path');
  520. $helper = JPath::find($this->_path['helper'], $this->_createFileName('helper', array('name' => $file)));
  521. if ($helper != false)
  522. {
  523. // include the requested template filename in the local scope
  524. include_once $helper;
  525. }
  526. }
  527. /**
  528. * Sets an entire array of search paths for templates or resources.
  529. *
  530. * @access protected
  531. * @param string $type The type of path to set, typically 'template'.
  532. * @param string|array $path The new set of search paths. If null or
  533. * false, resets to the current directory only.
  534. */
  535. function _setPath($type, $path)
  536. {
  537. jimport('joomla.application.helper');
  538. $component = JApplicationHelper::getComponentName();
  539. $app = &JFactory::getApplication();
  540. // clear out the prior search dirs
  541. $this->_path[$type] = array();
  542. // actually add the user-specified directories
  543. $this->_addPath($type, $path);
  544. // always add the fallback directories as last resort
  545. switch (strtolower($type))
  546. {
  547. case 'template':
  548. // Set the alternative template search dir
  549. if (isset($app))
  550. {
  551. $component = preg_replace('/[^A-Z0-9_\.-]/i', '', $component);
  552. $fallback = JPATH_BASE.DS.'templates'.DS.$app->getTemplate().DS.'html'.DS.$component.DS.$this->getName();
  553. $this->_addPath('template', $fallback);
  554. }
  555. break;
  556. }
  557. }
  558. /**
  559. * Adds to the search path for templates and resources.
  560. *
  561. * @access protected
  562. * @param string|array $path The directory or stream to search.
  563. */
  564. function _addPath($type, $path)
  565. {
  566. // just force to array
  567. settype($path, 'array');
  568. // loop through the path directories
  569. foreach ($path as $dir)
  570. {
  571. // no surrounding spaces allowed!
  572. $dir = trim($dir);
  573. // add trailing separators as needed
  574. if (substr($dir, -1) != DIRECTORY_SEPARATOR) {
  575. // directory
  576. $dir .= DIRECTORY_SEPARATOR;
  577. }
  578. // add to the top of the search dirs
  579. array_unshift($this->_path[$type], $dir);
  580. }
  581. }
  582. /**
  583. * Create the filename for a resource
  584. *
  585. * @access private
  586. * @param string $type The resource type to create the filename for
  587. * @param array $parts An associative array of filename information
  588. * @return string The filename
  589. * @since 1.5
  590. */
  591. function _createFileName($type, $parts = array())
  592. {
  593. $filename = '';
  594. switch($type)
  595. {
  596. case 'template' :
  597. $filename = strtolower($parts['name']).'.'.$this->_layoutExt;
  598. break;
  599. default :
  600. $filename = strtolower($parts['name']).'.php';
  601. break;
  602. }
  603. return $filename;
  604. }
  605. }