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.
Passed
Push — master ( 6bcf7a...9715be )
by Jamie
10:17
created

Operator::__debugInfo()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 4
Bugs 1 Features 1
Metric Value
c 4
b 1
f 1
dl 0
loc 14
ccs 0
cts 9
cp 0
rs 9.4286
cc 3
eloc 7
nc 3
nop 0
crap 12
1
<?php
2
3
namespace OpenStack\Common\Api;
4
5
use function GuzzleHttp\uri_template;
6
use GuzzleHttp\ClientInterface;
7
use GuzzleHttp\Promise\Promise;
8
use OpenStack\Common\Resource\ResourceInterface;
9
use OpenStack\Common\Transport\RequestSerializer;
10
use Psr\Http\Message\ResponseInterface;
11
12
/**
13
 * {@inheritDoc}
14
 */
15
abstract class Operator implements OperatorInterface
16
{
17
    /** @var ClientInterface */
18
    private $client;
19
20
    /** @var ApiInterface */
21
    protected $api;
22
23
    /**
24
     * {@inheritDoc}
25
     */
26 214
    public function __construct(ClientInterface $client, ApiInterface $api)
27
    {
28 214
        $this->client = $client;
29 214
        $this->api = $api;
30 214
    }
31
32
    /**
33
     * Magic method for dictating how objects are rendered when var_dump is called.
34
     * For the benefit of users, extremely verbose and heavy properties (such as HTTP clients) are
35
     * removed to provide easier access to normal state, such as resource attributes.
36
     *
37
     * @return array
38
     */
39
    public function __debugInfo()
40
    {
41
        $excludedVars = ['client', 'errorBuilder', 'api'];
42
43
        $output = [];
44
45
        foreach (get_object_vars($this) as $key => $val) {
46
            if (!in_array($key, $excludedVars)) {
47
                $output[$key] = $val;
48
            }
49
        }
50
51
        return $output;
52
    }
53
54
    /**
55
     * Retrieves a populated Operation according to the definition and values provided. A
56
     * HTTP client is also injected into the object to allow it to communicate with the remote API.
57
     *
58
     * @param array $definition  The data that dictates how the operation works
59
     *
60
     * @return Operation
61
     */
62 165
    public function getOperation(array $definition)
63
    {
64 165
        return new Operation($definition);
65
    }
66
67 164
    protected function sendRequest(Operation $operation, array $userValues = [], $async = false)
68
    {
69 164
        $uri     = uri_template($operation->getPath(), $userValues);
70 164
        $options = RequestSerializer::serializeOptions($operation, $userValues);
71 164
        $method  = $async ? 'requestAsync' : 'request';
72
73 164
        return $this->client->$method($operation->getMethod(), $uri, $options);
74
    }
75
76
    /**
77
     * {@inheritDoc}
78
     */
79
    public function executeAsync(array $definition, array $userValues = [])
80
    {
81
        return $this->sendRequest($this->getOperation($definition), $userValues, true);
82
    }
83
84 138
    public function execute(array $definition, array $userValues = [])
85
    {
86 138
        return $this->sendRequest($this->getOperation($definition), $userValues);
87
    }
88
89
    /**
90
     * {@inheritDoc}
91
     */
92 80
    public function model($class, $data = null)
93
    {
94 80
        $model = new $class($this->client, $this->api);
95
96
        // @codeCoverageIgnoreStart
97
        if (!$model instanceof ResourceInterface) {
98
            throw new \RuntimeException(sprintf('%s does not implement %s', $class, ResourceInterface::class));
99
        }
100
        // @codeCoverageIgnoreEnd
101
102 80
        if ($data instanceof ResponseInterface) {
103 2
            $model->populateFromResponse($data);
104 80
        } elseif (is_array($data)) {
105 23
            $model->populateFromArray($data);
106 23
        }
107
108 80
        return $model;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $model; (OpenStack\Common\Resource\ResourceInterface) is incompatible with the return type declared by the interface OpenStack\Common\Api\OperatorInterface::model of type OpenStack\Common\Api\ResourceInterface.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
109
    }
110
111
    /**
112
     * Will create a new instance of this class with the current HTTP client and API injected in. This
113
     * is useful when enumerating over a collection since multiple copies of the same resource class
114
     * are needed.
115
     *
116
     * @return static
117
     */
118 30
    public function newInstance()
119
    {
120 30
        return new static($this->client, $this->api);
121
    }
122
123
    /**
124
     * @return \GuzzleHttp\Psr7\Uri
125
     */
126 1
    protected function getHttpBaseUrl()
127
    {
128 1
        return $this->client->getConfig('base_url');
129
    }
130
131
    /**
132
     * Magic method which intercepts async calls, finds the sequential version, and wraps it in a
133
     * {@see Promise} object. In order for this to happen, the called methods need to be in the
134
     * following format: `createAsync`, where `create` is the sequential method being wrapped.
135
     *
136
     * @param $methodName The name of the method being invoked.
137
     * @param $args       The arguments to be passed to the sequential method.
138
     *
139
     * @return Promise
140
     */
141 2
    public function __call($methodName, $args)
142
    {
143 2
        if (substr($methodName, -5) === 'Async') {
144 2
            $realMethod = substr($methodName, 0, -5);
145 2
            if (!method_exists($this, $realMethod)) {
146 1
                throw new \InvalidArgumentException(sprintf(
147 1
                    '%s is not a defined method on %s', $realMethod, get_class($this)
148 1
                ));
149
            }
150
151 1
            $promise = new Promise(
152
                function () use (&$promise, $realMethod, $args) {
153 1
                    $value = call_user_func_array([$this, $realMethod], $args);
154 1
                    $promise->resolve($value);
155 1
                },
156
                function ($e) use (&$promise) {
157
                    $promise->reject($e);
158
                }
159 1
            );
160
161 1
            return $promise;
162
        }
163
    }
164
}