Layout.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Layout
  17. * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @license http://framework.zend.com/license/new-bsd New BSD License
  19. * @version $Id$
  20. */
  21. /**
  22. * Provide Layout support for MVC applications
  23. *
  24. * @category Zend
  25. * @package Zend_Layout
  26. * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  27. * @license http://framework.zend.com/license/new-bsd New BSD License
  28. */
  29. class Zend_Layout
  30. {
  31. /**
  32. * Placeholder container for layout variables
  33. * @var Zend_View_Helper_Placeholder_Container
  34. */
  35. protected $_container;
  36. /**
  37. * Key used to store content from 'default' named response segment
  38. * @var string
  39. */
  40. protected $_contentKey = 'content';
  41. /**
  42. * Are layouts enabled?
  43. * @var bool
  44. */
  45. protected $_enabled = true;
  46. /**
  47. * Helper class
  48. * @var string
  49. */
  50. protected $_helperClass = 'Zend_Layout_Controller_Action_Helper_Layout';
  51. /**
  52. * Inflector used to resolve layout script
  53. * @var Zend_Filter_Inflector
  54. */
  55. protected $_inflector;
  56. /**
  57. * Flag: is inflector enabled?
  58. * @var bool
  59. */
  60. protected $_inflectorEnabled = true;
  61. /**
  62. * Inflector target
  63. * @var string
  64. */
  65. protected $_inflectorTarget = ':script.:suffix';
  66. /**
  67. * Layout view
  68. * @var string
  69. */
  70. protected $_layout = 'layout';
  71. /**
  72. * Layout view script path
  73. * @var string
  74. */
  75. protected $_viewScriptPath = null;
  76. protected $_viewBasePath = null;
  77. protected $_viewBasePrefix = 'Layout_View';
  78. /**
  79. * Flag: is MVC integration enabled?
  80. * @var bool
  81. */
  82. protected $_mvcEnabled = true;
  83. /**
  84. * Instance registered with MVC, if any
  85. * @var Zend_Layout
  86. */
  87. protected static $_mvcInstance;
  88. /**
  89. * Flag: is MVC successful action only flag set?
  90. * @var bool
  91. */
  92. protected $_mvcSuccessfulActionOnly = true;
  93. /**
  94. * Plugin class
  95. * @var string
  96. */
  97. protected $_pluginClass = 'Zend_Layout_Controller_Plugin_Layout';
  98. /**
  99. * @var Zend_View_Interface
  100. */
  101. protected $_view;
  102. /**
  103. * View script suffix for layout script
  104. * @var string
  105. */
  106. protected $_viewSuffix = 'phtml';
  107. /**
  108. * Constructor
  109. *
  110. * Accepts either:
  111. * - A string path to layouts
  112. * - An array of options
  113. * - A Zend_Config object with options
  114. *
  115. * Layout script path, either as argument or as key in options, is
  116. * required.
  117. *
  118. * If mvcEnabled flag is false from options, simply sets layout script path.
  119. * Otherwise, also instantiates and registers action helper and controller
  120. * plugin.
  121. *
  122. * @param string|array|Zend_Config $options
  123. * @return void
  124. */
  125. public function __construct($options = null, $initMvc = false)
  126. {
  127. if (null !== $options) {
  128. if (is_string($options)) {
  129. $this->setLayoutPath($options);
  130. } elseif (is_array($options)) {
  131. $this->setOptions($options);
  132. } elseif ($options instanceof Zend_Config) {
  133. $this->setConfig($options);
  134. } else {
  135. require_once 'Zend/Layout/Exception.php';
  136. throw new Zend_Layout_Exception('Invalid option provided to constructor');
  137. }
  138. }
  139. $this->_initVarContainer();
  140. if ($initMvc) {
  141. $this->_setMvcEnabled(true);
  142. $this->_initMvc();
  143. } else {
  144. $this->_setMvcEnabled(false);
  145. }
  146. }
  147. /**
  148. * Static method for initialization with MVC support
  149. *
  150. * @param string|array|Zend_Config $options
  151. * @return Zend_Layout
  152. */
  153. public static function startMvc($options = null)
  154. {
  155. if (null === self::$_mvcInstance) {
  156. self::$_mvcInstance = new self($options, true);
  157. }
  158. if (is_string($options)) {
  159. self::$_mvcInstance->setLayoutPath($options);
  160. } elseif (is_array($options) || $options instanceof Zend_Config) {
  161. self::$_mvcInstance->setOptions($options);
  162. }
  163. return self::$_mvcInstance;
  164. }
  165. /**
  166. * Retrieve MVC instance of Zend_Layout object
  167. *
  168. * @return Zend_Layout|null
  169. */
  170. public static function getMvcInstance()
  171. {
  172. return self::$_mvcInstance;
  173. }
  174. /**
  175. * Reset MVC instance
  176. *
  177. * Unregisters plugins and helpers, and destroys MVC layout instance.
  178. *
  179. * @return void
  180. */
  181. public static function resetMvcInstance()
  182. {
  183. if (null !== self::$_mvcInstance) {
  184. $layout = self::$_mvcInstance;
  185. $pluginClass = $layout->getPluginClass();
  186. $front = Zend_Controller_Front::getInstance();
  187. if ($front->hasPlugin($pluginClass)) {
  188. $front->unregisterPlugin($pluginClass);
  189. }
  190. if (Zend_Controller_Action_HelperBroker::hasHelper('layout')) {
  191. Zend_Controller_Action_HelperBroker::removeHelper('layout');
  192. }
  193. unset($layout);
  194. self::$_mvcInstance = null;
  195. }
  196. }
  197. /**
  198. * Set options en masse
  199. *
  200. * @param array|Zend_Config $options
  201. * @return void
  202. */
  203. public function setOptions($options)
  204. {
  205. if ($options instanceof Zend_Config) {
  206. $options = $options->toArray();
  207. } elseif (!is_array($options)) {
  208. require_once 'Zend/Layout/Exception.php';
  209. throw new Zend_Layout_Exception('setOptions() expects either an array or a Zend_Config object');
  210. }
  211. foreach ($options as $key => $value) {
  212. $method = 'set' . ucfirst($key);
  213. if (method_exists($this, $method)) {
  214. $this->$method($value);
  215. }
  216. }
  217. }
  218. /**
  219. * Initialize MVC integration
  220. *
  221. * @return void
  222. */
  223. protected function _initMvc()
  224. {
  225. $this->_initPlugin();
  226. $this->_initHelper();
  227. }
  228. /**
  229. * Initialize front controller plugin
  230. *
  231. * @return void
  232. */
  233. protected function _initPlugin()
  234. {
  235. $pluginClass = $this->getPluginClass();
  236. require_once 'Zend/Controller/Front.php';
  237. $front = Zend_Controller_Front::getInstance();
  238. if (!$front->hasPlugin($pluginClass)) {
  239. if (!class_exists($pluginClass)) {
  240. require_once 'Zend/Loader.php';
  241. Zend_Loader::loadClass($pluginClass);
  242. }
  243. $front->registerPlugin(
  244. // register to run last | BUT before the ErrorHandler (if its available)
  245. new $pluginClass($this),
  246. 99
  247. );
  248. }
  249. }
  250. /**
  251. * Initialize action helper
  252. *
  253. * @return void
  254. */
  255. protected function _initHelper()
  256. {
  257. $helperClass = $this->getHelperClass();
  258. require_once 'Zend/Controller/Action/HelperBroker.php';
  259. if (!Zend_Controller_Action_HelperBroker::hasHelper('layout')) {
  260. if (!class_exists($helperClass)) {
  261. require_once 'Zend/Loader.php';
  262. Zend_Loader::loadClass($helperClass);
  263. }
  264. Zend_Controller_Action_HelperBroker::getStack()->offsetSet(-90, new $helperClass($this));
  265. }
  266. }
  267. /**
  268. * Set options from a config object
  269. *
  270. * @param Zend_Config $config
  271. * @return Zend_Layout
  272. */
  273. public function setConfig(Zend_Config $config)
  274. {
  275. $this->setOptions($config->toArray());
  276. return $this;
  277. }
  278. /**
  279. * Initialize placeholder container for layout vars
  280. *
  281. * @return Zend_View_Helper_Placeholder_Container
  282. */
  283. protected function _initVarContainer()
  284. {
  285. if (null === $this->_container) {
  286. require_once 'Zend/View/Helper/Placeholder/Registry.php';
  287. $this->_container = Zend_View_Helper_Placeholder_Registry::getRegistry()->getContainer(__CLASS__);
  288. }
  289. return $this->_container;
  290. }
  291. /**
  292. * Set layout script to use
  293. *
  294. * Note: enables layout.
  295. *
  296. * @param string $name
  297. * @return Zend_Layout
  298. */
  299. public function setLayout($name)
  300. {
  301. $this->_layout = (string) $name;
  302. $this->enableLayout();
  303. return $this;
  304. }
  305. /**
  306. * Get current layout script
  307. *
  308. * @return string
  309. */
  310. public function getLayout()
  311. {
  312. return $this->_layout;
  313. }
  314. /**
  315. * Disable layout
  316. *
  317. * @return Zend_Layout
  318. */
  319. public function disableLayout()
  320. {
  321. $this->_enabled = false;
  322. return $this;
  323. }
  324. /**
  325. * Enable layout
  326. *
  327. * @return Zend_Layout
  328. */
  329. public function enableLayout()
  330. {
  331. $this->_enabled = true;
  332. return $this;
  333. }
  334. /**
  335. * Is layout enabled?
  336. *
  337. * @return bool
  338. */
  339. public function isEnabled()
  340. {
  341. return $this->_enabled;
  342. }
  343. public function setViewBasePath($path, $prefix = 'Layout_View')
  344. {
  345. $this->_viewBasePath = $path;
  346. $this->_viewBasePrefix = $prefix;
  347. return $this;
  348. }
  349. public function getViewBasePath()
  350. {
  351. return $this->_viewBasePath;
  352. }
  353. public function setViewScriptPath($path)
  354. {
  355. $this->_viewScriptPath = $path;
  356. return $this;
  357. }
  358. public function getViewScriptPath()
  359. {
  360. return $this->_viewScriptPath;
  361. }
  362. /**
  363. * Set layout script path
  364. *
  365. * @param string $path
  366. * @return Zend_Layout
  367. */
  368. public function setLayoutPath($path)
  369. {
  370. return $this->setViewScriptPath($path);
  371. }
  372. /**
  373. * Get current layout script path
  374. *
  375. * @return string
  376. */
  377. public function getLayoutPath()
  378. {
  379. return $this->getViewScriptPath();
  380. }
  381. /**
  382. * Set content key
  383. *
  384. * Key in namespace container denoting default content
  385. *
  386. * @param string $contentKey
  387. * @return Zend_Layout
  388. */
  389. public function setContentKey($contentKey)
  390. {
  391. $this->_contentKey = (string) $contentKey;
  392. return $this;
  393. }
  394. /**
  395. * Retrieve content key
  396. *
  397. * @return string
  398. */
  399. public function getContentKey()
  400. {
  401. return $this->_contentKey;
  402. }
  403. /**
  404. * Set MVC enabled flag
  405. *
  406. * @param bool $mvcEnabled
  407. * @return Zend_Layout
  408. */
  409. protected function _setMvcEnabled($mvcEnabled)
  410. {
  411. $this->_mvcEnabled = ($mvcEnabled) ? true : false;
  412. return $this;
  413. }
  414. /**
  415. * Retrieve MVC enabled flag
  416. *
  417. * @return bool
  418. */
  419. public function getMvcEnabled()
  420. {
  421. return $this->_mvcEnabled;
  422. }
  423. /**
  424. * Set MVC Successful Action Only flag
  425. *
  426. * @param bool $successfulActionOnly
  427. * @return Zend_Layout
  428. */
  429. public function setMvcSuccessfulActionOnly($successfulActionOnly)
  430. {
  431. $this->_mvcSuccessfulActionOnly = ($successfulActionOnly) ? true : false;
  432. return $this;
  433. }
  434. /**
  435. * Get MVC Successful Action Only Flag
  436. *
  437. * @return bool
  438. */
  439. public function getMvcSuccessfulActionOnly()
  440. {
  441. return $this->_mvcSuccessfulActionOnly;
  442. }
  443. /**
  444. * Set view object
  445. *
  446. * @param Zend_View_Interface $view
  447. * @return Zend_Layout
  448. */
  449. public function setView(Zend_View_Interface $view)
  450. {
  451. $this->_view = $view;
  452. return $this;
  453. }
  454. /**
  455. * Retrieve helper class
  456. *
  457. * @return string
  458. */
  459. public function getHelperClass()
  460. {
  461. return $this->_helperClass;
  462. }
  463. /**
  464. * Set helper class
  465. *
  466. * @param string $helperClass
  467. * @return Zend_Layout
  468. */
  469. public function setHelperClass($helperClass)
  470. {
  471. $this->_helperClass = (string) $helperClass;
  472. return $this;
  473. }
  474. /**
  475. * Retrieve plugin class
  476. *
  477. * @return string
  478. */
  479. public function getPluginClass()
  480. {
  481. return $this->_pluginClass;
  482. }
  483. /**
  484. * Set plugin class
  485. *
  486. * @param string $pluginClass
  487. * @return Zend_Layout
  488. */
  489. public function setPluginClass($pluginClass)
  490. {
  491. $this->_pluginClass = (string) $pluginClass;
  492. return $this;
  493. }
  494. /**
  495. * Get current view object
  496. *
  497. * If no view object currently set, retrieves it from the ViewRenderer.
  498. *
  499. * @todo Set inflector from view renderer at same time
  500. * @return Zend_View_Interface
  501. */
  502. public function getView()
  503. {
  504. if (null === $this->_view) {
  505. require_once 'Zend/Controller/Action/HelperBroker.php';
  506. $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
  507. if (null === $viewRenderer->view) {
  508. $viewRenderer->initView();
  509. }
  510. $this->setView($viewRenderer->view);
  511. }
  512. return $this->_view;
  513. }
  514. /**
  515. * Set layout view script suffix
  516. *
  517. * @param string $viewSuffix
  518. * @return Zend_Layout
  519. */
  520. public function setViewSuffix($viewSuffix)
  521. {
  522. $this->_viewSuffix = (string) $viewSuffix;
  523. return $this;
  524. }
  525. /**
  526. * Retrieve layout view script suffix
  527. *
  528. * @return string
  529. */
  530. public function getViewSuffix()
  531. {
  532. return $this->_viewSuffix;
  533. }
  534. /**
  535. * Retrieve inflector target
  536. *
  537. * @return string
  538. */
  539. public function getInflectorTarget()
  540. {
  541. return $this->_inflectorTarget;
  542. }
  543. /**
  544. * Set inflector target
  545. *
  546. * @param string $inflectorTarget
  547. * @return Zend_Layout
  548. */
  549. public function setInflectorTarget($inflectorTarget)
  550. {
  551. $this->_inflectorTarget = (string) $inflectorTarget;
  552. return $this;
  553. }
  554. /**
  555. * Set inflector to use when resolving layout names
  556. *
  557. * @param Zend_Filter_Inflector $inflector
  558. * @return Zend_Layout
  559. */
  560. public function setInflector(Zend_Filter_Inflector $inflector)
  561. {
  562. $this->_inflector = $inflector;
  563. return $this;
  564. }
  565. /**
  566. * Retrieve inflector
  567. *
  568. * @return Zend_Filter_Inflector
  569. */
  570. public function getInflector()
  571. {
  572. if (null === $this->_inflector) {
  573. require_once 'Zend/Filter/Inflector.php';
  574. $inflector = new Zend_Filter_Inflector();
  575. $inflector->setTargetReference($this->_inflectorTarget)
  576. ->addRules(array(':script' => array('Word_CamelCaseToDash', 'StringToLower')))
  577. ->setStaticRuleReference('suffix', $this->_viewSuffix);
  578. $this->setInflector($inflector);
  579. }
  580. return $this->_inflector;
  581. }
  582. /**
  583. * Enable inflector
  584. *
  585. * @return Zend_Layout
  586. */
  587. public function enableInflector()
  588. {
  589. $this->_inflectorEnabled = true;
  590. return $this;
  591. }
  592. /**
  593. * Disable inflector
  594. *
  595. * @return Zend_Layout
  596. */
  597. public function disableInflector()
  598. {
  599. $this->_inflectorEnabled = false;
  600. return $this;
  601. }
  602. /**
  603. * Return status of inflector enabled flag
  604. *
  605. * @return bool
  606. */
  607. public function inflectorEnabled()
  608. {
  609. return $this->_inflectorEnabled;
  610. }
  611. /**
  612. * Set layout variable
  613. *
  614. * @param string $key
  615. * @param mixed $value
  616. * @return void
  617. */
  618. public function __set($key, $value)
  619. {
  620. $this->_container[$key] = $value;
  621. }
  622. /**
  623. * Get layout variable
  624. *
  625. * @param string $key
  626. * @return mixed
  627. */
  628. public function __get($key)
  629. {
  630. if (isset($this->_container[$key])) {
  631. return $this->_container[$key];
  632. }
  633. return null;
  634. }
  635. /**
  636. * Is a layout variable set?
  637. *
  638. * @param string $key
  639. * @return bool
  640. */
  641. public function __isset($key)
  642. {
  643. return (isset($this->_container[$key]));
  644. }
  645. /**
  646. * Unset a layout variable?
  647. *
  648. * @param string $key
  649. * @return void
  650. */
  651. public function __unset($key)
  652. {
  653. if (isset($this->_container[$key])) {
  654. unset($this->_container[$key]);
  655. }
  656. }
  657. /**
  658. * Assign one or more layout variables
  659. *
  660. * @param mixed $spec Assoc array or string key; if assoc array, sets each
  661. * key as a layout variable
  662. * @param mixed $value Value if $spec is a key
  663. * @return Zend_Layout
  664. * @throws Zend_Layout_Exception if non-array/string value passed to $spec
  665. */
  666. public function assign($spec, $value = null)
  667. {
  668. if (is_array($spec)) {
  669. $orig = $this->_container->getArrayCopy();
  670. $merged = array_merge($orig, $spec);
  671. $this->_container->exchangeArray($merged);
  672. return $this;
  673. }
  674. if (is_string($spec)) {
  675. $this->_container[$spec] = $value;
  676. return $this;
  677. }
  678. require_once 'Zend/Layout/Exception.php';
  679. throw new Zend_Layout_Exception('Invalid values passed to assign()');
  680. }
  681. /**
  682. * Render layout
  683. *
  684. * Sets internal script path as last path on script path stack, assigns
  685. * layout variables to view, determines layout name using inflector, and
  686. * renders layout view script.
  687. *
  688. * $name will be passed to the inflector as the key 'script'.
  689. *
  690. * @param mixed $name
  691. * @return mixed
  692. */
  693. public function render($name = null)
  694. {
  695. if (null === $name) {
  696. $name = $this->getLayout();
  697. }
  698. if ($this->inflectorEnabled() && (null !== ($inflector = $this->getInflector())))
  699. {
  700. $name = $this->_inflector->filter(array('script' => $name));
  701. }
  702. $view = $this->getView();
  703. if (null !== ($path = $this->getViewScriptPath())) {
  704. if (method_exists($view, 'addScriptPath')) {
  705. $view->addScriptPath($path);
  706. } else {
  707. $view->setScriptPath($path);
  708. }
  709. } elseif (null !== ($path = $this->getViewBasePath())) {
  710. $view->addBasePath($path, $this->_viewBasePrefix);
  711. }
  712. return $view->render($name);
  713. }
  714. }