Passed
Push — master ( d16bab...9efe7c )
by Anton
37s
created

src/JsonApiParser.php (5 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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
        $data =  ArrayHelper::getValue($array, 'data', []);
0 ignored issues
show
Equals sign not aligned with surrounding assignments; expected 2 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
38
        if (empty($data)) {
39
            if ($this->throwException) {
40
                throw new BadRequestHttpException('The request MUST include a single resource object as primary data.');
41
            }
42
            return [];
43
        }
44
        if (ArrayHelper::isAssociative($data)) {
45
            $result = $this->parseResource($data);
46
47
            $relObjects = ArrayHelper::getValue($data, 'relationships', []);
0 ignored issues
show
Equals sign not aligned with surrounding assignments; expected 14 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
48
            $result['relationships'] = $this->parseRelationships($relObjects);
49
        } else {
50
            foreach ($data as $object) {
51
                $resource = $this->parseResource($object);
52
                foreach (array_keys($resource) as $key) {
53
                    $result[$key][] = $resource[$key];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$result was never initialized. Although not strictly required by PHP, it is generally a good practice to add $result = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
54
                }
55
            }
56
        }
57
58
        return isset($result) ? $result : $array;
59
    }
60
61
    /**
62
     * @param $type 'type' member of the document
63
     * @return string form name
64
     */
65
    protected function typeToFormName($type)
66
    {
67
        return call_user_func($this->formNameCallback, $type);
68
    }
69
70
    /**
71
     * @param array $memberNames
72
     * @return array variable names
73
     */
74
    protected function parseMemberNames(array $memberNames = [])
75
    {
76
        return array_map($this->memberNameCallback, $memberNames);
77
    }
78
79
    /**
80
     * @param $item
81
     * @return array
82
     * @throws BadRequestHttpException
83
     */
84
    protected function parseResource($item)
85
    {
86
        if (!$type = ArrayHelper::getValue($item, 'type')) {
87
            if ($this->throwException) {
88
                throw new BadRequestHttpException('The resource object MUST contain at least a type member');
89
            }
90
            return [];
91
        }
92
        $formName = $this->typeToFormName($type);
93
94
        $attributes = ArrayHelper::getValue($item, 'attributes', []);
95
        $attributes = array_combine($this->parseMemberNames(array_keys($attributes)), array_values($attributes));
96
97
        if ($id = ArrayHelper::getValue($item, 'id')) {
98
            $attributes['id'] = $id;
99
        }
100
101
        return [$formName => $attributes];
102
    }
103
104
    /**
105
     * @param array $relObjects
106
     * @return array
107
     */
108
    protected function parseRelationships(array $relObjects = [])
109
    {
110
        $relationships = [];
111
        foreach ($relObjects as $name => $relationship) {
112
            if (!$relData = ArrayHelper::getValue($relationship, 'data')) {
113
                continue;
114
            }
115
            if (!ArrayHelper::isIndexed($relData)) {
116
                $relData = [$relData];
117
            }
118
            foreach ($relData as $identifier) {
119
                if (isset($identifier['type']) && isset($identifier['id'])) {
120
                    $formName = $this->typeToFormName($identifier['type']);
0 ignored issues
show
Equals sign not aligned with surrounding assignments; expected 26 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
121
                    $relationships[$name][$formName][] = ['id' => $identifier['id']];
122
                }
123
            }
124
        }
125
        return $relationships;
126
    }
127
}
0 ignored issues
show
As per coding style, files should not end with a newline character.

This check marks files that end in a newline character, i.e. an empy line.

Loading history...
128