From 85ca69156d9e6bb7ee73f2b7285589d4a98ace15 Mon Sep 17 00:00:00 2001 From: "roman.dykyi" Date: Thu, 13 May 2021 10:09:05 +0300 Subject: [PATCH] add criteria object --- README.md | 2 +- .../Application/Service/CrosswordReceiver.php | 4 +-- .../Domain/Criteria/WordSearchCriteria.php | 27 +++++++++++++++ .../Domain/Port/DictionaryInterface.php | 3 +- .../Constructor/Normal/AttemptWordFinder.php | 3 +- .../Crossword/Domain/Service/WordFinder.php | 5 +-- .../Dictionary/ApiDictionaryAdapter.php | 11 ++++-- .../Dictionary/DirectDictionaryAdapter.php | 10 ++++-- .../Dictionary/InMemoryDictionaryAdapter.php | 3 +- code/src/Crossword/UI/API/ConstructAction.php | 5 +-- .../src/Game/Application/Service/GamePlay.php | 3 +- .../Domain/Criteria/CrosswordCriteria.php | 34 +++++++++++++++++++ .../Game/Domain/Port/CrosswordInterface.php | 3 +- .../Domain/Service/CrosswordConstructor.php | 5 +-- .../Adapter/Crossword/ApiCrosswordAdapter.php | 12 +++++-- .../Crossword/DirectCrosswordAdapter.php | 6 ++-- .../Crossword/InMemoryCrosswordAdapter.php | 3 +- .../Service/CrosswordReceiverTest.php | 4 +-- .../Domain/Service/WordFinderTest.php | 13 +++---- 19 files changed, 124 insertions(+), 32 deletions(-) create mode 100644 code/src/Crossword/Domain/Criteria/WordSearchCriteria.php create mode 100644 code/src/Game/Domain/Criteria/CrosswordCriteria.php diff --git a/README.md b/README.md index fb526a3..f0925e7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ Crossword game ======= -![Build Status](https://travis-ci.com/dykyi-roman/crossword.svg?branch=master) +[![Build Status](https://scrutinizer-ci.com/g/dykyi-roman/crossword/badges/build.png?b=master)](https://scrutinizer-ci.com/g/dykyi-roman/crossword/build-status/master) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/dykyi-roman/crossword/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/dykyi-roman/crossword/?branch=master) [![Code Intelligence Status](https://scrutinizer-ci.com/g/dykyi-roman/crossword/badges/code-intelligence.svg?b=master)](https://scrutinizer-ci.com/code-intelligence) [![Code Coverage](https://scrutinizer-ci.com/g/dykyi-roman/crossword/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/dykyi-roman/crossword/?branch=master) diff --git a/code/src/Crossword/Application/Service/CrosswordReceiver.php b/code/src/Crossword/Application/Service/CrosswordReceiver.php index 08b3786..048dc58 100644 --- a/code/src/Crossword/Application/Service/CrosswordReceiver.php +++ b/code/src/Crossword/Application/Service/CrosswordReceiver.php @@ -23,11 +23,9 @@ public function __construct(ReadCrosswordRepositoryInterface $readCrosswordRepos /** * @throws ReceiveCrosswordException */ - public function receive(string $type, string $language, int $wordCount): array + public function receive(string $key): array { try { - $key = sprintf('%s-%s-%d', $language, $type, $wordCount); - return $this->readCrosswordRepository->get($key); } catch (Throwable $exception) { $this->logger->error($exception->getMessage()); diff --git a/code/src/Crossword/Domain/Criteria/WordSearchCriteria.php b/code/src/Crossword/Domain/Criteria/WordSearchCriteria.php new file mode 100644 index 0000000..acf714a --- /dev/null +++ b/code/src/Crossword/Domain/Criteria/WordSearchCriteria.php @@ -0,0 +1,27 @@ +language = $language; + $this->mask = $mask; + } + + public function mask(): string + { + return $this->mask; + } + + public function language(): string + { + return $this->language; + } +} diff --git a/code/src/Crossword/Domain/Port/DictionaryInterface.php b/code/src/Crossword/Domain/Port/DictionaryInterface.php index 1d9a0ea..04f5af0 100644 --- a/code/src/Crossword/Domain/Port/DictionaryInterface.php +++ b/code/src/Crossword/Domain/Port/DictionaryInterface.php @@ -4,6 +4,7 @@ namespace App\Crossword\Domain\Port; +use App\Crossword\Domain\Criteria\WordSearchCriteria; use App\Crossword\Domain\Dto\DictionaryLanguagesDto; use App\Crossword\Domain\Dto\DictionaryWordDto; use App\Crossword\Domain\Exception\ApiClientException; @@ -18,5 +19,5 @@ public function supportedLanguages(): DictionaryLanguagesDto; /** * @throws ApiClientException */ - public function searchWord(string $language, string $mask): DictionaryWordDto; + public function searchWord(WordSearchCriteria $criteria): DictionaryWordDto; } diff --git a/code/src/Crossword/Domain/Service/Constructor/Normal/AttemptWordFinder.php b/code/src/Crossword/Domain/Service/Constructor/Normal/AttemptWordFinder.php index 19adb39..cf78e34 100644 --- a/code/src/Crossword/Domain/Service/Constructor/Normal/AttemptWordFinder.php +++ b/code/src/Crossword/Domain/Service/Constructor/Normal/AttemptWordFinder.php @@ -4,6 +4,7 @@ namespace App\Crossword\Domain\Service\Constructor\Normal; +use App\Crossword\Domain\Criteria\WordSearchCriteria; use App\Crossword\Domain\Exception\WordFoundException; use App\Crossword\Domain\Service\WordFinder; use App\SharedKernel\Domain\Model\Mask; @@ -30,7 +31,7 @@ public function find(string $language, Mask $mask, int $attempt = self::ATTEMPT) do { try { - return $this->wordFinder->find($language, (string) $template); + return $this->wordFinder->search(new WordSearchCriteria($language, (string) $template)); } catch (WordFoundException) { $counter++; $template = $template->shiftLeft(); diff --git a/code/src/Crossword/Domain/Service/WordFinder.php b/code/src/Crossword/Domain/Service/WordFinder.php index bd8f97a..6a9eef5 100644 --- a/code/src/Crossword/Domain/Service/WordFinder.php +++ b/code/src/Crossword/Domain/Service/WordFinder.php @@ -4,6 +4,7 @@ namespace App\Crossword\Domain\Service; +use App\Crossword\Domain\Criteria\WordSearchCriteria; use App\Crossword\Domain\Exception\ApiClientException; use App\Crossword\Domain\Exception\WordFoundException; use App\Crossword\Domain\Port\DictionaryInterface; @@ -21,10 +22,10 @@ public function __construct(DictionaryInterface $dictionary, LoggerInterface $lo $this->dictionary = $dictionary; } - public function find(string $language, string $mask): Word + public function search(WordSearchCriteria $criteria): Word { try { - $searchWordDto = $this->dictionary->searchWord($language, $mask); + $searchWordDto = $this->dictionary->searchWord($criteria); if ($searchWordDto->count()) { return new Word($searchWordDto->word(), $searchWordDto->definition()); } diff --git a/code/src/Crossword/Infrastructure/Adapter/Dictionary/ApiDictionaryAdapter.php b/code/src/Crossword/Infrastructure/Adapter/Dictionary/ApiDictionaryAdapter.php index ed4205e..c2e28b5 100644 --- a/code/src/Crossword/Infrastructure/Adapter/Dictionary/ApiDictionaryAdapter.php +++ b/code/src/Crossword/Infrastructure/Adapter/Dictionary/ApiDictionaryAdapter.php @@ -4,6 +4,7 @@ namespace App\Crossword\Infrastructure\Adapter\Dictionary; +use App\Crossword\Domain\Criteria\WordSearchCriteria; use App\Crossword\Domain\Dto\DictionaryLanguagesDto; use App\Crossword\Domain\Dto\DictionaryWordDto; use App\Crossword\Domain\Exception\ApiClientException; @@ -41,9 +42,15 @@ public function supportedLanguages(): DictionaryLanguagesDto } } - public function searchWord(string $language, string $mask): DictionaryWordDto + public function searchWord(WordSearchCriteria $criteria): DictionaryWordDto { - $uri = sprintf('%s/words/%s/?mask=%s', $this->dictionaryApiHost, $language, $mask); + $uri = sprintf( + '%s/words/%s/?mask=%s', + $this->dictionaryApiHost, + $criteria->language(), + $criteria->mask() + ); + try { $response = $this->client->sendRequest(new Request('GET', $uri)); diff --git a/code/src/Crossword/Infrastructure/Adapter/Dictionary/DirectDictionaryAdapter.php b/code/src/Crossword/Infrastructure/Adapter/Dictionary/DirectDictionaryAdapter.php index 4f1a0f2..e4db0a9 100644 --- a/code/src/Crossword/Infrastructure/Adapter/Dictionary/DirectDictionaryAdapter.php +++ b/code/src/Crossword/Infrastructure/Adapter/Dictionary/DirectDictionaryAdapter.php @@ -4,6 +4,7 @@ namespace App\Crossword\Infrastructure\Adapter\Dictionary; +use App\Crossword\Domain\Criteria\WordSearchCriteria; use App\Crossword\Domain\Dto\DictionaryLanguagesDto; use App\Crossword\Domain\Dto\DictionaryWordDto; use App\Crossword\Domain\Port\DictionaryInterface; @@ -32,9 +33,14 @@ public function supportedLanguages(): DictionaryLanguagesDto return new DictionaryLanguagesDto($data->body()); } - public function searchWord(string $language, string $mask): DictionaryWordDto + public function searchWord(WordSearchCriteria $criteria): DictionaryWordDto { - $words = $this->wordsFinder->find($language, new Mask($mask), self::LIMIT); + $words = $this->wordsFinder->find( + $criteria->language(), + new Mask($criteria->mask()), + self::LIMIT + ); + $data = new SuccessApiResponse($words->jsonSerialize()); return new DictionaryWordDto($data->body()); diff --git a/code/src/Crossword/Infrastructure/Adapter/Dictionary/InMemoryDictionaryAdapter.php b/code/src/Crossword/Infrastructure/Adapter/Dictionary/InMemoryDictionaryAdapter.php index f3c912b..50d7fc6 100644 --- a/code/src/Crossword/Infrastructure/Adapter/Dictionary/InMemoryDictionaryAdapter.php +++ b/code/src/Crossword/Infrastructure/Adapter/Dictionary/InMemoryDictionaryAdapter.php @@ -4,6 +4,7 @@ namespace App\Crossword\Infrastructure\Adapter\Dictionary; +use App\Crossword\Domain\Criteria\WordSearchCriteria; use App\Crossword\Domain\Dto\DictionaryLanguagesDto; use App\Crossword\Domain\Dto\DictionaryWordDto; use App\Crossword\Domain\Exception\ApiClientException; @@ -29,7 +30,7 @@ public function supportedLanguages(): DictionaryLanguagesDto return $this->languagesDto; } - public function searchWord(string $language, string $mask): DictionaryWordDto + public function searchWord(WordSearchCriteria $criteria): DictionaryWordDto { if (null === $this->wordDto) { throw ApiClientException::badRequest('test error message'); diff --git a/code/src/Crossword/UI/API/ConstructAction.php b/code/src/Crossword/UI/API/ConstructAction.php index 55348e2..eae0865 100644 --- a/code/src/Crossword/UI/API/ConstructAction.php +++ b/code/src/Crossword/UI/API/ConstructAction.php @@ -53,10 +53,11 @@ final class ConstructAction * ) */ #[Route('/api/crossword/construct/{language}/{type}/{words}', name: 'crossword.api.construct', methods: ['GET'])] - public function __invoke(ConstructRequest $request, CrosswordReceiver $constructor): ResponseInterface + public function __invoke(ConstructRequest $request, CrosswordReceiver $crosswordReceiver): ResponseInterface { try { - $crossword = $constructor->receive($request->type(), $request->language(), $request->wordCount()); + $key = sprintf('%s-%s-%d', $request->language(), $request->type(), $request->wordCount()); + $crossword = $crosswordReceiver->receive($key); return new SuccessApiResponse($crossword); } catch (ReceiveCrosswordException) { diff --git a/code/src/Game/Application/Service/GamePlay.php b/code/src/Game/Application/Service/GamePlay.php index 7fdc879..1490e7f 100644 --- a/code/src/Game/Application/Service/GamePlay.php +++ b/code/src/Game/Application/Service/GamePlay.php @@ -5,6 +5,7 @@ namespace App\Game\Application\Service; use App\Game\Application\Dto\GameDto; +use App\Game\Domain\Criteria\CrosswordCriteria; use App\Game\Domain\Model\Grid; use App\Game\Domain\Service\CrosswordConstructor; @@ -19,7 +20,7 @@ public function __construct(CrosswordConstructor $constructor) public function new(string $language, string $type, int $wordCount): GameDto { - $crossword = $this->constructor->construct($language, $type, $wordCount); + $crossword = $this->constructor->construct(new CrosswordCriteria($language, $type, $wordCount)); $grid = new Grid($crossword); $definitions = array_map(static fn (array $item) => $item['word']['definition'], $crossword); foreach ($crossword as $index => $line) { diff --git a/code/src/Game/Domain/Criteria/CrosswordCriteria.php b/code/src/Game/Domain/Criteria/CrosswordCriteria.php new file mode 100644 index 0000000..818bc1e --- /dev/null +++ b/code/src/Game/Domain/Criteria/CrosswordCriteria.php @@ -0,0 +1,34 @@ +type = $type; + $this->language = $language; + $this->wordCount = $wordCount; + } + + public function language(): string + { + return $this->language; + } + + public function type(): string + { + return $this->type; + } + + public function wordCount(): int + { + return $this->wordCount; + } +} diff --git a/code/src/Game/Domain/Port/CrosswordInterface.php b/code/src/Game/Domain/Port/CrosswordInterface.php index dba4f9f..07865a6 100644 --- a/code/src/Game/Domain/Port/CrosswordInterface.php +++ b/code/src/Game/Domain/Port/CrosswordInterface.php @@ -4,6 +4,7 @@ namespace App\Game\Domain\Port; +use App\Game\Domain\Criteria\CrosswordCriteria; use App\Game\Domain\Dto\CrosswordDto; use App\Game\Domain\Dto\LanguagesDto; use App\Game\Domain\Exception\ApiClientException; @@ -13,7 +14,7 @@ interface CrosswordInterface /** * @throws ApiClientException */ - public function construct(string $language, string $type, int $wordCount): CrosswordDto; + public function construct(CrosswordCriteria $criteria): CrosswordDto; /** * @throws ApiClientException diff --git a/code/src/Game/Domain/Service/CrosswordConstructor.php b/code/src/Game/Domain/Service/CrosswordConstructor.php index 79a4af2..b13932a 100644 --- a/code/src/Game/Domain/Service/CrosswordConstructor.php +++ b/code/src/Game/Domain/Service/CrosswordConstructor.php @@ -4,6 +4,7 @@ namespace App\Game\Domain\Service; +use App\Game\Domain\Criteria\CrosswordCriteria; use App\Game\Domain\Exception\ApiClientException; use App\Game\Domain\Exception\CrosswordNotConstructedException; use App\Game\Domain\Port\CrosswordInterface; @@ -23,10 +24,10 @@ public function __construct(CrosswordInterface $crossword, LoggerInterface $logg /** * @throws CrosswordNotConstructedException */ - public function construct(string $language, string $type, int $wordCount): array + public function construct(CrosswordCriteria $criteria): array { try { - $crosswordDto = $this->crossword->construct($language, $type, $wordCount); + $crosswordDto = $this->crossword->construct($criteria); return $crosswordDto->count() ? $crosswordDto->crossword() : []; } catch (ApiClientException $exception) { diff --git a/code/src/Game/Infrastructure/Adapter/Crossword/ApiCrosswordAdapter.php b/code/src/Game/Infrastructure/Adapter/Crossword/ApiCrosswordAdapter.php index ee91388..bfdf181 100644 --- a/code/src/Game/Infrastructure/Adapter/Crossword/ApiCrosswordAdapter.php +++ b/code/src/Game/Infrastructure/Adapter/Crossword/ApiCrosswordAdapter.php @@ -4,6 +4,7 @@ namespace App\Game\Infrastructure\Adapter\Crossword; +use App\Game\Domain\Criteria\CrosswordCriteria; use App\Game\Domain\Dto\CrosswordDto; use App\Game\Domain\Dto\LanguagesDto; use App\Game\Domain\Exception\ApiClientException; @@ -29,9 +30,16 @@ public function __construct( $this->responseDataExtractor = $responseDataExtractor; } - public function construct(string $language, string $type, int $wordCount): CrosswordDto + public function construct(CrosswordCriteria $criteria): CrosswordDto { - $uri = sprintf('%s/construct/%s/%s/%d', $this->crosswordApiHost, $language, $type, $wordCount); + $uri = sprintf( + '%s/construct/%s/%s/%d', + $this->crosswordApiHost, + $criteria->language(), + $criteria->type(), + $criteria->wordCount() + ); + try { $response = $this->client->sendRequest(new Request('GET', $uri)); diff --git a/code/src/Game/Infrastructure/Adapter/Crossword/DirectCrosswordAdapter.php b/code/src/Game/Infrastructure/Adapter/Crossword/DirectCrosswordAdapter.php index a15af49..65b84fc 100644 --- a/code/src/Game/Infrastructure/Adapter/Crossword/DirectCrosswordAdapter.php +++ b/code/src/Game/Infrastructure/Adapter/Crossword/DirectCrosswordAdapter.php @@ -6,6 +6,7 @@ use App\Crossword\Application\Service\CrosswordReceiver; use App\Crossword\Application\Service\SupportedLanguages; +use App\Game\Domain\Criteria\CrosswordCriteria; use App\Game\Domain\Dto\CrosswordDto; use App\Game\Domain\Dto\LanguagesDto; use App\Game\Domain\Port\CrosswordInterface; @@ -22,9 +23,10 @@ public function __construct(CrosswordReceiver $crosswordReceiver, SupportedLangu $this->supportedLanguages = $supportedLanguages; } - public function construct(string $language, string $type, int $wordCount): CrosswordDto + public function construct(CrosswordCriteria $criteria): CrosswordDto { - $data = $this->crosswordReceiver->receive($type, $language, $wordCount); + $key = sprintf('%s-%s-%d', $criteria->language(), $criteria->type(), $criteria->wordCount()); + $data = $this->crosswordReceiver->receive($key); $response = new SuccessApiResponse($data); return new CrosswordDto($response->body()); diff --git a/code/src/Game/Infrastructure/Adapter/Crossword/InMemoryCrosswordAdapter.php b/code/src/Game/Infrastructure/Adapter/Crossword/InMemoryCrosswordAdapter.php index 9195ee0..4427a07 100644 --- a/code/src/Game/Infrastructure/Adapter/Crossword/InMemoryCrosswordAdapter.php +++ b/code/src/Game/Infrastructure/Adapter/Crossword/InMemoryCrosswordAdapter.php @@ -4,6 +4,7 @@ namespace App\Game\Infrastructure\Adapter\Crossword; +use App\Game\Domain\Criteria\CrosswordCriteria; use App\Game\Domain\Dto\CrosswordDto; use App\Game\Domain\Dto\LanguagesDto; use App\Game\Domain\Exception\ApiClientException; @@ -20,7 +21,7 @@ public function __construct(null | CrosswordDto $crosswordDto, null | LanguagesD $this->languagesDto = $languagesDto; } - public function construct(string $language, string $type, int $wordCount): CrosswordDto + public function construct(CrosswordCriteria $criteria): CrosswordDto { if (null === $this->crosswordDto) { throw ApiClientException::badRequest('test error message'); diff --git a/code/tests/Crossword/Application/Service/CrosswordReceiverTest.php b/code/tests/Crossword/Application/Service/CrosswordReceiverTest.php index 9c99a37..0c4901d 100644 --- a/code/tests/Crossword/Application/Service/CrosswordReceiverTest.php +++ b/code/tests/Crossword/Application/Service/CrosswordReceiverTest.php @@ -28,7 +28,7 @@ public function testSuccessfullyReceived(): void $cache->save(new CacheItem('ua-normal-3', [time() => json_encode(['data' => 'value'], JSON_THROW_ON_ERROR)])); $crosswordReceiver = new CrosswordReceiver(new ReadCrosswordRepository($cache), new NullLogger()); - $crossword = $crosswordReceiver->receive(Type::NORMAL, 'ua', 3); + $crossword = $crosswordReceiver->receive(sprintf('%s-%s-%d', 'ua', Type::NORMAL, 3)); self::assertSame($crossword, $data); } @@ -41,6 +41,6 @@ public function testThrowExceptionWhenCrosswordNotFoundInTheStorage(): void $this->expectException(ReceiveCrosswordException::class); $crosswordReceiver = new CrosswordReceiver(new ReadCrosswordRepository(new InMemoryClient()), new NullLogger()); - $crosswordReceiver->receive(Type::NORMAL, 'ua', 3); + $crosswordReceiver->receive(sprintf('%s-%s-%d', 'ua', Type::NORMAL, 3)); } } diff --git a/code/tests/Crossword/Domain/Service/WordFinderTest.php b/code/tests/Crossword/Domain/Service/WordFinderTest.php index bc6e56a..8a3b42c 100644 --- a/code/tests/Crossword/Domain/Service/WordFinderTest.php +++ b/code/tests/Crossword/Domain/Service/WordFinderTest.php @@ -5,6 +5,7 @@ namespace App\Tests\Crossword\Domain\Service; use App\Crossword\Application\Service\ErrorFactory; +use App\Crossword\Domain\Criteria\WordSearchCriteria; use App\Crossword\Domain\Dto\DictionaryWordDto; use App\Crossword\Domain\Exception\WordFoundException; use App\Crossword\Domain\Service\WordFinder; @@ -21,7 +22,7 @@ final class WordFinderTest extends CrosswordTestCase { /** - * @covers ::find + * @covers ::search */ public function testSuccessfullyFindWord(): void { @@ -30,7 +31,7 @@ public function testSuccessfullyFindWord(): void $inMemoryDictionaryProvider = new InMemoryDictionaryAdapter(null, $dictionaryWordDto); $wordFinder = new WordFinder($inMemoryDictionaryProvider, new NullLogger()); - $word = $wordFinder->find('en', '.*'); + $word = $wordFinder->search(new WordSearchCriteria('en', '.*')); self::assertInstanceOf(Word::class, $word); self::assertSame($word->value(), 'test'); @@ -38,7 +39,7 @@ public function testSuccessfullyFindWord(): void } /** - * @covers ::find + * @covers ::search */ public function testThrowExceptionWhenWordIsNotFound(): void { @@ -49,11 +50,11 @@ public function testThrowExceptionWhenWordIsNotFound(): void $inMemoryDictionaryProvider = new InMemoryDictionaryAdapter(null, $dictionaryWordDto); $wordFinder = new WordFinder($inMemoryDictionaryProvider, new NullLogger()); - $wordFinder->find('en', '.*'); + $wordFinder->search(new WordSearchCriteria('en', '.*')); } /** - * @covers ::find + * @covers ::search */ public function testThrowExceptionWhenApiIsThrowException(): void { @@ -62,6 +63,6 @@ public function testThrowExceptionWhenApiIsThrowException(): void $inMemoryDictionaryProvider = new InMemoryDictionaryAdapter(null, null); $wordFinder = new WordFinder($inMemoryDictionaryProvider, new NullLogger()); - $wordFinder->find('en', '.*'); + $wordFinder->search(new WordSearchCriteria('en', '.*')); } }