Passed
Push — master ( 215600...914e6e )
by Alain
02:30
created

ViewBuilder   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 211
Duplicated Lines 18.48 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 75%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 19
c 3
b 0
f 0
lcom 1
cbo 6
dl 39
loc 211
ccs 33
cts 44
cp 0.75
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
A create() 0 9 2
A getEngine() 0 4 1
A getView() 0 8 2
A getViewFinder() 9 9 2
A getEngineFinder() 9 9 2
A addLocation() 0 4 1
A scanLocations() 0 11 3
B resolveType() 21 21 5

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/**
3
 * Bright Nucleus View Component.
4
 *
5
 * @package   BrightNucleus\View
6
 * @author    Alain Schlesser <[email protected]>
7
 * @license   MIT
8
 * @link      http://www.brightnucleus.com/
9
 * @copyright 2016 Alain Schlesser, Bright Nucleus
10
 */
11
12
namespace BrightNucleus\View;
13
14
use BrightNucleus\Config\ConfigInterface;
15
use BrightNucleus\Config\ConfigTrait;
16
use BrightNucleus\Config\Exception\FailedToProcessConfigException;
17
use BrightNucleus\View\Engine\EngineFinderInterface;
18
use BrightNucleus\View\Engine\EngineInterface;
19
use BrightNucleus\View\Engine\ViewFinderInterface;
20
use BrightNucleus\View\Exception\FailedToInstantiateViewException;
21
use BrightNucleus\View\Location\LocationInterface;
22
use BrightNucleus\View\View\ViewInterface;
23
24
/**
25
 * Class ViewBuilder.
26
 *
27
 * @since   0.1.0
28
 *
29
 * @package BrightNucleus\View
30
 * @author  Alain Schlesser <[email protected]>
31
 */
32
class ViewBuilder
33
{
34
35
    use ConfigTrait;
36
37
    const ENGINE_FINDER_KEY = 'EngineFinder';
38
    const VIEW_FINDER_KEY   = 'ViewFinder';
39
40
    /**
41
     * ViewFinder instance.
42
     *
43
     * @since 0.1.0
44
     *
45
     * @var ViewFinderInterface
46
     */
47
    protected $viewFinder;
48
49
    /**
50
     * EngineFinder instance.
51
     *
52
     * @since 0.1.0
53
     *
54
     * @var EngineFinderInterface
55
     */
56
    protected $engineFinder;
57
58
    /**
59
     * Locations to scan for views.
60
     *
61
     * @since 0.1.0
62
     *
63
     * @var LocationInterface[]
64
     */
65
    protected $locations;
66
67
    /**
68
     * Instantiate a ViewBuilder object.
69
     *
70
     * @since 0.1.0
71
     *
72
     * @param ConfigInterface            $config       Configuration settings.
73
     * @param ViewFinderInterface|null   $viewFinder   ViewFinder instance.
74
     * @param EngineFinderInterface|null $engineFinder EngineFinder instance.
75
     *
76
     * @throws FailedToProcessConfigException If the config could not be processed.
77
     */
78 7
    public function __construct(
79
        ConfigInterface $config,
80
        ViewFinderInterface $viewFinder = null,
81
        EngineFinderInterface $engineFinder = null
82
    ) {
83 7
        $this->processConfig($config);
84 7
        $this->viewFinder   = $viewFinder;
85 7
        $this->engineFinder = $engineFinder;
86 7
    }
87
88
    /**
89
     * Create a new view for a given URI.
90
     *
91
     * @since 0.1.0
92
     *
93
     * @param string      $view View identifier to create a view for.
94
     * @param string|null $type Type of view to create.
95
     *
96
     * @return ViewInterface Instance of the requested view.
97
     */
98 17
    public function create($view, $type = null)
99
    {
100 17
        $uri    = $this->scanLocations([$view]);
101 17
        $engine = $this->getEngine($uri);
102
103 17
        return $uri
104 17
            ? $this->getView($uri, $engine, $type)
105 17
            : $this->getViewFinder()->getNullObject();
106
    }
107
108
    /**
109
     * Get an Engine that can deal with the given URI.
110
     *
111
     * @since 0.1.0
112
     *
113
     * @param string|false $uri URI to get an engine for.
114
     *
115
     * @return EngineInterface Instance of an engine that can deal with the given URI.
116
     */
117 17
    public function getEngine($uri)
118
    {
119 17
        return $this->getEngineFinder()->find([$uri]);
120
    }
121
122
    /**
123
     * Get a view for a given URI, engine and type.
124
     *
125
     * @since 0.1.0
126
     *
127
     * @param string          $uri    URI to get a view for.
128
     * @param EngineInterface $engine Engine to use for the view.
129
     * @param mixed           $type   Type of view to get.
130
     *
131
     * @return ViewInterface View that matches the given requirements.
132
     */
133 17
    public function getView($uri, EngineInterface $engine, $type = null)
134
    {
135 17
        if (null === $type) {
136 17
            return $this->getViewFinder()->find([$uri], $engine);
137
        }
138
139
        return $this->resolveType($type, $uri, $engine);
140
    }
141
142
    /**
143
     * Get the ViewFinder instance.
144
     *
145
     * @since 0.1.0
146
     *
147
     * @return ViewFinderInterface Instance of a ViewFinder.
148
     */
149 17 View Code Duplication
    public function getViewFinder()
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...
150
    {
151 17
        if (null === $this->viewFinder) {
152 7
            $viewFinderClass  = $this->config->getKey(static::VIEW_FINDER_KEY, 'ClassName');
0 ignored issues
show
Unused Code introduced by
The call to ConfigInterface::getKey() has too many arguments starting with 'ClassName'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
153 7
            $this->viewFinder = new $viewFinderClass($this->config->getSubConfig(static::VIEW_FINDER_KEY));
154
        }
155
156 17
        return $this->viewFinder;
157
    }
158
159
    /**
160
     * Get the EngineFinder instance.
161
     *
162
     * @since 0.1.0
163
     *
164
     * @return EngineFinderInterface Instance of a EngineFinder.
165
     */
166 17 View Code Duplication
    public function getEngineFinder()
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...
167
    {
168 17
        if (null === $this->engineFinder) {
169 7
            $engineFinderClass  = $this->config->getKey(static::ENGINE_FINDER_KEY, 'ClassName');
0 ignored issues
show
Unused Code introduced by
The call to ConfigInterface::getKey() has too many arguments starting with 'ClassName'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
170 7
            $this->engineFinder = new $engineFinderClass($this->config->getSubConfig(static::ENGINE_FINDER_KEY));
171
        }
172
173 17
        return $this->engineFinder;
174
    }
175
176
    /**
177
     * Add a location to scan with the ViewFinder.
178
     *
179
     * @since 0.1.0
180
     *
181
     * @param LocationInterface $location Location to scan with the ViewFinder.
182
     */
183 17
    public function addLocation(LocationInterface $location)
184
    {
185 17
        $this->locations[] = $location;
186 17
    }
187
188
    /**
189
     * Scan Locations for an URI that matches the specified criteria.
190
     *
191
     * @since 0.1.0
192
     *
193
     * @param array $criteria Criteria to match.
194
     *
195
     * @return string|bool URI of the requested view, or false if not found.
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use string|false.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
196
     */
197 17
    public function scanLocations(array $criteria)
198
    {
199
        /** @var LocationInterface $location */
200 17
        foreach ($this->locations as $location) {
201 17
            if ($uri = $location->getURI($criteria)) {
202 17
                return $uri;
203
            }
204
        }
205
206
        return false;
207
    }
208
209
    /**
210
     * Resolve the view type.
211
     *
212
     * @since 0.1.0
213
     *
214
     * @param mixed           $type   Type of view that was requested.
215
     * @param string          $uri    URI to get a view for.
216
     * @param EngineInterface $engine Engine to use for the view.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $engine not be null|EngineInterface?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
217
     *
218
     * @return ViewInterface Resolved View object.
219
     * @throws FailedToInstantiateViewException If the view type could not be resolved.
220
     */
221 View Code Duplication
    protected function resolveType($type, $uri, EngineInterface $engine = null)
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...
222
    {
223
        if (is_string($type) && $this->config->hasKey(static::VIEW_FINDER_KEY)) {
224
            $type = new $type($uri, $engine);
225
        }
226
227
        if (is_callable($type)) {
228
            $type = $type($uri, $engine);
229
        }
230
231
        if (! $type instanceof ViewInterface) {
232
            throw new FailedToInstantiateViewException(
233
                sprintf(
234
                    _('Could not instantiate view "%s".'),
235
                    serialize($type)
236
                )
237
            );
238
        }
239
240
        return $type;
241
    }
242
}
243