From 8ac53721f286f07cbcf4481930d4f5bed7b4c93e Mon Sep 17 00:00:00 2001 From: Greg Bowler Date: Sun, 15 Mar 2026 18:15:25 +0000 Subject: [PATCH] feature: implement isProduction closes #229 --- src/Config.php | 4 ++++ src/ConfigFactory.php | 17 +++++++++++++++++ test/phpunit/ConfigFactoryConfigTest.php | 22 ++++++++++++++++++++++ test/phpunit/ConfigTest.php | 20 ++++++++++++++++++++ 4 files changed, 63 insertions(+) diff --git a/src/Config.php b/src/Config.php index 9cd2cf2..2dea428 100644 --- a/src/Config.php +++ b/src/Config.php @@ -29,6 +29,10 @@ public function getSection(string $sectionName):?ConfigSection { return $this->sectionList[$sectionName] ?? null; } + public function isProduction():bool { + return $this->getBool("app.production") ?? false; + } + protected function getSectionValue(string $name):?string { $parts = explode(".", $name, 2); $section = $this->getSection($parts[0]); diff --git a/src/ConfigFactory.php b/src/ConfigFactory.php index 759e959..713b527 100644 --- a/src/ConfigFactory.php +++ b/src/ConfigFactory.php @@ -51,6 +51,10 @@ public static function createForProject( $config = $config->withMerge($previousConfig); } + if($file === "production") { + $config = self::withProductionFlag($config); + } + $previousConfig = $config; } @@ -65,4 +69,17 @@ public static function createFromPathName(string $pathName):?Config { $parser = new IniParser($pathName); return $parser->parse(); } + + protected static function withProductionFlag(Config $config):Config { + $appSection = $config->getSection("app"); + if($appSection && $appSection->contains("production")) { + return $config; + } + + return $config->withMerge(new Config( + new ConfigSection("app", [ + "production" => "true", + ]) + )); + } } diff --git a/test/phpunit/ConfigFactoryConfigTest.php b/test/phpunit/ConfigFactoryConfigTest.php index ac6ac9f..d63df64 100644 --- a/test/phpunit/ConfigFactoryConfigTest.php +++ b/test/phpunit/ConfigFactoryConfigTest.php @@ -34,6 +34,7 @@ public function testCreateForProject():void { self::assertEquals("this appears by default", $config->get("block1.value.existsByDefault")); self::assertEquals("my.production.database", $config->get("database.host")); self::assertEquals("example", $config->get("database.schema")); + self::assertTrue($config->isProduction()); } public function testCreateFromPathName():void { @@ -83,4 +84,25 @@ public function testCreateForProjectPreservesFalseyOverrides():void { self::assertSame(0, $config->getInt("session.max_age")); self::assertSame("", $config->getString("session.label")); } + + public function testCreateForProjectProductionFileDoesNotOverrideExplicitFlag():void { + $filePath = implode(DIRECTORY_SEPARATOR, [ + $this->tmp, + "config.ini", + ]); + $filePathProduction = implode(DIRECTORY_SEPARATOR, [ + $this->tmp, + "config.production.ini", + ]); + + file_put_contents($filePath, implode(PHP_EOL, [ + "[app]", + "production=false", + "", + ])); + file_put_contents($filePathProduction, Helper::INI_OVERRIDE_PROD); + + $config = ConfigFactory::createForProject($this->tmp); + self::assertFalse($config->isProduction()); + } } diff --git a/test/phpunit/ConfigTest.php b/test/phpunit/ConfigTest.php index edf6433..36259e6 100644 --- a/test/phpunit/ConfigTest.php +++ b/test/phpunit/ConfigTest.php @@ -67,6 +67,26 @@ public function testTypeSafeGetter() { self::assertNull($sut->getFloat("nothing-here")); } + public function testIsProductionDefaultsToFalse():void { + putenv("app_production"); + $config = new Config(); + self::assertFalse($config->isProduction()); + } + + public function testIsProductionUsesAppProductionValue():void { + putenv("app_production"); + $config = new Config( + new ConfigSection("app", [ + "production" => "0", + ]) + ); + self::assertFalse($config->isProduction()); + + putenv("app_production=true"); + self::assertTrue($config->isProduction()); + putenv("app_production"); + } + public function testWithMergeReturnsNewAndDoesNotMutateOriginal():void { $original = new Config( new ConfigSection("app", [