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
Push — master ( 8c3ee0...d7f4ea )
by Hong
04:46
created

Resolver   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 228
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 3

Importance

Changes 1
Bugs 0 Features 1
Metric Value
wmc 25
c 1
b 0
f 1
lcom 3
cbo 3
dl 0
loc 228
rs 10

15 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 23 2
A resolve() 0 7 3
A setObjectResolver() 0 10 2
A getInSection() 0 4 1
A hasInSection() 0 6 1
A setInSection() 0 7 1
A getService() 0 4 1
A hasService() 0 8 3
A setService() 0 13 2
A getMapping() 0 4 1
A hasMapping() 0 4 1
A setMapping() 0 4 1
A autoWiring() 0 5 1
A getSectionId() 0 7 2
A autoClassName() 0 8 3
1
<?php
2
/**
3
 * Phossa Project
4
 *
5
 * PHP version 5.4
6
 *
7
 * @category  Library
8
 * @package   Phossa2\Di
9
 * @copyright Copyright (c) 2016 phossa.com
10
 * @license   http://mit-license.org/ MIT License
11
 * @link      http://www.phossa.com/
12
 */
13
/*# declare(strict_types=1); */
14
15
namespace Phossa2\Di\Resolver;
16
17
use Phossa2\Di\Container;
18
use Phossa2\Config\Config;
19
use Phossa2\Di\Interfaces\ResolverInterface;
20
use Phossa2\Di\Interfaces\AutoWiringInterface;
21
use Phossa2\Config\Interfaces\ConfigInterface;
22
use Phossa2\Config\Interfaces\WritableInterface;
23
use Phossa2\Config\Delegator as ConfigDelegator;
24
25
/**
26
 * Resolver
27
 *
28
 * - Resolver is a config delegator with
29
 *   - '#service_id' type of objects lookup
30
 *   - parameter config lookup.
31
 *
32
 * - Resolver implements ResolverInterface for easy access to different sections
33
 *   of the parameter config.
34
 *
35
 * @package Phossa2\Di
36
 * @author  Hong Zhang <[email protected]>
37
 * @see     \Phossa2\Config\Delegator
38
 * @see     ResolverInterface
39
 * @see     AutoWiringInterface
40
 * @version 2.0.0
41
 * @since   2.0.0 added
42
 */
43
class Resolver extends ConfigDelegator implements ResolverInterface, AutoWiringInterface
44
{
45
    /**
46
     * The outer master
47
     *
48
     * @var    Container
49
     * @access protected
50
     */
51
    protected $master;
52
53
    /**
54
     * The object resolver
55
     *
56
     * @var    ObjectResolver
57
     * @access protected
58
     */
59
    protected $object_resolver;
60
61
    /**
62
     * The parameter resolver
63
     *
64
     * @var    ConfigInterface
65
     * @access protected
66
     */
67
    protected $config_resolver;
68
69
    /**
70
     * Container related definition starting node at $config
71
     *
72
     * @var    string
73
     * @access protected
74
     */
75
    protected $base_node;
76
77
    /**
78
     * Autowiring: automatically resolve classname if it is a defined class
79
     *
80
     * @var    bool
81
     * @access protected
82
     */
83
    protected $auto = true;
84
85
    /**
86
     * @param  Container $master the master
87
     * @param  ConfigInterface $config used for parameter resolving
88
     * @param  string $nodeName
89
     * @access public
90
     */
91
    public function __construct(
92
        Container $master,
93
        ConfigInterface $config,
94
        /*# string */ $nodeName
95
    ) {
96
        // set config and make it writable
97
        $this->config_resolver = $config;
98
        if ($config instanceof WritableInterface) {
99
            $config->setWritable(true);
100
        }
101
102
        // set base node
103
        $this->base_node = $nodeName;
104
105
        // set object resolver
106
        $this->master = $master;
107
        $this->object_resolver = new ObjectResolver();
108
        $this->setObjectResolver();
109
110
        // set up lookup pool
111
        $this->addRegistry($this->object_resolver)
112
             ->addRegistry($this->config_resolver);
113
    }
114
115
    /**
116
     * {@inheritDoc}
117
     */
118
    public function resolve(&$toResolve)
119
    {
120
        if (is_array($toResolve) || is_string($toResolve)) {
121
            $this->config_resolver->deReferenceArray($toResolve);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Phossa2\Config\Interfaces\ConfigInterface as the method deReferenceArray() does only exist in the following implementations of said interface: Phossa2\Config\Config.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
122
        }
123
        return $this;
124
    }
125
126
    /**
127
     * {@inheritDoc}
128
     */
129
    public function setObjectResolver()
130
    {
131
        // either master container or master's container delegator
132
        if ($this->master->hasDelegator()) {
133
            $container = $this->master->getDelegator();
134
        } else {
135
            $container = $this->master;
136
        }
137
        $this->object_resolver->setContainer($container);
138
    }
139
140
    /**
141
     * {@inheritDoc}
142
     */
143
    public function getInSection(/*# string */ $id, /*# string */ $section)
144
    {
145
        return $this->get($this->getSectionId($id, $section));
146
    }
147
148
    /**
149
     * {@inheritDoc}
150
     */
151
    public function hasInSection(
152
        /*# string */ $id,
153
        /*# string */ $section
154
    )/*# : bool */ {
155
        return $this->has($this->getSectionId($id, $section));
156
    }
157
158
    /**
159
     * {@inheritDoc}
160
     */
161
    public function setInSection(
162
        /*# string */ $id,
163
        /*# string */ $section,
164
        $value
165
    ) {
166
        return $this->set($this->getSectionId($id, $section), $value);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->set($this-...id, $section), $value); (Phossa2\Config\Delegator) is incompatible with the return type declared by the interface Phossa2\Di\Interfaces\Re...Interface::setInSection of type Phossa2\Di\Interfaces\ResolverInterface.

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...
167
    }
168
169
    /**
170
     * {@inheritDoc}
171
     */
172
    public function getService(/*# string */ $id = '')
173
    {
174
        return $this->getInSection($id, 'service');
175
    }
176
177
    /**
178
     * {@inheritDoc}
179
     */
180
    public function hasService(/*# string */ $id = '')/*# : bool */
181
    {
182
        // with autoWiring supported
183
        if ($this->hasInSection($id, 'service') || $this->autoClassName($id)) {
184
            return true;
185
        }
186
        return false;
187
    }
188
189
    /**
190
     * {@inheritDoc}
191
     */
192
    public function setService(
193
        /*# string */ $id,
194
        $definition,
195
        array $arguments = []
196
    ) {
197
        if (!empty($arguments)) {
198
            $definition = [
199
                'class' => $definition,
200
                'args'  => $arguments
201
            ];
202
        }
203
        return $this->setInSection($id, 'service', $definition);
204
    }
205
206
    /**
207
     * {@inheritDoc}
208
     */
209
    public function getMapping(/*# string */ $id = '')
210
    {
211
        return $this->getInSection($id, 'mapping');
212
    }
213
214
    /**
215
     * {@inheritDoc}
216
     */
217
    public function hasMapping(/*# string */ $id = '')/*# : bool */
218
    {
219
        return $this->hasInSection($id, 'mapping');
220
    }
221
222
    /**
223
     * {@inheritDoc}
224
     */
225
    public function setMapping(/*# string */ $from, $to)
226
    {
227
        return $this->setInSection($from, 'mapping', $to);
228
    }
229
230
    /**
231
     * {@inheritDoc}
232
     */
233
    public function autoWiring(/*# bool */ $on = true)
234
    {
235
        $this->auto = (bool) $on;
236
        return $this;
237
    }
238
239
    /**
240
     * Generate new id base on base and section
241
     *
242
     * @param  string $id
243
     * @param  string $section
244
     * @return string
245
     * @access protected
246
     */
247
    protected function getSectionId(
248
        /*# string */ $id,
249
        /*# string */ $section
250
    )/*# : string */ {
251
        $sec = $this->base_node . '.' . $section;
252
        return '' == $id ? $sec : ($sec . '.' . $id);
253
    }
254
255
    /**
256
     * If autowiring is on, and $id is a existing classname, return true
257
     *
258
     * @param  string $id
259
     * @return bool
260
     * @access protected
261
     */
262
    protected function autoClassName(/*# string */ $id)/*# : bool */
263
    {
264
        if ($this->auto && class_exists($id)) {
265
            $this->setService($id, ['class' => $id]);
266
            return true;
267
        }
268
        return false;
269
    }
270
}
271