PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / 2.3.0
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution v2.3.0
2.4.0 2.3.0 2.2.5 2.2.0 2.1.2 2.1.1 trunk 1.10.0 1.10.01 1.10.02 1.5.0 1.5.01 1.5.02 1.5.1 1.5.10 1.5.20 1.5.21 1.5.22 1.5.23 1.5.24 1.5.25 1.6.0 1.7.0 1.7.1 1.7.2 All 33 releases
fluent-booking / vendor / wpfluent / framework / src / WPFluent / Foundation / Concerns / DynamicFacadeTrait.php

DynamicFacadeTrait.php in Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution 2.3.0, at vendor/wpfluent/framework/src/WPFluent/Foundation/Concerns/DynamicFacadeTrait.php

203 lines 6.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentBooking\Framework\Foundation\Concerns;
4
5 use FluentBooking\Framework\Support\Facade;
6 use RuntimeException;
7
8 trait DynamicFacadeTrait
9 {
10 /**
11 * Register the dynamic facade resolver.
12 *
13 * Registers an SPL autoloader to intercept facade class requests within
14 * the current namespace's Facade sub-namespace. Dynamically
15 * creates facade classes on-demand.
16 *
17 * @param \FluentBooking\Framework\Foundation\Application $app
18 * @return void
19 */
20 protected function registerFacadeResolver($app)
21 {
22 Facade::setFacadeApplication($app);
23
24 spl_autoload_register(function($class) use ($app) {
25 $fqn = __NAMESPACE__;
26
27 $ns = substr($fqn, 0, strpos($fqn, '\\'));
28
29 if (str_contains($class, $facade = $ns . '\Facade')) {
30 $this->createFacadeFor($facade, $class, $app);
31 }
32 }, true, true);
33 }
34
35 /**
36 * Resolve the binding name for the facade.
37 *
38 * Transforms the fully qualified facade class name to a service container
39 * binding key (accessor) by stripping the facade namespace
40 * and normalizing names.
41 *
42 * Special cases (e.g. 'route' to 'router') are handled here.
43 *
44 * @param string $facade Facade namespace prefix (e.g., FluentBooking\Framework\Facade)
45 * @param string $class Fully qualified facade class name
46 * @param \FluentBooking\Framework\Foundation\Application $app
47 * @return string|null The resolved accessor name if bound in the container.
48 */
49 protected function resolveFacadeAccessor($facade, $class, $app)
50 {
51 $name = strtolower(trim(str_replace($facade, '', $class), '\\'));
52
53 if ($name === 'route') {
54 $name = 'router';
55 }
56
57 return $app->bound($name) ? $name : null;
58 }
59
60 /**
61 * Create a facade resolver class dynamically.
62 *
63 * Generates a PHP facade class file under the uploads directory and loads it.
64 * This enables real-time facade creation for any requested class.
65 *
66 * @param string $facade Facade namespace prefix
67 * @param string $class Fully qualified class name of the facade to generate
68 * @param \FluentBooking\Framework\Foundation\Application $app
69 * @return void
70 * @throws \RuntimeException If the facade stub file is missing
71 */
72 protected function createFacadeFor($facade, $class, $app)
73 {
74 $accessor = $this->resolveFacadeAccessor($facade, $class, $app);
75 [$namespace, $baseClass] = $this->extractNamespaceAndClass($class);
76 $slug = $app->config->get('slug');
77
78 $facadesDir = $this->getFacadeDirectory($slug);
79 $this->ensureDirectoryExists($facadesDir);
80
81 $facadeFile = $this->getFacadeFilePath($facadesDir, $class);
82
83 if (!file_exists($facadeFile)) {
84 $facadeCode = $this->populateFacadeStub(
85 $namespace, $baseClass, $accessor
86 );
87
88 file_put_contents($facadeFile, $facadeCode);
89 }
90
91 $this->loadFacadeClass($class, $facadeFile);
92 }
93
94 /**
95 * Extract the namespace and base class name from a
96 * fully qualified class name (FQCN).
97 *
98 * @param string $fqcn Fully qualified class name
99 * @return array{string, string} Tuple of namespace and base class name
100 */
101 protected function extractNamespaceAndClass($fqcn)
102 {
103 $parts = explode('\\', $fqcn);
104 $baseClass = array_pop($parts);
105 $namespace = implode('\\', $parts);
106 return [$namespace, $baseClass];
107 }
108
109 /**
110 * Get the directory path where facade classes are stored based on app.slug.
111 *
112 * @param string $slug Plugin slug used for folder naming inside uploads
113 * @return string The absolute directory path where facade classes are saved
114 */
115 protected function getFacadeDirectory($slug)
116 {
117 $uploadDir = wp_upload_dir();
118 return "{$uploadDir['basedir']}/{$slug}/facades";
119 }
120
121 /**
122 * Ensure that the given directory exists; create it recursively if not.
123 *
124 * @param string $dir Directory path
125 * @return void
126 */
127 protected function ensureDirectoryExists($dir)
128 {
129 if (!is_dir($dir)) {
130 mkdir($dir, 0755, true);
131 }
132 }
133
134 /**
135 * Get the full path for the generated facade PHP file based on class name.
136 *
137 * Converts namespace separators to underscores for safe file names.
138 *
139 * @param string $facadesDir Directory where facades are stored
140 * @param string $class Fully qualified class name
141 * @return string Full file path for the facade class file
142 */
143 protected function getFacadeFilePath($facadesDir, $class)
144 {
145 $safeName = str_replace(['\\', '/'], '_', $class);
146 return "{$facadesDir}/{$safeName}.php";
147 }
148
149 /**
150 * Populate the facade stub template placeholders with real values.
151 *
152 * Replaces `{{ namespace }}`, `{{ $stub }}`, `{{ class }}` and
153 * `{{ accessor }}` placeholders with corresponding values.
154 *
155 * @param string $namespace The namespace for the facade class
156 * @param string $class The base class name for the facade class
157 * @param string $accessor The accessor name returned by getFacadeAccessor()
158 * @return string The populated PHP class code
159 */
160 protected function populateFacadeStub($namespace, $class, $accessor)
161 {
162 return str_replace(
163 ['{{ namespace }}', '{{ use }}', '{{ class }}', '{{ accessor }}'],
164 [$namespace, Facade::class, $class, $accessor],
165 $this->getFacadeStub(__DIR__ . '/facade.stub')
166 );
167 }
168
169 /**
170 * Retrieve the content of the facade stub file.
171 *
172 * Throws a RuntimeException if the stub file is missing.
173 *
174 * @param string $stubPath Absolute path to the stub file
175 * @return string The stub file content
176 * @throws \RuntimeException If stub file does not exist
177 */
178 protected function getFacadeStub($stubPath)
179 {
180 if (!file_exists($stubPath)) {
181 throw new RuntimeException(
182 "Facade stub not found at: {$stubPath}"
183 );
184 }
185
186 return file_get_contents($stubPath);
187 }
188
189 /**
190 * Load the generated facade class file if the class is not already loaded.
191 *
192 * @param string $class Fully qualified class name
193 * @param string $facadeFile Absolute path to the generated facade PHP file
194 * @return void
195 */
196 protected function loadFacadeClass($class, $facadeFile)
197 {
198 if (!class_exists($class, false)) {
199 require_once $facadeFile;
200 }
201 }
202 }
203