Completed
Push — master ( fe3c08...47da09 )
by Alex
04:22
created

JsonLightODataWriter::writeBagContent()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 20
Code Lines 12

Duplication

Lines 12
Ratio 60 %

Importance

Changes 0
Metric Value
dl 12
loc 20
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 12
nc 3
nop 1
1
<?php
2
3
namespace POData\Writers\Json;
4
5
use POData\Common\MimeTypes;
6
use POData\Common\ODataConstants;
7
use POData\Common\Version;
8
use POData\ObjectModel\ODataBagContent;
9
use POData\ObjectModel\ODataEntry;
10
use POData\ObjectModel\ODataFeed;
11
use POData\ObjectModel\ODataLink;
12
use POData\ObjectModel\ODataProperty;
13
use POData\ObjectModel\ODataPropertyContent;
14
use POData\ObjectModel\ODataURL;
15
use POData\ObjectModel\ODataURLCollection;
16
17
/**
18
 * Class JsonLightODataWriter is a writer for the json format in OData V3 also known as JSON Light.
19
 */
20
class JsonLightODataWriter extends JsonODataV2Writer
21
{
22
    /**
23
     * @var JsonLightMetadataLevel
24
     */
25
    protected $metadataLevel;
26
27
    /**
28
     * The service base uri.
29
     *
30
     * @var string
31
     */
32
    protected $baseUri;
33
34
    /**
35
     * @param string $absoluteServiceUri
36
     */
37
    public function __construct(JsonLightMetadataLevel $metadataLevel, $absoluteServiceUri)
38
    {
39
        if (strlen($absoluteServiceUri) == 0) {
40
            throw new \Exception('absoluteServiceUri must not be empty or null');
41
        }
42
        $this->baseUri = $absoluteServiceUri;
43
44
        $this->_writer = new JsonWriter('');
45
        $this->urlKey = ODataConstants::JSON_URL_STRING;
46
        $this->dataArrayName = ODataConstants::JSON_LIGHT_VALUE_NAME;
47
        $this->rowCountName = ODataConstants::JSON_LIGHT_ROWCOUNT_STRING;
48
        $this->metadataLevel = $metadataLevel;
49
    }
50
51
    /**
52
     * Determines if the given writer is capable of writing the response or not.
53
     *
54
     * @param Version $responseVersion the OData version of the response
55
     * @param string  $contentType     the Content Type of the response
56
     *
57
     * @return bool true if the writer can handle the response, false otherwise
58
     */
59 View Code Duplication
    public function canHandle(Version $responseVersion, $contentType)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
60
    {
61
        if ($responseVersion != Version::v3()) {
62
            return false;
63
        }
64
65
        $parts = explode(';', $contentType);
66
67
        //It must be app/json and have the right odata= piece
68
        return in_array(MimeTypes::MIME_APPLICATION_JSON, $parts) && in_array($this->metadataLevel->getValue(), $parts);
69
    }
70
71
    /**
72
     * Write the given OData model in a specific response format.
73
     *
74
     * @param ODataURL|ODataURLCollection|ODataPropertyContent|ODataFeed|ODataEntry $model Object of requested content
75
     *
76
     * @return JsonLightODataWriter
77
     */
78
    public function write($model)
79
    {
80
        $this->_writer->startObjectScope();
81
82
        if ($model instanceof ODataURL) {
83
            $this->writeTopLevelMeta('url');
84
            $this->writeURL($model);
85
        } elseif ($model instanceof ODataURLCollection) {
86
            $this->writeTopLevelMeta('urlCollection');
87
            $this->writeURLCollection($model);
88
        } elseif ($model instanceof ODataPropertyContent) {
89
            $this->writeTopLevelMeta($model->properties[0]->typeName);
90
            $this->writeTopLevelProperty($model->properties[0]);
91
        } elseif ($model instanceof ODataFeed) {
92
            $this->writeTopLevelMeta($model->title);
93
            $this->writeRowCount($model->rowCount);
94
            $this->_writer
95
                ->writeName($this->dataArrayName)
96
                ->startArrayScope();
97
            $this->writeFeed($model);
98
            $this->_writer->endScope();
99
        } elseif ($model instanceof ODataEntry) {
100
            $this->writeTopLevelMeta($model->resourceSetName . '/@Element');
101
            $this->writeEntry($model);
102
        }
103
104
        $this->_writer->endScope();
105
106
        return $this;
107
    }
108
109
    /**
110
     * @param ODataProperty $property
111
     *
112
     * @return JsonLightODataWriter
113
     */
114
    protected function writeTopLevelProperty(ODataProperty $property)
115
    {
116
        $this->writePropertyMeta($property);
117
        if ($property->value == null) {
118
            $this->_writer->writeName(ODataConstants::JSON_LIGHT_VALUE_NAME);
119
            $this->_writer->writeValue('null');
120
        } elseif ($property->value instanceof ODataPropertyContent) {
121
            //In the case of complex properties at the top level we don't write the name of the property,
122
            //just the sub properties.
123
            $this->writeComplexPropertyMeta($property)
124
                ->writeProperties($property->value);
125
        } elseif ($property->value instanceof ODataBagContent) {
126
            $this->_writer->writeName(ODataConstants::JSON_LIGHT_VALUE_NAME);
127
            $this->writeBagContent($property->value);
128
        } else {
129
            $this->_writer->writeName(ODataConstants::JSON_LIGHT_VALUE_NAME);
130
            $this->_writer->writeValue($property->value, $property->typeName);
131
        }
132
133
        return $this;
134
    }
135
136
    /**
137
     * @param string $fragment
138
     */
139
    protected function writeTopLevelMeta($fragment)
140
    {
141
        if ($this->metadataLevel == JsonLightMetadataLevel::NONE()) {
142
            return;
143
        }
144
145
        $this->_writer
146
            ->writeName(ODataConstants::JSON_LIGHT_METADATA_STRING)
147
            ->writeValue($this->baseUri . '/' . ODataConstants::URI_METADATA_SEGMENT . '#' . $fragment);
148
    }
149
150
    protected function writePropertyMeta(ODataProperty $property)
151
    {
152
        if ($this->metadataLevel != JsonLightMetadataLevel::FULL()) {
153
            //Only full meta level outputs this info
154
            return $this;
155
        }
156
157
        if (is_null($property->value)) {
158
            //it appears full metadata doesn't output types for nulls...
159
            return $this;
160
        }
161
162
        switch ($property->typeName) {
163
            //The type metadata is only included on certain types of properties
164
            //Note this also excludes Complex types
165
166
            case 'Edm.Decimal':
167
            case 'Edm.DateTime':
168
                $this->_writer
169
                    ->writeName($property->name . ODataConstants::JSON_LIGHT_METADATA_PROPERTY_TYPE_SUFFIX_STRING)
170
                    ->writeValue($property->typeName);
171
        }
172
173
        return $this;
174
    }
175
176
    /**
177
     * @param ODataEntry $entry Entry to write metadata for
178
     *
179
     * @return JsonLightODataWriter
180
     */
181
    protected function writeEntryMetadata(ODataEntry $entry)
182
    {
183
        if ($this->metadataLevel != JsonLightMetadataLevel::FULL()) {
184
            //Only full meta level outputs this info
185
            return $this;
186
        }
187
188
        $this->_writer
189
            ->writeName(ODataConstants::JSON_LIGHT_METADATA_TYPE_STRING)
190
            ->writeValue($entry->type)
191
            ->writeName(ODataConstants::JSON_LIGHT_METADATA_ID_STRING)
192
            ->writeValue($entry->id)
193
            ->writeName(ODataConstants::JSON_LIGHT_METADATA_ETAG_STRING)
194
            ->writeValue($entry->eTag)
195
            ->writeName(ODataConstants::JSON_LIGHT_METADATA_EDIT_LINK_STRING)
196
            ->writeValue($entry->editLink);
197
198
        return $this;
199
    }
200
201
    /**
202
     * @param ODataLink $link Link to write
203
     *
204
     * @return JsonLightODataWriter
205
     */
206
    protected function writeLink(ODataLink $link)
207
    {
208
        if ($this->metadataLevel == JsonLightMetadataLevel::FULL()) {
209
            //Interestingly the fullmetadata outputs this metadata..even if the thing is expanded
210
            $this->_writer
211
                ->writeName($link->title . ODataConstants::JSON_LIGHT_METADATA_LINK_NAVIGATION_SUFFIX_STRING)
212
                ->writeValue($link->url);
213
        }
214
215
        if ($link->isExpanded) {
216
            $this->_writer->writeName($link->title);
217
218
            if (is_null($link->expandedResult)) {
219
                $this->_writer->writeValue('null');
220
            } else {
221
                $this->writeExpandedLink($link);
222
            }
223
        }
224
225
        return $this;
226
    }
227
228 View Code Duplication
    protected function writeExpandedLink(ODataLink $link)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
229
    {
230
        if ($link->isCollection) {
231
            $this->_writer->startArrayScope();
232
            $this->writeFeed($link->expandedResult);
0 ignored issues
show
Bug introduced by
It seems like $link->expandedResult can also be of type object<POData\ObjectModel\ODataEntry>; however, POData\Writers\Json\JsonODataV1Writer::writeFeed() does only seem to accept object<POData\ObjectModel\ODataFeed>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
233
        } else {
234
            $this->_writer->startObjectScope();
235
            $this->writeEntry($link->expandedResult);
0 ignored issues
show
Bug introduced by
It seems like $link->expandedResult can also be of type object<POData\ObjectModel\ODataFeed>; however, POData\Writers\Json\Json...aV1Writer::writeEntry() does only seem to accept object<POData\ObjectModel\ODataEntry>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
236
        }
237
238
        $this->_writer->endScope();
239
    }
240
241
    /**
242
     * Writes the next page link.
243
     *
244
     * @param ODataLink $nextPageLinkUri Uri for next page link
245
     *
246
     * @return JsonLightODataWriter
247
     */
248
    protected function writeNextPageLink(ODataLink $nextPageLinkUri = null)
249
    {
250
        return;
251
    }
252
253
    /**
254
     * Begin write complex property.
255
     *
256
     * @param ODataProperty $property property to write
257
     *
258
     * @return JsonLightODataWriter
259
     */
260
    protected function writeComplexProperty(ODataProperty $property)
261
    {
262
        $this->_writer->startObjectScope();
263
264
        $this->writeComplexPropertyMeta($property)
265
            ->writeProperties($property->value);
0 ignored issues
show
Bug introduced by
It seems like $property->value can also be of type object<POData\ObjectModel\ODataBagContent> or string; however, POData\Writers\Json\Json...iter::writeProperties() does only seem to accept object<POData\ObjectModel\ODataPropertyContent>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
266
267
        $this->_writer->endScope();
268
269
        return $this;
270
    }
271
272
    protected function writeComplexPropertyMeta(ODataProperty $property)
273
    {
274
        if ($this->metadataLevel == JsonLightMetadataLevel::FULL()) {
275
            $this->_writer
276
                ->writeName(ODataConstants::JSON_LIGHT_METADATA_TYPE_STRING)
277
                ->writeValue($property->typeName);
278
        }
279
280
        return $this;
281
    }
282
283
    protected function writeBagContent(ODataBagContent $bag)
284
    {
285
        $this->_writer->startArrayScope();
286
287 View Code Duplication
        foreach ($bag->propertyContents as $content) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
288
            if ($content instanceof ODataPropertyContent) {
289
                $this->_writer->startObjectScope();
290
                $this->writeProperties($content);
291
                $this->_writer->endScope();
292
            } else {
293
                // retrieving the collection datatype in order
294
                //to write in json specific format, with in chords or not
295
                preg_match('#\((.*?)\)#', $bag->type, $type);
296
                $this->_writer->writeValue($content, $type[1]);
297
            }
298
        }
299
300
        $this->_writer->endScope();
301
        return $this;
302
    }
303
}
304