Stencil   B
last analyzed

Complexity

Total Complexity 39

Size/Duplication

Total Lines 405
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 5
Metric Value
wmc 39
lcom 3
cbo 5
dl 0
loc 405
rs 8.2857

23 Methods

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