Passed
Push — master ( 4ac39c...ddccf7 )
by Alain
03:15
created

ViewBuilder::getEngine()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 1
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 10
    public function __construct(
81
        ConfigInterface $config,
82
        ViewFinderInterface $viewFinder = null,
83
        EngineFinderInterface $engineFinder = null
84
    ) {
85 10
        $this->processConfig($config);
86 10
        $this->viewFinder   = $viewFinder;
87 10
        $this->engineFinder = $engineFinder;
88 10
        $this->locations    = new LocationCollection();
89 10
    }
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 24
    public function create($view, $type = null)
102
    {
103 24
        $uri    = $this->scanLocations([$view]);
104 24
        $engine = $this->getEngine($uri);
105
106 24
        return $uri
107 23
            ? $this->getView($uri, $engine, $type)
108 24
            : $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 24
    public function getEngine($uri)
121
    {
122 24
        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 23
    public function getView($uri, EngineInterface $engine, $type = null)
137
    {
138 23
        if (null === $type) {
139 23
            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 24
    public function getViewFinder()
153
    {
154 24
        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 24
    public function getEngineFinder()
165
    {
166 24
        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 24
    public function addLocation(LocationInterface $location)
177
    {
178 24
        $this->locations->add($location);
179 24
    }
180
181
    /**
182
     * Get the collection of locations registered with this ViewBuilder.
183
     *
184
     * @since 0.1.3
185
     *
186
     * @return LocationCollection 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 24
    public function scanLocations(array $criteria)
203
    {
204
        $uris = $this->locations->map(function ($location) use ($criteria) {
205
            /** @var LocationInterface $location */
206 24
            return $location->getURI($criteria);
207 24
        })->filter(function ($uri) {
208 24
            return false !== $uri;
209 24
        });
210
211 24
        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 FinderInterface The requested finder instance.
223
     */
224 24
    protected function getFinder(&$property, $key)
225
    {
226 24
        if (null === $property) {
227 10
            $engineFinderClass = $this->config->getKey($key, 'ClassName');
228 10
            $property          = new $engineFinderClass($this->config->getSubConfig($key));
229
        }
230
231 24
        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 EngineInterface|null $engine Engine to use for the view.
242
     *
243
     * @return ViewInterface Resolved View object.
244
     * @throws FailedToInstantiateViewException If the view type could not be resolved.
245
     */
246
    protected function resolveType($type, $uri, EngineInterface $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 ViewInterface) {
264
            throw new FailedToInstantiateViewException(
265
                sprintf(
266
                    _('Could not instantiate view "%s".'),
267
                    serialize($type)
268
                )
269
            );
270
        }
271
272
        return $type;
273
    }
274
}
275