diff --git a/src/Query/QueryFactory.php b/src/Query/QueryFactory.php index abfe753..94c8521 100644 --- a/src/Query/QueryFactory.php +++ b/src/Query/QueryFactory.php @@ -60,19 +60,34 @@ protected function findQueryFilePathInDirectory( string $directory, string $name, ):?string { + $invalidMatchExtension = null; + $validQueryFilePath = null; + foreach(new DirectoryIterator($directory) as $fileInfo) { - if($fileInfo->isDot() - || $fileInfo->isDir()) { + if(!$fileInfo->isFile()) { continue; } - $this->getExtensionIfValid($fileInfo); $fileNameNoExtension = strtok($fileInfo->getFilename(), "."); if($fileNameNoExtension !== $name) { continue; } - return $fileInfo->getRealPath(); + try { + $this->getExtensionIfValid($fileInfo); + $validQueryFilePath ??= $fileInfo->getRealPath(); + } + catch(QueryFileExtensionException) { + $invalidMatchExtension = strtolower($fileInfo->getExtension()); + } + } + + if(!is_null($validQueryFilePath)) { + return $validQueryFilePath; + } + + if(!is_null($invalidMatchExtension)) { + throw new QueryFileExtensionException($invalidMatchExtension); } return null; @@ -81,7 +96,7 @@ protected function findQueryFilePathInDirectory( protected function locateOverrideDirectory(string $classFilePath):?string { $baseName = pathinfo($classFilePath, PATHINFO_FILENAME); foreach(new DirectoryIterator(dirname($classFilePath)) as $fileInfo) { - if($fileInfo->isDot() || !$fileInfo->isDir()) { + if(!$fileInfo->isDir()) { continue; } @@ -207,20 +222,12 @@ protected function getExtensionIfValid(SplFileInfo $fileInfo):string { protected function throwCorrectException(Exception $exception):void { $message = $exception->getMessage(); - - switch(get_class($exception)) { - case InvalidArgumentException::class: - $matches = []; - if(1 !== preg_match( - "/Database \[(.+)\] not configured/", $message, $matches)) { - throw $exception; - } - - $connectionName = $matches[1]; - throw new ConnectionNotConfiguredException($connectionName); - - default: + $matches = []; + if(1 !== preg_match("/Database \[(.+)\] not configured/", $message, $matches)) { throw $exception; } + + $connectionName = $matches[1]; + throw new ConnectionNotConfiguredException($connectionName); } } diff --git a/test/phpunit/Query/QueryFactoryTest.php b/test/phpunit/Query/QueryFactoryTest.php index b708ba4..a9939ae 100644 --- a/test/phpunit/Query/QueryFactoryTest.php +++ b/test/phpunit/Query/QueryFactoryTest.php @@ -3,6 +3,7 @@ use Gt\Database\Connection\DefaultSettings; use Gt\Database\Connection\Driver; +use Gt\Database\Connection\ConnectionNotConfiguredException; use Gt\Database\Query\PhpQuery; use Gt\Database\Query\Query; use Gt\Database\Query\QueryFactory; @@ -214,6 +215,52 @@ public function testCreatePhpPrefersOverrideDirectoryWhenClassIsLowerCase():void } } + public function testCreatePhpPrefersOverrideDirectoryWhenMethodIsNotPublic():void { + $basePath = Helper::getTmpDir(); + $classPath = implode(DIRECTORY_SEPARATOR, [ + $basePath, + "query", + "User.php", + ]); + $overrideDirectory = implode(DIRECTORY_SEPARATOR, [ + $basePath, + "query", + "User", + ]); + mkdir($overrideDirectory, 0775, true); + file_put_contents( + $classPath, + <<create("getById"); + + self::assertInstanceOf(SqlQuery::class, $query); + self::assertSame( + realpath("$overrideDirectory/getById.sql"), + $query->getFilePath() + ); + } + finally { + Helper::deleteDir($basePath); + } + } + public function testCreatePhpThrowsWhenOverrideConflictsWithPublicMethod():void { $basePath = Helper::getTmpDir(); $classPath = implode(DIRECTORY_SEPARATOR, [ @@ -255,4 +302,104 @@ public function getById():string { Helper::deleteDir($basePath); } } + + public function testCreateTranslatesConnectionNotConfiguredException():void { + $basePath = Helper::getTmpDir(); + $queryDirectory = implode(DIRECTORY_SEPARATOR, [ + $basePath, + "query", + ]); + mkdir($queryDirectory, 0775, true); + file_put_contents("$queryDirectory/users.sql", "select 1"); + + $driver = $this->createMock(Driver::class); + $driver->method("getConnection") + ->willThrowException( + new \InvalidArgumentException("Database [reporting] not configured") + ); + + try { + $sut = new QueryFactory($queryDirectory, $driver); + + self::expectException(ConnectionNotConfiguredException::class); + self::expectExceptionMessage("reporting"); + $sut->create("users"); + } + finally { + Helper::deleteDir($basePath); + } + } + + public function testCreateRethrowsUnexpectedInvalidArgumentException():void { + $basePath = Helper::getTmpDir(); + $queryDirectory = implode(DIRECTORY_SEPARATOR, [ + $basePath, + "query", + ]); + mkdir($queryDirectory, 0775, true); + file_put_contents("$queryDirectory/users.sql", "select 1"); + + $driver = $this->createMock(Driver::class); + $driver->method("getConnection") + ->willThrowException(new \InvalidArgumentException("Unexpected error")); + + try { + $sut = new QueryFactory($queryDirectory, $driver); + + self::expectException(\InvalidArgumentException::class); + self::expectExceptionMessage("Unexpected error"); + $sut->create("users"); + } + finally { + Helper::deleteDir($basePath); + } + } + + public function testFindQueryFilePathIgnoresUnrelatedInvalidExtensions():void { + $basePath = Helper::getTmpDir(); + $queryDirectory = implode(DIRECTORY_SEPARATOR, [ + $basePath, + "query", + ]); + mkdir($queryDirectory, 0775, true); + file_put_contents("$queryDirectory/valid.sql", "select 1"); + file_put_contents("$queryDirectory/other.sql~", "select 2"); + + try { + $sut = new QueryFactory($queryDirectory, new Driver(new DefaultSettings())); + $queryFilePath = $sut->findQueryFilePath("valid"); + + self::assertSame( + realpath("$queryDirectory/valid.sql"), + $queryFilePath + ); + } + finally { + Helper::deleteDir($basePath); + } + } + + public function testFindQueryFilePathPrefersSupportedExtensionOverEditorBackup():void { + $basePath = Helper::getTmpDir(); + $queryDirectory = implode(DIRECTORY_SEPARATOR, [ + $basePath, + "query", + ]); + mkdir($queryDirectory, 0775, true); + file_put_contents("$queryDirectory/report.sql", "select 1"); + file_put_contents("$queryDirectory/report.sql~", "select 2"); + + try { + $sut = new QueryFactory($queryDirectory, new Driver(new DefaultSettings())); + $queryFilePath = $sut->findQueryFilePath("report"); + + self::assertSame( + realpath("$queryDirectory/report.sql"), + $queryFilePath + ); + } + finally { + Helper::deleteDir($basePath); + } + } }