GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#159)
by Roman
01:45
created

AbstractResource::populateFromArray()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 17
ccs 5
cts 5
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 9
nc 3
nop 1
crap 3
1
<?php declare(strict_types=1);
2
3
namespace OpenStack\Common\Resource;
4
5
use OpenStack\Common\Transport\Serializable;
6
use OpenStack\Common\Transport\Utils;
7
use Psr\Http\Message\ResponseInterface;
8
9
/**
10
 * Represents a top-level abstraction of a remote API resource. Usually a resource represents a discrete
11
 * entity such as a Server, Container, Load Balancer. Apart from a representation of state, a resource can
12
 * also execute RESTFul operations on itself (updating, deleting, listing) or on other models.
13
 *
14
 * @package OpenStack\Common\Resource
15
 */
16
abstract class AbstractResource implements ResourceInterface, Serializable
17
{
18
    /**
19
     * The JSON key that indicates how the API nests singular resources. For example, when
20
     * performing a GET, it could respond with ``{"server": {"id": "12345"}}``. In this case,
21
     * "server" is the resource key, since the essential state of the server is nested inside.
22
     *
23
     * @var string
24
     */
25
    protected $resourceKey;
26
27
    /**
28
     * An array of aliases that will be checked when the resource is being populated. For example,
29
     *
30
     * 'FOO_BAR' => 'fooBar'
31
     *
32
     * will extract FOO_BAR from the response, and save it as 'fooBar' in the resource.
33
     *
34
     * 'FOO_BAR' => ['fooBar', \DateTimeImmutable]
35
     *
36
     * will extract FOO_BAR from the response, and save it as 'fooBar' with type \DateTimeImmutable in the resource.
37
     *
38
     * 'FOO_BAR' => ['fooBar', \DateTimeImmutable, true]
39
     *
40
     * do the same as above plus indicates that target property is a list
41
     *
42
     * @var array
43
     */
44
    protected $aliases = [];
45
46
    /**
47
     * Populates the current resource from a response object.
48
     *
49
     * @param ResponseInterface $response
50
     *
51
     * @return AbstractResource
52
     */
53
    public function populateFromResponse(ResponseInterface $response): self
54
    {
55
        if (strpos($response->getHeaderLine('Content-Type'), 'application/json') === 0) {
56
            $json = Utils::jsonDecode($response);
57
            if (!empty($json)) {
58
                $this->populateFromArray(Utils::flattenJson($json, $this->resourceKey));
59
            }
60
        }
61
62
        return $this;
63 74
    }
64
65 74
    /**
66 61
     * Populates the current resource from a data array.
67 61
     *
68 61
     * @param array $array
69 61
     *
70 61
     * @return mixed|void
71
     */
72 74
    public function populateFromArray(array $array): self
73
    {
74
        foreach ($array as $key => $val) {
75
            $alias = (array)($this->aliases[$key] ?? $key);
76
77
            $propertyName = $alias[0];
78
79
            if (property_exists($this, $propertyName)) {
80
                $class = $alias[1] ?? false;
81
                $isList = $alias[2] ?? false;
82 133
83
                $this->$propertyName = $this->normalizePropertyValue($val, $class, $isList);
84 133
            }
85
        }
86 133
87 133
        return $this;
88
    }
89 133
90 131
    private function normalizePropertyValue($value, $class, $isList)
91 128
    {
92 128
        // make sure that target class exists
93
        $class = (($class && class_exists($class)) ? $class : false);
94 131
95 131
        if ($value === null || !$class) {
96 133
            return $value;
97 133
        } elseif ($isList && is_array($value)) {
98
            $array = [];
99 128
            foreach ($value as $subVal) {
100 2
                $array[] = $this->model($class, $subVal);
101 128
            }
102 6
            return $array;
103 6
        } elseif ($class === \DateTimeImmutable::class) {
104 6
            return new \DateTimeImmutable($value);
105 6
        }
106 6
107 128
        return $this->model($class, $value);
108 28
    }
109 127
110 11
    /**
111 11
     * Internal method which retrieves the values of provided keys.
112
     *
113 128
     * @param array $keys
114
     *
115
     * @return array
116 124
     */
117
    protected function getAttrs(array $keys)
118 124
    {
119 124
        $output = [];
120 124
121
        foreach ($keys as $key) {
122
            if (property_exists($this, $key) && $this->$key !== null) {
123 12
                $output[$key] = $this->$key;
124
            }
125 12
        }
126 12
127 12
        return $output;
128 12
    }
129
130 12 View Code Duplication
    public function model(string $class, $data = null): ResourceInterface
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...
131
    {
132
        $model = new $class();
133 131
134
        // @codeCoverageIgnoreStart
135 131
        if (!$model instanceof ResourceInterface) {
136
            throw new \RuntimeException(sprintf('%s does not implement %s', $class, ResourceInterface::class));
137 131
        }
138 3
        // @codeCoverageIgnoreEnd
139
140
        if ($data instanceof ResponseInterface) {
141 128
            $model->populateFromResponse($data);
142 128
        } elseif (is_array($data)) {
143 128
            $model->populateFromArray($data);
144
        }
145
146
        return $model;
147
    }
148
149
    public function serialize(): \stdClass
150
    {
151
        $output = new \stdClass();
152
153 65
        foreach ((new \ReflectionClass($this))->getProperties(\ReflectionProperty::IS_PUBLIC) as $property) {
154
            $name = $property->getName();
155 65
            $val = $this->{$name};
156
157 65
            $fn = function ($val) {
158 65
                return ($val instanceof Serializable) ? $val->serialize() : $val;
159 65
            };
160 65
161 65
            if (is_array($val)) {
162
                foreach ($val as $sk => $sv) {
163 65
                    $val[$sk] = $fn($sv);
164
                }
165
            }
166
167
            $output->{$name} = $fn($val);
168
        }
169
170
        return $output;
171 60
    }
172
}
173