Passed
Push — master ( 71c354...905f3e )
by Jip
04:07
created

Stencil::start_recording()   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 2
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
90
		/**
91
		 * Make sure we only load index.php
92
		 *
93
		 * This removes the need for the use of the constant to skip the default loading
94
		 * which would be a very inconvenient thing to do when somebody wants to switch
95
		 * themes.
96
		 */
97
		add_filter( 'template_include', array( $this, 'template_include_override' ) );
98
	}
99
100
	/**
101
	 * Get the template engine instance
102
	 *
103
	 * Named controller for usability
104
	 *
105
	 * @return Stencil
106
	 * @throws Exception If Stencil was not initialized properly.
107
	 */
108
	public static function controller() {
109
		if ( ! isset( self::$instance ) ) {
110
			throw new Exception( 'Stencil not booted properly.' );
111
		}
112
113
		return self::$instance;
114
	}
115
116
	/**
117
	 * Get a new Handler
118
	 *
119
	 * @param Stencil_Implementation|null     $implementation Optional. Set Implementation on new Handler.
120
	 * @param Stencil_Recorder_Interface|null $recorder Optional. Supply a custom Recorder.
121
	 *
122
	 * @return Stencil_Handler
123
	 */
124
	public static function get_handler( Stencil_Implementation $implementation = null, Stencil_Recorder_Interface $recorder = null ) {
125
		/**
126
		 * Use "default" implementation if none supplied
127
		 */
128
		$implementation = ! is_null( $implementation ) ? $implementation : new self::$default_implementation_class();
129
130
		return new Stencil_Handler( $implementation, $recorder );
131
	}
132
133
	/**
134
	 * Set the flow controller
135
	 *
136
	 * Handler proxy functions
137
	 *
138
	 * @param Stencil_Flow_Interface $flow The new Flow to set to Stencil.
139
	 */
140
	public function set_flow( Stencil_Flow_Interface $flow ) {
141
		self::$flow = $flow;
142
	}
143
144
	/**
145
	 * Get the used flow
146
	 *
147
	 * Handler proxy functions
148
	 *
149
	 * @return Stencil_Flow_Interface
150
	 */
151
	public function get_flow() {
152
		return self::$flow;
153
	}
154
155
156
	/**
157
	 * Get a variable value from the template
158
	 *
159
	 * Handler proxy function
160
	 *
161
	 * @param string $variable Variable name to retrieve.
162
	 *
163
	 * @return mixed
164
	 */
165
	public function get( $variable ) {
166
		return self::$handler->get( $variable );
167
	}
168
169
	/**
170
	 * Set a variable to the template
171
	 *
172
	 * Handler proxy function
173
	 *
174
	 * @param string $variable Name of the variable to set.
175
	 * @param mixed  $value Value of the variable to set.
176
	 *
177
	 * @return mixed The value of the variable after it being set.
178
	 */
179
	public function set( $variable, $value ) {
180
		return self::$handler->set( $variable, $value );
181
	}
182
183
	/**
184
	 * Get the implementation
185
	 *
186
	 * Handler proxy functions
187
	 *
188
	 * @return Stencil_Implementation
189
	 */
190
	public function get_implementation() {
191
		return self::$handler->get_implementation();
192
	}
193
194
	/**
195
	 * Get the reference to the engine of the loaded Proxy
196
	 *
197
	 * This way theme developers can apply services and other
198
	 * engine specific functionality easily
199
	 *
200
	 * @return mixed
201
	 */
202
	public function get_engine() {
203
		return self::$handler->get_engine();
204
	}
205
206
	/**
207
	 * Set the recorder
208
	 *
209
	 * Handler proxy functions
210
	 *
211
	 * @param Stencil_Recorder_Interface $recorder New Recorder to use.
212
	 */
213
	public function set_recorder( Stencil_Recorder_Interface $recorder ) {
214
		self::$handler->set_recorder( $recorder );
215
	}
216
217
	/**
218
	 * Handler proxy functions
219
	 *
220
	 * Get the used recorder
221
	 *
222
	 * @return Stencil_Recorder_Interface
223
	 */
224
	public function get_recorder() {
225
		return self::$handler->get_recorder();
226
	}
227
228
	/**
229
	 * Start recording for a variable
230
	 *
231
	 * Handler proxy functions
232
	 *
233
	 * @param string                          $variable Variable to Record into.
234
	 * @param Stencil_Recorder_Interface|null $recorder Optional. Custom recorder to use for this action.
235
	 */
236
	public function start_recording( $variable, Stencil_Recorder_Interface $recorder = null ) {
237
		self::$handler->start_recording( $variable, $recorder );
238
	}
239
240
	/**
241
	 * Finish a recording
242
	 *
243
	 * Handler proxy functions
244
	 *
245
	 * @returns mixed Value of Recording.
246
	 */
247
	public function finish_recording() {
248
		return self::$handler->finish_recording();
249
	}
250
251
	/**
252
	 * Set the hierarchy handler for a page type
253
	 *
254
	 * HandlerFactory proxy functions
255
	 *
256
	 * @param string            $type Page Type to set for.
257
	 * @param array|Traversable $handler Handler that will provide hierarchy for specified page.
258
	 */
259
	public function set_hierarchy_handler( $type, $handler ) {
260
		Stencil_Handler_Factory::set_hierarchy_handler( $type, $handler );
261
	}
262
263
	/**
264
	 * Set the page type handler for a page
265
	 *
266
	 * HandlerFactory proxy functions
267
	 *
268
	 * @param string   $type Page Type to set for.
269
	 * @param callable $handler Handler that will be executed for specified page.
270
	 */
271
	public function set_page_type_handler( $type, $handler ) {
272
		Stencil_Handler_Factory::set_page_type_handler( $type, $handler );
273
	}
274
275
	/**
276
	 * Set the page type hooker for a page
277
	 *
278
	 * HandlerFactory proxy functions
279
	 *
280
	 * @param string   $type Page Type to set for.
281
	 * @param callable $handler Hooker that will be executed for specified page.
282
	 */
283
	public function set_page_type_hooker( $type, $handler ) {
284
		Stencil_Handler_Factory::set_page_type_hooker( $type, $handler );
285
	}
286
287
	/**
288
	 * Remove the page type handler for a page
289
	 *
290
	 * HandlerFactory proxy functions
291
	 *
292
	 * @param string $type Page Type to remove handler of.
293
	 */
294
	public function remove_page_type_handler( $type ) {
295
		Stencil_Handler_Factory::remove_page_type_handler( $type );
296
	}
297
298
	/**
299
	 * Remove the page hooker for a page
300
	 *
301
	 * HandlerFactory proxy functions
302
	 *
303
	 * @param string $type Page Type to remove hooker of.
304
	 */
305
	public function remove_page_type_hooker( $type ) {
306
		Stencil_Handler_Factory::remove_page_type_hooker( $type );
307
	}
308
309
	/**
310
	 * Run the main process
311
	 *
312
	 * @param string|null $page Optional. Fake a certain page.
313
	 */
314
	public function run( $page = null ) {
315
		if ( empty( $page ) || ! is_string( $page ) ) {
316
			$page = Stencil_Environment::get_page();
317
		}
318
319
		// Add to template.
320
		$this->set( 'page', $page );
321
322
		// Get actions that need to be run.
323
		$actions = self::$flow->get_page_actions( $page );
324
325
		// Execute actions.
326
		if ( is_array( $actions ) && array() !== $actions ) {
327
			foreach ( $actions as $action ) {
328
				// Apply variables.
329
				$handler = Stencil_Handler_Factory::get_page_type_handler( $action );
330
				if ( is_callable( $handler ) ) {
331
					call_user_func( $handler, $this );
332
				}
333
334
				$hooker = Stencil_Handler_Factory::get_page_type_hooker( $action );
335
				if ( is_callable( $hooker ) ) {
336
					call_user_func( $hooker, $this );
337
				}
338
			}
339
		}
340
341
		// Get available views.
342
		$options = self::$flow->get_view_hierarchy( $page );
343
		$view    = self::$handler->get_usable_view( $options );
344
345
		// Display the view.
346
		self::$handler->display( $view );
347
	}
348
349
	/**
350
	 * Append assets directory to the template directory uri
351
	 *
352
	 * @param string $base Base Path to append the assets directory to.
353
	 *
354
	 * @return string
355
	 */
356
	public static function append_assets_directory( $base ) {
357
		static $cache;
358
359
		if ( ! isset( $cache ) ) {
360
361
			/**
362
			 * Only apply if theme is Stencil ready
363
			 */
364
			$theme = Stencil_Environment::filter( 'require', false );
365
			if ( false !== $theme ) {
366
367
				/**
368
				 * Filter: stencil_assets_path
369
				 *
370
				 * Default template dir uri is appended by 'assets' for a structured theme directory
371
				 * Themes can disable or modify the default
372
				 */
373
				$assets_path = Stencil_Environment::filter( 'assets_path', 'assets' );
374
				if ( ! empty( $assets_path ) ) {
375
					$cache = $base . '/' . $assets_path;
376
				}
377
			}
378
379
			$cache = isset( $cache ) ? $cache : $base;
380
		}
381
382
		return $cache;
383
	}
384
385
	/**
386
	 * Rewrite all scripts to index.php of the theme
387
	 *
388
	 * @param string $template Template that is being loaded.
389
	 *
390
	 * @return mixed
391
	 */
392
	public static function template_include_override( $template ) {
393
		/**
394
		 * Only apply if theme uses Stencil
395
		 */
396
		$theme = Stencil_Environment::filter( 'require', false );
397
		if ( false !== $theme ) {
398
399
			/**
400
			 * Make it optional with default disabled
401
			 */
402
			$force = Stencil_Environment::filter( 'template_index_only', false );
403
			if ( $force ) {
404
				return get_index_template();
405
			}
406
		}
407
408
		return $template;
409
	}
410
}
411