XmlView::_serialize()   F
last analyzed

Complexity

Conditions 16
Paths 320

Size

Total Lines 48

Duplication

Lines 8
Ratio 16.67 %

Importance

Changes 0
Metric Value
cc 16
nc 320
nop 1
dl 8
loc 48
rs 3.2333
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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         2.1.0
13
 * @license       https://opensource.org/licenses/mit-license.php MIT License
14
 */
15
namespace Cake\View;
16
17
use Cake\Core\Configure;
18
use Cake\Utility\Hash;
19
use Cake\Utility\Xml;
20
21
/**
22
 * A view class that is used for creating XML responses.
23
 *
24
 * By setting the '_serialize' key in your controller, you can specify a view variable
25
 * that should be serialized to XML and used as the response for the request.
26
 * This allows you to omit views + layouts, if your just need to emit a single view
27
 * variable as the XML response.
28
 *
29
 * In your controller, you could do the following:
30
 *
31
 * ```
32
 * $this->set(['posts' => $posts, '_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 define `'_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->set('_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 use the `_serialize` key, 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
    /**
68
     * XML views are located in the 'xml' sub directory for controllers' views.
69
     *
70
     * @var string
71
     */
72
    protected $subDir = 'xml';
73
74
    /**
75
     * Response type.
76
     *
77
     * @var string
78
     */
79
    protected $_responseType = 'xml';
80
81
    /**
82
     * List of special view vars.
83
     *
84
     * @var array
85
     */
86
    protected $_specialVars = ['_serialize', '_rootNode', '_xmlOptions'];
87
88
    /**
89
     * Serialize view vars.
90
     *
91
     * ### Special parameters
92
     * `_xmlOptions` You can set an array of custom options for Xml::fromArray() this way, e.g.
93
     *   'format' as 'attributes' instead of 'tags'.
94
     *
95
     * @param array|string $serialize The name(s) of the view variable(s) that need(s) to be serialized
96
     * @return string The serialized data
97
     */
98
    protected function _serialize($serialize)
99
    {
100
        $rootNode = isset($this->viewVars['_rootNode']) ? $this->viewVars['_rootNode'] : 'response';
101
102
        if ($serialize === true) {
103
            $serialize = array_diff(
104
                array_keys($this->viewVars),
105
                $this->_specialVars
106
            );
107
108
            if (empty($serialize)) {
109
                $serialize = null;
110
            } elseif (count($serialize) === 1) {
111
                $serialize = current($serialize);
112
            }
113
        }
114
115
        if (is_array($serialize)) {
116
            $data = [$rootNode => []];
117 View Code Duplication
            foreach ($serialize as $alias => $key) {
118
                if (is_numeric($alias)) {
119
                    $alias = $key;
120
                }
121
                if (array_key_exists($key, $this->viewVars)) {
122
                    $data[$rootNode][$alias] = $this->viewVars[$key];
123
                }
124
            }
125
        } else {
126
            $data = isset($this->viewVars[$serialize]) ? $this->viewVars[$serialize] : null;
127
            if (is_array($data) && Hash::numeric(array_keys($data))) {
128
                $data = [$rootNode => [$serialize => $data]];
129
            }
130
        }
131
132
        $options = [];
133
        if (isset($this->viewVars['_xmlOptions'])) {
134
            $options = $this->viewVars['_xmlOptions'];
135
        }
136
        if (Configure::read('debug')) {
137
            $options['pretty'] = true;
138
        }
139
140
        if (isset($options['return']) && strtolower($options['return']) === 'domdocument') {
141
            return Xml::fromArray($data, $options)->saveXML();
142
        }
143
144
        return Xml::fromArray($data, $options)->asXML();
0 ignored issues
show
Bug introduced by
The method asXML does only exist in SimpleXMLElement, but not in DOMDocument.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
145
    }
146
}
147