Passed
Pull Request — master (#117)
by Glynn
02:41
created

App_Factory::default_setup()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 21
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 9
c 0
b 0
f 0
dl 0
loc 21
rs 9.9666
cc 2
nc 2
nop 1
1
<?php
2
3
declare(strict_types=1);
4
/**
5
 * Factory for creating standard instances of the App.
6
 *
7
 * @author Glynn Quelch <[email protected]>
8
 * @license http://www.opensource.org/licenses/mit-license.html  MIT License
9
 * @package PinkCrab\Perique
10
 * @since 0.4.0
11
 */
12
13
namespace PinkCrab\Perique\Application;
14
15
use Dice\Dice;
16
use PinkCrab\Loader\Hook_Loader;
17
use PinkCrab\Perique\Application\App;
18
use PinkCrab\Perique\Interfaces\Renderable;
19
use PinkCrab\Perique\Interfaces\DI_Container;
20
use PinkCrab\Perique\Services\View\PHP_Engine;
21
use PinkCrab\Perique\Services\Dice\PinkCrab_Dice;
22
use PinkCrab\Perique\Interfaces\Registration_Middleware;
23
use PinkCrab\Perique\Exceptions\App_Initialization_Exception;
24
use PinkCrab\Perique\Services\Registration\Registration_Service;
25
use PinkCrab\Perique\Services\Registration\Middleware\Hookable_Middleware;
26
27
class App_Factory {
28
29
	/**
30
	 * The app instance.
31
	 *
32
	 * @var App
33
	 */
34
	protected $app;
35
36
	/**
37
	 * The base path of the app.
38
	 *
39
	 * @var string
40
	 */
41
	protected $base_path;
42
43
	/**
44
	 * The base view path
45
	 *
46
	 * @var string|null
47
	 * @since 1.4.0
48
	 */
49
	protected $base_view_path;
50
51
	public function __construct( ?string $base_path = null ) {
52
		$this->app = new App();
53
54
		if ( null === $base_path ) {
55
			$file_index      = 0;
56
			$trace           = debug_backtrace(); //phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_debug_backtrace
57
			$this->base_path = isset( $trace[ $file_index ]['file'] ) ? \trailingslashit( dirname( $trace[ $file_index ]['file'] ) ) : __DIR__;
58
		} else {
59
			$this->base_path = \trailingslashit( $base_path );
60
		}
61
	}
62
63
		/**
64
	 * Gets the defined base path.
65
	 *
66
	 * @return string
67
	 * @since 1.4.0
68
	 */
69
	public function get_base_path(): string {
70
		return $this->base_path;
71
	}
72
73
	/**
74
	 * Sets the base view path.
75
	 *
76
	 * @since 1.4.0
77
	 * @param string $base_view_path
78
	 * @return self
79
	 */
80
	public function set_base_view_path( string $base_view_path ): self {
81
		$this->base_view_path = \trailingslashit( $base_view_path );
82
		return $this;
83
	}
84
85
	/**
86
	 * Get the base view path.
87
	 *
88
	 * @since 1.4.0
89
	 * @return string
90
	 */
91
	public function get_base_view_path(): string {
92
		return null !== $this->base_view_path
93
			? $this->base_view_path
94
			: \trailingslashit( $this->default_config_paths()['path']['view'] );
95
	}
96
97
	/**
98
	 * Pre populates a standard instance of the App
99
	 *
100
	 * THIS WAS REPLACED IN 1.4.0
101
	 * ASSUMES THE VIEW BASE PATH IS THE SAME AS THE BASE PATH
102
	 * THIS IS KEPT FOR BACKWARDS COMPATIBILITY
103
	 *
104
	 * @return self
105
	 */
106
	public function with_wp_dice( bool $include_default_rules = false ): self {
107
		// If the view path is not set, set it to the same as base path.
108
		if ( null === $this->base_view_path ) {
109
			$this->base_view_path = $this->base_path;
110
		}
111
		return $this->default_setup( $include_default_rules );
112
	}
113
114
	/**
115
	 * Pre populates a standard instance of the App
116
	 * Uses the PinkCrab_Dice container
117
	 * Sets up registration and loader instances.
118
	 * Adds Hookable Middleware
119
	 *
120
	 * Just requires Class List, Config and DI Rules.
121
	 * @since 1.4.0
122
	 *
123
	 * @param bool $include_default_rules
124
	 * @return self
125
	 */
126
	public function default_setup( bool $include_default_rules = true ): self {
127
		$loader = new Hook_Loader();
128
129
		// Setup DI Container
130
		$container = PinkCrab_Dice::withDice( new Dice() );
131
132
		if ( $include_default_rules === true ) {
133
			$container->addRules( $this->default_di_rules() );
134
		}
135
136
		$this->app->set_container( $container );
137
138
		// Set registration middleware
139
		$this->app->set_registration_services( new Registration_Service() );
140
141
		$this->app->set_loader( $loader );
142
143
		// Include Hookable.
144
		$this->app->registration_middleware( new Hookable_Middleware() );
145
146
		return $this;
147
	}
148
149
	/**
150
	 * Returns the basic DI rules which are used to set.
151
	 * Renderable with PHP_Engine implementation
152
	 *
153
	 * @return array<mixed>
154
	 */
155
	protected function default_di_rules(): array {
156
		return array(
157
			'*' => array(
158
				'substitutions' => array(
159
					Renderable::class => new PHP_Engine( $this->get_base_view_path() ),
160
				),
161
			),
162
		);
163
	}
164
165
	/**
166
	 * Set the DI rules
167
	 *
168
	 * @param array<string,array<string,string|object|callable|null|false|\Closure>> $rules
169
	 * @return self
170
	 */
171
	public function di_rules( array $rules ): self {
172
		$this->app->container_config(
173
			function( DI_Container $container ) use ( $rules ): void {
174
				$container->addRules( $rules );
175
			}
176
		);
177
		return $this;
178
	}
179
180
	/**
181
	 * Sets the registration class list.
182
	 *
183
	 * @param array<int, string> $class_list Array of fully namespaced class names.
184
	 * @return self
185
	 */
186
	public function registration_classes( array $class_list ): self {
187
		$this->app->registration_classes( $class_list );
188
		return $this;
189
	}
190
191
	/**
192
	 * Sets the apps internal config
193
	 *
194
	 * @param array<string, mixed> $app_config
195
	 * @return self
196
	 */
197
	public function app_config( array $app_config ): self {
198
		$this->app->set_app_config( \array_replace_recursive( $this->default_config_paths(), $app_config ) );
199
		return $this;
200
	}
201
202
	/**
203
	 * Returns the populated app.
204
	 *
205
	 * @return \PinkCrab\Perique\Application\App
206
	 */
207
	public function app(): App {
208
		return $this->app;
209
	}
210
211
	/**
212
	 * Returns a booted version of the app.
213
	 *
214
	 * @return \PinkCrab\Perique\Application\App
215
	 */
216
	public function boot(): App {
217
		// Sets default settings if not already set.
218
		if ( ! $this->app->has_app_config() ) {
219
			$this->app_config( $this->default_config_paths() );
220
		}
221
222
		return $this->app->boot();
223
	}
224
225
	/**
226
	 * Generates some default paths for the app_config based on base path.
227
	 *
228
	 * @return array{
229
	 *  url:array{
230
	 *    plugin:string,
231
	 *    view:string,
232
	 *    assets:string,
233
	 *    upload_root:string,
234
	 *    upload_current:string,
235
	 *  },
236
	 *  path:array{
237
	 *    plugin:string,
238
	 *    view:string,
239
	 *    assets:string,
240
	 *    upload_root:string,
241
	 *    upload_current:string,
242
	 *  }
243
	 * }
244
	 */
245
	private function default_config_paths(): array {
246
		$wp_uploads = \wp_upload_dir();
247
		return array(
248
			'path' => array(
249
				'plugin'         => rtrim( $this->base_path, \DIRECTORY_SEPARATOR ),
250
				'view'           => rtrim( $this->base_path, \DIRECTORY_SEPARATOR ) . '/views',
251
				'assets'         => rtrim( $this->base_path, \DIRECTORY_SEPARATOR ) . '/assets',
252
				'upload_root'    => $wp_uploads['basedir'],
253
				'upload_current' => $wp_uploads['path'],
254
			),
255
			'url'  => array(
256
				'plugin'         => plugins_url( basename( $this->base_path ) ),
257
				'view'           => plugins_url( basename( $this->base_path ) ) . '/views',
258
				'assets'         => plugins_url( basename( $this->base_path ) ) . '/assets',
259
				'upload_root'    => $wp_uploads['baseurl'],
260
				'upload_current' => $wp_uploads['url'],
261
			),
262
		);
263
	}
264
265
	/**
266
	 * Add registration middleware
267
	 *
268
	 * @param Registration_Middleware $middleware
269
	 * @return self
270
	 * @throws App_Initialization_Exception Code 3
271
	 */
272
	public function registration_middleware( Registration_Middleware $middleware ): self {
273
		$this->app->registration_middleware( $middleware );
274
		return $this;
275
	}
276
277
	/**
278
	 * Add registration middleware as a class string.
279
	 * This is constructed via the DI Container before being added.
280
	 *
281
	 * @param class-string<Registration_Middleware> $class_name
282
	 * @return self
283
	 * @throws App_Initialization_Exception Code 1 If DI container not registered
284
	 * @throws App_Initialization_Exception Code 9 If class doesn't create as middleware.
285
	 */
286
	public function construct_registration_middleware( string $class_name ): self {
287
		$this->app->construct_registration_middleware( $class_name );
288
		return $this;
289
	}
290
}
291