From eb58cea5365b07d0c6bb231301cc1d526291070d Mon Sep 17 00:00:00 2001 From: Jason Coward Date: Fri, 27 Mar 2026 11:40:30 -0600 Subject: [PATCH] Throw xPDOException when ContainerInterface lacks required 'config' entry Previously, passing a PSR-11 container without a 'config' entry to xPDO caused initConfig() to silently fall back to a minimal default config array, hiding the broken API contract from the caller. Now an explicit xPDOException is thrown, making the required contract clear. Closes #269. --- src/xPDO/xPDO.php | 2 + test/complete.phpunit.xml | 1 + test/mysql.phpunit.xml | 1 + test/pgsql.phpunit.xml | 1 + test/sqlite.phpunit.xml | 1 + test/xPDO/Test/xPDOPsr11InitTest.php | 68 ++++++++++++++++++++++++++++ 6 files changed, 74 insertions(+) create mode 100644 test/xPDO/Test/xPDOPsr11InitTest.php diff --git a/src/xPDO/xPDO.php b/src/xPDO/xPDO.php index 9567b3d..bbf14f4 100644 --- a/src/xPDO/xPDO.php +++ b/src/xPDO/xPDO.php @@ -369,6 +369,8 @@ protected function initConfig($data) { $this->services = $data; if ($this->services->has('config')) { $data = $this->services->get('config'); + } else { + throw new xPDOException('A ContainerInterface passed to xPDO must provide a \'config\' entry containing the xPDO configuration array.'); } } if (!is_array($data)) { diff --git a/test/complete.phpunit.xml b/test/complete.phpunit.xml index 2514653..157888c 100644 --- a/test/complete.phpunit.xml +++ b/test/complete.phpunit.xml @@ -34,6 +34,7 @@ ./xPDO/Test/Transport/xPDOTransportTest.php ./xPDO/Test/Transport/xPDOVehicleTest.php ./xPDO/Test/PSR4/xPDOTest.php + ./xPDO/Test/xPDOPsr11InitTest.php ./xPDO/Test/TearDownTest.php diff --git a/test/mysql.phpunit.xml b/test/mysql.phpunit.xml index 2514653..157888c 100644 --- a/test/mysql.phpunit.xml +++ b/test/mysql.phpunit.xml @@ -34,6 +34,7 @@ ./xPDO/Test/Transport/xPDOTransportTest.php ./xPDO/Test/Transport/xPDOVehicleTest.php ./xPDO/Test/PSR4/xPDOTest.php + ./xPDO/Test/xPDOPsr11InitTest.php ./xPDO/Test/TearDownTest.php diff --git a/test/pgsql.phpunit.xml b/test/pgsql.phpunit.xml index 2cd17e5..fbb12fa 100644 --- a/test/pgsql.phpunit.xml +++ b/test/pgsql.phpunit.xml @@ -34,6 +34,7 @@ ./xPDO/Test/Transport/xPDOTransportTest.php ./xPDO/Test/Transport/xPDOVehicleTest.php ./xPDO/Test/PSR4/xPDOTest.php + ./xPDO/Test/xPDOPsr11InitTest.php ./xPDO/Test/TearDownTest.php diff --git a/test/sqlite.phpunit.xml b/test/sqlite.phpunit.xml index fa81718..7f89e66 100644 --- a/test/sqlite.phpunit.xml +++ b/test/sqlite.phpunit.xml @@ -34,6 +34,7 @@ ./xPDO/Test/Transport/xPDOTransportTest.php ./xPDO/Test/Transport/xPDOVehicleTest.php ./xPDO/Test/PSR4/xPDOTest.php + ./xPDO/Test/xPDOPsr11InitTest.php ./xPDO/Test/TearDownTest.php diff --git a/test/xPDO/Test/xPDOPsr11InitTest.php b/test/xPDO/Test/xPDOPsr11InitTest.php new file mode 100644 index 0000000..8666667 --- /dev/null +++ b/test/xPDO/Test/xPDOPsr11InitTest.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace xPDO\Test; + +use PHPUnit\Framework\TestCase; +use xPDO\xPDO; +use xPDO\xPDOContainer; +use xPDO\xPDOException; + +/** + * Tests for PSR-11 container initialization contract (issue #269). + * + * These tests verify that passing a ContainerInterface to xPDO makes the + * required 'config' entry contract explicit rather than silently falling back + * to default values when it is missing. + * + * @package xPDO\Test + */ +class xPDOPsr11InitTest extends TestCase +{ + /** + * Passing a container without a 'config' entry must throw xPDOException. + * + * Before the fix, xPDO would silently fall back to an empty config array + * when the container did not provide a 'config' entry, hiding the broken + * API contract from the caller. + */ + public function testContainerWithoutConfigEntryThrowsException(): void + { + $container = new xPDOContainer(); + // Deliberately do NOT add a 'config' entry + + $this->expectException(xPDOException::class); + $this->expectExceptionMessage('config'); + + new xPDO(null, '', '', $container); + } + + /** + * Passing a container WITH a valid 'config' entry must initialize normally. + * + * This is the positive-path contract test: a container that provides the + * required 'config' entry must result in a fully initialised xPDO instance + * without throwing. + */ + public function testContainerWithConfigEntryInitializesSuccessfully(): void + { + $properties = include __DIR__ . '/../../properties.inc.php'; + $driver = getenv('TEST_DRIVER') ?: 'sqlite'; + $config = $properties["{$driver}_array_options"]; + + $container = new xPDOContainer(); + $container->add('config', $config); + + $xpdo = new xPDO(null, '', '', $container); + + $this->assertInstanceOf(xPDO::class, $xpdo); + $this->assertSame($container, $xpdo->services); + } +}