Passed
Push — master ( de569e...cba919 )
by Jip
03:18
created

Stencil::get_engine()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 3
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
/**
3
 * Stencil core class
4
 *
5
 * This class contains all the logic of the interface between the theme and the template engine
6
 * Selecting views, loading the proper files and triggering the hooks and filters.
7
 *
8
 * Author: Jip Moors ([email protected])
9
 * Date: 4 juli 2015
10
 *
11
 * @package Stencil
12
 */
13
14
/**
15
 * Class stencil
16
 */
17
final class Stencil implements Stencil_Interface, Stencil_Handlers_Interface, Stencil_Handler_Interface {
18
	/**
19
	 * Instance for singleton
20
	 *
21
	 * @var Stencil
22
	 */
23
	private static $instance;
24
25
	/**
26
	 * Handler instance
27
	 *
28
	 * @var Stencil_Handler
29
	 */
30
	private static $handler;
31
32
	/**
33
	 * Flow instance
34
	 *
35
	 * @var Stencil_Flow_Interface
36
	 */
37
	private static $flow;
38
39
	/**
40
	 * The default implementation class
41
	 *
42
	 * @var string
43
	 */
44
	private static $default_implementation_class;
45
46
	/**
47
	 * Boot up the main Stencil flow
48
	 *
49
	 * Triggered by the {FILTER_PREFIX}engine_ready hook
50
	 *
51
	 * @param Stencil_Implementation $engine Boot Stencil with the supplied engine.
52
	 */
53
	public static function boot( Stencil_Implementation $engine ) {
54
		remove_action( Stencil_Environment::format_hook( 'engine_ready' ), array( __CLASS__, __FUNCTION__ ) );
55
56
		if ( ! isset( self::$instance ) ) {
57
			self::$instance = new Stencil( $engine );
58
59
			/**
60
			 * This cannot be inside the constructor:
61
			 */
62
			Stencil_Environment::trigger( 'initialize', self::$instance );
63
		}
64
	}
65
66
	/**
67
	 * Construct the class and initialize engine
68
	 *
69
	 * @param Stencil_Implementation $engine Initilize Stencil with the supplied engine.
70
	 */
71
	private function __construct( Stencil_Implementation $engine ) {
72
		// Set the handler.
73
		self::$default_implementation_class = get_class( $engine );
74
		self::$handler                      = $this->get_handler( $engine );
75
76
		// Flow is irrelevant for AJAX calls; as are header and footers.
77
		if ( ! defined( 'DOING_AJAX' ) || false === DOING_AJAX ) {
78
			// For the default engine, load the wp_head and wp_footer into variables.
79
			self::$handler->load_wp_header_and_footer( true );
80
81
			// Set default flow.
82
			self::$flow = new Stencil_Flow();
83
		}
84
85
		/**
86
		 * Append the 'assets' directory to the template URI for easy access
87
		 */
88
		add_filter( 'template_directory_uri', array( $this, 'append_assets_directory' ) );
89
		add_filter( 'stylesheet_directory_uri', array( $this, 'append_assets_directory' ) );
90
91
		/**
92
		 * Make sure we only load index.php
93
		 *
94
		 * This removes the need for the use of the constant to skip the default loading
95
		 * which would be a very inconvenient thing to do when somebody wants to switch
96
		 * themes.
97
		 */
98
		add_filter( 'template_include', array( $this, 'template_include_override' ) );
99
	}
100
101
	/**
102
	 * Get the template engine instance
103
	 *
104
	 * Named controller for usability
105
	 *
106
	 * @return Stencil
107
	 * @throws Exception If Stencil was not initialized properly.
108
	 */
109
	public static function controller() {
110
		if ( ! isset( self::$instance ) ) {
111
			throw new Exception( 'Stencil not booted properly.' );
112
		}
113
114
		return self::$instance;
115
	}
116
117
	/**
118
	 * Get a new Handler
119
	 *
120
	 * @param Stencil_Implementation|null     $implementation Optional. Set Implementation on new Handler.
121
	 * @param Stencil_Recorder_Interface|null $recorder Optional. Supply a custom Recorder.
122
	 *
123
	 * @return Stencil_Handler
124
	 */
125
	public static function get_handler( Stencil_Implementation $implementation = null, Stencil_Recorder_Interface $recorder = null ) {
126
		/**
127
		 * Use "default" implementation if none supplied
128
		 */
129
		$implementation = ! is_null( $implementation ) ? $implementation : new self::$default_implementation_class();
130
131
		return new Stencil_Handler( $implementation, $recorder );
132
	}
133
134
	/**
135
	 * Set the flow controller
136
	 *
137
	 * Handler proxy functions
138
	 *
139
	 * @param Stencil_Flow_Interface $flow The new Flow to set to Stencil.
140
	 */
141
	public function set_flow( Stencil_Flow_Interface $flow ) {
142
		self::$flow = $flow;
143
	}
144
145
	/**
146
	 * Get the used flow
147
	 *
148
	 * Handler proxy functions
149
	 *
150
	 * @return Stencil_Flow_Interface
151
	 */
152
	public function get_flow() {
153
		return self::$flow;
154
	}
155
156
157
	/**
158
	 * Get a variable value from the template
159
	 *
160
	 * Handler proxy function
161
	 *
162
	 * @param string $variable Variable name to retrieve.
163
	 *
164
	 * @return mixed
165
	 */
166
	public function get( $variable ) {
167
		return self::$handler->get( $variable );
168
	}
169
170
	/**
171
	 * Set a variable to the template
172
	 *
173
	 * Handler proxy function
174
	 *
175
	 * @param string $variable Name of the variable to set.
176
	 * @param mixed  $value Value of the variable to set.
177
	 *
178
	 * @return mixed The value of the variable after it being set.
179
	 */
180
	public function set( $variable, $value ) {
181
		return self::$handler->set( $variable, $value );
182
	}
183
184
	/**
185
	 * Get the implementation
186
	 *
187
	 * Handler proxy functions
188
	 *
189
	 * @return Stencil_Implementation
190
	 */
191
	public function get_implementation() {
192
		return self::$handler->get_implementation();
193
	}
194
195
	/**
196
	 * Get the reference to the engine of the loaded Proxy
197
	 *
198
	 * This way theme developers can apply services and other
199
	 * engine specific functionality easily
200
	 *
201
	 * @return mixed
202
	 */
203
	public function get_engine() {
204
		return self::$handler->get_engine();
205
	}
206
207
	/**
208
	 * Set the recorder
209
	 *
210
	 * Handler proxy functions
211
	 *
212
	 * @param Stencil_Recorder_Interface $recorder New Recorder to use.
213
	 */
214
	public function set_recorder( Stencil_Recorder_Interface $recorder ) {
215
		self::$handler->set_recorder( $recorder );
216
	}
217
218
	/**
219
	 * Handler proxy functions
220
	 *
221
	 * Get the used recorder
222
	 *
223
	 * @return Stencil_Recorder_Interface
224
	 */
225
	public function get_recorder() {
226
		return self::$handler->get_recorder();
227
	}
228
229
	/**
230
	 * Start recording for a variable
231
	 *
232
	 * Handler proxy functions
233
	 *
234
	 * @param string                          $variable Variable to Record into.
235
	 * @param Stencil_Recorder_Interface|null $recorder Optional. Custom recorder to use for this action.
236
	 */
237
	public function start_recording( $variable, Stencil_Recorder_Interface $recorder = null ) {
238
		self::$handler->start_recording( $variable, $recorder );
239
	}
240
241
	/**
242
	 * Finish a recording
243
	 *
244
	 * Handler proxy functions
245
	 *
246
	 * @returns mixed Value of Recording.
247
	 */
248
	public function finish_recording() {
249
		return self::$handler->finish_recording();
250
	}
251
252
	/**
253
	 * Set the hierarchy handler for a page type
254
	 *
255
	 * HandlerFactory proxy functions
256
	 *
257
	 * @param string                 $page Page Type to set for.
258
	 * @param array|Traversable|null $handler Optional. Handler that will provide hierarchy for specified page.
259
	 */
260
	public function set_hierarchy( $page, $handler ) {
261
		Stencil_Handler_Factory::set_hierarchy_handler( $page, $handler = null );
262
	}
263
264
	/**
265
	 * Remove all view options for a page
266
	 *
267
	 * This will make the page be displayed with the 'index' view
268
	 *
269
	 * @param string $page Page to remove hierarchy of
270
	 */
271
	public function remove_hierarchy( $page ) {
272
		Stencil_Handler_Factory::set_hierarchy_handler( $page );
273
	}
274
275
	/**
276
	 * Set the page type handler for a page
277
	 *
278
	 * HandlerFactory proxy functions
279
	 *
280
	 * @param string   $page Page to set for.
281
	 * @param callable $handler Handler that will be executed for specified page.
282
	 */
283
	public function set_page_type_handler( $page, $handler ) {
284
		Stencil_Handler_Factory::set_page_type_handler( $page, $handler );
285
	}
286
287
	/**
288
	 * Set the page type hooker for a page
289
	 *
290
	 * HandlerFactory proxy functions
291
	 *
292
	 * @param string   $page Page to set for.
293
	 * @param callable $handler Hooker that will be executed for specified page.
294
	 */
295
	public function set_page_type_hooker( $page, $handler ) {
296
		Stencil_Handler_Factory::set_page_type_hooker( $page, $handler );
297
	}
298
299
	/**
300
	 * Remove the page type handler for a page
301
	 *
302
	 * HandlerFactory proxy functions
303
	 *
304
	 * @param string $page Page Type to remove handler of.
305
	 */
306
	public function remove_page_type_handler( $page ) {
307
		Stencil_Handler_Factory::remove_page_type_handler( $page );
308
	}
309
310
	/**
311
	 * Remove the page hooker for a page
312
	 *
313
	 * HandlerFactory proxy functions
314
	 *
315
	 * @param string $page Page Type to remove hooker of.
316
	 */
317
	public function remove_page_type_hooker( $page ) {
318
		Stencil_Handler_Factory::remove_page_type_hooker( $page );
319
	}
320
321
	/**
322
	 * Run the main process
323
	 *
324
	 * @param string|null $page Optional. Fake a certain page.
325
	 */
326
	public function run( $page = null ) {
327
		if ( empty( $page ) || ! is_string( $page ) ) {
328
			$page = Stencil_Environment::get_page();
329
		}
330
331
		// Add to template.
332
		$this->set( 'page', $page );
333
334
		// Get actions that need to be run.
335
		$actions = self::$flow->get_page_actions( $page );
336
337
		// Execute actions.
338
		if ( is_array( $actions ) && array() !== $actions ) {
339
			foreach ( $actions as $action ) {
340
				// Apply variables.
341
				Stencil_Handler_Factory::run_page_type_handler( $action, $this );
342
				Stencil_Handler_Factory::run_page_type_hook( $action, $this );
343
			}
344
		}
345
346
		// Get available views.
347
		$options = self::$flow->get_view_hierarchy( $page );
348
		$view    = self::$handler->get_usable_view( $options );
349
350
		// Display the view.
351
		self::$handler->display( $view );
352
	}
353
354
	/**
355
	 * Append assets directory to the template directory uri
356
	 *
357
	 * @param string $base Base Path to append the assets directory to.
358
	 *
359
	 * @return string
360
	 */
361
	public static function append_assets_directory( $base ) {
362
		static $cache;
363
364
		if ( ! isset( $cache ) ) {
365
366
			/**
367
			 * Only apply if theme is Stencil ready
368
			 */
369
			$theme = Stencil_Environment::filter( 'require', false );
370
			if ( false !== $theme ) {
371
372
				/**
373
				 * Filter: stencil_assets_path
374
				 *
375
				 * Default template dir uri is appended by 'assets' for a structured theme directory
376
				 * Themes can disable or modify the default
377
				 */
378
				$assets_path = Stencil_Environment::filter( 'assets_path', 'assets' );
379
				if ( ! empty( $assets_path ) ) {
380
					$cache = $base . '/' . $assets_path;
381
				}
382
			}
383
384
			$cache = isset( $cache ) ? $cache : $base;
385
		}
386
387
		return $cache;
388
	}
389
390
	/**
391
	 * Rewrite all scripts to index.php of the theme
392
	 *
393
	 * @param string $template Template that is being loaded.
394
	 *
395
	 * @return mixed
396
	 */
397
	public static function template_include_override( $template ) {
398
		/**
399
		 * Only apply if theme uses Stencil
400
		 */
401
		$theme = Stencil_Environment::filter( 'require', false );
402
		if ( false !== $theme ) {
403
404
			/**
405
			 * Make it optional with default disabled
406
			 */
407
			$force = Stencil_Environment::filter( 'template_index_only', false );
408
			if ( $force ) {
409
				return get_index_template();
410
			}
411
		}
412
413
		return $template;
414
	}
415
}
416