diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 35acac9..c9157a8 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -11,14 +11,10 @@ jobs: strategy: matrix: php-version: - - "7.4" - - "8.0" - - "8.1" + - "8.2" deps: - "normal" - include: - - deps: "low" - php-version: "7.4" + - "low" steps: - name: "Checkout" diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 8b0c53e..b6bcaf6 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -11,9 +11,7 @@ jobs: strategy: matrix: php-version: - - "7.4" - - "8.0" - - "8.1" + - "8.2" steps: - name: "Checkout" diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index f3f328d..781a55e 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -21,7 +21,7 @@ 'strict_param' => false, 'array_syntax' => ['syntax' => 'short'], 'concat_space' => ['spacing' => 'one'], - 'phpdoc_align' => [], + 'phpdoc_align' => ['align' => 'left'], 'phpdoc_summary' => false, 'void_return' => false, 'phpdoc_var_without_name' => false, diff --git a/README.md b/README.md index 76b7d19..09bb1b9 100644 --- a/README.md +++ b/README.md @@ -164,20 +164,20 @@ use Answear\LuigisBoxBundle\Exception\ServiceUnavailableException; try { // ... request -} catch (BadRequestException $e){ +} catch (BadRequestException $exception){ //bad request - $request = $e->getRequest(); - $response = $e->getResponse(); -} catch (TooManyItemsException $e){ + $request = $exception->request; + $response = $exception->response; +} catch (TooManyItemsException $exception){ //items limit reached - $limit = $e->getLimit(); -} catch (MalformedResponseException $e){ + $limit = $exception->limit; +} catch (MalformedResponseException $exception){ //bad response - $response = $e->getResponse(); -} catch (TooManyRequestsException $e){ + $response = $exception->response; +} catch (TooManyRequestsException $exception){ //repeat request after $retryAfter seconds - $retryAfter = $e->getRetryAfterSeconds(); -} catch (ServiceUnavailableException $e){ + $retryAfter = $exception->retryAfterSeconds; +} catch (ServiceUnavailableException $exception){ //delay request } ``` diff --git a/composer.json b/composer.json index 5a3b8b0..553cb88 100644 --- a/composer.json +++ b/composer.json @@ -4,25 +4,24 @@ "type": "symfony-bundle", "license": "MIT", "require": { - "php": ">=7.4|^8.0", + "php": "^8.2", "ext-json": "*", - "marc-mabe/php-enum": "^3.0|^4.3", - "webmozart/assert": "^1.3", - "symfony/validator": "^5.4|^6.0", - "symfony/http-kernel": "^5.4|^6.0", - "guzzlehttp/guzzle": "^6.0 || ^7.0", - "symfony/serializer": "^5.4|^6.0", - "symfony/property-access": "^5.4|^6.0" + "webmozart/assert": "^1.11", + "symfony/validator": "^6.0|^7.0", + "symfony/http-kernel": "^6.0|^7.0", + "guzzlehttp/guzzle": "^6.0|^7.0", + "symfony/serializer": "^6.0|^7.0", + "symfony/property-access": "^6.0|^7.0" }, "require-dev": { "roave/security-advisories": "dev-master", - "phpunit/phpunit": "^9.5.23", - "symfony/phpunit-bridge": "6.1.*", - "phpro/grumphp": "1.13.x", - "friendsofphp/php-cs-fixer": "^3.9.5", - "phpstan/phpstan": "^1.10.34", - "phpstan/phpstan-webmozart-assert": "^1.2.4", - "matthiasnoback/symfony-config-test": "^4.3" + "phpunit/phpunit": "^10.5", + "symfony/phpunit-bridge": "^6.1|^7.0", + "phpro/grumphp": "^2.8", + "friendsofphp/php-cs-fixer": "^3.64", + "phpstan/phpstan": "^1.12", + "phpstan/phpstan-webmozart-assert": "^1.2", + "matthiasnoback/symfony-config-test": "^5.2" }, "autoload": { "psr-4": { diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 94509aa..4e1df7d 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,29 +1,20 @@ - ./tests - - - - diff --git a/src/LuigisBoxBundle/DTO/ConfigDTO.php b/src/LuigisBoxBundle/DTO/ConfigDTO.php index f7608dd..dd59918 100644 --- a/src/LuigisBoxBundle/DTO/ConfigDTO.php +++ b/src/LuigisBoxBundle/DTO/ConfigDTO.php @@ -5,100 +5,24 @@ namespace Answear\LuigisBoxBundle\DTO; use Answear\LuigisBoxBundle\DependencyInjection\Configuration; +use Webmozart\Assert\Assert; -class ConfigDTO +readonly class ConfigDTO { private const MAX_SEARCH_CACHE_TTL = 300; - /** - * @var string - */ - private $host; - - /** - * @var string - */ - private $publicKey; - - /** - * @var string - */ - private $privateKey; - - /** - * @var float - */ - private $connectionTimeout; - - /** - * @var float - */ - private $requestTimeout; - - /** - * @var float - */ - private $searchTimeout; - - /** - * @var int - */ - private $searchCacheTtl; + public int $searchCacheTtl; public function __construct( - string $publicKey, - string $privateKey, - string $host = Configuration::HOST, - float $connectionTimeout = Configuration::CONNECTION_TIMEOUT, - float $requestTimeout = Configuration::REQUEST_TIMEOUT, - float $searchTimeout = Configuration::SEARCH_TIMEOUT, - int $searchCacheTtl = Configuration::SEARCH_CACHE_TIMEOUT + public string $publicKey, + public string $privateKey, + public string $host = Configuration::HOST, + public float $connectionTimeout = Configuration::CONNECTION_TIMEOUT, + public float $requestTimeout = Configuration::REQUEST_TIMEOUT, + public float $searchTimeout = Configuration::SEARCH_TIMEOUT, + int $searchCacheTtl = Configuration::SEARCH_CACHE_TIMEOUT, ) { - if ($searchCacheTtl < 0) { - throw new \InvalidArgumentException('searchCacheTtl cannot be negative.'); - } - - $this->host = $host; - $this->publicKey = $publicKey; - $this->privateKey = $privateKey; - $this->connectionTimeout = $connectionTimeout; - $this->requestTimeout = $requestTimeout; - $this->searchTimeout = $searchTimeout; + Assert::greaterThanEq($searchCacheTtl, 0, 'searchCacheTtl cannot be negative.'); $this->searchCacheTtl = min($searchCacheTtl, self::MAX_SEARCH_CACHE_TTL); } - - public function getHost(): string - { - return $this->host; - } - - public function getPublicKey(): string - { - return $this->publicKey; - } - - public function getPrivateKey(): string - { - return $this->privateKey; - } - - public function getConnectionTimeout(): float - { - return $this->connectionTimeout; - } - - public function getRequestTimeout(): float - { - return $this->requestTimeout; - } - - public function getSearchTimeout(): float - { - return $this->searchTimeout; - } - - public function getSearchCacheTtl(): int - { - return $this->searchCacheTtl; - } } diff --git a/src/LuigisBoxBundle/Exception/ApiErrorException.php b/src/LuigisBoxBundle/Exception/ApiErrorException.php index 44fd6df..76cd90e 100644 --- a/src/LuigisBoxBundle/Exception/ApiErrorException.php +++ b/src/LuigisBoxBundle/Exception/ApiErrorException.php @@ -8,20 +8,10 @@ class ApiErrorException extends \RuntimeException { - /** - * @var Request - */ - private $request; - - public function __construct(string $message, Request $request) + public function __construct( + string $message, + public readonly Request $request) { parent::__construct($message); - - $this->request = $request; - } - - public function getRequest(): Request - { - return $this->request; } } diff --git a/src/LuigisBoxBundle/Exception/BadRequestException.php b/src/LuigisBoxBundle/Exception/BadRequestException.php index fccee48..30adf0b 100644 --- a/src/LuigisBoxBundle/Exception/BadRequestException.php +++ b/src/LuigisBoxBundle/Exception/BadRequestException.php @@ -9,31 +9,10 @@ class BadRequestException extends \RuntimeException { - /** - * @var ResponseInterface - */ - private $response; - - /** - * @var Request - */ - private $request; - - public function __construct(ResponseInterface $response, Request $request) - { + public function __construct( + public readonly ResponseInterface $response, + public readonly Request $request, + ) { parent::__construct('Bad request.'); - - $this->response = $response; - $this->request = $request; - } - - public function getResponse(): ResponseInterface - { - return $this->response; - } - - public function getRequest(): Request - { - return $this->request; } } diff --git a/src/LuigisBoxBundle/Exception/MalformedResponseException.php b/src/LuigisBoxBundle/Exception/MalformedResponseException.php index 53f10f4..e791b59 100644 --- a/src/LuigisBoxBundle/Exception/MalformedResponseException.php +++ b/src/LuigisBoxBundle/Exception/MalformedResponseException.php @@ -9,31 +9,12 @@ class MalformedResponseException extends \RuntimeException { - /** - * @var ResponseInterface - */ - private $response; - - /** - * @var Request - */ - private $request; - - public function __construct(string $message, ResponseInterface $response, Request $request, ?\Throwable $previous = null) + public function __construct( + string $message, + public readonly ResponseInterface $response, + public readonly Request $request, + ?\Throwable $previous = null) { parent::__construct($message, 0, $previous); - - $this->response = $response; - $this->request = $request; - } - - public function getResponse(): ResponseInterface - { - return $this->response; - } - - public function getRequest(): Request - { - return $this->request; } } diff --git a/src/LuigisBoxBundle/Exception/TooManyItemsException.php b/src/LuigisBoxBundle/Exception/TooManyItemsException.php index fd8e4d4..861fd6d 100644 --- a/src/LuigisBoxBundle/Exception/TooManyItemsException.php +++ b/src/LuigisBoxBundle/Exception/TooManyItemsException.php @@ -8,51 +8,17 @@ class TooManyItemsException extends \RuntimeException { - /** - * @var int|null - */ - private $passedObjectsCount; + public function __construct( + public readonly ?int $passedObjectsCount, + public readonly ?int $limit, + public readonly ?ResponseInterface $response = null, + ) { + $message = sprintf('Expect less than or equal %s items. Got %s.', $limit, $passedObjectsCount); - /** - * @var int|null - */ - private $limit; - - /** - * @var ResponseInterface|null - */ - private $response; - - public function __construct(?int $passedObjectsCount, ?int $limit, ?ResponseInterface $response = null) - { - $message = sprintf( - 'Expect less than or equal %s items. Got %s.', - $limit, - $passedObjectsCount - ); if (null === $passedObjectsCount || null === $limit) { $message = 'To many items in single request.'; } parent::__construct($message); - - $this->passedObjectsCount = $passedObjectsCount; - $this->limit = $limit; - $this->response = $response; - } - - public function getPassedObjectsCount(): int - { - return $this->passedObjectsCount; - } - - public function getLimit(): int - { - return $this->limit; - } - - public function getResponse(): ?ResponseInterface - { - return $this->response; } } diff --git a/src/LuigisBoxBundle/Exception/TooManyRequestsException.php b/src/LuigisBoxBundle/Exception/TooManyRequestsException.php index 10469c3..aa6a3e0 100644 --- a/src/LuigisBoxBundle/Exception/TooManyRequestsException.php +++ b/src/LuigisBoxBundle/Exception/TooManyRequestsException.php @@ -8,33 +8,12 @@ class TooManyRequestsException extends \RuntimeException { - /** - * @var int - */ - private $retryAfterSeconds; - - /** - * @var ResponseInterface - */ - private $response; - - public function __construct(int $retryAfterSeconds, ResponseInterface $response) - { + public function __construct( + public readonly int $retryAfterSeconds, + public readonly ResponseInterface $response, + ) { parent::__construct( 'To many requests. Check $retryAfterSeconds field to see how many seconds must wait before retrying the request.' ); - - $this->retryAfterSeconds = $retryAfterSeconds; - $this->response = $response; - } - - public function getRetryAfterSeconds(): int - { - return $this->retryAfterSeconds; - } - - public function getResponse(): ResponseInterface - { - return $this->response; } } diff --git a/src/LuigisBoxBundle/Factory/AbstractFactory.php b/src/LuigisBoxBundle/Factory/AbstractFactory.php index a654a2e..911e517 100644 --- a/src/LuigisBoxBundle/Factory/AbstractFactory.php +++ b/src/LuigisBoxBundle/Factory/AbstractFactory.php @@ -12,20 +12,10 @@ abstract class AbstractFactory { - /** - * @var ConfigProvider - */ - private $configProvider; - - /** - * @var LuigisBoxSerializer - */ - private $serializer; - - public function __construct(ConfigProvider $configProvider, LuigisBoxSerializer $serializer) - { - $this->configProvider = $configProvider; - $this->serializer = $serializer; + public function __construct( + private ConfigProvider $configProvider, + private LuigisBoxSerializer $serializer, + ) { } public function prepareRequest(ObjectsInterface $bodyObject): Request diff --git a/src/LuigisBoxBundle/Factory/PartialContentUpdateFactory.php b/src/LuigisBoxBundle/Factory/PartialContentUpdateFactory.php index bbb372e..ae5ffc6 100644 --- a/src/LuigisBoxBundle/Factory/PartialContentUpdateFactory.php +++ b/src/LuigisBoxBundle/Factory/PartialContentUpdateFactory.php @@ -9,32 +9,14 @@ use Answear\LuigisBoxBundle\ValueObject\ContentAvailabilityCollection; use Answear\LuigisBoxBundle\ValueObject\ContentUpdateCollection; use GuzzleHttp\Psr7\Request; -use Webmozart\Assert\Assert; class PartialContentUpdateFactory extends AbstractFactory { private const HTTP_METHOD = 'PATCH'; private const ENDPOINT = '/' . ConfigProvider::API_VERSION . '/content'; - /** - * @param ContentAvailabilityCollection|ContentAvailability $object - */ - public function prepareRequestForAvailability($object): Request + public function prepareRequestForAvailability(ContentAvailabilityCollection|ContentAvailability $object): Request { - $expectedClasses = [ - ContentAvailabilityCollection::class, - ContentAvailability::class, - ]; - - Assert::isInstanceOfAny( - $object, - $expectedClasses, - sprintf( - 'Passed object must be an instance of [%s]', - implode(', ', $expectedClasses) - ) - ); - $objects = $object; if ($object instanceof ContentAvailability) { $objects = new ContentAvailabilityCollection([$object]); diff --git a/src/LuigisBoxBundle/Factory/SearchFactory.php b/src/LuigisBoxBundle/Factory/SearchFactory.php index d897487..805b4e4 100644 --- a/src/LuigisBoxBundle/Factory/SearchFactory.php +++ b/src/LuigisBoxBundle/Factory/SearchFactory.php @@ -14,14 +14,8 @@ class SearchFactory { private const ENDPOINT = '/search'; - /** - * @var ConfigProvider - */ - private $configProvider; - - public function __construct(ConfigProvider $configProvider) + public function __construct(private ConfigProvider $configProvider) { - $this->configProvider = $configProvider; } public function prepareRequest(SearchUrlBuilder $searchUrlBuilder): Request @@ -39,7 +33,7 @@ public function prepareRequest(SearchUrlBuilder $searchUrlBuilder): Request $urlQuery ) ), - $this->configProvider->getHeaders() + $this->configProvider->headers ); } diff --git a/src/LuigisBoxBundle/Factory/UpdateByRequestStatusFactory.php b/src/LuigisBoxBundle/Factory/UpdateByRequestStatusFactory.php index 9a51272..9e082d8 100644 --- a/src/LuigisBoxBundle/Factory/UpdateByRequestStatusFactory.php +++ b/src/LuigisBoxBundle/Factory/UpdateByRequestStatusFactory.php @@ -11,14 +11,8 @@ class UpdateByRequestStatusFactory { private const ENDPOINT = '/' . ConfigProvider::API_VERSION . '/update_by_query'; - /** - * @var ConfigProvider - */ - private $configProvider; - - public function __construct(ConfigProvider $configProvider) + public function __construct(private ConfigProvider $configProvider) { - $this->configProvider = $configProvider; } public function prepareRequest(int $jobId): Request diff --git a/src/LuigisBoxBundle/Response/ApiResponse.php b/src/LuigisBoxBundle/Response/ApiResponse.php index 85469ad..0c95535 100644 --- a/src/LuigisBoxBundle/Response/ApiResponse.php +++ b/src/LuigisBoxBundle/Response/ApiResponse.php @@ -10,77 +10,43 @@ class ApiResponse private const ERRORS_COUNT_PARAM = 'errors_count'; private const ERRORS_PARAM = 'errors'; - /** - * @var bool - */ - private $success = false; + public readonly bool $success; - /** - * @var int - */ - private $okCount; + public readonly int $okCount; - /** - * @var int - */ - private $errorsCount; + public readonly int $errorsCount; /** * @var ApiResponseError[] */ - private $errors = []; + public readonly array $errors; - /** - * @var array - */ - private $rawResponse; + public readonly array $rawResponse; - public function __construct(int $allCount, array $response) - { + public function __construct( + int $allCount, + array $response, + ) { $this->rawResponse = $response; $this->okCount = (int) $response[self::OK_COUNT_PARAM]; $this->errorsCount = (int) ($response[self::ERRORS_COUNT_PARAM] ?? 0); + $success = false; if ($this->okCount === $allCount) { - $this->success = true; + $success = true; } + $this->success = $success; - $errors = $response[self::ERRORS_PARAM] ?? []; - foreach ($errors as $url => $error) { - $this->addError(new ApiResponseError($url, $error)); + $responseErrors = $response[self::ERRORS_PARAM] ?? []; + $errors = []; + foreach ($responseErrors as $url => $error) { + $errors[] = new ApiResponseError($url, $error); } - } - - public function getRawResponse(): array - { - return $this->rawResponse; + $this->errors = $errors; } public function isSuccess(): bool { return $this->success; } - - public function getOkCount(): int - { - return $this->okCount; - } - - public function getErrorsCount(): int - { - return $this->errorsCount; - } - - /** - * @return ApiResponseError[] - */ - public function getErrors(): array - { - return $this->errors; - } - - private function addError(ApiResponseError $apiResponseError): void - { - $this->errors[] = $apiResponseError; - } } diff --git a/src/LuigisBoxBundle/Response/ApiResponseError.php b/src/LuigisBoxBundle/Response/ApiResponseError.php index 7ac831a..065865e 100644 --- a/src/LuigisBoxBundle/Response/ApiResponseError.php +++ b/src/LuigisBoxBundle/Response/ApiResponseError.php @@ -10,61 +10,26 @@ class ApiResponseError implements \JsonSerializable private const REASON_PARAM = 'reason'; private const CAUSED_BY_PARAM = 'caused_by'; - /** - * @var string - */ - private $url; - - /** - * @var string - */ - private $type; - - /** - * @var string - */ - private $reason; - - /** - * @var array|null - */ - private $causedBy; - - public function __construct(string $url, array $error) - { - $this->url = $url; + public readonly string $type; + public readonly string $reason; + public readonly ?array $causedBy; + + public function __construct( + public readonly string $url, + array $error, + ) { $this->type = $error[self::TYPE_PARAM]; $this->reason = $error[self::REASON_PARAM]; $this->causedBy = $error[self::CAUSED_BY_PARAM] ?? null; } - public function getUrl(): string - { - return $this->url; - } - - public function getType(): string - { - return $this->type; - } - - public function getReason(): string - { - return $this->reason; - } - - public function getCausedBy(): ?array - { - return $this->causedBy; - } - public function jsonSerialize(): array { return [ - 'url' => $this->getUrl(), - 'type' => $this->getType(), - 'reason' => $this->getReason(), - 'causedBy' => $this->getCausedBy(), + 'url' => $this->url, + 'type' => $this->type, + 'reason' => $this->reason, + 'causedBy' => $this->causedBy, ]; } } diff --git a/src/LuigisBoxBundle/Response/Search/Facet.php b/src/LuigisBoxBundle/Response/Search/Facet.php index 8effd68..f0ad320 100644 --- a/src/LuigisBoxBundle/Response/Search/Facet.php +++ b/src/LuigisBoxBundle/Response/Search/Facet.php @@ -12,20 +12,14 @@ class Facet private const TYPE_PARAM = 'type'; private const VALUES_PARAM = 'values'; - /** - * @var string - */ - private $name; + public readonly string $name; - /** - * @var string - */ - private $type; + public readonly string $type; /** * @var FacetValue[] */ - private $values = []; + public readonly array $values; public function __construct(array $facetData) { @@ -35,26 +29,11 @@ public function __construct(array $facetData) $this->name = $facetData[self::NAME_PARAM]; $this->type = $facetData[self::TYPE_PARAM]; + + $values = []; foreach ($facetData[self::VALUES_PARAM] as $facetValueData) { - $this->values[] = new FacetValue($facetValueData); + $values[] = new FacetValue($facetValueData); } - } - - public function getName(): string - { - return $this->name; - } - - public function getType(): string - { - return $this->type; - } - - /** - * @return FacetValue[] - */ - public function getValues(): array - { - return $this->values; + $this->values = $values; } } diff --git a/src/LuigisBoxBundle/Response/Search/FacetValue.php b/src/LuigisBoxBundle/Response/Search/FacetValue.php index b040112..7a73a87 100644 --- a/src/LuigisBoxBundle/Response/Search/FacetValue.php +++ b/src/LuigisBoxBundle/Response/Search/FacetValue.php @@ -11,15 +11,9 @@ class FacetValue private const VALUE_PARAM = 'value'; private const HITS_COUNT_PARAM = 'hits_count'; - /** - * @var string - */ - private $value; + public readonly string $value; - /** - * @var int - */ - private $hitsCount; + public readonly int $hitsCount; public function __construct(array $facetValueData) { @@ -29,14 +23,4 @@ public function __construct(array $facetValueData) $this->value = $facetValueData[self::VALUE_PARAM]; $this->hitsCount = $facetValueData[self::HITS_COUNT_PARAM]; } - - public function getValue(): string - { - return $this->value; - } - - public function getHitsCount(): int - { - return $this->hitsCount; - } } diff --git a/src/LuigisBoxBundle/Response/Search/Hit.php b/src/LuigisBoxBundle/Response/Search/Hit.php index adc54fb..ff5ff86 100644 --- a/src/LuigisBoxBundle/Response/Search/Hit.php +++ b/src/LuigisBoxBundle/Response/Search/Hit.php @@ -16,40 +16,19 @@ class Hit private const ATTRIBUTES_PARAM = 'attributes'; private const URL_PARAM = 'url'; - /** - * @var string - */ - private $url; + public readonly string $url; - /** - * @var array - */ - private $attributes; + public readonly array $attributes; - /** - * @var array - */ - private $nested; + public readonly array $nested; - /** - * @var string - */ - private $type; + public readonly string $type; - /** - * @var array - */ - private $highlight; + public readonly array $highlight; - /** - * @var bool - */ - private $exact; + public readonly bool $exact; - /** - * @var bool - */ - private $alternative; + public readonly bool $alternative; public function __construct(array $hitArray) { @@ -69,39 +48,4 @@ public function __construct(array $hitArray) $this->exact = $hitArray[self::EXACT_PARAM]; $this->alternative = $hitArray[self::ALTERNATIVE_PARAM]; } - - public function getUrl(): string - { - return $this->url; - } - - public function getAttributes(): array - { - return $this->attributes; - } - - public function getNested(): array - { - return $this->nested; - } - - public function getType(): string - { - return $this->type; - } - - public function getHighlight(): array - { - return $this->highlight; - } - - public function isExact(): bool - { - return $this->exact; - } - - public function isAlternative(): bool - { - return $this->alternative; - } } diff --git a/src/LuigisBoxBundle/Response/SearchResponse.php b/src/LuigisBoxBundle/Response/SearchResponse.php index c625cfe..d159d65 100644 --- a/src/LuigisBoxBundle/Response/SearchResponse.php +++ b/src/LuigisBoxBundle/Response/SearchResponse.php @@ -19,55 +19,35 @@ class SearchResponse private const RESULTS_QUERY_PARAM = 'query'; private const RESULTS_PARAM = 'results'; - /** - * @var string - */ - private $searchUrl; + public readonly string $query; - /** - * @var string - */ - private $query; + public readonly ?string $correctedQuery; - /** - * @var string|null - */ - private $correctedQuery; - - /** - * @var array - */ - private $filters; + public readonly array $filters; /** * @var Search\Hit[] */ - private $hits; + public readonly array $hits; /** * @var Search\Hit[] */ - private $quickSearchHits; + public readonly array $quickSearchHits; /** * @var Search\Facet[] */ - private $facets; + public readonly array $facets; - /** - * @var int - */ - private $totalHits; + public readonly int $totalHits; - /** - * @var int - */ - private $currentSize; - - public function __construct(string $searchUrl, array $response) - { - $this->searchUrl = $searchUrl; + public readonly int $currentSize; + public function __construct( + public readonly string $searchUrl, + array $response, + ) { Assert::isArray($response[self::RESULTS_PARAM]); $result = $response[self::RESULTS_PARAM]; @@ -87,60 +67,6 @@ public function __construct(string $searchUrl, array $response) $this->currentSize = isset($result[self::RESULTS_OFFSET_PARAM]) ? (int) $result[self::RESULTS_OFFSET_PARAM] : $result[self::RESULTS_TOTAL_HITS_PARAM]; } - public function getSearchUrl(): string - { - return $this->searchUrl; - } - - public function getQuery(): string - { - return $this->query; - } - - public function getCorrectedQuery(): ?string - { - return $this->correctedQuery; - } - - public function getFilters(): array - { - return $this->filters; - } - - /** - * @return Search\Hit[] - */ - public function getHits(): array - { - return $this->hits; - } - - /** - * @return Search\Hit[] - */ - public function getQuickSearchHits(): array - { - return $this->quickSearchHits; - } - - /** - * @return Search\Facet[] - */ - public function getFacets(): array - { - return $this->facets; - } - - public function getTotalHits(): int - { - return $this->totalHits; - } - - public function getCurrentSize(): int - { - return $this->currentSize; - } - private function prepareFilters(array $filtersArray): array { $filters = []; diff --git a/src/LuigisBoxBundle/Response/UpdateByQuery/UpdateByQueryResponse.php b/src/LuigisBoxBundle/Response/UpdateByQuery/UpdateByQueryResponse.php index 12226d5..0927f38 100644 --- a/src/LuigisBoxBundle/Response/UpdateByQuery/UpdateByQueryResponse.php +++ b/src/LuigisBoxBundle/Response/UpdateByQuery/UpdateByQueryResponse.php @@ -10,15 +10,9 @@ class UpdateByQueryResponse { private const STATUS_URL = 'status_url'; - /** - * @var array - */ - private $rawResponse; + public readonly array $rawResponse; - /** - * @var int - */ - private $jobId; + public readonly int $jobId; public function __construct(array $response) { @@ -26,16 +20,6 @@ public function __construct(array $response) $this->jobId = $this->getJobIdFromStatusUrl($response[self::STATUS_URL]); } - public function getRawResponse(): array - { - return $this->rawResponse; - } - - public function getJobId(): int - { - return $this->jobId; - } - private function getJobIdFromStatusUrl(string $statusUrl): int { parse_str($statusUrl, $parsed); diff --git a/src/LuigisBoxBundle/Response/UpdateByQuery/UpdateByQueryStatusResponse.php b/src/LuigisBoxBundle/Response/UpdateByQuery/UpdateByQueryStatusResponse.php index dc749b9..edadec3 100644 --- a/src/LuigisBoxBundle/Response/UpdateByQuery/UpdateByQueryStatusResponse.php +++ b/src/LuigisBoxBundle/Response/UpdateByQuery/UpdateByQueryStatusResponse.php @@ -15,35 +15,20 @@ class UpdateByQueryStatusResponse private const FAILURES = 'failures'; private const STATUS_COMPLETED = 'complete'; - /** - * @var array - */ - private $rawResponse; + public readonly array $rawResponse; - /** - * @var string - */ - private $trackerId; + public readonly string $trackerId; - /** - * @var bool - */ - private $completed; + public readonly bool $completed; - /** - * @var int|null - */ - private $okCount; + public readonly ?int $okCount; - /** - * @var int|null - */ - private $errorsCount; + public readonly ?int $errorsCount; /** - * @var ApiResponseError[]|null + * @var ?ApiResponseError[] */ - private $errors; + public readonly ?array $errors; public function __construct(array $response) { @@ -51,43 +36,26 @@ public function __construct(array $response) $this->trackerId = $response[self::TRACKER_ID]; $this->completed = self::STATUS_COMPLETED === $response[self::STATUS]; + $okCount = null; + $errorsCount = null; + $errors = null; + if ($this->completed) { - $this->okCount = $response[self::UPDATES_COUNT]; - $this->errorsCount = $response[self::FAILURES_COUNT]; - $this->errors = []; + $okCount = $response[self::UPDATES_COUNT]; + $errorsCount = $response[self::FAILURES_COUNT]; + $errors = []; foreach ($response[self::FAILURES] as $url => $failure) { - $this->errors[] = new ApiResponseError($url, $failure); + $errors[] = new ApiResponseError($url, $failure); } } - } - public function getRawResponse(): array - { - return $this->rawResponse; - } - - public function getTrackerId(): string - { - return $this->trackerId; + $this->okCount = $okCount; + $this->errorsCount = $errorsCount; + $this->errors = $errors; } public function isCompleted(): bool { return $this->completed; } - - public function getOkCount(): ?int - { - return $this->okCount; - } - - public function getErrorsCount(): ?int - { - return $this->errorsCount; - } - - public function getErrors(): ?array - { - return $this->errors; - } } diff --git a/src/LuigisBoxBundle/Service/AbstractClient.php b/src/LuigisBoxBundle/Service/AbstractClient.php index ac1828e..83d1864 100644 --- a/src/LuigisBoxBundle/Service/AbstractClient.php +++ b/src/LuigisBoxBundle/Service/AbstractClient.php @@ -16,18 +16,10 @@ abstract class AbstractClient { - /** - * @var ConfigProvider - */ - protected $configProvider; - /** - * @var \GuzzleHttp\Client - */ - protected $client; - - public function __construct(ConfigProvider $configProvider, ?\GuzzleHttp\Client $client = null) - { - $this->configProvider = $configProvider; + public function __construct( + protected ConfigProvider $configProvider, + protected ?\GuzzleHttp\Client $client = null, + ) { $this->client = $client ?? $this->getGuzzleClient(); } diff --git a/src/LuigisBoxBundle/Service/ConfigProvider.php b/src/LuigisBoxBundle/Service/ConfigProvider.php index 6882f6c..7a787b2 100644 --- a/src/LuigisBoxBundle/Service/ConfigProvider.php +++ b/src/LuigisBoxBundle/Service/ConfigProvider.php @@ -12,23 +12,22 @@ class ConfigProvider { public const API_VERSION = 'v1'; - /** - * @var string - */ - private $configName; + private string $configName; /** * @var string[] */ - private $headers = []; + public array $headers = []; /** * @var ConfigDTO[] */ - private $configs; + private array $configs; - public function __construct(string $defaultConfigName, array $configs) - { + public function __construct( + string $defaultConfigName, + array $configs, + ) { $configsDTO = []; foreach ($configs as $configName => $item) { Assert::keyExists($item, 'host'); @@ -111,31 +110,18 @@ public function setHeader(string $name, string $value): void $this->headers[$name] = $value; } - public function getHeaders(): array - { - return $this->headers; - } - public function resetHeaders(): void { $this->headers = []; } - /** - * @deprecated use getAuthorizationHeaders method instead - */ - public function getRequestHeaders(string $httpMethod, string $endpoint, \DateTimeInterface $date): array - { - return $this->getAuthorizationHeaders($httpMethod, $endpoint, $date); - } - public function getAuthorizationHeaders(string $httpMethod, string $endpoint, \DateTimeInterface $date): array { $configDTO = $this->getConfigDTO(); return AuthenticationUtil::getRequestHeaders( - $configDTO->getPublicKey(), - $configDTO->getPrivateKey(), + $configDTO->publicKey, + $configDTO->privateKey, $httpMethod, $endpoint, $date @@ -144,32 +130,32 @@ public function getAuthorizationHeaders(string $httpMethod, string $endpoint, \D public function getHost(): string { - return $this->getConfigDTO()->getHost(); + return $this->getConfigDTO()->host; } public function getPublicKey(): string { - return $this->getConfigDTO()->getPublicKey(); + return $this->getConfigDTO()->publicKey; } public function getConnectionTimeout(): float { - return $this->getConfigDTO()->getConnectionTimeout(); + return $this->getConfigDTO()->connectionTimeout; } public function getRequestTimeout(): float { - return $this->getConfigDTO()->getRequestTimeout(); + return $this->getConfigDTO()->requestTimeout; } public function getSearchTimeout(): float { - return $this->getConfigDTO()->getSearchTimeout(); + return $this->getConfigDTO()->searchTimeout; } public function getSearchCacheTtl(): int { - return $this->getConfigDTO()->getSearchCacheTtl(); + return $this->getConfigDTO()->searchCacheTtl; } private function getConfigDTO(): ConfigDTO diff --git a/src/LuigisBoxBundle/Service/Request.php b/src/LuigisBoxBundle/Service/Request.php index 0904e0f..35044c1 100644 --- a/src/LuigisBoxBundle/Service/Request.php +++ b/src/LuigisBoxBundle/Service/Request.php @@ -27,36 +27,12 @@ class Request implements RequestInterface private const CONTENT_UPDATE_OBJECTS_LIMIT = 100; private const PARTIAL_CONTENT_UPDATE_OBJECTS_LIMIT = 50; - /** - * @var Client - */ - private $client; - - /** - * @var ContentUpdateFactory - */ - private $contentUpdateFactory; - - /** - * @var PartialContentUpdateFactory - */ - private $partialContentUpdateFactory; - - /** - * @var ContentRemovalFactory - */ - private $contentRemovalFactory; - public function __construct( - Client $client, - ContentUpdateFactory $contentUpdateFactory, - PartialContentUpdateFactory $partialContentUpdateFactory, - ContentRemovalFactory $contentRemovalFactory + private Client $client, + private ContentUpdateFactory $contentUpdateFactory, + private PartialContentUpdateFactory $partialContentUpdateFactory, + private ContentRemovalFactory $contentRemovalFactory, ) { - $this->client = $client; - $this->contentUpdateFactory = $contentUpdateFactory; - $this->partialContentUpdateFactory = $partialContentUpdateFactory; - $this->contentRemovalFactory = $contentRemovalFactory; } /** @@ -68,7 +44,7 @@ public function __construct( */ public function contentUpdate(ContentUpdateCollection $objects): ApiResponse { - Assert::allIsInstanceOf($objects->getObjects(), ContentUpdate::class); + Assert::allIsInstanceOf($objects->objects, ContentUpdate::class); if (\count($objects) > self::CONTENT_UPDATE_OBJECTS_LIMIT) { throw new TooManyItemsException(\count($objects), self::CONTENT_UPDATE_OBJECTS_LIMIT); @@ -91,7 +67,7 @@ public function contentUpdate(ContentUpdateCollection $objects): ApiResponse */ public function partialContentUpdate(ContentUpdateCollection $objects): ApiResponse { - Assert::allIsInstanceOf($objects->getObjects(), PartialContentUpdate::class); + Assert::allIsInstanceOf($objects->objects, PartialContentUpdate::class); if (\count($objects) > self::PARTIAL_CONTENT_UPDATE_OBJECTS_LIMIT) { throw new TooManyItemsException(\count($objects), self::PARTIAL_CONTENT_UPDATE_OBJECTS_LIMIT); diff --git a/src/LuigisBoxBundle/Service/SearchRequest.php b/src/LuigisBoxBundle/Service/SearchRequest.php index 93331f7..ccd53ec 100644 --- a/src/LuigisBoxBundle/Service/SearchRequest.php +++ b/src/LuigisBoxBundle/Service/SearchRequest.php @@ -18,22 +18,10 @@ class SearchRequest implements SearchRequestInterface { - /** - * @var SearchClient - */ - private $client; - - /** - * @var SearchFactory - */ - private $searchFactory; - public function __construct( - SearchClient $client, - SearchFactory $searchFactory + private SearchClient $client, + private SearchFactory $searchFactory, ) { - $this->client = $client; - $this->searchFactory = $searchFactory; } /** diff --git a/src/LuigisBoxBundle/Service/UpdateByQueryRequest.php b/src/LuigisBoxBundle/Service/UpdateByQueryRequest.php index facec9a..6ad43cb 100644 --- a/src/LuigisBoxBundle/Service/UpdateByQueryRequest.php +++ b/src/LuigisBoxBundle/Service/UpdateByQueryRequest.php @@ -20,29 +20,11 @@ class UpdateByQueryRequest implements UpdateByQueryRequestInterface { - /** - * @var Client - */ - private $client; - - /** - * @var UpdateByRequestFactory - */ - private $factory; - - /** - * @var UpdateByRequestStatusFactory - */ - private $statusFactory; - public function __construct( - Client $client, - UpdateByRequestFactory $factory, - UpdateByRequestStatusFactory $statusFactory + private Client $client, + private UpdateByRequestFactory $factory, + private UpdateByRequestStatusFactory $statusFactory, ) { - $this->client = $client; - $this->factory = $factory; - $this->statusFactory = $statusFactory; } /** diff --git a/src/LuigisBoxBundle/ValueObject/AbstractContentUpdate.php b/src/LuigisBoxBundle/ValueObject/AbstractContentUpdate.php index 66a8e70..c1516f0 100644 --- a/src/LuigisBoxBundle/ValueObject/AbstractContentUpdate.php +++ b/src/LuigisBoxBundle/ValueObject/AbstractContentUpdate.php @@ -9,65 +9,40 @@ abstract class AbstractContentUpdate { /** - * @var string + * @var ?string[] */ - protected $url; + protected ?array $autocompleteType; - /** - * @var string|null - */ - protected $type; - - /** - * @var string[]|null - */ - protected $autocompleteType; - - /** - * @var string|null - */ - protected $generation; + protected ?string $generation; /** * The date/time must be formatted in the ISO 8601 format, e.g. 2019-05-17T21:12:35+00:00 - * - * @var string|null */ - protected $activeFrom; + protected ?string $activeFrom; /** * The date/time must be formatted in the ISO 8601 format, e.g. 2019-05-17T21:12:35+00:00 - * - * @var string|null */ - protected $activeTo; + protected ?string $activeTo; /** - * @var array + * @var ?AbstractContentUpdate[] */ - protected $fields; + protected ?array $nested; - /** - * @var AbstractContentUpdate[]|null - */ - protected $nested; - - public function __construct(string $url, ?string $type, array $fields) - { + public function __construct( + protected string $url, + protected ?string $type, + protected array $fields, + ) { if (isset($fields['availability'])) { Assert::oneOf($fields['availability'], [0, 1], 'Field availability must be one of [0, 1]'); } if (isset($fields['availability_rank'])) { Assert::integer($fields['availability_rank'], 'Field availability_rank must be integer'); - if ($fields['availability_rank'] < 1 || $fields['availability_rank'] > 15) { - throw new \InvalidArgumentException('Field availability_rank must be between 1 and 15'); - } + Assert::range($fields['availability_rank'], 1, 15, 'Field availability_rank must be between 1 and 15'); } - - $this->url = $url; - $this->type = $type; - $this->fields = $fields; } public function getUrl(): string @@ -129,10 +104,7 @@ public function getFields(): array return $this->fields; } - /** - * @return string|array|null - */ - public function getField(string $fieldName) + public function getField(string $fieldName): array|string|null { return $this->fields[$fieldName] ?? null; } diff --git a/src/LuigisBoxBundle/ValueObject/ContentAvailability.php b/src/LuigisBoxBundle/ValueObject/ContentAvailability.php index 0314b18..57af3d1 100644 --- a/src/LuigisBoxBundle/ValueObject/ContentAvailability.php +++ b/src/LuigisBoxBundle/ValueObject/ContentAvailability.php @@ -4,31 +4,11 @@ namespace Answear\LuigisBoxBundle\ValueObject; -class ContentAvailability +readonly class ContentAvailability { - /** - * @var string - */ - private $url; - - /** - * @var bool - */ - private $available; - - public function __construct(string $url, bool $available) - { - $this->url = $url; - $this->available = $available; - } - - public function getUrl(): string - { - return $this->url; - } - - public function isAvailable(): bool - { - return $this->available; + public function __construct( + public string $url, + public bool $available, + ) { } } diff --git a/src/LuigisBoxBundle/ValueObject/ContentAvailabilityCollection.php b/src/LuigisBoxBundle/ValueObject/ContentAvailabilityCollection.php index b41b78f..5d54e76 100644 --- a/src/LuigisBoxBundle/ValueObject/ContentAvailabilityCollection.php +++ b/src/LuigisBoxBundle/ValueObject/ContentAvailabilityCollection.php @@ -6,30 +6,18 @@ use Webmozart\Assert\Assert; -class ContentAvailabilityCollection implements \Countable +readonly class ContentAvailabilityCollection implements \Countable { /** - * @var ContentAvailability[] + * @param ContentAvailability[] $objects */ - private $objects; - - public function __construct(array $objects) + public function __construct(public array $objects) { Assert::allIsInstanceOf($objects, ContentAvailability::class); - - $this->objects = $objects; - } - - /** - * @return ContentAvailability[] - */ - public function getObjects(): array - { - return $this->objects; } public function count(): int { - return \count($this->getObjects()); + return \count($this->objects); } } diff --git a/src/LuigisBoxBundle/ValueObject/ContentRemoval.php b/src/LuigisBoxBundle/ValueObject/ContentRemoval.php index 9ebc076..6dd3a90 100644 --- a/src/LuigisBoxBundle/ValueObject/ContentRemoval.php +++ b/src/LuigisBoxBundle/ValueObject/ContentRemoval.php @@ -4,31 +4,11 @@ namespace Answear\LuigisBoxBundle\ValueObject; -class ContentRemoval +readonly class ContentRemoval { - /** - * @var string - */ - private $url; - - /** - * @var string - */ - private $type; - - public function __construct(string $url, string $type) - { - $this->url = $url; - $this->type = $type; - } - - public function getUrl(): string - { - return $this->url; - } - - public function getType(): string - { - return $this->type; + public function __construct( + public string $url, + public string $type, + ) { } } diff --git a/src/LuigisBoxBundle/ValueObject/ContentRemovalCollection.php b/src/LuigisBoxBundle/ValueObject/ContentRemovalCollection.php index eb4b368..0bb8b52 100644 --- a/src/LuigisBoxBundle/ValueObject/ContentRemovalCollection.php +++ b/src/LuigisBoxBundle/ValueObject/ContentRemovalCollection.php @@ -6,30 +6,15 @@ use Webmozart\Assert\Assert; -class ContentRemovalCollection implements ObjectsInterface, \Countable +readonly class ContentRemovalCollection implements ObjectsInterface, \Countable { - /** - * @var ContentRemoval[] - */ - private $objects; - - public function __construct(array $objects) + public function __construct(public array $objects) { Assert::allIsInstanceOf($objects, ContentRemoval::class); - - $this->objects = $objects; - } - - /** - * @return ContentRemoval[] - */ - public function getObjects(): array - { - return $this->objects; } public function count(): int { - return \count($this->getObjects()); + return \count($this->objects); } } diff --git a/src/LuigisBoxBundle/ValueObject/ContentUpdate.php b/src/LuigisBoxBundle/ValueObject/ContentUpdate.php index bc64119..1c69543 100644 --- a/src/LuigisBoxBundle/ValueObject/ContentUpdate.php +++ b/src/LuigisBoxBundle/ValueObject/ContentUpdate.php @@ -8,8 +8,12 @@ class ContentUpdate extends AbstractContentUpdate { - public function __construct(string $title, string $url, ?string $type, array $fields) - { + public function __construct( + string $title, + string $url, + ?string $type, + array $fields, + ) { $fields['title'] = $fields['title'] ?? $title; Assert::notEmpty($fields['title'], 'Field title can not be empty'); diff --git a/src/LuigisBoxBundle/ValueObject/ContentUpdateCollection.php b/src/LuigisBoxBundle/ValueObject/ContentUpdateCollection.php index 3252692..6e47af3 100644 --- a/src/LuigisBoxBundle/ValueObject/ContentUpdateCollection.php +++ b/src/LuigisBoxBundle/ValueObject/ContentUpdateCollection.php @@ -6,40 +6,28 @@ use Webmozart\Assert\Assert; -class ContentUpdateCollection implements ObjectsInterface, \Countable +readonly class ContentUpdateCollection implements ObjectsInterface, \Countable { /** - * @var AbstractContentUpdate[] + * @param AbstractContentUpdate[] $objects */ - private $objects; - - public function __construct(array $objects) + public function __construct(public array $objects) { Assert::allIsInstanceOf($objects, AbstractContentUpdate::class); - - $this->objects = $objects; } public static function fromContentAvailabilityObjects(ContentAvailabilityCollection $objects): self { $contentUpdateObjects = []; - foreach ($objects->getObjects() as $object) { + foreach ($objects->objects as $object) { $contentUpdateObjects[] = PartialContentUpdate::fromContentAvailability($object); } return new self($contentUpdateObjects); } - /** - * @return AbstractContentUpdate[] - */ - public function getObjects(): array - { - return $this->objects; - } - public function count(): int { - return \count($this->getObjects()); + return \count($this->objects); } } diff --git a/src/LuigisBoxBundle/ValueObject/PartialContentUpdate.php b/src/LuigisBoxBundle/ValueObject/PartialContentUpdate.php index c5a55b3..6ca5593 100644 --- a/src/LuigisBoxBundle/ValueObject/PartialContentUpdate.php +++ b/src/LuigisBoxBundle/ValueObject/PartialContentUpdate.php @@ -11,10 +11,10 @@ class PartialContentUpdate extends AbstractContentUpdate public static function fromContentAvailability(ContentAvailability $object): self { return new self( - $object->getUrl(), + $object->url, null, [ - 'availability' => $object->isAvailable() ? 1 : 0, + 'availability' => $object->available ? 1 : 0, ] ); } diff --git a/src/LuigisBoxBundle/ValueObject/Search/Context.php b/src/LuigisBoxBundle/ValueObject/Search/Context.php index a09b829..c2c459d 100644 --- a/src/LuigisBoxBundle/ValueObject/Search/Context.php +++ b/src/LuigisBoxBundle/ValueObject/Search/Context.php @@ -8,30 +8,15 @@ class Context { - /** - * @var string|null - */ - private $geoLocation; - - /** - * @var string|null - */ - private $geoLocationField; - - /** - * @var string|null - */ - private $availabilityField; - - /** - * @var string|null - */ - private $boostField; - - /** - * @var string|null - */ - private $freshnessField; + private ?string $geoLocation = null; + + private ?string $geoLocationField = null; + + private ?string $availabilityField = null; + + private ?string $boostField = null; + + private ?string $freshnessField = null; public function getGeoLocation(): ?string { diff --git a/src/LuigisBoxBundle/ValueObject/SearchUrlBuilder.php b/src/LuigisBoxBundle/ValueObject/SearchUrlBuilder.php index 520a5c0..ee52187 100644 --- a/src/LuigisBoxBundle/ValueObject/SearchUrlBuilder.php +++ b/src/LuigisBoxBundle/ValueObject/SearchUrlBuilder.php @@ -17,84 +17,36 @@ class SearchUrlBuilder public const RANGE_SEPARATOR = '|'; private const AVAILABLE_ORDER_DIRECTIONS = ['asc', 'desc']; - /** - * @var string|null - */ - private $query; - - /** - * @var bool|null - */ - private $queryUnderstanding; - - /** - * @var array|null - */ - private $filters; - - /** - * @var array|null - */ - private $mustFilters; - - /** - * @var int - */ - private $size = self::DEFAULT_SIZE; - - /** - * @var string|null - */ - private $sort; - - /** - * @var string|null - */ - private $quicksearchTypes; - - /** - * @var string|null - */ - private $facets; - - /** - * @var int|null - */ - private $dynamicFacetsSize; - - /** - * @var int - */ - private $page; - - /** - * @var bool|null - */ - private $useFixits; - - /** - * @var array|null - */ - private $prefer; - - /** - * @var string|null - */ - private $hitFields; - - /** - * @var Search\Context|null - */ - private $context; - - /** - * @var string|null - */ - private $userId; - - public function __construct(int $page = 1) + private ?string $query = null; + + private ?bool $queryUnderstanding = null; + + private ?array $filters = null; + + private ?array $mustFilters = null; + + private int $size = self::DEFAULT_SIZE; + + private ?string $sort = null; + + private ?string $quicksearchTypes = null; + + private ?string $facets = null; + + private ?int $dynamicFacetsSize = null; + + private ?bool $useFixits = null; + + private ?array $prefer = null; + + private ?string $hitFields = null; + + private ?Search\Context $context = null; + + private ?string $userId = null; + + public function __construct(private readonly int $page = 1) { - $this->page = $page; } public function setQuery(string $query): self @@ -115,19 +67,8 @@ public function enableQueryUnderstanding(): self return $this; } - /** - * @param bool|int|string $value - */ - public function addFilter(string $key, $value): self + public function addFilter(string $key, bool|int|string $value): self { - if (!is_bool($value) - && !is_int($value) - && !is_string($value)) { - throw new \InvalidArgumentException( - sprintf('Value must be bool|int|string, %s provided.', gettype($value)) - ); - } - $this->filters[$key] = $this->filters[$key] ?? []; if (\is_string($this->filters[$key])) { $this->filters[$key] = [$this->filters[$key]]; @@ -160,10 +101,7 @@ public function setFilters(array $filters): self return $this; } - /** - * @param bool|int|string $value - */ - public function addMustFilter(string $key, $value): self + public function addMustFilter(string $key, bool|int|string $value): self { if (!is_bool($value) && !is_int($value) diff --git a/src/LuigisBoxBundle/ValueObject/UpdateByQuery.php b/src/LuigisBoxBundle/ValueObject/UpdateByQuery.php index 56a8cea..7d29cba 100644 --- a/src/LuigisBoxBundle/ValueObject/UpdateByQuery.php +++ b/src/LuigisBoxBundle/ValueObject/UpdateByQuery.php @@ -4,31 +4,11 @@ namespace Answear\LuigisBoxBundle\ValueObject; -class UpdateByQuery implements ObjectsInterface +readonly class UpdateByQuery implements ObjectsInterface { - /** - * @var UpdateByQuery\Search - */ - private $search; - - /** - * @var UpdateByQuery\Update - */ - private $update; - - public function __construct(UpdateByQuery\Search $search, UpdateByQuery\Update $update) - { - $this->search = $search; - $this->update = $update; - } - - public function getSearch(): UpdateByQuery\Search - { - return $this->search; - } - - public function getUpdate(): UpdateByQuery\Update - { - return $this->update; + public function __construct( + public UpdateByQuery\Search $search, + public UpdateByQuery\Update $update, + ) { } } diff --git a/src/LuigisBoxBundle/ValueObject/UpdateByQuery/Search.php b/src/LuigisBoxBundle/ValueObject/UpdateByQuery/Search.php index 359357d..5c087b6 100644 --- a/src/LuigisBoxBundle/ValueObject/UpdateByQuery/Search.php +++ b/src/LuigisBoxBundle/ValueObject/UpdateByQuery/Search.php @@ -6,34 +6,21 @@ use Webmozart\Assert\Assert; -class Search +readonly class Search { - /** - * @var string[] - */ - private $types; + public array $partial; /** - * @var array + * @param string[] $types */ - private $partial = ['fields' => []]; - - public function __construct(array $types, array $fields) - { + public function __construct( + public array $types, + array $fields = [], + ) { Assert::allString($types); Assert::notEmpty($fields); - $this->types = $types; - $this->partial['fields'] = $fields; - } - - public function getTypes(): array - { - return $this->types; - } - - public function getPartial(): array - { - return $this->partial; + $partial['fields'] = $fields; + $this->partial = $partial; } } diff --git a/src/LuigisBoxBundle/ValueObject/UpdateByQuery/Update.php b/src/LuigisBoxBundle/ValueObject/UpdateByQuery/Update.php index 620a36a..06dc961 100644 --- a/src/LuigisBoxBundle/ValueObject/UpdateByQuery/Update.php +++ b/src/LuigisBoxBundle/ValueObject/UpdateByQuery/Update.php @@ -6,21 +6,10 @@ use Webmozart\Assert\Assert; -class Update +readonly class Update { - /** - * @var array - */ - private $fields; - - public function __construct(array $fields) + public function __construct(public array $fields) { Assert::notEmpty($fields); - $this->fields = $fields; - } - - public function getFields(): array - { - return $this->fields; } } diff --git a/tests/Acceptance/DependencyInjection/ConfigurationTest.php b/tests/Acceptance/DependencyInjection/ConfigurationTest.php index d462691..dcad481 100644 --- a/tests/Acceptance/DependencyInjection/ConfigurationTest.php +++ b/tests/Acceptance/DependencyInjection/ConfigurationTest.php @@ -8,6 +8,8 @@ use Answear\LuigisBoxBundle\DependencyInjection\Configuration; use Answear\LuigisBoxBundle\Service\ConfigProvider; use Matthias\SymfonyConfigTest\PhpUnit\ConfigurationTestCaseTrait; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -15,10 +17,8 @@ class ConfigurationTest extends TestCase { use ConfigurationTestCaseTrait; - /** - * @test - * @dataProvider provideValidConfig - */ + #[Test] + #[DataProvider('provideValidConfig')] public function validTest(array $configs, string $expectedConfigName): void { $extension = $this->getExtension(); @@ -32,10 +32,8 @@ public function validTest(array $configs, string $expectedConfigName): void self::assertIsArray($configProviderDefinition->getArgument(1)); } - /** - * @test - * @dataProvider provideInvalidConfig - */ + #[Test] + #[DataProvider('provideInvalidConfig')] public function invalid(array $config, ?string $expectedMessage = null): void { $this->assertConfigurationIsInvalid( @@ -44,16 +42,14 @@ public function invalid(array $config, ?string $expectedMessage = null): void ); } - /** - * @test - * @dataProvider provideValidConfig - */ + #[Test] + #[DataProvider('provideValidConfig')] public function valid(array $config): void { $this->assertConfigurationIsValid($config); } - public function provideInvalidConfig(): iterable + public static function provideInvalidConfig(): iterable { yield [ [ @@ -159,7 +155,7 @@ public function provideInvalidConfig(): iterable ]; } - public function provideValidConfig(): iterable + public static function provideValidConfig(): iterable { yield [ [ diff --git a/tests/Acceptance/Service/RequestTest.php b/tests/Acceptance/Service/RequestTest.php index 4b8a2a9..3b661a9 100644 --- a/tests/Acceptance/Service/RequestTest.php +++ b/tests/Acceptance/Service/RequestTest.php @@ -12,20 +12,23 @@ use Answear\LuigisBoxBundle\Service\LuigisBoxSerializer; use Answear\LuigisBoxBundle\Service\Request; use Answear\LuigisBoxBundle\Service\RequestInterface; -use Answear\LuigisBoxBundle\Tests\DataProvider\Faker\ExampleConfiguration; +use Answear\LuigisBoxBundle\Tests\ExampleConfiguration; use Answear\LuigisBoxBundle\ValueObject\ContentAvailability; +use Answear\LuigisBoxBundle\ValueObject\ContentAvailabilityCollection; +use Answear\LuigisBoxBundle\ValueObject\ContentRemoval; use Answear\LuigisBoxBundle\ValueObject\ContentRemovalCollection; +use Answear\LuigisBoxBundle\ValueObject\ContentUpdate; use Answear\LuigisBoxBundle\ValueObject\ContentUpdateCollection; +use Answear\LuigisBoxBundle\ValueObject\PartialContentUpdate; use GuzzleHttp\Psr7\Response; use GuzzleHttp\Psr7\Uri; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; class RequestTest extends TestCase { - /** - * @var ConfigProvider - */ - private $configProvider; + private ConfigProvider $configProvider; protected function setUp(): void { @@ -34,75 +37,176 @@ protected function setUp(): void $this->configProvider = ExampleConfiguration::provideDefaultConfig(); } - /** - * @test - * @dataProvider \Answear\LuigisBoxBundle\Tests\DataProvider\RequestDataProvider::forContentUpdate() - */ + #[Test] + #[DataProvider('forContentUpdate')] public function contentUpdateRequestPassed( string $httpMethod, ContentUpdateCollection $collection, string $expectedContent, - array $apiResponse + array $apiResponse, ): void { $response = $this->getRequestService($httpMethod, $expectedContent, $apiResponse)->contentUpdate( $collection ); self::assertTrue($response->isSuccess()); - self::assertSame(\count($collection), $response->getOkCount()); - self::assertSame(0, $response->getErrorsCount()); - self::assertSame([], $response->getErrors()); + self::assertSame(\count($collection), $response->okCount); + self::assertSame(0, $response->errorsCount); + self::assertSame([], $response->errors); } - /** - * @test - * @dataProvider \Answear\LuigisBoxBundle\Tests\DataProvider\RequestDataProvider::forPartialContentUpdate() - */ + public static function forContentUpdate(): iterable + { + yield [ + 'POST', + new ContentUpdateCollection([new ContentUpdate('title', 'product/1', 'products', [])]), + '{"objects":[{"url":"product\/1","type":"products","fields":{"title":"title"}}]}', + [ + 'ok_count' => 1, + ], + ]; + + $collection = new ContentUpdateCollection( + [new ContentUpdate('title', 'product/1', 'products', ['availability' => 1])] + ); + yield [ + 'POST', + $collection, + '{"objects":[{"url":"product\/1","type":"products","fields":{"availability":1,"title":"title"}}]}', + [ + 'ok_count' => 1, + ], + ]; + + $contentUpdate1 = new ContentUpdate('title', 'product/2', 'products', ['availability' => 1]); + $contentUpdate1->setActiveTo('2019-12-12 00:01:02'); + $contentUpdate1->setAutocompleteType( + [ + 'categories', + 'other', + ] + ); + $contentUpdate2 = new ContentUpdate('title', 'product/1', 'products', ['availability' => 0]); + $contentUpdate2->setGeneration('one'); + $contentUpdate2->setNested([$contentUpdate1]); + $collection = new ContentUpdateCollection( + [$contentUpdate1, $contentUpdate2] + ); + yield [ + 'POST', + $collection, + '{"objects":[{"autocomplete_type":["categories","other"],"active_to":"2019-12-12 00:01:02","url":"product\/2","type":"products","fields":{"availability":1,"title":"title"}},{"generation":"one","nested":[{"autocomplete_type":["categories","other"],"active_to":"2019-12-12 00:01:02","url":"product\/2","type":"products","fields":{"availability":1,"title":"title"}}],"url":"product\/1","type":"products","fields":{"availability":0,"title":"title"}}]}', + [ + 'ok_count' => 2, + ], + ]; + } + + #[Test] + #[DataProvider('forPartialContentUpdate')] public function partialContentUpdateRequestPassed( string $httpMethod, ContentUpdateCollection $collection, string $expectedContent, - array $apiResponse + array $apiResponse, ): void { $response = $this->getRequestService($httpMethod, $expectedContent, $apiResponse)->partialContentUpdate( $collection ); self::assertTrue($response->isSuccess()); - self::assertSame(\count($collection), $response->getOkCount()); - self::assertSame(0, $response->getErrorsCount()); - self::assertSame([], $response->getErrors()); + self::assertSame(\count($collection), $response->okCount); + self::assertSame(0, $response->errorsCount); + self::assertSame([], $response->errors); } - /** - * @test - * @dataProvider \Answear\LuigisBoxBundle\Tests\DataProvider\RequestDataProvider::forContentRemoval() - */ + public static function forPartialContentUpdate(): iterable + { + yield [ + 'PATCH', + new ContentUpdateCollection([new PartialContentUpdate('product/1', 'products', ['brand' => 'brand name'])]), + '{"objects":[{"url":"product\/1","type":"products","fields":{"brand":"brand name"}}]}', + [ + 'ok_count' => 1, + ], + ]; + + yield [ + 'PATCH', + new ContentUpdateCollection([new PartialContentUpdate('product/1', 'products', ['title' => 'title'])]), + '{"objects":[{"url":"product\/1","type":"products","fields":{"title":"title"}}]}', + [ + 'ok_count' => 1, + ], + ]; + + $collection = new ContentUpdateCollection( + [new PartialContentUpdate('product/1', 'products', ['title' => 'title', 'availability' => 1])] + ); + yield [ + 'PATCH', + $collection, + '{"objects":[{"url":"product\/1","type":"products","fields":{"title":"title","availability":1}}]}', + [ + 'ok_count' => 1, + ], + ]; + + $contentUpdate1 = new PartialContentUpdate('product/2', 'products', ['title' => 'title', 'availability' => 1]); + $contentUpdate1->setActiveTo('2019-12-12 00:01:02'); + $contentUpdate2 = new PartialContentUpdate('product/1', 'products', ['title' => 'title', 'availability' => 0]); + $contentUpdate2->setGeneration('one'); + $contentUpdate2->setNested([$contentUpdate1]); + $collection = new ContentUpdateCollection( + [$contentUpdate1, $contentUpdate2] + ); + yield [ + 'PATCH', + $collection, + '{"objects":[{"active_to":"2019-12-12 00:01:02","url":"product\/2","type":"products","fields":{"title":"title","availability":1}},{"generation":"one","nested":[{"active_to":"2019-12-12 00:01:02","url":"product\/2","type":"products","fields":{"title":"title","availability":1}}],"url":"product\/1","type":"products","fields":{"title":"title","availability":0}}]}', + [ + 'ok_count' => 2, + ], + ]; + } + + #[Test] + #[DataProvider('forContentRemoval')] public function contentRemovalRequestPassed( string $httpMethod, ContentRemovalCollection $collection, string $expectedContent, - array $apiResponse + array $apiResponse, ): void { $response = $this->getRequestService($httpMethod, $expectedContent, $apiResponse)->contentRemoval( $collection ); self::assertTrue($response->isSuccess()); - self::assertSame(\count($collection), $response->getOkCount()); - self::assertSame(0, $response->getErrorsCount()); - self::assertSame([], $response->getErrors()); + self::assertSame(\count($collection), $response->okCount); + self::assertSame(0, $response->errorsCount); + self::assertSame([], $response->errors); + } + + public static function forContentRemoval(): iterable + { + yield [ + 'DELETE', + new ContentRemovalCollection([new ContentRemoval('product/1', 'product')]), + '{"objects":[{"url":"product\/1","type":"product"}]}', + [ + 'ok_count' => 1, + ], + ]; } - /** - * @test - * @dataProvider \Answear\LuigisBoxBundle\Tests\DataProvider\RequestDataProvider::forChangeAvailability() - */ + #[Test] + #[DataProvider('forChangeAvailability')] public function changeAvailabilityRequestPassed( string $httpMethod, $collection, string $expectedContent, - array $apiResponse + array $apiResponse, ): void { $response = $this->getRequestService($httpMethod, $expectedContent, $apiResponse)->changeAvailability( $collection @@ -111,16 +215,48 @@ public function changeAvailabilityRequestPassed( self::assertTrue($response->isSuccess()); self::assertSame( ($collection instanceof ContentAvailability) ? 1 : \count($collection), - $response->getOkCount() + $response->okCount ); - self::assertSame(0, $response->getErrorsCount()); - self::assertSame([], $response->getErrors()); + self::assertSame(0, $response->errorsCount); + self::assertSame([], $response->errors); + } + + public static function forChangeAvailability(): iterable + { + yield [ + 'PATCH', + new ContentAvailabilityCollection([new ContentAvailability('product/1', true)]), + '{"objects":[{"url":"product\/1","fields":{"availability":1}}]}', + [ + 'ok_count' => 1, + ], + ]; + + yield [ + 'PATCH', + new ContentAvailabilityCollection( + [new ContentAvailability('product/1', true), new ContentAvailability('product/2', false)] + ), + '{"objects":[{"url":"product\/1","fields":{"availability":1}},{"url":"product\/2","fields":{"availability":0}}]}', + [ + 'ok_count' => 2, + ], + ]; + + yield [ + 'PATCH', + new ContentAvailability('product/1', true), + '{"objects":[{"url":"product\/1","fields":{"availability":1}}]}', + [ + 'ok_count' => 1, + ], + ]; } private function getRequestService( string $httpMethod, string $expectedContent, - array $apiResponse + array $apiResponse, ): RequestInterface { $endpoint = '/v1/content'; diff --git a/tests/Acceptance/Service/SearchRequestTest.php b/tests/Acceptance/Service/SearchRequestTest.php index c090426..027afbb 100644 --- a/tests/Acceptance/Service/SearchRequestTest.php +++ b/tests/Acceptance/Service/SearchRequestTest.php @@ -8,18 +8,17 @@ use Answear\LuigisBoxBundle\Service\ConfigProvider; use Answear\LuigisBoxBundle\Service\SearchClient; use Answear\LuigisBoxBundle\Service\SearchRequest; -use Answear\LuigisBoxBundle\Tests\DataProvider\Faker\ExampleConfiguration; +use Answear\LuigisBoxBundle\Tests\ExampleConfiguration; use Answear\LuigisBoxBundle\ValueObject\SearchUrlBuilder; +use GuzzleHttp\Psr7\Request; use GuzzleHttp\Psr7\Response; use GuzzleHttp\Psr7\Uri; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; class SearchRequestTest extends TestCase { - /** - * @var ConfigProvider - */ - private $configProvider; + private ConfigProvider $configProvider; protected function setUp(): void { @@ -28,9 +27,7 @@ protected function setUp(): void $this->configProvider = ExampleConfiguration::provideDefaultConfig(); } - /** - * @test - */ + #[Test] public function additionalHeadersTest(): void { $expectedContent = ''; @@ -49,16 +46,16 @@ public function additionalHeadersTest(): void new SearchUrlBuilder() ); - self::assertSame('', $response->getQuery()); + self::assertSame('', $response->query); } private function getSearchService( string $expectedContent, - array $apiResponse + array $apiResponse, ): SearchRequest { $endpoint = '/search'; - $expectedRequest = new \GuzzleHttp\Psr7\Request( + $expectedRequest = new Request( 'GET', new Uri('host' . $endpoint), [ @@ -72,7 +69,7 @@ private function getSearchService( ->method('request') ->with( self::callback( - static function (\GuzzleHttp\Psr7\Request $currentRequest) use ($expectedRequest) { + static function (Request $currentRequest) use ($expectedRequest) { $currentHeaders = $currentRequest->getHeaders(); $expectedHeaders = $expectedRequest->getHeaders(); diff --git a/tests/Acceptance/Service/UpdateByQueryRequestTest.php b/tests/Acceptance/Service/UpdateByQueryRequestTest.php index 5cf7960..63b371a 100644 --- a/tests/Acceptance/Service/UpdateByQueryRequestTest.php +++ b/tests/Acceptance/Service/UpdateByQueryRequestTest.php @@ -10,69 +10,136 @@ use Answear\LuigisBoxBundle\Service\LuigisBoxSerializer; use Answear\LuigisBoxBundle\Service\UpdateByQueryRequest; use Answear\LuigisBoxBundle\Service\UpdateByQueryRequestInterface; -use Answear\LuigisBoxBundle\Tests\DataProvider\Faker\ExampleConfiguration; +use Answear\LuigisBoxBundle\Tests\ExampleConfiguration; use Answear\LuigisBoxBundle\ValueObject\UpdateByQuery; use GuzzleHttp\Psr7\Response; use GuzzleHttp\Psr7\Uri; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; class UpdateByQueryRequestTest extends TestCase { - /** - * @test - * @dataProvider \Answear\LuigisBoxBundle\Tests\DataProvider\UpdateByQueryRequestDataProvider::forUpdate() - */ + #[Test] + #[DataProvider('forUpdate')] public function updatePassed( UpdateByQuery $updateByQuery, string $expectedContent, array $apiResponse, - int $jobId + int $jobId, ): void { $response = $this->getService('PATCH', '/v1/update_by_query', $expectedContent, $apiResponse)->update( $updateByQuery ); - $this->assertSame($apiResponse, $response->getRawResponse()); - $this->assertSame($jobId, $response->getJobId()); + $this->assertSame($apiResponse, $response->rawResponse); + $this->assertSame($jobId, $response->jobId); + } + + public static function forUpdate(): iterable + { + yield [ + new UpdateByQuery( + new UpdateByQuery\Search(['product'], ['color' => 'olive']), + new UpdateByQuery\Update(['color' => 'green']), + ), + '{"search":{"partial":{"fields":{"color":"olive"}},"types":["product"]},"update":{"fields":{"color":"green"}}}', + [ + 'status_url' => '/v1/update_by_query?job_id=1', + ], + 1, + ]; + + yield [ + new UpdateByQuery( + new UpdateByQuery\Search(['product', 'brand'], ['color' => 'olive']), + new UpdateByQuery\Update(['color' => ['green', 'blue'], 'brand' => 'Star']), + ), + '{"search":{"partial":{"fields":{"color":"olive"}},"types":["product","brand"]},"update":{"fields":{"color":["green","blue"],"brand":"Star"}}}', + [ + 'status_url' => '/v1/update_by_query?job_id=12', + ], + 12, + ]; } - /** - * @test - * @dataProvider \Answear\LuigisBoxBundle\Tests\DataProvider\UpdateByQueryRequestDataProvider::forUpdateStatus() - */ + #[Test] + #[DataProvider('forUpdateStatus')] public function updateStatusPassed( int $jobId, - array $apiResponse + array $apiResponse, ): void { $response = $this->getService('GET', '/v1/update_by_query?job_id=' . $jobId, '', $apiResponse) ->getStatus($jobId); $this->assertSame('complete' === $apiResponse['status'], $response->isCompleted()); - $this->assertSame($apiResponse['tracker_id'], $response->getTrackerId()); - $this->assertSame($apiResponse['updates_count'] ?? null, $response->getOkCount()); - $this->assertSame($apiResponse['failures_count'] ?? null, $response->getErrorsCount()); + $this->assertSame($apiResponse['tracker_id'], $response->trackerId); + $this->assertSame($apiResponse['updates_count'] ?? null, $response->okCount); + $this->assertSame($apiResponse['failures_count'] ?? null, $response->errorsCount); if (!isset($apiResponse['failures'])) { - $this->assertNull($response->getErrors()); + $this->assertNull($response->errors); } else { - foreach ($response->getErrors() as $error) { - $failure = $apiResponse['failures'][$error->getUrl()]; + foreach ($response->errors as $error) { + $failure = $apiResponse['failures'][$error->url]; $this->assertNotEmpty($failure); - $this->assertSame($failure['type'], $error->getType()); - $this->assertSame($failure['reason'], $error->getReason()); - $this->assertSame($failure['caused_by'], $error->getCausedBy()); + $this->assertSame($failure['type'], $error->type); + $this->assertSame($failure['reason'], $error->reason); + $this->assertSame($failure['caused_by'], $error->causedBy); } } - $this->assertSame($apiResponse, $response->getRawResponse()); + $this->assertSame($apiResponse, $response->rawResponse); + } + + public static function forUpdateStatus(): iterable + { + yield [ + 1, + [ + 'tracker_id' => 'abcd', + 'status' => 'complete', + 'updates_count' => 5, + 'failures_count' => 0, + 'failures' => [], + ], + ]; + + yield [ + 111, + [ + 'tracker_id' => 'iabad', + 'status' => 'in progress', + ], + ]; + + yield [ + 12, + [ + 'tracker_id' => 'abad', + 'status' => 'complete', + 'updates_count' => 5, + 'failures_count' => 1, + 'failures' => [ + '/products/1' => [ + 'type' => 'data_schema_mismatch', + 'reason' => 'failed to parse [attributes.price]', + 'caused_by' => [ + 'type' => 'number_format_exception', + 'reason' => 'For input string: "wrong sale price"', + ], + ], + ], + ], + ]; } private function getService( string $httpMethod, string $endpoint, string $expectedContent, - array $apiResponse + array $apiResponse, ): UpdateByQueryRequestInterface { $expectedRequest = new \GuzzleHttp\Psr7\Request( $httpMethod, diff --git a/tests/DataProvider/ContentUpdateDataProvider.php b/tests/DataProvider/ContentUpdateDataProvider.php deleted file mode 100644 index f8cb054..0000000 --- a/tests/DataProvider/ContentUpdateDataProvider.php +++ /dev/null @@ -1,107 +0,0 @@ - 2, - ], - ]; - } - - public static function provideSuccessPartialContentUpdateObjects(): iterable - { - $objects = [ - new PartialContentUpdate( - 'test.url', - 'products', - [], - ), - new PartialContentUpdate( - 'test.url2', - 'categories', - [] - ), - ]; - - yield [ - new ContentUpdateCollection($objects), - [ - 'ok_count' => 2, - ], - ]; - } - - public static function provideAboveLimitContentUpdateObjects(): iterable - { - $objects = []; - for ($i = 0; $i <= Request::getContentUpdateLimit(); ++$i) { - $objects[] = new ContentUpdate( - 'test url title' . $i, - 'test.url' . $i, - 'products', - [] - ); - } - - yield [new ContentUpdateCollection($objects)]; - } - - public static function provideAboveLimitPartialContentUpdateObjects(): iterable - { - $objects = []; - for ($i = 0; $i <= Request::getPartialContentUpdateLimit(); ++$i) { - $objects[] = new PartialContentUpdate( - 'test.url' . $i, - 'products', - [] - ); - } - - yield [new ContentUpdateCollection($objects)]; - } - - public static function provideContentRemovalObjects(): iterable - { - $objects = [ - new ContentRemoval('test.url', 'product'), - new ContentRemoval('test.url2', 'product'), - ]; - - yield [ - new ContentRemovalCollection($objects), - [ - 'ok_count' => 2, - ], - ]; - } -} diff --git a/tests/DataProvider/RequestDataProvider.php b/tests/DataProvider/RequestDataProvider.php deleted file mode 100644 index 6e9c272..0000000 --- a/tests/DataProvider/RequestDataProvider.php +++ /dev/null @@ -1,157 +0,0 @@ - 1, - ], - ]; - - $collection = new ContentUpdateCollection( - [new ContentUpdate('title', 'product/1', 'products', ['availability' => 1])] - ); - yield [ - 'POST', - $collection, - '{"objects":[{"url":"product\/1","type":"products","fields":{"availability":1,"title":"title"}}]}', - [ - 'ok_count' => 1, - ], - ]; - - $contentUpdate1 = new ContentUpdate('title', 'product/2', 'products', ['availability' => 1]); - $contentUpdate1->setActiveTo('2019-12-12 00:01:02'); - $contentUpdate1->setAutocompleteType( - [ - 'categories', - 'other', - ] - ); - $contentUpdate2 = new ContentUpdate('title', 'product/1', 'products', ['availability' => 0]); - $contentUpdate2->setGeneration('one'); - $contentUpdate2->setNested([$contentUpdate1]); - $collection = new ContentUpdateCollection( - [$contentUpdate1, $contentUpdate2] - ); - yield [ - 'POST', - $collection, - '{"objects":[{"url":"product\/2","type":"products","autocomplete_type":["categories","other"],"active_to":"2019-12-12 00:01:02","fields":{"availability":1,"title":"title"}},{"url":"product\/1","type":"products","generation":"one","fields":{"availability":0,"title":"title"},"nested":[{"url":"product\/2","type":"products","autocomplete_type":["categories","other"],"active_to":"2019-12-12 00:01:02","fields":{"availability":1,"title":"title"}}]}]}', - [ - 'ok_count' => 2, - ], - ]; - } - - public function forPartialContentUpdate(): iterable - { - yield [ - 'PATCH', - new ContentUpdateCollection([new PartialContentUpdate('product/1', 'products', ['brand' => 'brand name'])]), - '{"objects":[{"url":"product\/1","type":"products","fields":{"brand":"brand name"}}]}', - [ - 'ok_count' => 1, - ], - ]; - - yield [ - 'PATCH', - new ContentUpdateCollection([new PartialContentUpdate('product/1', 'products', ['title' => 'title'])]), - '{"objects":[{"url":"product\/1","type":"products","fields":{"title":"title"}}]}', - [ - 'ok_count' => 1, - ], - ]; - - $collection = new ContentUpdateCollection( - [new PartialContentUpdate('product/1', 'products', ['title' => 'title', 'availability' => 1])] - ); - yield [ - 'PATCH', - $collection, - '{"objects":[{"url":"product\/1","type":"products","fields":{"title":"title","availability":1}}]}', - [ - 'ok_count' => 1, - ], - ]; - - $contentUpdate1 = new PartialContentUpdate('product/2', 'products', ['title' => 'title', 'availability' => 1]); - $contentUpdate1->setActiveTo('2019-12-12 00:01:02'); - $contentUpdate2 = new PartialContentUpdate('product/1', 'products', ['title' => 'title', 'availability' => 0]); - $contentUpdate2->setGeneration('one'); - $contentUpdate2->setNested([$contentUpdate1]); - $collection = new ContentUpdateCollection( - [$contentUpdate1, $contentUpdate2] - ); - yield [ - 'PATCH', - $collection, - '{"objects":[{"url":"product\/2","type":"products","active_to":"2019-12-12 00:01:02","fields":{"title":"title","availability":1}},{"url":"product\/1","type":"products","generation":"one","fields":{"title":"title","availability":0},"nested":[{"url":"product\/2","type":"products","active_to":"2019-12-12 00:01:02","fields":{"title":"title","availability":1}}]}]}', - [ - 'ok_count' => 2, - ], - ]; - } - - public function forContentRemoval(): iterable - { - yield [ - 'DELETE', - new ContentRemovalCollection([new ContentRemoval('product/1', 'product')]), - '{"objects":[{"url":"product\/1","type":"product"}]}', - [ - 'ok_count' => 1, - ], - ]; - } - - public function forChangeAvailability(): iterable - { - yield [ - 'PATCH', - new ContentAvailabilityCollection([new ContentAvailability('product/1', true)]), - '{"objects":[{"url":"product\/1","fields":{"availability":1}}]}', - [ - 'ok_count' => 1, - ], - ]; - - yield [ - 'PATCH', - new ContentAvailabilityCollection( - [new ContentAvailability('product/1', true), new ContentAvailability('product/2', false)] - ), - '{"objects":[{"url":"product\/1","fields":{"availability":1}},{"url":"product\/2","fields":{"availability":0}}]}', - [ - 'ok_count' => 2, - ], - ]; - - yield [ - 'PATCH', - new ContentAvailability('product/1', true), - '{"objects":[{"url":"product\/1","fields":{"availability":1}}]}', - [ - 'ok_count' => 1, - ], - ]; - } -} diff --git a/tests/DataProvider/SearchDataProvider.php b/tests/DataProvider/SearchDataProvider.php deleted file mode 100644 index d22ecad..0000000 --- a/tests/DataProvider/SearchDataProvider.php +++ /dev/null @@ -1,223 +0,0 @@ -addFilter('type', 'product'); - $urlBuilder->setQuicksearchTypes(['category']); - - yield [ - $urlBuilder, - [ - 'results' => [ - 'query' => '', - 'corrected_query' => null, - 'filters' => [ - 'type:product', - ], - 'hits' => [ - [ - 'url' => '/p/cardio-bunny-stroj-kapielowy-sahara-swimsuit-77', - 'attributes' => [ - 'id' => [ - 0 => 77, - ], - 'attributes' => [ - 0 => 'Jeans', - 1 => 'Krótki', - ], - 'price' => 23, - 'price_amount' => 23.3, - 'category' => [ - 0 => 'On', - 1 => 'Odzież', - 2 => 'Spodnie', - ], - 'id_count' => 1, - 'attributes_count' => 2, - 'category_count' => 3, - 'boosted_via' => [], - 'title' => 'Cardio Bunny - Strój kąpielowy Sahara Swimsuit', - 'boosted_via_count' => 0, - 'original_url' => '/p/cardio-bunny-stroj-kapielowy-sahara-swimsuit-77', - 'boost' => 0, - ], - 'nested' => [], - 'type' => 'product', - 'highlight' => [], - 'exact' => true, - 'alternative' => false, - ], - [ - 'url' => '/p/cardio-bunny-top-sportowy-rio-17', - 'attributes' => [ - 'id' => [ - 0 => 17, - ], - 'category' => [ - 0 => 'On', - 1 => 'Odzież', - 2 => 'Top', - ], - 'id_count' => 1, - 'category_count' => 3, - 'boosted_via' => [ - 0 => 'item', - ], - 'title' => 'Cardio Bunny - Top sportowy Rio', - 'original_url' => '/p/cardio-bunny-top-sportowy-rio-17', - 'boost' => 1, - 'boosted_via_count' => 1, - ], - 'nested' => [], - 'type' => 'product', - 'highlight' => [], - 'exact' => true, - 'alternative' => false, - ], - [ - 'url' => '/p/medicine-fugit-72', - 'attributes' => [ - 'id' => [ - 0 => 72, - ], - 'id_count' => 1, - 'brand' => [ - 0 => 'Changed Name', - ], - 'brand_count' => 1, - 'boosted_via' => [], - 'title' => 'Fugit', - 'original_url' => '/p/medicine-fugit-72', - 'boost' => 0, - 'boosted_via_count' => 0, - ], - 'nested' => [], - 'type' => 'product', - 'highlight' => [], - 'exact' => true, - 'alternative' => false, - ], - [ - 'url' => '/p/medicine-sit-73', - 'attributes' => [ - 'id' => [ - 0 => 73, - ], - 'id_count' => 1, - 'availability' => 0, - 'brand' => [ - 0 => 'Changed Name', - ], - 'brand_count' => 1, - 'boosted_via' => [], - 'title' => 'Sit', - 'original_url' => '/p/medicine-sit-73', - 'boost' => 0, - 'boosted_via_count' => 0, - ], - 'nested' => [], - 'type' => 'product', - 'highlight' => [], - 'exact' => true, - 'alternative' => false, - ], - ], - 'quicksearch_hits' => [ - [ - 'url' => '/c/fila-mikina-1407', - 'attributes' => [ - 'test' => ['test'], - 'test_count' => 1, - 'boosted_via' => [], - 'title' => 'Kategoria - Fila - Mikina', - 'original_url' => 'https://beta-sk.softwear.co/c/fila-mikina-1407', - 'boost' => 0, - 'boosted_via_count' => 0, - ], - 'nested' => [], - 'type' => 'category', - 'highlight' => null, - 'exact' => true, - 'alternative' => false, - ], - ], - 'facets' => [], - 'total_hits' => 17, - 'offset' => '4', - ], - 'next_page' => 'https://live.luigisbox.com/search?tracker_id=111111-222222&f[]=type:product&quicksearch_types=category&page=2', - ], - ]; - - $urlBuilder = new SearchUrlBuilder(); - $urlBuilder->setQuery('fila'); - - yield [ - $urlBuilder, - [ - 'results' => [ - 'query' => 'fila', - 'corrected_query' => null, - 'filters' => [], - 'hits' => [ - [ - 'url' => '/c/fila-mikina-1407', - 'attributes' => [ - 'test' => [ - 0 => 'test', - ], - 'test_count' => 1, - 'boosted_via' => [ - ], - 'title' => 'Kategoria - Fila - Mikina', - 'original_url' => 'https://beta-sk.softwear.co/c/fila-mikina-1407', - 'boost' => 0, - 'boosted_via_count' => 0, - ], - 'nested' => [], - 'type' => 'category', - 'highlight' => [], - 'exact' => true, - 'alternative' => false, - ], - ], - 'quicksearch_hits' => [], - 'facets' => [], - 'total_hits' => 1, - ], - 'next_page' => null, - ], - ]; - - $urlBuilder = new SearchUrlBuilder(); - $urlBuilder->setQuery('fila'); - $urlBuilder->addFilter('price', '5|2'); - - yield [ - $urlBuilder, - [ - 'results' => [ - 'query' => 'fila', - 'corrected_query' => null, - 'filters' => [ - 'price:5|2', - ], - 'hits' => [], - 'quicksearch_hits' => [], - 'facets' => [], - 'total_hits' => 0, - ], - 'next_page' => null, - ], - ]; - } -} diff --git a/tests/DataProvider/UpdateByQueryRequestDataProvider.php b/tests/DataProvider/UpdateByQueryRequestDataProvider.php deleted file mode 100644 index c8ad934..0000000 --- a/tests/DataProvider/UpdateByQueryRequestDataProvider.php +++ /dev/null @@ -1,79 +0,0 @@ - 'olive']), - new UpdateByQuery\Update(['color' => 'green']), - ), - '{"search":{"types":["product"],"partial":{"fields":{"color":"olive"}}},"update":{"fields":{"color":"green"}}}', - [ - 'status_url' => '/v1/update_by_query?job_id=1', - ], - 1, - ]; - - yield [ - new UpdateByQuery( - new UpdateByQuery\Search(['product', 'brand'], ['color' => 'olive']), - new UpdateByQuery\Update(['color' => ['green', 'blue'], 'brand' => 'Star']), - ), - '{"search":{"types":["product","brand"],"partial":{"fields":{"color":"olive"}}},"update":{"fields":{"color":["green","blue"],"brand":"Star"}}}', - [ - 'status_url' => '/v1/update_by_query?job_id=12', - ], - 12, - ]; - } - - public function forUpdateStatus(): iterable - { - yield [ - 1, - [ - 'tracker_id' => 'abcd', - 'status' => 'complete', - 'updates_count' => 5, - 'failures_count' => 0, - 'failures' => [], - ], - ]; - - yield [ - 111, - [ - 'tracker_id' => 'iabad', - 'status' => 'in progress', - ], - ]; - - yield [ - 12, - [ - 'tracker_id' => 'abad', - 'status' => 'complete', - 'updates_count' => 5, - 'failures_count' => 1, - 'failures' => [ - '/products/1' => [ - 'type' => 'data_schema_mismatch', - 'reason' => 'failed to parse [attributes.price]', - 'caused_by' => [ - 'type' => 'number_format_exception', - 'reason' => 'For input string: "wrong sale price"', - ], - ], - ], - ], - ]; - } -} diff --git a/tests/DataProvider/ValueObjectDataProvider.php b/tests/DataProvider/ValueObjectDataProvider.php deleted file mode 100644 index 3c1df85..0000000 --- a/tests/DataProvider/ValueObjectDataProvider.php +++ /dev/null @@ -1,124 +0,0 @@ - 'test url title', - ], - ]; - - yield [ - 'test.url2', - 'categories', - [ - 'title' => 'test url title', - 'availability' => 0, - 'availability_rank' => 14, - ], - ]; - - yield [ - 'test.url2', - 'categories', - [ - 'title' => 'test url title', - 'availability' => 0, - 'availability_rank' => 14, - ], - ]; - - yield [ - 'test.url2', - null, - [ - 'title' => 'test url title', - ], - ]; - - yield [ - 'test.url2', - 'categories', - [ - 'title' => 'test url title', - 'availability' => 0, - 'availability_rank' => 14, - ], - [ - 'categories', - 'autocomplete type 2', - ], - 'generation 1', - [ - new ContentUpdate( - 'title', - 's', - 'products', - [] - ), - ], - ]; - } - - public static function provideContentUpdateObjectsForException(): iterable - { - yield [ - 'Field title can not be empty', - 'test.url', - 'products', - [], - ]; - - yield [ - 'Field availability must be one of [0, 1]', - 'test.url', - 'products', - [ - 'title' => 'title', - 'availability' => 3, - ], - ]; - - yield [ - 'Field availability_rank must be between 1 and 15', - 'test.url', - 'products', - [ - 'title' => 'title', - 'availability_rank' => 16, - ], - ]; - - yield [ - 'Expected an instance of Answear\LuigisBoxBundle\ValueObject\ContentUpdate. Got: Answear\LuigisBoxBundle\ValueObject\ContentRemoval', - 'test.url', - 'products', - [ - 'title' => 'title', - ], - null, - null, - [ - new ContentRemoval('', ''), - ], - ]; - } - - public static function provideContentRemovalObjects(): iterable - { - yield [ - 'test.url', - ]; - } -} diff --git a/tests/DataProvider/Faker/ExampleConfiguration.php b/tests/ExampleConfiguration.php similarity index 91% rename from tests/DataProvider/Faker/ExampleConfiguration.php rename to tests/ExampleConfiguration.php index 9e37c43..b32f25c 100644 --- a/tests/DataProvider/Faker/ExampleConfiguration.php +++ b/tests/ExampleConfiguration.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Answear\LuigisBoxBundle\Tests\DataProvider\Faker; +namespace Answear\LuigisBoxBundle\Tests; use Answear\LuigisBoxBundle\Service\ConfigProvider; diff --git a/tests/Unit/DTO/ConfigDTOTest.php b/tests/Unit/DTO/ConfigDTOTest.php index ab5e76f..503b0f4 100644 --- a/tests/Unit/DTO/ConfigDTOTest.php +++ b/tests/Unit/DTO/ConfigDTOTest.php @@ -5,15 +5,14 @@ namespace Answear\LuigisBoxBundle\Tests\Acceptance\DependencyInjection; use Answear\LuigisBoxBundle\DTO\ConfigDTO; -use Answear\LuigisBoxBundle\Tests\DataProvider\Faker\ExampleConfiguration; +use Answear\LuigisBoxBundle\Tests\ExampleConfiguration; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; class ConfigDTOTest extends TestCase { - /** - * @test - */ - public function addConfig() + #[Test] + public function addConfig(): void { $configProvider = ExampleConfiguration::provideDefaultConfig(); @@ -27,10 +26,8 @@ public function addConfig() $this->assertEquals('new-public', $configProvider->getPublicKey()); } - /** - * @test - */ - public function addConfigWithColidingName() + #[Test] + public function addConfigWithColidingName(): void { $this->expectExceptionMessage('Configuration with key "config_name" already exists.'); $configProvider = ExampleConfiguration::provideDefaultConfig(); diff --git a/tests/Unit/Factory/ContentUpdateFactoryTest.php b/tests/Unit/Factory/ContentUpdateFactoryTest.php index b3d8f7a..9532bdc 100644 --- a/tests/Unit/Factory/ContentUpdateFactoryTest.php +++ b/tests/Unit/Factory/ContentUpdateFactoryTest.php @@ -6,17 +6,16 @@ use Answear\LuigisBoxBundle\Factory\ContentUpdateFactory; use Answear\LuigisBoxBundle\Service\LuigisBoxSerializer; -use Answear\LuigisBoxBundle\Tests\DataProvider\Faker\ExampleConfiguration; +use Answear\LuigisBoxBundle\Tests\ExampleConfiguration; use Answear\LuigisBoxBundle\ValueObject\ContentUpdate; use Answear\LuigisBoxBundle\ValueObject\ContentUpdateCollection; use Answear\LuigisBoxBundle\ValueObject\ObjectsInterface; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; class ContentUpdateFactoryTest extends TestCase { - /** - * @test - */ + #[Test] public function prepareRequestSuccessfully(): void { $objects = $this->getObjects(); diff --git a/tests/Unit/Factory/PartialContentUpdateFactoryTest.php b/tests/Unit/Factory/PartialContentUpdateFactoryTest.php index c0ad484..83c6716 100644 --- a/tests/Unit/Factory/PartialContentUpdateFactoryTest.php +++ b/tests/Unit/Factory/PartialContentUpdateFactoryTest.php @@ -6,17 +6,17 @@ use Answear\LuigisBoxBundle\Factory\PartialContentUpdateFactory; use Answear\LuigisBoxBundle\Service\LuigisBoxSerializer; -use Answear\LuigisBoxBundle\Tests\DataProvider\Faker\ExampleConfiguration; +use Answear\LuigisBoxBundle\Tests\ExampleConfiguration; use Answear\LuigisBoxBundle\ValueObject\ContentAvailability; use Answear\LuigisBoxBundle\ValueObject\ContentAvailabilityCollection; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; class PartialContentUpdateFactoryTest extends TestCase { - /** - * @test - * @dataProvider provideAvailabilityObjects - */ + #[Test] + #[DataProvider('provideAvailabilityObjects')] public function prepareRequestSuccessfully($objects): void { $factory = $this->getFactory(); @@ -34,7 +34,7 @@ public function prepareRequestSuccessfully($objects): void $this->assertSame('serialized', $request->getBody()->getContents()); } - public function provideAvailabilityObjects(): iterable + public static function provideAvailabilityObjects(): iterable { yield [new ContentAvailability('url', true)]; diff --git a/tests/Unit/Factory/SearchFactoryTest.php b/tests/Unit/Factory/SearchFactoryTest.php index 201c29e..9748f16 100644 --- a/tests/Unit/Factory/SearchFactoryTest.php +++ b/tests/Unit/Factory/SearchFactoryTest.php @@ -5,15 +5,14 @@ namespace Answear\LuigisBoxBundle\Tests\Unit\Factory; use Answear\LuigisBoxBundle\Factory\SearchFactory; -use Answear\LuigisBoxBundle\Tests\DataProvider\Faker\ExampleConfiguration; +use Answear\LuigisBoxBundle\Tests\ExampleConfiguration; use Answear\LuigisBoxBundle\ValueObject\SearchUrlBuilder; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; class SearchFactoryTest extends TestCase { - /** - * @test - */ + #[Test] public function prepareRequestSuccessfully(): void { $builderUrl = $this->getBuilderUrl(); diff --git a/tests/Unit/Service/RequestExceptionsTest.php b/tests/Unit/Service/RequestExceptionsTest.php index 3bd5370..0239b45 100644 --- a/tests/Unit/Service/RequestExceptionsTest.php +++ b/tests/Unit/Service/RequestExceptionsTest.php @@ -19,13 +19,12 @@ use Answear\LuigisBoxBundle\ValueObject\ContentUpdateCollection; use GuzzleHttp\Exception\TransferException; use GuzzleHttp\Psr7\Response; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; class RequestExceptionsTest extends TestCase { - /** - * @test - */ + #[Test] public function tooManyItemsExceptionThrows(): void { $this->expectException(TooManyItemsException::class); @@ -42,9 +41,7 @@ public function tooManyItemsExceptionThrows(): void $service->contentUpdate($objects); } - /** - * @test - */ + #[Test] public function tooManyRequestsExceptionThrows(): void { $this->expectException(TooManyRequestsException::class); @@ -63,9 +60,7 @@ public function tooManyRequestsExceptionThrows(): void $service->contentUpdate($objects); } - /** - * @test - */ + #[Test] public function malformedResponseThrows(): void { $this->expectException(MalformedResponseException::class); @@ -84,9 +79,7 @@ public function malformedResponseThrows(): void $service->contentUpdate($objects); } - /** - * @test - */ + #[Test] public function serviceUnavailableThrows(): void { $this->expectException(ServiceUnavailableException::class); diff --git a/tests/Unit/Service/RequestTest.php b/tests/Unit/Service/RequestTest.php index b6d8fc6..4dbe2b0 100644 --- a/tests/Unit/Service/RequestTest.php +++ b/tests/Unit/Service/RequestTest.php @@ -11,65 +11,124 @@ use Answear\LuigisBoxBundle\Service\Client; use Answear\LuigisBoxBundle\Service\Request; use Answear\LuigisBoxBundle\Service\RequestInterface; +use Answear\LuigisBoxBundle\ValueObject\ContentRemoval; use Answear\LuigisBoxBundle\ValueObject\ContentRemovalCollection; use Answear\LuigisBoxBundle\ValueObject\ContentUpdate; use Answear\LuigisBoxBundle\ValueObject\ContentUpdateCollection; use Answear\LuigisBoxBundle\ValueObject\ObjectsInterface; +use Answear\LuigisBoxBundle\ValueObject\PartialContentUpdate; use GuzzleHttp\Psr7\Response; use GuzzleHttp\Psr7\Uri; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; class RequestTest extends TestCase { - /** - * @test - * @dataProvider \Answear\LuigisBoxBundle\Tests\DataProvider\ContentUpdateDataProvider::provideSuccessContentUpdateObjects() - */ + #[Test] + #[DataProvider('provideSuccessContentUpdateObjects')] public function contentUpdateWithSuccess(ContentUpdateCollection $objects, array $apiResponse): void { $requestService = $this->getRequestServiceForContentUpdate($objects, $apiResponse); $response = $requestService->contentUpdate($objects); $this->assertTrue($response->isSuccess()); - $this->assertSame(\count($objects), $response->getOkCount()); - $this->assertSame(0, $response->getErrorsCount()); - $this->assertSame([], $response->getErrors()); + $this->assertSame(\count($objects), $response->okCount); + $this->assertSame(0, $response->errorsCount); + $this->assertSame([], $response->errors); } - /** - * @test - * @dataProvider \Answear\LuigisBoxBundle\Tests\DataProvider\ContentUpdateDataProvider::provideSuccessPartialContentUpdateObjects() - */ + public static function provideSuccessContentUpdateObjects(): iterable + { + $objects = [ + new ContentUpdate( + 'test url title', + 'test.url', + 'products', + [], + ), + new ContentUpdate( + 'test url title', + 'test.url2', + 'categories', + [] + ), + ]; + + yield [ + new ContentUpdateCollection($objects), + [ + 'ok_count' => 2, + ], + ]; + } + + #[Test] + #[DataProvider('provideSuccessPartialContentUpdateObjects')] public function partialContentUpdateWithSuccess(ContentUpdateCollection $objects, array $apiResponse): void { $requestService = $this->getRequestServiceForPartialUpdate($objects, $apiResponse); $response = $requestService->partialContentUpdate($objects); $this->assertTrue($response->isSuccess()); - $this->assertSame(\count($objects), $response->getOkCount()); - $this->assertSame(0, $response->getErrorsCount()); - $this->assertSame([], $response->getErrors()); + $this->assertSame(\count($objects), $response->okCount); + $this->assertSame(0, $response->errorsCount); + $this->assertSame([], $response->errors); } - /** - * @test - * @dataProvider \Answear\LuigisBoxBundle\Tests\DataProvider\ContentUpdateDataProvider::provideContentRemovalObjects() - */ + public static function provideSuccessPartialContentUpdateObjects(): iterable + { + $objects = [ + new PartialContentUpdate( + 'test.url', + 'products', + [], + ), + new PartialContentUpdate( + 'test.url2', + 'categories', + [] + ), + ]; + + yield [ + new ContentUpdateCollection($objects), + [ + 'ok_count' => 2, + ], + ]; + } + + #[Test] + #[DataProvider('provideContentRemovalObjects')] public function contentRemovalWithSuccess(ContentRemovalCollection $objects, array $apiResponse): void { $requestService = $this->getRequestServiceForRemoval($objects, $apiResponse); $response = $requestService->contentRemoval($objects); $this->assertTrue($response->isSuccess()); - $this->assertSame(\count($objects), $response->getOkCount()); - $this->assertSame(0, $response->getErrorsCount()); - $this->assertSame([], $response->getErrors()); + $this->assertSame(\count($objects), $response->okCount); + $this->assertSame(0, $response->errorsCount); + $this->assertSame([], $response->errors); + } + + public static function provideContentRemovalObjects(): iterable + { + $objects = [ + new ContentRemoval('test.url', 'product'), + new ContentRemoval('test.url2', 'product'), + ]; + + yield [ + new ContentRemovalCollection($objects), + [ + 'ok_count' => 2, + ], + ]; } - /** - * @test - * @dataProvider \Answear\LuigisBoxBundle\Tests\DataProvider\ContentUpdateDataProvider::provideAboveLimitContentUpdateObjects() - */ + #[Test] + #[DataProvider('provideAboveLimitContentUpdateObjects')] public function contentUpdateWithExceededLimit(ContentUpdateCollection $objects): void { $this->expectException(TooManyItemsException::class); @@ -79,10 +138,23 @@ public function contentUpdateWithExceededLimit(ContentUpdateCollection $objects) $requestService->contentUpdate($objects); } - /** - * @test - * @dataProvider \Answear\LuigisBoxBundle\Tests\DataProvider\ContentUpdateDataProvider::provideAboveLimitPartialContentUpdateObjects() - */ + public static function provideAboveLimitContentUpdateObjects(): iterable + { + $objects = []; + for ($i = 0; $i <= Request::getContentUpdateLimit(); ++$i) { + $objects[] = new ContentUpdate( + 'test url title' . $i, + 'test.url' . $i, + 'products', + [] + ); + } + + yield [new ContentUpdateCollection($objects)]; + } + + #[Test] + #[DataProvider('provideAboveLimitPartialContentUpdateObjects')] public function partialContentUpdateWithExceededLimit(ContentUpdateCollection $objects): void { $this->expectException(TooManyItemsException::class); @@ -92,9 +164,21 @@ public function partialContentUpdateWithExceededLimit(ContentUpdateCollection $o $requestService->partialContentUpdate($objects); } - /** - * @test - */ + public static function provideAboveLimitPartialContentUpdateObjects(): iterable + { + $objects = []; + for ($i = 0; $i <= Request::getPartialContentUpdateLimit(); ++$i) { + $objects[] = new PartialContentUpdate( + 'test.url' . $i, + 'products', + [] + ); + } + + yield [new ContentUpdateCollection($objects)]; + } + + #[Test] public function contentUpdateWithErrors(): void { $objects = new ContentUpdateCollection( @@ -133,19 +217,19 @@ public function contentUpdateWithErrors(): void $response = $requestService->contentUpdate($objects); $this->assertFalse($response->isSuccess()); - $this->assertSame(1, $response->getOkCount()); - $this->assertSame(1, $response->getErrorsCount()); - $this->assertCount(1, $response->getErrors()); - - $apiResponseError = $response->getErrors()[0]; - $this->assertSame('test.url2', $apiResponseError->getUrl()); - $this->assertSame('malformed_input', $apiResponseError->getType()); - $this->assertSame('incorrect object format', $apiResponseError->getReason()); + $this->assertSame(1, $response->okCount); + $this->assertSame(1, $response->errorsCount); + $this->assertCount(1, $response->errors); + + $apiResponseError = $response->errors[0]; + $this->assertSame('test.url2', $apiResponseError->url); + $this->assertSame('malformed_input', $apiResponseError->type); + $this->assertSame('incorrect object format', $apiResponseError->reason); $this->assertSame( [ 'title' => ['must be filled'], ], - $apiResponseError->getCausedBy() + $apiResponseError->causedBy ); } diff --git a/tests/Unit/Service/SearchRequestTest.php b/tests/Unit/Service/SearchRequestTest.php index ba64b71..56b32d4 100644 --- a/tests/Unit/Service/SearchRequestTest.php +++ b/tests/Unit/Service/SearchRequestTest.php @@ -14,36 +14,247 @@ use Answear\LuigisBoxBundle\ValueObject\SearchUrlBuilder; use GuzzleHttp\Psr7\Response; use GuzzleHttp\Psr7\Uri; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; class SearchRequestTest extends TestCase { private const CACHE_TTL = 'cache-ttl'; - /** - * @test - * @dataProvider \Answear\LuigisBoxBundle\Tests\DataProvider\SearchDataProvider::provideSuccessObjects() - */ + #[Test] + #[DataProvider('provideSuccessObjects')] public function searchWithSuccess(SearchUrlBuilder $urlBuilder, array $arrayRawResponse): void { $requestService = $this->getRequestService($urlBuilder, $arrayRawResponse); $response = $requestService->search($urlBuilder); - $this->assertStringContainsString(self::CACHE_TTL, $response->getSearchUrl()); - $this->assertSame($urlBuilder->toUrlQuery(), strstr($response->getSearchUrl(), '&v=', true)); + $this->assertStringContainsString(self::CACHE_TTL, $response->searchUrl); + $this->assertSame($urlBuilder->toUrlQuery(), strstr($response->searchUrl, '&v=', true)); $rawResults = $arrayRawResponse['results']; - $this->assertSame($rawResults['query'], $response->getQuery()); - $this->assertSame($rawResults['corrected_query'], $response->getCorrectedQuery()); - $this->assertFiltersSame($rawResults['filters'], $response->getFilters()); - $this->assertHitsSame($rawResults['hits'], $response->getHits()); - $this->assertHitsSame($rawResults['quicksearch_hits'], $response->getQuickSearchHits()); - $this->assertFacetsSame($rawResults['facets'], $response->getFacets()); - $this->assertSame($rawResults['total_hits'], $response->getTotalHits()); + $this->assertSame($rawResults['query'], $response->query); + $this->assertSame($rawResults['corrected_query'], $response->correctedQuery); + $this->assertFiltersSame($rawResults['filters'], $response->filters); + $this->assertHitsSame($rawResults['hits'], $response->hits); + $this->assertHitsSame($rawResults['quicksearch_hits'], $response->quickSearchHits); + $this->assertFacetsSame($rawResults['facets'], $response->facets); + $this->assertSame($rawResults['total_hits'], $response->totalHits); } - /** - * @test - */ + public static function provideSuccessObjects(): iterable + { + $urlBuilder = new SearchUrlBuilder(2); + $urlBuilder->addFilter('type', 'product'); + $urlBuilder->setQuicksearchTypes(['category']); + + yield [ + $urlBuilder, + [ + 'results' => [ + 'query' => '', + 'corrected_query' => null, + 'filters' => [ + 'type:product', + ], + 'hits' => [ + [ + 'url' => '/p/cardio-bunny-stroj-kapielowy-sahara-swimsuit-77', + 'attributes' => [ + 'id' => [ + 0 => 77, + ], + 'attributes' => [ + 0 => 'Jeans', + 1 => 'Krótki', + ], + 'price' => 23, + 'price_amount' => 23.3, + 'category' => [ + 0 => 'On', + 1 => 'Odzież', + 2 => 'Spodnie', + ], + 'id_count' => 1, + 'attributes_count' => 2, + 'category_count' => 3, + 'boosted_via' => [], + 'title' => 'Cardio Bunny - Strój kąpielowy Sahara Swimsuit', + 'boosted_via_count' => 0, + 'original_url' => '/p/cardio-bunny-stroj-kapielowy-sahara-swimsuit-77', + 'boost' => 0, + ], + 'nested' => [], + 'type' => 'product', + 'highlight' => [], + 'exact' => true, + 'alternative' => false, + ], + [ + 'url' => '/p/cardio-bunny-top-sportowy-rio-17', + 'attributes' => [ + 'id' => [ + 0 => 17, + ], + 'category' => [ + 0 => 'On', + 1 => 'Odzież', + 2 => 'Top', + ], + 'id_count' => 1, + 'category_count' => 3, + 'boosted_via' => [ + 0 => 'item', + ], + 'title' => 'Cardio Bunny - Top sportowy Rio', + 'original_url' => '/p/cardio-bunny-top-sportowy-rio-17', + 'boost' => 1, + 'boosted_via_count' => 1, + ], + 'nested' => [], + 'type' => 'product', + 'highlight' => [], + 'exact' => true, + 'alternative' => false, + ], + [ + 'url' => '/p/medicine-fugit-72', + 'attributes' => [ + 'id' => [ + 0 => 72, + ], + 'id_count' => 1, + 'brand' => [ + 0 => 'Changed Name', + ], + 'brand_count' => 1, + 'boosted_via' => [], + 'title' => 'Fugit', + 'original_url' => '/p/medicine-fugit-72', + 'boost' => 0, + 'boosted_via_count' => 0, + ], + 'nested' => [], + 'type' => 'product', + 'highlight' => [], + 'exact' => true, + 'alternative' => false, + ], + [ + 'url' => '/p/medicine-sit-73', + 'attributes' => [ + 'id' => [ + 0 => 73, + ], + 'id_count' => 1, + 'availability' => 0, + 'brand' => [ + 0 => 'Changed Name', + ], + 'brand_count' => 1, + 'boosted_via' => [], + 'title' => 'Sit', + 'original_url' => '/p/medicine-sit-73', + 'boost' => 0, + 'boosted_via_count' => 0, + ], + 'nested' => [], + 'type' => 'product', + 'highlight' => [], + 'exact' => true, + 'alternative' => false, + ], + ], + 'quicksearch_hits' => [ + [ + 'url' => '/c/fila-mikina-1407', + 'attributes' => [ + 'test' => ['test'], + 'test_count' => 1, + 'boosted_via' => [], + 'title' => 'Kategoria - Fila - Mikina', + 'original_url' => 'https://beta-sk.softwear.co/c/fila-mikina-1407', + 'boost' => 0, + 'boosted_via_count' => 0, + ], + 'nested' => [], + 'type' => 'category', + 'highlight' => null, + 'exact' => true, + 'alternative' => false, + ], + ], + 'facets' => [], + 'total_hits' => 17, + 'offset' => '4', + ], + 'next_page' => 'https://live.luigisbox.com/search?tracker_id=111111-222222&f[]=type:product&quicksearch_types=category&page=2', + ], + ]; + + $urlBuilder = new SearchUrlBuilder(); + $urlBuilder->setQuery('fila'); + + yield [ + $urlBuilder, + [ + 'results' => [ + 'query' => 'fila', + 'corrected_query' => null, + 'filters' => [], + 'hits' => [ + [ + 'url' => '/c/fila-mikina-1407', + 'attributes' => [ + 'test' => [ + 0 => 'test', + ], + 'test_count' => 1, + 'boosted_via' => [ + ], + 'title' => 'Kategoria - Fila - Mikina', + 'original_url' => 'https://beta-sk.softwear.co/c/fila-mikina-1407', + 'boost' => 0, + 'boosted_via_count' => 0, + ], + 'nested' => [], + 'type' => 'category', + 'highlight' => [], + 'exact' => true, + 'alternative' => false, + ], + ], + 'quicksearch_hits' => [], + 'facets' => [], + 'total_hits' => 1, + ], + 'next_page' => null, + ], + ]; + + $urlBuilder = new SearchUrlBuilder(); + $urlBuilder->setQuery('fila'); + $urlBuilder->addFilter('price', '5|2'); + + yield [ + $urlBuilder, + [ + 'results' => [ + 'query' => 'fila', + 'corrected_query' => null, + 'filters' => [ + 'price:5|2', + ], + 'hits' => [], + 'quicksearch_hits' => [], + 'facets' => [], + 'total_hits' => 0, + ], + 'next_page' => null, + ], + ]; + } + + #[Test] public function searchWithErrors(): void { $this->expectException(BadRequestException::class); @@ -67,7 +278,7 @@ public function searchWithErrors(): void private function getRequestService( SearchUrlBuilder $searchUrlBuilder, array $apiResponse, - int $responseStatus = 200 + int $responseStatus = 200, ): SearchRequestInterface { $guzzleRequest = new \GuzzleHttp\Psr7\Request( 'POST', @@ -123,12 +334,12 @@ private function assertHitsSame(array $rawHits, array $hits): void foreach ($rawHits as $key => $rawHit) { $searchHit = $hits[$key]; - $this->assertSame($rawHit['url'], $searchHit->getUrl()); - $this->assertSame($rawHit['attributes'], $searchHit->getAttributes()); - $this->assertSame($rawHit['nested'], $searchHit->getNested()); - $this->assertSame($rawHit['type'], $searchHit->getType()); - $this->assertSame($rawHit['exact'], $searchHit->isExact()); - $this->assertSame($rawHit['alternative'], $searchHit->isAlternative()); + $this->assertSame($rawHit['url'], $searchHit->url); + $this->assertSame($rawHit['attributes'], $searchHit->attributes); + $this->assertSame($rawHit['nested'], $searchHit->nested); + $this->assertSame($rawHit['type'], $searchHit->type); + $this->assertSame($rawHit['exact'], $searchHit->exact); + $this->assertSame($rawHit['alternative'], $searchHit->alternative); } } @@ -142,9 +353,9 @@ private function assertFacetsSame(array $rawFacets, array $facets): void foreach ($rawFacets as $key => $rawFacet) { $searchFacet = $facets[$key]; - $this->assertSame($rawFacet['name'], $searchFacet->getName()); - $this->assertSame('string', $searchFacet->getType()); - $this->assertSame([], $searchFacet->getValues()); + $this->assertSame($rawFacet['name'], $searchFacet->name); + $this->assertSame('string', $searchFacet->type); + $this->assertSame([], $searchFacet->values); } } } diff --git a/tests/Unit/ValueObject/ContentRemovalTest.php b/tests/Unit/ValueObject/ContentRemovalTest.php index c3fb20e..97b1c31 100644 --- a/tests/Unit/ValueObject/ContentRemovalTest.php +++ b/tests/Unit/ValueObject/ContentRemovalTest.php @@ -5,18 +5,25 @@ namespace Answear\LuigisBoxBundle\Tests\Unit\ValueObject; use Answear\LuigisBoxBundle\ValueObject\ContentRemoval; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; class ContentRemovalTest extends TestCase { - /** - * @test - * @dataProvider \Answear\LuigisBoxBundle\Tests\DataProvider\ValueObjectDataProvider::provideContentRemovalObjects() - */ + #[Test] + #[DataProvider('provideContentRemovalObjects')] public function createObjectSuccessfully(string $url): void { $object = new ContentRemoval($url, ''); - $this->assertSame($url, $object->getUrl()); + $this->assertSame($url, $object->url); + } + + public static function provideContentRemovalObjects(): iterable + { + yield [ + 'test.url', + ]; } } diff --git a/tests/Unit/ValueObject/ContentUpdateTest.php b/tests/Unit/ValueObject/ContentUpdateTest.php index 4e85dcf..74d13ee 100644 --- a/tests/Unit/ValueObject/ContentUpdateTest.php +++ b/tests/Unit/ValueObject/ContentUpdateTest.php @@ -4,22 +4,23 @@ namespace Answear\LuigisBoxBundle\Tests\Unit\ValueObject; +use Answear\LuigisBoxBundle\ValueObject\ContentRemoval; use Answear\LuigisBoxBundle\ValueObject\ContentUpdate; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; class ContentUpdateTest extends TestCase { - /** - * @test - * @dataProvider \Answear\LuigisBoxBundle\Tests\DataProvider\ValueObjectDataProvider::provideContentUpdateObjects() - */ + #[Test] + #[DataProvider('provideContentUpdateObjects')] public function createObjectSuccessfully( string $url, ?string $type, array $fields, ?array $autocompleteType = null, ?string $generation = null, - ?array $nested = null + ?array $nested = null, ): void { $object = new ContentUpdate($fields['title'] ?? '', $url, $type, $fields); $object->setAutocompleteType($autocompleteType); @@ -34,9 +35,69 @@ public function createObjectSuccessfully( $this->assertSame($nested ?? [], $object->getNested()); } - /** - * @test - */ + public static function provideContentUpdateObjects(): iterable + { + yield [ + 'test.url', + 'products', + [ + 'title' => 'test url title', + ], + ]; + + yield [ + 'test.url2', + 'categories', + [ + 'title' => 'test url title', + 'availability' => 0, + 'availability_rank' => 14, + ], + ]; + + yield [ + 'test.url2', + 'categories', + [ + 'title' => 'test url title', + 'availability' => 0, + 'availability_rank' => 14, + ], + ]; + + yield [ + 'test.url2', + null, + [ + 'title' => 'test url title', + ], + ]; + + yield [ + 'test.url2', + 'categories', + [ + 'title' => 'test url title', + 'availability' => 0, + 'availability_rank' => 14, + ], + [ + 'categories', + 'autocomplete type 2', + ], + 'generation 1', + [ + new ContentUpdate( + 'title', + 's', + 'products', + [] + ), + ], + ]; + } + + #[Test] public function passingFieldTitleFromTitleProperty(): void { $title = 'Title property'; @@ -64,9 +125,7 @@ public function passingFieldTitleFromTitleProperty(): void ); } - /** - * @test - */ + #[Test] public function passingFieldTitleInsteadOfTitleProperty(): void { $title = 'Title property'; @@ -89,10 +148,8 @@ public function passingFieldTitleInsteadOfTitleProperty(): void $this->assertSame($fields, $object->getFields()); } - /** - * @test - * @dataProvider \Answear\LuigisBoxBundle\Tests\DataProvider\ValueObjectDataProvider::provideContentUpdateObjectsForException() - */ + #[Test] + #[DataProvider('provideContentUpdateObjectsForException')] public function createObjectWithFailure( string $expectedExceptionMessage, string $url, @@ -100,7 +157,7 @@ public function createObjectWithFailure( array $fields, ?array $autocompleteType = null, ?string $generation = null, - ?array $nested = null + ?array $nested = null, ): void { $this->expectExceptionMessage($expectedExceptionMessage); @@ -116,4 +173,48 @@ public function createObjectWithFailure( $this->assertSame($generation, $object->getGeneration()); $this->assertSame($nested ?? [], $object->getNested()); } + + public static function provideContentUpdateObjectsForException(): iterable + { + yield [ + 'Field title can not be empty', + 'test.url', + 'products', + [], + ]; + + yield [ + 'Field availability must be one of [0, 1]', + 'test.url', + 'products', + [ + 'title' => 'title', + 'availability' => 3, + ], + ]; + + yield [ + 'Field availability_rank must be between 1 and 15', + 'test.url', + 'products', + [ + 'title' => 'title', + 'availability_rank' => 16, + ], + ]; + + yield [ + 'Expected an instance of Answear\LuigisBoxBundle\ValueObject\ContentUpdate. Got: Answear\LuigisBoxBundle\ValueObject\ContentRemoval', + 'test.url', + 'products', + [ + 'title' => 'title', + ], + null, + null, + [ + new ContentRemoval('', ''), + ], + ]; + } } diff --git a/tests/Unit/ValueObject/SearchUrlBuilderTest.php b/tests/Unit/ValueObject/SearchUrlBuilderTest.php index 9a635ac..55af5aa 100644 --- a/tests/Unit/ValueObject/SearchUrlBuilderTest.php +++ b/tests/Unit/ValueObject/SearchUrlBuilderTest.php @@ -6,13 +6,12 @@ use Answear\LuigisBoxBundle\ValueObject\Search\Context; use Answear\LuigisBoxBundle\ValueObject\SearchUrlBuilder; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; class SearchUrlBuilderTest extends TestCase { - /** - * @test - */ + #[Test] public function buildValidUrlTest(): void { $query = [ @@ -175,7 +174,7 @@ private function assertOk(array $query, SearchUrlBuilder $searchBuilder): void */ private function parse(string $string): array { - $decoder = function ($value) { + $decoder = static function ($value) { return rawurldecode(str_replace('+', ' ', (string) $value)); };