Layout.php 18 KB

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