XmlView.php 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  5. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  6. *
  7. * Licensed under The MIT License
  8. * For full copyright and license information, please see the LICENSE.txt
  9. * Redistributions of files must retain the above copyright notice.
  10. *
  11. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  12. * @link https://cakephp.org CakePHP(tm) Project
  13. * @since 2.1.0
  14. * @license https://opensource.org/licenses/mit-license.php MIT License
  15. */
  16. namespace Cake\View;
  17. use Cake\Core\Configure;
  18. use Cake\Utility\Hash;
  19. use Cake\Utility\Xml;
  20. /**
  21. * A view class that is used for creating XML responses.
  22. *
  23. * By setting the 'serialize' option in view builder of your controller, you can specify
  24. * a view variable that should be serialized to XML and used as the response for the request.
  25. * This allows you to omit views + layouts, if your just need to emit a single view
  26. * variable as the XML response.
  27. *
  28. * In your controller, you could do the following:
  29. *
  30. * ```
  31. * $this->set(['posts' => $posts]);
  32. * $this->viewBuilder()->setOption('serialize', true);
  33. * ```
  34. *
  35. * When the view is rendered, the `$posts` view variable will be serialized
  36. * into XML.
  37. *
  38. * **Note** The view variable you specify must be compatible with Xml::fromArray().
  39. *
  40. * You can also set `'serialize'` as an array. This will create an additional
  41. * top level element named `<response>` containing all the named view variables:
  42. *
  43. * ```
  44. * $this->set(compact('posts', 'users', 'stuff'));
  45. * $this->viewBuilder()->setOption('serialize', true);
  46. * ```
  47. *
  48. * The above would generate a XML object that looks like:
  49. *
  50. * `<response><posts>...</posts><users>...</users></response>`
  51. *
  52. * You can also set `'serialize'` to a string or array to serialize only the
  53. * specified view variables.
  54. *
  55. * If you don't set the `serialize` option, you will need a view. You can use extended
  56. * views to provide layout like functionality.
  57. */
  58. class XmlView extends SerializedView
  59. {
  60. /**
  61. * XML layouts are located in the xml sub directory of `Layouts/`
  62. *
  63. * @var string
  64. */
  65. protected $layoutPath = 'xml';
  66. /**
  67. * XML views are located in the 'xml' sub directory for controllers' views.
  68. *
  69. * @var string
  70. */
  71. protected $subDir = 'xml';
  72. /**
  73. * Response type.
  74. *
  75. * @var string
  76. */
  77. protected $_responseType = 'xml';
  78. /**
  79. * Option to allow setting an array of custom options for Xml::fromArray()
  80. *
  81. * For e.g. 'format' as 'attributes' instead of 'tags'.
  82. *
  83. * @var array|null
  84. */
  85. protected $xmlOptions;
  86. /**
  87. * Default config options.
  88. *
  89. * Use ViewBuilder::setOption()/setOptions() in your controller to set these options.
  90. *
  91. * - `serialize`: Option to convert a set of view variables into a serialized response.
  92. * Its value can be a string for single variable name or array for multiple
  93. * names. If true all view variables will be serialized. If null or false
  94. * normal view template will be rendered.
  95. * - `xmlOptions`: Option to allow setting an array of custom options for Xml::fromArray().
  96. * For e.g. 'format' as 'attributes' instead of 'tags'.
  97. * - `rootNode`: Root node name. Defaults to "response".
  98. *
  99. * @var array{serialize:string|bool|null, xmlOptions: int|null, rootNode: string|null}
  100. */
  101. protected $_defaultConfig = [
  102. 'serialize' => null,
  103. 'xmlOptions' => null,
  104. 'rootNode' => null,
  105. ];
  106. /**
  107. * Serialize view vars.
  108. *
  109. * @param array|string $serialize The name(s) of the view variable(s) that need(s) to be serialized
  110. * @return string|false The serialized data
  111. */
  112. protected function _serialize($serialize)
  113. {
  114. $rootNode = $this->getConfig('rootNode', 'response');
  115. if (is_array($serialize)) {
  116. if (empty($serialize)) {
  117. $serialize = null;
  118. } elseif (count($serialize) === 1) {
  119. $serialize = current($serialize);
  120. }
  121. }
  122. if (is_array($serialize)) {
  123. $data = [$rootNode => []];
  124. foreach ($serialize as $alias => $key) {
  125. if (is_numeric($alias)) {
  126. $alias = $key;
  127. }
  128. if (array_key_exists($key, $this->viewVars)) {
  129. $data[$rootNode][$alias] = $this->viewVars[$key];
  130. }
  131. }
  132. } else {
  133. $data = $this->viewVars[$serialize] ?? null;
  134. if (is_array($data) && Hash::numeric(array_keys($data))) {
  135. $data = [$rootNode => [$serialize => $data]];
  136. }
  137. }
  138. $options = $this->getConfig('xmlOptions', []);
  139. if (Configure::read('debug')) {
  140. $options['pretty'] = true;
  141. }
  142. if (isset($options['return']) && strtolower($options['return']) === 'domdocument') {
  143. return Xml::fromArray($data, $options)->saveXML();
  144. }
  145. return Xml::fromArray($data, $options)->asXML();
  146. }
  147. }