diff --git a/.travis.yml b/.travis.yml index 75efb47..aeb52b2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ before_script: script: - vendor/bin/phpunit --coverage-text --coverage-clover build/logs/clover.xml - vendor/bin/phpstan analyse src bin --level=7 - - vendor/bin/phpcs --standard=ruleset.xml --extensions=php src bin tests + - vendor/bin/phpcs --standard=ruleset.xml --extensions=php --ignore=tests/TestEntities src bin tests - if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then ./cc-test-reporter after-build -t clover --exit-code $TRAVIS_TEST_RESULT; fi notifications: diff --git a/README.md b/README.md index ba06454..b12fdf3 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,6 @@ Squirrel Entities Component [![Build Status](https://img.shields.io/travis/com/squirrelphp/entities.svg)](https://travis-ci.com/squirrelphp/entities) [![Test Coverage](https://api.codeclimate.com/v1/badges/36a9f5a3b4abbaf7901c/test_coverage)](https://codeclimate.com/github/squirrelphp/entities/test_coverage) ![PHPStan](https://img.shields.io/badge/style-level%207-success.svg?style=flat-round&label=phpstan) [![Packagist Version](https://img.shields.io/packagist/v/squirrelphp/entities.svg?style=flat-round)](https://packagist.org/packages/squirrelphp/entities) [![PHP Version](https://img.shields.io/packagist/php-v/squirrelphp/entities.svg)](https://packagist.org/packages/squirrelphp/entities) [![Software License](https://img.shields.io/badge/license-MIT-success.svg?style=flat-round)](LICENSE) -Simple, safe and flexible implementation of handling SQL entities and repositories as well as multi-table SQL queries while staying lightweight and easy to understand and use. +Simple & safe implementation of handling SQL entities and repositories as well as multi-table SQL queries while staying lightweight and easy to understand and use. Offers rapid application development by generating repositories (which should not be added to VCS) for entities, and [squirrelphp/entities-bundle](https://github.com/squirrelphp/entities-bundle) offers automatic integration of these repositories into Symfony. -This package is still not 100% finished - some tests are missing (although the most important parts have test coverage) and the documentation will be a challenge. For now it is released so it can be used as-is and improved over time. \ No newline at end of file +This package is still not 100% finished - mainly documentation is lacking and needs to be added, and some slight API changes are still possible, although unlikely at this point. Some refactoring would also be good. \ No newline at end of file diff --git a/bin/squirrel_repositories_generate b/bin/squirrel_repositories_generate index 0af9928..aaaa77b 100755 --- a/bin/squirrel_repositories_generate +++ b/bin/squirrel_repositories_generate @@ -39,7 +39,10 @@ $input = new ArgvInput(null, $inputDefinition); $srcDirectories = $input->getOption('source-dir'); // Execute command to generate repositories -$cmd = new \Squirrel\Entities\Generate\RepositoriesGenerateCommand($srcDirectories); +$cmd = new \Squirrel\Entities\Generate\RepositoriesGenerateCommand( + $srcDirectories, + new \Squirrel\Entities\Generate\PHPFilesInDirectoryGetContents() +); $log = $cmd(); // Add summary of processed entities diff --git a/captainhook.json b/captainhook.json index 414b49d..3065f24 100644 --- a/captainhook.json +++ b/captainhook.json @@ -35,7 +35,7 @@ "conditions": [] }, { - "action": "vendor/bin/phpcs --standard=ruleset.xml --extensions=php --cache src bin tests", + "action": "vendor/bin/phpcs --standard=ruleset.xml --extensions=php --cache --ignore=tests/TestEntities src bin tests", "options": [], "conditions": [] } diff --git a/composer.json b/composer.json index 740b91d..ed81a01 100644 --- a/composer.json +++ b/composer.json @@ -57,7 +57,7 @@ "scripts": { "phpstan": "vendor/bin/phpstan analyse src bin --level=7", "phpunit": "vendor/bin/phpunit --colors=always", - "phpcs": "vendor/bin/phpcs --standard=ruleset.xml --extensions=php --cache src bin tests", + "phpcs": "vendor/bin/phpcs --standard=ruleset.xml --extensions=php --cache --ignore=tests/TestEntities src bin tests", "codecoverage": "vendor/bin/phpunit --coverage-html tests/_reports" } } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 9f44502..96ccc25 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -5,7 +5,7 @@ xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/6.3/phpunit.xsd" backupGlobals="false" colors="true" - bootstrap="vendor/autoload.php" + bootstrap="tests/autoload.php" > @@ -15,7 +15,10 @@ - src + src + + src/Generate/PHPFilesInDirectoryGetContents.php + diff --git a/ruleset.xml b/ruleset.xml index 62e0a17..4913898 100644 --- a/ruleset.xml +++ b/ruleset.xml @@ -10,7 +10,6 @@ - diff --git a/src/Action/MultiSelectIterator.php b/src/Action/MultiSelectIterator.php index 893d8ac..081a408 100644 --- a/src/Action/MultiSelectIterator.php +++ b/src/Action/MultiSelectIterator.php @@ -10,85 +10,21 @@ */ class MultiSelectIterator implements \Iterator, ActionInterface { + use SelectIteratorTrait; + /** * @var MultiRepositoryReadOnlyInterface */ private $repository; - /** - * @var array SELECT query to execute - */ - private $query = []; - /** * @var MultiRepositorySelectQueryInterface|null */ private $selectReference; - /** - * @var int - */ - private $position = -1; - - /** - * @var array|null - */ - private $lastResult; - public function __construct(MultiRepositoryReadOnlyInterface $repository, array $query) { $this->repository = $repository; $this->query = $query; } - - /** - * @return array|null - */ - public function current() - { - return $this->lastResult; - } - - public function next() - { - if (isset($this->selectReference)) { - $this->lastResult = $this->repository->fetch($this->selectReference); - $this->position++; - } - } - - /** - * @return int - */ - public function key() - { - return $this->position; - } - - /** - * @return bool - */ - public function valid() - { - return ( $this->lastResult === null ? false : true ); - } - - public function rewind() - { - $this->clear(); - - $this->selectReference = $this->repository->select($this->query); - - $this->next(); - } - - public function clear() - { - if (isset($this->selectReference)) { - $this->repository->clear($this->selectReference); - } - $this->position = -1; - $this->selectReference = null; - $this->lastResult = null; - } } diff --git a/src/Action/SelectIterator.php b/src/Action/SelectIterator.php index 94d2d6b..8c09074 100644 --- a/src/Action/SelectIterator.php +++ b/src/Action/SelectIterator.php @@ -10,85 +10,21 @@ */ class SelectIterator implements \Iterator, ActionInterface { + use SelectIteratorTrait; + /** * @var RepositoryReadOnlyInterface */ private $repository; - /** - * @var array SELECT query to execute - */ - private $query = []; - /** * @var RepositorySelectQueryInterface|null */ private $selectReference; - /** - * @var int - */ - private $position = -1; - - /** - * @var object|null - */ - private $lastResult; - public function __construct(RepositoryReadOnlyInterface $repository, array $query) { $this->repository = $repository; $this->query = $query; } - - /** - * @return object|null - */ - public function current() - { - return $this->lastResult; - } - - public function next() - { - if (isset($this->selectReference)) { - $this->lastResult = $this->repository->fetch($this->selectReference); - $this->position++; - } - } - - /** - * @return int - */ - public function key() - { - return $this->position; - } - - /** - * @return bool - */ - public function valid() - { - return ( $this->lastResult === null ? false : true ); - } - - public function rewind() - { - $this->clear(); - - $this->selectReference = $this->repository->select($this->query); - - $this->next(); - } - - public function clear() - { - if (isset($this->selectReference)) { - $this->repository->clear($this->selectReference); - } - $this->position = -1; - $this->selectReference = null; - $this->lastResult = null; - } } diff --git a/src/Action/SelectIteratorTrait.php b/src/Action/SelectIteratorTrait.php new file mode 100644 index 0000000..eded518 --- /dev/null +++ b/src/Action/SelectIteratorTrait.php @@ -0,0 +1,85 @@ +lastResult; + } + + public function next() + { + if (isset($this->selectReference)) { + $this->lastResult = $this->repository->fetch($this->selectReference); + $this->position++; + } + } + + /** + * @return int + */ + public function key() + { + return $this->position; + } + + /** + * @return bool + */ + public function valid() + { + return ( $this->lastResult === null ? false : true ); + } + + public function rewind() + { + $this->clear(); + + $this->selectReference = $this->repository->select($this->query); + + $this->next(); + } + + public function clear() + { + if (isset($this->selectReference)) { + $this->repository->clear($this->selectReference); + } + $this->position = -1; + $this->selectReference = null; + $this->lastResult = null; + } +} diff --git a/src/Generate/FindClassesWithAnnotation.php b/src/Generate/FindClassesWithAnnotation.php index a55cda5..772aaaa 100644 --- a/src/Generate/FindClassesWithAnnotation.php +++ b/src/Generate/FindClassesWithAnnotation.php @@ -39,7 +39,10 @@ public function __invoke(string $fileContents) $namespaceStarted = false; // We have found the SQLMapper annotation - so there can be entities in this file - if ($importClassName === 'Squirrel\\Entities\\Annotation') { + if ($importClassName === 'Squirrel\\Entities\\Annotation' + || $importClassName === 'Squirrel\\Entities\\Annotation\\Entity' + || $importClassName === 'Squirrel\\Entities\\Annotation\\Field' + ) { $annotationUseFound = true; } } diff --git a/src/Generate/PHPFilesInDirectoryGetContents.php b/src/Generate/PHPFilesInDirectoryGetContents.php new file mode 100644 index 0000000..3a53375 --- /dev/null +++ b/src/Generate/PHPFilesInDirectoryGetContents.php @@ -0,0 +1,36 @@ +in($directory)->files()->name('*.php')->sortByName(); + + // Go through files which were found + foreach ($sourceFinder as $file) { + // Safety check because Finder can return false if the file was not found + if ($file->getRealPath() === false) { + throw new \InvalidArgumentException('File in source directory not found'); + } + + // Get file contents + $fileContents = \file_get_contents($file->getRealPath()); + + // Another safety check because file_get_contents can return false if the file was not found + if ($fileContents===false) { + throw new \InvalidArgumentException('File in source directory could not be retrieved'); + } + + yield [ + 'filename' => $file->getFilename(), + 'path' => $file->getPath(), + 'contents' => $fileContents, + ]; + } + } +} diff --git a/src/Generate/RepositoriesGenerateCommand.php b/src/Generate/RepositoriesGenerateCommand.php index 93998f9..210a61b 100644 --- a/src/Generate/RepositoriesGenerateCommand.php +++ b/src/Generate/RepositoriesGenerateCommand.php @@ -4,7 +4,6 @@ use Doctrine\Common\Annotations\AnnotationReader; use Squirrel\Entities\Annotation\EntityProcessor; -use Symfony\Component\Finder\Finder; /** * Generate repositories and service definitions for SQLMapper entities @@ -22,9 +21,10 @@ class RepositoriesGenerateCommand private $sourceCodeDirectories; /** - * @var string + * @var array */ - private $repositoryPhpFileBlueprintReadOnly = <<<'EOD' + private $repositoryPhpFileBlueprint = [ + 'ReadOnly' => <<<'EOD' <<<'EOD' repository = $repository; parent::__construct($repository); } - + public function insert(): \Squirrel\Entities\Action\InsertEntry { return new \Squirrel\Entities\Action\InsertEntry($this->repository); } - + public function insertOrUpdate(): \Squirrel\Entities\Action\InsertOrUpdateEntry { return new \Squirrel\Entities\Action\InsertOrUpdateEntry($this->repository); } - + public function update(): \Squirrel\Entities\Action\UpdateEntries { return new \Squirrel\Entities\Action\UpdateEntries($this->repository); } - + public function delete(): \Squirrel\Entities\Action\DeleteEntries { return new \Squirrel\Entities\Action\DeleteEntries($this->repository); @@ -272,15 +269,26 @@ public function delete(): \Squirrel\Entities\Action\DeleteEntries } } -EOD; +EOD + , + ]; + + /** + * @var PHPFilesInDirectoryGetContents + */ + private $PHPFilesInDirectoryGetContents; /** * @param string[] $sourceCodeDirectories + * @param PHPFilesInDirectoryGetContents $PHPFilesInDirectoryGetContents */ - public function __construct(array $sourceCodeDirectories) - { + public function __construct( + array $sourceCodeDirectories, + PHPFilesInDirectoryGetContents $PHPFilesInDirectoryGetContents + ) { $this->findClassesWithAnnotation = new FindClassesWithAnnotation(); $this->sourceCodeDirectories = $sourceCodeDirectories; + $this->PHPFilesInDirectoryGetContents = $PHPFilesInDirectoryGetContents; } /** @@ -298,27 +306,10 @@ public function __invoke(): array // Go through directories foreach ($this->sourceCodeDirectories as $directory) { - // Find the files in the directory - $sourceFinder = new Finder(); - $sourceFinder->in($directory)->files()->name('*.php'); - // Go through files which were found - foreach ($sourceFinder as $file) { - // Safety check because Finder can return false if the file was not found - if ($file->getRealPath()===false) { - throw new \InvalidArgumentException('File in source directory not found'); - } - - // Get file contents - $fileContents = \file_get_contents($file->getRealPath()); - - // Another safety check because file_get_contents can return false if the file was not found - if ($fileContents===false) { - throw new \InvalidArgumentException('File in source directory could not be retrieved'); - } - + foreach (($this->PHPFilesInDirectoryGetContents)($directory) as $fileData) { // Get all possible entity classes with our annotation - $classes = $this->findClassesWithAnnotation->__invoke($fileContents); + $classes = $this->findClassesWithAnnotation->__invoke($fileData['contents']); // Go through the possible entity classes foreach ($classes as $class) { @@ -333,89 +324,32 @@ public function __invoke(): array if (isset($repositoryConfig)) { $log[] = 'Entity found: ' . $namespace . '\\' . $className; - // Replace all the variables in the repository classes blueprint - $replacementFunction = function ($repositoryPhpFile, $namespace, $className) { - $fullClassnameWithoutSeparator = \str_replace( - '\\', - '', - $namespace . $className - ); - $repositoryPhpFile = \str_replace( - '{namespaceOfEntity}', - $namespace, - $repositoryPhpFile - ); - $repositoryPhpFile = \str_replace( - '{namespaceOfBuilders}', - 'Squirrel\\Entities\\Action\\' . $fullClassnameWithoutSeparator, - $repositoryPhpFile - ); - $repositoryPhpFile = \str_replace( - '{classOfEntity}', - $className, - $repositoryPhpFile - ); - return $repositoryPhpFile; - }; - - // Compile file name and file contents for repository - $repositoryPhpFilename = $file->getPath() . '/' . - \str_replace( - '.php', - '', - $file->getFilename() - ) . 'RepositoryReadOnly.php'; - $repositoryPhpFile = $replacementFunction( - $this->repositoryPhpFileBlueprintReadOnly, + $gitignoreFilesForPaths[$fileData['path']][] = $this->generateRepositoryFile( $namespace, - $className + $className, + $fileData, + 'ReadOnly' ); - // Save repository PHP file - only if it changed or doesn't exist yet - if (!\file_exists($repositoryPhpFilename) || - \file_get_contents($repositoryPhpFilename) !== $repositoryPhpFile - ) { - \file_put_contents($repositoryPhpFilename, $repositoryPhpFile); - } - - // Add PHP file to list for which we want to create a .gitignore file - $gitignoreFilesForPaths[$file->getPath()][] = \str_replace( - '.php', - '', - $file->getFilename() - ) . 'RepositoryReadOnly.php'; - - // Compile file name and file contents for repository - $repositoryPhpFilename = $file->getPath() . '/' . - \str_replace( - '.php', - '', - $file->getFilename() - ) . 'RepositoryWriteable.php'; - $repositoryPhpFile = $replacementFunction( - $this->repositoryPhpFileBlueprintWriteable, + $gitignoreFilesForPaths[$fileData['path']][] = $this->generateRepositoryFile( $namespace, - $className + $className, + $fileData, + 'Writeable' ); - - // Save repository PHP file - only if it changed or doesn't exist yet - if (!\file_exists($repositoryPhpFilename) || - \file_get_contents($repositoryPhpFilename) !== $repositoryPhpFile - ) { - \file_put_contents($repositoryPhpFilename, $repositoryPhpFile); - } - - // Add PHP file to list for which we want to create a .gitignore file - $gitignoreFilesForPaths[$file->getPath()][] = \str_replace( - '.php', - '', - $file->getFilename() - ) . 'RepositoryWriteable.php'; } } } } + // Go through all paths where we created repository files + $this->createGitignoreFiles($gitignoreFilesForPaths); + + return $log; + } + + private function createGitignoreFiles(array $gitignoreFilesForPaths) + { // Go through all paths where we created repository files foreach ($gitignoreFilesForPaths as $path => $files) { // Make sure all files are unique / no duplicates @@ -440,7 +374,51 @@ public function __invoke(): array ); } } + } - return $log; + private function generateRepositoryFile(string $namespace, string $className, array $fileData, string $type) + { + $phpFilename = \str_replace('.php', '', $fileData['filename']) . 'Repository' . $type . '.php'; + + // Compile file name and file contents for repository + $fullPhpFilename = $fileData['path'] . '/' . $phpFilename; + $fileContents = $this->repositoryFileContentsFillInBlueprint( + $this->repositoryPhpFileBlueprint[$type], + $namespace, + $className + ); + + // Save repository PHP file - only if it changed or doesn't exist yet + if (!\file_exists($fullPhpFilename) || \file_get_contents($fullPhpFilename) !== $fileContents) { + \file_put_contents($fullPhpFilename, $fileContents); + } + + // Add PHP file to list for which we want to create a .gitignore file + return $phpFilename; + } + + private function repositoryFileContentsFillInBlueprint($repositoryPhpFile, $namespace, $className) + { + $fullClassnameWithoutSeparator = \str_replace( + '\\', + '', + $namespace . $className + ); + $repositoryPhpFile = \str_replace( + '{namespaceOfEntity}', + $namespace, + $repositoryPhpFile + ); + $repositoryPhpFile = \str_replace( + '{namespaceOfBuilders}', + 'Squirrel\\Entities\\Action\\' . $fullClassnameWithoutSeparator, + $repositoryPhpFile + ); + $repositoryPhpFile = \str_replace( + '{classOfEntity}', + $className, + $repositoryPhpFile + ); + return $repositoryPhpFile; } } diff --git a/tests/RepositoriesGenerateCommandTest.php b/tests/RepositoriesGenerateCommandTest.php new file mode 100644 index 0000000..c429850 --- /dev/null +++ b/tests/RepositoriesGenerateCommandTest.php @@ -0,0 +1,158 @@ +in(__DIR__ . '/' . 'TestEntities')->files()->sortByName()->ignoreDotFiles(false); + + $foundFiles = []; + + foreach ($sourceFinder as $file) { + $foundFiles[] = $file->getFilename(); + } + + // Make sure we have the same array contents / the same files + $this->assertEqualsCanonicalizing($validFiles, $foundFiles); + + $repositoriesGenerator = new RepositoriesGenerateCommand( + [__DIR__ . '/' . 'TestEntities'], + new PHPFilesInDirectoryGetContents + ); + + // Execute the generator + $repositoriesGenerator(); + + $validFiles = [ + '.gitignore', + 'NonRepository.php', + 'NonRepositoryWithAnnotationInUse.php', + 'User.php', + 'UserRepositoryReadOnly.php', + 'UserRepositoryWriteable.php', + 'UserAddress.php', + 'UserAddressRepositoryReadOnly.php', + 'UserAddressRepositoryWriteable.php', + ]; + + $sourceFinder = new Finder(); + $sourceFinder->in(__DIR__ . '/' . 'TestEntities')->files()->sortByName()->ignoreDotFiles(false); + + $foundFiles = []; + + foreach ($sourceFinder as $file) { + $foundFiles[] = $file->getFilename(); + } + + // Make sure we have the same array contents / the same files + $this->assertEqualsCanonicalizing($validFiles, $foundFiles); + + // Check the .gitignore file contents, that we exclude the right files in the right order + $this->assertEquals( + '.gitignore' . "\n" . + 'UserRepositoryReadOnly.php' . "\n" . 'UserRepositoryWriteable.php' . "\n" . + 'UserAddressRepositoryReadOnly.php' . "\n" . 'UserAddressRepositoryWriteable.php', + \file_get_contents(__DIR__ . '/' . 'TestEntities/' . '.gitignore') + ); + + // Include our generated classes, making sure that they are valid + require(__DIR__ . '/' . 'TestEntities/' . 'UserRepositoryReadOnly.php'); + require(__DIR__ . '/' . 'TestEntities/' . 'UserRepositoryWriteable.php'); + require(__DIR__ . '/' . 'TestEntities/' . 'UserAddressRepositoryReadOnly.php'); + require(__DIR__ . '/' . 'TestEntities/' . 'UserAddressRepositoryWriteable.php'); + + // Make sure all repository classes exist + if (!\class_exists('Squirrel\Entities\Tests\TestEntities\UserRepositoryReadOnly', false)) { + $this->assertEquals('', 'Squirrel\Entities\Tests\TestEntities\UserRepositoryReadOnly'); + } + if (!\class_exists('Squirrel\Entities\Tests\TestEntities\UserRepositoryWriteable', false)) { + $this->assertEquals('', 'Squirrel\Entities\Tests\TestEntities\UserRepositoryWriteable'); + } + if (!\class_exists('Squirrel\Entities\Tests\TestEntities\UserAddressRepositoryReadOnly', false)) { + $this->assertEquals('', 'Squirrel\Entities\Tests\TestEntities\UserAddressRepositoryReadOnly'); + } + if (!\class_exists('Squirrel\Entities\Tests\TestEntities\UserAddressRepositoryWriteable', false)) { + $this->assertEquals('', 'Squirrel\Entities\Tests\TestEntities\UserAddressRepositoryWriteable'); + } + if (!\class_exists('Squirrel\Entities\Action\SquirrelEntitiesTestsTestEntitiesUser\SelectEntries', false)) { + $this->assertEquals( + '', + 'Squirrel\Entities\Action\SquirrelEntitiesTestsTestEntitiesUser\SelectEntries' + ); + } + if (!\class_exists( + 'Squirrel\Entities\Action\SquirrelEntitiesTestsTestEntitiesUser\SelectIterator', + false + )) { + $this->assertEquals( + '', + 'Squirrel\Entities\Action\SquirrelEntitiesTestsTestEntitiesUser\SelectIterator' + ); + } + if (!\class_exists( + 'Squirrel\Entities\Action\SquirrelEntitiesTestsTestEntitiesUserAddress\SelectEntries', + false + )) { + $this->assertEquals( + '', + 'Squirrel\Entities\Action\SquirrelEntitiesTestsTestEntitiesUserAddress\SelectEntries' + ); + } + if (!\class_exists( + 'Squirrel\Entities\Action\SquirrelEntitiesTestsTestEntitiesUserAddress\SelectIterator', + false + )) { + $this->assertEquals( + '', + 'Squirrel\Entities\Action\SquirrelEntitiesTestsTestEntitiesUserAddress\SelectIterator' + ); + } + + $repositoryReadOnly = \Mockery::mock(RepositoryReadOnlyInterface::class); + + $customRepository = new \Squirrel\Entities\Tests\TestEntities\UserRepositoryReadOnly($repositoryReadOnly); + + $this->assertEquals(new CountEntries($repositoryReadOnly), $customRepository->count()); + $this->assertEquals( + new \Squirrel\Entities\Action\SquirrelEntitiesTestsTestEntitiesUser\SelectEntries($repositoryReadOnly), + $customRepository->select() + ); + + $repositoryWriteable = \Mockery::mock(RepositoryWriteableInterface::class); + + $writeableRepository = new \Squirrel\Entities\Tests\TestEntities\UserRepositoryWriteable($repositoryWriteable); + + $this->assertEquals(new CountEntries($repositoryWriteable), $writeableRepository->count()); + $this->assertEquals(new InsertEntry($repositoryWriteable), $writeableRepository->insert()); + $this->assertEquals(new InsertOrUpdateEntry($repositoryWriteable), $writeableRepository->insertOrUpdate()); + $this->assertEquals(new UpdateEntries($repositoryWriteable), $writeableRepository->update()); + $this->assertEquals(new DeleteEntries($repositoryWriteable), $writeableRepository->delete()); + + @\unlink(__DIR__ . '/' . 'TestEntities/' . '.gitignore'); + @\unlink(__DIR__ . '/' . 'TestEntities/' . 'UserRepositoryReadOnly.php'); + @\unlink(__DIR__ . '/' . 'TestEntities/' . 'UserRepositoryWriteable.php'); + @\unlink(__DIR__ . '/' . 'TestEntities/' . 'UserAddressRepositoryReadOnly.php'); + @\unlink(__DIR__ . '/' . 'TestEntities/' . 'UserAddressRepositoryWriteable.php'); + } +} diff --git a/tests/RepositoryActions/SelectEntriesTest.php b/tests/RepositoryActions/SelectEntriesTest.php index 8746cf4..7b486c3 100644 --- a/tests/RepositoryActions/SelectEntriesTest.php +++ b/tests/RepositoryActions/SelectEntriesTest.php @@ -8,17 +8,36 @@ class SelectEntriesTest extends \PHPUnit\Framework\TestCase { + /** + * @var RepositoryReadOnlyInterface + */ private $repository; + /** + * @var SelectEntries + */ + private $selectBuilder; + + /** + * @var SelectIterator + */ + private $selectIteratorClass; + protected function setUp(): void { $this->repository = \Mockery::mock(RepositoryReadOnlyInterface::class); + $this->selectBuilder = new SelectEntries($this->repository); + $this->selectIteratorClass = SelectIterator::class; } - public function testNoDataGetEntries() + private function getSelector($query) { - $selectBuilder = new SelectEntries($this->repository); + $iteratorClass = $this->selectIteratorClass; + return new $iteratorClass($this->repository, $query); + } + public function testNoDataGetEntries() + { $this->repository ->shouldReceive('fetchAll') ->once() @@ -32,16 +51,14 @@ public function testNoDataGetEntries() ]) ->andReturn([]); - $results = $selectBuilder->getAllEntries(); + $results = $this->selectBuilder->getAllEntries(); $this->assertEquals([], $results); } public function testGetEntries() { - $selectBuilder = new SelectEntries($this->repository); - - $selectBuilder + $this->selectBuilder ->where([ 'responseId' => 5, 'otherField' => '333', @@ -78,16 +95,14 @@ public function testGetEntries() ]) ->andReturn([]); - $results = $selectBuilder->getAllEntries(); + $results = $this->selectBuilder->getAllEntries(); $this->assertEquals([], $results); } public function testGetEntriesFieldAndStringOrder() { - $selectBuilder = new SelectEntries($this->repository); - - $selectBuilder + $this->selectBuilder ->where([ 'responseId' => 5, 'otherField' => '333', @@ -118,15 +133,13 @@ public function testGetEntriesFieldAndStringOrder() ]) ->andReturn([]); - $results = $selectBuilder->getAllEntries(); + $results = $this->selectBuilder->getAllEntries(); $this->assertEquals([], $results); } public function testNoDataGetOneEntry() { - $selectBuilder = new SelectEntries($this->repository); - $this->repository ->shouldReceive('fetchOne') ->once() @@ -139,16 +152,14 @@ public function testNoDataGetOneEntry() ]) ->andReturn([]); - $results = $selectBuilder->getOneEntry(); + $results = $this->selectBuilder->getOneEntry(); $this->assertEquals([], $results); } public function testGetOneEntry() { - $selectBuilder = new SelectEntries($this->repository); - - $selectBuilder + $this->selectBuilder ->where([ 'responseId' => 5, 'otherField' => '333', @@ -183,15 +194,13 @@ public function testGetOneEntry() ]) ->andReturn([]); - $results = $selectBuilder->getOneEntry(); + $results = $this->selectBuilder->getOneEntry(); $this->assertEquals([], $results); } public function testNoDataGetFlattenedFields() { - $selectBuilder = new SelectEntries($this->repository); - $this->repository ->shouldReceive('fetchAll') ->once() @@ -206,16 +215,14 @@ public function testNoDataGetFlattenedFields() ]) ->andReturn([]); - $results = $selectBuilder->getFlattenedFields(); + $results = $this->selectBuilder->getFlattenedFields(); $this->assertEquals([], $results); } public function testIterator() { - $selectBuilder = new SelectEntries($this->repository); - - $expectedResult = new SelectIterator($this->repository, [ + $expectedResult = $this->getSelector([ 'where' => [ 'responseId' => 5, 'otherField' => '333', @@ -232,7 +239,7 @@ public function testIterator() 'lock' => true, ]); - $results = $selectBuilder + $results = $this->selectBuilder ->where([ 'responseId' => 5, 'otherField' => '333', @@ -254,9 +261,7 @@ public function testIterator() public function testGetFlattenedFields() { - $selectBuilder = new SelectEntries($this->repository); - - $selectBuilder + $this->selectBuilder ->where([ 'responseId' => 5, 'otherField' => '333', @@ -294,7 +299,7 @@ public function testGetFlattenedFields() ]) ->andReturn([]); - $results = $selectBuilder->getFlattenedFields(); + $results = $this->selectBuilder->getFlattenedFields(); $this->assertEquals([], $results); } diff --git a/tests/TestEntities/NonRepository.php b/tests/TestEntities/NonRepository.php new file mode 100644 index 0000000..79f37de --- /dev/null +++ b/tests/TestEntities/NonRepository.php @@ -0,0 +1,19 @@ +userId; + } +} diff --git a/tests/TestEntities/NonRepositoryWithAnnotationInUse.php b/tests/TestEntities/NonRepositoryWithAnnotationInUse.php new file mode 100644 index 0000000..857adab --- /dev/null +++ b/tests/TestEntities/NonRepositoryWithAnnotationInUse.php @@ -0,0 +1,21 @@ +userId; + } +} diff --git a/tests/TestEntities/User.php b/tests/TestEntities/User.php new file mode 100644 index 0000000..3727a89 --- /dev/null +++ b/tests/TestEntities/User.php @@ -0,0 +1,158 @@ + $value) { + $this->$key = $value; + } + } + + /** + * @return int + */ + public function getUserId(): int + { + return $this->userId; + } + + /** + * @return bool + */ + public function isActive(): bool + { + return $this->active; + } + + /** + * @return string + */ + public function getUserName(): string + { + return $this->userName; + } + + /** + * @return string + */ + public function getLoginNameMD5(): string + { + return $this->loginNameMD5; + } + + /** + * @return string + */ + public function getLoginPassword(): string + { + return $this->loginPassword; + } + + /** + * @return string + */ + public function getEmailAddress(): string + { + return $this->emailAddress; + } + + /** + * @return float + */ + public function getBalance(): float + { + return $this->balance; + } + + /** + * @return int|null + */ + public function getLocationId(): ?int + { + return $this->locationId; + } + + /** + * @return int + */ + public function getCreateDate(): int + { + return $this->createDate; + } +} diff --git a/tests/TestEntities/UserAddress.php b/tests/TestEntities/UserAddress.php new file mode 100644 index 0000000..56eb41a --- /dev/null +++ b/tests/TestEntities/UserAddress.php @@ -0,0 +1,99 @@ + $value) { + $this->$key = $value; + } + } + + /** + * @return int + */ + public function getUserId(): int + { + return $this->userId; + } + + /** + * @return bool + */ + public function isAtHome(): bool + { + return $this->atHome; + } + + /** + * @return string + */ + public function getStreetName(): string + { + return $this->streetName; + } + + /** + * @return string + */ + public function getStreetNumber(): string + { + return $this->streetNumber; + } + + /** + * @return string + */ + public function getCity(): string + { + return $this->city; + } +} diff --git a/tests/autoload.php b/tests/autoload.php new file mode 100644 index 0000000..c81f281 --- /dev/null +++ b/tests/autoload.php @@ -0,0 +1,23 @@ +