Skip to content

Commit

Permalink
refactor #13174 [CatalogPromotion] Refactor scope validators to be mo…
Browse files Browse the repository at this point in the history
…re extendable (GSadee)

This PR was merged into the 1.11-dev branch.

Discussion
----------

| Q               | A
| --------------- | -----
| Branch?         | master
| Bug fix?        | no
| New feature?    | no
| BC breaks?      | no
| Deprecations?   | 
| Related tickets | based on #13173
| License         | MIT

<!--
 - Bug fixes must be submitted against the 1.9 or 1.10 branch (the lowest possible)
 - Features and deprecations must be submitted against the master branch
 - Make sure that the correct base branch is set

 To be sure you are not breaking any Backward Compatibilities, check the documentation:
 https://docs.sylius.com/en/latest/book/organization/backward-compatibility-promise.html
-->


Commits
-------

c797d49 [CatalogPromotion] Refactor scope validators to be more extendable
9efc29a [CatalogPromotion] Refactor main scope validator to dehardcode types
b6efb9a [CatalogPromotion] Refactor scope validators to do an actual validation
  • Loading branch information
Zales0123 committed Oct 6, 2021
2 parents 37b62c2 + b6efb9a commit 61dee95
Show file tree
Hide file tree
Showing 8 changed files with 335 additions and 159 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,22 @@
</service>

<service id="Sylius\Bundle\CoreBundle\Validator\Constraints\CatalogPromotionScopeValidator">
<argument type="service" id="sylius.repository.product_variant" />
<argument type="service" id="sylius.repository.taxon" />
<argument type="collection">
<argument type="constant">Sylius\Component\Core\Model\CatalogPromotionScopeInterface::TYPE_FOR_TAXONS</argument>
<argument type="constant">Sylius\Component\Core\Model\CatalogPromotionScopeInterface::TYPE_FOR_VARIANTS</argument>
</argument>
<argument type="tagged_iterator" tag="sylius.catalog_promotion.scope_validator" index-by="key" />
<tag name="validator.constraint_validator" alias="sylius_catalog_promotion_scope" />
</service>

<service id="Sylius\Bundle\CoreBundle\Validator\CatalogPromotionScope\ForTaxonsScopeValidator">
<argument type="service" id="sylius.repository.taxon" />
<tag name="sylius.catalog_promotion.scope_validator" key="for_taxons"/>
</service>

<service id="Sylius\Bundle\CoreBundle\Validator\CatalogPromotionScope\ForVariantsScopeValidator">
<argument type="service" id="sylius.repository.product_variant" />
<tag name="sylius.catalog_promotion.scope_validator" key="for_variants"/>
</service>
</services>
</container>
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* 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\CoreBundle\Validator\CatalogPromotionScope;

use Sylius\Bundle\CoreBundle\Validator\Constraints\CatalogPromotionScope;
use Sylius\Component\Taxonomy\Repository\TaxonRepositoryInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Webmozart\Assert\Assert;

final class ForTaxonsScopeValidator implements ScopeValidatorInterface
{
private TaxonRepositoryInterface $taxonRepository;

public function __construct(TaxonRepositoryInterface $taxonRepository)
{
$this->taxonRepository = $taxonRepository;
}

public function validate(array $configuration, Constraint $constraint, ExecutionContextInterface $context): void
{
/** @var CatalogPromotionScope $constraint */
Assert::isInstanceOf($constraint, CatalogPromotionScope::class);

if (!isset($configuration['taxons']) || empty($configuration['taxons'])) {
$context->buildViolation($constraint->taxonsNotEmpty)->atPath('configuration.taxons')->addViolation();

return;
}

foreach ($configuration['taxons'] as $taxonCode) {
if (null === $this->taxonRepository->findOneBy(['code' => $taxonCode])) {
$context->buildViolation($constraint->invalidTaxons)->atPath('configuration.taxons')->addViolation();

return;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* 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\CoreBundle\Validator\CatalogPromotionScope;

use Sylius\Bundle\CoreBundle\Validator\Constraints\CatalogPromotionScope;
use Sylius\Component\Core\Repository\ProductVariantRepositoryInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Webmozart\Assert\Assert;

final class ForVariantsScopeValidator implements ScopeValidatorInterface
{
private ProductVariantRepositoryInterface $variantRepository;

public function __construct(ProductVariantRepositoryInterface $variantRepository)
{
$this->variantRepository = $variantRepository;
}

public function validate(array $configuration, Constraint $constraint, ExecutionContextInterface $context): void
{
/** @var CatalogPromotionScope $constraint */
Assert::isInstanceOf($constraint, CatalogPromotionScope::class);

if (!array_key_exists('variants', $configuration) || empty($configuration['variants'])) {
$context->buildViolation($constraint->variantsNotEmpty)->atPath('configuration.variants')->addViolation();

return;
}

foreach ($configuration['variants'] as $variantCode) {
if (null === $this->variantRepository->findOneBy(['code' => $variantCode])) {
$context->buildViolation($constraint->invalidVariants)->atPath('configuration.variants')->addViolation();

return;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* 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\CoreBundle\Validator\CatalogPromotionScope;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Context\ExecutionContextInterface;

interface ScopeValidatorInterface
{
public function validate(array $configuration, Constraint $constraint, ExecutionContextInterface $context): void;
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,22 @@

namespace Sylius\Bundle\CoreBundle\Validator\Constraints;

use Sylius\Bundle\CoreBundle\Validator\CatalogPromotionScope\ScopeValidatorInterface;
use Sylius\Component\Core\Model\CatalogPromotionScopeInterface;
use Sylius\Component\Core\Repository\ProductVariantRepositoryInterface;
use Sylius\Component\Resource\Repository\RepositoryInterface;
use Sylius\Component\Taxonomy\Repository\TaxonRepositoryInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Webmozart\Assert\Assert;

final class CatalogPromotionScopeValidator extends ConstraintValidator
{
private ProductVariantRepositoryInterface $variantRepository;
private array $scopeTypes;

private TaxonRepositoryInterface $taxonRepository;
private array $scopeValidators;

public function __construct(
ProductVariantRepositoryInterface $variantRepository,
TaxonRepositoryInterface $taxonRepository
) {
$this->variantRepository = $variantRepository;
$this->taxonRepository = $taxonRepository;
public function __construct(array $scopeTypes, iterable $scopeValidators)
{
$this->scopeTypes = $scopeTypes;
$this->scopeValidators = $scopeValidators instanceof \Traversable ? iterator_to_array($scopeValidators) : $scopeValidators;
}

public function validate($value, Constraint $constraint): void
Expand All @@ -41,57 +37,21 @@ public function validate($value, Constraint $constraint): void
Assert::isInstanceOf($constraint, CatalogPromotionScope::class);

/** @var CatalogPromotionScopeInterface $value */
if (
$value->getType() !== CatalogPromotionScopeInterface::TYPE_FOR_VARIANTS &&
$value->getType() !== CatalogPromotionScopeInterface::TYPE_FOR_TAXONS
) {
if (!in_array($value->getType(), $this->scopeTypes, true)) {
$this->context->buildViolation($constraint->invalidType)->atPath('type')->addViolation();

return;
}

$configuration = $value->getConfiguration();

if ($value->getType() === CatalogPromotionScopeInterface::TYPE_FOR_VARIANTS) {
$this->validateForVariantsType($configuration, $constraint);

return;
}

$this->validateForTaxonType($configuration, $constraint);
}

private function validateForVariantsType(array $configuration, CatalogPromotionScope $constraint): void
{
if (!array_key_exists('variants', $configuration) || empty($configuration['variants'])) {
$this->context->buildViolation($constraint->variantsNotEmpty)->atPath('configuration.variants')->addViolation();

$type = $value->getType();
if (!key_exists($type, $this->scopeValidators)) {
return;
}

foreach ($configuration['variants'] as $variantCode) {
if (null === $this->variantRepository->findOneBy(['code' => $variantCode])) {
$this->context->buildViolation($constraint->invalidVariants)->atPath('configuration.variants')->addViolation();

break;
}
}
}

private function validateForTaxonType(array $configuration, CatalogPromotionScope $constraint): void
{
if (!isset($configuration['taxons']) || empty($configuration['taxons'])) {
$this->context->buildViolation($constraint->taxonsNotEmpty)->atPath('configuration.taxons')->addViolation();

return;;
}

foreach ($configuration['taxons'] as $taxonCode) {
if (null === $this->taxonRepository->findOneBy(['code' => $taxonCode])) {
$this->context->buildViolation($constraint->invalidTaxons)->atPath('configuration.taxons')->addViolation();
$configuration = $value->getConfiguration();

return;
}
}
/** @var ScopeValidatorInterface $validator */
$validator = $this->scopeValidators[$type];
$validator->validate($configuration, $constraint, $this->context);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace spec\Sylius\Bundle\CoreBundle\Validator\CatalogPromotionScope;

use PhpSpec\ObjectBehavior;
use Sylius\Bundle\CoreBundle\Validator\CatalogPromotionScope\ScopeValidatorInterface;
use Sylius\Bundle\CoreBundle\Validator\Constraints\CatalogPromotionScope;
use Sylius\Component\Core\Model\TaxonInterface;
use Sylius\Component\Taxonomy\Repository\TaxonRepositoryInterface;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Component\Validator\Violation\ConstraintViolationBuilderInterface;

final class ForTaxonsScopeValidatorSpec extends ObjectBehavior
{
function let(TaxonRepositoryInterface $taxonRepository): void
{
$this->beConstructedWith($taxonRepository);
}

function it_is_a_scope_validator(): void
{
$this->shouldHaveType(ScopeValidatorInterface::class);
}

function it_adds_violation_if_catalog_promotion_scope_does_not_have_taxons_key_configured(
ExecutionContextInterface $executionContext,
ConstraintViolationBuilderInterface $constraintViolationBuilder
): void {
$executionContext->buildViolation('sylius.catalog_promotion_scope.for_taxons.not_empty')->willReturn($constraintViolationBuilder);
$constraintViolationBuilder->atPath('configuration.taxons')->willReturn($constraintViolationBuilder);
$constraintViolationBuilder->addViolation()->shouldBeCalled();

$this->validate([], new CatalogPromotionScope(), $executionContext);
}

function it_adds_violation_if_catalog_promotion_scope_has_not_existing_taxons_configured(
TaxonRepositoryInterface $taxonRepository,
ExecutionContextInterface $executionContext,
ConstraintViolationBuilderInterface $constraintViolationBuilder
): void {
$taxonRepository->findOneBy(['code' => 'not_existing_taxon'])->willReturn(null);

$executionContext->buildViolation('sylius.catalog_promotion_scope.for_taxons.invalid_taxons')->willReturn($constraintViolationBuilder);
$constraintViolationBuilder->atPath('configuration.taxons')->willReturn($constraintViolationBuilder);
$constraintViolationBuilder->addViolation()->shouldBeCalled();

$this->validate(['taxons' => ['not_existing_taxon']], new CatalogPromotionScope(), $executionContext);
}

function it_does_nothing_if_catalog_promotion_scope_is_valid(
TaxonRepositoryInterface $taxonRepository,
ExecutionContextInterface $executionContext,
TaxonInterface $taxon
): void {
$taxonRepository->findOneBy(['code' => 'taxon'])->willReturn($taxon);

$executionContext->buildViolation('sylius.catalog_promotion_scope.for_taxons.not_empty')->shouldNotBeCalled();
$executionContext->buildViolation('sylius.catalog_promotion_scope.for_taxons.invalid_taxons')->shouldNotBeCalled();

$this->validate(['taxons' => ['taxon']], new CatalogPromotionScope(), $executionContext);
}
}
Loading

0 comments on commit 61dee95

Please sign in to comment.