Completed
Push — master ( 6ac80e...ea27d1 )
by Chris
03:18
created

Resolver::generate()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
nc 8
nop 1
dl 0
loc 19
rs 9.3222
c 0
b 0
f 0
1
<?php
2
namespace Darya\View;
3
4
/**
5
 * Finds and instantiates views of the given implementation using the given base
6
 * paths and file extensions.
7
 *
8
 * Optionally shares variables and configurations with all templates that are
9
 * resolved.
10
 *
11
 * TODO: $vars -> $variables
12
 *
13
 * @author Chris Andrew <[email protected]>
14
 */
15
class Resolver
16
{
17
	/**
18
	 * View implementor to resolve.
19
	 *
20
	 * @var string
21
	 */
22
	protected $engine;
23
24
	/**
25
	 * Paths to search for templates within.
26
	 *
27
	 * @var array
28
	 */
29
	protected $basePaths = array();
30
31
	/**
32
	 * Template file extensions to search for.
33
	 *
34
	 * @var array
35
	 */
36
	protected $extensions = array();
37
38
	/**
39
	 * Extra directories to search within.
40
	 *
41
	 * @var array
42
	 */
43
	protected $directories = array('views');
44
45
	/**
46
	 * Variables to assign to all views that are resolved.
47
	 *
48
	 * @var array
49
	 */
50
	protected $shared = array();
51
52
	/**
53
	 * Config variables to set for all views that are resolved.
54
	 *
55
	 * @var array
56
	 */
57
	protected $config = array();
58
59
	/**
60
	 * Normalise the given path.
61
	 *
62
	 * @param string $path
63
	 * @return path
64
	 */
65
	public static function normalise($path)
66
	{
67
		return preg_replace('~[\\\|/]+~', '/', rtrim($path, '\/'));
68
	}
69
70
	/**
71
	 * Create a new view resolver.
72
	 *
73
	 * @param string       $engine     View implementor to resolve
74
	 * @param string|array $basePath   [optional] Single path or set of paths
75
	 * @param string|array $extensions [optional] Template file extensions
76
	 */
77
	public function __construct($engine, $basePath = null, $extensions = array())
78
	{
79
		$this->setEngine($engine);
80
81
		if ($basePath) {
82
			$this->registerBasePaths($basePath);
83
		}
84
85
		if (!empty($extensions)) {
86
			$this->registerExtensions($extensions);
87
		}
88
	}
89
90
	/**
91
	 * Set the engine (View implementor) to resolve.
92
	 *
93
	 * @param string $engine
94
	 */
95
	public function setEngine($engine)
96
	{
97
		if (!class_exists($engine) || !is_subclass_of($engine, 'Darya\View\View')) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of returns inconsistent results on some PHP versions for interfaces; you could instead use ReflectionClass::implementsInterface.
Loading history...
98
			throw new \Exception("View engine $engine does not exist or does not extend Darya\View\View");
99
		}
100
101
		$this->engine = $engine;
102
	}
103
104
	/**
105
	 * Register a base path or set of base paths to resolve views from.
106
	 *
107
	 * @param string|array $path Single path or set of paths
108
	 */
109
	public function registerBasePaths($path)
110
	{
111
		if (is_array($path)) {
112
			$this->basePaths = array_merge($this->basePaths, $path);
113
		} else {
114
			$this->basePaths[] = $path;
115
		}
116
	}
117
118
	/**
119
	 * Register file extensions to consider when resolving template files.
120
	 *
121
	 * @param string|array $extensions
122
	 */
123
	public function registerExtensions($extensions)
124
	{
125
		foreach ((array) $extensions as $extension) {
126
			$this->extensions[] = '.' . ltrim($extension, '.');
127
		}
128
	}
129
130
	/**
131
	 * Register extra directory names to search within when resolving template
132
	 * files.
133
	 *
134
	 * 'views' is registered by default.
135
	 *
136
	 * @param string|array $directories
137
	 */
138
	public function registerDirectories($directories)
139
	{
140
		$directories = (array) $directories;
141
142
		foreach ($directories as $key => $directory) {
143
			$directories[$key] = ltrim($directory, '\/');
144
		}
145
146
		$this->directories = array_merge($this->directories, $directories);
147
	}
148
149
	/**
150
	 * Set variables to assign to all resolved views.
151
	 *
152
	 * @param array $vars
153
	 */
154
	public function share(array $vars = array())
155
	{
156
		$this->shared = array_merge($this->shared, $vars);
157
	}
158
159
	/**
160
	 * Set config variables to set for all resolved views.
161
	 *
162
	 * @param array $config
163
	 */
164
	public function shareConfig(array $config = array())
165
	{
166
		$this->config = array_merge($this->config, $config);
167
	}
168
169
	/**
170
	 * Generate file paths to attempt when resolving template files.
171
	 *
172
	 * @param string $path
173
	 * @return array
174
	 */
175
	public function generate($path)
176
	{
177
		$dirname = dirname($path);
178
		$dir = $dirname != '.' ? $dirname : '';
179
		$file = basename($path);
180
		$paths = array();
181
182
		foreach ($this->basePaths as $basePath) {
183
			foreach ($this->extensions as $extension) {
184
				$paths[] = "$basePath/$path$extension";
185
186
				foreach ($this->directories as $directory) {
187
					$paths[] = "$basePath/$dir/$directory/$file$extension";
188
				}
189
			}
190
		}
191
192
		return $paths;
193
	}
194
195
	/**
196
	 * Find a template file using the given path.
197
	 *
198
	 * @param string $path
199
	 * @return string
200
	 */
201
	public function resolve($path)
202
	{
203
		$path = static::normalise($path);
204
205
		if (is_file($path)) {
206
			return $path;
207
		}
208
209
		$filePaths = $this->generate($path);
210
211
		foreach ($filePaths as $filePath) {
212
			if (is_file($filePath)) {
213
				return $filePath;
214
			}
215
		}
216
	}
217
218
	/**
219
	 * Determine whether a template exists at the given path.
220
	 *
221
	 * @param string $path
222
	 * @return bool
223
	 */
224
	public function exists($path)
225
	{
226
		return $this->resolve($path) !== null;
227
	}
228
229
	/**
230
	 * Resolve a view instance with a template at the given path, as well as
231
	 * shared variables and config.
232
	 *
233
	 * @param string $path [optional] Template path
234
	 * @param array  $vars [optional] Variables to assign to the View
235
	 * @return View
236
	 */
237
	public function create($path = null, $vars = array())
238
	{
239
		$file = $this->resolve($path);
240
241
		$engine = $this->engine;
242
		$engine = new $engine($file, array_merge($this->shared, $vars), $this->config);
243
		$engine->setResolver($this);
244
245
		return $engine;
246
	}
247
}
248