|
8 | 8 |
|
9 | 9 | namespace XWP\DI;
|
10 | 10 |
|
11 |
| -use DI\CompiledContainer; |
12 |
| -use DI\Container; |
| 11 | +use DI\CompiledContainer as Compiled; |
| 12 | +use DI\ContainerBuilder; |
13 | 13 | use DI\Definition\Source\DefinitionSource;
|
| 14 | +use XWP\DI\Hook\Compiler; |
| 15 | +use XWP\DI\Hook\Parser; |
14 | 16 |
|
15 | 17 | /**
|
16 | 18 | * Custom container builder.
|
17 | 19 | *
|
18 |
| - * @extends \DI\ContainerBuilder<Container> |
| 20 | + * @extends ContainerBuilder<Container> |
| 21 | + * @method Container build() |
19 | 22 | */
|
20 |
| -class App_Builder extends \DI\ContainerBuilder { |
| 23 | +class App_Builder extends ContainerBuilder { |
| 24 | + /** |
| 25 | + * Directory to store the compiled hooks. |
| 26 | + * |
| 27 | + * @var string |
| 28 | + */ |
| 29 | + protected ?string $cacheHooksDir = null; |
| 30 | + |
21 | 31 | /**
|
22 | 32 | * Static method to configure the container.
|
23 | 33 | *
|
24 |
| - * @param array<string, mixed> $config Configuration options. |
| 34 | + * @param array<string,mixed> $config Configuration options. |
25 | 35 | * @return App_Builder
|
26 | 36 | */
|
27 | 37 | public static function configure( array $config = array() ): App_Builder {
|
28 |
| - return ( new App_Builder() ) |
29 |
| - ->useAttributes( $config['attributes'] ) |
30 |
| - ->useAutowiring( $config['autowiring'] ) |
31 |
| - ->writeProxiesToFile( writeToFile: $config['proxies'], proxyDirectory: $config['compile_dir'] ) |
| 38 | + return ( new App_Builder( Container::class ) ) |
| 39 | + ->useAttributes( $config['use_attributes'] ) |
| 40 | + ->useAutowiring( $config['use_autowiring'] ) |
32 | 41 | ->enableCompilation(
|
33 |
| - compile: $config['compile'], |
34 |
| - directory: $config['compile_dir'], |
35 |
| - containerClass: $config['compile_class'], |
36 |
| - ); |
| 42 | + compile: $config['cache_app'], |
| 43 | + directory: $config['cache_dir'], |
| 44 | + containerClass: $config['app_class'], |
| 45 | + // @phpstan-ignore argument.type |
| 46 | + containerParentClass: Compiled_Container::class, |
| 47 | + ) |
| 48 | + ->enableDefinitionCache( enableCache: $config['cache_defs'], cacheNamespace: $config['app_id'] ) |
| 49 | + ->enableHookCache( enableCache: $config['cache_hooks'], cacheDirectory: $config['cache_dir'] ) |
| 50 | + ->writeProxiesToFile( writeToFile: $config['use_proxies'], proxyDirectory: $config['cache_dir'] ) |
| 51 | + ->addBaseDefinition( $config ) |
| 52 | + ->addModuleDefinition( $config ); |
37 | 53 | }
|
38 | 54 |
|
39 |
| - //phpcs:ignore Squiz.Commenting.FunctionComment.Missing |
| 55 | + /** |
| 56 | + * Enable compilation. |
| 57 | + * |
| 58 | + * @template T of Compiled |
| 59 | + * @param string $directory Directory to store the compiled container. |
| 60 | + * @param string $containerClass Name of the compiled container class. |
| 61 | + * @param class-string<T> $containerParentClass Parent class of the compiled container. |
| 62 | + * @param bool $compile Should we compile the container. |
| 63 | + * @return static |
| 64 | + */ |
40 | 65 | public function enableCompilation(
|
41 | 66 | string $directory,
|
42 | 67 | string $containerClass = 'CompiledContainer',
|
43 |
| - string $containerParentClass = CompiledContainer::class, |
| 68 | + string $containerParentClass = Compiled::class, |
44 | 69 | bool $compile = true,
|
45 | 70 | ): static {
|
46 | 71 | if ( ! $compile ) {
|
47 | 72 | return $this;
|
48 | 73 | }
|
49 | 74 |
|
50 |
| - if ( ! \is_dir( $directory ) && ! \wp_mkdir_p( $directory ) ) { |
51 |
| - return $this; |
52 |
| - } |
| 75 | + $this->ensureCacheDirExists( $directory ); |
53 | 76 |
|
54 | 77 | // @phpstan-ignore return.type
|
55 | 78 | return parent::enableCompilation( $directory, $containerClass, $containerParentClass );
|
56 | 79 | }
|
57 | 80 |
|
58 | 81 | /**
|
59 |
| - * Add definitions to the container. |
| 82 | + * Enable definition cache. |
| 83 | + * |
| 84 | + * @param string $cacheNamespace Namespace for the cache. |
| 85 | + * @param bool $enableCache Should we cache the definitions. |
| 86 | + * @return static |
| 87 | + */ |
| 88 | + public function enableDefinitionCache( string $cacheNamespace = '', bool $enableCache = false ): static { |
| 89 | + return $enableCache |
| 90 | + ? parent::enableDefinitionCache( \rtrim( $cacheNamespace, '.' ) . '.' ) |
| 91 | + : $this; |
| 92 | + } |
| 93 | + |
| 94 | + /** |
| 95 | + * Enable hook cache. |
| 96 | + * |
| 97 | + * @param bool $enableCache Should we cache the hooks. |
| 98 | + * @param string $cacheDirectory Directory to store the cached hooks. |
| 99 | + * @return static |
| 100 | + */ |
| 101 | + public function enableHookCache( bool $enableCache, string $cacheDirectory ): static { |
| 102 | + $this->cacheHooksDir = $enableCache ? $cacheDirectory : null; |
| 103 | + |
| 104 | + if ( $enableCache ) { |
| 105 | + $this->ensureCacheDirExists( $cacheDirectory ); |
| 106 | + } |
| 107 | + |
| 108 | + return $this; |
| 109 | + } |
| 110 | + |
| 111 | + /** |
| 112 | + * Add the base definition to the container. |
| 113 | + * |
| 114 | + * @param array<string,mixed> $config Configuration options. |
| 115 | + * @return App_Builder |
| 116 | + */ |
| 117 | + public function addBaseDefinition( array $config ): App_Builder { |
| 118 | + $definition = array( |
| 119 | + 'xwp.app' => \DI\get( 'Module-' . $config['app_module'] ), |
| 120 | + 'xwp.app.cache' => \DI\value( |
| 121 | + array( |
| 122 | + 'app' => $config['cache_app'], |
| 123 | + 'defs' => $config['cache_defs'], |
| 124 | + 'dir' => $config['cache_dir'], |
| 125 | + 'hooks' => $config['cache_hooks'], |
| 126 | + ), |
| 127 | + ), |
| 128 | + 'xwp.app.debug' => \DI\value( \defined( 'WP_DEBUG' ) && WP_DEBUG ), |
| 129 | + 'xwp.app.env' => \DI\factory( 'wp_get_environment_type' ), |
| 130 | + 'xwp.app.id' => \DI\value( $config['app_id'] ), |
| 131 | + 'xwp.app.module' => \DI\value( $config['app_module'] ), |
| 132 | + 'xwp.app.type' => \DI\value( $config['app_type'] ), |
| 133 | + 'xwp.app.uuid' => \DI\factory( 'wp_generate_uuid4' ), |
| 134 | + 'xwp.app.ver' => \DI\value( $config['app_version'] ), |
| 135 | + ); |
| 136 | + |
| 137 | + if ( $config['app_file'] && 'plugin' === $config['app_type'] ) { |
| 138 | + $definition['xwp.app.file'] = \DI\value( $config['app_file'] ); |
| 139 | + $definition['xwp.app.base'] = \DI\factory( 'plugin_basename', ) |
| 140 | + ->parameter( 'file', \DI\get( 'xwp.app.file' ) ); |
| 141 | + $definition['xwp.app.path'] = \DI\factory( 'plugin_dir_path' ) |
| 142 | + ->parameter( 'file', \DI\get( 'xwp.app.file' ) ); |
| 143 | + } |
| 144 | + |
| 145 | + return parent::addDefinitions( $definition ); |
| 146 | + } |
| 147 | + |
| 148 | + /** |
| 149 | + * Add a module definition to the container. |
60 | 150 | *
|
61 |
| - * @param class-string|string|array<string,mixed>|DefinitionSource ...$definitions Can be an array of definitions, the |
62 |
| - * name of a file containing definitions |
63 |
| - * or a DefinitionSource object. |
64 |
| - * @return $this |
| 151 | + * @param array<string,mixed> $config Configuration options. |
| 152 | + * @return App_Builder |
65 | 153 | */
|
66 |
| - public function addDefinitions( string|array|DefinitionSource ...$definitions ): static { |
67 |
| - return \is_string( $definitions[0] ) && \class_exists( $definitions[0] ) |
68 |
| - ? parent::addDefinitions( ...\xwp_register_module( $definitions[0] )->get_definitions() ) |
69 |
| - : parent::addDefinitions( ...$definitions ); |
| 154 | + public function addModuleDefinition( array $config ): App_Builder { |
| 155 | + $parser = new Parser( $config['app_module'] ); |
| 156 | + |
| 157 | + $defns = $this->isHookCacheEnabled() |
| 158 | + ? ( new Compiler( $parser ) )->compile( $config['cache_dir'] ) |
| 159 | + : $parser->make()->get_parsed(); |
| 160 | + |
| 161 | + return $this->addDefinitions( $defns ); |
| 162 | + } |
| 163 | + |
| 164 | + /** |
| 165 | + * Are we caching the hook definitions? |
| 166 | + * |
| 167 | + * @return bool |
| 168 | + */ |
| 169 | + public function isHookCacheEnabled(): bool { |
| 170 | + return (bool) $this->cacheHooksDir; |
| 171 | + } |
| 172 | + |
| 173 | + /** |
| 174 | + * Ensure the cache directory exists. |
| 175 | + * |
| 176 | + * @param string $directory Directory to check. |
| 177 | + * @return void |
| 178 | + * |
| 179 | + * @throws \RuntimeException If the directory could not be created. |
| 180 | + */ |
| 181 | + protected function ensureCacheDirExists( string $directory ): void { |
| 182 | + if ( ! \is_dir( $directory ) && ! \wp_mkdir_p( $directory ) ) { |
| 183 | + throw new \RuntimeException( |
| 184 | + \sprintf( 'Could not create cache directory: %s', \esc_html( $directory ) ), |
| 185 | + ); |
| 186 | + } |
70 | 187 | }
|
71 | 188 | }
|
0 commit comments