diff --git a/composer.json b/composer.json index 79cbc93e..1a82eacf 100644 --- a/composer.json +++ b/composer.json @@ -41,7 +41,8 @@ "EzSystems\\EzRecommendationClientBundle\\": "src/bundle/", "EzSystems\\EzRecommendationClient\\": "src/lib/", "Ibexa\\Contracts\\Personalization\\": "src/contracts/", - "Ibexa\\Personalization\\": "src/lib/" + "Ibexa\\Personalization\\": "src/lib/", + "Ibexa\\Bundle\\Personalization\\": "src/bundle/" } }, "autoload-dev": { diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 6bbe9b6d..1f30f392 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,20 +1,5 @@ parameters: ignoreErrors: - - - message: "#^Cannot call method getDefinition\\(\\) on Symfony\\\\Component\\\\Console\\\\Application\\|null\\.$#" - count: 1 - path: src/bundle/Command/ExportCommand.php - - - - message: "#^Method EzSystems\\\\EzRecommendationClientBundle\\\\Command\\\\ExportCommand\\:\\:configure\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/bundle/Command/ExportCommand.php - - - - message: "#^Parameter \\#5 \\$default of method Symfony\\\\Component\\\\Console\\\\Command\\\\Command\\:\\:addOption\\(\\) expects array\\\\|bool\\|string\\|null, int given\\.$#" - count: 3 - path: src/bundle/Command/ExportCommand.php - - message: "#^Left side of && is always true\\.$#" count: 1 @@ -95,11 +80,6 @@ parameters: count: 1 path: src/bundle/Controller/ExportController.php - - - message: "#^Parameter \\#2 \\$values of method Symfony\\\\Component\\\\HttpFoundation\\\\ResponseHeaderBag\\:\\:set\\(\\) expects array\\\\|string, int\\|false given\\.$#" - count: 1 - path: src/bundle/Controller/ExportController.php - - message: "#^Method EzSystems\\\\EzRecommendationClientBundle\\\\Controller\\\\RecommendationController\\:\\:getTemplate\\(\\) should return string but returns string\\|null\\.$#" count: 1 @@ -390,16 +370,6 @@ parameters: count: 1 path: src/lib/Event/Subscriber/AbstractCoreEventSubscriber.php - - - message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Event\\\\Subscriber\\\\ContentEventSubscriber\\:\\:getSubscribedEvents\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/lib/Event/Subscriber/ContentEventSubscriber.php - - - - message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Event\\\\Subscriber\\\\LocationEventSubscriber\\:\\:getSubscribedEvents\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/lib/Event/Subscriber/LocationEventSubscriber.php - - message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Event\\\\Subscriber\\\\LocationEventSubscriber\\:\\:swapLocation\\(\\) has parameter \\$locations with no value type specified in iterable type array\\.$#" count: 1 @@ -410,11 +380,6 @@ parameters: count: 1 path: src/lib/Event/Subscriber/LocationEventSubscriber.php - - - message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Event\\\\Subscriber\\\\ObjectStateEventSubscriber\\:\\:getSubscribedEvents\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/lib/Event/Subscriber/ObjectStateEventSubscriber.php - - message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Event\\\\Subscriber\\\\RecommendationEventSubscriber\\:\\:extractRecommendationItems\\(\\) return type has no value type specified in iterable type array\\.$#" count: 1 @@ -425,11 +390,6 @@ parameters: count: 1 path: src/lib/Event/Subscriber/RecommendationEventSubscriber.php - - - message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Event\\\\Subscriber\\\\RecommendationEventSubscriber\\:\\:getSubscribedEvents\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/lib/Event/Subscriber/RecommendationEventSubscriber.php - - message: "#^Parameter \\#1 \\$parameters of class EzSystems\\\\EzRecommendationClient\\\\Request\\\\BasicRecommendationRequest constructor expects array\\, array\\ given\\.$#" count: 1 @@ -475,11 +435,6 @@ parameters: count: 1 path: src/lib/Event/Subscriber/RecommendationRandomContentEventSubscriber.php - - - message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Event\\\\Subscriber\\\\RecommendationRandomContentEventSubscriber\\:\\:getSubscribedEvents\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/lib/Event/Subscriber/RecommendationRandomContentEventSubscriber.php - - message: "#^PHPDoc tag @param for parameter \\$contentService with type eZ\\\\Publish\\\\API\\\\Repository\\\\SearchService is not subtype of native type eZ\\\\Publish\\\\API\\\\Repository\\\\ContentService\\.$#" count: 1 @@ -505,16 +460,6 @@ parameters: count: 1 path: src/lib/Event/Subscriber/RecommendationRandomContentEventSubscriber.php - - - message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Event\\\\Subscriber\\\\TrashEventSubscriber\\:\\:getSubscribedEvents\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/lib/Event/Subscriber/TrashEventSubscriber.php - - - - message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Event\\\\Subscriber\\\\UserAPIRequestDefaultSourceEventSubscriber\\:\\:getSubscribedEvents\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/lib/Event/Subscriber/UserAPIRequestDefaultSourceEventSubscriber.php - - message: "#^Cannot access property \\$source on EzSystems\\\\EzRecommendationClient\\\\SPI\\\\UserAPIRequest\\|null\\.$#" count: 1 @@ -525,11 +470,6 @@ parameters: count: 1 path: src/lib/Event/Subscriber/UserCollectionGeneratorEventSubscriber.php - - - message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Event\\\\Subscriber\\\\UserCollectionGeneratorEventSubscriber\\:\\:getSubscribedEvents\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/lib/Event/Subscriber/UserCollectionGeneratorEventSubscriber.php - - message: "#^Property EzSystems\\\\EzRecommendationClient\\\\Event\\\\Subscriber\\\\UserCollectionGeneratorEventSubscriber\\:\\:\\$eventDispatcher \\(Symfony\\\\Component\\\\EventDispatcher\\\\EventDispatcher\\) does not accept Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\.$#" count: 1 @@ -555,16 +495,6 @@ parameters: count: 1 path: src/lib/Exception/BadResponseException.php - - - message: "#^Parameter \\#3 \\$previous of method Exception\\:\\:__construct\\(\\) expects Throwable\\|null, EzSystems\\\\EzRecommendationClient\\\\Exception\\\\Throwable\\|null given\\.$#" - count: 1 - path: src/lib/Exception/CredentialsNotFoundException.php - - - - message: "#^Parameter \\$previous of method EzSystems\\\\EzRecommendationClient\\\\Exception\\\\CredentialsNotFoundException\\:\\:__construct\\(\\) has invalid typehint type EzSystems\\\\EzRecommendationClient\\\\Exception\\\\Throwable\\.$#" - count: 1 - path: src/lib/Exception/CredentialsNotFoundException.php - - message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Exception\\\\FileNotFoundException\\:\\:__construct\\(\\) has parameter \\$code with no typehint specified\\.$#" count: 1 @@ -611,54 +541,44 @@ parameters: path: src/lib/Exception/InvalidRelationException.php - - message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Exporter\\\\Exporter\\:\\:generateUrlList\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 + message: "#^Access to an undefined property Ibexa\\\\Personalization\\\\Value\\\\Export\\\\Parameters\\:\\:\\$lang\\.$#" + count: 3 path: src/lib/Exporter/Exporter.php - - message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Exporter\\\\Exporter\\:\\:getContentForGivenLanguages\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 + message: "#^Access to an undefined property Ibexa\\\\Personalization\\\\Value\\\\Export\\\\Parameters\\:\\:\\$page\\.$#" + count: 2 path: src/lib/Exporter/Exporter.php - - message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Exporter\\\\Exporter\\:\\:run\\(\\) return type has no value type specified in iterable type array\\.$#" + message: "#^Call to an undefined method Ibexa\\\\Personalization\\\\Value\\\\Export\\\\Parameters\\:\\:getProperties\\(\\)\\.$#" count: 1 path: src/lib/Exporter/Exporter.php - - message: "#^Parameter \\#2 \\$lang of method EzSystems\\\\EzRecommendationClient\\\\Exporter\\\\Exporter\\:\\:generateUrlList\\(\\) expects string, string\\|null given\\.$#" + message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Exporter\\\\Exporter\\:\\:generateUrlList\\(\\) return type has no value type specified in iterable type array\\.$#" count: 1 path: src/lib/Exporter/Exporter.php - - message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Exporter\\\\ExporterInterface\\:\\:run\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/lib/Exporter/ExporterInterface.php - - - - message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Factory\\\\ConfigurableExportParametersFactory\\:\\:create\\(\\) has parameter \\$properties with no value type specified in iterable type array\\.$#" - count: 1 - path: src/lib/Factory/ConfigurableExportParametersFactory.php - - - - message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Factory\\\\ConfigurableExportParametersFactory\\:\\:getMissingRequiredOptions\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#" + message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Exporter\\\\Exporter\\:\\:getContentForGivenLanguages\\(\\) return type has no value type specified in iterable type array\\.$#" count: 1 - path: src/lib/Factory/ConfigurableExportParametersFactory.php + path: src/lib/Exporter/Exporter.php - - message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Factory\\\\ConfigurableExportParametersFactory\\:\\:getMissingRequiredOptions\\(\\) return type has no value type specified in iterable type array\\.$#" + message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Exporter\\\\Exporter\\:\\:run\\(\\) return type has no value type specified in iterable type array\\.$#" count: 1 - path: src/lib/Factory/ConfigurableExportParametersFactory.php + path: src/lib/Exporter/Exporter.php - - message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Factory\\\\ExportParametersFactory\\:\\:create\\(\\) has parameter \\$properties with no value type specified in iterable type array\\.$#" + message: "#^Parameter \\#2 \\$parameters of method EzSystems\\\\EzRecommendationClient\\\\Service\\\\ContentServiceInterface\\:\\:fetchContent\\(\\) expects EzSystems\\\\EzRecommendationClient\\\\Value\\\\ExportParameters, Ibexa\\\\Personalization\\\\Value\\\\Export\\\\Parameters given\\.$#" count: 1 - path: src/lib/Factory/ExportParametersFactory.php + path: src/lib/Exporter/Exporter.php - - message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Factory\\\\ExportParametersFactoryInterface\\:\\:create\\(\\) has parameter \\$properties with no value type specified in iterable type array\\.$#" + message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Exporter\\\\ExporterInterface\\:\\:run\\(\\) return type has no value type specified in iterable type array\\.$#" count: 1 - path: src/lib/Factory/ExportParametersFactoryInterface.php + path: src/lib/Exporter/ExporterInterface.php - message: "#^Parameter \\#1 \\$str of function strtolower expects string, string\\|null given\\.$#" @@ -1100,11 +1020,6 @@ parameters: count: 1 path: src/lib/SPI/Content.php - - - message: "#^Method EzSystems\\\\EzRecommendationClient\\\\SPI\\\\ExportParametersFactoryDecorator\\:\\:create\\(\\) has parameter \\$properties with no value type specified in iterable type array\\.$#" - count: 1 - path: src/lib/SPI/ExportParametersFactoryDecorator.php - - message: "#^Property EzSystems\\\\EzRecommendationClient\\\\SPI\\\\Notification\\:\\:\\$events type has no value type specified in iterable type array\\.$#" count: 1 @@ -1280,11 +1195,6 @@ parameters: count: 1 path: src/lib/Service/ExportNotificationService.php - - - message: "#^Cannot cast Symfony\\\\Component\\\\Validator\\\\ConstraintViolationListInterface to string\\.$#" - count: 1 - path: src/lib/Service/ExportService.php - - message: "#^Property EzSystems\\\\EzRecommendationClient\\\\Service\\\\ExportService\\:\\:\\$notificationService \\(EzSystems\\\\EzRecommendationClient\\\\Service\\\\ExportNotificationService\\) does not accept EzSystems\\\\EzRecommendationClient\\\\Service\\\\NotificationService\\.$#" count: 1 @@ -2005,31 +1915,6 @@ parameters: count: 1 path: tests/lib/Service/EventNotificationServiceTest.php - - - message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Tests\\\\Service\\\\ExportNotificationServiceTest\\:\\:testCreateExportNotification\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/lib/Service/ExportNotificationServiceTest.php - - - - message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Tests\\\\Service\\\\ExportNotificationServiceTest\\:\\:testCreateInstanceOfEventNotificationService\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/lib/Service/ExportNotificationServiceTest.php - - - - message: "#^Method EzSystems\\\\EzRecommendationClient\\\\Tests\\\\Service\\\\ExportNotificationServiceTest\\:\\:testSendNotification\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/lib/Service/ExportNotificationServiceTest.php - - - - message: "#^Property EzSystems\\\\EzRecommendationClient\\\\Tests\\\\Service\\\\ExportNotificationServiceTest\\:\\:\\$notificationOptions type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/lib/Service/ExportNotificationServiceTest.php - - - - message: "#^Property EzSystems\\\\EzRecommendationClient\\\\Tests\\\\Service\\\\ExportNotificationServiceTest\\:\\:\\$urls type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/lib/Service/ExportNotificationServiceTest.php - - message: "#^Property EzSystems\\\\EzRecommendationClient\\\\Tests\\\\Service\\\\NotificationServiceTest\\:\\:\\$basicNotificationOptions type has no value type specified in iterable type array\\.$#" count: 1 diff --git a/phpunit.xml b/phpunit.xml index 6dddc399..96dec4e6 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -19,4 +19,9 @@ + + + + + diff --git a/src/bundle/Command/ExportCommand.php b/src/bundle/Command/ExportCommand.php index d6c6bd0b..db458904 100644 --- a/src/bundle/Command/ExportCommand.php +++ b/src/bundle/Command/ExportCommand.php @@ -6,12 +6,13 @@ */ declare(strict_types=1); -namespace EzSystems\EzRecommendationClientBundle\Command; +namespace Ibexa\Bundle\Personalization\Command; use eZ\Bundle\EzPublishCoreBundle\Command\BackwardCompatibleCommand; -use EzSystems\EzRecommendationClient\Factory\ExportParametersFactoryInterface; use EzSystems\EzRecommendationClient\Http\HttpEnvironmentInterface; use EzSystems\EzRecommendationClient\Service\ExportServiceInterface; +use Ibexa\Personalization\Export\Input\CommandInputResolverInterface; +use Ibexa\Personalization\Factory\Export\ParametersFactoryInterface; use Psr\Log\LoggerInterface; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; @@ -25,53 +26,45 @@ final class ExportCommand extends Command implements BackwardCompatibleCommand { public const SUCCESS = 0; - /** @var \EzSystems\EzRecommendationClient\Service\ExportServiceInterface */ - private $exportService; + private ExportServiceInterface $exportService; - /** @var \EzSystems\EzRecommendationClient\Http\HttpEnvironmentInterface */ - private $httpEnvironment; + private HttpEnvironmentInterface $httpEnvironment; - /** @var \Psr\Log\LoggerInterface */ - private $logger; + private LoggerInterface $logger; - /** @var \EzSystems\EzRecommendationClient\Factory\ExportParametersFactoryInterface */ - private $exportParametersFactory; + private CommandInputResolverInterface $inputResolver; + + private ParametersFactoryInterface $exportParametersFactory; public function __construct( ExportServiceInterface $exportService, HttpEnvironmentInterface $httpEnvironment, LoggerInterface $logger, - ExportParametersFactoryInterface $exportParametersFactory + CommandInputResolverInterface $inputResolver, + ParametersFactoryInterface $exportParametersFactory ) { parent::__construct(); $this->exportService = $exportService; $this->httpEnvironment = $httpEnvironment; $this->logger = $logger; + $this->inputResolver = $inputResolver; $this->exportParametersFactory = $exportParametersFactory; } - /** - * {@inheritdoc} - */ - protected function configure() + protected function configure(): void { $this ->setName('ibexa:recommendation:run-export') ->setAliases(['ezrecommendation:export:run']) ->setDescription('Run export to files.') - ->addOption('webHook', null, InputOption::VALUE_OPTIONAL, 'Guzzle Client base_uri parameter, will be used to send recommendation data') + ->addOption('customer-id', null, InputOption::VALUE_REQUIRED, 'Personalization customer id') + ->addOption('license-key', null, InputOption::VALUE_REQUIRED, 'Personalization license key') + ->addOption('web-hook', null, InputOption::VALUE_OPTIONAL, 'Recommendation engine URI used to send recommendation data') ->addOption('host', null, InputOption::VALUE_OPTIONAL, 'Host used in exportDownload url for notifier in export feature') - ->addOption('customerId', null, InputOption::VALUE_OPTIONAL, 'Your eZ Recommendation customer ID') - ->addOption('licenseKey', null, InputOption::VALUE_OPTIONAL, 'Your eZ Recommendation license key') - ->addOption('pageSize', null, InputOption::VALUE_OPTIONAL, '', 500) - ->addOption('page', null, InputOption::VALUE_OPTIONAL, '', 1) - ->addOption('path', null, InputOption::VALUE_OPTIONAL, 'A string of subtree path, eg: /1/2/') - ->addOption('hidden', null, InputOption::VALUE_OPTIONAL, 'If set to 1 - Criterion Visibility: VISIBLE will be used', 0) - ->addOption('image', null, InputOption::VALUE_OPTIONAL, 'Image_variations used for images') - ->addOption('contentTypeIdList', null, InputOption::VALUE_REQUIRED, 'List of Content Types ID') - ->addOption('fields', null, InputOption::VALUE_OPTIONAL, 'List of the fields, eg: title, description') - ; + ->addOption('item-type-identifier-list', null, InputOption::VALUE_REQUIRED, 'List of item types identifiers') + ->addOption('languages', null, InputOption::VALUE_REQUIRED, 'List of items languages') + ->addOption('page-size', null, InputOption::VALUE_OPTIONAL, '', '500'); } /** @@ -84,14 +77,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int date_default_timezone_set('UTC'); - $options = array_diff_key( - $input->getOptions(), - $this->getApplication()->getDefinition()->getOptions() - ); - $options['siteaccess'] = $input->getOption('siteaccess'); - - $this->exportService->process( - $this->exportParametersFactory->create($options), + $this->exportService->runExport( + $this->exportParametersFactory->create( + $this->inputResolver->resolve( + $input, $this->getApplication() + ), + ParametersFactoryInterface::COMMAND_TYPE + ), $output ); diff --git a/src/bundle/Controller/ExportController.php b/src/bundle/Controller/ExportController.php index b56fc757..1599a9da 100644 --- a/src/bundle/Controller/ExportController.php +++ b/src/bundle/Controller/ExportController.php @@ -60,7 +60,11 @@ public function downloadAction(string $filePath): Response $response->headers->set('Content-Type', 'mime/type'); $response->headers->set('Content-Disposition', 'attachment;filename="' . $filePath); - $response->headers->set('Content-Length', filesize($this->fileManager->getDir() . $filePath)); + $fileSize = filesize($this->fileManager->getDir() . $filePath); + + if (is_int($fileSize)) { + $response->headers->set('Content-Length', (string)$fileSize); + } $response->setContent($content); diff --git a/src/bundle/Resources/config/services.yaml b/src/bundle/Resources/config/services.yaml index 75700874..49b9f998 100644 --- a/src/bundle/Resources/config/services.yaml +++ b/src/bundle/Resources/config/services.yaml @@ -8,6 +8,7 @@ imports: - { resource: services/converters.yaml } - { resource: services/credentials_checker.yaml } - { resource: services/events.yaml } + - { resource: services/export.yaml } - { resource: services/exporter.yaml } - { resource: services/factory.yaml } - { resource: services/fields.yaml } diff --git a/src/bundle/Resources/config/services/commands.yaml b/src/bundle/Resources/config/services/commands.yaml index 49a570e6..b3ecf103 100644 --- a/src/bundle/Resources/config/services/commands.yaml +++ b/src/bundle/Resources/config/services/commands.yaml @@ -4,18 +4,12 @@ services: autoconfigure: true public: false - EzSystems\EzRecommendationClientBundle\Command\: - resource: '../../../../src/bundle/Command/*' - - EzSystems\EzRecommendationClientBundle\Command\ExportCommand: - arguments: - $exportParametersFactory: '@EzSystems\EzRecommendationClient\Factory\ConfigurableExportParametersFactory' - + Ibexa\Bundle\Personalization\Command\ExportCommand: tags: - { name: console.command } - - { name: monolog.logger, channel: ezrecommendation } + - { name: monolog.logger, channel: ibexa-recommendation } EzSystems\EzRecommendationClientBundle\Command\UserAttributesUpdateCommand: tags: - { name: console.command } - - { name: monolog.logger, channel: ezrecommendation } + - { name: monolog.logger, channel: ibexa-recommendation } diff --git a/src/bundle/Resources/config/services/export.yaml b/src/bundle/Resources/config/services/export.yaml new file mode 100644 index 00000000..16053fd6 --- /dev/null +++ b/src/bundle/Resources/config/services/export.yaml @@ -0,0 +1,10 @@ +services: + _defaults: + autowire: true + autoconfigure: true + public: false + + Ibexa\Personalization\Export\Input\CommandInputResolver: ~ + + Ibexa\Personalization\Export\Input\CommandInputResolverInterface: + '@Ibexa\Personalization\Export\Input\CommandInputResolver' diff --git a/src/bundle/Resources/config/services/factory.yaml b/src/bundle/Resources/config/services/factory.yaml index 87651350..b2720b4f 100644 --- a/src/bundle/Resources/config/services/factory.yaml +++ b/src/bundle/Resources/config/services/factory.yaml @@ -4,12 +4,22 @@ services: autoconfigure: true public: false - EzSystems\EzRecommendationClient\Factory\: - resource: '../../../../src/lib/Factory/*' + EzSystems\EzRecommendationClient\Factory\EzRecommendationClientAPIFactory: ~ - EzSystems\EzRecommendationClient\Factory\ExportParametersFactory: ~ + EzSystems\EzRecommendationClient\Factory\FakeRequestFactory: ~ - EzSystems\EzRecommendationClient\Factory\ConfigurableExportParametersFactory: + EzSystems\EzRecommendationClient\Factory\RequestFactoryInterface: + '@EzSystems\EzRecommendationClient\Factory\FakeRequestFactory' + + EzSystems\EzRecommendationClient\Factory\TokenFactory: ~ + + EzSystems\EzRecommendationClient\Factory\TokenFactoryInterface: + '@EzSystems\EzRecommendationClient\Factory\TokenFactory' + + Ibexa\Personalization\Factory\Export\ParametersFactory: arguments: - $innerService: '@EzSystems\EzRecommendationClient\Factory\ExportParametersFactory' - $credentialsResolver: '@EzSystems\EzRecommendationClient\Config\ExportCredentialsResolver' + $siteAccessService: '@ezpublish.siteaccess_service' + $credentialsResolver: '@EzSystems\EzRecommendationClient\Config\EzRecommendationClientCredentialsResolver' + + Ibexa\Personalization\Factory\Export\ParametersFactoryInterface: + '@Ibexa\Personalization\Factory\Export\ParametersFactory' diff --git a/src/bundle/Resources/config/services/values.yaml b/src/bundle/Resources/config/services/values.yaml index f4b7eb52..af6aedaf 100644 --- a/src/bundle/Resources/config/services/values.yaml +++ b/src/bundle/Resources/config/services/values.yaml @@ -4,9 +4,6 @@ services: autoconfigure: true public: false - EzSystems\EzRecommendationClient\Value\: - resource: '../../../../src/lib/Value/*' - EzSystems\EzRecommendationClient\Value\ContentDataVisitor: tags: - { name: ezpublish_rest.output.value_object_visitor, type: EzSystems\EzRecommendationClient\Value\ContentData } diff --git a/src/lib/Exception/CredentialsNotFoundException.php b/src/lib/Exception/CredentialsNotFoundException.php index e9e87eba..373cb7d2 100644 --- a/src/lib/Exception/CredentialsNotFoundException.php +++ b/src/lib/Exception/CredentialsNotFoundException.php @@ -8,10 +8,22 @@ namespace EzSystems\EzRecommendationClient\Exception; -class CredentialsNotFoundException extends NotFoundException +use Throwable; + +final class CredentialsNotFoundException extends NotFoundException { - public function __construct(int $code = 0, ?Throwable $previous = null) + public function __construct(?string $siteAccess = null, int $code = 0, Throwable $previous = null) { - parent::__construct('Credentials for recommendation client are not set', $code, $previous); + $message = 'Credentials for recommendation client are not set'; + + if (null !== $siteAccess) { + $message .= ' for siteAccess: ' . $siteAccess; + } + + parent::__construct( + $message, + $code, + $previous + ); } } diff --git a/src/lib/Exception/ExportCredentialsNotFoundException.php b/src/lib/Exception/ExportCredentialsNotFoundException.php deleted file mode 100644 index 986b9ccf..00000000 --- a/src/lib/Exception/ExportCredentialsNotFoundException.php +++ /dev/null @@ -1,13 +0,0 @@ - $missingParameters + */ + public function __construct(array $missingParameters, string $type, int $code = 0, Throwable $previous = null) + { + $parameters = []; + + if ($type === ParametersFactoryInterface::COMMAND_TYPE) { + foreach ($missingParameters as $parameter) { + $parameters[] = str_replace('_', '-', $parameter); + } + } else { + $parameters = $missingParameters; + } + + parent::__construct( + sprintf( + 'Required parameters: %s are missing', + implode(', ', $parameters) + ), + $code, + $previous + ); + } } diff --git a/src/lib/Export/Input/CommandInputResolver.php b/src/lib/Export/Input/CommandInputResolver.php new file mode 100644 index 00000000..e02b67b9 --- /dev/null +++ b/src/lib/Export/Input/CommandInputResolver.php @@ -0,0 +1,43 @@ +getOptions(); + $options = []; + $inputOptions = + null !== $application + ? array_diff_key($inputOptions, $application->getDefinition()->getOptions()) + : $inputOptions; + + foreach ($inputOptions as $optionKey => $optionValue) { + $options[str_replace('-', '_', $optionKey)] = $optionValue; + } + + /** + * @phpstan-var array{ + * item_type_identifier_list: string, + * languages: string, + * page_size: string, + * customer_id: ?string, + * license_key: ?string, + * siteaccess: ?string, + * web_hook: ?string, + * host: ?string, + * } $options + */ + return $options; + } +} diff --git a/src/lib/Export/Input/CommandInputResolverInterface.php b/src/lib/Export/Input/CommandInputResolverInterface.php new file mode 100644 index 00000000..d25bb555 --- /dev/null +++ b/src/lib/Export/Input/CommandInputResolverInterface.php @@ -0,0 +1,29 @@ +writeln(sprintf('Exporting %s content types', \count($parameters->contentTypeIdList))); + $output->writeln(sprintf('Exporting %s content types', \count($parameters->getItemTypeIdentifierList()))); - foreach ($parameters->contentTypeIdList as $id) { + foreach ($parameters->getItemTypeIdentifierList() as $id) { $contentTypeId = (int)$id; $urls[$contentTypeId] = $this->getContentForGivenLanguages($contentTypeId, $chunkDir, $parameters, $output); } @@ -87,7 +87,7 @@ public function run(ExportParameters $parameters, string $chunkDir, OutputInterf private function getContentForGivenLanguages( int $contentTypeId, string $chunkDir, - ExportParameters $parameters, + Parameters $parameters, OutputInterface $output): array { $contents = []; @@ -95,7 +95,14 @@ private function getContentForGivenLanguages( foreach ($parameters->languages as $lang) { $parameters->lang = $lang; - $count = $this->contentHelper->countContentItemsByContentTypeId($contentTypeId, $parameters->getProperties()); + $options = [ + 'lang' => $lang, + 'languages' => $parameters->getLanguages(), + 'pageSize' => $parameters->getPageSize(), + 'customerId' => $parameters->getCustomerId(), + 'siteaccess' => $parameters->getSiteaccess(), + ]; + $count = $this->contentHelper->countContentItemsByContentTypeId($contentTypeId, $options); $info = sprintf('Fetching %s items of contentTypeId %s (language: %s)', $count, $contentTypeId, $parameters->lang); $output->writeln($info); @@ -122,7 +129,7 @@ private function getContentForGivenLanguages( private function generateFileForContentType( int $contentTypeId, string $chunkPath, - ExportParameters $parameters, + Parameters $parameters, OutputInterface $output): void { $content = $this->repository->sudo( diff --git a/src/lib/Exporter/ExporterInterface.php b/src/lib/Exporter/ExporterInterface.php index d2427444..85d0949b 100644 --- a/src/lib/Exporter/ExporterInterface.php +++ b/src/lib/Exporter/ExporterInterface.php @@ -8,10 +8,10 @@ namespace EzSystems\EzRecommendationClient\Exporter; -use EzSystems\EzRecommendationClient\Value\ExportParameters; +use Ibexa\Personalization\Value\Export\Parameters; use Symfony\Component\Console\Output\OutputInterface; interface ExporterInterface { - public function run(ExportParameters $parameters, string $chunkDir, OutputInterface $output): array; + public function run(Parameters $parameters, string $chunkDir, OutputInterface $output): array; } diff --git a/src/lib/Factory/ConfigurableExportParametersFactory.php b/src/lib/Factory/ConfigurableExportParametersFactory.php deleted file mode 100644 index f1444417..00000000 --- a/src/lib/Factory/ConfigurableExportParametersFactory.php +++ /dev/null @@ -1,130 +0,0 @@ -credentialsResolver = $credentialsResolver; - $this->configResolver = $configResolver; - $this->siteAccessHelper = $siteAccessHelper; - - parent::__construct($innerService); - } - - /** - * {@inheritdoc} - * - * @throws \EzSystems\EzRecommendationClient\Exception\ExportCredentialsNotFoundException - * @throws \EzSystems\EzRecommendationClient\Exception\MissingExportParameterException - * @throws \eZ\Publish\Core\Base\Exceptions\NotFoundException - */ - public function create(array $properties = []): ExportParameters - { - if (!empty($this->getMissingRequiredOptions($properties))) { - throw new MissingExportParameterException(sprintf( - 'Required parameters %s are missing', - implode(', ', $this->getMissingRequiredOptions($properties)) - )); - } - - $properties['siteaccess'] = $properties['siteaccess'] ?? $this->getSiteAccess(); - - if (!isset($properties['customerId']) && !isset($properties['licenseKey'])) { - /** @var \EzSystems\EzRecommendationClient\Value\Config\ExportCredentials $credentials */ - $credentials = $this->credentialsResolver->getCredentials($properties['siteaccess']); - - if (!$this->credentialsResolver->hasCredentials()) { - throw new ExportCredentialsNotFoundException(sprintf( - 'Recommendation client export credentials are not set for siteAccess: %s', - $properties['siteaccess'] - )); - } - - $properties['customerId'] = $credentials->getLogin(); - $properties['licenseKey'] = $credentials->getPassword(); - } - - $properties['host'] = $properties['host'] ?? $this->getHostUri($properties['siteaccess']); - $properties['webHook'] = $properties['webHook'] ?? $this->getWebHook( - (int)$properties['customerId'], - $properties['siteaccess'] - ); - - return $this->innerService->create($properties); - } - - private function getSiteAccess(): string - { - return current($this->siteAccessHelper->getSiteAccesses()); - } - - private function getHostUri(string $siteAccess): string - { - return $this->configResolver->getParameter( - 'host_uri', - Parameters::NAMESPACE, - $siteAccess - ); - } - - private function getWebHook(int $customerId, string $siteAccess): string - { - return $this->configResolver->getParameter( - 'api.notifier.endpoint', - Parameters::NAMESPACE, - $siteAccess - ) . sprintf(Notifier::ENDPOINT_PATH, $customerId); - } - - private function getMissingRequiredOptions(array $options): array - { - $missingOptions = []; - - if (isset($options['customerId']) || isset($options['licenseKey'])) { - if (!isset($options['customerId'])) { - $missingOptions[] = 'customerId'; - } - - if (!isset($options['licenseKey'])) { - $missingOptions[] = 'licenseKey'; - } - - if (!isset($options['siteaccess'])) { - $missingOptions[] = 'siteaccess'; - } - } - - return $missingOptions; - } -} diff --git a/src/lib/Factory/Export/ParametersFactory.php b/src/lib/Factory/Export/ParametersFactory.php new file mode 100644 index 00000000..d1bcbb23 --- /dev/null +++ b/src/lib/Factory/Export/ParametersFactory.php @@ -0,0 +1,345 @@ +credentialsResolver = $credentialsResolver; + $this->configResolver = $configResolver; + $this->siteAccessService = $siteAccessService; + } + + /** + * @throws \EzSystems\EzRecommendationClient\Exception\MissingExportParameterException + * @throws \EzSystems\EzRecommendationClient\Exception\InvalidArgumentException + */ + public function create(array $options, string $type): Parameters + { + $this->exportParametersType = $type; + + return Parameters::fromArray( + $this->getExportParameters($options) + ); + } + + /** + * @phpstan-param array{ + * item_type_identifier_list: string, + * languages: string, + * page_size: string, + * customer_id: ?string, + * license_key: ?string, + * siteaccess: ?string, + * web_hook: ?string, + * host: ?string, + * } $options + * + * @phpstan-return array{ + * item_type_identifier_list: string, + * languages: string, + * page_size: string, + * customer_id: string, + * license_key: string, + * siteaccess: string, + * web_hook: string, + * host: string, + * } + * + * @throws \EzSystems\EzRecommendationClient\Exception\MissingExportParameterException + * @throws \EzSystems\EzRecommendationClient\Exception\InvalidArgumentException + */ + private function getExportParameters(array $options): array + { + if (isset($options['siteaccess']) && !$this->hasConfiguredSiteAccess($options['siteaccess'])) { + throw new InvalidArgumentException(sprintf( + 'SiteAccess %s doesn\'t exists', + $options['siteaccess'] + )); + } + + $configuration = $this->countConfiguredCustomerSettings() === 1 + ? $this->getCredentialsAndSiteAccessForSingleConfiguration($options) + : $this->getCredentialsAndSiteAccessForMultiCustomerConfiguration($options); + + $siteAccess = $configuration['siteaccess']; + $customerId = $configuration['customer_id']; + + return [ + 'customer_id' => $customerId, + 'license_key' => $configuration['license_key'], + 'siteaccess' => $configuration['siteaccess'], + 'item_type_identifier_list' => $options['item_type_identifier_list'], + 'languages' => $options['languages'], + 'host' => $options['host'] ?? $this->getHostUri($siteAccess), + 'web_hook' => $options['web_hook'] ?? $this->getWebHook( + (int)$customerId, + $siteAccess + ), + 'page_size' => $options['page_size'], + ]; + } + + private function hasConfiguredSiteAccess(string $siteAccessName): bool + { + foreach ($this->siteAccessService->getAll() as $siteAccess) { + if ($siteAccessName === $siteAccess->name) { + return true; + } + } + + return false; + } + + private function countConfiguredCustomerSettings(): int + { + $configuredCounter = 0; + + foreach ($this->siteAccessService->getAll() as $siteAccess) { + if ($this->credentialsResolver->hasCredentials($siteAccess->name)) { + ++$configuredCounter; + } + } + + return $configuredCounter; + } + + /** + * @phpstan-param array{ + * item_type_identifier_list: string, + * languages: string, + * page_size: string, + * customer_id: ?string, + * license_key: ?string, + * siteaccess: ?string, + * web_hook: ?string, + * host: ?string, + * } $options + * + * @phpstan-return array{ + * customer_id: string, + * license_key: string, + * siteaccess: string, + * } + * + * @throws \EzSystems\EzRecommendationClient\Exception\MissingExportParameterException + */ + private function getCredentialsAndSiteAccessForSingleConfiguration(array $options): array + { + if ( + (isset($options['customer_id']) || isset($options['license_key'])) + && $this->hasMissingRequiredOptions($options) + ) { + throw new MissingExportParameterException( + $this->getMissingRequiredOptions($options), + $this->exportParametersType + ); + } + + if (isset($options['customer_id'], $options['license_key'], $options['siteaccess'])) { + return [ + 'customer_id' => $options['customer_id'], + 'license_key' => $options['license_key'], + 'siteaccess' => $options['siteaccess'], + ]; + } + + return $this->getCredentialsAndSiteAccess(); + } + + /** + * @phpstan-return array{ + * customer_id: string, + * license_key: string, + * siteaccess: string, + * } + */ + private function getCredentialsAndSiteAccess(): array + { + $siteAccess = $this->getSingleConfiguredSiteAccess(); + $configuredCredentials = $this->getCredentialsForScope($siteAccess); + + return [ + 'customer_id' => $configuredCredentials['customer_id'], + 'license_key' => $configuredCredentials['license_key'], + 'siteaccess' => $siteAccess, + ]; + } + + private function getSingleConfiguredSiteAccess(): string + { + foreach ($this->siteAccessService->getAll() as $siteAccess) { + if ($this->credentialsResolver->hasCredentials($siteAccess->name)) { + return $siteAccess->name; + } + } + + throw new CredentialsNotFoundException(); + } + + /** + * @phpstan-return array{ + * customer_id: string, + * license_key: string, + * } + */ + private function getCredentialsForScope(string $siteAccess): array + { + if (!$this->credentialsResolver->hasCredentials($siteAccess)) { + throw new CredentialsNotFoundException($siteAccess); + } + + /** @var \EzSystems\EzRecommendationClient\Value\Config\EzRecommendationClientCredentials $credentials */ + $credentials = $this->credentialsResolver->getCredentials($siteAccess); + /** @var int $customerId */ + $customerId = $credentials->getCustomerId(); + /** @var string $licenseKey */ + $licenseKey = $credentials->getLicenseKey(); + + return [ + 'customer_id' => (string)$customerId, + 'license_key' => $licenseKey, + ]; + } + + /** + * @phpstan-param array{ + * item_type_identifier_list: string, + * languages: string, + * page_size: string, + * customer_id: ?string, + * license_key: ?string, + * siteaccess: ?string, + * web_hook: ?string, + * host: ?string, + * } $options + * + * @phpstan-return array{ + * customer_id: string, + * license_key: string, + * siteaccess: string, + * } + * + * @throws \EzSystems\EzRecommendationClient\Exception\MissingExportParameterException + */ + private function getCredentialsAndSiteAccessForMultiCustomerConfiguration(array $options): array + { + if ($this->hasMissingRequiredOptions($options)) { + throw new MissingExportParameterException( + $this->getMissingRequiredOptions($options), + $this->exportParametersType + ); + } + + /** @var string $customerId */ + $customerId = $options['customer_id']; + /** @var string $licenseKey */ + $licenseKey = $options['license_key']; + /** @var string $siteAccess */ + $siteAccess = $options['siteaccess']; + + return [ + 'customer_id' => $customerId, + 'license_key' => $licenseKey, + 'siteaccess' => $siteAccess, + ]; + } + + private function getHostUri(string $siteAccess): string + { + return $this->configResolver->getParameter( + self::HOST_URI_PARAMETER_NAME, + self::PARAMETERS_NAMESPACE, + $siteAccess + ); + } + + private function getWebHook(int $customerId, string $siteAccess): string + { + return $this->configResolver->getParameter( + self::NOTIFIER_ENDPOINT_PARAMETER_NAME, + self::PARAMETERS_NAMESPACE, + $siteAccess + ) . sprintf(Notifier::ENDPOINT_PATH, $customerId); + } + + /** + * @phpstan-param array{ + * item_type_identifier_list: string, + * languages: string, + * page_size: string, + * customer_id: ?string, + * license_key: ?string, + * siteaccess: ?string, + * web_hook: ?string, + * host: ?string, + * } $options + */ + private function hasMissingRequiredOptions(array $options): bool + { + return !empty($this->getMissingRequiredOptions($options)); + } + + /** + * Checks if one of the required option is missing. + * For single configuration user doesn't need to provide any of these options, + * but if one of them is provided then rest of it are needed. + * + * @phpstan-param array{ + * item_type_identifier_list: string, + * languages: string, + * page_size: string, + * customer_id: ?string, + * license_key: ?string, + * siteaccess: ?string, + * web_hook: ?string, + * host: ?string, + * } $options + * + * @return array + */ + private function getMissingRequiredOptions(array $options): array + { + return array_diff(self::REQUIRED_OPTIONS, array_keys( + array_filter($options, static function (?string $option = null): bool { + return null !== $option; + }) + )); + } +} diff --git a/src/lib/Factory/Export/ParametersFactoryInterface.php b/src/lib/Factory/Export/ParametersFactoryInterface.php new file mode 100644 index 00000000..1280f9b4 --- /dev/null +++ b/src/lib/Factory/Export/ParametersFactoryInterface.php @@ -0,0 +1,32 @@ +siteAccessHelper = $siteAccessHelper; - } - - public function create(array $properties = []): ExportParameters - { - $properties['contentTypeIdList'] = ParamsConverterHelper::getIdListFromString( - $properties['contentTypeIdList'] - ); - $properties['languages'] = $this->siteAccessHelper->getLanguages( - (int)$properties['customerId'], - $properties['siteaccess'] - ); - - isset($properties['fields']) ? ParamsConverterHelper::getArrayFromString($properties['fields']) : null; - - return new ExportParameters($properties); - } -} diff --git a/src/lib/Factory/ExportParametersFactoryInterface.php b/src/lib/Factory/ExportParametersFactoryInterface.php deleted file mode 100644 index 677c4d2b..00000000 --- a/src/lib/Factory/ExportParametersFactoryInterface.php +++ /dev/null @@ -1,21 +0,0 @@ -generateSubtreeCriteria((int)$options['customerId'], $options['siteaccess']); $query = new Query(); diff --git a/src/lib/Helper/SiteAccessHelper.php b/src/lib/Helper/SiteAccessHelper.php index eb25d785..31bf3372 100644 --- a/src/lib/Helper/SiteAccessHelper.php +++ b/src/lib/Helper/SiteAccessHelper.php @@ -10,7 +10,8 @@ use eZ\Publish\Core\Base\Exceptions\NotFoundException; use eZ\Publish\Core\MVC\ConfigResolverInterface; -use eZ\Publish\Core\MVC\Symfony\SiteAccess as CurrentSiteAccess; +use eZ\Publish\Core\MVC\Symfony\SiteAccess; +use eZ\Publish\Core\MVC\Symfony\SiteAccess\SiteAccessServiceInterface; /** * Provides utility to manipulate siteAccess. @@ -22,23 +23,22 @@ final class SiteAccessHelper /** @var \eZ\Publish\Core\MVC\ConfigResolverInterface */ private $configResolver; - /** @var \eZ\Publish\Core\MVC\Symfony\SiteAccess */ - private $siteAccess; - /** @var array */ private $siteAccessConfig; /** @var string */ private $defaultSiteAccessName; + private SiteAccessServiceInterface $siteAccessService; + public function __construct( ConfigResolverInterface $configResolver, - CurrentSiteAccess $siteAccess, + SiteAccessServiceInterface $siteAccessService, array $siteAccessConfig, string $defaultSiteAccessName = self::SYSTEM_DEFAULT_SITE_ACCESS_NAME ) { $this->configResolver = $configResolver; - $this->siteAccess = $siteAccess; + $this->siteAccessService = $siteAccessService; $this->siteAccessConfig = $siteAccessConfig; $this->defaultSiteAccessName = $defaultSiteAccessName; } @@ -51,7 +51,7 @@ public function getRootLocationBySiteAccessName(?string $siteAccessName): int return $this->configResolver->getParameter( 'content.tree_root.location_id', null, - $siteAccessName ?: $this->siteAccess->name + $siteAccessName ?: $this->getCurrentScope() ); } @@ -90,7 +90,7 @@ public function getLanguages(int $customerId, ?string $siteAccess): array public function getSiteAccessesByCustomerId(?int $customerId): array { if ($customerId === null) { - return [$this->siteAccess->name]; + return [$this->getCurrentScope()]; } $siteAccesses = []; @@ -131,7 +131,7 @@ public function getSiteAccesses(?int $customerId = null, ?string $siteAccess = n } elseif ($customerId) { $siteAccesses = $this->getSiteaccessesByCustomerId($customerId); } else { - $siteAccesses = [$this->siteAccess->name]; + $siteAccesses = [$this->getCurrentScope()]; } return $siteAccesses; @@ -181,6 +181,13 @@ public function isSiteAccessSameAsSystemDefault(string $siteAccessName): bool return $siteAccessName === self::SYSTEM_DEFAULT_SITE_ACCESS_NAME; } + private function getCurrentScope(): ?string + { + return null !== $this->siteAccessService->getCurrent() + ? $this->siteAccessService->getCurrent()->name + : null; + } + /** * Checks if customerId is configured with default siteAccess. */ diff --git a/src/lib/SPI/ExportParametersFactoryDecorator.php b/src/lib/SPI/ExportParametersFactoryDecorator.php deleted file mode 100644 index ffd59dec..00000000 --- a/src/lib/SPI/ExportParametersFactoryDecorator.php +++ /dev/null @@ -1,31 +0,0 @@ -innerService = $innerService; - } - - /** - * {@inheritdoc} - */ - public function create(array $properties = []): ExportParameters - { - return $this->innerService->create($properties); - } -} diff --git a/src/lib/Service/ExportNotificationService.php b/src/lib/Service/ExportNotificationService.php index ab49e008..2ede92f4 100644 --- a/src/lib/Service/ExportNotificationService.php +++ b/src/lib/Service/ExportNotificationService.php @@ -11,7 +11,7 @@ use EzSystems\EzRecommendationClient\Request\ExportNotifierRequest; use EzSystems\EzRecommendationClient\SPI\Notification; use EzSystems\EzRecommendationClient\Value\ExportNotification; -use EzSystems\EzRecommendationClient\Value\ExportParameters; +use Ibexa\Personalization\Value\Export\Parameters; use Psr\Http\Message\ResponseInterface; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -19,10 +19,14 @@ final class ExportNotificationService extends NotificationService { private const NOTIFICATION_ACTION_NAME = 'export'; - public function sendNotification(ExportParameters $parameters, array $urls, array $securedDirCredentials): ?ResponseInterface + public function sendNotification(Parameters $parameters, array $urls, array $securedDirCredentials): ?ResponseInterface { - $options = $parameters->getProperties(); - $options['events'] = $this->getNotificationEvents($urls, $securedDirCredentials); + $options = [ + 'events' => $this->getNotificationEvents($urls, $securedDirCredentials), + 'customerId' => $parameters->getCustomerId(), + 'licenseKey' => $parameters->getLicenseKey(), + 'webHook' => $parameters->getWebHook(), + ]; $resolver = new OptionsResolver(); $this->configureOptions($resolver); @@ -42,7 +46,7 @@ public function createNotification(array $options): Notification $notification->events = $options['events']; $notification->licenseKey = $options['licenseKey']; $notification->customerId = (int)$options['customerId']; - $notification->transaction = (new \DateTime())->format('YmdHis') . rand(111, 999); + $notification->transaction = date('YmdHis') . random_int(111, 999); $notification->endPointUri = $options['webHook']; return $notification; diff --git a/src/lib/Service/ExportService.php b/src/lib/Service/ExportService.php index 6bbe5bdb..624a0848 100644 --- a/src/lib/Service/ExportService.php +++ b/src/lib/Service/ExportService.php @@ -9,75 +9,41 @@ namespace EzSystems\EzRecommendationClient\Service; use EzSystems\EzRecommendationClient\Config\CredentialsResolverInterface; -use EzSystems\EzRecommendationClient\Exception\InvalidArgumentException; use EzSystems\EzRecommendationClient\Exporter\ExporterInterface; use EzSystems\EzRecommendationClient\File\FileManagerInterface; -use EzSystems\EzRecommendationClient\Value\ExportParameters; +use Ibexa\Personalization\Value\Export\Parameters; use Psr\Log\LoggerInterface; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Validator\Validator\ValidatorInterface; final class ExportService implements ExportServiceInterface { - /** @var \EzSystems\EzRecommendationClient\Exporter\ExporterInterface */ - private $exporter; - - /** @var \Symfony\Component\Validator\Validator\ValidatorInterface */ - private $validator; + private ExporterInterface $exporter; /** @var \Psr\Log\LoggerInterface */ - private $logger; + private LoggerInterface $logger; - /** @var \EzSystems\EzRecommendationClient\Config\CredentialsResolverInterface */ - private $credentialsResolver; + private CredentialsResolverInterface $credentialsResolver; - /** @var \EzSystems\EzRecommendationClient\File\FileManagerInterface */ - private $fileManager; + private FileManagerInterface $fileManager; /** @var \EzSystems\EzRecommendationClient\Service\ExportNotificationService */ - private $notificationService; + private ExportNotificationService $notificationService; public function __construct( ExporterInterface $exporter, - ValidatorInterface $validator, LoggerInterface $logger, CredentialsResolverInterface $credentialsResolver, FileManagerInterface $fileManager, NotificationService $notificationService ) { $this->exporter = $exporter; - $this->validator = $validator; $this->logger = $logger; $this->credentialsResolver = $credentialsResolver; $this->fileManager = $fileManager; $this->notificationService = $notificationService; } - /** - * {@inheritdoc} - * - * @throws \Exception - */ - public function process(ExportParameters $parameters, OutputInterface $output): void - { - $errors = $this->validator->validate($parameters); - - if (\count($errors) > 0) { - $errors = (string)$errors; - - $output->write($errors); - $this->logger->error($errors); - - throw new InvalidArgumentException($errors); - } - - $this->runExport($parameters, $output); - } - - /** - * @throws \Exception - */ - private function runExport(ExportParameters $parameters, OutputInterface $output): void + public function runExport(Parameters $parameters, OutputInterface $output): void { try { $chunkDir = $this->fileManager->createChunkDir(); diff --git a/src/lib/Service/ExportServiceInterface.php b/src/lib/Service/ExportServiceInterface.php index 399be34e..7f7ba44f 100644 --- a/src/lib/Service/ExportServiceInterface.php +++ b/src/lib/Service/ExportServiceInterface.php @@ -8,10 +8,10 @@ namespace EzSystems\EzRecommendationClient\Service; -use EzSystems\EzRecommendationClient\Value\ExportParameters; +use Ibexa\Personalization\Value\Export\Parameters; use Symfony\Component\Console\Output\OutputInterface; interface ExportServiceInterface { - public function process(ExportParameters $parameters, OutputInterface $output): void; + public function runExport(Parameters $parameters, OutputInterface $output): void; } diff --git a/src/lib/Service/Notification/NotificationServiceInterface.php b/src/lib/Service/Notification/NotificationServiceInterface.php new file mode 100644 index 00000000..87490325 --- /dev/null +++ b/src/lib/Service/Notification/NotificationServiceInterface.php @@ -0,0 +1,17 @@ + */ + public array $itemTypeIdentifierList; + + /** @var array */ + public array $languages; + + public string $siteaccess; + + public string $webHook; + + public string $host; + + public int $pageSize; + + /** + * @param array $itemTypeIdentifierList + * @param array $languages + */ + private function __construct( + string $customerId, + string $licenseKey, + array $itemTypeIdentifierList, + array $languages, + string $siteaccess, + string $webHook, + string $host, + int $pageSize + ) { + $this->customerId = $customerId; + $this->licenseKey = $licenseKey; + $this->itemTypeIdentifierList = $itemTypeIdentifierList; + $this->languages = $languages; + $this->siteaccess = $siteaccess; + $this->webHook = $webHook; + $this->host = $host; + $this->pageSize = $pageSize; + } + + public function getCustomerId(): string + { + return $this->customerId; + } + + public function getLicenseKey(): string + { + return $this->licenseKey; + } + + /** + * @return array + */ + public function getItemTypeIdentifierList(): array + { + return $this->itemTypeIdentifierList; + } + + /** + * @return array + */ + public function getLanguages(): array + { + return $this->languages; + } + + public function getSiteaccess(): string + { + return $this->siteaccess; + } + + public function getWebHook(): string + { + return $this->webHook; + } + + public function getHost(): string + { + return $this->host; + } + + public function getPageSize(): int + { + return $this->pageSize; + } + + /** + * @phpstan-param array{ + * customer_id: string, + * license_key: string, + * item_type_identifier_list: string, + * languages: string, + * siteaccess: string, + * web_hook: string, + * host: string, + * page_size: string, + * } $properties + */ + public static function fromArray(array $properties): self + { + return new self( + $properties['customer_id'], + $properties['license_key'], + ParamsConverterHelper::getArrayFromString($properties['item_type_identifier_list']), + ParamsConverterHelper::getArrayFromString($properties['languages']), + $properties['siteaccess'], + $properties['web_hook'], + $properties['host'], + (int)$properties['page_size'], + ); + } +} diff --git a/tests/bundle/Command/AbstractCommandTestCase.php b/tests/bundle/Command/AbstractCommandTestCase.php new file mode 100644 index 00000000..b119986b --- /dev/null +++ b/tests/bundle/Command/AbstractCommandTestCase.php @@ -0,0 +1,31 @@ +command = $application->find(static::getCommandName()); + $this->commandTester = new CommandTester($this->command); + } + + abstract protected static function getCommandName(): string; +} diff --git a/tests/bundle/Command/ExportCommandTest.php b/tests/bundle/Command/ExportCommandTest.php new file mode 100644 index 00000000..6bbba23d --- /dev/null +++ b/tests/bundle/Command/ExportCommandTest.php @@ -0,0 +1,81 @@ +expectException(InvalidArgumentException::class); + $this->expectExceptionMessage( + sprintf('SiteAccess %s doesn\'t exist', $siteAccess) + ); + $this->commandTester->execute( + [ + '--siteaccess' => $siteAccess, + ] + ); + } + + /** + * @param array $parameters + * + * @dataProvider provideForTestCommandThrowExceptionWhenRequiredParametersAreMissing + */ + public function testThrowExceptionWhenRequiredParametersAreMissing( + array $parameters, + string $expectExceptionMessage + ): void { + $this->expectException(MissingExportParameterException::class); + $this->expectExceptionMessage($expectExceptionMessage); + $this->commandTester->execute($parameters); + } + + /** + * @return array, string}>. + */ + public function provideForTestCommandThrowExceptionWhenRequiredParametersAreMissing(): array + { + return [ + [ + [ + '--item-type-identifier-list' => 'product, article, blog_post', + '--languages=eng-GB', + '--customer-id' => '12345', + ], + 'Required parameters: license-key, siteaccess are missing', + ], + [ + [ + '--item-type-identifier-list' => 'product, article, blog_post', + '--languages=eng-GB', + '--license-key' => '12345-12345-12345-12345', + ], + 'Required parameters: customer-id, siteaccess are missing', + ], + [ + [ + '--item-type-identifier-list' => 'product, article, blog_post', + '--languages=eng-GB', + '--siteaccess' => 'first_siteaccess', + ], + 'Required parameters: customer-id, license-key are missing', + ], + ]; + } +} diff --git a/tests/lib/Export/Input/CommandInputResolverTest.php b/tests/lib/Export/Input/CommandInputResolverTest.php new file mode 100644 index 00000000..3126f035 --- /dev/null +++ b/tests/lib/Export/Input/CommandInputResolverTest.php @@ -0,0 +1,74 @@ +inputResolver = new CommandInputResolver(); + $this->input = $this->createMock(InputInterface::class); + $this->application = $this->createMock(Application::class); + } + + public function testResolve(): void + { + $this->input + ->expects(self::once()) + ->method('getOptions') + ->willReturn( + [ + 'customer-id' => 1234, + 'item-type-id' => 'product', + 'host' => null, + 'help' => false, + 'version' => false, + ] + ); + + $this->application + ->expects(self::once()) + ->method('getDefinition') + ->willReturn( + new InputDefinition( + [ + new InputArgument('command'), + new InputOption('help'), + new InputOption('version'), + ] + ) + ); + + self::assertEquals( + [ + 'customer_id' => 1234, + 'item_type_id' => 'product', + 'host' => null, + ], + $this->inputResolver->resolve($this->input, $this->application) + ); + } +} diff --git a/tests/lib/Factory/Export/ParametersFactoryTest.php b/tests/lib/Factory/Export/ParametersFactoryTest.php new file mode 100644 index 00000000..debefd5a --- /dev/null +++ b/tests/lib/Factory/Export/ParametersFactoryTest.php @@ -0,0 +1,255 @@ +credentialsResolver = $this->createMock(CredentialsResolverInterface::class); + $this->configResolver = $this->createMock(ConfigResolverInterface::class); + $this->siteAccessService = $this->createMock(SiteAccessServiceInterface::class); + $this->parametersFactory = new ParametersFactory( + $this->credentialsResolver, + $this->configResolver, + $this->siteAccessService, + ); + $this->options = [ + 'customer_id' => '12345', + 'license_key' => '12345-12345-12345-12345', + 'siteaccess' => 'test', + 'item_type_identifier_list' => 'article, product, blog', + 'languages' => 'eng-GB', + 'web_hook' => 'https://reco-engine.com/api/12345/items', + 'host' => 'https://127.0.0.1', + 'page_size' => '500', + ]; + } + + /** + * @throws \EzSystems\EzRecommendationClient\Exception\MissingExportParameterException + */ + public function testCreateFromAllOptions(): void + { + $this->configureSiteAccessServiceToReturnAllSiteAccesses(); + + self::assertEquals( + Parameters::fromArray($this->options), + $this->parametersFactory->create($this->options, ParametersFactoryInterface::COMMAND_TYPE) + ); + } + + public function testCreateWithAutocomplete(): void + { + $siteAccess = 'test'; + $options = [ + 'customer_id' => null, + 'license_key' => null, + 'siteaccess' => null, + 'item_type_identifier_list' => 'article, product, blog', + 'languages' => 'eng-GB', + 'page_size' => '500', + 'web_hook' => null, + 'host' => null, + ]; + + $this->credentialsResolver + ->expects(self::atLeastOnce()) + ->method('hasCredentials') + ->with($siteAccess) + ->willReturn(true); + + $this->siteAccessService + ->expects(self::atLeastOnce()) + ->method('getAll') + ->willReturn( + [ + new SiteAccess($siteAccess), + ] + ); + + $this->credentialsResolver + ->expects(self::once()) + ->method('getCredentials') + ->with($siteAccess) + ->willReturn(new EzRecommendationClientCredentials( + 12345, + '12345-12345-12345-12345' + )); + + $this->configureConfigResolverToReturnHostUriAndApiNotifierUri($siteAccess); + + self::assertEquals( + Parameters::fromArray($this->options), + $this->parametersFactory->create($options, ParametersFactoryInterface::COMMAND_TYPE) + ); + } + + public function testCreateForSingleConfiguration(): void + { + $siteAccess = 'test'; + $options = [ + 'customer_id' => '12345', + 'license_key' => '12345-12345-12345-12345', + 'siteaccess' => $siteAccess, + 'item_type_identifier_list' => 'article, product, blog', + 'languages' => 'eng-GB', + 'page_size' => '500', + 'web_hook' => null, + 'host' => null, + ]; + + $this->siteAccessService + ->method('getAll') + ->willReturn( + [ + new SiteAccess($siteAccess), + ] + ); + + $this->credentialsResolver + ->expects(self::once()) + ->method('hasCredentials') + ->with($siteAccess) + ->willReturn(true); + + $this->configureConfigResolverToReturnHostUriAndApiNotifierUri($siteAccess); + + self::assertEquals( + Parameters::fromArray($this->options), + $this->parametersFactory->create($options, ParametersFactoryInterface::COMMAND_TYPE) + ); + } + + public function testCreateForMultiCustomerConfiguration(): void + { + $firstSiteAccess = 'test'; + $secondSiteAccess = 'second_siteaccess'; + + $options = [ + 'customer_id' => '12345', + 'license_key' => '12345-12345-12345-12345', + 'siteaccess' => $firstSiteAccess, + 'item_type_identifier_list' => 'article, product, blog', + 'languages' => 'eng-GB', + 'page_size' => '500', + 'web_hook' => null, + 'host' => null, + ]; + + $this->configureSiteAccessServiceToReturnAllSiteAccesses(); + + $this->credentialsResolver + ->expects(self::at(0)) + ->method('hasCredentials') + ->with($firstSiteAccess) + ->willReturn(true); + + $this->credentialsResolver + ->expects(self::at(1)) + ->method('hasCredentials') + ->with($secondSiteAccess) + ->willReturn(true); + + $this->configureConfigResolverToReturnHostUriAndApiNotifierUri($firstSiteAccess); + + self::assertEquals( + Parameters::fromArray($this->options), + $this->parametersFactory->create($options, ParametersFactoryInterface::COMMAND_TYPE) + ); + } + + /** + * @throws \EzSystems\EzRecommendationClient\Exception\MissingExportParameterException + */ + public function testThrowExportCredentialsNotFoundException(): void + { + $siteAccess = 'invalid'; + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage(sprintf('SiteAccess %s doesn\'t exists', $siteAccess)); + + $this->configureSiteAccessServiceToReturnAllSiteAccesses(); + + $this->parametersFactory->create( + [ + 'customer_id' => null, + 'license_key' => null, + 'siteaccess' => $siteAccess, + 'item_type_identifier_list' => 'article, product, blog', + 'languages' => 'eng-GB', + 'page_size' => '500', + 'web_hook' => null, + 'host' => null, + ], + ParametersFactoryInterface::COMMAND_TYPE + ); + } + + private function configureSiteAccessServiceToReturnAllSiteAccesses(): void + { + $this->siteAccessService + ->method('getAll') + ->willReturn( + [ + new SiteAccess('test'), + new SiteAccess('second_siteaccess'), + ] + ); + } + + private function configureConfigResolverToReturnHostUriAndApiNotifierUri(string $siteAccess): void + { + $this->configResolver + ->expects(self::atLeastOnce()) + ->method('getParameter') + ->willReturnMap( + [ + ['host_uri', 'ezrecommendation', $siteAccess, 'https://127.0.0.1'], + ['api.notifier.endpoint', 'ezrecommendation', $siteAccess, 'https://reco-engine.com'], + ] + ); + } +} diff --git a/tests/lib/Helper/SiteAccessHelperTest.php b/tests/lib/Helper/SiteAccessHelperTest.php index b28cf436..59efd679 100644 --- a/tests/lib/Helper/SiteAccessHelperTest.php +++ b/tests/lib/Helper/SiteAccessHelperTest.php @@ -9,7 +9,9 @@ namespace EzSystems\EzRecommendationClient\Tests\Helper; use eZ\Publish\Core\Base\Exceptions\NotFoundException; -use eZ\Publish\Core\MVC\Symfony\SiteAccess as CurrentSiteAccess; +use eZ\Publish\Core\MVC\ConfigResolverInterface; +use eZ\Publish\Core\MVC\Symfony\SiteAccess; +use eZ\Publish\Core\MVC\Symfony\SiteAccess\SiteAccessServiceInterface; use EzSystems\EzRecommendationClient\Helper\SiteAccessHelper; use PHPUnit\Framework\TestCase; @@ -18,27 +20,33 @@ class SiteAccessHelperTest extends TestCase /** @var \PHPUnit\Framework\MockObject\MockObject|\eZ\Publish\Core\MVC\ConfigResolverInterface */ private $configResolver; + /** @var \eZ\Publish\Core\MVC\Symfony\SiteAccess\SiteAccessServiceInterface|\PHPUnit\Framework\MockObject\MockObject */ + private SiteAccessServiceInterface $siteAccessService; + public function setUp(): void { parent::setUp(); - $this->configResolver = $this->getMockBuilder('eZ\Publish\Core\MVC\ConfigResolverInterface')->getMock(); + $this->configResolver = $this->createMock(ConfigResolverInterface::class); + $this->siteAccessService = $this->createMock(SiteAccessServiceInterface::class); } public function testGetRootLocationBySiteAccessNameWithoutParameterSpecified() { + $this->siteAccessService + ->expects(self::atLeastOnce()) + ->method('getCurrent') + ->willReturn(new SiteAccess('foo', 'test')); + $this->configResolver ->expects($this->once()) ->method('getParameter') ->with($this->equalTo('content.tree_root.location_id')) - ->willReturn(123) - ; - - $siteAccess = new CurrentSiteAccess('foo', 'test'); + ->willReturn(123); $siteAccessHelper = new SiteAccessHelper( $this->configResolver, - $siteAccess, + $this->siteAccessService, [], 'default' ); @@ -54,14 +62,11 @@ public function testGetRootLocationBySiteAccessName() ->expects($this->once()) ->method('getParameter') ->with($this->equalTo('content.tree_root.location_id'), null, 'foo') - ->willReturn(123) - ; - - $siteAccess = new CurrentSiteAccess('foo', 'test'); + ->willReturn(123); $siteAccessHelper = new SiteAccessHelper( $this->configResolver, - $siteAccess, + $this->siteAccessService, [], 'default' ); @@ -82,21 +87,17 @@ public function testGetRootLocationsBySiteAccesses() ->expects($this->at(0)) ->method('getParameter') ->with($this->equalTo('content.tree_root.location_id'), null, 'abc') - ->willReturn(1) - ; + ->willReturn(1); $this->configResolver ->expects($this->at(1)) ->method('getParameter') ->with($this->equalTo('content.tree_root.location_id'), null, 'cde') - ->willReturn(2) - ; - - $siteAccess = new CurrentSiteAccess('foo', 'test'); + ->willReturn(2); $siteAccessHelper = new SiteAccessHelper( $this->configResolver, - $siteAccess, + $this->siteAccessService, [], 'default' ); @@ -112,14 +113,11 @@ public function testGetLanguageList() ->expects($this->once()) ->method('getParameter') ->with($this->equalTo('languages')) - ->willReturn(['eng-GB', 'fre-FR']) - ; - - $siteAccess = new CurrentSiteAccess('foo', 'test'); + ->willReturn(['eng-GB', 'fre-FR']); $siteAccessHelper = new SiteAccessHelper( $this->configResolver, - $siteAccess, + $this->siteAccessService, [], 'default' ); @@ -135,33 +133,29 @@ public function testGetMainLanguagesWithSiteAccess() ->expects($this->once()) ->method('getParameter') ->with($this->equalTo('languages'), null, 'foo') - ->willReturn(['eng-GB', 'fre-FR']) - ; - - $siteAccess = new CurrentSiteAccess('foo', 'test'); + ->willReturn(['eng-GB', 'fre-FR']); $siteAccessHelper = new SiteAccessHelper( $this->configResolver, - $siteAccess, + $this->siteAccessService, [], 'default' ); $result = $siteAccessHelper->getLanguages(1542, 'foo'); - $this->assertEquals(['eng-GB'], $result); + $this->assertEquals( + ['eng-GB'], $result + ); } public function testGetLanguagesByCustomerId() { $this->configResolver - ->expects($this->once()) + ->expects(self::once()) ->method('getParameter') ->with($this->equalTo('languages'), null, 'foo') - ->willReturn(['eng-GB', 'fre-FR']) - ; - - $siteAccess = new CurrentSiteAccess('foo', 'test'); + ->willReturn(['eng-GB', 'fre-FR']); $siteAccessConfig = [ 'default' => [ @@ -178,24 +172,28 @@ public function testGetLanguagesByCustomerId() $siteAccessHelper = new SiteAccessHelper( $this->configResolver, - $siteAccess, + $this->siteAccessService, $siteAccessConfig, 'default' ); - $result = $siteAccessHelper->getLanguages(123, null); - // should return only one language: main language by matched siteAccess - $this->assertEquals(['eng-GB'], $result); + $this->assertEquals( + ['eng-GB'], + $siteAccessHelper->getLanguages(123, null) + ); } public function testGetSiteAccessesByCustomerIdWithoutCustomerId() { - $siteAccess = new CurrentSiteAccess('foo', 'test'); + $this->siteAccessService + ->expects(self::atLeastOnce()) + ->method('getCurrent') + ->willReturn(new SiteAccess('foo', 'test')); $siteAccessHelper = new SiteAccessHelper( $this->configResolver, - $siteAccess, + $this->siteAccessService, [], 'default' ); @@ -207,8 +205,6 @@ public function testGetSiteAccessesByCustomerIdWithoutCustomerId() public function testGetSiteAccessesByCustomerId() { - $siteAccess = new CurrentSiteAccess('foo', 'test'); - $siteAccessConfig = [ 'default' => [ 'authentication' => [ @@ -229,7 +225,7 @@ public function testGetSiteAccessesByCustomerId() $siteAccessHelper = new SiteAccessHelper( $this->configResolver, - $siteAccess, + $this->siteAccessService, $siteAccessConfig, 'default' ); @@ -241,8 +237,6 @@ public function testGetSiteAccessesByCustomerId() public function testGetSiteAccessesByCustomerIdWithChangedDefaultSiteAccess() { - $siteAccess = new CurrentSiteAccess('foo', 'test'); - $siteAccessConfig = [ 'default' => [ 'authentication' => [ @@ -263,7 +257,7 @@ public function testGetSiteAccessesByCustomerIdWithChangedDefaultSiteAccess() $siteAccessHelper = new SiteAccessHelper( $this->configResolver, - $siteAccess, + $this->siteAccessService, $siteAccessConfig, 'foo' ); @@ -275,8 +269,6 @@ public function testGetSiteAccessesByCustomerIdWithChangedDefaultSiteAccess() public function testGetSiteAccessesByCustomerIdWithChangedDefaultSiteAccessDifferentCustomerId() { - $siteAccess = new CurrentSiteAccess('foo', 'test'); - $siteAccessConfig = [ 'default' => [ 'authentication' => [ @@ -297,7 +289,7 @@ public function testGetSiteAccessesByCustomerIdWithChangedDefaultSiteAccessDiffe $siteAccessHelper = new SiteAccessHelper( $this->configResolver, - $siteAccess, + $this->siteAccessService, $siteAccessConfig, 'foo' ); @@ -309,8 +301,6 @@ public function testGetSiteAccessesByCustomerIdWithChangedDefaultSiteAccessDiffe public function testGetSiteAccessesByCustomerIdWithMultipleConfig() { - $siteAccess = new CurrentSiteAccess('foo', 'test'); - $siteAccessConfig = [ 'default' => [ 'authentication' => [ @@ -331,7 +321,7 @@ public function testGetSiteAccessesByCustomerIdWithMultipleConfig() $siteAccessHelper = new SiteAccessHelper( $this->configResolver, - $siteAccess, + $this->siteAccessService, $siteAccessConfig, 'default' ); @@ -343,8 +333,6 @@ public function testGetSiteAccessesByCustomerIdWithMultipleConfig() public function testGetSiteAccessesByCustomerIdWithChangedDefaultSiteAccessAndMultipleConfig() { - $siteAccess = new CurrentSiteAccess('foo', 'test'); - $siteAccessConfig = [ 'default' => [ 'authentication' => [ @@ -365,7 +353,7 @@ public function testGetSiteAccessesByCustomerIdWithChangedDefaultSiteAccessAndMu $siteAccessHelper = new SiteAccessHelper( $this->configResolver, - $siteAccess, + $this->siteAccessService, $siteAccessConfig, 'foo' ); @@ -377,8 +365,6 @@ public function testGetSiteAccessesByCustomerIdWithChangedDefaultSiteAccessAndMu public function testGetSiteAccessesByCustomerIdWithWrongCustomerId() { - $siteAccess = new CurrentSiteAccess('foo', 'test'); - $siteAccessConfig = [ 'default' => [ 'authentication' => [ @@ -394,7 +380,7 @@ public function testGetSiteAccessesByCustomerIdWithWrongCustomerId() $siteAccessHelper = new SiteAccessHelper( $this->configResolver, - $siteAccess, + $this->siteAccessService, $siteAccessConfig ); @@ -406,13 +392,16 @@ public function testGetSiteAccessesByCustomerIdWithWrongCustomerId() public function testGetSiteAccesses() { - $siteAccess = new CurrentSiteAccess('default', 'test'); + $this->siteAccessService + ->expects(self::atLeastOnce()) + ->method('getCurrent') + ->willReturn(new SiteAccess('default', 'test')); $siteAccessHelper = new SiteAccessHelper( $this->configResolver, - $siteAccess, + $this->siteAccessService, [], - 'foo' + 'default' ); $result = $siteAccessHelper->getSiteAccesses(null, null); @@ -422,8 +411,6 @@ public function testGetSiteAccesses() public function testGetSiteAccessesWithCustomerId() { - $siteAccess = new CurrentSiteAccess('default', 'test'); - $siteAccessConfig = [ 'foo' => [ 'authentication' => [ @@ -434,7 +421,7 @@ public function testGetSiteAccessesWithCustomerId() $siteAccessHelper = new SiteAccessHelper( $this->configResolver, - $siteAccess, + $this->siteAccessService, $siteAccessConfig, 'foo' ); @@ -446,11 +433,9 @@ public function testGetSiteAccessesWithCustomerId() public function testGetSiteAccessesWithSiteAccess() { - $siteAccess = new CurrentSiteAccess('default', 'test'); - $siteAccessHelper = new SiteAccessHelper( $this->configResolver, - $siteAccess, + $this->siteAccessService, [], 'foo' ); @@ -462,11 +447,9 @@ public function testGetSiteAccessesWithSiteAccess() public function testGetSiteAccessesWithWrongCustomerId() { - $siteAccess = new CurrentSiteAccess('default', 'test'); - $siteAccessHelper = new SiteAccessHelper( $this->configResolver, - $siteAccess, + $this->siteAccessService, [], 'foo' ); diff --git a/tests/lib/Service/ExportNotificationServiceTest.php b/tests/lib/Service/ExportNotificationServiceTest.php index 13996fdf..5efa2f72 100644 --- a/tests/lib/Service/ExportNotificationServiceTest.php +++ b/tests/lib/Service/ExportNotificationServiceTest.php @@ -11,22 +11,23 @@ use EzSystems\EzRecommendationClient\API\Notifier; use EzSystems\EzRecommendationClient\Service\ExportNotificationService; use EzSystems\EzRecommendationClient\Value\ExportNotification; -use EzSystems\EzRecommendationClient\Value\ExportParameters; +use GuzzleHttp\Psr7\Response; +use Ibexa\Personalization\Value\Export\Parameters; class ExportNotificationServiceTest extends NotificationServiceTest { /** @var \EzSystems\EzRecommendationClient\Service\ExportNotificationService */ private $notificationService; - /** @var \EzSystems\EzRecommendationClient\Value\ExportParameters|\PHPUnit\Framework\MockObject\MockObject */ - private $exportParametersMock; - - /** @var array */ + /** @var array|string>>> */ private $urls; - /** @var array */ + /** @var array */ private $notificationOptions; + /** @var \Ibexa\Personalization\Value\Export\Parameters */ + private $exportParameters; + public function setUp(): void { parent::setUp(); @@ -35,7 +36,16 @@ public function setUp(): void $this->clientMock, $this->loggerMock ); - $this->exportParametersMock = $this->createMock(ExportParameters::class); + $this->exportParameters = Parameters::fromArray([ + 'customer_id' => '12345', + 'license_key' => '12345-12345-12345-12345', + 'siteaccess' => 'test', + 'item_type_identifier_list' => 'article, product, blog', + 'languages' => 'eng-GB', + 'web_hook' => 'https://reco-engine.com/api/12345/items', + 'host' => 'https://127.0.0.1', + 'page_size' => '500', + ]); $this->urls = [ 1 => [ 'eng-EN' => [ @@ -72,12 +82,12 @@ public function setUp(): void ); } - public function testCreateInstanceOfEventNotificationService() + public function testCreateInstanceOfEventNotificationService(): void { $this->assertInstanceOf(ExportNotificationService::class, $this->notificationService); } - public function testCreateExportNotification() + public function testCreateExportNotification(): void { $this->assertInstanceOf( ExportNotification::class, @@ -85,22 +95,27 @@ public function testCreateExportNotification() ); } - public function testSendNotification() + public function testSendNotification(): void { - $this->exportParametersMock - ->expects($this->once()) - ->method('getProperties') - ->willReturn($this->notificationOptions); - + $notifier = $this->createMock(Notifier::class); $this->clientMock + ->expects(self::once()) ->method('__call') ->with(Notifier::API_NAME, []) - ->willReturn($this->createMock(Notifier::class)); + ->willReturn($notifier); + + $notifier + ->expects(self::once()) + ->method('notify') + ->willReturn(new Response()); - $this->notificationService->sendNotification( - $this->exportParametersMock, - $this->urls, - ['login' => 'abc', 'pass' => 'def'] + self::assertEquals( + new Response(), + $this->notificationService->sendNotification( + $this->exportParameters, + $this->urls, + ['login' => 'abc', 'pass' => 'def'] + ) ); } }