Passed
Push — master ( 6d9d43...921f98 )
by Alain
02:46
created

ViewBuilder   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 227
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 70.83%

Importance

Changes 10
Bugs 0 Features 1
Metric Value
wmc 19
c 10
b 0
f 1
lcom 1
cbo 7
dl 0
loc 227
ccs 34
cts 48
cp 0.7083
rs 10

10 Methods

Rating   Name   Duplication   Size   Complexity  
A getFinder() 0 9 2
B resolveType() 0 28 6
A __construct() 0 10 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 9 2
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\LocationCollection;
22
use BrightNucleus\View\Location\LocationInterface;
23
use BrightNucleus\View\Support\FinderInterface;
24
use BrightNucleus\View\View\ViewInterface;
25
26
/**
27
 * Class ViewBuilder.
28
 *
29
 * @since   0.1.0
30
 *
31
 * @package BrightNucleus\View
32
 * @author  Alain Schlesser <[email protected]>
33
 */
34
class ViewBuilder
35
{
36
37
    use ConfigTrait;
38
39
    const ENGINE_FINDER_KEY = 'EngineFinder';
40
    const VIEW_FINDER_KEY   = 'ViewFinder';
41
42
    /**
43
     * ViewFinder instance.
44
     *
45
     * @since 0.1.0
46
     *
47
     * @var ViewFinderInterface
48
     */
49
    protected $viewFinder;
50
51
    /**
52
     * EngineFinder instance.
53
     *
54
     * @since 0.1.0
55
     *
56
     * @var EngineFinderInterface
57
     */
58
    protected $engineFinder;
59
60
    /**
61
     * Locations to scan for views.
62
     *
63
     * @since 0.1.0
64
     *
65
     * @var LocationCollection
66
     */
67
    protected $locations;
68
69
    /**
70
     * Instantiate a ViewBuilder object.
71
     *
72
     * @since 0.1.0
73
     *
74
     * @param ConfigInterface            $config       Configuration settings.
75
     * @param ViewFinderInterface|null   $viewFinder   ViewFinder instance.
76
     * @param EngineFinderInterface|null $engineFinder EngineFinder instance.
77
     *
78
     * @throws FailedToProcessConfigException If the config could not be processed.
79
     */
80 8
    public function __construct(
81
        ConfigInterface $config,
82
        ViewFinderInterface $viewFinder = null,
83
        EngineFinderInterface $engineFinder = null
84
    ) {
85 8
        $this->processConfig($config);
86 8
        $this->viewFinder   = $viewFinder;
87 8
        $this->engineFinder = $engineFinder;
88 8
        $this->locations    = new LocationCollection();
89 8
    }
90
91
    /**
92
     * Create a new view for a given URI.
93
     *
94
     * @since 0.1.0
95
     *
96
     * @param string $view View identifier to create a view for.
97
     * @param mixed  $type Type of view to create.
98
     *
99
     * @return ViewInterface Instance of the requested view.
100
     */
101 18
    public function create($view, $type = null)
102
    {
103 18
        $uri    = $this->scanLocations([$view]);
104 18
        $engine = $this->getEngine($uri);
105
106 18
        return $uri
107 17
            ? $this->getView($uri, $engine, $type)
108 18
            : $this->getViewFinder()->getNullObject();
109
    }
110
111
    /**
112
     * Get an Engine that can deal with the given URI.
113
     *
114
     * @since 0.1.0
115
     *
116
     * @param string|false $uri URI to get an engine for.
117
     *
118
     * @return EngineInterface Instance of an engine that can deal with the given URI.
119
     */
120 18
    public function getEngine($uri)
121
    {
122 18
        return $this->getEngineFinder()->find([$uri]);
123
    }
124
125
    /**
126
     * Get a view for a given URI, engine and type.
127
     *
128
     * @since 0.1.0
129
     *
130
     * @param string          $uri    URI to get a view for.
131
     * @param EngineInterface $engine Engine to use for the view.
132
     * @param mixed           $type   Type of view to get.
133
     *
134
     * @return ViewInterface View that matches the given requirements.
135
     */
136 17
    public function getView($uri, EngineInterface $engine, $type = null)
137
    {
138 17
        if (null === $type) {
139 17
            return $this->getViewFinder()->find([$uri], $engine);
140
        }
141
142
        return $this->resolveType($type, $uri, $engine);
143
    }
144
145
    /**
146
     * Get the ViewFinder instance.
147
     *
148
     * @since 0.1.0
149
     *
150
     * @return ViewFinderInterface Instance of a ViewFinder.
151
     */
152 18
    public function getViewFinder()
153
    {
154 18
        return $this->getFinder($this->viewFinder, static::VIEW_FINDER_KEY);
155
    }
156
157
    /**
158
     * Get the EngineFinder instance.
159
     *
160
     * @since 0.1.0
161
     *
162
     * @return EngineFinderInterface Instance of a EngineFinder.
163
     */
164 18
    public function getEngineFinder()
165
    {
166 18
        return $this->getFinder($this->engineFinder, static::ENGINE_FINDER_KEY);
167
    }
168
169
    /**
170
     * Add a location to scan with the ViewFinder.
171
     *
172
     * @since 0.1.0
173
     *
174
     * @param LocationInterface $location Location to scan with the ViewFinder.
175
     */
176 18
    public function addLocation(LocationInterface $location)
177
    {
178 18
        $this->locations->add($location);
179 18
    }
180
181
    /**
182
     * Scan Locations for an URI that matches the specified criteria.
183
     *
184
     * @since 0.1.0
185
     *
186
     * @param array $criteria Criteria to match.
187
     *
188
     * @return string|false URI of the requested view, or false if not found.
189
     */
190 18
    public function scanLocations(array $criteria)
191
    {
192
        return $this->locations->map(function ($location) use ($criteria) {
193
            /** @var LocationInterface $location */
194 18
            return $location->getURI($criteria);
195 18
        })->filter(function ($uri) {
196 18
            return false !== $uri;
197 18
        })->first() ?: 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 18
    protected function getFinder(&$property, $key)
211
    {
212 18
        if (null === $property) {
213 8
            $engineFinderClass = $this->config->getKey($key, 'ClassName');
214 8
            $property          = new $engineFinderClass($this->config->getSubConfig($key));
215
        }
216
217 18
        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
        $configKey = [static::VIEW_FINDER_KEY, 'Views', $type];
235
236
        if (is_string($type) && $this->config->hasKey($configKey)) {
237
            $className = $this->config->getKey($configKey);
238
            $type      = new $className($uri, $engine);
239
        }
240
241
        if (is_string($type)) {
242
            $type = new $type($uri, $engine);
243
        }
244
245
        if (is_callable($type)) {
246
            $type = $type($uri, $engine);
247
        }
248
249
        if (! $type instanceof ViewInterface) {
250
            throw new FailedToInstantiateViewException(
251
                sprintf(
252
                    _('Could not instantiate view "%s".'),
253
                    serialize($type)
254
                )
255
            );
256
        }
257
258
        return $type;
259
    }
260
}
261