Layout.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  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-2008 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-2008 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. } elseif (is_string($options)) {
  158. self::$_mvcInstance->setLayoutPath($options);
  159. } else {
  160. self::$_mvcInstance->setOptions($options);
  161. }
  162. return self::$_mvcInstance;
  163. }
  164. /**
  165. * Retrieve MVC instance of Zend_Layout object
  166. *
  167. * @return Zend_Layout|null
  168. */
  169. public static function getMvcInstance()
  170. {
  171. return self::$_mvcInstance;
  172. }
  173. /**
  174. * Reset MVC instance
  175. *
  176. * Unregisters plugins and helpers, and destroys MVC layout instance.
  177. *
  178. * @return void
  179. */
  180. public static function resetMvcInstance()
  181. {
  182. if (null !== self::$_mvcInstance) {
  183. $layout = self::$_mvcInstance;
  184. $pluginClass = $layout->getPluginClass();
  185. $front = Zend_Controller_Front::getInstance();
  186. if ($front->hasPlugin($pluginClass)) {
  187. $front->unregisterPlugin($pluginClass);
  188. }
  189. if (Zend_Controller_Action_HelperBroker::hasHelper('layout')) {
  190. Zend_Controller_Action_HelperBroker::removeHelper('layout');
  191. }
  192. unset($layout);
  193. self::$_mvcInstance = null;
  194. }
  195. }
  196. /**
  197. * Set options en masse
  198. *
  199. * @param array $options
  200. * @return void
  201. */
  202. public function setOptions($options)
  203. {
  204. if ($options instanceof Zend_Config) {
  205. $options = $options->toArray();
  206. } elseif (!is_array($options)) {
  207. require_once 'Zend/Layout/Exception.php';
  208. throw new Zend_Layout_Exception('setOptions() expects either an array or a Zend_Config object');
  209. }
  210. foreach ($options as $key => $value) {
  211. $method = 'set' . ucfirst($key);
  212. if (method_exists($this, $method)) {
  213. $this->$method($value);
  214. }
  215. }
  216. }
  217. /**
  218. * Initialize MVC integration
  219. *
  220. * @return void
  221. */
  222. protected function _initMvc()
  223. {
  224. $this->_initPlugin();
  225. $this->_initHelper();
  226. }
  227. /**
  228. * Initialize front controller plugin
  229. *
  230. * @return void
  231. */
  232. protected function _initPlugin()
  233. {
  234. $pluginClass = $this->getPluginClass();
  235. require_once 'Zend/Controller/Front.php';
  236. $front = Zend_Controller_Front::getInstance();
  237. if (!$front->hasPlugin($pluginClass)) {
  238. require_once 'Zend/Loader.php';
  239. Zend_Loader::loadClass($pluginClass);
  240. $front->registerPlugin(
  241. // register to run last | BUT before the ErrorHandler (if its available)
  242. new $pluginClass($this),
  243. 99
  244. );
  245. }
  246. }
  247. /**
  248. * Initialize action helper
  249. *
  250. * @return void
  251. */
  252. protected function _initHelper()
  253. {
  254. $helperClass = $this->getHelperClass();
  255. require_once 'Zend/Controller/Action/HelperBroker.php';
  256. if (!Zend_Controller_Action_HelperBroker::hasHelper('layout')) {
  257. require_once 'Zend/Loader.php';
  258. Zend_Loader::loadClass($helperClass);
  259. Zend_Controller_Action_HelperBroker::getStack()->offsetSet(-90, new $helperClass($this));
  260. }
  261. }
  262. /**
  263. * Set options from a config object
  264. *
  265. * @param Zend_Config $config
  266. * @return Zend_Layout
  267. */
  268. public function setConfig(Zend_Config $config)
  269. {
  270. $this->setOptions($config->toArray());
  271. return $this;
  272. }
  273. /**
  274. * Initialize placeholder container for layout vars
  275. *
  276. * @return Zend_View_Helper_Placeholder_Container
  277. */
  278. protected function _initVarContainer()
  279. {
  280. if (null === $this->_container) {
  281. require_once 'Zend/View/Helper/Placeholder/Registry.php';
  282. $this->_container = Zend_View_Helper_Placeholder_Registry::getRegistry()->getContainer(__CLASS__);
  283. }
  284. return $this->_container;
  285. }
  286. /**
  287. * Set layout script to use
  288. *
  289. * Note: enables layout.
  290. *
  291. * @param string $name
  292. * @return Zend_Layout
  293. */
  294. public function setLayout($name)
  295. {
  296. $this->_layout = (string) $name;
  297. $this->enableLayout();
  298. return $this;
  299. }
  300. /**
  301. * Get current layout script
  302. *
  303. * @return string
  304. */
  305. public function getLayout()
  306. {
  307. return $this->_layout;
  308. }
  309. /**
  310. * Disable layout
  311. *
  312. * @return Zend_Layout
  313. */
  314. public function disableLayout()
  315. {
  316. $this->_enabled = false;
  317. return $this;
  318. }
  319. /**
  320. * Enable layout
  321. *
  322. * @return Zend_Layout
  323. */
  324. public function enableLayout()
  325. {
  326. $this->_enabled = true;
  327. return $this;
  328. }
  329. /**
  330. * Is layout enabled?
  331. *
  332. * @return bool
  333. */
  334. public function isEnabled()
  335. {
  336. return $this->_enabled;
  337. }
  338. public function setViewBasePath($path, $prefix = 'Layout_View')
  339. {
  340. $this->_viewBasePath = $path;
  341. $this->_viewBasePrefix = $prefix;
  342. return $this;
  343. }
  344. public function getViewBasePath()
  345. {
  346. return $this->_viewBasePath;
  347. }
  348. public function setViewScriptPath($path)
  349. {
  350. $this->_viewScriptPath = $path;
  351. return $this;
  352. }
  353. public function getViewScriptPath()
  354. {
  355. return $this->_viewScriptPath;
  356. }
  357. /**
  358. * Set layout script path
  359. *
  360. * @param string $path
  361. * @return Zend_Layout
  362. */
  363. public function setLayoutPath($path)
  364. {
  365. return $this->setViewScriptPath($path);
  366. }
  367. /**
  368. * Get current layout script path
  369. *
  370. * @return string
  371. */
  372. public function getLayoutPath()
  373. {
  374. return $this->getViewScriptPath();
  375. }
  376. /**
  377. * Set content key
  378. *
  379. * Key in namespace container denoting default content
  380. *
  381. * @param string $contentKey
  382. * @return Zend_Layout
  383. */
  384. public function setContentKey($contentKey)
  385. {
  386. $this->_contentKey = (string) $contentKey;
  387. return $this;
  388. }
  389. /**
  390. * Retrieve content key
  391. *
  392. * @return string
  393. */
  394. public function getContentKey()
  395. {
  396. return $this->_contentKey;
  397. }
  398. /**
  399. * Set MVC enabled flag
  400. *
  401. * @param bool $mvcEnabled
  402. * @return Zend_Layout
  403. */
  404. protected function _setMvcEnabled($mvcEnabled)
  405. {
  406. $this->_mvcEnabled = ($mvcEnabled) ? true : false;
  407. return $this;
  408. }
  409. /**
  410. * Retrieve MVC enabled flag
  411. *
  412. * @return bool
  413. */
  414. public function getMvcEnabled()
  415. {
  416. return $this->_mvcEnabled;
  417. }
  418. /**
  419. * Set MVC Successful Action Only flag
  420. *
  421. * @param bool $successfulActionOnly
  422. * @return Zend_Layout
  423. */
  424. public function setMvcSuccessfulActionOnly($successfulActionOnly)
  425. {
  426. $this->_mvcSuccessfulActionOnly = ($successfulActionOnly) ? true : false;
  427. return $this;
  428. }
  429. /**
  430. * Get MVC Successful Action Only Flag
  431. *
  432. * @return bool
  433. */
  434. public function getMvcSuccessfulActionOnly()
  435. {
  436. return $this->_mvcSuccessfulActionOnly;
  437. }
  438. /**
  439. * Set view object
  440. *
  441. * @param Zend_View_Interface $view
  442. * @return Zend_Layout
  443. */
  444. public function setView(Zend_View_Interface $view)
  445. {
  446. $this->_view = $view;
  447. return $this;
  448. }
  449. /**
  450. * Retrieve helper class
  451. *
  452. * @return string
  453. */
  454. public function getHelperClass()
  455. {
  456. return $this->_helperClass;
  457. }
  458. /**
  459. * Set helper class
  460. *
  461. * @param string $helperClass
  462. * @return Zend_Layout
  463. */
  464. public function setHelperClass($helperClass)
  465. {
  466. $this->_helperClass = (string) $helperClass;
  467. return $this;
  468. }
  469. /**
  470. * Retrieve plugin class
  471. *
  472. * @return string
  473. */
  474. public function getPluginClass()
  475. {
  476. return $this->_pluginClass;
  477. }
  478. /**
  479. * Set plugin class
  480. *
  481. * @param string $pluginClass
  482. * @return Zend_Layout
  483. */
  484. public function setPluginClass($pluginClass)
  485. {
  486. $this->_pluginClass = (string) $pluginClass;
  487. return $this;
  488. }
  489. /**
  490. * Get current view object
  491. *
  492. * If no view object currently set, retrieves it from the ViewRenderer.
  493. *
  494. * @todo Set inflector from view renderer at same time
  495. * @return Zend_View_Interface
  496. */
  497. public function getView()
  498. {
  499. if (null === $this->_view) {
  500. require_once 'Zend/Controller/Action/HelperBroker.php';
  501. $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
  502. if (null === $viewRenderer->view) {
  503. $viewRenderer->initView();
  504. }
  505. $this->setView($viewRenderer->view);
  506. }
  507. return $this->_view;
  508. }
  509. /**
  510. * Set layout view script suffix
  511. *
  512. * @param string $viewSuffix
  513. * @return Zend_Layout
  514. */
  515. public function setViewSuffix($viewSuffix)
  516. {
  517. $this->_viewSuffix = (string) $viewSuffix;
  518. return $this;
  519. }
  520. /**
  521. * Retrieve layout view script suffix
  522. *
  523. * @return string
  524. */
  525. public function getViewSuffix()
  526. {
  527. return $this->_viewSuffix;
  528. }
  529. /**
  530. * Retrieve inflector target
  531. *
  532. * @return string
  533. */
  534. public function getInflectorTarget()
  535. {
  536. return $this->_inflectorTarget;
  537. }
  538. /**
  539. * Set inflector target
  540. *
  541. * @param string $inflectorTarget
  542. * @return Zend_Layout
  543. */
  544. public function setInflectorTarget($inflectorTarget)
  545. {
  546. $this->_inflectorTarget = (string) $inflectorTarget;
  547. return $this;
  548. }
  549. /**
  550. * Set inflector to use when resolving layout names
  551. *
  552. * @param Zend_Filter_Inflector $inflector
  553. * @return Zend_Layout
  554. */
  555. public function setInflector(Zend_Filter_Inflector $inflector)
  556. {
  557. $this->_inflector = $inflector;
  558. return $this;
  559. }
  560. /**
  561. * Retrieve inflector
  562. *
  563. * @return Zend_Filter_Inflector
  564. */
  565. public function getInflector()
  566. {
  567. if (null === $this->_inflector) {
  568. require_once 'Zend/Filter/Inflector.php';
  569. $inflector = new Zend_Filter_Inflector();
  570. $inflector->setTargetReference($this->_inflectorTarget)
  571. ->addRules(array(':script' => array('Word_CamelCaseToDash', 'StringToLower')))
  572. ->setStaticRuleReference('suffix', $this->_viewSuffix);
  573. $this->setInflector($inflector);
  574. }
  575. return $this->_inflector;
  576. }
  577. /**
  578. * Enable inflector
  579. *
  580. * @return Zend_Layout
  581. */
  582. public function enableInflector()
  583. {
  584. $this->_inflectorEnabled = true;
  585. return $this;
  586. }
  587. /**
  588. * Disable inflector
  589. *
  590. * @return Zend_Layout
  591. */
  592. public function disableInflector()
  593. {
  594. $this->_inflectorEnabled = false;
  595. return $this;
  596. }
  597. /**
  598. * Return status of inflector enabled flag
  599. *
  600. * @return bool
  601. */
  602. public function inflectorEnabled()
  603. {
  604. return $this->_inflectorEnabled;
  605. }
  606. /**
  607. * Set layout variable
  608. *
  609. * @param string $key
  610. * @param mixed $value
  611. * @return void
  612. */
  613. public function __set($key, $value)
  614. {
  615. $this->_container[$key] = $value;
  616. }
  617. /**
  618. * Get layout variable
  619. *
  620. * @param string $key
  621. * @return mixed
  622. */
  623. public function __get($key)
  624. {
  625. if (isset($this->_container[$key])) {
  626. return $this->_container[$key];
  627. }
  628. return null;
  629. }
  630. /**
  631. * Is a layout variable set?
  632. *
  633. * @param string $key
  634. * @return bool
  635. */
  636. public function __isset($key)
  637. {
  638. return (isset($this->_container[$key]));
  639. }
  640. /**
  641. * Unset a layout variable?
  642. *
  643. * @param string $key
  644. * @return void
  645. */
  646. public function __unset($key)
  647. {
  648. if (isset($this->_container[$key])) {
  649. unset($this->_container[$key]);
  650. }
  651. }
  652. /**
  653. * Assign one or more layout variables
  654. *
  655. * @param mixed $spec Assoc array or string key; if assoc array, sets each
  656. * key as a layout variable
  657. * @param mixed $value Value if $spec is a key
  658. * @return Zend_Layout
  659. * @throws Zend_Layout_Exception if non-array/string value passed to $spec
  660. */
  661. public function assign($spec, $value = null)
  662. {
  663. if (is_array($spec)) {
  664. $orig = $this->_container->getArrayCopy();
  665. $merged = array_merge($orig, $spec);
  666. $this->_container->exchangeArray($merged);
  667. return $this;
  668. }
  669. if (is_string($spec)) {
  670. $this->_container[$spec] = $value;
  671. return $this;
  672. }
  673. require_once 'Zend/Layout/Exception.php';
  674. throw new Zend_Layout_Exception('Invalid values passed to assign()');
  675. }
  676. /**
  677. * Render layout
  678. *
  679. * Sets internal script path as last path on script path stack, assigns
  680. * layout variables to view, determines layout name using inflector, and
  681. * renders layout view script.
  682. *
  683. * $name will be passed to the inflector as the key 'script'.
  684. *
  685. * @param mixed $name
  686. * @return mixed
  687. */
  688. public function render($name = null)
  689. {
  690. if (null === $name) {
  691. $name = $this->getLayout();
  692. }
  693. if ($this->inflectorEnabled() && (null !== ($inflector = $this->getInflector())))
  694. {
  695. $name = $this->_inflector->filter(array('script' => $name));
  696. }
  697. $view = $this->getView();
  698. if (null !== ($path = $this->getViewScriptPath())) {
  699. if (method_exists($view, 'addScriptPath')) {
  700. $view->addScriptPath($path);
  701. } else {
  702. $view->setScriptPath($path);
  703. }
  704. } elseif (null !== ($path = $this->getViewBasePath())) {
  705. $view->addBasePath($path, $this->_viewBasePrefix);
  706. }
  707. return $view->render($name);
  708. }
  709. }