diff --git a/README.md b/README.md
index 9d8ab5a..7e54d90 100644
--- a/README.md
+++ b/README.md
@@ -33,11 +33,9 @@ return [
### Step 3: Configure plugin
```yaml
-# config/packages/_sylius.yaml
+# config/packages/setono_sylius_partner_ads.yaml
imports:
- # ...
- { resource: "@SetonoSyliusPartnerAdsPlugin/Resources/config/app/config.yaml" }
- # ...
```
### Step 4: Import routing
@@ -48,67 +46,20 @@ setono_partner_ads_plugin:
resource: "@SetonoSyliusPartnerAdsPlugin/Resources/config/routing.yaml"
```
-### Step 5: HTTP client
-If you already use a PSR18 HTTP client you need to inject that service:
-```yaml
-setono_sylius_partner_ads:
- http_client: '@http_client_service_id'
-```
-
-If not, you can just do composer the Buzz library and it will automatically register the Buzz client as the HTTP client:
-
-```bash
-$ composer require kriswallsmith/buzz
-```
-
-### Step 6: Update your database schema
+### Step 5: Update your database schema
```bash
$ php bin/console doctrine:migrations:diff
$ php bin/console doctrine:migrations:migrate
```
-### Step 7: Setup program
+### Step 6: Setup program
Login to your Sylius app admin and go to the Partner Ads page and click "Create" to create a new program. Fill in the program id of your Partner Ads program, make sure "enable" is toggled on, and choose which channel the program should be applied to. Please notice you should only make one program for each channel, or else you will end up with undefined behaviour.
-### Step 8 (optional, but recommended): Configure Async HTTP requests
-This plugin will make a HTTP request to Partner Ads when a customer completes an order. This will make the 'Thank you' page load slower. To circumvent that you can use RabbitMQ with Symfony Messenger to send this HTTP request asynchronously.
-
-Follow the installation instructions here: [How to Use the Messenger](https://symfony.com/doc/current/messenger.html) and then [configure a transport](https://symfony.com/doc/current/messenger.html#transports).
-
-Basically you should do:
-```bash
-$ composer req messenger symfony/serializer-pack
-```
-
-Then configure the Messenger component:
-```yaml
-# config/packages/messenger.yaml
-framework:
- messenger:
- transports:
- amqp: "%env(MESSENGER_TRANSPORT_DSN)%"
-```
-
-```yaml
-# .env
-###> symfony/messenger ###
-MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages
-###< symfony/messenger ###
-```
-
-And finally configure the plugin to use your transport:
-
-```yaml
-setono_sylius_partner_ads:
- messenger:
- transport: amqp
-```
+### Step 7 (optional, but recommended): Configure Async HTTP requests
-After this the Messenger will be automatically enabled in this plugin and subsequently it will send an asynchronous request to Partner Ads instead of a synchronous.
-For testing purposes you can sign up for a free RabbitMQ cloud service here: [CloudAMQP](https://www.cloudamqp.com/plans.html).
[ico-version]: https://poser.pugx.org/setono/sylius-partner-ads-plugin/v/stable
[ico-license]: https://poser.pugx.org/setono/sylius-partner-ads-plugin/license
diff --git a/composer.json b/composer.json
index 65b78da..9b214ca 100644
--- a/composer.json
+++ b/composer.json
@@ -16,21 +16,24 @@
"psr/http-client": "^1.0",
"psr/http-factory": "^1.0",
"psr/http-message": "^1.0",
+ "setono/doctrine-object-manager-trait": "^1.1",
"setono/symfony-main-request-trait": "^1.0",
"sylius/resource-bundle": "^1.6",
- "symfony/config": "^4.4 || ^5.4",
- "symfony/dependency-injection": "^4.4 || ^5.4",
- "symfony/event-dispatcher": "^4.4 || ^5.4",
- "symfony/form": "^4.4 || ^5.4",
- "symfony/http-foundation": "^4.4 || ^5.4",
- "symfony/http-kernel": "^4.4 || ^5.4",
- "symfony/messenger": "^4.4 || ^5.4",
+ "symfony/config": "^4.4 || ^5.4 || ^6.0",
+ "symfony/dependency-injection": "^4.4 || ^5.4 || ^6.0",
+ "symfony/event-dispatcher": "^4.4 || ^5.4 || ^6.0",
+ "symfony/form": "^4.4 || ^5.4 || ^6.0",
+ "symfony/http-client": "^4.4 || ^5.4 || ^6.0",
+ "symfony/http-client-contracts": "^1.1 || ^2.5 || ^3.1",
+ "symfony/http-foundation": "^4.4 || ^5.4 || ^6.0",
+ "symfony/http-kernel": "^4.4 || ^5.4 || ^6.0",
+ "symfony/messenger": "^4.4 || ^5.4 || ^6.0",
+ "symfony/workflow": "^4.4 || ^5.4 || ^6.0",
"webmozart/assert": "^1.11"
},
"require-dev": {
"api-platform/core": "^2.7",
"friendsofsymfony/oauth-server-bundle": ">2.0.0-alpha.0 ^2.0@dev",
- "kriswallsmith/buzz": "^1.2",
"lexik/jwt-authentication-bundle": "^2.16",
"matthiasnoback/symfony-config-test": "^4.3",
"matthiasnoback/symfony-dependency-injection-test": "^4.3",
@@ -41,11 +44,11 @@
"setono/code-quality-pack": "^2.2",
"sylius/admin-api-bundle": "^1.11",
"sylius/sylius": "~1.10.14",
- "symfony/debug-bundle": "^4.4 || ^5.4",
- "symfony/dotenv": "^4.4 || ^5.4",
- "symfony/intl": "^4.4 || ^5.4",
+ "symfony/debug-bundle": "^4.4 || ^5.4 || ^6.0",
+ "symfony/dotenv": "^4.4 || ^5.4 || ^6.0",
+ "symfony/intl": "^4.4 || ^5.4 || ^6.0",
"symfony/serializer-pack": "^1.0",
- "symfony/web-profiler-bundle": "^4.4 || ^5.4",
+ "symfony/web-profiler-bundle": "^4.4 || ^5.4 || ^6.0",
"symfony/webpack-encore-bundle": "^1.15"
},
"prefer-stable": true,
diff --git a/ecs.php b/ecs.php
index bdc2526..42dca52 100644
--- a/ecs.php
+++ b/ecs.php
@@ -8,7 +8,7 @@
return static function (ContainerConfigurator $containerConfigurator): void {
$containerConfigurator->import('vendor/sylius-labs/coding-standard/ecs.php');
$containerConfigurator->parameters()->set(Option::PATHS, [
- 'src', 'tests', 'spec'
+ 'src', 'tests'
]);
$containerConfigurator->parameters()->set(Option::SKIP, [
'tests/Application/node_modules/**',
diff --git a/psalm.xml b/psalm.xml
index 5787415..71f3e00 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -23,5 +23,6 @@
+
diff --git a/spec/Calculator/OrderTotalCalculatorSpec.php b/spec/Calculator/OrderTotalCalculatorSpec.php
deleted file mode 100644
index 3ecc60f..0000000
--- a/spec/Calculator/OrderTotalCalculatorSpec.php
+++ /dev/null
@@ -1,45 +0,0 @@
-shouldHaveType(OrderTotalCalculator::class);
- }
-
- public function it_returns_correct_total(OrderInterface $order): void
- {
- $tests = [
- [
- 'total' => 0,
- 'shipping' => 0,
- 'expected' => 0.0,
- ],
- [
- 'total' => 10,
- 'shipping' => 9,
- 'expected' => 0.01,
- ],
- [
- 'total' => 123456,
- 'shipping' => 1245,
- 'expected' => 1222.11,
- ],
- ];
-
- foreach ($tests as $test) {
- $order->getTotal()->willReturn($test['total']);
- $order->getShippingTotal()->willReturn($test['shipping']);
-
- $this->get($order)->shouldReturn($test['expected']);
- }
- }
-}
diff --git a/spec/Client/ClientSpec.php b/spec/Client/ClientSpec.php
deleted file mode 100644
index f59979f..0000000
--- a/spec/Client/ClientSpec.php
+++ /dev/null
@@ -1,51 +0,0 @@
-provide(Argument::cetera())->willReturn($this->url);
-
- $this->beConstructedWith($httpClient, $requestFactory, $notifyUrlProvider);
- }
-
- public function it_is_initializable(): void
- {
- $this->shouldHaveType(Client::class);
- }
-
- public function it_implements_client_interface(): void
- {
- $this->shouldHaveType(ClientInterface::class);
- }
-
- public function it_notifies(
- HttpClientInterface $httpClient,
- RequestFactoryInterface $requestFactory,
- RequestInterface $request,
- ResponseInterface $response
- ): void {
- $requestFactory->createRequest('GET', $this->url)->willReturn($request);
-
- $response->getStatusCode()->willReturn(200);
- $response->getBody()->shouldBeCalled();
- $httpClient->sendRequest($request)->willReturn($response);
- $this->notify(123, 'order-123', 123.123, 123, '123.456.789.000');
- }
-}
diff --git a/spec/EventListener/NotifySubscriberSpec.php b/spec/EventListener/NotifySubscriberSpec.php
deleted file mode 100644
index 87670b3..0000000
--- a/spec/EventListener/NotifySubscriberSpec.php
+++ /dev/null
@@ -1,168 +0,0 @@
-beConstructedWith($messageBus, $cookieHandler, $orderTotalCalculator, $programContext, $orderRepository);
- }
-
- public function it_is_initializable(): void
- {
- $this->shouldHaveType(NotifySubscriber::class);
- }
-
- public function it_implements_event_subscriber_interface(): void
- {
- $this->shouldImplement(EventSubscriberInterface::class);
- }
-
- public function it_notifies(
- RequestEvent $event,
- OrderInterface $order,
- CookieHandlerInterface $cookieHandler,
- OrderTotalCalculatorInterface $orderTotalCalculator,
- ProgramContextInterface $programContext,
- ProgramInterface $program,
- MessageBusInterface $messageBus,
- StampInterface $stamp,
- OrderRepositoryInterface $orderRepository
- ): void {
- $request = self::getRequest();
- $event->getRequest()->willReturn($request);
- $event->isMainRequest()->willReturn(true);
-
- $orderRepository->find(123)->willReturn($order);
-
- $cookieHandler->has($request)->willReturn(true);
- $cookieHandler->get($request)->willReturn(123);
- $programContext->getProgram()->willReturn($program);
- $program->getProgramId()->willReturn(1234);
- $orderTotalCalculator->get($order)->willReturn(199.0);
- $envelope = new Envelope(new stdClass(), [$stamp->getWrappedObject()]);
-
- $messageBus->dispatch(Argument::any())->willReturn($envelope)->shouldBeCalled();
-
- $this->notify($event);
- }
-
- private static function getRequest(): Request
- {
- $session = new class() implements SessionInterface {
- public function start()
- {
- }
-
- public function getId()
- {
- }
-
- public function setId($id)
- {
- }
-
- public function getName()
- {
- }
-
- public function setName($name)
- {
- }
-
- public function invalidate($lifetime = null)
- {
- }
-
- public function migrate($destroy = false, $lifetime = null)
- {
- }
-
- public function save()
- {
- }
-
- public function has($name)
- {
- }
-
- public function get($name, $default = null)
- {
- return 123;
- }
-
- public function set($name, $value)
- {
- }
-
- public function all()
- {
- }
-
- public function replace(array $attributes)
- {
- }
-
- public function remove($name)
- {
- }
-
- public function clear()
- {
- }
-
- public function isStarted()
- {
- }
-
- public function registerBag(SessionBagInterface $bag)
- {
- }
-
- public function getBag($name)
- {
- }
-
- public function getMetadataBag()
- {
- }
- };
-
- return new class($session) extends Request {
- public function __construct(SessionInterface $session)
- {
- parent::__construct();
-
- $this->attributes->set('_route', 'sylius_shop_order_thank_you');
- $this->setSession($session);
- }
- };
- }
-}
diff --git a/spec/EventListener/SetCookieSubscriberSpec.php b/spec/EventListener/SetCookieSubscriberSpec.php
deleted file mode 100644
index 723233b..0000000
--- a/spec/EventListener/SetCookieSubscriberSpec.php
+++ /dev/null
@@ -1,91 +0,0 @@
-beConstructedWith($cookieHandler, $this->param);
- }
-
- public function it_is_initializable(): void
- {
- $this->shouldHaveType(SetCookieSubscriber::class);
- }
-
- public function it_does_not_do_anything_when_not_master_request(
- HttpKernelInterface $kernel,
- Request $request,
- Response $response
- ): void {
- $event = new ResponseEvent($kernel->getWrappedObject(), $request->getWrappedObject(), HttpKernelInterface::SUB_REQUEST, $response->getWrappedObject());
-
- $request->isXmlHttpRequest()->shouldNotBeCalled();
-
- $this->setCookie($event);
- }
-
- public function it_does_not_do_anything_when_xml_request(
- HttpKernelInterface $kernel,
- Request $request,
- Response $response,
- CookieHandlerInterface $cookieHandler
- ): void {
- $event = new ResponseEvent($kernel->getWrappedObject(), $request->getWrappedObject(), HttpKernelInterface::MAIN_REQUEST, $response->getWrappedObject());
- $request->isXmlHttpRequest()->willReturn(true);
-
- $cookieHandler->set(Argument::any(), Argument::any())->shouldNotBeCalled();
-
- $this->setCookie($event);
- }
-
- public function it_does_not_do_anything_when_query_param_is_not_set(
- HttpKernelInterface $kernel,
- Request $request,
- Response $response,
- CookieHandlerInterface $cookieHandler,
- ParameterBag $query
- ): void {
- $event = new ResponseEvent($kernel->getWrappedObject(), $request->getWrappedObject(), HttpKernelInterface::MAIN_REQUEST, $response->getWrappedObject());
- $request->isXmlHttpRequest()->willReturn(false);
- $query->has($this->param)->willReturn(false);
- $request->query = $query;
-
- $cookieHandler->set(Argument::any(), Argument::any())->shouldNotBeCalled();
-
- $this->setCookie($event);
- }
-
- public function it_sets(
- HttpKernelInterface $kernel,
- Request $request,
- Response $response,
- CookieHandlerInterface $cookieHandler,
- ParameterBag $query
- ): void {
- $event = new ResponseEvent($kernel->getWrappedObject(), $request->getWrappedObject(), HttpKernelInterface::MAIN_REQUEST, $response->getWrappedObject());
- $request->isXmlHttpRequest()->willReturn(false);
- $query->has($this->param)->willReturn(true);
- $query->get($this->param)->willReturn('123');
- $request->query = $query;
-
- $cookieHandler->set(Argument::any(), '123')->shouldBeCalled();
-
- $this->setCookie($event);
- }
-}
diff --git a/spec/UrlProvider/NotifyUrlProviderSpec.php b/spec/UrlProvider/NotifyUrlProviderSpec.php
deleted file mode 100644
index b2c83e2..0000000
--- a/spec/UrlProvider/NotifyUrlProviderSpec.php
+++ /dev/null
@@ -1,48 +0,0 @@
-beConstructedWith('https://example.com/?programid={program_id}&type=salg&partnerid={partner_id}&userip={ip}&ordreid={order_id}&varenummer=x&antal=1&omprsalg={value}');
- }
-
- public function it_is_initializable(): void
- {
- $this->shouldHaveType(NotifyUrlProvider::class);
- }
-
- public function it_implements_notify_url_provider_interface(): void
- {
- $this->shouldImplement(NotifyUrlProviderInterface::class);
- }
-
- public function it_throws_exception(): void
- {
- $this->beConstructedWith('');
-
- $this->shouldThrow(MissingVariableInUrlException::class)->during('provide', [123, '123', 123.123, 123, '123']);
- }
-
- public function it_provides_correct_url(): void
- {
- $programId = 123;
- $partnerId = 456;
- $ip = '123.123.123.123';
- $orderId = 'order-123';
- $value = 123.123;
-
- $expectedUrl = "https://example.com/?programid=$programId&type=salg&partnerid=$partnerId&userip=$ip&ordreid=$orderId&varenummer=x&antal=1&omprsalg=$value";
-
- $this->provide($programId, $orderId, $value, $partnerId, $ip)->shouldReturn($expectedUrl);
- }
-}
diff --git a/src/Calculator/OrderTotalCalculator.php b/src/Calculator/OrderTotalCalculator.php
index aa5b7af..e8acff8 100644
--- a/src/Calculator/OrderTotalCalculator.php
+++ b/src/Calculator/OrderTotalCalculator.php
@@ -8,10 +8,8 @@
final class OrderTotalCalculator implements OrderTotalCalculatorInterface
{
- public function get(OrderInterface $order): float
+ public function calculate(OrderInterface $order): int
{
- $orderTotal = $order->getTotal() - $order->getShippingTotal();
-
- return round($orderTotal / 100, 2);
+ return $order->getTotal() - $order->getShippingTotal();
}
}
diff --git a/src/Calculator/OrderTotalCalculatorInterface.php b/src/Calculator/OrderTotalCalculatorInterface.php
index d13d443..a03f225 100644
--- a/src/Calculator/OrderTotalCalculatorInterface.php
+++ b/src/Calculator/OrderTotalCalculatorInterface.php
@@ -9,8 +9,7 @@
interface OrderTotalCalculatorInterface
{
/**
- * Returns the order total formatted for Partner Ads, which is order total with vat but without any fees and shipping
- * If the order total after calculations is 57191, then this method should return 571.91
+ * Returns the order total for Partner Ads, which is order total with vat but without any fees or shipping
*/
- public function get(OrderInterface $order): float;
+ public function calculate(OrderInterface $order): int;
}
diff --git a/src/Client/Client.php b/src/Client/Client.php
deleted file mode 100644
index 29c4f78..0000000
--- a/src/Client/Client.php
+++ /dev/null
@@ -1,49 +0,0 @@
-httpClient = $httpClient;
- $this->requestFactory = $requestFactory;
- $this->notifyUrlProvider = $notifyUrlProvider;
- }
-
- public function notify(int $programId, string $orderId, float $total, int $partnerId, string $ip): void
- {
- $url = $this->notifyUrlProvider->provide($programId, $orderId, $total, $partnerId, $ip);
-
- $this->sendRequest('GET', $url);
- }
-
- private function sendRequest(string $method, string $url): string
- {
- $request = $this->requestFactory->createRequest($method, $url);
-
- $response = $this->httpClient->sendRequest($request);
-
- if ($response->getStatusCode() !== 200) {
- throw new RequestFailedException($request, $response, $response->getStatusCode());
- }
-
- return (string) $response->getBody();
- }
-}
diff --git a/src/Client/ClientInterface.php b/src/Client/ClientInterface.php
deleted file mode 100644
index 2c2febf..0000000
--- a/src/Client/ClientInterface.php
+++ /dev/null
@@ -1,23 +0,0 @@
-affiliateOrderDispatcher = $affiliateOrderDispatcher;
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int
+ {
+ if ($this->affiliateOrderDispatcher instanceof LoggerAwareInterface) {
+ $this->affiliateOrderDispatcher->setLogger(new ConsoleLogger($output));
+ }
+
+ $this->affiliateOrderDispatcher->dispatch();
+
+ return 0;
+ }
+}
diff --git a/src/Context/ProgramContextInterface.php b/src/Context/ProgramContextInterface.php
index 789b201..a895232 100644
--- a/src/Context/ProgramContextInterface.php
+++ b/src/Context/ProgramContextInterface.php
@@ -9,7 +9,7 @@
interface ProgramContextInterface
{
/**
- * Returns the program enabled for the active channel
+ * Returns the program enabled for the active channel, if any
*/
public function getProgram(): ?ProgramInterface;
}
diff --git a/src/CookieHandler/CookieHandler.php b/src/CookieHandler/CookieHandler.php
index 75e1505..666938b 100644
--- a/src/CookieHandler/CookieHandler.php
+++ b/src/CookieHandler/CookieHandler.php
@@ -4,40 +4,86 @@
namespace Setono\SyliusPartnerAdsPlugin\CookieHandler;
+use DateTimeImmutable;
+use Setono\MainRequestTrait\MainRequestTrait;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\Event\ResponseEvent;
+use Symfony\Component\HttpKernel\KernelEvents;
+use Webmozart\Assert\Assert;
-final class CookieHandler implements CookieHandlerInterface
+final class CookieHandler implements CookieHandlerInterface, EventSubscriberInterface
{
+ use MainRequestTrait;
+
+ private RequestStack $requestStack;
+
+ private string $queryParameter;
+
private string $cookieName;
private int $expire;
- public function __construct(string $cookieName, int $expire)
+ public function __construct(RequestStack $requestStack, string $queryParameter, string $cookieName, int $expire)
{
+ $this->requestStack = $requestStack;
+ $this->queryParameter = $queryParameter;
$this->cookieName = $cookieName;
$this->expire = $expire;
}
- public function set(Response $response, int $partnerId): void
+ public static function getSubscribedEvents(): array
{
- $cookie = new Cookie($this->cookieName, (string) $partnerId, sprintf('now + %s days', $this->expire));
- $response->headers->setCookie($cookie);
+ return [
+ KernelEvents::RESPONSE => 'checkCookie',
+ ];
}
- public function remove(Response $response): void
+ public function checkCookie(ResponseEvent $event): void
{
- $response->headers->clearCookie($this->cookieName);
+ if (!$this->isMainRequest($event)) {
+ return;
+ }
+
+ $request = $event->getRequest();
+
+ $partnerId = $request->query->get($this->queryParameter);
+ if (!is_numeric($partnerId)) {
+ return;
+ }
+
+ $this->set($event->getResponse(), (int) $partnerId);
}
- public function get(Request $request): int
+ public function set(Response $response, int $partnerId): void
+ {
+ $response->headers->setCookie(new Cookie(
+ $this->cookieName,
+ (string) $partnerId,
+ new DateTimeImmutable(sprintf('+%d days', $this->expire))
+ ));
+ }
+
+ public function value(Request $request = null): int
{
+ if (null === $request) {
+ $request = $this->getMainRequestFromRequestStack($this->requestStack);
+ Assert::notNull($request);
+ }
+
return (int) $request->cookies->get($this->cookieName);
}
- public function has(Request $request): bool
+ public function isset(Request $request = null): bool
{
+ if (null === $request) {
+ $request = $this->getMainRequestFromRequestStack($this->requestStack);
+ Assert::notNull($request);
+ }
+
return $request->cookies->has($this->cookieName);
}
}
diff --git a/src/CookieHandler/CookieHandlerInterface.php b/src/CookieHandler/CookieHandlerInterface.php
index 3213e82..a39086e 100644
--- a/src/CookieHandler/CookieHandlerInterface.php
+++ b/src/CookieHandler/CookieHandlerInterface.php
@@ -15,17 +15,16 @@ interface CookieHandlerInterface
public function set(Response $response, int $partnerId): void;
/**
- * Removes the cookie on the given response
+ * Returns the cookie value which is a Partner Ads partner id.
+ * If the request is null, it will use the main request from the request stack
+ *
+ * todo what if the cookie isn't set on the request?
*/
- public function remove(Response $response): void;
+ public function value(Request $request = null): int;
/**
- * Returns the cookie value which is a Partner Ads partner id
+ * Returns true if the request has the cookie set.
+ * If the request is null, it will use the main request from the request stack
*/
- public function get(Request $request): int;
-
- /**
- * Returns true if the request has the cookie set
- */
- public function has(Request $request): bool;
+ public function isset(Request $request = null): bool;
}
diff --git a/src/DependencyInjection/Compiler/RegisterCommandBusPass.php b/src/DependencyInjection/Compiler/RegisterCommandBusPass.php
deleted file mode 100644
index 3ff4d53..0000000
--- a/src/DependencyInjection/Compiler/RegisterCommandBusPass.php
+++ /dev/null
@@ -1,28 +0,0 @@
-hasParameter('setono_sylius_partner_ads.messenger.command_bus')) {
- return;
- }
-
- /** @var string $commandBusId */
- $commandBusId = $container->getParameter('setono_sylius_partner_ads.messenger.command_bus');
-
- if (!$container->has($commandBusId)) {
- throw new ServiceNotFoundException($commandBusId);
- }
-
- $container->setAlias('setono_sylius_partner_ads.command_bus', $commandBusId);
- }
-}
diff --git a/src/DependencyInjection/Compiler/RegisterHttpClientPass.php b/src/DependencyInjection/Compiler/RegisterHttpClientPass.php
deleted file mode 100644
index a38ed67..0000000
--- a/src/DependencyInjection/Compiler/RegisterHttpClientPass.php
+++ /dev/null
@@ -1,44 +0,0 @@
-hasParameter('setono_sylius_partner_ads.http_client')) {
- return;
- }
-
- $httpClientServiceId = 'setono_sylius_partner_ads.http_client';
-
- /** @var string|null $httpClientServiceIdParam */
- $httpClientServiceIdParam = $container->getParameter('setono_sylius_partner_ads.http_client');
- if (null === $httpClientServiceIdParam) {
- if (!interface_exists(BuzzClientInterface::class)) {
- throw new InterfaceNotFoundException(BuzzClientInterface::class);
- }
-
- $definition = new Definition(Curl::class, [
- new Reference('setono_sylius_partner_ads.http_client.response_factory'),
- ]);
- $container->setDefinition($httpClientServiceId, $definition);
- } else {
- if (!$container->has($httpClientServiceIdParam)) {
- throw new ServiceNotFoundException($httpClientServiceIdParam);
- }
- $container->setAlias($httpClientServiceId, $httpClientServiceIdParam);
- }
- }
-}
diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php
index 058f27e..c1709bd 100644
--- a/src/DependencyInjection/Configuration.php
+++ b/src/DependencyInjection/Configuration.php
@@ -4,14 +4,15 @@
namespace Setono\SyliusPartnerAdsPlugin\DependencyInjection;
-use Buzz\Client\BuzzClientInterface;
-use Setono\SyliusPartnerAdsPlugin\Doctrine\ORM\ProgramRepository;
use Setono\SyliusPartnerAdsPlugin\Form\Type\ProgramType;
+use Setono\SyliusPartnerAdsPlugin\Model\AffiliateOrder;
use Setono\SyliusPartnerAdsPlugin\Model\Program;
+use Setono\SyliusPartnerAdsPlugin\Repository\AffiliateOrderRepository;
+use Setono\SyliusPartnerAdsPlugin\Repository\ProgramRepository;
use Sylius\Bundle\ResourceBundle\Controller\ResourceController;
+use Sylius\Bundle\ResourceBundle\Form\Type\DefaultResourceType;
use Sylius\Bundle\ResourceBundle\SyliusResourceBundle;
use Sylius\Component\Resource\Factory\Factory;
-use Symfony\Component\Config\Definition\Builder\ScalarNodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
@@ -27,11 +28,26 @@ public function getConfigTreeBuilder(): TreeBuilder
$rootNode
->addDefaultsIfNotSet()
->children()
- ->append($this->addHttpClientNode())
->scalarNode('driver')->defaultValue(SyliusResourceBundle::DRIVER_DOCTRINE_ORM)->cannotBeEmpty()->end()
->arrayNode('resources')
->addDefaultsIfNotSet()
->children()
+ ->arrayNode('affiliate_order')
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->variableNode('options')->end()
+ ->arrayNode('classes')
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->scalarNode('model')->defaultValue(AffiliateOrder::class)->cannotBeEmpty()->end()
+ ->scalarNode('controller')->defaultValue(ResourceController::class)->cannotBeEmpty()->end()
+ ->scalarNode('repository')->defaultValue(AffiliateOrderRepository::class)->cannotBeEmpty()->end()
+ ->scalarNode('factory')->defaultValue(Factory::class)->end()
+ ->scalarNode('form')->defaultValue(DefaultResourceType::class)->cannotBeEmpty()->end()
+ ->end()
+ ->end()
+ ->end()
+ ->end()
->arrayNode('program')
->addDefaultsIfNotSet()
->children()
@@ -50,16 +66,6 @@ public function getConfigTreeBuilder(): TreeBuilder
->end()
->end()
->end()
- ->arrayNode('urls')
- ->addDefaultsIfNotSet()
- ->children()
- ->scalarNode('notify')
- ->cannotBeEmpty()
- ->defaultValue('https://www.partner-ads.com/dk/leadtracks2s.php?programid={program_id}&type=salg&partnerid={partner_id}&userip={ip}&ordreid={order_id}&varenummer=x&antal=1&omprsalg={value}')
- ->info('The URL to use when notifying Partner Ads of a new order. Remember to include the variables')
- ->end()
- ->end()
- ->end()
->scalarNode('query_parameter')
->cannotBeEmpty()
->defaultValue('paid')
@@ -70,9 +76,9 @@ public function getConfigTreeBuilder(): TreeBuilder
->children()
->scalarNode('name')
->cannotBeEmpty()
- ->defaultValue('setono_sylius_partner_ads_cookie')
+ ->defaultValue('sspa_affiliate')
->example('partner_ads')
- ->info('The name of the cookie')
+ ->info('The name of the cookie where the affiliate\'s id is saved')
->end()
->integerNode('expire')
->min(0)
@@ -82,46 +88,9 @@ public function getConfigTreeBuilder(): TreeBuilder
->end()
->end()
->end()
- ->arrayNode('messenger')
- ->addDefaultsIfNotSet()
- ->children()
- ->scalarNode('command_bus')
- ->cannotBeEmpty()
- ->defaultValue('message_bus')
- ->example('message_bus')
- ->info('The service id for the message bus you use for commands')
- ->end()
- ->scalarNode('transport')
- ->cannotBeEmpty()
- ->defaultNull()
- ->info('The transport to use if you would like HTTP requests to be async (which is a very good choice on production)')
- ->example('amqp')
- ->end()
- ->end()
-
- ->end()
->end()
;
return $treeBuilder;
}
-
- public function addHttpClientNode(): ScalarNodeDefinition
- {
- $treeBuilder = new TreeBuilder('http_client', 'scalar');
-
- $node = $treeBuilder->getRootNode();
- $node
- ->cannotBeEmpty()
- ->info('The service id for your PSR18 HTTP client')
- ;
-
- if (interface_exists(BuzzClientInterface::class)) {
- $node->defaultNull();
- } else {
- $node->isRequired();
- }
-
- return $node;
- }
}
diff --git a/src/DependencyInjection/SetonoSyliusPartnerAdsExtension.php b/src/DependencyInjection/SetonoSyliusPartnerAdsExtension.php
index 38023e8..bdd0ff9 100644
--- a/src/DependencyInjection/SetonoSyliusPartnerAdsExtension.php
+++ b/src/DependencyInjection/SetonoSyliusPartnerAdsExtension.php
@@ -4,7 +4,7 @@
namespace Setono\SyliusPartnerAdsPlugin\DependencyInjection;
-use Setono\SyliusPartnerAdsPlugin\Message\Command\Notify;
+use Setono\SyliusPartnerAdsPlugin\Workflow\AffiliateOrderWorkflow;
use Sylius\Bundle\ResourceBundle\DependencyInjection\Extension\AbstractResourceExtension;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -18,13 +18,9 @@ public function load(array $configs, ContainerBuilder $container): void
$config = $this->processConfiguration($this->getConfiguration([], $container), $configs);
$loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
- $container->setParameter('setono_sylius_partner_ads.http_client', $config['http_client']);
- $container->setParameter('setono_sylius_partner_ads.urls.notify', $config['urls']['notify']);
$container->setParameter('setono_sylius_partner_ads.query_parameter', $config['query_parameter']);
$container->setParameter('setono_sylius_partner_ads.cookie.name', $config['cookie']['name']);
$container->setParameter('setono_sylius_partner_ads.cookie.expire', $config['cookie']['expire']);
- $container->setParameter('setono_sylius_partner_ads.messenger.command_bus', $config['messenger']['command_bus']);
- $container->setParameter('setono_sylius_partner_ads.messenger.transport', $config['messenger']['transport']);
$this->registerResources('setono_sylius_partner_ads', $config['driver'], $config['resources'], $container);
@@ -33,20 +29,8 @@ public function load(array $configs, ContainerBuilder $container): void
public function prepend(ContainerBuilder $container): void
{
- $config = $this->processConfiguration($this->getConfiguration([], $container), $container->getExtensionConfig($this->getAlias()));
-
- $transport = $config['messenger']['transport'];
-
- if (null === $transport) {
- return;
- }
-
$container->prependExtensionConfig('framework', [
- 'messenger' => [
- 'routing' => [
- Notify::class => $transport,
- ],
- ],
+ 'workflows' => AffiliateOrderWorkflow::getConfig(),
]);
}
}
diff --git a/src/Dispatcher/AffiliateOrderDispatcher.php b/src/Dispatcher/AffiliateOrderDispatcher.php
new file mode 100644
index 0000000..02f49ce
--- /dev/null
+++ b/src/Dispatcher/AffiliateOrderDispatcher.php
@@ -0,0 +1,67 @@
+managerRegistry = $managerRegistry;
+ $this->commandBus = $commandBus;
+ $this->affiliateOrderRepository = $invitationRepository;
+ $this->workflowRegistry = $workflowRegistry;
+ }
+
+ public function dispatch(): void
+ {
+ $affiliateOrders = $this->affiliateOrderRepository->findNew();
+
+ foreach ($affiliateOrders as $affiliateOrder) {
+ $workflow = $this->getWorkflow($affiliateOrder);
+ if (!$workflow->can($affiliateOrder, AffiliateOrderWorkflow::TRANSITION_START)) {
+ continue;
+ }
+
+ $workflow->apply($affiliateOrder, AffiliateOrderWorkflow::TRANSITION_START);
+
+ $this->getManager($affiliateOrder)->flush();
+
+ $this->commandBus->dispatch(new ProcessAffiliateOrder($affiliateOrder));
+ }
+ }
+
+ private function getWorkflow(AffiliateOrderInterface $affiliateOrder): WorkflowInterface
+ {
+ if (null === $this->workflow) {
+ $this->workflow = $this->workflowRegistry->get($affiliateOrder, AffiliateOrderWorkflow::NAME);
+ }
+
+ return $this->workflow;
+ }
+}
diff --git a/src/Dispatcher/AffiliateOrderDispatcherInterface.php b/src/Dispatcher/AffiliateOrderDispatcherInterface.php
new file mode 100644
index 0000000..6d0ccda
--- /dev/null
+++ b/src/Dispatcher/AffiliateOrderDispatcherInterface.php
@@ -0,0 +1,13 @@
+messageBus = $messageBus;
- $this->cookieHandler = $cookieHandler;
- $this->orderTotalCalculator = $orderTotalCalculator;
- $this->programContext = $programContext;
- $this->orderRepository = $orderRepository;
- }
-
- public static function getSubscribedEvents(): array
- {
- return [
- KernelEvents::REQUEST => 'notify',
- ];
- }
-
- public function notify(RequestEvent $event): void
- {
- $request = $event->getRequest();
-
- if (!$this->isMainRequest($event)) {
- return;
- }
-
- if (!$request->attributes->has('_route')) {
- return;
- }
-
- $route = $request->attributes->get('_route');
- if ('sylius_shop_order_thank_you' !== $route) {
- return;
- }
-
- /** @var int|null $orderId */
- $orderId = $request->getSession()->get('sylius_order_id');
-
- if (null === $orderId) {
- return;
- }
-
- /** @var OrderInterface|null $order */
- $order = $this->orderRepository->find($orderId);
- if (null === $order) {
- return;
- }
-
- if (!$this->cookieHandler->has($request)) {
- return;
- }
-
- $program = $this->programContext->getProgram();
-
- if (null === $program || $program->getProgramId() === null) {
- return;
- }
-
- $this->messageBus->dispatch(new Notify(
- (int) $program->getProgramId(),
- (string) $order->getNumber(),
- $this->orderTotalCalculator->get($order),
- $this->cookieHandler->get($request),
- (string) $request->getClientIp()
- ));
- }
-}
diff --git a/src/EventListener/SetCookieSubscriber.php b/src/EventListener/SetCookieSubscriber.php
deleted file mode 100644
index 65d237a..0000000
--- a/src/EventListener/SetCookieSubscriber.php
+++ /dev/null
@@ -1,55 +0,0 @@
-cookieHandler = $cookieHandler;
- $this->queryParameter = $queryParameter;
- }
-
- public static function getSubscribedEvents(): array
- {
- return [
- KernelEvents::RESPONSE => [
- 'setCookie',
- ],
- ];
- }
-
- public function setCookie(ResponseEvent $event): void
- {
- if (!$this->isMainRequest($event)) {
- return;
- }
-
- $request = $event->getRequest();
-
- // Only add handle 'real' page loads, not AJAX requests like add to cart
- if ($request->isXmlHttpRequest()) {
- return;
- }
-
- if (!$request->query->has($this->queryParameter)) {
- return;
- }
-
- $this->cookieHandler->set($event->getResponse(), (int) $request->query->get($this->queryParameter));
- }
-}
diff --git a/src/EventSubscriber/CreateAffiliateOrderSubscriber.php b/src/EventSubscriber/CreateAffiliateOrderSubscriber.php
new file mode 100644
index 0000000..0d7531e
--- /dev/null
+++ b/src/EventSubscriber/CreateAffiliateOrderSubscriber.php
@@ -0,0 +1,87 @@
+cookieHandler = $cookieHandler;
+ $this->affiliateOrderFactory = $affiliateOrderFactory;
+ $this->managerRegistry = $managerRegistry;
+ $this->programContext = $programContext;
+ $this->requestStack = $requestStack;
+ }
+
+ public static function getSubscribedEvents(): array
+ {
+ return [
+ 'sylius.order.pre_complete' => 'create',
+ ];
+ }
+
+ public function create(ResourceControllerEvent $event): void
+ {
+ $request = $this->getMainRequestFromRequestStack($this->requestStack);
+ if (null === $request) {
+ return;
+ }
+
+ if (!$this->cookieHandler->isset($request)) {
+ return;
+ }
+
+ $program = $this->programContext->getProgram();
+ if (null === $program) {
+ return;
+ }
+
+ /** @var OrderInterface $order */
+ $order = $event->getSubject();
+ Assert::isInstanceOf($order, OrderInterface::class);
+
+ // todo check if there's already an affiliate order associated with this order. It's an edge case and maybe not even possible, but we don't want to break the checkout
+
+ $affiliateOrder = $this->affiliateOrderFactory->createWithData(
+ $program,
+ $order,
+ $this->cookieHandler->value($request),
+ $request->getClientIp() ?? '0.0.0.0'
+ );
+
+ // we don't flush since we are listening to the pre_complete event and when the order completes
+ // the entity manager is flushed and this entity is saved along with the order
+ $this->getManager($affiliateOrder)->persist($affiliateOrder);
+ }
+}
diff --git a/src/Exception/InterfaceNotFoundException.php b/src/Exception/InterfaceNotFoundException.php
deleted file mode 100644
index 5d6ba64..0000000
--- a/src/Exception/InterfaceNotFoundException.php
+++ /dev/null
@@ -1,24 +0,0 @@
-interface = $interface;
-
- parent::__construct(sprintf('The interface "%s" was not found', $this->interface));
- }
-
- public function getInterface(): string
- {
- return $this->interface;
- }
-}
diff --git a/src/Exception/MissingVariableInUrlException.php b/src/Exception/MissingVariableInUrlException.php
deleted file mode 100644
index 5934b4e..0000000
--- a/src/Exception/MissingVariableInUrlException.php
+++ /dev/null
@@ -1,32 +0,0 @@
-url = $url;
- $this->missingVariable = $missingVariable;
-
- parent::__construct(sprintf('The URL %s is missing variable %s', $this->url, $this->missingVariable));
- }
-
- public function getUrl(): string
- {
- return $this->url;
- }
-
- public function getMissingVariable(): string
- {
- return $this->missingVariable;
- }
-}
diff --git a/src/Exception/RequestFailedException.php b/src/Exception/RequestFailedException.php
deleted file mode 100644
index d22bbb4..0000000
--- a/src/Exception/RequestFailedException.php
+++ /dev/null
@@ -1,42 +0,0 @@
-request = $request;
- $this->response = $response;
- $this->statusCode = $statusCode;
-
- parent::__construct(sprintf('Request failed with status code %d', $this->statusCode));
- }
-
- public function getRequest(): RequestInterface
- {
- return $this->request;
- }
-
- public function getResponse(): ResponseInterface
- {
- return $this->response;
- }
-
- public function getStatusCode(): int
- {
- return $this->statusCode;
- }
-}
diff --git a/src/Factory/AffiliateOrderFactory.php b/src/Factory/AffiliateOrderFactory.php
new file mode 100644
index 0000000..b16698d
--- /dev/null
+++ b/src/Factory/AffiliateOrderFactory.php
@@ -0,0 +1,45 @@
+decorated = $decorated;
+ }
+
+ public function createNew(): AffiliateOrderInterface
+ {
+ /** @var AffiliateOrderInterface|object $obj */
+ $obj = $this->decorated->createNew();
+ Assert::isInstanceOf($obj, AffiliateOrderInterface::class);
+
+ return $obj;
+ }
+
+ public function createWithData(
+ ProgramInterface $program,
+ OrderInterface $order,
+ int $partner,
+ string $ip
+ ): AffiliateOrderInterface {
+ $obj = $this->createNew();
+ $obj->setProgram($program);
+ $obj->setOrder($order);
+ $obj->setPartner($partner);
+ $obj->setIp($ip);
+
+ return $obj;
+ }
+}
diff --git a/src/Factory/AffiliateOrderFactoryInterface.php b/src/Factory/AffiliateOrderFactoryInterface.php
new file mode 100644
index 0000000..1c7b402
--- /dev/null
+++ b/src/Factory/AffiliateOrderFactoryInterface.php
@@ -0,0 +1,22 @@
+programId = $programId;
- $this->orderId = $orderId;
- $this->orderTotal = $orderTotal;
- $this->partnerId = $partnerId;
- $this->ip = $ip;
- }
-
- public function getProgramId(): int
- {
- return $this->programId;
- }
-
- public function getOrderId(): string
- {
- return $this->orderId;
- }
-
- public function getOrderTotal(): float
- {
- return $this->orderTotal;
- }
-
- public function getPartnerId(): int
- {
- return $this->partnerId;
- }
-
- public function getIp(): string
- {
- return $this->ip;
- }
-}
diff --git a/src/Message/Command/ProcessAffiliateOrder.php b/src/Message/Command/ProcessAffiliateOrder.php
new file mode 100644
index 0000000..eb80c39
--- /dev/null
+++ b/src/Message/Command/ProcessAffiliateOrder.php
@@ -0,0 +1,28 @@
+getId();
+ }
+
+ Assert::integer($invitation);
+
+ $this->invitation = $invitation;
+ }
+}
diff --git a/src/Message/Handler/NotifyHandler.php b/src/Message/Handler/NotifyHandler.php
deleted file mode 100644
index b872ada..0000000
--- a/src/Message/Handler/NotifyHandler.php
+++ /dev/null
@@ -1,23 +0,0 @@
-client = $client;
- }
-
- public function __invoke(Notify $message): void
- {
- $this->client->notify($message->getProgramId(), $message->getOrderId(), $message->getOrderTotal(), $message->getPartnerId(), $message->getIp());
- }
-}
diff --git a/src/Model/AffiliateOrder.php b/src/Model/AffiliateOrder.php
new file mode 100644
index 0000000..de5e7f2
--- /dev/null
+++ b/src/Model/AffiliateOrder.php
@@ -0,0 +1,80 @@
+id;
+ }
+
+ public function getProgram(): ?ProgramInterface
+ {
+ return $this->program;
+ }
+
+ public function setProgram(ProgramInterface $program): void
+ {
+ $this->program = $program;
+ }
+
+ public function getOrder(): ?OrderInterface
+ {
+ return $this->order;
+ }
+
+ public function setOrder(OrderInterface $order): void
+ {
+ $this->order = $order;
+ }
+
+ public function getPartner(): ?int
+ {
+ return $this->partner;
+ }
+
+ public function setPartner(int $partner): void
+ {
+ $this->partner = $partner;
+ }
+
+ public function getIp(): ?string
+ {
+ return $this->ip;
+ }
+
+ public function setIp(string $ip): void
+ {
+ $this->ip = $ip;
+ }
+
+ public function getState(): string
+ {
+ return $this->state;
+ }
+
+ public function setState(string $state): void
+ {
+ $this->state = $state;
+ }
+}
diff --git a/src/Model/AffiliateOrderInterface.php b/src/Model/AffiliateOrderInterface.php
new file mode 100644
index 0000000..94d9c90
--- /dev/null
+++ b/src/Model/AffiliateOrderInterface.php
@@ -0,0 +1,48 @@
+httpClient = $httpClient;
+ $this->orderTotalCalculator = $orderTotalCalculator;
+ }
+
+ public function process(AffiliateOrderInterface $affiliateOrder): void
+ {
+ $program = $affiliateOrder->getProgram();
+ Assert::notNull($program);
+
+ $order = $affiliateOrder->getOrder();
+ Assert::notNull($order);
+
+ $url = new NotifyUrl(
+ (int) $program->getProgramId(),
+ (int) $affiliateOrder->getPartner(),
+ (string) $affiliateOrder->getIp(),
+ (string) $order->getNumber(),
+ $this->orderTotalCalculator->calculate($order)
+ );
+
+ Assert::same($this->httpClient->request('GET', (string) $url)->getStatusCode(), 200);
+ }
+}
diff --git a/src/Processor/AffiliateOrderProcessorInterface.php b/src/Processor/AffiliateOrderProcessorInterface.php
new file mode 100644
index 0000000..0f6cdb4
--- /dev/null
+++ b/src/Processor/AffiliateOrderProcessorInterface.php
@@ -0,0 +1,12 @@
+createQueryBuilder('o')
+ ->andWhere('o.state = :state')
+ ->setParameter('state', AffiliateOrderInterface::STATE_INITIAL)
+ ->getQuery()
+ ->getResult()
+ ;
+
+ Assert::isArray($objs);
+ Assert::allIsInstanceOf($objs, AffiliateOrderInterface::class);
+
+ return $objs;
+ }
+}
diff --git a/src/Repository/AffiliateOrderRepositoryInterface.php b/src/Repository/AffiliateOrderRepositoryInterface.php
new file mode 100644
index 0000000..2c336fe
--- /dev/null
+++ b/src/Repository/AffiliateOrderRepositoryInterface.php
@@ -0,0 +1,16 @@
+
+ */
+ public function findNew(): array;
+}
diff --git a/src/Doctrine/ORM/ProgramRepository.php b/src/Repository/ProgramRepository.php
similarity index 85%
rename from src/Doctrine/ORM/ProgramRepository.php
rename to src/Repository/ProgramRepository.php
index 52449fd..a41934b 100644
--- a/src/Doctrine/ORM/ProgramRepository.php
+++ b/src/Repository/ProgramRepository.php
@@ -2,10 +2,9 @@
declare(strict_types=1);
-namespace Setono\SyliusPartnerAdsPlugin\Doctrine\ORM;
+namespace Setono\SyliusPartnerAdsPlugin\Repository;
use Setono\SyliusPartnerAdsPlugin\Model\ProgramInterface;
-use Setono\SyliusPartnerAdsPlugin\Repository\ProgramRepositoryInterface;
use Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository;
use Sylius\Component\Channel\Model\ChannelInterface;
use Webmozart\Assert\Assert;
diff --git a/src/Repository/ProgramRepositoryInterface.php b/src/Repository/ProgramRepositoryInterface.php
index 931c2cd..cb8a765 100644
--- a/src/Repository/ProgramRepositoryInterface.php
+++ b/src/Repository/ProgramRepositoryInterface.php
@@ -11,7 +11,7 @@
interface ProgramRepositoryInterface extends RepositoryInterface
{
/**
- * Returns the program that is enabled on the given channel or null if no account is enabled for the given channel
+ * Returns the program that is enabled on the given channel or null if no program is enabled for the given channel
*/
public function findOneByChannel(ChannelInterface $channel): ?ProgramInterface;
}
diff --git a/src/Resources/config/app/config.yaml b/src/Resources/config/app/config.yaml
index 748ac95..177c89d 100644
--- a/src/Resources/config/app/config.yaml
+++ b/src/Resources/config/app/config.yaml
@@ -1,2 +1,7 @@
imports:
- "@SetonoSyliusPartnerAdsPlugin/Resources/config/grids/setono_sylius_partner_ads_admin_program.yaml"
+
+framework:
+ messenger:
+ buses:
+ setono_sylius_partner_ads.command_bus: ~
diff --git a/src/Resources/config/doctrine/model/AffiliateOrder.orm.xml b/src/Resources/config/doctrine/model/AffiliateOrder.orm.xml
new file mode 100644
index 0000000..8fff931
--- /dev/null
+++ b/src/Resources/config/doctrine/model/AffiliateOrder.orm.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Resources/config/doctrine/model/Program.orm.xml b/src/Resources/config/doctrine/model/Program.orm.xml
index 2820aed..f3b0560 100644
--- a/src/Resources/config/doctrine/model/Program.orm.xml
+++ b/src/Resources/config/doctrine/model/Program.orm.xml
@@ -1,24 +1,21 @@
-
-
-
-
-
-
-
-
+
-
-
+
+
-
-
+
+
+
+
+
diff --git a/src/Resources/config/routing.yaml b/src/Resources/config/routes.yaml
similarity index 65%
rename from src/Resources/config/routing.yaml
rename to src/Resources/config/routes.yaml
index cfeb411..af32234 100644
--- a/src/Resources/config/routing.yaml
+++ b/src/Resources/config/routes.yaml
@@ -1,3 +1,3 @@
setono_sylius_partner_ads_admin:
- resource: routing/admin.yaml
+ resource: routes/admin.yaml
prefix: /admin/partner-ads
diff --git a/src/Resources/config/routing/admin.yaml b/src/Resources/config/routes/admin.yaml
similarity index 100%
rename from src/Resources/config/routing/admin.yaml
rename to src/Resources/config/routes/admin.yaml
diff --git a/src/Resources/config/services.xml b/src/Resources/config/services.xml
index 34524bb..7e77104 100644
--- a/src/Resources/config/services.xml
+++ b/src/Resources/config/services.xml
@@ -1,16 +1,17 @@
-
+
-
+
-
+
+
+
-
-
diff --git a/src/Resources/config/services/client.xml b/src/Resources/config/services/client.xml
deleted file mode 100644
index 65a3349..0000000
--- a/src/Resources/config/services/client.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Resources/config/services/command.xml b/src/Resources/config/services/command.xml
new file mode 100644
index 0000000..c7e6bdd
--- /dev/null
+++ b/src/Resources/config/services/command.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Resources/config/services/cookie_handler.xml b/src/Resources/config/services/cookie_handler.xml
index bf7209c..2a343cb 100644
--- a/src/Resources/config/services/cookie_handler.xml
+++ b/src/Resources/config/services/cookie_handler.xml
@@ -1,10 +1,16 @@
-
+
-
+
+
+ %setono_sylius_partner_ads.query_parameter%
%setono_sylius_partner_ads.cookie.name%
%setono_sylius_partner_ads.cookie.expire%
+
+
diff --git a/src/Resources/config/services/dispatcher.xml b/src/Resources/config/services/dispatcher.xml
new file mode 100644
index 0000000..c5252c5
--- /dev/null
+++ b/src/Resources/config/services/dispatcher.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Resources/config/services/event_listener.xml b/src/Resources/config/services/event_listener.xml
deleted file mode 100644
index 31bd771..0000000
--- a/src/Resources/config/services/event_listener.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- %setono_sylius_partner_ads.query_parameter%
-
-
-
-
diff --git a/src/Resources/config/services/event_subscriber.xml b/src/Resources/config/services/event_subscriber.xml
new file mode 100644
index 0000000..9747da3
--- /dev/null
+++ b/src/Resources/config/services/event_subscriber.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Resources/config/services/factory.xml b/src/Resources/config/services/factory.xml
new file mode 100644
index 0000000..86559f7
--- /dev/null
+++ b/src/Resources/config/services/factory.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/Resources/config/services/http_client.xml b/src/Resources/config/services/http_client.xml
deleted file mode 100644
index 99c8a9b..0000000
--- a/src/Resources/config/services/http_client.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/src/Resources/config/services/message.xml b/src/Resources/config/services/message.xml
index 5e13e97..a3e7fa5 100644
--- a/src/Resources/config/services/message.xml
+++ b/src/Resources/config/services/message.xml
@@ -1,7 +1,7 @@
-
-
-
-
+
+
+
diff --git a/src/Resources/config/services/message/handler.xml b/src/Resources/config/services/message/handler.xml
deleted file mode 100644
index 279740f..0000000
--- a/src/Resources/config/services/message/handler.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Resources/config/services/url_provider.xml b/src/Resources/config/services/url_provider.xml
deleted file mode 100644
index 3a5f492..0000000
--- a/src/Resources/config/services/url_provider.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
- %setono_sylius_partner_ads.urls.notify%
-
-
-
diff --git a/src/SetonoSyliusPartnerAdsPlugin.php b/src/SetonoSyliusPartnerAdsPlugin.php
index 0ac2c7f..1727fe5 100644
--- a/src/SetonoSyliusPartnerAdsPlugin.php
+++ b/src/SetonoSyliusPartnerAdsPlugin.php
@@ -4,25 +4,14 @@
namespace Setono\SyliusPartnerAdsPlugin;
-use Setono\SyliusPartnerAdsPlugin\DependencyInjection\Compiler\RegisterCommandBusPass;
-use Setono\SyliusPartnerAdsPlugin\DependencyInjection\Compiler\RegisterHttpClientPass;
use Sylius\Bundle\CoreBundle\Application\SyliusPluginTrait;
use Sylius\Bundle\ResourceBundle\AbstractResourceBundle;
use Sylius\Bundle\ResourceBundle\SyliusResourceBundle;
-use Symfony\Component\DependencyInjection\ContainerBuilder;
final class SetonoSyliusPartnerAdsPlugin extends AbstractResourceBundle
{
use SyliusPluginTrait;
- public function build(ContainerBuilder $container): void
- {
- parent::build($container);
-
- $container->addCompilerPass(new RegisterCommandBusPass());
- $container->addCompilerPass(new RegisterHttpClientPass());
- }
-
public function getSupportedDrivers(): array
{
return [
diff --git a/src/UrlProvider/NotifyUrlProvider.php b/src/UrlProvider/NotifyUrlProvider.php
deleted file mode 100644
index a9ac7cf..0000000
--- a/src/UrlProvider/NotifyUrlProvider.php
+++ /dev/null
@@ -1,34 +0,0 @@
-url = $url;
- }
-
- public function provide(int $programId, string $orderId, float $value, int $partnerId, string $ip): string
- {
- $variables = ['{program_id}', '{partner_id}', '{ip}', '{order_id}', '{value}'];
-
- foreach ($variables as $variable) {
- if (mb_strpos($this->url, $variable) === false) {
- throw new MissingVariableInUrlException($this->url, $variable);
- }
- }
-
- return str_replace(
- ['{program_id}', '{partner_id}', '{ip}', '{order_id}', '{value}'],
- [$programId, $partnerId, $ip, $orderId, $value],
- $this->url
- );
- }
-}
diff --git a/src/UrlProvider/NotifyUrlProviderInterface.php b/src/UrlProvider/NotifyUrlProviderInterface.php
deleted file mode 100644
index 311c347..0000000
--- a/src/UrlProvider/NotifyUrlProviderInterface.php
+++ /dev/null
@@ -1,15 +0,0 @@
-programId = $programId;
+ $this->partnerId = $partnerId;
+ $this->ip = $ip;
+ $this->orderNumber = $orderNumber;
+ $this->orderTotal = $orderTotal;
+ }
+
+ public function value(): string
+ {
+ return sprintf(
+ 'https://www.partner-ads.com/dk/leadtracks2s.php?programid=%d&type=salg&partnerid=%d&userip=%s&ordreid=%s&varenummer=x&antal=1&omprsalg=%F',
+ $this->programId,
+ $this->partnerId,
+ $this->ip,
+ $this->orderNumber,
+ round($this->orderTotal / 100, 2)
+ );
+ }
+
+ public function __toString(): string
+ {
+ return $this->value();
+ }
+}
diff --git a/src/Workflow/AffiliateOrderWorkflow.php b/src/Workflow/AffiliateOrderWorkflow.php
new file mode 100644
index 0000000..7337668
--- /dev/null
+++ b/src/Workflow/AffiliateOrderWorkflow.php
@@ -0,0 +1,77 @@
+
+ */
+ public static function getStates(): array
+ {
+ return [
+ AffiliateOrderInterface::STATE_FAILED,
+ AffiliateOrderInterface::STATE_INITIAL,
+ AffiliateOrderInterface::STATE_PENDING,
+ AffiliateOrderInterface::STATE_PROCESSING,
+ AffiliateOrderInterface::STATE_SENT,
+ ];
+ }
+
+ public static function getConfig(): array
+ {
+ $transitions = [];
+ foreach (self::getTransitions() as $transition) {
+ $transitions[$transition->getName()] = [
+ 'from' => $transition->getFroms(),
+ 'to' => $transition->getTos(),
+ ];
+ }
+
+ return [
+ self::NAME => [
+ 'type' => 'state_machine',
+ 'marking_store' => [
+ 'type' => 'method',
+ 'property' => 'state',
+ ],
+ 'supports' => AffiliateOrderInterface::class,
+ 'initial_marking' => AffiliateOrderInterface::STATE_INITIAL,
+ 'places' => self::getStates(),
+ 'transitions' => $transitions,
+ ],
+ ];
+ }
+
+ /**
+ * @return array
+ */
+ public static function getTransitions(): array
+ {
+ return [
+ new Transition(self::TRANSITION_START, AffiliateOrderInterface::STATE_INITIAL, AffiliateOrderInterface::STATE_PENDING),
+ new Transition(self::TRANSITION_PROCESS, AffiliateOrderInterface::STATE_PENDING, AffiliateOrderInterface::STATE_PROCESSING),
+ new Transition(self::TRANSITION_SEND, AffiliateOrderInterface::STATE_PROCESSING, AffiliateOrderInterface::STATE_SENT),
+ new Transition(self::TRANSITION_FAIL, self::getStates(), AffiliateOrderInterface::STATE_FAILED),
+ ];
+ }
+}
diff --git a/tests/Application/Client/Client.php b/tests/Application/Client/Client.php
deleted file mode 100644
index 57256f4..0000000
--- a/tests/Application/Client/Client.php
+++ /dev/null
@@ -1,31 +0,0 @@
-notifyUrlProvider = $notifyUrlProvider;
- $this->logger = $logger;
- }
-
- public function notify(int $programId, string $orderId, float $total, int $partnerId, string $ip): void
- {
- $url = $this->notifyUrlProvider->provide($programId, $orderId, $total, $partnerId, $ip);
-
- $this->logger->debug('Notify request: ' . $url);
- }
-}
diff --git a/tests/Application/config/packages/setono_sylius_partner_ads.yaml b/tests/Application/config/packages/setono_sylius_partner_ads.yaml
index 1593f48..336ad13 100644
--- a/tests/Application/config/packages/setono_sylius_partner_ads.yaml
+++ b/tests/Application/config/packages/setono_sylius_partner_ads.yaml
@@ -1,6 +1,2 @@
imports:
- { resource: "@SetonoSyliusPartnerAdsPlugin/Resources/config/app/config.yaml" }
-
-setono_sylius_partner_ads:
- urls:
- notify: http://127.0.0.1:8000/callback.php?programid={program_id}&type=salg&partnerid={partner_id}&userip={ip}&ordreid={order_id}&varenummer=x&antal=1&omprsalg={value}
diff --git a/tests/Application/config/routes.yaml b/tests/Application/config/routes.yaml
index e808adc..e69de29 100644
--- a/tests/Application/config/routes.yaml
+++ b/tests/Application/config/routes.yaml
@@ -1,2 +0,0 @@
-setono_partner_ads_plugin:
- resource: "@SetonoSyliusPartnerAdsPlugin/Resources/config/routing.yaml"
diff --git a/tests/Application/config/routes/dev/twig.yaml b/tests/Application/config/routes/dev/twig.yaml
deleted file mode 100644
index f4ee839..0000000
--- a/tests/Application/config/routes/dev/twig.yaml
+++ /dev/null
@@ -1,3 +0,0 @@
-_errors:
- resource: '@TwigBundle/Resources/config/routing/errors.xml'
- prefix: /_error
diff --git a/tests/Application/config/routes/setono_partner_ads_plugin.yaml b/tests/Application/config/routes/setono_partner_ads_plugin.yaml
new file mode 100644
index 0000000..7a1ba41
--- /dev/null
+++ b/tests/Application/config/routes/setono_partner_ads_plugin.yaml
@@ -0,0 +1,2 @@
+setono_partner_ads_plugin:
+ resource: "@SetonoSyliusPartnerAdsPlugin/Resources/config/routes.yaml"
diff --git a/tests/Application/config/services.yaml b/tests/Application/config/services.yaml
index a4a0d81..615506e 100644
--- a/tests/Application/config/services.yaml
+++ b/tests/Application/config/services.yaml
@@ -2,10 +2,3 @@
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
locale: en_US
-
-services:
- Tests\Setono\SyliusPartnerAdsPlugin\Application\Client\Client:
- decorates: setono_sylius_partner_ads.client.default
- arguments:
- - '@setono_sylius_partner_ads.url_provider.notify'
- - '@logger'
diff --git a/tests/CookieHandler/CookieHandlerTest.php b/tests/CookieHandler/CookieHandlerTest.php
index e4b2557..0c3d49a 100644
--- a/tests/CookieHandler/CookieHandlerTest.php
+++ b/tests/CookieHandler/CookieHandlerTest.php
@@ -39,26 +39,6 @@ public function it_sets(): void
$this->assertSame($this->expire, $expireInDays);
}
- /**
- * @test
- */
- public function it_removes(): void
- {
- $response = new Response();
- $cookieHandler = $this->createCookieHandler($response);
-
- $cookieHandler->remove($response);
-
- $cookies = $response->headers->getCookies();
-
- $this->assertCount(1, $cookies);
-
- $cookie = $cookies[0];
-
- $this->assertSame($this->name, $cookie->getName());
- $this->assertNull($cookie->getValue());
- }
-
/**
* @test
*/
@@ -67,7 +47,7 @@ public function it_gets_the_value(): void
$cookieHandler = $this->createCookieHandler(new Response());
$request = $this->createRequest();
- $value = $cookieHandler->get($request);
+ $value = $cookieHandler->value($request);
$this->assertSame($this->partnerId, $value);
}
@@ -80,7 +60,7 @@ public function it_returns_true_if_cookie_is_set(): void
$cookieHandler = $this->createCookieHandler(new Response());
$request = $this->createRequest();
- $this->assertTrue($cookieHandler->has($request));
+ $this->assertTrue($cookieHandler->isset($request));
}
/**
@@ -91,7 +71,7 @@ public function it_returns_false_if_cookie_is_not_set(): void
$cookieHandler = $this->createCookieHandler(new Response());
$request = $this->createRequest('doesnotexist');
- $this->assertFalse($cookieHandler->has($request));
+ $this->assertFalse($cookieHandler->isset($request));
}
private function createCookieHandler(Response $response): CookieHandler