Passed
Push — master ( 87ba60...d80a49 )
by Alain
02:43
created

ViewBuilder::getConfig()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 6
cts 6
cp 1
rs 9.6666
c 0
b 0
f 0
cc 2
eloc 6
nc 2
nop 1
crap 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\ConfigFactory;
15
use BrightNucleus\Config\ConfigInterface;
16
use BrightNucleus\Config\ConfigTrait;
17
use BrightNucleus\Config\Exception\FailedToProcessConfigException;
18
use BrightNucleus\View\Engine\BaseEngineFinder;
19
use BrightNucleus\View\Engine\Engine;
20
use BrightNucleus\View\Engine\ViewFinder;
21
use BrightNucleus\View\Exception\FailedToInstantiateView;
22
use BrightNucleus\View\Location\Locations;
23
use BrightNucleus\View\Location\Location;
24
use BrightNucleus\View\Support\Finder;
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
     * BaseViewFinder instance.
44
     *
45
     * @since 0.1.0
46
     *
47
     * @var ViewFinder
48
     */
49
    protected $viewFinder;
50
51
    /**
52
     * BaseEngineFinder instance.
53
     *
54
     * @since 0.1.0
55
     *
56
     * @var BaseEngineFinder
57
     */
58
    protected $engineFinder;
59
60
    /**
61
     * Locations to scan for views.
62
     *
63
     * @since 0.1.0
64
     *
65
     * @var Locations
66
     */
67
    protected $locations;
68
69
    /**
70
     * Instantiate a ViewBuilder object.
71
     *
72
     * @since 0.1.0
73
     *
74
     * @param ConfigInterface       $config       Optional. Configuration settings.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $config not be null|ConfigInterface?

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...
75
     * @param ViewFinder|null       $viewFinder   Optional. BaseViewFinder instance.
76
     * @param BaseEngineFinder|null $engineFinder Optional. BaseEngineFinder instance.
77
     *
78
     * @throws FailedToProcessConfigException If the config could not be processed.
79
     */
80 16
    public function __construct(
81
        ConfigInterface $config = null,
82
        ViewFinder $viewFinder = null,
83
        BaseEngineFinder $engineFinder = null
84
    ) {
85 16
        $this->processConfig($this->getConfig($config));
86 16
        $this->viewFinder   = $viewFinder;
87 16
        $this->engineFinder = $engineFinder;
88 16
        $this->locations    = new Locations();
89 16
    }
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 View Instance of the requested view.
100
     */
101 30
    public function create($view, $type = null)
102
    {
103 30
        $uri    = $this->scanLocations([$view]);
104 30
        $engine = $this->getEngine($uri);
105
106 30
        return $uri
107 29
            ? $this->getView($uri, $engine, $type)
108 30
            : $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 Engine Instance of an engine that can deal with the given URI.
119
     */
120 30
    public function getEngine($uri)
121
    {
122 30
        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 Engine $engine Engine to use for the view.
132
     * @param mixed  $type   Type of view to get.
133
     *
134
     * @return View View that matches the given requirements.
135
     */
136 29
    public function getView($uri, Engine $engine, $type = null)
137
    {
138 29
        $view = (null === $type)
139 29
            ? $this->getViewFinder()->find([$uri], $engine)
140 29
            : $this->resolveType($type, $uri, $engine);
141
142 29
        return $view->setBuilder($this);
143
    }
144
145
    /**
146
     * Get the BaseViewFinder instance.
147
     *
148
     * @since 0.1.0
149
     *
150
     * @return ViewFinder Instance of a BaseViewFinder.
151
     */
152 30
    public function getViewFinder()
153
    {
154 30
        return $this->getFinder($viewFinder, static::VIEW_FINDER_KEY);
155
    }
156
157
    /**
158
     * Get the BaseEngineFinder instance.
159
     *
160
     * @since 0.1.0
161
     *
162
     * @return BaseEngineFinder Instance of a BaseEngineFinder.
163
     */
164 30
    public function getEngineFinder()
165
    {
166 30
        return $this->getFinder($this->engineFinder, static::ENGINE_FINDER_KEY);
167
    }
168
169
    /**
170
     * Add a location to scan with the BaseViewFinder.
171
     *
172
     * @since 0.1.0
173
     *
174
     * @param Location $location Location to scan with the BaseViewFinder.
175
     */
176 30
    public function addLocation(Location $location)
177
    {
178 30
        $this->locations->add($location);
179 30
    }
180
181
    /**
182
     * Get the collection of locations registered with this ViewBuilder.
183
     *
184
     * @since 0.1.3
185
     *
186
     * @return Locations Collection of locations.
187
     */
188
    public function getLocations()
189
    {
190
        return $this->locations;
191
    }
192
193
    /**
194
     * Scan Locations for an URI that matches the specified criteria.
195
     *
196
     * @since 0.1.0
197
     *
198
     * @param array $criteria Criteria to match.
199
     *
200
     * @return string|false URI of the requested view, or false if not found.
201
     */
202 30
    public function scanLocations(array $criteria)
203
    {
204
        $uris = $this->locations->map(function ($location) use ($criteria) {
205
            /** @var Location $location */
206 30
            return $location->getURI($criteria);
207 30
        })->filter(function ($uri) {
208 30
            return false !== $uri;
209 30
        });
210
211 30
        return $uris->count() > 0 ? $uris->first() : false;
212
    }
213
214
    /**
215
     * Get a finder instance.
216
     *
217
     * @since 0.1.1
218
     *
219
     * @param mixed  $property Property to use.
220
     * @param string $key      Configuration key to use.
221
     *
222
     * @return Finder The requested finder instance.
223
     */
224 30
    protected function getFinder(&$property, $key)
225
    {
226 30
        if (null === $property) {
227 30
            $finderClass = $this->config->getKey($key, 'ClassName');
228 30
            $property    = new $finderClass($this->config->getSubConfig($key));
229
        }
230
231 30
        return $property;
232
    }
233
234
    /**
235
     * Resolve the view type.
236
     *
237
     * @since 0.1.0
238
     *
239
     * @param mixed       $type   Type of view that was requested.
240
     * @param string      $uri    URI to get a view for.
241
     * @param Engine|null $engine Engine to use for the view.
242
     *
243
     * @return View Resolved View object.
244
     * @throws FailedToInstantiateView If the view type could not be resolved.
245
     */
246
    protected function resolveType($type, $uri, Engine $engine = null)
247
    {
248
        $configKey = [static::VIEW_FINDER_KEY, 'Views', $type];
249
250
        if (is_string($type) && $this->config->hasKey($configKey)) {
251
            $className = $this->config->getKey($configKey);
252
            $type      = new $className($uri, $engine);
253
        }
254
255
        if (is_string($type)) {
256
            $type = new $type($uri, $engine);
257
        }
258
259
        if (is_callable($type)) {
260
            $type = $type($uri, $engine);
261
        }
262
263
        if ( ! $type instanceof View) {
264
            throw new FailedToInstantiateView(
265
                sprintf(
266
                    _('Could not instantiate view "%s".'),
267
                    serialize($type)
268
                )
269
            );
270
        }
271
272
        return $type;
273
    }
274
275
    /**
276
     * Get the configuration to use in the ViewBuilder.
277
     *
278
     * @since 0.2.0
279
     *
280
     * @return ConfigInterface Configuration passed in through the constructor.
281
     */
282 16
    protected function getConfig($config = null)
283
    {
284 16
        $defaults = ConfigFactory::create(__DIR__ . '/../../config/defaults.php', $config);
285 16
        $config   = $config
286 15
            ? ConfigFactory::createFromArray(array_merge_recursive($defaults->getArrayCopy(), $config->getArrayCopy()))
287 16
            : $defaults;
288
289 16
        return $config->getSubConfig('BrightNucleus\View');
290
    }
291
}
292