Layout.php 18 KB

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