ViewBuilder.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  11. * @link https://cakephp.org CakePHP(tm) Project
  12. * @since 3.1.0
  13. * @license https://opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\View;
  16. use Cake\Core\App;
  17. use Cake\Event\EventManager;
  18. use Cake\Http\Response;
  19. use Cake\Http\ServerRequest;
  20. use Cake\View\Exception\MissingViewException;
  21. use JsonSerializable;
  22. use Serializable;
  23. /**
  24. * Provides an API for iteratively building a view up.
  25. *
  26. * Once you have configured the view and established all the context
  27. * you can create a view instance with `build()`.
  28. */
  29. class ViewBuilder implements JsonSerializable, Serializable
  30. {
  31. /**
  32. * The subdirectory to the template.
  33. *
  34. * @var string|null
  35. */
  36. protected $_templatePath;
  37. /**
  38. * The template file to render.
  39. *
  40. * @var string|null
  41. */
  42. protected $_template;
  43. /**
  44. * The plugin name to use.
  45. *
  46. * @var string|null|false
  47. */
  48. protected $_plugin;
  49. /**
  50. * The theme name to use.
  51. *
  52. * @var string|null|false
  53. */
  54. protected $_theme;
  55. /**
  56. * The layout name to render.
  57. *
  58. * @var string|null|false
  59. */
  60. protected $_layout;
  61. /**
  62. * Whether or not autoLayout should be enabled.
  63. *
  64. * @var bool|null
  65. */
  66. protected $_autoLayout;
  67. /**
  68. * The layout path to build the view with.
  69. *
  70. * @var string|null
  71. */
  72. protected $_layoutPath;
  73. /**
  74. * The view variables to use
  75. *
  76. * @var string|null
  77. */
  78. protected $_name;
  79. /**
  80. * The view class name to use.
  81. * Can either use plugin notation, a short name
  82. * or a fully namespaced classname.
  83. *
  84. * @var string|null
  85. */
  86. protected $_className;
  87. /**
  88. * Additional options used when constructing the view.
  89. *
  90. * This options array lets you provide custom constructor
  91. * arguments to application/plugin view classes.
  92. *
  93. * @var array
  94. */
  95. protected $_options = [];
  96. /**
  97. * The helpers to use
  98. *
  99. * @var array
  100. */
  101. protected $_helpers = [];
  102. /**
  103. * View vars
  104. *
  105. * @var array
  106. */
  107. protected $_vars = [];
  108. /**
  109. * Saves a variable for use inside a template.
  110. *
  111. * @param string $name A string or an array of data.
  112. * @param mixed $value Value.
  113. * @return $this
  114. */
  115. public function setVar($name, $value = null)
  116. {
  117. $this->_vars[$name] = $value;
  118. return $this;
  119. }
  120. /**
  121. * Saves view vars for use inside templates.
  122. *
  123. * @param array $data Array of data.
  124. * @param bool $merge Whether to merge with existing vars, default true.
  125. * @return $this
  126. */
  127. public function setVars($data, $merge = true)
  128. {
  129. if ($merge) {
  130. $this->_vars = $data + $this->_vars;
  131. } else {
  132. $this->_vars = $data;
  133. }
  134. return $this;
  135. }
  136. /**
  137. * Check if view var is set.
  138. *
  139. * @param string $name Var name
  140. * @return bool
  141. */
  142. public function hasVar($name)
  143. {
  144. return array_key_exists($name, $this->_vars);
  145. }
  146. /**
  147. * Get view var
  148. *
  149. * @param string $name Var name
  150. * @return mixed The var value or null if unset.
  151. */
  152. public function getVar($name)
  153. {
  154. return isset($this->_vars[$name]) ? $this->_vars[$name] : null;
  155. }
  156. /**
  157. * Get all view vars.
  158. *
  159. * @return array
  160. */
  161. public function getVars()
  162. {
  163. return $this->_vars;
  164. }
  165. /**
  166. * Sets path for template files.
  167. *
  168. * @param string $path Path for view files.
  169. * @return $this
  170. */
  171. public function setTemplatePath($path)
  172. {
  173. $this->_templatePath = $path;
  174. return $this;
  175. }
  176. /**
  177. * Gets path for template files.
  178. *
  179. * @return string
  180. */
  181. public function getTemplatePath()
  182. {
  183. return $this->_templatePath;
  184. }
  185. /**
  186. * Get/set path for template files.
  187. *
  188. * @deprecated 3.4.0 Use setTemplatePath()/getTemplatePath() instead.
  189. * @param string|null $path Path for view files. If null returns current path.
  190. * @return string|$this
  191. */
  192. public function templatePath($path = null)
  193. {
  194. deprecationWarning('ViewBuilder::templatePath() is deprecated. Use ViewBuilder::setTemplatePath() or ViewBuilder::getTemplatePath() instead.');
  195. if ($path !== null) {
  196. return $this->setTemplatePath($path);
  197. }
  198. return $this->getTemplatePath();
  199. }
  200. /**
  201. * Sets path for layout files.
  202. *
  203. * @param string $path Path for layout files.
  204. * @return $this
  205. */
  206. public function setLayoutPath($path)
  207. {
  208. $this->_layoutPath = $path;
  209. return $this;
  210. }
  211. /**
  212. * Gets path for layout files.
  213. *
  214. * @return string
  215. */
  216. public function getLayoutPath()
  217. {
  218. return $this->_layoutPath;
  219. }
  220. /**
  221. * Get/set path for layout files.
  222. *
  223. * @deprecated 3.4.0 Use setLayoutPath()/getLayoutPath() instead.
  224. * @param string|null $path Path for layout files. If null returns current path.
  225. * @return string|$this
  226. */
  227. public function layoutPath($path = null)
  228. {
  229. deprecationWarning('ViewBuilder::layoutPath() is deprecated. Use ViewBuilder::setLayoutPath() or ViewBuilder::getLayoutPath() instead.');
  230. if ($path !== null) {
  231. return $this->setLayoutPath($path);
  232. }
  233. return $this->getLayoutPath();
  234. }
  235. /**
  236. * Turns on or off CakePHP's conventional mode of applying layout files.
  237. * On by default. Setting to off means that layouts will not be
  238. * automatically applied to rendered views.
  239. *
  240. * @param bool $enable Boolean to turn on/off.
  241. * @return $this
  242. */
  243. public function enableAutoLayout($enable = true)
  244. {
  245. $this->_autoLayout = (bool)$enable;
  246. return $this;
  247. }
  248. /**
  249. * Turns off CakePHP's conventional mode of applying layout files.
  250. *
  251. * Setting to off means that layouts will not be automatically applied to
  252. * rendered views.
  253. *
  254. * @return $this
  255. */
  256. public function disableAutoLayout()
  257. {
  258. $this->_autoLayout = false;
  259. return $this;
  260. }
  261. /**
  262. * Returns if CakePHP's conventional mode of applying layout files is enabled.
  263. * Disabled means that layouts will not be automatically applied to rendered views.
  264. *
  265. * @return bool|null
  266. */
  267. public function isAutoLayoutEnabled()
  268. {
  269. return $this->_autoLayout;
  270. }
  271. /**
  272. * Turns on or off CakePHP's conventional mode of applying layout files.
  273. * On by default. Setting to off means that layouts will not be
  274. * automatically applied to rendered views.
  275. *
  276. * @deprecated 3.4.0 Use enableAutoLayout()/isAutoLayoutEnabled() instead.
  277. * @param bool|null $enable Boolean to turn on/off. If null returns current value.
  278. * @return bool|$this
  279. */
  280. public function autoLayout($enable = null)
  281. {
  282. deprecationWarning('ViewBuilder::autoLayout() is deprecated. Use ViewBuilder::enableAutoLayout() or ViewBuilder::isAutoLayoutEnable() instead.');
  283. if ($enable !== null) {
  284. return $this->enableAutoLayout($enable);
  285. }
  286. return $this->isAutoLayoutEnabled();
  287. }
  288. /**
  289. * Sets the plugin name to use.
  290. *
  291. * `False` to remove current plugin name is deprecated as of 3.4.0. Use directly `null` instead.
  292. *
  293. * @param string|null|false $name Plugin name.
  294. * Use null or false to remove the current plugin name.
  295. * @return $this
  296. */
  297. public function setPlugin($name)
  298. {
  299. $this->_plugin = $name;
  300. return $this;
  301. }
  302. /**
  303. * Gets the plugin name to use.
  304. *
  305. * @return string|null|false
  306. */
  307. public function getPlugin()
  308. {
  309. return $this->_plugin;
  310. }
  311. /**
  312. * The plugin name to use
  313. *
  314. * @deprecated 3.4.0 Use setPlugin()/getPlugin() instead.
  315. * @param string|null|false $name Plugin name. If null returns current plugin.
  316. * Use false to remove the current plugin name.
  317. * @return string|false|null|$this
  318. */
  319. public function plugin($name = null)
  320. {
  321. deprecationWarning('ViewBuilder::plugin() is deprecated. Use ViewBuilder::setPlugin() or ViewBuilder::getPlugin() instead.');
  322. if ($name !== null) {
  323. return $this->setPlugin($name);
  324. }
  325. return $this->getPlugin();
  326. }
  327. /**
  328. * Sets the helpers to use.
  329. *
  330. * @param array $helpers Helpers to use.
  331. * @param bool $merge Whether or not to merge existing data with the new data.
  332. * @return $this
  333. */
  334. public function setHelpers(array $helpers, $merge = true)
  335. {
  336. if ($merge) {
  337. $helpers = array_merge($this->_helpers, $helpers);
  338. }
  339. $this->_helpers = $helpers;
  340. return $this;
  341. }
  342. /**
  343. * Gets the helpers to use.
  344. *
  345. * @return array
  346. */
  347. public function getHelpers()
  348. {
  349. return $this->_helpers;
  350. }
  351. /**
  352. * The helpers to use
  353. *
  354. * @deprecated 3.4.0 Use setHelpers()/getHelpers() instead.
  355. * @param array|null $helpers Helpers to use.
  356. * @param bool $merge Whether or not to merge existing data with the new data.
  357. * @return array|$this
  358. */
  359. public function helpers(array $helpers = null, $merge = true)
  360. {
  361. deprecationWarning('ViewBuilder::helpers() is deprecated. Use ViewBuilder::setHelpers() or ViewBuilder::getHelpers() instead.');
  362. if ($helpers !== null) {
  363. return $this->setHelpers($helpers, $merge);
  364. }
  365. return $this->getHelpers();
  366. }
  367. /**
  368. * Sets the view theme to use.
  369. *
  370. * `False` to remove current theme is deprecated as of 3.4.0. Use directly `null` instead.
  371. *
  372. * @param string|null|false $theme Theme name.
  373. * Use null or false to remove the current theme.
  374. * @return $this
  375. */
  376. public function setTheme($theme)
  377. {
  378. $this->_theme = $theme;
  379. return $this;
  380. }
  381. /**
  382. * Gets the view theme to use.
  383. *
  384. * @return string|null|false
  385. */
  386. public function getTheme()
  387. {
  388. return $this->_theme;
  389. }
  390. /**
  391. * The view theme to use.
  392. *
  393. * @deprecated 3.4.0 Use setTheme()/getTheme() instead.
  394. * @param string|null|false $theme Theme name. If null returns current theme.
  395. * Use false to remove the current theme.
  396. * @return string|false|null|$this
  397. */
  398. public function theme($theme = null)
  399. {
  400. deprecationWarning('ViewBuilder::theme() is deprecated. Use ViewBuilder::setTheme() or ViewBuilder::getTheme() instead.');
  401. if ($theme !== null) {
  402. return $this->setTheme($theme);
  403. }
  404. return $this->getTheme();
  405. }
  406. /**
  407. * Sets the name of the view file to render. The name specified is the
  408. * filename in /src/Template/<SubFolder> without the .ctp extension.
  409. *
  410. * @param string $name View file name to set.
  411. * @return $this
  412. */
  413. public function setTemplate($name)
  414. {
  415. $this->_template = $name;
  416. return $this;
  417. }
  418. /**
  419. * Gets the name of the view file to render. The name specified is the
  420. * filename in /src/Template/<SubFolder> without the .ctp extension.
  421. *
  422. * @return string
  423. */
  424. public function getTemplate()
  425. {
  426. return $this->_template;
  427. }
  428. /**
  429. * Get/set the name of the view file to render. The name specified is the
  430. * filename in /src/Template/<SubFolder> without the .ctp extension.
  431. *
  432. * @deprecated 3.4.0 Use setTemplate()/getTemplate()
  433. * @param string|null $name View file name to set. If null returns current name.
  434. * @return string|$this
  435. */
  436. public function template($name = null)
  437. {
  438. deprecationWarning('ViewBuilder::template() is deprecated. Use ViewBuilder::setTemplate() or ViewBuilder::getTemplate() instead.');
  439. if ($name !== null) {
  440. return $this->setTemplate($name);
  441. }
  442. return $this->getTemplate();
  443. }
  444. /**
  445. * Sets the name of the layout file to render the view inside of.
  446. * The name specified is the filename of the layout in /src/Template/Layout
  447. * without the .ctp extension.
  448. *
  449. * @param string $name Layout file name to set.
  450. * @return $this
  451. */
  452. public function setLayout($name)
  453. {
  454. $this->_layout = $name;
  455. return $this;
  456. }
  457. /**
  458. * Gets the name of the layout file to render the view inside of.
  459. *
  460. * @return string
  461. */
  462. public function getLayout()
  463. {
  464. return $this->_layout;
  465. }
  466. /**
  467. * Get/set the name of the layout file to render the view inside of.
  468. * The name specified is the filename of the layout in /src/Template/Layout
  469. * without the .ctp extension.
  470. *
  471. * @deprecated 3.4.0 Use setLayout()/getLayout() instead.
  472. * @param string|null $name Layout file name to set. If null returns current name.
  473. * @return string|$this
  474. */
  475. public function layout($name = null)
  476. {
  477. deprecationWarning('ViewBuilder::layout() is deprecated. Use ViewBuilder::setLayout() or ViewBuilder::getLayout() instead.');
  478. if ($name !== null) {
  479. return $this->setLayout($name);
  480. }
  481. return $this->getLayout();
  482. }
  483. /**
  484. * Sets additional options for the view.
  485. *
  486. * This lets you provide custom constructor arguments to application/plugin view classes.
  487. *
  488. * @param array $options An array of options.
  489. * @param bool $merge Whether or not to merge existing data with the new data.
  490. * @return $this
  491. */
  492. public function setOptions(array $options, $merge = true)
  493. {
  494. if ($merge) {
  495. $options = array_merge($this->_options, $options);
  496. }
  497. $this->_options = $options;
  498. return $this;
  499. }
  500. /**
  501. * Gets additional options for the view.
  502. *
  503. * @return array
  504. */
  505. public function getOptions()
  506. {
  507. return $this->_options;
  508. }
  509. /**
  510. * Set additional options for the view.
  511. *
  512. * This lets you provide custom constructor arguments to application/plugin view classes.
  513. *
  514. * @deprecated 3.4.0 Use setOptions()/getOptions() instead.
  515. * @param array|null $options Either an array of options or null to get current options.
  516. * @param bool $merge Whether or not to merge existing data with the new data.
  517. * @return array|$this
  518. */
  519. public function options(array $options = null, $merge = true)
  520. {
  521. deprecationWarning('ViewBuilder::options() is deprecated. Use ViewBuilder::setOptions() or ViewBuilder::getOptions() instead.');
  522. if ($options !== null) {
  523. return $this->setOptions($options, $merge);
  524. }
  525. return $this->getOptions();
  526. }
  527. /**
  528. * Sets the view name.
  529. *
  530. * @param string $name The name of the view.
  531. * @return $this
  532. */
  533. public function setName($name)
  534. {
  535. $this->_name = $name;
  536. return $this;
  537. }
  538. /**
  539. * Gets the view name.
  540. *
  541. * @return string
  542. */
  543. public function getName()
  544. {
  545. return $this->_name;
  546. }
  547. /**
  548. * Get/set the view name
  549. *
  550. * @deprecated 3.4.0 Use setName()/getName() instead.
  551. * @param string|null $name The name of the view
  552. * @return string|$this
  553. */
  554. public function name($name = null)
  555. {
  556. deprecationWarning('ViewBuilder::name() is deprecated. Use ViewBuilder::setName() or ViewBuilder::getName() instead.');
  557. if ($name !== null) {
  558. return $this->setName($name);
  559. }
  560. return $this->getName();
  561. }
  562. /**
  563. * Sets the view classname.
  564. *
  565. * Accepts either a short name (Ajax) a plugin name (MyPlugin.Ajax)
  566. * or a fully namespaced name (App\View\AppView) or null to use the
  567. * View class provided by CakePHP.
  568. *
  569. * @param string|null $name The class name for the view.
  570. * @return $this
  571. */
  572. public function setClassName($name)
  573. {
  574. $this->_className = $name;
  575. return $this;
  576. }
  577. /**
  578. * Gets the view classname.
  579. *
  580. * @return string|null
  581. */
  582. public function getClassName()
  583. {
  584. return $this->_className;
  585. }
  586. /**
  587. * Get/set the view classname.
  588. *
  589. * Accepts either a short name (Ajax) a plugin name (MyPlugin.Ajax)
  590. * or a fully namespaced name (App\View\AppView).
  591. *
  592. * @deprecated 3.4.0 Use setClassName()/getClassName() instead.
  593. * @param string|null $name The class name for the view. Can
  594. * be a plugin.class name reference, a short alias, or a fully
  595. * namespaced name.
  596. * @return string|$this
  597. */
  598. public function className($name = null)
  599. {
  600. deprecationWarning('ViewBuilder::className() is deprecated. Use ViewBuilder::setClassName() or ViewBuilder::getClassName() instead.');
  601. if ($name !== null) {
  602. return $this->setClassName($name);
  603. }
  604. return $this->getClassName();
  605. }
  606. /**
  607. * Using the data in the builder, create a view instance.
  608. *
  609. * If className() is null, App\View\AppView will be used.
  610. * If that class does not exist, then Cake\View\View will be used.
  611. *
  612. * @param array $vars The view variables/context to use.
  613. * @param \Cake\Http\ServerRequest|null $request The request to use.
  614. * @param \Cake\Http\Response|null $response The response to use.
  615. * @param \Cake\Event\EventManager|null $events The event manager to use.
  616. * @return \Cake\View\View
  617. * @throws \Cake\View\Exception\MissingViewException
  618. */
  619. public function build($vars = [], ServerRequest $request = null, Response $response = null, EventManager $events = null)
  620. {
  621. $className = $this->_className;
  622. if ($className === null) {
  623. $className = App::className('App', 'View', 'View') ?: 'Cake\View\View';
  624. }
  625. if ($className === 'View') {
  626. $className = App::className($className, 'View');
  627. } else {
  628. $className = App::className($className, 'View', 'View');
  629. }
  630. if (!$className) {
  631. throw new MissingViewException(['class' => $this->_className]);
  632. }
  633. $data = [
  634. 'name' => $this->_name,
  635. 'templatePath' => $this->_templatePath,
  636. 'template' => $this->_template,
  637. 'plugin' => $this->_plugin,
  638. 'theme' => $this->_theme,
  639. 'layout' => $this->_layout,
  640. 'autoLayout' => $this->_autoLayout,
  641. 'layoutPath' => $this->_layoutPath,
  642. 'helpers' => $this->_helpers,
  643. 'viewVars' => $vars + $this->_vars,
  644. ];
  645. $data += $this->_options;
  646. return new $className($request, $response, $events, $data);
  647. }
  648. /**
  649. * Serializes the view builder object to a value that can be natively
  650. * serialized and re-used to clone this builder instance.
  651. *
  652. * @return array Serializable array of configuration properties.
  653. */
  654. public function jsonSerialize()
  655. {
  656. $properties = [
  657. '_templatePath', '_template', '_plugin', '_theme', '_layout', '_autoLayout',
  658. '_layoutPath', '_name', '_className', '_options', '_helpers'
  659. ];
  660. $array = [];
  661. foreach ($properties as $property) {
  662. $array[$property] = $this->{$property};
  663. }
  664. return array_filter($array, function ($i) {
  665. return !is_array($i) && strlen($i) || !empty($i);
  666. });
  667. }
  668. /**
  669. * Configures a view builder instance from serialized config.
  670. *
  671. * @param array $config View builder configuration array.
  672. * @return $this Configured view builder instance.
  673. */
  674. public function createFromArray($config)
  675. {
  676. foreach ($config as $property => $value) {
  677. $this->{$property} = $value;
  678. }
  679. return $this;
  680. }
  681. /**
  682. * Serializes the view builder object.
  683. *
  684. * @return string
  685. */
  686. public function serialize()
  687. {
  688. $array = $this->jsonSerialize();
  689. return serialize($array);
  690. }
  691. /**
  692. * Unserializes the view builder object.
  693. *
  694. * @param string $data Serialized string.
  695. * @return $this Configured view builder instance.
  696. */
  697. public function unserialize($data)
  698. {
  699. return $this->createFromArray(unserialize($data));
  700. }
  701. }