JsonApiParser   A
last analyzed

Complexity

Total Complexity 22

Size/Duplication

Total Lines 119
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 46
c 1
b 0
f 0
dl 0
loc 119
rs 10
wmc 22

5 Methods

Rating   Name   Duplication   Size   Complexity  
A parseResource() 0 18 4
A parseMemberNames() 0 3 1
A typeToFormName() 0 3 1
B parseRelationships() 0 20 7
B parse() 0 28 9
1
<?php
2
/**
3
 * @author Anton Tuyakhov <[email protected]>
4
 */
5
6
namespace tuyakhov\jsonapi;
7
8
use yii\helpers\ArrayHelper;
9
use yii\web\BadRequestHttpException;
10
use \yii\web\JsonParser;
11
12
class JsonApiParser extends JsonParser
13
{
14
    /**
15
     * Converts 'type' member to form name
16
     * If not set, type will be converted to singular form.
17
     * For example, 'articles' will be converted to 'Article'
18
     * @var callable
19
     */
20
    public $formNameCallback = ['tuyakhov\jsonapi\Inflector', 'type2form'];
21
22
    /**
23
     * Converts member names to variable names
24
     * If not set, all special characters will be replaced by underscore
25
     * For example, 'first-name' will be converted to 'first_name'
26
     * @var callable
27
     */
28
    public $memberNameCallback = ['tuyakhov\jsonapi\Inflector', 'member2var'];
29
30
    /**
31
     * Parse resource object into the input data to populates the model
32
     * @inheritdoc
33
     */
34
    public function parse($rawBody, $contentType)
35
    {
36
        $array = parent::parse($rawBody, $contentType);
37
        if (!empty($array) && !ArrayHelper::keyExists('data', $array)) {
38
            if ($this->throwException) {
39
                throw new BadRequestHttpException('The request MUST include a single resource object as primary data.');
40
            }
41
            return [];
42
        }
43
        $data =  ArrayHelper::getValue($array, 'data', []);
44
        if (empty($data)) {
45
            return [];
46
        }
47
        if (ArrayHelper::isAssociative($data)) {
48
            $result = $this->parseResource($data);
49
50
            $relObjects = ArrayHelper::getValue($data, 'relationships', []);
51
            $result['relationships'] = $this->parseRelationships($relObjects);
52
        } else {
53
            foreach ($data as $object) {
54
                $resource = $this->parseResource($object);
55
                foreach (array_keys($resource) as $key) {
56
                    $result[$key][] = $resource[$key];
57
                }
58
            }
59
        }
60
61
        return isset($result) ? $result : $array;
62
    }
63
64
    /**
65
     * @param $type 'type' member of the document
0 ignored issues
show
Documentation Bug introduced by
The doc comment 'type' at position 0 could not be parsed: Unknown type name ''type'' at position 0 in 'type'.
Loading history...
66
     * @return string form name
67
     */
68
    protected function typeToFormName($type)
69
    {
70
        return call_user_func($this->formNameCallback, $type);
71
    }
72
73
    /**
74
     * @param array $memberNames
75
     * @return array variable names
76
     */
77
    protected function parseMemberNames(array $memberNames = [])
78
    {
79
        return array_map($this->memberNameCallback, $memberNames);
80
    }
81
82
    /**
83
     * @param $item
84
     * @return array
85
     * @throws BadRequestHttpException
86
     */
87
    protected function parseResource($item)
88
    {
89
        if (!$type = ArrayHelper::getValue($item, 'type')) {
90
            if ($this->throwException) {
91
                throw new BadRequestHttpException('The resource object MUST contain at least a type member');
92
            }
93
            return [];
94
        }
95
        $formName = $this->typeToFormName($type);
96
97
        $attributes = ArrayHelper::getValue($item, 'attributes', []);
98
        $attributes = array_combine($this->parseMemberNames(array_keys($attributes)), array_values($attributes));
99
100
        if ($id = ArrayHelper::getValue($item, 'id')) {
101
            $attributes['id'] = $id;
102
        }
103
104
        return [$formName => $attributes];
105
    }
106
107
    /**
108
     * @param array $relObjects
109
     * @return array
110
     */
111
    protected function parseRelationships(array $relObjects = [])
112
    {
113
        $relationships = [];
114
        foreach ($relObjects as $name => $relationship) {
115
            if (!ArrayHelper::keyExists('data', $relationship)) {
116
                continue;
117
            }
118
            $relData = ArrayHelper::getValue($relationship, 'data', []);
119
            if (!ArrayHelper::isIndexed($relData)) {
120
                $relData = [$relData];
121
            }
122
            $relationships[$name] = [];
123
            foreach ($relData as $identifier) {
124
                if (isset($identifier['type']) && isset($identifier['id'])) {
125
                    $formName = $this->typeToFormName($identifier['type']);
126
                    $relationships[$name][$formName][] = ['id' => $identifier['id']];
127
                }
128
            }
129
        }
130
        return $relationships;
131
    }
132
}
133