diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f850144..98d47c92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Ensure that the `delete()` method of the HTTP Client doesn't set a body by default. - Ensure that `with_terms()` can support an array of term slugs when passed with a taxonomy index. +- Ensure that framework configuration respects the application configuration. ## v1.2.0 - 2024-09-23 diff --git a/src/mantle/database/console/class-seed-command.php b/src/mantle/database/console/class-seed-command.php index 94f1fe65..2dc0b589 100644 --- a/src/mantle/database/console/class-seed-command.php +++ b/src/mantle/database/console/class-seed-command.php @@ -28,9 +28,9 @@ class Seed_Command extends Command { /** * Run Database Seeding */ - public function handle(): void { + public function handle(): int { if ( ! $this->confirm_to_proceed() ) { - return; + return static::FAILURE; } // Disable cache purging. @@ -38,6 +38,13 @@ public function handle(): void { remove_action_validated( 'shutdown', [ \WPCOM_VIP_Cache_Manager::instance(), 'execute_purges' ] ); } + $class = $this->container->get_namespace() . '\\Database\\Seeds\\Database_Seeder'; + + if ( ! class_exists( $class ) ) { + $this->error( "Database Seeder class not found: {$class}" ); + return static::FAILURE; + } + $this->container ->make( $this->option( 'class', \App\Database\Seeds\Database_Seeder::class ) ) ->set_container( $this->container ) @@ -45,5 +52,7 @@ public function handle(): void { ->__invoke(); $this->success( __( 'Database seeding completed.', 'mantle' ) ); + + return static::SUCCESS; } } diff --git a/src/mantle/framework/bootstrap/class-load-configuration.php b/src/mantle/framework/bootstrap/class-load-configuration.php index 2aadc68d..889dad42 100644 --- a/src/mantle/framework/bootstrap/class-load-configuration.php +++ b/src/mantle/framework/bootstrap/class-load-configuration.php @@ -43,13 +43,13 @@ public static function merge( array $config ): void { public function bootstrap( Application $app ): void { $config = $app->make( 'config' ); - // Load the configuration files if not loaded from cache. + // Load the configuration files if not already loaded from cache. if ( ! $config->get( 'config.loaded_from_cache' ) ) { $this->load_configuration_files( $app, $config ); } if ( ! empty( static::$merge ) ) { - $this->load_merge_configuration( $config ); + $this->load_late_configuration( $config ); } } @@ -81,13 +81,7 @@ protected function load_configuration_to_repository( array $files, Repository_Co continue; } - $existing_config = $repository->get( $key ); - - foreach ( $this->get_mergeable_options( $key ) as $option ) { - $config[ $option ] = array_merge( $existing_config[ $option ] ?? [], $config[ $option ] ?? [] ); - } - - $repository->set( $key, $config ); + $repository->set( $key, $this->merge_configuration( $key, $repository->get( $key ), $config ) ); } } } @@ -106,14 +100,13 @@ protected function load_configuration_files( Application $app, Repository_Contra return; } - // Load the root-level config. $this->load_configuration_to_repository( $files['global'], $repository ); $env = $app->environment(); // Load the environment-specific configurations if one exists. - if ( ! empty( $files['env'][ $env ] ) ) { - $this->load_configuration_to_repository( $files['env'][ $env ], $repository ); + if ( ! empty( $files['environment'][ $env ] ) ) { + $this->load_configuration_to_repository( $files['environment'][ $env ], $repository ); } } @@ -154,18 +147,18 @@ protected function get_configuration_directories( Application $app ): array { * Find the configuration files to load. * * @param Application $app Application instance. - * @return array{global: array, env: array>} + * @return array{global: array, environment: array>} */ protected function get_configuration_files( Application $app ): array { $files = [ - 'global' => [], - 'env' => [], + 'global' => [], + 'environment' => [], ]; $finder = Finder::create() ->files() ->name( '*.php' ) - ->depth( '< 2' ) // Only descend two levels. + ->depth( '< 2' ) ->in( $this->get_configuration_directories( $app ) ); foreach ( $finder as $file ) { @@ -179,50 +172,52 @@ protected function get_configuration_files( Application $app ): array { }; if ( $environment ) { - $files['env'][ $environment ][ $name ][] = $file->getRealPath(); + $files['environment'][ $environment ][ $name ][] = $file->getRealPath(); } else { $files['global'][ $name ][] = $file->getRealPath(); } } - // Sort them to ensure a similar experience across all hosting environments. - foreach ( $files as $type => $config_files ) { - ksort( $files[ $type ], SORT_NATURAL ); + return $files; + } + + /** + * Retrieve the base configuration. + * + * @return array> + */ + protected function get_base_configuration(): array { + $config = []; + + foreach ( Finder::create()->files()->name( '*.php' )->depth( '< 2' )->in( dirname( __DIR__, 4 ) . '/config' ) as $file ) { + $name = basename( $file->getRealPath(), '.php' ); + + $config[ $name ] = $this->merge_configuration( + $name, $config[ $name ] ?? [], + require $file->getRealPath() // phpcs:ignore WordPressVIPMinimum.Files.IncludingFile.UsingVariable + ); } - return $files; + return $config; } /** * Load the additional configuration from the bootloader to the repository. * * @throws InvalidArgumentException If the configuration value is not an array. - * @throws InvalidArgumentException If the mergeable option is not an array. * * @param Repository_Contract $repository Configuration Repository. */ - protected function load_merge_configuration( Repository_Contract $repository ): void { + protected function load_late_configuration( Repository_Contract $repository ): void { foreach ( static::$merge as $config_key => $values ) { if ( ! is_array( $values ) ) { - throw new InvalidArgumentException( "The bootstrap-loaded configuration value for key '{$config_key}' must be an array." ); - } - - $config = $repository->get( $config_key, [] ); - $mergeable_options = $this->get_mergeable_options( $config_key ); - - foreach ( $values as $key => $value ) { - if ( in_array( $key, $mergeable_options, true ) ) { - if ( ! is_array( $value ) ) { - throw new InvalidArgumentException( "The mergeable option '{$key}' for key '{$config_key}' must be an array." ); - } - - $config[ $key ] = array_merge( $config[ $key ] ?? [], $value ); - } else { - $config[ $key ] = $value; - } + throw new InvalidArgumentException( "The bootloader configuration value for key '{$config_key}' must be an array." ); } - $repository->set( $config_key, $config ); + $repository->set( + $config_key, + $this->merge_configuration( $config_key, $repository->get( $config_key, [] ), $values ), + ); static::$merge = []; } @@ -241,4 +236,34 @@ protected function get_mergeable_options( string $name ): array { 'app' => [ 'providers' ], ][ $name ] ?? []; } + + /** + * Merge two configurations together. + * + * Will merge the two configurations together and merge any mergeable options. + * + * @throws InvalidArgumentException If the mergeable option is not an array. + * @see Load_Configuration::get_mergeable_options() + * + * @param string $config_name Configuration name. + * @param array $config_a First configuration. + * @param array $config_b Second configuration. + */ + protected function merge_configuration( string $config_name, array $config_a, array $config_b ): array { + $new_config = array_merge( $config_a, $config_b ); + + foreach ( $this->get_mergeable_options( $config_name ) as $option ) { + if ( ! isset( $config_a[ $option ] ) || ! isset( $config_b[ $option ] ) ) { + continue; + } + + if ( ! is_array( $config_a[ $option ] ) || ! is_array( $config_b[ $option ] ) ) { + throw new InvalidArgumentException( "The mergeable option '{$option}' for key '{$config_name}' must be an array." ); + } + + $new_config[ $option ] = array_merge( $config_a[ $option ] ?? [], $config_b[ $option ] ?? [] ); + } + + return $new_config; + } } diff --git a/src/mantle/framework/console/class-about-command.php b/src/mantle/framework/console/class-about-command.php index db7759c3..a35cf04a 100644 --- a/src/mantle/framework/console/class-about-command.php +++ b/src/mantle/framework/console/class-about-command.php @@ -132,7 +132,6 @@ protected function gather_information(): void { static::add( fn () => [ - 'Cache' => config( 'cache.default' ), 'Filesystem' => config( 'filesystem.default' ), 'Logging' => config( 'logging.default' ), 'Queue' => config( 'queue.default' ), diff --git a/src/mantle/framework/console/class-config-cache-command.php b/src/mantle/framework/console/class-config-cache-command.php index 3239bcda..50a295d1 100644 --- a/src/mantle/framework/console/class-config-cache-command.php +++ b/src/mantle/framework/console/class-config-cache-command.php @@ -76,7 +76,10 @@ public function handle( Filesystem $filesystem ): void { * Boot a fresh copy of the application configuration. */ protected function get_fresh_configuration(): array { - $app = require $this->container->get_bootstrap_path( '/app.php' ); // phpcs:ignore WordPressVIPMinimum.Files.IncludingFile.UsingVariable + $bootloader = require $this->container->get_bootstrap_path( '/app.php' ); // phpcs:ignore WordPressVIPMinimum.Files.IncludingFile.UsingVariable + + $app = $bootloader->get_application(); + $app->set_base_path( $this->container->get_base_path() ); $app->make( Kernel::class )->bootstrap();