Passed
Push — master ( 1e7324...b1935f )
by Alain
02:45
created

ViewBuilder   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 226
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 69.57%

Importance

Changes 7
Bugs 0 Features 1
Metric Value
wmc 20
c 7
b 0
f 1
lcom 1
cbo 6
dl 0
loc 226
ccs 32
cts 46
cp 0.6957
rs 10

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

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
153
    }
154
155
    /**
156
     * Get the EngineFinder instance.
157
     *
158
     * @since 0.1.0
159
     *
160
     * @return EngineFinderInterface Instance of a EngineFinder.
161
     */
162 17
    public function getEngineFinder()
163
    {
164 17
        return $this->getFinder($this->engineFinder, ViewBuilder::ENGINE_FINDER_KEY);
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
165
    }
166
167
    /**
168
     * Add a location to scan with the ViewFinder.
169
     *
170
     * @since 0.1.0
171
     *
172
     * @param LocationInterface $location Location to scan with the ViewFinder.
173
     */
174 17
    public function addLocation(LocationInterface $location)
175
    {
176 17
        $this->locations[] = $location;
177 17
    }
178
179
    /**
180
     * Scan Locations for an URI that matches the specified criteria.
181
     *
182
     * @since 0.1.0
183
     *
184
     * @param array $criteria Criteria to match.
185
     *
186
     * @return string|false URI of the requested view, or false if not found.
187
     */
188 17
    public function scanLocations(array $criteria)
189
    {
190
        /** @var LocationInterface $location */
191 17
        foreach ($this->locations as $location) {
192 17
            if ($uri = $location->getURI($criteria)) {
193 17
                return $uri;
194
            }
195
        }
196
197
        return false;
198
    }
199
200
    /**
201
     * Get a finder instance.
202
     *
203
     * @since 0.1.1
204
     *
205
     * @param mixed  $property Property to use.
206
     * @param string $key      Configuration key to use.
207
     *
208
     * @return FinderInterface The requested finder instance.
209
     */
210 17
    protected function getFinder(&$property, $key)
211
    {
212 17
        if (null === $property) {
213 7
            $engineFinderClass = $this->config->getKey($key, 'ClassName');
1 ignored issue
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...
214 7
            $property          = new $engineFinderClass($this->config->getSubConfig($key));
215
        }
216
217 17
        return $property;
218
    }
219
220
    /**
221
     * Resolve the view type.
222
     *
223
     * @since 0.1.0
224
     *
225
     * @param mixed                $type   Type of view that was requested.
226
     * @param string               $uri    URI to get a view for.
227
     * @param EngineInterface|null $engine Engine to use for the view.
228
     *
229
     * @return ViewInterface Resolved View object.
230
     * @throws FailedToInstantiateViewException If the view type could not be resolved.
231
     */
232
    protected function resolveType($type, $uri, EngineInterface $engine = null)
233
    {
234
        if (is_string($type) && $this->config->hasKey(static::VIEW_FINDER_KEY, 'Views', $type)) {
0 ignored issues
show
Unused Code introduced by
The call to ConfigInterface::hasKey() has too many arguments starting with 'Views'.

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...
235
            $className = $this->config->getKey(static::VIEW_FINDER_KEY, 'Views', $type);
0 ignored issues
show
Unused Code introduced by
The call to ConfigInterface::getKey() has too many arguments starting with 'Views'.

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...
236
            $type      = new $className($uri, $engine);
237
        }
238
239
        if (is_string($type)) {
240
            $type = new $type($uri, $engine);
241
        }
242
243
        if (is_callable($type)) {
244
            $type = $type($uri, $engine);
245
        }
246
247
        if (! $type instanceof ViewInterface) {
248
            throw new FailedToInstantiateViewException(
249
                sprintf(
250
                    _('Could not instantiate view "%s".'),
251
                    serialize($type)
252
                )
253
            );
254
        }
255
256
        return $type;
257
    }
258
}
259