Skip to content

Commit

Permalink
Merge branch '1.13' into 1.14
Browse files Browse the repository at this point in the history
* 1.13:
  [CS][DX] Refactor
  [CS][DX] Refactor
  Apply Review fixes
  fix the build
  fallback order item test
  add contract tests
  Filter order items collection for visitors and shop users
  Add voter for the adjustments subresources
  Resolve createdByGuest on order fixtures
  • Loading branch information
GSadee committed Jun 6, 2024
2 parents 9420df1 + a59b1b7 commit 59f1d17
Show file tree
Hide file tree
Showing 21 changed files with 843 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ Feature: Receiving discounts with product minimum price specified
Given the store operates on a single channel in "United States"
And the store ships everywhere for Free
And the store allows paying Offline
And I am a logged in customer
And the store classifies its products as "T-Shirts"
And the store has a "T-Shirt" configurable product
And this product has "PHP T-Shirt" variant priced at "$50.00"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Core\Repository\OrderRepositoryInterface;
use Sylius\Component\Order\Model\AdjustmentInterface;
use Webmozart\Assert\Assert;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

final class OrderAdjustmentsSubresourceDataProvider implements RestrictedDataProviderInterface, SubresourceDataProviderInterface
{
Expand All @@ -43,7 +43,9 @@ public function getSubresource(string $resourceClass, array $identifiers, array

/** @var OrderInterface|null $order */
$order = $this->orderRepository->findOneBy(['tokenValue' => $subresourceIdentifiers['tokenValue']]);
Assert::notNull($order);
if ($order === null) {
throw new NotFoundHttpException('Order not found');
}

return $order->getAdjustmentsRecursively();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?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\Bundle\ApiBundle\Doctrine\QueryCollectionExtension;

use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\ContextAwareQueryCollectionExtensionInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use Doctrine\ORM\QueryBuilder;
use Sylius\Bundle\ApiBundle\Context\UserContextInterface;
use Sylius\Component\Core\Model\OrderItemInterface;
use Sylius\Component\Core\Model\ShopUserInterface;

final class OrderItemsByShopUserExtension implements ContextAwareQueryCollectionExtensionInterface
{
public function __construct(private UserContextInterface $userContext)
{
}

/** @param array<string, mixed> $context */
public function applyToCollection(
QueryBuilder $queryBuilder,
QueryNameGeneratorInterface $queryNameGenerator,
string $resourceClass,
?string $operationName = null,
array $context = [],
): void {
if (!is_a($resourceClass, OrderItemInterface::class, true)) {
return;
}

$user = $this->userContext->getUser();
if (!$user instanceof ShopUserInterface) {
return;
}

$rootAlias = $queryBuilder->getRootAliases()[0];
$orderParameterName = $queryNameGenerator->generateParameterName('order');
$customerJoinParameterName = $queryNameGenerator->generateJoinAlias('customer_join');
$customerParameterName = $queryNameGenerator->generateParameterName('customer');

$queryBuilder
->leftJoin(sprintf('%s.order', $rootAlias), $orderParameterName)
->leftJoin(sprintf('%s.customer', $orderParameterName), $customerJoinParameterName)
->andWhere(sprintf('%s = :%s', $customerJoinParameterName, $customerParameterName))
->setParameter($customerParameterName, $user->getCustomer()->getId())
->addOrderBy(sprintf('%s.id', $rootAlias), 'ASC')
;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?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\Bundle\ApiBundle\Doctrine\QueryCollectionExtension;

use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\ContextAwareQueryCollectionExtensionInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use Doctrine\ORM\QueryBuilder;
use Sylius\Bundle\ApiBundle\Context\UserContextInterface;
use Sylius\Component\Core\Model\OrderItemInterface;

final class OrderItemsByVisitorExtension implements ContextAwareQueryCollectionExtensionInterface
{
public function __construct(private UserContextInterface $userContext)
{
}

/** @param array<string, mixed> $context */
public function applyToCollection(
QueryBuilder $queryBuilder,
QueryNameGeneratorInterface $queryNameGenerator,
string $resourceClass,
?string $operationName = null,
array $context = [],
): void {
if (!is_a($resourceClass, OrderItemInterface::class, true)) {
return;
}

$user = $this->userContext->getUser();
if ($user !== null) {
return;
}

$rootAlias = $queryBuilder->getRootAliases()[0];
$orderParameterName = $queryNameGenerator->generateJoinAlias('order');
$customerParameterName = $queryNameGenerator->generateJoinAlias('customer');
$userParameterName = $queryNameGenerator->generateJoinAlias('user');

$queryBuilder
->leftJoin(sprintf('%s.order', $rootAlias), $orderParameterName)
->leftJoin(sprintf('%s.customer', $orderParameterName), $customerParameterName)
->leftJoin(sprintf('%s.user', $customerParameterName), $userParameterName)
->andWhere(
$queryBuilder->expr()->andX(
$queryBuilder->expr()->isNull($userParameterName),
$queryBuilder->expr()->eq(sprintf('%s.createdByGuest', $orderParameterName), ':createdByGuest'),
),
)
->setParameter('createdByGuest', true)
->addOrderBy(sprintf('%s.id', $rootAlias), 'ASC')
;
}
}
37 changes: 37 additions & 0 deletions src/Sylius/Bundle/ApiBundle/Provider/AdjustmentOrderProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?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\Bundle\ApiBundle\Provider;

use Sylius\Component\Core\Model\AdjustmentInterface;
use Sylius\Component\Core\Model\OrderItemInterface;
use Sylius\Component\Core\Model\OrderItemUnitInterface;
use Sylius\Component\Order\Model\OrderInterface;

/** @experimental */
final class AdjustmentOrderProvider implements AdjustmentOrderProviderInterface
{
public function provide(AdjustmentInterface $adjustment): ?OrderInterface
{
switch ($adjustment) {
case $adjustment->getAdjustable() instanceof OrderInterface:
return $adjustment->getOrder();
case $adjustment->getAdjustable() instanceof OrderItemInterface:
return $adjustment->getOrderItem()->getOrder();
case $adjustment->getAdjustable() instanceof OrderItemUnitInterface:
return $adjustment->getOrderItemUnit()->getOrderItem()->getOrder();
default:
return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?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\Bundle\ApiBundle\Provider;

use Sylius\Component\Core\Model\AdjustmentInterface;
use Sylius\Component\Order\Model\OrderInterface;

/** @experimental */
interface AdjustmentOrderProviderInterface
{
public function provide(AdjustmentInterface $adjustment): ?OrderInterface;
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@

<subresourceOperations>
<subresourceOperation name="api_orders_adjustments_get_subresource">
<attribute name="access_control">is_granted('SYLIUS_ORDER_ADJUSTMENT', object)</attribute>
<attribute name="normalization_context">
<attribute name="groups">
<attribute>shop:cart:show</attribute>
Expand All @@ -53,6 +54,7 @@
</subresourceOperation>

<subresourceOperation name="api_orders_items_adjustments_get_subresource">
<attribute name="access_control">is_granted('SYLIUS_ORDER_ADJUSTMENT', object)</attribute>
<attribute name="normalization_context">
<attribute name="groups">
<attribute>shop:cart:show</attribute>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@
<tag name="api_platform.doctrine.orm.query_extension.collection" />
</service>

<service id="Sylius\Bundle\ApiBundle\Doctrine\QueryCollectionExtension\OrderItemsByVisitorExtension">
<argument type="service" id="Sylius\Bundle\ApiBundle\Context\UserContextInterface" />
<tag name="api_platform.doctrine.orm.query_extension.collection" />
</service>

<service id="Sylius\Bundle\ApiBundle\Doctrine\QueryCollectionExtension\OrderItemsByShopUserExtension">
<argument type="service" id="Sylius\Bundle\ApiBundle\Context\UserContextInterface" />
<tag name="api_platform.doctrine.orm.query_extension.collection" />
</service>

<service id="Sylius\Bundle\ApiBundle\Doctrine\QueryCollectionExtension\OrdersByLoggedInUserExtension">
<argument type="service" id="Sylius\Bundle\ApiBundle\Context\UserContextInterface" />
<tag name="api_platform.doctrine.orm.query_extension.collection" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
<service id="sylius.api.provider.liip_image_filters" class="Sylius\Bundle\ApiBundle\Provider\LiipImageFiltersProvider">
<argument>%liip_imagine.filter_sets%</argument>
</service>

<service id="Sylius\Bundle\ApiBundle\Provider\ImageFiltersProviderInterface" alias="sylius.api.provider.liip_image_filters" />

<service id="Sylius\Bundle\ApiBundle\Provider\AdjustmentOrderProviderInterface" class="Sylius\Bundle\ApiBundle\Provider\AdjustmentOrderProvider" />
</services>
</container>
24 changes: 24 additions & 0 deletions src/Sylius/Bundle/ApiBundle/Resources/config/services/security.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>

<!--
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.
-->

<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"
>
<services>
<service id="sylius_api.security.voter.order" class="Sylius\Bundle\ApiBundle\Security\OrderAdjustmentsVoter">
<argument type="service" id="Sylius\Bundle\ApiBundle\Provider\AdjustmentOrderProviderInterface" />
<tag name="security.voter" />
</service>
</services>
</container>
65 changes: 65 additions & 0 deletions src/Sylius/Bundle/ApiBundle/Security/OrderAdjustmentsVoter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?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\Bundle\ApiBundle\Security;

use Doctrine\Common\Collections\Collection;
use Sylius\Bundle\ApiBundle\Provider\AdjustmentOrderProviderInterface;
use Sylius\Component\Core\Model\AdjustmentInterface;
use Sylius\Component\Core\Model\OrderInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;

final class OrderAdjustmentsVoter extends Voter
{
public function __construct(private AdjustmentOrderProviderInterface $adjustmentOrderProvider)
{
}

public const SYLIUS_ORDER_ADJUSTMENT = 'SYLIUS_ORDER_ADJUSTMENT';

protected function supports(string $attribute, mixed $subject): bool
{
return $subject instanceof Collection;
}

public function supportsAttribute(string $attribute): bool
{
return self::SYLIUS_ORDER_ADJUSTMENT === $attribute;
}

protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
{
$user = $token->getUser();

if ($subject === [] || $subject->isEmpty() || !$subject->first() instanceof AdjustmentInterface) {
return true;
}

/** @var AdjustmentInterface $subjectItem */
foreach ($subject as $subjectItem) {
if ($this->adjustmentOrderProvider->provide($subjectItem)) {
/** @var OrderInterface $order */
$order = $this->adjustmentOrderProvider->provide($subjectItem);

if (!$order->isCreatedByGuest() || $order->getUser()) {
return $order->getUser() === $user;
}

break;
}
}

return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use Sylius\Component\Core\Repository\OrderRepositoryInterface;
use Sylius\Component\Order\Model\AdjustmentInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

final class OrderAdjustmentsSubresourceDataProviderSpec extends ObjectBehavior
{
Expand Down Expand Up @@ -54,7 +55,7 @@ function it_throws_an_exception_if_order_with_given_token_does_not_exist(OrderRe
$orderRepository->findOneBy(['tokenValue' => 'TOKEN'])->willReturn(null);

$this
->shouldThrow(\InvalidArgumentException::class)
->shouldThrow(NotFoundHttpException::class)
->during('getSubresource', [
AdjustmentInterface::class,
[],
Expand Down
Loading

0 comments on commit 59f1d17

Please sign in to comment.