mirror of
https://github.com/Sylius/Sylius.git
synced 2026-07-14 09:02:12 +00:00
feature #11055 Define countries for a channel (pamil)
This PR was merged into the 1.7-dev branch.
Discussion
----------
| Q | A
| --------------- | -----
| Branch? | master
| Bug fix? | no
| New feature? | yes
| BC breaks? | no
| Deprecations? | no
| Related tickets | fixes #9122
| License | MIT
Currently used only in checkout addressing to limit the list of countries. If not defined, fallbacks to the previous behaviour - all enabled countries.
<img width="672" alt="Screenshot 2020-01-22 at 20 10 51" src="https://user-images.githubusercontent.com/1897953/72925676-65ef8f80-3d53-11ea-831c-25fad0973a83.png">
Commits
-------
2e68737703 Define countries for a channel
This commit is contained in:
commit
e8145f02b9
23 changed files with 326 additions and 16 deletions
37
app/migrations/Version20200122082429.php
Normal file
37
app/migrations/Version20200122082429.php
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sylius\Migrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20200122082429 extends AbstractMigration
|
||||
{
|
||||
public function getDescription() : string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema) : void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.');
|
||||
|
||||
$this->addSql('CREATE TABLE sylius_channel_countries (channel_id INT NOT NULL, country_id INT NOT NULL, INDEX IDX_D96E51AE72F5A1AA (channel_id), INDEX IDX_D96E51AEF92F3E70 (country_id), PRIMARY KEY(channel_id, country_id)) DEFAULT CHARACTER SET UTF8 COLLATE `UTF8_unicode_ci` ENGINE = InnoDB');
|
||||
$this->addSql('ALTER TABLE sylius_channel_countries ADD CONSTRAINT FK_D96E51AE72F5A1AA FOREIGN KEY (channel_id) REFERENCES sylius_channel (id) ON DELETE CASCADE');
|
||||
$this->addSql('ALTER TABLE sylius_channel_countries ADD CONSTRAINT FK_D96E51AEF92F3E70 FOREIGN KEY (country_id) REFERENCES sylius_country (id) ON DELETE CASCADE');
|
||||
}
|
||||
|
||||
public function down(Schema $schema) : void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.');
|
||||
|
||||
$this->addSql('DROP TABLE sylius_channel_countries');
|
||||
}
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@ Or pretty much any other channel type you can imagine.
|
|||
* products,
|
||||
* currencies,
|
||||
* locales (language),
|
||||
* countries,
|
||||
* themes,
|
||||
* hostnames,
|
||||
* taxes,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ Feature: Adding a new channel
|
|||
Background:
|
||||
Given the store has currency "Euro"
|
||||
And the store has locale "English (United States)"
|
||||
And the store operates in "United States" and "Poland"
|
||||
And I am logged in as an administrator
|
||||
|
||||
@ui
|
||||
|
|
@ -31,6 +32,7 @@ Feature: Adding a new channel
|
|||
And I define its color as "blue"
|
||||
And I choose "Euro" as the base currency
|
||||
And I choose "English (United States)" as a default locale
|
||||
And I choose "United States" and "Poland" as operating countries
|
||||
And I allow to skip shipping step if only one shipping method is available
|
||||
And I allow to skip payment step if only one payment method is available
|
||||
And I add it
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
@checkout
|
||||
Feature: Restricting list of countries available for addressing
|
||||
In order to make choosing countries easier
|
||||
As a Customer
|
||||
I want to have only available countries listed
|
||||
|
||||
Background:
|
||||
Given the store operates on a single channel in "United States"
|
||||
And the store operates in "Poland"
|
||||
And the store has a product "PHP T-Shirt" priced at "$19.99"
|
||||
And the store ships everywhere for free
|
||||
And I am a logged in customer
|
||||
|
||||
@ui
|
||||
Scenario: Having only countries available for current channel listed
|
||||
Given this channel operates in the "United States" country
|
||||
When I add product "PHP T-Shirt" to the cart
|
||||
And I go to the checkout addressing step
|
||||
Then I should have only "United States" country available to choose from
|
||||
|
||||
@ui
|
||||
Scenario: Having all the countries listed if channel does not define available ones
|
||||
Given this channel does not define operating countries
|
||||
When I add product "PHP T-Shirt" to the cart
|
||||
And I go to the checkout addressing step
|
||||
Then I should have both "United States" and "Poland" countries available to choose from
|
||||
|
|
@ -229,6 +229,28 @@ final class ChannelContext implements Context
|
|||
$this->channelManager->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given /^(this channel) operates in the ("[^"]+" country)$/
|
||||
*/
|
||||
public function channelOperatesInCountry(ChannelInterface $channel, CountryInterface $country): void
|
||||
{
|
||||
$channel->addCountry($country);
|
||||
|
||||
$this->channelManager->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given /^(this channel) does not define operating countries$/
|
||||
*/
|
||||
public function channelDoesNotDefineOperatingCountries(ChannelInterface $channel): void
|
||||
{
|
||||
foreach ($channel->getCountries() as $country) {
|
||||
$channel->removeCountry($country);
|
||||
}
|
||||
|
||||
$this->channelManager->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $state
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -102,6 +102,14 @@ final class ManagingChannelsContext implements Context
|
|||
$this->createPage->chooseDefaultLocale($locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I choose :firstCountry and :secondCountry as operating countries
|
||||
*/
|
||||
public function iChooseOperatingCountries(string ...$countries): void
|
||||
{
|
||||
$this->createPage->chooseOperatingCountries($countries);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I specify menu taxon as :menuTaxon
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -56,9 +56,10 @@ final class CheckoutAddressingContext implements Context
|
|||
|
||||
/**
|
||||
* @Given I am at the checkout addressing step
|
||||
* @When I go to the checkout addressing step
|
||||
* @When I go back to addressing step of the checkout
|
||||
*/
|
||||
public function iAmAtTheCheckoutAddressingStep()
|
||||
public function iAmAtTheCheckoutAddressingStep(): void
|
||||
{
|
||||
$this->addressPage->open();
|
||||
}
|
||||
|
|
@ -385,6 +386,23 @@ final class CheckoutAddressingContext implements Context
|
|||
$this->assertElementValidationMessage($type, $secondElement, sprintf('Please enter %s.', $secondElement));
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should have only :firstCountry country available to choose from
|
||||
* @Then I should have both :firstCountry and :secondCountry countries available to choose from
|
||||
*/
|
||||
public function shouldHaveCountriesToChooseFrom(string ...$countries): void
|
||||
{
|
||||
$availableShippingCountries = $this->addressPage->getAvailableShippingCountries();
|
||||
$availableBillingCountries = $this->addressPage->getAvailableBillingCountries();
|
||||
|
||||
sort($countries);
|
||||
sort($availableShippingCountries);
|
||||
sort($availableBillingCountries);
|
||||
|
||||
Assert::same($availableShippingCountries, $countries);
|
||||
Assert::same($availableBillingCountries, $countries);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AddressInterface
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -65,6 +65,13 @@ class CreatePage extends BaseCreatePage implements CreatePageInterface
|
|||
}
|
||||
}
|
||||
|
||||
public function chooseOperatingCountries(array $countries): void
|
||||
{
|
||||
foreach ($countries as $country) {
|
||||
$this->getElement('countries')->selectOption($country, true);
|
||||
}
|
||||
}
|
||||
|
||||
public function chooseBaseCurrency(?string $currency): void
|
||||
{
|
||||
if (null !== $currency) {
|
||||
|
|
@ -104,6 +111,7 @@ class CreatePage extends BaseCreatePage implements CreatePageInterface
|
|||
{
|
||||
return array_merge(parent::getDefinedElements(), [
|
||||
'code' => '#sylius_channel_code',
|
||||
'countries' => '#sylius_channel_countries',
|
||||
'currencies' => '#sylius_channel_currencies',
|
||||
'base_currency' => '#sylius_channel_baseCurrency',
|
||||
'default_locale' => '#sylius_channel_defaultLocale',
|
||||
|
|
|
|||
|
|
@ -41,6 +41,9 @@ interface CreatePageInterface extends BaseCreatePageInterface
|
|||
|
||||
public function chooseDefaultLocale(?string $locale): void;
|
||||
|
||||
/** @param string[] $countries */
|
||||
public function chooseOperatingCountries(array $countries): void;
|
||||
|
||||
public function chooseBaseCurrency(?string $currency): void;
|
||||
|
||||
public function chooseTaxCalculationStrategy(string $taxCalculationStrategy): void;
|
||||
|
|
|
|||
|
|
@ -250,6 +250,16 @@ class AddressPage extends SymfonyPage implements AddressPageInterface
|
|||
return $this->getPreFilledAddress(self::TYPE_BILLING);
|
||||
}
|
||||
|
||||
public function getAvailableShippingCountries(): array
|
||||
{
|
||||
return $this->getOptionsFromSelect($this->getElement('shipping_country'));
|
||||
}
|
||||
|
||||
public function getAvailableBillingCountries(): array
|
||||
{
|
||||
return $this->getOptionsFromSelect($this->getElement('billing_country'));
|
||||
}
|
||||
|
||||
protected function getDefinedElements(): array
|
||||
{
|
||||
return array_merge(parent::getDefinedElements(), [
|
||||
|
|
@ -283,6 +293,18 @@ class AddressPage extends SymfonyPage implements AddressPageInterface
|
|||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function getOptionsFromSelect(NodeElement $element): array
|
||||
{
|
||||
return array_map(
|
||||
/** @return string[] */
|
||||
static function (NodeElement $element): string { return $element->getText(); },
|
||||
$element->findAll('css', 'option[value!=""]')
|
||||
);
|
||||
}
|
||||
|
||||
private function getPreFilledAddress(string $type): AddressInterface
|
||||
{
|
||||
$this->assertAddressType($type);
|
||||
|
|
|
|||
|
|
@ -65,4 +65,10 @@ interface AddressPageInterface extends SymfonyPageInterface
|
|||
public function getPreFilledShippingAddress(): AddressInterface;
|
||||
|
||||
public function getPreFilledBillingAddress(): AddressInterface;
|
||||
|
||||
/** @return string[] */
|
||||
public function getAvailableShippingCountries(): array;
|
||||
|
||||
/** @return string[] */
|
||||
public function getAvailableBillingCountries(): array;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,10 @@ namespace Sylius\Bundle\AddressingBundle\Form\Type;
|
|||
|
||||
use Sylius\Component\Addressing\Model\CountryInterface;
|
||||
use Sylius\Component\Resource\Repository\RepositoryInterface;
|
||||
use Symfony\Bridge\Doctrine\Form\DataTransformer\CollectionToArrayTransformer;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
|
|
@ -30,6 +32,13 @@ final class CountryChoiceType extends AbstractType
|
|||
$this->countryRepository = $countryRepository;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
if ($options['multiple']) {
|
||||
$builder->addModelTransformer(new CollectionToArrayTransformer());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
@ -45,14 +54,6 @@ final class CountryChoiceType extends AbstractType
|
|||
$countries = $this->countryRepository->findBy(['enabled' => $options['enabled']]);
|
||||
}
|
||||
|
||||
if ($options['choice_filter']) {
|
||||
$countries = array_filter($countries, $options['choice_filter']);
|
||||
}
|
||||
|
||||
usort($countries, function (CountryInterface $a, CountryInterface $b): int {
|
||||
return $a->getName() <=> $b->getName();
|
||||
});
|
||||
|
||||
return $countries;
|
||||
},
|
||||
'choice_value' => 'code',
|
||||
|
|
@ -63,6 +64,17 @@ final class CountryChoiceType extends AbstractType
|
|||
'placeholder' => 'sylius.form.country.select',
|
||||
])
|
||||
->setAllowedTypes('choice_filter', ['null', 'callable'])
|
||||
->setNormalizer('choices', static function (Options $options, array $countries): array {
|
||||
if ($options['choice_filter']) {
|
||||
$countries = array_filter($countries, $options['choice_filter']);
|
||||
}
|
||||
|
||||
usort($countries, static function (CountryInterface $firstCountry, CountryInterface $secondCountry): int {
|
||||
return $firstCountry->getName() <=> $secondCountry->getName();
|
||||
});
|
||||
|
||||
return $countries;
|
||||
})
|
||||
;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@
|
|||
{{ form_row(form.contactEmail) }}
|
||||
{{ form_row(form.description, {'attr': {'rows' : '3'}}) }}
|
||||
</div>
|
||||
<div class="ui attached segment">
|
||||
{{ form_row(form.countries) }}
|
||||
</div>
|
||||
<div class="ui hidden divider"></div>
|
||||
<h4 class="ui top attached large header">{{ 'sylius.ui.money'|trans }}</h4>
|
||||
<div class="ui attached segment">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
<?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\Form\Extension;
|
||||
|
||||
use Sylius\Bundle\AddressingBundle\Form\Type\AddressType;
|
||||
use Sylius\Component\Core\Model\ChannelInterface;
|
||||
use Symfony\Component\Form\AbstractTypeExtension;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
final class AddressTypeExtension extends AbstractTypeExtension
|
||||
{
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
$resolver
|
||||
->setDefault('channel', null)
|
||||
->setAllowedTypes('channel', ['null', ChannelInterface::class])
|
||||
;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
/** @var ChannelInterface|null $channel */
|
||||
$channel = $options['channel'];
|
||||
|
||||
if ($channel === null || $channel->getCountries()->count() === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$oldCountryCodeField = $builder->get('countryCode');
|
||||
|
||||
$countryCodeField = $builder->create(
|
||||
$oldCountryCodeField->getName(),
|
||||
get_class($oldCountryCodeField->getType()->getInnerType()),
|
||||
array_replace($oldCountryCodeField->getOptions(), ['choices' => $channel->getCountries()->toArray()])
|
||||
);
|
||||
|
||||
$builder->add($countryCodeField);
|
||||
}
|
||||
|
||||
public static function getExtendedTypes(): array
|
||||
{
|
||||
return [AddressType::class];
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace Sylius\Bundle\CoreBundle\Form\Extension;
|
||||
|
||||
use Sylius\Bundle\AddressingBundle\Form\Type\CountryChoiceType;
|
||||
use Sylius\Bundle\AddressingBundle\Form\Type\ZoneChoiceType;
|
||||
use Sylius\Bundle\ChannelBundle\Form\Type\ChannelType;
|
||||
use Sylius\Bundle\CoreBundle\Form\EventSubscriber\AddBaseCurrencySubscriber;
|
||||
|
|
@ -54,6 +55,11 @@ final class ChannelTypeExtension extends AbstractTypeExtension
|
|||
'required' => false,
|
||||
'multiple' => true,
|
||||
])
|
||||
->add('countries', CountryChoiceType::class, [
|
||||
'label' => 'sylius.form.channel.countries',
|
||||
'required' => false,
|
||||
'multiple' => true,
|
||||
])
|
||||
->add('defaultTaxZone', ZoneChoiceType::class, [
|
||||
'required' => false,
|
||||
'label' => 'sylius.form.channel.tax_zone_default',
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ use Sylius\Bundle\AddressingBundle\Form\Type\AddressType as SyliusAddressType;
|
|||
use Sylius\Bundle\CoreBundle\Form\Type\Customer\CustomerGuestType;
|
||||
use Sylius\Bundle\ResourceBundle\Form\Type\AbstractResourceType;
|
||||
use Sylius\Component\Core\Model\CustomerInterface;
|
||||
use Sylius\Component\Core\Model\OrderInterface;
|
||||
use Sylius\Component\Customer\Model\CustomerAwareInterface;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
|
@ -34,13 +35,6 @@ final class AddressType extends AbstractResourceType
|
|||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
$builder
|
||||
->add('shippingAddress', SyliusAddressType::class, [
|
||||
'shippable' => true,
|
||||
'constraints' => [new Valid()],
|
||||
])
|
||||
->add('billingAddress', SyliusAddressType::class, [
|
||||
'constraints' => [new Valid()],
|
||||
])
|
||||
->add('differentBillingAddress', CheckboxType::class, [
|
||||
'mapped' => false,
|
||||
'required' => false,
|
||||
|
|
@ -51,6 +45,27 @@ final class AddressType extends AbstractResourceType
|
|||
'required' => false,
|
||||
'label' => 'sylius.form.checkout.addressing.different_shipping_address',
|
||||
])
|
||||
->addEventListener(FormEvents::PRE_SET_DATA, static function (FormEvent $event): void {
|
||||
$form = $event->getForm();
|
||||
$order = $event->getData();
|
||||
|
||||
/** @var OrderInterface $order */
|
||||
Assert::isInstanceOf($order, OrderInterface::class);
|
||||
|
||||
$channel = $order->getChannel();
|
||||
|
||||
$form
|
||||
->add('shippingAddress', SyliusAddressType::class, [
|
||||
'shippable' => true,
|
||||
'constraints' => [new Valid()],
|
||||
'channel' => $channel,
|
||||
])
|
||||
->add('billingAddress', SyliusAddressType::class, [
|
||||
'constraints' => [new Valid()],
|
||||
'channel' => $channel,
|
||||
])
|
||||
;
|
||||
})
|
||||
->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($options): void {
|
||||
$form = $event->getForm();
|
||||
$resource = $event->getData();
|
||||
|
|
|
|||
|
|
@ -56,6 +56,16 @@
|
|||
</inverse-join-columns>
|
||||
</join-table>
|
||||
</many-to-many>
|
||||
<many-to-many field="countries" target-entity="Sylius\Component\Addressing\Model\CountryInterface" fetch="EAGER">
|
||||
<join-table name="sylius_channel_countries">
|
||||
<join-columns>
|
||||
<join-column name="channel_id" nullable="false" on-delete="CASCADE" />
|
||||
</join-columns>
|
||||
<inverse-join-columns>
|
||||
<join-column name="country_id" nullable="false" on-delete="CASCADE" />
|
||||
</inverse-join-columns>
|
||||
</join-table>
|
||||
</many-to-many>
|
||||
|
||||
<one-to-one field="shopBillingData" target-entity="Sylius\Component\Core\Model\ShopBillingData">
|
||||
<join-column name="shop_billing_data_id" on-delete="CASCADE"/>
|
||||
|
|
|
|||
|
|
@ -54,6 +54,9 @@
|
|||
<services>
|
||||
<defaults public="true" />
|
||||
|
||||
<service id="sylius.form.extension.type.address" class="Sylius\Bundle\CoreBundle\Form\Extension\AddressTypeExtension">
|
||||
<tag name="form.type_extension" extended-type="Sylius\Bundle\AddressingBundle\Form\Type\AddressType" />
|
||||
</service>
|
||||
<service id="sylius.form.extension.type.country" class="Sylius\Bundle\CoreBundle\Form\Extension\CountryTypeExtension">
|
||||
<argument type="service" id="sylius.repository.country" />
|
||||
<tag name="form.type_extension" extended-type="Sylius\Bundle\AddressingBundle\Form\Type\CountryType" />
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ sylius:
|
|||
street: Street
|
||||
tax_id: Tax ID
|
||||
contact_email: Contact email
|
||||
countries: Countries
|
||||
currencies: Currencies
|
||||
currency_base: Base currency
|
||||
account_verification_required: Is account verification required?
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ namespace Sylius\Component\Core\Model;
|
|||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Sylius\Component\Addressing\Model\CountryInterface;
|
||||
use Sylius\Component\Addressing\Model\ZoneInterface;
|
||||
use Sylius\Component\Channel\Model\Channel as BaseChannel;
|
||||
use Sylius\Component\Currency\Model\CurrencyInterface;
|
||||
|
|
@ -48,6 +49,13 @@ class Channel extends BaseChannel implements ChannelInterface
|
|||
*/
|
||||
protected $locales;
|
||||
|
||||
/**
|
||||
* @var Collection|CountryInterface[]
|
||||
*
|
||||
* @psalm-var Collection<array-key, CountryInterface>
|
||||
*/
|
||||
protected $countries;
|
||||
|
||||
/** @var string */
|
||||
protected $themeName;
|
||||
|
||||
|
|
@ -77,6 +85,8 @@ class Channel extends BaseChannel implements ChannelInterface
|
|||
$this->currencies = new ArrayCollection();
|
||||
/** @var ArrayCollection<array-key, LocaleInterface> $this->locales */
|
||||
$this->locales = new ArrayCollection();
|
||||
/** @var ArrayCollection<array-key, CountryInterface> $this->countries */
|
||||
$this->countries = new ArrayCollection();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -215,6 +225,30 @@ class Channel extends BaseChannel implements ChannelInterface
|
|||
return $this->locales->contains($locale);
|
||||
}
|
||||
|
||||
public function getCountries(): Collection
|
||||
{
|
||||
return $this->countries;
|
||||
}
|
||||
|
||||
public function addCountry(CountryInterface $country): void
|
||||
{
|
||||
if (!$this->hasCountry($country)) {
|
||||
$this->countries->add($country);
|
||||
}
|
||||
}
|
||||
|
||||
public function removeCountry(CountryInterface $country): void
|
||||
{
|
||||
if ($this->hasCountry($country)) {
|
||||
$this->countries->removeElement($country);
|
||||
}
|
||||
}
|
||||
|
||||
public function hasCountry(CountryInterface $country): bool
|
||||
{
|
||||
return $this->countries->contains($country);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ declare(strict_types=1);
|
|||
|
||||
namespace Sylius\Component\Core\Model;
|
||||
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Sylius\Component\Addressing\Model\CountryInterface;
|
||||
use Sylius\Component\Addressing\Model\ZoneInterface;
|
||||
use Sylius\Component\Channel\Model\ChannelInterface as BaseChannelInterface;
|
||||
use Sylius\Component\Currency\Model\CurrenciesAwareInterface;
|
||||
|
|
@ -68,4 +70,17 @@ interface ChannelInterface extends
|
|||
public function getMenuTaxon(): ?TaxonInterface;
|
||||
|
||||
public function setMenuTaxon(?TaxonInterface $menuTaxon): void;
|
||||
|
||||
/**
|
||||
* @return Collection|CountryInterface[]
|
||||
*
|
||||
* @psalm-return Collection<array-key, CountryInterface>
|
||||
*/
|
||||
public function getCountries(): Collection;
|
||||
|
||||
public function addCountry(CountryInterface $country): void;
|
||||
|
||||
public function removeCountry(CountryInterface $country): void;
|
||||
|
||||
public function hasCountry(CountryInterface $country): bool;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
]
|
||||
},
|
||||
"currencies": {},
|
||||
"countries": {},
|
||||
"defaultTaxZone": {},
|
||||
"taxCalculationStrategy": {
|
||||
"errors": [
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
"locales": {},
|
||||
"defaultLocale": {},
|
||||
"currencies": {},
|
||||
"countries": {},
|
||||
"defaultTaxZone": {},
|
||||
"taxCalculationStrategy": {
|
||||
"errors": [
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue