[Locales] Create ADR for locales exposing

This commit is contained in:
Adam Kasperczak 2021-07-02 12:19:58 +02:00
parent d516bf1233
commit 90ceff637e
5 changed files with 55 additions and 17 deletions

View file

@ -0,0 +1,26 @@
# Using data provider for getting available locales in active channel for shop user
* Status: proposed
* Date: 2021-07-05
## Context and Problem Statement
Customer should have access only to locales available in their channel
## Considered Options
### Using Doctrine Collection extension
* Good, because consistent with actual approach to modifying responses content
* Good, because works with rest of API extension like pagination
* Bad, because locales don't have relation to channel, so using Doctrine Collection extension is extremely hard.
### Using Data Provider
* Good, because we already have this approach for older resources
* Good, because easy to implement
* Bad, because using data providers omits extra Doctrine extensions like pagination
## Decision Outcome
Chosen option: Using Data Provider
Shops shouldn't have many locales for each channel, so lack of a pagination is smaller problem than creating overcomplicated query in Doctrine Collection extension

View file

@ -1,5 +1,5 @@
@locales
Feature: Getting a available locales in current channel
Feature: Getting available locales in the current channel
In order to use a shop in chosen locale
As a Customer
I want to be able to get available locales

View file

@ -56,9 +56,11 @@ final class LocaleContext implements Context
*/
public function theLocaleWithCodeShouldBeAvailable(string $name, string $code): void
{
Assert::true(
$this->isLocaleWithName($name, $this->responseChecker->getCollection($this->client->getLastResponse()))
);
Assert::true($this->isLocaleWithNameAndCode(
$this->responseChecker->getCollection($this->client->getLastResponse()),
$name,
$code
));
}
/**
@ -66,15 +68,17 @@ final class LocaleContext implements Context
*/
public function theLocaleWithCodeShouldNotBeAvailable(string $name, string $code): void
{
Assert::false(
$this->isLocaleWithName($name, $this->responseChecker->getCollection($this->client->getLastResponse()))
);
Assert::false($this->isLocaleWithNameAndCode(
$this->responseChecker->getCollection($this->client->getLastResponse()),
$name,
$code
));
}
private function isLocaleWithName(string $name, array $locales): bool
private function isLocaleWithNameAndCode(array $locales, string $name, string $code): bool
{
foreach ($locales as $locale) {
if ($locale['name'] === $name) {
if ($locale['name'] === $name && $locale['code'] === $code) {
return true;
}
}

View file

@ -15,8 +15,10 @@ namespace Sylius\Bundle\ApiBundle\DataProvider;
use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface;
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
use Doctrine\Common\Collections\Collection;
use Sylius\Bundle\ApiBundle\Context\UserContextInterface;
use Sylius\Bundle\ApiBundle\Serializer\ContextKeys;
use Sylius\Component\Core\Model\AdminUserInterface;
use Sylius\Component\Core\Model\ChannelInterface;
use Sylius\Component\Locale\Model\LocaleInterface;
use Sylius\Component\Resource\Repository\RepositoryInterface;
@ -31,8 +33,10 @@ final class LocaleCollectionDataProvider implements CollectionDataProviderInterf
/** @var UserContextInterface */
private $userContext;
public function __construct(RepositoryInterface $localeRepository, UserContextInterface $userContext)
{
public function __construct(
RepositoryInterface $localeRepository,
UserContextInterface $userContext
) {
$this->localeRepository = $localeRepository;
$this->userContext = $userContext;
}
@ -44,12 +48,14 @@ final class LocaleCollectionDataProvider implements CollectionDataProviderInterf
public function getCollection(string $resourceClass, string $operationName = null, array $context = [])
{
Assert::keyExists($context, ContextKeys::CHANNEL);
$user = $this->userContext->getUser();
if ($user !== null && in_array('ROLE_API_ACCESS', $user->getRoles())) {
if ($user instanceof AdminUserInterface && in_array('ROLE_API_ACCESS', $user->getRoles())) {
return $this->localeRepository->findAll();
}
Assert::keyExists($context, ContextKeys::CHANNEL);
/** @var ChannelInterface $channel */
$channel = $context[ContextKeys::CHANNEL];

View file

@ -14,9 +14,11 @@ declare(strict_types=1);
namespace spec\Sylius\Bundle\ApiBundle\DataProvider;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use PhpSpec\ObjectBehavior;
use Sylius\Bundle\ApiBundle\Context\UserContextInterface;
use Sylius\Bundle\ApiBundle\Serializer\ContextKeys;
use Sylius\Component\Core\Model\AdminUserInterface;
use Sylius\Component\Core\Model\ChannelInterface;
use Sylius\Component\Core\Model\ProductInterface;
use Sylius\Component\Locale\Model\LocaleInterface;
@ -57,17 +59,17 @@ final class LocaleCollectionDataProviderSpec extends ObjectBehavior
$channel->addLocale($firstLocale);
$channel->addLocale($secondLocale);
$channel->getLocales()->willReturn([$firstLocale, $secondLocale]);
$channel->getLocales()->willReturn(new ArrayCollection([$firstLocale->getWrappedObject(), $secondLocale->getWrappedObject()]));
$this
->getCollection(LocaleInterface::class, 'get', [ContextKeys::CHANNEL => $channel])
->shouldReturn(new ArrayCollection([$firstLocale, $secondLocale]))
->shouldBeLike(new ArrayCollection([$firstLocale->getWrappedObject(), $secondLocale->getWrappedObject()]))
;
}
function it_provides_all_locales_if_user_is_admin(
UserContextInterface $userContext,
UserInterface $user,
AdminUserInterface $user,
ChannelInterface $channel,
LocaleInterface $firstLocale,
LocaleInterface $secondLocale,