Skip to content

Commit

Permalink
refactor #795 Init factory provider (loic425)
Browse files Browse the repository at this point in the history
This PR was merged into the 1.11 branch.

Discussion
----------

| Q               | A
| --------------- | -----
| Bug fix?        | no
| New feature?    | yes
| BC breaks?      | no
| Deprecations?   | no
| Related tickets | 
| License         | MIT

Based on #794 

Commits
-------

9f46bfd Phpunit tests for Symfony factory listener
145c13e Init factory provider
cd70829 Fix coding standard
  • Loading branch information
lchrusciel authored Nov 24, 2023
2 parents 7f9f07a + cd70829 commit ae385e3
Show file tree
Hide file tree
Showing 4 changed files with 313 additions and 120 deletions.
134 changes: 134 additions & 0 deletions src/Component/Tests/State/Provider/FactoryProviderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace State\Provider;

use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use Prophecy\Prophecy\ObjectProphecy;
use Sylius\Component\Resource\src\State\Provider\FactoryProvider;
use Sylius\Resource\Context\Context;
use Sylius\Resource\Context\Option\RequestOption;
use Sylius\Resource\Metadata\Create;
use Sylius\Resource\Metadata\Update;
use Sylius\Resource\State\FactoryInterface;
use Sylius\Resource\State\ProviderInterface;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\HttpFoundation\Request;

final class FactoryProviderTest extends TestCase
{
use ProphecyTrait;

private ProviderInterface|ObjectProphecy $decorated;

private FactoryInterface|ObjectProphecy $factory;

private FactoryProvider $factoryProvider;

protected function setUp(): void
{
$this->decorated = $this->prophesize(ProviderInterface::class);
$this->factory = $this->prophesize(FactoryInterface::class);

$this->factoryProvider = new FactoryProvider(
$this->decorated->reveal(),
$this->factory->reveal(),
);
}

/** @test */
public function it_uses_factory_from_operation(): void
{
$request = $this->prophesize(Request::class);
$attributes = $this->prophesize(ParameterBag::class);
$data = $this->prophesize(\stdClass::class);

$operation = new Create();

$context = new Context(new RequestOption($request->reveal()));

$this->decorated->provide($operation, $context)->willReturn(['foo' => 'fighters'])->shouldBeCalled();

$request->attributes = $attributes;

$this->factory->create($operation, $context)->willReturn($data)->shouldBeCalled();

$attributes->set('data', $data)->shouldBeCalled();

$this->factoryProvider->provide($operation, $context);
}

/** @test */
public function it_does_not_store_data_on_request_when_it_does_not_exist(): void
{
$attributes = $this->prophesize(ParameterBag::class);
$data = $this->prophesize(\stdClass::class);

$operation = new Create();

$context = new Context();

$this->decorated->provide($operation, $context)->willReturn(['foo' => 'fighters'])->shouldBeCalled();

$this->factory->create($operation, $context)->willReturn($data)->shouldBeCalled();

$attributes->set('data', $data)->shouldNotBeCalled();

$this->factoryProvider->provide($operation, $context);
}

/** @test */
public function it_does_nothing_when_operation_is_not_a_factory_aware_operation(): void
{
$request = $this->prophesize(Request::class);
$attributes = $this->prophesize(ParameterBag::class);
$data = $this->prophesize(\stdClass::class);

$operation = new Update();

$context = new Context();

$this->decorated->provide($operation, $context)->willReturn(['foo' => 'fighters'])->shouldBeCalled();

$request->attributes = $attributes;

$this->factory->create($operation, $context)->willReturn($data)->shouldNotBeCalled();

$attributes->set('data', $data)->shouldNotBeCalled();

$this->factoryProvider->provide($operation, $context);
}

/** @test */
public function it_does_nothing_when_factory_is_disabled(): void
{
$request = $this->prophesize(Request::class);
$attributes = $this->prophesize(ParameterBag::class);
$data = $this->prophesize(\stdClass::class);

$operation = new Create(factory: false);

$context = new Context();

$this->decorated->provide($operation, $context)->willReturn(['foo' => 'fighters'])->shouldBeCalled();

$request->attributes = $attributes;

$this->factory->create($operation, $context)->willReturn($data)->shouldNotBeCalled();

$attributes->set('data', $data)->shouldNotBeCalled();

$this->factoryProvider->provide($operation, $context);
}
}
129 changes: 129 additions & 0 deletions src/Component/Tests/Symfony/EventListener/FactoryListenerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Sylius\Component\Resource\Tests\Symfony\EventListener;

use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use Prophecy\Prophecy\ObjectProphecy;
use Sylius\Resource\Context\Context;
use Sylius\Resource\Context\Initiator\RequestContextInitiatorInterface;
use Sylius\Resource\Metadata\Create;
use Sylius\Resource\Metadata\Operation\HttpOperationInitiatorInterface;
use Sylius\Resource\Metadata\Update;
use Sylius\Resource\State\FactoryInterface;
use Sylius\Resource\Symfony\EventListener\FactoryListener;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\RequestEvent;

final class FactoryListenerTest extends TestCase
{
use ProphecyTrait;

private HttpOperationInitiatorInterface|ObjectProphecy $operationInitiator;

private RequestContextInitiatorInterface|ObjectProphecy $requestContextInitiator;

private FactoryInterface|ObjectProphecy $factory;

private FactoryListener $factoryListener;

protected function setUp(): void
{
$this->operationInitiator = $this->prophesize(HttpOperationInitiatorInterface::class);
$this->requestContextInitiator = $this->prophesize(RequestContextInitiatorInterface::class);
$this->factory = $this->prophesize(FactoryInterface::class);

$this->factoryListener = new FactoryListener(
$this->operationInitiator->reveal(),
$this->requestContextInitiator->reveal(),
$this->factory->reveal(),
);
}

/** @test */
public function it_uses_factory_from_operation(): void
{
$event = $this->prophesize(RequestEvent::class);
$request = $this->prophesize(Request::class);
$attributes = $this->prophesize(ParameterBag::class);
$data = $this->prophesize(\stdClass::class);

$operation = new Create();

$event->getRequest()->willReturn($request);
$request->attributes = $attributes;

$context = new Context();

$this->operationInitiator->initializeOperation($request)->willReturn($operation);
$this->requestContextInitiator->initializeContext($request)->willReturn($context);

$this->factory->create($operation, $context)->willReturn($data)->shouldBeCalled();

$attributes->set('data', $data)->shouldBeCalled();

$this->factoryListener->onKernelRequest($event->reveal());
}

/** @test */
public function it_does_nothing_when_operation_is_not_a_create_operation(): void
{
$event = $this->prophesize(RequestEvent::class);
$request = $this->prophesize(Request::class);
$attributes = $this->prophesize(ParameterBag::class);
$data = $this->prophesize(\stdClass::class);

$operation = new Update();

$event->getRequest()->willReturn($request);
$request->attributes = $attributes;

$context = new Context();

$this->operationInitiator->initializeOperation($request)->willReturn($operation);
$this->requestContextInitiator->initializeContext($request)->willReturn($context);

$this->factory->create($operation, $context)->willReturn($data)->shouldNotBeCalled();

$attributes->set('data', $data)->shouldNotBeCalled();

$this->factoryListener->onKernelRequest($event->reveal());
}

/** @test */
public function it_does_nothing_when_factory_is_disabled(): void
{
$event = $this->prophesize(RequestEvent::class);
$request = $this->prophesize(Request::class);
$attributes = $this->prophesize(ParameterBag::class);
$data = $this->prophesize(\stdClass::class);

$operation = new Create(factory: false);

$event->getRequest()->willReturn($request);
$request->attributes = $attributes;

$context = new Context();

$this->operationInitiator->initializeOperation($request)->willReturn($operation);
$this->requestContextInitiator->initializeContext($request)->willReturn($context);

$this->factory->create($operation, $context)->willReturn($data)->shouldNotBeCalled();

$attributes->set('data', $data)->shouldNotBeCalled();

$this->factoryListener->onKernelRequest($event->reveal());
}
}
50 changes: 50 additions & 0 deletions src/Component/src/State/Provider/FactoryProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Sylius\Component\Resource\src\State\Provider;

use Sylius\Resource\Context\Context;
use Sylius\Resource\Context\Option\RequestOption;
use Sylius\Resource\Metadata\FactoryAwareOperationInterface;
use Sylius\Resource\Metadata\Operation;
use Sylius\Resource\State\FactoryInterface;
use Sylius\Resource\State\ProviderInterface;

final class FactoryProvider implements ProviderInterface
{
public function __construct(
private ProviderInterface $decorated,
private FactoryInterface $factory,
) {
}

public function provide(Operation $operation, Context $context): object|array|null
{
$data = $this->decorated->provide($operation, $context);

$request = $context->get(RequestOption::class)?->request();

if (
!$operation instanceof FactoryAwareOperationInterface ||
!($operation->getFactory() ?? true)
) {
return $data;
}

$data = $this->factory->create($operation, $context);

$request?->attributes->set('data', $data);

return $data;
}
}
Loading

0 comments on commit ae385e3

Please sign in to comment.