Passed
Push — master ( 924354...73c61e )
by Robbie
01:41
created

JSONDataFormatter::convertDataObjectToJSONObject()   C

Complexity

Conditions 19
Paths 6

Size

Total Lines 80
Code Lines 48

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 19
eloc 48
nc 6
nop 3
dl 0
loc 80
rs 5.0192
c 0
b 0
f 0

How to fix   Long Method    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
namespace SilverStripe\RestfulServer\DataFormatter;
4
5
use SilverStripe\RestfulServer\RestfulServer;
6
use SilverStripe\View\ArrayData;
7
use SilverStripe\Core\Convert;
8
use SilverStripe\RestfulServer\DataFormatter;
9
use SilverStripe\ORM\DataObjectInterface;
10
use SilverStripe\Control\Director;
11
use SilverStripe\ORM\SS_List;
12
use SilverStripe\ORM\FieldType;
13
14
/**
15
 * Formats a DataObject's member fields into a JSON string
16
 */
17
class JSONDataFormatter extends DataFormatter
18
{
19
    /**
20
     * @config
21
     * @todo pass this from the API to the data formatter somehow
22
     */
23
    private static $api_base = "api/v1/";
24
25
    protected $outputContentType = 'application/json';
26
27
    /**
28
     * @return array
29
     */
30
    public function supportedExtensions()
31
    {
32
        return array(
33
            'json',
34
            'js'
35
        );
36
    }
37
38
    /**
39
     * @return array
40
     */
41
    public function supportedMimeTypes()
42
    {
43
        return array(
44
            'application/json',
45
            'text/x-json'
46
        );
47
    }
48
49
    /**
50
     * @param $array
51
     * @return string
52
     */
53
    public function convertArray($array)
54
    {
55
        return Convert::array2json($array);
56
    }
57
58
    /**
59
     * Generate a JSON representation of the given {@link DataObject}.
0 ignored issues
show
Bug introduced by
The type SilverStripe\RestfulServ...ataFormatter\DataObject was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
60
     *
61
     * @param DataObject $obj   The object
62
     * @param Array $fields     If supplied, only fields in the list will be returned
63
     * @param $relations        Not used
0 ignored issues
show
Bug introduced by
The type SilverStripe\RestfulServer\DataFormatter\Not was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
64
     * @return String JSON
65
     */
66
    public function convertDataObject(DataObjectInterface $obj, $fields = null, $relations = null)
67
    {
68
        return Convert::array2json($this->convertDataObjectToJSONObject($obj, $fields, $relations));
0 ignored issues
show
Bug introduced by
$this->convertDataObject...j, $fields, $relations) of type SilverStripe\RestfulServ...rmatter\EmptyJSONObject is incompatible with the type array expected by parameter $val of SilverStripe\Core\Convert::array2json(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

68
        return Convert::array2json(/** @scrutinizer ignore-type */ $this->convertDataObjectToJSONObject($obj, $fields, $relations));
Loading history...
69
    }
70
71
    /**
72
     * Internal function to do the conversion of a single data object. It builds an empty object and dynamically
73
     * adds the properties it needs to it. If it's done as a nested array, json_encode or equivalent won't use
74
     * JSON object notation { ... }.
75
     * @param DataObjectInterface $obj
76
     * @param  $fields
77
     * @param  $relations
78
     * @return EmptyJSONObject
0 ignored issues
show
Bug introduced by
The type SilverStripe\RestfulServ...rmatter\EmptyJSONObject was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
79
     */
80
    public function convertDataObjectToJSONObject(DataObjectInterface $obj, $fields = null, $relations = null)
81
    {
82
        $className = get_class($obj);
83
        $id = $obj->ID;
84
85
        $serobj = ArrayData::array_to_object();
86
87
        foreach ($this->getFieldsForObj($obj) as $fieldName => $fieldType) {
88
            // Field filtering
89
            if ($fields && !in_array($fieldName, $fields)) {
90
                continue;
91
            }
92
93
            $fieldValue = self::cast($obj->obj($fieldName));
94
            $mappedFieldName = $this->getFieldAlias($className, $fieldName);
95
            $serobj->$mappedFieldName = $fieldValue;
96
        }
97
98
        if ($this->relationDepth > 0) {
99
            foreach ($obj->hasOne() as $relName => $relClass) {
100
                if (!singleton($relClass)->stat('api_access')) {
101
                    continue;
102
                }
103
104
                // Field filtering
105
                if ($fields && !in_array($relName, $fields)) {
106
                    continue;
107
                }
108
                if ($this->customRelations && !in_array($relName, $this->customRelations)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->customRelations of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
109
                    continue;
110
                }
111
112
                $fieldName = $relName . 'ID';
113
                $rel = $this->config()->api_base;
114
                $rel .= $obj->$fieldName
115
                    ? $this->sanitiseClassName($relClass) . '/' . $obj->$fieldName
116
                    : $this->sanitiseClassName($className) . "/$id/$relName";
117
                $href = Director::absoluteURL($rel);
118
                $serobj->$relName = ArrayData::array_to_object(array(
119
                    "className" => $relClass,
120
                    "href" => "$href.json",
121
                    "id" => self::cast($obj->obj($fieldName))
122
                ));
123
            }
124
125
            foreach ($obj->hasMany() + $obj->manyMany() as $relName => $relClass) {
126
                $relClass = RestfulServer::parseRelationClass($relClass);
127
128
                //remove dot notation from relation names
129
                $parts = explode('.', $relClass);
0 ignored issues
show
Bug introduced by
It seems like $relClass can also be of type array; however, parameter $string of explode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

129
                $parts = explode('.', /** @scrutinizer ignore-type */ $relClass);
Loading history...
130
                $relClass = array_shift($parts);
131
132
                if (!singleton($relClass)->stat('api_access')) {
133
                    continue;
134
                }
135
136
                // Field filtering
137
                if ($fields && !in_array($relName, $fields)) {
138
                    continue;
139
                }
140
                if ($this->customRelations && !in_array($relName, $this->customRelations)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->customRelations of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
141
                    continue;
142
                }
143
144
                $innerParts = array();
145
                $items = $obj->$relName();
146
                foreach ($items as $item) {
147
                    $rel = $this->config()->api_base . $this->sanitiseClassName($relClass) . "/$item->ID";
148
                    $href = Director::absoluteURL($rel);
149
                    $innerParts[] = ArrayData::array_to_object(array(
150
                        "className" => $relClass,
151
                        "href" => "$href.json",
152
                        "id" => $item->ID
153
                    ));
154
                }
155
                $serobj->$relName = $innerParts;
156
            }
157
        }
158
159
        return $serobj;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $serobj returns the type stdClass which is incompatible with the documented return type SilverStripe\RestfulServ...rmatter\EmptyJSONObject.
Loading history...
160
    }
161
162
    /**
163
     * Generate a JSON representation of the given {@link SS_List}.
164
     *
165
     * @param SS_List $set
166
     * @return String XML
167
     */
168
    public function convertDataObjectSet(SS_List $set, $fields = null)
169
    {
170
        $items = array();
171
        foreach ($set as $do) {
172
            if (!$do->canView()) {
173
                continue;
174
            }
175
            $items[] = $this->convertDataObjectToJSONObject($do, $fields);
176
        }
177
178
        $serobj = ArrayData::array_to_object(array(
179
            "totalSize" => (is_numeric($this->totalSize)) ? $this->totalSize : null,
0 ignored issues
show
introduced by
The condition is_numeric($this->totalSize) is always true.
Loading history...
180
            "items" => $items
181
        ));
182
183
        return Convert::array2json($serobj);
0 ignored issues
show
Bug introduced by
$serobj of type stdClass is incompatible with the type array expected by parameter $val of SilverStripe\Core\Convert::array2json(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

183
        return Convert::array2json(/** @scrutinizer ignore-type */ $serobj);
Loading history...
184
    }
185
186
    /**
187
     * @param string $strData
188
     * @return array|bool|void
189
     */
190
    public function convertStringToArray($strData)
191
    {
192
        return Convert::json2array($strData);
193
    }
194
195
    public static function cast(FieldType\DBField $dbfield)
196
    {
197
        switch (true) {
198
            case $dbfield instanceof FieldType\DBInt:
199
                return (int)$dbfield->RAW();
200
            case $dbfield instanceof FieldType\DBFloat:
201
                return (float)$dbfield->RAW();
202
            case $dbfield instanceof FieldType\DBBoolean:
203
                return (bool)$dbfield->RAW();
204
            case is_null($dbfield->RAW()):
205
                return null;
206
        }
207
        return $dbfield->RAW();
208
    }
209
}
210