├── tests ├── Unit │ └── .gitkeep └── bootstrap.php ├── .php-version.dist ├── php.ini.dist ├── dist ├── .env.local ├── templates │ └── bundles │ │ └── SyliusAdminBundle │ │ └── Channel │ │ └── _form.html.twig └── src │ ├── Kernel.php │ ├── Entity │ └── Channel │ │ └── Channel.php │ └── Migrations │ ├── Version20211103111331.php │ └── Version20231214131617.php ├── docs └── images │ └── banner.jpg ├── src ├── Resources │ ├── config │ │ ├── config.yaml │ │ ├── sylius │ │ │ └── grid.yaml │ │ ├── monsieurbiz │ │ │ └── settings.yaml │ │ ├── validation │ │ │ └── Channel.yaml │ │ └── services.yaml │ ├── templates │ │ └── bundles │ │ │ └── SyliusAdminBundle │ │ │ └── Channel │ │ │ └── _form.html.twig │ ├── translations │ │ ├── messages.en.yaml │ │ └── messages.fr.yaml │ └── views │ │ └── Admin │ │ └── Channel │ │ ├── _standardForm.html.twig │ │ └── _noCommerceForm.html.twig ├── Provider │ ├── FeaturesProviderInterface.php │ └── FeaturesProvider.php ├── Firewall │ ├── RegistryInterface.php │ └── Registry.php ├── Form │ ├── EventSubscriber │ │ └── RemoveBaseCurrencySubscriber.php │ ├── Type │ │ └── Settings │ │ │ └── NoCommerceType.php │ └── Extension │ │ └── ChannelTypeExtension.php ├── Model │ ├── Config.php │ └── ConfigInterface.php ├── Menu │ ├── AdminCustomerShowMenuListener.php │ ├── ShopAccountMenuListener.php │ └── AdminMenuListener.php ├── Twig │ └── Extension │ │ └── NoCommerceExtension.php ├── DependencyInjection │ ├── RemoveSyliusDataCollectorsPass.php │ ├── Configuration.php │ ├── MonsieurBizSyliusNoCommerceExtension.php │ └── FirewallRegistryPass.php ├── Context │ └── NoCurrencyContext.php ├── Routing │ └── NoCommerceRequestContext.php ├── MonsieurBizSyliusNoCommercePlugin.php ├── EventListener │ └── DisableFirewallListener.php ├── Kernel │ └── SyliusNoCommerceKernelTrait.php ├── Registry │ └── TemplateBlockRegistryDecorator.php └── Collector │ └── NoCommerceSyliusCollector.php ├── phpspec.yml.dist ├── .gitignore ├── DEVELOPMENT.md ├── phpstan.neon ├── docker-compose.yaml.dist ├── LICENSE.txt ├── TESTING.md ├── .github └── workflows │ ├── security.yaml │ ├── tests.yaml │ └── recipe.yaml ├── .editorconfig ├── composer.json ├── phpmd.xml ├── phpunit.xml.dist ├── README.md ├── Makefile ├── .php-cs-fixer.dist.php └── symfony.lock /tests/Unit/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.php-version.dist: -------------------------------------------------------------------------------- 1 | 8.3 2 | -------------------------------------------------------------------------------- /php.ini.dist: -------------------------------------------------------------------------------- 1 | memory_limit=-1 2 | -------------------------------------------------------------------------------- /dist/.env.local: -------------------------------------------------------------------------------- 1 | SYLIUS_FIXTURES_HOSTNAME=${SYMFONY_DEFAULT_ROUTE_HOST:-localhost} 2 | -------------------------------------------------------------------------------- /docs/images/banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monsieurbiz/SyliusNoCommercePlugin/HEAD/docs/images/banner.jpg -------------------------------------------------------------------------------- /src/Resources/config/config.yaml: -------------------------------------------------------------------------------- 1 | imports: 2 | - { resource: "sylius/grid.yaml" } 3 | - { resource: "monsieurbiz/settings.yaml" } 4 | -------------------------------------------------------------------------------- /phpspec.yml.dist: -------------------------------------------------------------------------------- 1 | suites: 2 | main: 3 | namespace: MonsieurBiz\SyliusNoCommercePlugin 4 | psr4_prefix: MonsieurBiz\SyliusNoCommercePlugin 5 | src_path: src 6 | spec_path: tests 7 | -------------------------------------------------------------------------------- /src/Resources/config/sylius/grid.yaml: -------------------------------------------------------------------------------- 1 | sylius_grid: 2 | grids: 3 | sylius_admin_customer: 4 | actions: 5 | item: 6 | show_orders: 7 | enabled: false 8 | -------------------------------------------------------------------------------- /dist/templates/bundles/SyliusAdminBundle/Channel/_form.html.twig: -------------------------------------------------------------------------------- 1 | {% if form.vars.noCommerceEnabled %} 2 | {% include '@MonsieurBizSyliusNoCommercePlugin/Admin/Channel/_noCommerceForm.html.twig' %} 3 | {% else %} 4 | {% include '@MonsieurBizSyliusNoCommercePlugin/Admin/Channel/_standardForm.html.twig' %} 5 | {% endif %} 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | /composer.lock 3 | 4 | /etc/build/* 5 | !/etc/build/.gitignore 6 | 7 | /tests/Application 8 | 9 | /behat.yml 10 | /phpspec.yml 11 | 12 | /package-lock.json 13 | 14 | /.php-version 15 | /php.ini 16 | /.phpunit.result.cache 17 | /node_modules 18 | /yarn.lock 19 | 20 | /.php-cs-fixer.cache 21 | 22 | -------------------------------------------------------------------------------- /src/Resources/templates/bundles/SyliusAdminBundle/Channel/_form.html.twig: -------------------------------------------------------------------------------- 1 | {% if form.vars.noCommerceEnabled %} 2 | {% include '@MonsieurBizSyliusNoCommercePlugin/Admin/Channel/_noCommerceForm.html.twig' %} 3 | {% else %} 4 | {% include '@MonsieurBizSyliusNoCommercePlugin/Admin/Channel/_standardForm.html.twig' %} 5 | {% endif %} 6 | -------------------------------------------------------------------------------- /DEVELOPMENT.md: -------------------------------------------------------------------------------- 1 | ## Node 2 | 3 | Be sure you have node 14 on your machine. You can use NVM to easily switch versions. 4 | 5 | # Docker 6 | 7 | Be sure you have docker on your machine. 8 | 9 | # Symfony 10 | 11 | Be sure you have the Symfony binary on your machine. 12 | 13 | ``` 14 | curl -sS https://get.symfony.com/cli/installer | bash 15 | ``` 16 | -------------------------------------------------------------------------------- /phpstan.neon: -------------------------------------------------------------------------------- 1 | parameters: 2 | level: 8 3 | paths: 4 | - %rootDir%/src/ 5 | 6 | excludePaths: 7 | # Makes PHPStan crash 8 | - 'src/DependencyInjection/Configuration.php' 9 | - 'src/DependencyInjection/MonsieurBizSyliusNoCommerceExtension.php' 10 | 11 | # Test dependencies 12 | - 'tests/Application/**/*' 13 | 14 | ignoreErrors: 15 | - identifier: missingType.iterableValue 16 | -------------------------------------------------------------------------------- /src/Resources/translations/messages.en.yaml: -------------------------------------------------------------------------------- 1 | monsieurbiz: 2 | nocommerce: 3 | ui: 4 | form: 5 | field: 6 | disabled_firewall_contexts: 7 | label: Firewalls to be disabled 8 | enabled: 9 | label: Enabled, clear cache after modification 10 | allow_admin: 11 | label: Allow all routes in admin, clear cache after modification 12 | -------------------------------------------------------------------------------- /src/Resources/translations/messages.fr.yaml: -------------------------------------------------------------------------------- 1 | monsieurbiz: 2 | nocommerce: 3 | ui: 4 | form: 5 | field: 6 | disabled_firewall_contexts: 7 | label: Firewalls à désactiver 8 | enabled: 9 | label: Activer, vider le cache après modification 10 | allow_admin: 11 | label: Autoriser toutes les routes dans l'admin, vider le cache après modification 12 | -------------------------------------------------------------------------------- /docker-compose.yaml.dist: -------------------------------------------------------------------------------- 1 | services: 2 | database: 3 | image: mysql:8.0 4 | command: --default-authentication-plugin=mysql_native_password 5 | ports: 6 | - 3306 7 | environment: 8 | MYSQL_ALLOW_EMPTY_PASSWORD: 1 9 | MYSQL_DATABASE: sylius 10 | volumes: 11 | - database:/var/lib/mysql 12 | 13 | mailer: 14 | image: monsieurbiz/mailcatcher 15 | ports: 16 | - 1025 17 | - 1080 18 | 19 | volumes: 20 | database: {} 21 | -------------------------------------------------------------------------------- /src/Resources/config/monsieurbiz/settings.yaml: -------------------------------------------------------------------------------- 1 | monsieurbiz_sylius_settings: 2 | plugins: 3 | monsieurbiz.nocommerce: 4 | vendor_name: Monsieur Biz 5 | vendor_url: 6 | plugin_name: No Commerce 7 | description: No Commerce configuration 8 | icon: shopping bag 9 | use_locales: false 10 | classes: 11 | form: MonsieurBiz\SyliusNoCommercePlugin\Form\Type\Settings\NoCommerceType 12 | default_values: 13 | enabled: true 14 | -------------------------------------------------------------------------------- /src/Provider/FeaturesProviderInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace MonsieurBiz\SyliusNoCommercePlugin\Provider; 15 | 16 | use Sylius\Component\Core\Model\ChannelInterface; 17 | 18 | interface FeaturesProviderInterface 19 | { 20 | public function isNoCommerceEnabledForChannel(?ChannelInterface $channel = null): bool; 21 | 22 | public function allowAdmin(): bool; 23 | } 24 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | use Symfony\Component\Dotenv\Dotenv; 15 | 16 | require dirname(__DIR__) . '/vendor/autoload.php'; 17 | 18 | if (file_exists(dirname(__DIR__) . '/config/bootstrap.php')) { 19 | require dirname(__DIR__) . '/config/bootstrap.php'; 20 | } elseif (method_exists(Dotenv::class, 'bootEnv')) { 21 | (new Dotenv())->bootEnv(dirname(__DIR__) . '/.env'); 22 | } 23 | -------------------------------------------------------------------------------- /src/Firewall/RegistryInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace MonsieurBiz\SyliusNoCommercePlugin\Firewall; 15 | 16 | use IteratorAggregate; 17 | use Symfony\Bundle\SecurityBundle\Security\FirewallContext; 18 | 19 | /** 20 | * @extends IteratorAggregate 21 | */ 22 | interface RegistryInterface extends IteratorAggregate 23 | { 24 | public function addFirewall(FirewallContext $firewall): void; 25 | } 26 | -------------------------------------------------------------------------------- /src/Firewall/Registry.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace MonsieurBiz\SyliusNoCommercePlugin\Firewall; 15 | 16 | use ArrayIterator; 17 | use Symfony\Bundle\SecurityBundle\Security\FirewallContext; 18 | use Traversable; 19 | 20 | class Registry implements RegistryInterface 21 | { 22 | /** 23 | * @var FirewallContext[] 24 | */ 25 | private array $firewalls = []; 26 | 27 | public function addFirewall(FirewallContext $firewall): void 28 | { 29 | $this->firewalls[] = $firewall; 30 | } 31 | 32 | public function getIterator(): Traversable 33 | { 34 | return new ArrayIterator($this->firewalls); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2021 Monsieur Biz 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /src/Form/EventSubscriber/RemoveBaseCurrencySubscriber.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace MonsieurBiz\SyliusNoCommercePlugin\Form\EventSubscriber; 15 | 16 | use Symfony\Component\EventDispatcher\EventSubscriberInterface; 17 | use Symfony\Component\Form\FormEvent; 18 | use Symfony\Component\Form\FormEvents; 19 | 20 | final class RemoveBaseCurrencySubscriber implements EventSubscriberInterface 21 | { 22 | public static function getSubscribedEvents(): array 23 | { 24 | return [ 25 | FormEvents::PRE_SET_DATA => 'preSetData', 26 | ]; 27 | } 28 | 29 | public function preSetData(FormEvent $event): void 30 | { 31 | $form = $event->getForm(); 32 | $form->remove('baseCurrency'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Model/Config.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace MonsieurBiz\SyliusNoCommercePlugin\Model; 15 | 16 | final class Config implements ConfigInterface 17 | { 18 | private array $config = []; 19 | 20 | public function __construct(array $config) 21 | { 22 | $this->config = $config; 23 | } 24 | 25 | public function areCountriesAllowed(): bool 26 | { 27 | return (bool) $this->config['allow_countries'] ?: false; 28 | } 29 | 30 | public function areCustomersAllowed(): bool 31 | { 32 | return (bool) $this->config['allow_customers'] ?: false; 33 | } 34 | 35 | public function areZonesAllowed(): bool 36 | { 37 | return (bool) $this->config['allow_zones'] ?: false; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /TESTING.md: -------------------------------------------------------------------------------- 1 | # Testing 2 | 3 | ## Requirements 4 | 5 | You'll need: 6 | 7 | - PHP 7.4 minimum. 8 | - docker, for the database. 9 | - symfony CLI, to run the local server. 10 | - composer, to install PHP dependencies. 11 | - npm and yarn, to install ui dependencies and build the JS/CSS files. 12 | 13 | ## Installation 14 | 15 | ```bash 16 | make install 17 | ``` 18 | 19 | This will run a Sylius app (the one in `tests/Application/`) with the plugin 20 | installed and all Sylius' sample data. It uses the symfony binary. 21 | 22 | ## Usage 23 | 24 | ### List all available commands 25 | 26 | ```bash 27 | make help 28 | ``` 29 | 30 | ### Running minimum plugin tests 31 | 32 | - PHPUnit 33 | 34 | ```bash 35 | make test.phpunit 36 | ``` 37 | 38 | - PHP CS fixer 39 | 40 | ```bash 41 | make test.phpcs 42 | ``` 43 | 44 | > Tip: You can fix your code with `make test.phpcs.fix`! 45 | 46 | - PHPSpec 47 | 48 | ```bash 49 | make test.phpspec 50 | ``` 51 | 52 | - PHPStan 53 | 54 | ```bash 55 | make test.phpstan 56 | ``` 57 | 58 | > Tip: You can run all tests with `make test.all`! 59 | -------------------------------------------------------------------------------- /dist/src/Kernel.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace App; 15 | 16 | use MonsieurBiz\SyliusNoCommercePlugin\Kernel\SyliusNoCommerceKernelTrait; 17 | use PSS\SymfonyMockerContainer\DependencyInjection\MockerContainer; 18 | use Symfony\Component\HttpKernel\Kernel as BaseKernel; 19 | 20 | final class Kernel extends BaseKernel 21 | { 22 | use SyliusNoCommerceKernelTrait; 23 | 24 | protected function getContainerBaseClass(): string 25 | { 26 | if (class_exists(MockerContainer::class) && $this->isTestEnvironment()) { 27 | return MockerContainer::class; 28 | } 29 | 30 | return parent::getContainerBaseClass(); 31 | } 32 | 33 | private function isTestEnvironment(): bool 34 | { 35 | return str_starts_with($this->getEnvironment(), 'test'); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Menu/AdminCustomerShowMenuListener.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace MonsieurBiz\SyliusNoCommercePlugin\Menu; 15 | 16 | use MonsieurBiz\SyliusNoCommercePlugin\Provider\FeaturesProviderInterface; 17 | use Sylius\Bundle\UiBundle\Menu\Event\MenuBuilderEvent; 18 | 19 | final class AdminCustomerShowMenuListener 20 | { 21 | private FeaturesProviderInterface $featuresProvider; 22 | 23 | public function __construct( 24 | FeaturesProviderInterface $featuresProvider 25 | ) { 26 | $this->featuresProvider = $featuresProvider; 27 | } 28 | 29 | public function __invoke(MenuBuilderEvent $event): void 30 | { 31 | if (!$this->featuresProvider->isNoCommerceEnabledForChannel()) { 32 | return; 33 | } 34 | 35 | $menu = $event->getMenu(); 36 | $menu->removeChild('order_index'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Menu/ShopAccountMenuListener.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace MonsieurBiz\SyliusNoCommercePlugin\Menu; 15 | 16 | use MonsieurBiz\SyliusNoCommercePlugin\Provider\FeaturesProviderInterface; 17 | use Sylius\Bundle\UiBundle\Menu\Event\MenuBuilderEvent; 18 | 19 | final class ShopAccountMenuListener 20 | { 21 | private FeaturesProviderInterface $featuresProvider; 22 | 23 | public function __construct( 24 | FeaturesProviderInterface $featuresProvider 25 | ) { 26 | $this->featuresProvider = $featuresProvider; 27 | } 28 | 29 | public function __invoke(MenuBuilderEvent $event): void 30 | { 31 | if (!$this->featuresProvider->isNoCommerceEnabledForChannel()) { 32 | return; 33 | } 34 | 35 | $menu = $event->getMenu(); 36 | 37 | $menu->removeChild('address_book'); 38 | $menu->removeChild('order_history'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /dist/src/Entity/Channel/Channel.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace App\Entity\Channel; 15 | 16 | use Doctrine\ORM\Mapping as ORM; 17 | use Sylius\Component\Core\Model\Channel as BaseChannel; 18 | 19 | #[ORM\Entity()] 20 | #[ORM\Table(name: 'sylius_channel')] 21 | #[ORM\AssociationOverrides( 22 | [ 23 | new ORM\AssociationOverride( 24 | name: 'baseCurrency', 25 | joinColumns: new ORM\JoinColumn(name: 'base_currency_id', referencedColumnName: 'id', nullable: true) 26 | )] 27 | )] 28 | /** 29 | * @ORM\Entity 30 | * @ORM\Table(name="sylius_channel") 31 | * @ORM\AssociationOverrides({ 32 | * @ORM\AssociationOverride(name="baseCurrency", 33 | * joinColumns=@ORM\JoinColumn( 34 | * name="base_currency_id", referencedColumnName="id", nullable=true 35 | * ) 36 | * ) 37 | * }) 38 | */ 39 | class Channel extends BaseChannel 40 | { 41 | } 42 | -------------------------------------------------------------------------------- /src/Twig/Extension/NoCommerceExtension.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace MonsieurBiz\SyliusNoCommercePlugin\Twig\Extension; 15 | 16 | use MonsieurBiz\SyliusNoCommercePlugin\Provider\FeaturesProviderInterface; 17 | use Twig\Extension\AbstractExtension; 18 | use Twig\TwigFunction; 19 | 20 | final class NoCommerceExtension extends AbstractExtension 21 | { 22 | private FeaturesProviderInterface $featuresProvider; 23 | 24 | public function __construct( 25 | FeaturesProviderInterface $featuresProvider 26 | ) { 27 | $this->featuresProvider = $featuresProvider; 28 | } 29 | 30 | public function getFunctions(): array 31 | { 32 | return [ 33 | new TwigFunction('is_no_commerce_enabled', [$this, 'isNoCommerceEnabled']), 34 | ]; 35 | } 36 | 37 | public function isNoCommerceEnabled(): bool 38 | { 39 | return $this->featuresProvider->isNoCommerceEnabledForChannel(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /dist/src/Migrations/Version20211103111331.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace App\Migrations; 15 | 16 | use Doctrine\DBAL\Schema\Schema; 17 | use Doctrine\Migrations\AbstractMigration; 18 | 19 | /** 20 | * Auto-generated Migration: Please modify to your needs! 21 | */ 22 | final class Version20211103111331 extends AbstractMigration 23 | { 24 | public function getDescription(): string 25 | { 26 | return ''; 27 | } 28 | 29 | public function up(Schema $schema): void 30 | { 31 | // this up() migration is auto-generated, please modify it to your needs 32 | $this->addSql('ALTER TABLE sylius_channel CHANGE base_currency_id base_currency_id INT DEFAULT NULL'); 33 | } 34 | 35 | public function down(Schema $schema): void 36 | { 37 | // this down() migration is auto-generated, please modify it to your needs 38 | $this->addSql('ALTER TABLE sylius_channel CHANGE base_currency_id base_currency_id INT NOT NULL'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /dist/src/Migrations/Version20231214131617.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace App\Migrations; 15 | 16 | use Doctrine\DBAL\Schema\Schema; 17 | use Doctrine\Migrations\AbstractMigration; 18 | 19 | /** 20 | * Auto-generated Migration: Please modify to your needs! 21 | */ 22 | final class Version20231214131617 extends AbstractMigration 23 | { 24 | public function getDescription(): string 25 | { 26 | return ''; 27 | } 28 | 29 | public function up(Schema $schema): void 30 | { 31 | // this up() migration is auto-generated, please modify it to your needs 32 | $this->addSql('ALTER TABLE mbiz_settings_setting CHANGE json_value json_value JSON DEFAULT NULL'); 33 | } 34 | 35 | public function down(Schema $schema): void 36 | { 37 | // this down() migration is auto-generated, please modify it to your needs 38 | $this->addSql('ALTER TABLE mbiz_settings_setting CHANGE json_value json_value JSON DEFAULT NULL'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/DependencyInjection/RemoveSyliusDataCollectorsPass.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace MonsieurBiz\SyliusNoCommercePlugin\DependencyInjection; 15 | 16 | use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; 17 | use Symfony\Component\DependencyInjection\ContainerBuilder; 18 | 19 | final class RemoveSyliusDataCollectorsPass implements CompilerPassInterface 20 | { 21 | /** 22 | * @SuppressWarnings(PHPMD.CyclomaticComplexity) 23 | */ 24 | public function process(ContainerBuilder $container): void 25 | { 26 | foreach ($container->getDefinitions() as $id => $definition) { 27 | if ($definition->hasTag('data_collector')) { 28 | $tagDetails = current($definition->getTag('data_collector')); 29 | if ('sylius_cart' === ($tagDetails['id'] ?? '')) { 30 | $container->removeDefinition($id); 31 | } 32 | } 33 | } 34 | if ($container->hasAlias('sylius.collector.cart')) { 35 | $container->removeAlias('sylius.collector.cart'); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Context/NoCurrencyContext.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace MonsieurBiz\SyliusNoCommercePlugin\Context; 15 | 16 | use MonsieurBiz\SyliusNoCommercePlugin\Provider\FeaturesProviderInterface; 17 | use Sylius\Component\Currency\Context\CurrencyContextInterface; 18 | 19 | final class NoCurrencyContext implements CurrencyContextInterface 20 | { 21 | public const NONE_CURRENCY_CODE = 'NONE'; 22 | 23 | private CurrencyContextInterface $decoratedCurrencyContext; 24 | 25 | private FeaturesProviderInterface $featuresProvider; 26 | 27 | public function __construct( 28 | CurrencyContextInterface $decoratedCurrencyContext, 29 | FeaturesProviderInterface $featuresProvider 30 | ) { 31 | $this->decoratedCurrencyContext = $decoratedCurrencyContext; 32 | $this->featuresProvider = $featuresProvider; 33 | } 34 | 35 | public function getCurrencyCode(): string 36 | { 37 | if (!$this->featuresProvider->isNoCommerceEnabledForChannel()) { 38 | return $this->decoratedCurrencyContext->getCurrencyCode(); 39 | } 40 | 41 | return self::NONE_CURRENCY_CODE; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/DependencyInjection/Configuration.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace MonsieurBiz\SyliusNoCommercePlugin\DependencyInjection; 15 | 16 | use Symfony\Component\Config\Definition\Builder\TreeBuilder; 17 | use Symfony\Component\Config\Definition\ConfigurationInterface; 18 | 19 | final class Configuration implements ConfigurationInterface 20 | { 21 | /** 22 | * @inheritdoc 23 | */ 24 | public function getConfigTreeBuilder(): TreeBuilder 25 | { 26 | $treeBuilder = new TreeBuilder('monsieurbiz_sylius_nocommerce'); 27 | $rootNode = $treeBuilder->getRootNode(); 28 | 29 | $rootNode 30 | ->children() 31 | // Config 32 | ->arrayNode('config') 33 | ->addDefaultsIfNotSet() 34 | ->children() 35 | ->booleanNode('allow_countries')->defaultFalse()->end() 36 | ->booleanNode('allow_customers')->defaultFalse()->end() 37 | ->booleanNode('allow_zones')->defaultFalse()->end() 38 | ->end() 39 | ->end() 40 | ; 41 | 42 | return $treeBuilder; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/DependencyInjection/MonsieurBizSyliusNoCommerceExtension.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace MonsieurBiz\SyliusNoCommercePlugin\DependencyInjection; 15 | 16 | use Symfony\Component\Config\FileLocator; 17 | use Symfony\Component\DependencyInjection\ContainerBuilder; 18 | use Symfony\Component\DependencyInjection\Extension\Extension; 19 | use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; 20 | 21 | final class MonsieurBizSyliusNoCommerceExtension extends Extension 22 | { 23 | /** 24 | * @inheritdoc 25 | */ 26 | public function load(array $config, ContainerBuilder $container): void 27 | { 28 | $configuration = $this->getConfiguration([], $container); 29 | $config = $this->processConfiguration(/** @scrutinizer ignore-type */ $configuration, $config); 30 | $container->setParameter($this->getAlias() . '.config', $config['config']); 31 | $loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); 32 | $loader->load('services.yaml'); 33 | } 34 | 35 | /** 36 | * @inheritdoc 37 | */ 38 | public function getAlias(): string 39 | { 40 | return str_replace(['no_commerce', 'monsieur_biz'], ['nocommerce', 'monsieurbiz'], parent::getAlias()); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /.github/workflows/security.yaml: -------------------------------------------------------------------------------- 1 | name: Security 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | jobs: 8 | 9 | security: 10 | 11 | runs-on: ubuntu-latest 12 | 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | php: ['8.1', '8.2', '8.3'] 17 | 18 | steps: 19 | - uses: actions/checkout@v3 20 | 21 | - name: Setup PHP 22 | uses: shivammathur/setup-php@v2 23 | with: 24 | php-version: ${{ matrix.php }} 25 | extensions: gd, intl, json 26 | 27 | - name: Set project php-version 28 | run: | 29 | echo "${{ matrix.php }}" > .php-version 30 | 31 | - name: Determine composer cache directory 32 | id: composer-cache-directory 33 | run: echo "directory=$(composer config cache-dir)" >> $GITHUB_OUTPUT 34 | 35 | - name: Cache dependencies installed with composer 36 | uses: actions/cache@v3 37 | id: cache-composer 38 | with: 39 | path: ${{ steps.composer-cache-directory.outputs.directory }} 40 | key: composer2-php:${{ matrix.php }}-${{ github.sha }} 41 | restore-keys: composer2-php:${{ matrix.php }}- 42 | 43 | - name: Ensure that composer cache directory exists 44 | run: mkdir -p ${{ steps.composer-cache-directory.outputs.directory }} 45 | 46 | - name: Composer Github Auth 47 | run: composer config -g github-oauth.github.com ${{ github.token }} 48 | 49 | - name: Install PHP dependencies 50 | run: composer update --prefer-dist 51 | 52 | - uses: symfonycorp/security-checker-action@v4 53 | 54 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | # Change these settings to your own preference 9 | indent_style = space 10 | indent_size = 4 11 | 12 | # We recommend you to keep these unchanged 13 | end_of_line = lf 14 | charset = utf-8 15 | trim_trailing_whitespace = true 16 | insert_final_newline = true 17 | 18 | [*.feature] 19 | indent_style = space 20 | indent_size = 4 21 | 22 | [*.js] 23 | indent_style = space 24 | indent_size = 2 25 | 26 | [*.json] 27 | indent_style = space 28 | indent_size = 2 29 | 30 | [*.md] 31 | indent_style = space 32 | indent_size = 4 33 | trim_trailing_whitespace = false 34 | 35 | [*.neon] 36 | indent_style = space 37 | indent_size = 4 38 | 39 | [*.php] 40 | indent_style = space 41 | indent_size = 4 42 | 43 | [*.sh] 44 | indent_style = space 45 | indent_size = 4 46 | 47 | [*.{yaml,yml}] 48 | indent_style = space 49 | indent_size = 4 50 | trim_trailing_whitespace = false 51 | 52 | [.babelrc] 53 | indent_style = space 54 | indent_size = 2 55 | 56 | [.gitmodules] 57 | indent_style = tab 58 | indent_size = 4 59 | 60 | [.php_cs{,.dist}] 61 | indent_style = space 62 | indent_size = 4 63 | 64 | [composer.json] 65 | indent_style = space 66 | indent_size = 4 67 | 68 | [package.json] 69 | indent_style = space 70 | indent_size = 2 71 | 72 | [phpspec.yml{,.dist}] 73 | indent_style = space 74 | indent_size = 4 75 | 76 | [phpstan.neon] 77 | indent_style = space 78 | indent_size = 4 79 | 80 | [phpunit.xml{,.dist}] 81 | indent_style = space 82 | indent_size = 4 83 | 84 | [Makefile] 85 | indent_style = tab 86 | -------------------------------------------------------------------------------- /src/DependencyInjection/FirewallRegistryPass.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace MonsieurBiz\SyliusNoCommercePlugin\DependencyInjection; 15 | 16 | use Symfony\Bundle\SecurityBundle\Security\FirewallContext; 17 | use Symfony\Component\DependencyInjection\ChildDefinition; 18 | use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; 19 | use Symfony\Component\DependencyInjection\ContainerBuilder; 20 | use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; 21 | use Symfony\Component\DependencyInjection\Reference; 22 | 23 | final class FirewallRegistryPass implements CompilerPassInterface 24 | { 25 | /** 26 | * @SuppressWarnings(PHPMD.CyclomaticComplexity) 27 | */ 28 | public function process(ContainerBuilder $container): void 29 | { 30 | $registry = $container->findDefinition('MonsieurBiz\SyliusNoCommercePlugin\Firewall\RegistryInterface'); 31 | 32 | foreach ($container->getDefinitions() as $code => $configuration) { 33 | if (!$configuration instanceof ChildDefinition) { 34 | continue; 35 | } 36 | 37 | try { 38 | $parent = $container->getDefinition($configuration->getParent()); 39 | } catch (ServiceNotFoundException $e) { 40 | continue; 41 | } 42 | 43 | if (FirewallContext::class !== $parent->getClass()) { 44 | continue; 45 | } 46 | $registry->addMethodCall('addFirewall', [new Reference($code)]); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Resources/config/validation/Channel.yaml: -------------------------------------------------------------------------------- 1 | Sylius\Component\Core\Model\Channel: 2 | constraints: 3 | - Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity: 4 | fields: code 5 | message: sylius.channel.code.unique 6 | groups: [monsieurbiz_nocommerce] 7 | - Sylius\Bundle\CoreBundle\Validator\Constraints\ChannelDefaultLocaleEnabled: 8 | groups: [monsieurbiz_nocommerce] 9 | - Sylius\Bundle\CoreBundle\Validator\Constraints\HasEnabledEntity: 10 | groups: [monsieurbiz_nocommerce] 11 | properties: 12 | code: 13 | - NotBlank: 14 | message: sylius.channel.code.not_blank 15 | groups: [monsieurbiz_nocommerce] 16 | - Regex: 17 | message: sylius.channel.code.regex 18 | pattern: /^[\w-]*$/ 19 | groups: [monsieurbiz_nocommerce] 20 | name: 21 | - NotBlank: 22 | message: sylius.channel.name.not_blank 23 | groups: [monsieurbiz_nocommerce] 24 | defaultLocale: 25 | - NotBlank: 26 | message: sylius.channel.default_locale.not_blank 27 | groups: [monsieurbiz_nocommerce] 28 | taxCalculationStrategy: 29 | - NotBlank: 30 | groups: [monsieurbiz_nocommerce] 31 | contactEmail: 32 | - Length: 33 | min: 2 34 | minMessage: sylius.channel.contact_email.min 35 | max: 254 36 | maxMessage: sylius.channel.contact_email.max 37 | groups: [monsieurbiz_nocommerce] 38 | - Email: 39 | message: sylius.channel.contact_email.invalid 40 | mode: strict 41 | groups: [monsieurbiz_nocommerce] 42 | -------------------------------------------------------------------------------- /src/Provider/FeaturesProvider.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace MonsieurBiz\SyliusNoCommercePlugin\Provider; 15 | 16 | use Exception; 17 | use MonsieurBiz\SyliusSettingsPlugin\Settings\SettingsInterface; 18 | use Sylius\Component\Channel\Context\ChannelContextInterface; 19 | use Sylius\Component\Core\Model\ChannelInterface; 20 | 21 | final class FeaturesProvider implements FeaturesProviderInterface 22 | { 23 | private ChannelContextInterface $channelContext; 24 | 25 | private SettingsInterface $nocommerceSettings; 26 | 27 | public function __construct( 28 | ChannelContextInterface $channelContext, 29 | SettingsInterface $nocommerceSettings 30 | ) { 31 | $this->channelContext = $channelContext; 32 | $this->nocommerceSettings = $nocommerceSettings; 33 | } 34 | 35 | public function isNoCommerceEnabledForChannel(?ChannelInterface $channel = null): bool 36 | { 37 | try { 38 | if (null === $channel) { 39 | $channel = $this->channelContext->getChannel(); 40 | } 41 | // In case we are getting a channel that does not exist yet, we return null to have the channel set properly 42 | if (null === $channel->getId()) { 43 | return true; 44 | } 45 | } catch (Exception $exception) { 46 | return false; 47 | } 48 | 49 | return (bool) $this->nocommerceSettings->getCurrentValue($channel, null, 'enabled'); 50 | } 51 | 52 | public function allowAdmin(): bool 53 | { 54 | return (bool) $this->nocommerceSettings->getCurrentValue(null, null, 'allow_admin'); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "monsieurbiz/sylius-no-commerce-plugin", 3 | "type": "sylius-plugin", 4 | "keywords": ["sylius", "sylius-plugin", "monsieurbiz"], 5 | "description": "Disable the e-commerce on your Sylius.", 6 | "license": "MIT", 7 | "require": { 8 | "monsieurbiz/sylius-settings-plugin": "^1.2.0", 9 | "php": "^8.1", 10 | "sylius/sylius": ">=1.12 <2.0" 11 | }, 12 | "require-dev": { 13 | "friendsofphp/php-cs-fixer": "^3.16", 14 | "phpspec/phpspec": "^7.0", 15 | "phpstan/phpstan": "^1.8.4", 16 | "phpstan/phpstan-doctrine": "^1.3.2", 17 | "phpstan/phpstan-webmozart-assert": "^1.1", 18 | "phpunit/phpunit": "^10.5", 19 | "phpmd/phpmd": "^2.15" 20 | }, 21 | "prefer-stable": true, 22 | "autoload": { 23 | "psr-4": { 24 | "MonsieurBiz\\SyliusNoCommercePlugin\\": "src/" 25 | } 26 | }, 27 | "scripts": { 28 | "auto-scripts": { 29 | "cache:clear": "symfony-cmd", 30 | "assets:install %PUBLIC_DIR%": "symfony-cmd" 31 | }, 32 | "phpcs": "PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix --using-cache=no", 33 | "phpstan": "phpstan analyse -c phpstan.neon src/", 34 | "phpmd": "phpmd --exclude Migrations/* src/ ansi phpmd.xml", 35 | "phpunit": "phpunit", 36 | "phpspec": "phpspec run" 37 | }, 38 | "extra": { 39 | "branch-alias": { 40 | "dev-master": "1.1-dev" 41 | }, 42 | "symfony": { 43 | "docker": false, 44 | "endpoint": ["https://api.github.com/repos/monsieurbiz/symfony-recipes/contents/index.json?ref=flex/master", "flex://defaults"] 45 | } 46 | }, 47 | "config": { 48 | "allow-plugins": { 49 | "symfony/thanks": true, 50 | "symfony/flex": true, 51 | "dealerdirect/phpcodesniffer-composer-installer": true, 52 | "ergebnis/composer-normalize": true, 53 | "php-http/discovery": true 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Routing/NoCommerceRequestContext.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace MonsieurBiz\SyliusNoCommercePlugin\Routing; 15 | 16 | use Exception; 17 | use MonsieurBiz\SyliusNoCommercePlugin\Provider\FeaturesProviderInterface; 18 | use Symfony\Component\Routing\RequestContext as BaseRequestContext; 19 | 20 | final class NoCommerceRequestContext extends BaseRequestContext 21 | { 22 | private BaseRequestContext $decorated; 23 | 24 | private FeaturesProviderInterface $featuresProvider; 25 | 26 | public function __construct( 27 | BaseRequestContext $decorated, 28 | FeaturesProviderInterface $featuresProvider 29 | ) { 30 | parent::__construct( 31 | $decorated->getBaseUrl(), 32 | $decorated->getMethod(), 33 | $decorated->getHost(), 34 | $decorated->getScheme(), 35 | $decorated->getHttpPort(), 36 | $decorated->getHttpsPort(), 37 | $decorated->getPathInfo(), 38 | $decorated->getQueryString() 39 | ); 40 | $this->decorated = $decorated; 41 | $this->featuresProvider = $featuresProvider; 42 | } 43 | 44 | public function checkNoCommerce(): bool 45 | { 46 | return $this->featuresProvider->isNoCommerceEnabledForChannel(); 47 | } 48 | 49 | /** 50 | * @throws Exception 51 | * 52 | * @return mixed 53 | */ 54 | public function __call(string $name, array $arguments) 55 | { 56 | $callback = [$this->decorated, $name]; 57 | if (\is_callable($callback)) { 58 | return \call_user_func($callback, ...$arguments); 59 | } 60 | 61 | throw new Exception(\sprintf('Method %s not found for class "%s"', $name, \get_class($this->decorated))); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/MonsieurBizSyliusNoCommercePlugin.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace MonsieurBiz\SyliusNoCommercePlugin; 15 | 16 | use LogicException; 17 | use MonsieurBiz\SyliusNoCommercePlugin\DependencyInjection\FirewallRegistryPass; 18 | use MonsieurBiz\SyliusNoCommercePlugin\DependencyInjection\RemoveSyliusDataCollectorsPass; 19 | use Sylius\Bundle\CoreBundle\Application\SyliusPluginTrait; 20 | use Symfony\Component\DependencyInjection\Compiler\PassConfig; 21 | use Symfony\Component\DependencyInjection\ContainerBuilder; 22 | use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; 23 | use Symfony\Component\HttpKernel\Bundle\Bundle; 24 | 25 | final class MonsieurBizSyliusNoCommercePlugin extends Bundle 26 | { 27 | use SyliusPluginTrait; 28 | 29 | /** 30 | * Returns the plugin's container extension. 31 | * 32 | * @throws LogicException 33 | * 34 | * @return ExtensionInterface|null The container extension 35 | */ 36 | public function getContainerExtension(): ?ExtensionInterface 37 | { 38 | if (null === $this->containerExtension) { 39 | $this->containerExtension = false; 40 | $extension = $this->createContainerExtension(); 41 | if (null !== $extension) { 42 | $this->containerExtension = $extension; 43 | } 44 | } 45 | 46 | return $this->containerExtension instanceof ExtensionInterface 47 | ? $this->containerExtension 48 | : null; 49 | } 50 | 51 | public function build(ContainerBuilder $container): void 52 | { 53 | parent::build($container); 54 | $container->addCompilerPass(new RemoveSyliusDataCollectorsPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 1); 55 | $container->addCompilerPass(new FirewallRegistryPass()); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /.github/workflows/tests.yaml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | 8 | jobs: 9 | 10 | php: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | fail-fast: false 16 | matrix: 17 | php: ['8.1', '8.2', '8.3'] 18 | 19 | env: 20 | SYMFONY_ARGS: --no-tls 21 | COMPOSER_ARGS: --prefer-dist 22 | DOCKER_INTERACTIVE_ARGS: -t 23 | 24 | steps: 25 | - uses: actions/checkout@v2 26 | - uses: actions/setup-node@v2 27 | with: 28 | node-version: '14' 29 | - name: Setup PHP 30 | uses: shivammathur/setup-php@v2 31 | with: 32 | php-version: ${{ matrix.php }} 33 | extensions: gd, intl, json 34 | ini-values: date.timezone=UTC 35 | tools: symfony-cli 36 | 37 | - name: Set project php-version 38 | run: | 39 | echo "${{ matrix.php }}" > .php-version 40 | 41 | - name: Determine composer cache directory 42 | id: composer-cache-directory 43 | run: echo "directory=$(composer config cache-dir)" >> $GITHUB_OUTPUT 44 | 45 | - name: Cache dependencies installed with composer 46 | uses: actions/cache@v3 47 | id: cache-composer 48 | with: 49 | path: ${{ steps.composer-cache-directory.outputs.directory }} 50 | key: composer2-php:${{ matrix.php }}-${{ github.sha }} 51 | restore-keys: composer2-php:${{ matrix.php }}- 52 | 53 | - name: Ensure that composer cache directory exists 54 | run: mkdir -p ${{ steps.composer-cache-directory.outputs.directory }} 55 | 56 | - name: Composer Github Auth 57 | run: composer config -g github-oauth.github.com ${{ github.token }} 58 | 59 | - run: make install 60 | 61 | - run: make test.composer 62 | 63 | - run: make test.phpcs 64 | 65 | - run: make test.phpunit 66 | 67 | - run: make test.phpstan 68 | 69 | - run: make test.phpmd 70 | 71 | - run: make test.phpspec 72 | 73 | - run: make test.yaml 74 | 75 | - run: make test.twig 76 | 77 | - run: make test.schema 78 | 79 | - run: make test.container 80 | -------------------------------------------------------------------------------- /src/Form/Type/Settings/NoCommerceType.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace MonsieurBiz\SyliusNoCommercePlugin\Form\Type\Settings; 15 | 16 | use MonsieurBiz\SyliusNoCommercePlugin\Firewall\RegistryInterface; 17 | use MonsieurBiz\SyliusSettingsPlugin\Form\AbstractSettingsType; 18 | use Symfony\Component\Form\Extension\Core\Type\CheckboxType; 19 | use Symfony\Component\Form\Extension\Core\Type\ChoiceType; 20 | use Symfony\Component\Form\FormBuilderInterface; 21 | 22 | class NoCommerceType extends AbstractSettingsType 23 | { 24 | private const FIREWALLS_NAMES_CANNOT_BE_DISABLED = [ 25 | 'admin', 26 | ]; 27 | 28 | private RegistryInterface $firewallRegistry; 29 | 30 | public function __construct(RegistryInterface $firewallRegistry) 31 | { 32 | $this->firewallRegistry = $firewallRegistry; 33 | } 34 | 35 | /** 36 | * @SuppressWarnings(PHPMD.UnusedFormalParameter) 37 | * @SuppressWarnings(PHPMD.CyclomaticComplexity) 38 | */ 39 | public function buildForm(FormBuilderInterface $builder, array $options): void 40 | { 41 | $choices = []; 42 | foreach ($this->firewallRegistry as $firewall) { 43 | $firewallConfig = $firewall->getConfig(); 44 | if (null === $firewallConfig) { 45 | continue; 46 | } 47 | $firewallName = $firewallConfig->getName(); 48 | if (\in_array($firewallName, self::FIREWALLS_NAMES_CANNOT_BE_DISABLED, true)) { 49 | continue; 50 | } 51 | $choices[$firewallName] = $firewallConfig->getContext() ?? $firewallName; 52 | } 53 | 54 | $this->addWithDefaultCheckbox($builder, 'enabled', CheckboxType::class, [ 55 | 'label' => 'monsieurbiz.nocommerce.ui.form.field.enabled.label', 56 | 'required' => false, 57 | ]); 58 | 59 | if ($this->isDefaultForm($builder)) { 60 | $builder->add('allow_admin', CheckboxType::class, [ 61 | 'label' => 'monsieurbiz.nocommerce.ui.form.field.allow_admin.label', 62 | 'required' => false, 63 | ]); 64 | } 65 | 66 | $this->addWithDefaultCheckbox($builder, 'disabled_firewall_contexts', ChoiceType::class, [ 67 | 'label' => 'monsieurbiz.nocommerce.ui.form.field.disabled_firewall_contexts.label', 68 | 'required' => false, 69 | 'multiple' => true, 70 | 'choices' => $choices, 71 | ]); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/Form/Extension/ChannelTypeExtension.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace MonsieurBiz\SyliusNoCommercePlugin\Form\Extension; 15 | 16 | use MonsieurBiz\SyliusNoCommercePlugin\Form\EventSubscriber\RemoveBaseCurrencySubscriber; 17 | use MonsieurBiz\SyliusNoCommercePlugin\Provider\FeaturesProviderInterface; 18 | use Sylius\Bundle\ChannelBundle\Form\Type\ChannelType; 19 | use Sylius\Component\Core\Model\ChannelInterface; 20 | use Symfony\Component\Form\AbstractTypeExtension; 21 | use Symfony\Component\Form\FormBuilderInterface; 22 | use Symfony\Component\Form\FormInterface; 23 | use Symfony\Component\Form\FormView; 24 | 25 | final class ChannelTypeExtension extends AbstractTypeExtension 26 | { 27 | private FeaturesProviderInterface $featuresProvider; 28 | 29 | public function __construct( 30 | FeaturesProviderInterface $featuresProvider 31 | ) { 32 | $this->featuresProvider = $featuresProvider; 33 | } 34 | 35 | /** 36 | * @SuppressWarnings(PHPMD.UnusedFormalParameters) 37 | */ 38 | public function buildForm(FormBuilderInterface $builder, array $options): void 39 | { 40 | /* 41 | * We are testing with the channel that is currently edited to know which field to remove 42 | * In case of a creation, the setting value is not set yet so the provider will check if the no commerce plugin is enabled in the global scope 43 | */ 44 | /** @var ChannelInterface $channel */ 45 | $channel = $options['data']; 46 | if (!$this->featuresProvider->isNoCommerceEnabledForChannel($channel)) { 47 | return; 48 | } 49 | 50 | $builder 51 | ->remove('shopBillingData') 52 | ->remove('menuTaxon') 53 | ->remove('skippingShippingStepAllowed') 54 | ->remove('skippingPaymentStepAllowed') 55 | ->remove('baseCurrency') 56 | ->remove('currencies') 57 | ->remove('defaultTaxZone') 58 | ->remove('taxCalculationStrategy') 59 | ->remove('channelPriceHistoryConfig') 60 | ->addEventSubscriber(new RemoveBaseCurrencySubscriber()) 61 | ; 62 | } 63 | 64 | public static function getExtendedTypes(): array 65 | { 66 | return [ChannelType::class]; 67 | } 68 | 69 | public function buildView(FormView $view, FormInterface $form, array $options): void 70 | { 71 | parent::buildView($view, $form, $options); 72 | 73 | /** @var ChannelInterface $channel */ 74 | $channel = $options['data']; 75 | 76 | $view->vars['noCommerceEnabled'] = $this->featuresProvider->isNoCommerceEnabledForChannel($channel); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /.github/workflows/recipe.yaml: -------------------------------------------------------------------------------- 1 | name: Flex Recipe 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | 8 | jobs: 9 | 10 | recipe: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | fail-fast: false 16 | matrix: 17 | php: ['8.1', '8.2', '8.3'] 18 | sylius: ["~1.12.0", "~1.13.0", "1.14.0"] 19 | 20 | steps: 21 | - name: Setup PHP 22 | uses: shivammathur/setup-php@v2 23 | with: 24 | php-version: ${{ matrix.php }} 25 | extensions: gd, intl, json 26 | ini-values: date.timezone=UTC 27 | tools: symfony-cli 28 | 29 | - name: Set project php-version 30 | run: | 31 | echo ${{ matrix.php }} > .php-version 32 | 33 | - uses: actions/checkout@v3 34 | with: 35 | path: plugin 36 | 37 | - name: Determine composer cache directory 38 | id: composer-cache-directory 39 | working-directory: plugin 40 | run: echo "directory=$(composer config cache-dir)" >> $GITHUB_OUTPUT 41 | 42 | - name: Cache dependencies installed with composer 43 | uses: actions/cache@v3 44 | id: cache-composer 45 | with: 46 | path: ${{ steps.composer-cache-directory.outputs.directory }} 47 | key: composer2-php:${{ matrix.php }}-sylius:${{ matrix.sylius }}-${{ hashFiles('**/composer.json') }} 48 | restore-keys: composer2-php:${{ matrix.php }}-sylius:${{ matrix.sylius }}- 49 | 50 | - name: Ensure that composer cache directory exists 51 | run: mkdir -p ${{ steps.composer-cache-directory.outputs.directory }} 52 | 53 | - name: Composer Github Auth 54 | run: composer config -g github-oauth.github.com ${{ github.token }} 55 | 56 | - name: Create Sylius-Standard project without install 57 | run: | 58 | composer create-project --prefer-dist --no-scripts --no-progress --no-install sylius/sylius-standard sylius "${{ matrix.sylius }}" 59 | 60 | # Because the sylius-standard has a soft constraint 61 | - name: Make sure to install the required version of Sylius 62 | working-directory: ./sylius 63 | run: | 64 | composer require --no-install --no-scripts --no-progress sylius/sylius="${{ matrix.sylius }}" 65 | 66 | - name: Setup some requirements 67 | working-directory: ./sylius 68 | run: | 69 | composer config --no-plugins allow-plugins true 70 | composer config --no-plugins extra.symfony.allow-contrib true 71 | composer config --no-plugins secure-http false 72 | composer config --no-plugins --unset platform.php 73 | composer config --no-plugins extra.symfony.docker false 74 | composer config --no-plugins --json extra.symfony.endpoint '["https://api.github.com/repos/monsieurbiz/symfony-recipes/contents/index.json?ref=flex/master","flex://defaults"]' 75 | composer config repositories.plugin '{"type": "path", "url": "../plugin/"}' 76 | 77 | - name: Require plugin & install all dependencies 78 | working-directory: ./sylius 79 | run: | 80 | composer require monsieurbiz/sylius-no-commerce-plugin="*@dev" 81 | -------------------------------------------------------------------------------- /phpmd.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /src/Resources/config/services.yaml: -------------------------------------------------------------------------------- 1 | parameters: 2 | sylius.form.type.channel.validation_groups: [monsieurbiz_nocommerce] 3 | monsieurbiz_sylius_nocommerce.disable_firewall.ignored_routes: [] 4 | 5 | services: 6 | _defaults: 7 | autowire: true 8 | autoconfigure: true 9 | public: false 10 | 11 | MonsieurBiz\SyliusNoCommercePlugin\: 12 | resource: '../../' 13 | 14 | MonsieurBiz\SyliusNoCommercePlugin\Form\Extension\: 15 | resource: '../../Form/Extension' 16 | tags: 17 | - { name: form.type_extension, priority: -10000 } 18 | 19 | MonsieurBiz\SyliusNoCommercePlugin\Menu\AdminMenuListener: 20 | tags: 21 | - { name: kernel.event_listener, event: sylius.menu.admin.main, priority: -10000 } 22 | 23 | MonsieurBiz\SyliusNoCommercePlugin\Menu\AdminCustomerShowMenuListener: 24 | tags: 25 | - { name: kernel.event_listener, event: sylius.menu.admin.customer.show, priority: -10000 } 26 | 27 | MonsieurBiz\SyliusNoCommercePlugin\Menu\ShopAccountMenuListener: 28 | tags: 29 | - { name: kernel.event_listener, event: sylius.menu.shop.account, priority: -10000 } 30 | 31 | MonsieurBiz\SyliusNoCommercePlugin\EventListener\DisableFirewallListener: 32 | arguments: 33 | $ignoredRoutes: '%monsieurbiz_sylius_nocommerce.disable_firewall.ignored_routes%' 34 | tags: 35 | - { name: kernel.event_listener, event: kernel.request, priority: -10000 } 36 | 37 | MonsieurBiz\SyliusNoCommercePlugin\Model\Config: 38 | arguments: 39 | - '%monsieurbiz_sylius_nocommerce.config%' 40 | 41 | Symfony\Bundle\SecurityBundle\Security\FirewallMap: '@security.firewall.map' 42 | 43 | monsieurbiz.nocommerce.firewall.registry: '@MonsieurBiz\SyliusNoCommercePlugin\Firewall\Registry' 44 | 45 | MonsieurBiz\SyliusNoCommercePlugin\Collector\NoCommerceSyliusCollector: 46 | autowire: false 47 | arguments: 48 | - '@sylius.context.shopper' 49 | - '%kernel.bundles%' 50 | - '%locale%' 51 | - '@monsieurbiz.no_commerce.provider.features_provider' 52 | tags: 53 | - { name: data_collector, template: '@SyliusCore/Collector/sylius.html.twig', id: sylius_core, priority: -512 } 54 | 55 | MonsieurBiz\SyliusNoCommercePlugin\Context\NoCurrencyContext: 56 | decorates: sylius.context.currency.channel_aware 57 | arguments: 58 | - '@MonsieurBiz\SyliusNoCommercePlugin\Context\NoCurrencyContext.inner' 59 | - '@monsieurbiz.no_commerce.provider.features_provider' 60 | 61 | MonsieurBiz\SyliusNoCommercePlugin\Registry\TemplateBlockRegistryDecorator: 62 | decorates: 'Sylius\Bundle\UiBundle\Registry\TemplateBlockRegistryInterface' 63 | arguments: 64 | $templateBlockRegistry: '@MonsieurBiz\SyliusNoCommercePlugin\Registry\TemplateBlockRegistryDecorator.inner' 65 | $featuresProvider: '@monsieurbiz.no_commerce.provider.features_provider' 66 | 67 | monsieurbiz.no_commerce.provider.features_provider: 68 | class: 'MonsieurBiz\SyliusNoCommercePlugin\Provider\FeaturesProvider' 69 | public: true 70 | 71 | # Routing Context 72 | MonsieurBiz\SyliusNoCommercePlugin\Routing\NoCommerceRequestContext: 73 | decorates: router.request_context 74 | arguments: 75 | - '@MonsieurBiz\SyliusNoCommercePlugin\Routing\NoCommerceRequestContext.inner' 76 | - '@monsieurbiz.no_commerce.provider.features_provider' 77 | -------------------------------------------------------------------------------- /src/EventListener/DisableFirewallListener.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace MonsieurBiz\SyliusNoCommercePlugin\EventListener; 15 | 16 | use MonsieurBiz\SyliusNoCommercePlugin\Provider\FeaturesProviderInterface; 17 | use MonsieurBiz\SyliusSettingsPlugin\Settings\SettingsInterface; 18 | use Sylius\Component\Channel\Context\ChannelContextInterface; 19 | use Sylius\Component\Channel\Context\ChannelNotFoundException; 20 | use Symfony\Bundle\SecurityBundle\Security\FirewallMap; 21 | use Symfony\Component\HttpFoundation\Request; 22 | use Symfony\Component\HttpKernel\Event\RequestEvent; 23 | use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; 24 | 25 | final class DisableFirewallListener 26 | { 27 | private const PROFILER_ROUTES = ['_wdt', '_profiler', '_profiler_search', '_profiler_search_results']; 28 | 29 | private FirewallMap $firewallContext; 30 | 31 | private SettingsInterface $nocommerceSettings; 32 | 33 | private ChannelContextInterface $channelContext; 34 | 35 | private FeaturesProviderInterface $featuresProvider; 36 | 37 | private array $ignoredRoutes; 38 | 39 | public function __construct( 40 | FirewallMap $firewallContext, 41 | SettingsInterface $nocommerceSettings, 42 | ChannelContextInterface $channelContext, 43 | FeaturesProviderInterface $featuresProvider, 44 | array $ignoredRoutes = [] 45 | ) { 46 | $this->firewallContext = $firewallContext; 47 | $this->nocommerceSettings = $nocommerceSettings; 48 | $this->channelContext = $channelContext; 49 | $this->featuresProvider = $featuresProvider; 50 | $this->ignoredRoutes = $ignoredRoutes; 51 | } 52 | 53 | /** 54 | * @SuppressWarnings(PHPMD.CyclomaticComplexity) 55 | */ 56 | public function __invoke(RequestEvent $event): void 57 | { 58 | if (!$this->canCheckRoute($event)) { 59 | return; 60 | } 61 | 62 | if (!$this->featuresProvider->isNoCommerceEnabledForChannel()) { 63 | return; 64 | } 65 | 66 | try { 67 | $currentChannel = $this->channelContext->getChannel(); 68 | $disabledFirewall = (array) ($this->nocommerceSettings->getCurrentValue($currentChannel, null, 'disabled_firewall_contexts') ?: []); 69 | $firewallContextName = $this->getFirewallContextName($event->getRequest()); 70 | if (\in_array($firewallContextName, $disabledFirewall, true)) { 71 | throw new NotFoundHttpException('Route not found'); 72 | } 73 | } catch (ChannelNotFoundException $exception) { 74 | // nothing to do without channel 75 | } 76 | } 77 | 78 | private function canCheckRoute(RequestEvent $event): bool 79 | { 80 | $ignoredRoutes = array_merge(self::PROFILER_ROUTES, $this->ignoredRoutes); 81 | 82 | return $event->isMainRequest() 83 | && !\in_array($event->getRequest()->attributes->get('_route'), $ignoredRoutes, true); 84 | } 85 | 86 | private function getFirewallContextName(Request $request): string 87 | { 88 | $firewallConfig = $this->firewallContext->getFirewallConfig($request); 89 | if (null === $firewallConfig) { 90 | return ''; 91 | } 92 | 93 | return $firewallConfig->getContext() ?? $firewallConfig->getName(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/Menu/AdminMenuListener.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace MonsieurBiz\SyliusNoCommercePlugin\Menu; 15 | 16 | use Knp\Menu\ItemInterface; 17 | use MonsieurBiz\SyliusNoCommercePlugin\Provider\FeaturesProviderInterface; 18 | use Sylius\Bundle\UiBundle\Menu\Event\MenuBuilderEvent; 19 | use Symfony\Component\Routing\Route; 20 | use Symfony\Component\Routing\RouteCollection; 21 | use Symfony\Component\Routing\RouterInterface; 22 | 23 | final class AdminMenuListener 24 | { 25 | private FeaturesProviderInterface $featuresProvider; 26 | 27 | private RouterInterface $router; 28 | 29 | public function __construct( 30 | FeaturesProviderInterface $featuresProvider, 31 | RouterInterface $router 32 | ) { 33 | $this->featuresProvider = $featuresProvider; 34 | $this->router = $router; 35 | } 36 | 37 | /** 38 | * @SuppressWarnings(PHPMD.CyclomaticComplexity) 39 | */ 40 | public function __invoke(MenuBuilderEvent $event): void 41 | { 42 | $menu = $event->getMenu(); 43 | 44 | if (!$this->featuresProvider->isNoCommerceEnabledForChannel()) { 45 | return; 46 | } 47 | 48 | // We loop on all items and check if each route is enabled or not 49 | // If the route is disabled, we remove the menu item 50 | // If all children are removed, we remove the parent menu item 51 | 52 | // Retrieve all avaible routes 53 | $routes = $this->router->getRouteCollection(); 54 | 55 | // Loop on level 1 menu items 56 | foreach ($menu->getChildren() as $childMenu) { 57 | // Loop on level 2 menu items 58 | foreach ($childMenu->getChildren() as $menuItem) { 59 | // Remove menu item if route is disabled 60 | $this->removeChildIfRoutesDisabled($childMenu, $menuItem->getName(), $routes); 61 | } 62 | 63 | // Remove parent menu item if no child left 64 | if (0 === \count($childMenu->getChildren())) { 65 | $menu->removeChild($childMenu->getName()); 66 | } 67 | } 68 | } 69 | 70 | /** 71 | * If the route in the menu items matches a route that is disabled, remove the menu item. 72 | * We now that the route is disabled if the condition contains "not context.checkNoCommerce()". 73 | */ 74 | private function removeChildIfRoutesDisabled(ItemInterface $menu, string $menuName, RouteCollection $routes): void 75 | { 76 | $menuItem = $menu->getChild($menuName); 77 | if (!$menuItem || null === $menuItem->getExtra('routes')) { 78 | return; 79 | } 80 | 81 | $route = $this->getRouteByUri((string) $menuItem->getUri(), $routes); 82 | if (false !== strpos((string) $route?->getCondition(), 'not context.checkNoCommerce()')) { 83 | $menu->removeChild($menuName); 84 | } 85 | } 86 | 87 | /** 88 | * @SuppressWarnings(PHPMD.UnusedLocalVariable) 89 | */ 90 | private function getRouteByUri(string $uri, RouteCollection $routes): ?Route 91 | { 92 | foreach ($routes as $name => $route) { 93 | if ($uri === $route->getPath()) { 94 | return $route; 95 | } 96 | } 97 | 98 | return null; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | tests/Unit 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/Kernel/SyliusNoCommerceKernelTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace MonsieurBiz\SyliusNoCommercePlugin\Kernel; 15 | 16 | use Exception; 17 | use MonsieurBiz\SyliusNoCommercePlugin\Model\Config; 18 | use MonsieurBiz\SyliusNoCommercePlugin\Model\ConfigInterface; 19 | use MonsieurBiz\SyliusNoCommercePlugin\Provider\FeaturesProviderInterface; 20 | use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; 21 | use Symfony\Component\Config\Loader\LoaderInterface; 22 | use Symfony\Component\Routing\RouteCollection; 23 | 24 | trait SyliusNoCommerceKernelTrait 25 | { 26 | use MicroKernelTrait { 27 | MicroKernelTrait::loadRoutes as parentLoadRoutes; 28 | } 29 | 30 | /** 31 | * @SuppressWarnings(PHPMD.CyclomaticComplexity) 32 | */ 33 | public function loadRoutes(LoaderInterface $loader): RouteCollection 34 | { 35 | $collection = $this->parentLoadRoutes($loader); 36 | 37 | $routesToRemove = $this->getRoutesToRemove(); 38 | foreach ($collection as $name => $route) { 39 | foreach ($routesToRemove as $routeToRemove) { 40 | if (false !== strpos($name, $routeToRemove)) { 41 | $routeCondition = $route->getCondition(); 42 | if ($routeCondition && false === strpos($routeCondition, 'not context.checkNoCommerce()')) { 43 | $route->setCondition($routeCondition . ' and not context.checkNoCommerce()'); 44 | } elseif (!$routeCondition) { 45 | $route->setCondition('not context.checkNoCommerce()'); 46 | } 47 | } 48 | } 49 | } 50 | 51 | return $collection; 52 | } 53 | 54 | /** 55 | * Create a NoCommerce Config object. 56 | */ 57 | private function getConfig(): ConfigInterface 58 | { 59 | return new Config( 60 | (array) ($this->container->getParameter('monsieurbiz_sylius_nocommerce.config') ?? []) 61 | ); 62 | } 63 | 64 | /** 65 | * Retrieve all routes to remove depending on config. 66 | * 67 | * @SuppressWarnings(PHPMD.CyclomaticComplexity) 68 | */ 69 | public function getRoutesToRemove(): array 70 | { 71 | $config = $this->getConfig(); 72 | $routesToRemove = []; 73 | $routesByGroup = ConfigInterface::ROUTES_BY_GROUP; 74 | 75 | /** @deprecated */ 76 | if ($config->areCustomersAllowed()) { 77 | unset($routesByGroup['customer_shop'], $routesByGroup['customer_api'], $routesByGroup['customer_admin']); 78 | } 79 | 80 | /** @deprecated */ 81 | if ($config->areZonesAllowed()) { 82 | unset($routesByGroup['zone_admin'], $routesByGroup['zone_api']); 83 | } 84 | 85 | /** @deprecated */ 86 | if ($config->areZonesAllowed() || $config->areCountriesAllowed()) { 87 | unset($routesByGroup['country_admin'], $routesByGroup['country_api']); 88 | } 89 | 90 | /** @var FeaturesProviderInterface $featuresProvider */ 91 | $featuresProvider = $this->container->get('monsieurbiz.no_commerce.provider.features_provider'); 92 | 93 | try { 94 | $allowAdmin = $featuresProvider->allowAdmin(); 95 | } catch (Exception $e) { 96 | $allowAdmin = false; 97 | } 98 | 99 | foreach ($routesByGroup as $routesKey => $routes) { 100 | // Allow admin group routes 101 | if (true === $allowAdmin && false !== strpos($routesKey, ConfigInterface::ADMIN_ROUTE_GROUP_MATCHER)) { 102 | continue; 103 | } 104 | 105 | $routesToRemove = array_merge($routesToRemove, $routes); 106 | } 107 | 108 | return $routesToRemove; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/Resources/views/Admin/Channel/_standardForm.html.twig: -------------------------------------------------------------------------------- 1 | {{ form_errors(form) }} 2 |
3 |
4 |

{{ 'sylius.ui.general'|trans }}

5 |
6 | {{ form_errors(form) }} 7 |
8 |
9 | {{ form_row(form.code) }} 10 |
11 |
12 | {{ form_row(form.name) }} 13 |
14 |
15 | {{ form_row(form.color) }} 16 |
17 |
18 | 19 | {{ form_row(form.enabled) }} 20 |
21 |
22 |
23 | {{ form_label(form.hostname) }} 24 |
25 |
https://
26 | {{ form_widget(form.hostname) }} 27 |
28 | {{ form_errors(form.hostname) }} 29 |
30 | {{ form_row(form.contactEmail) }} 31 | {{ form_row(form.description, {'attr': {'rows' : '3'}}) }} 32 |
33 |
34 | {{ form_row(form.countries) }} 35 |
36 | 37 |

{{ 'sylius.ui.money'|trans }}

38 |
39 |
40 | {{ form_row(form.baseCurrency) }} 41 | {{ form_row(form.currencies) }} 42 |
43 |
44 |
45 | {{ form_row(form.defaultTaxZone) }} 46 | {{ form_row(form.taxCalculationStrategy) }} 47 |
48 |
49 |
50 |

{{ form_label(form.shopBillingData) }}

51 |
52 |
53 | {{ form_row(form.shopBillingData.company) }} 54 | {{ form_row(form.shopBillingData.taxId) }} 55 |
56 |
57 | {{ form_row(form.shopBillingData.countryCode) }} 58 | {{ form_row(form.shopBillingData.street) }} 59 |
60 |
61 | {{ form_row(form.shopBillingData.city) }} 62 | {{ form_row(form.shopBillingData.postcode) }} 63 |
64 |
65 | 66 |

{{ 'sylius.ui.look_and_feel'|trans }}

67 |
68 | {{ form_row(form.themeName) }} 69 |
70 |
71 | {{ form_row(form.locales) }} 72 | {{ form_row(form.defaultLocale) }} 73 |
74 |
75 | {{ form_row(form.menuTaxon) }} 76 |
77 | 78 |
79 | {{ form_row(form.skippingShippingStepAllowed) }} 80 | {{ form_row(form.skippingPaymentStepAllowed) }} 81 | {{ form_row(form.accountVerificationRequired) }} 82 |
83 | {% if form.channelPriceHistoryConfig is defined %} 84 |
85 | {{ form_row(form.channelPriceHistoryConfig.lowestPriceForDiscountedProductsVisible) }} 86 | {{ form_row(form.channelPriceHistoryConfig.lowestPriceForDiscountedProductsCheckingPeriod) }} 87 | {{ form_row(form.channelPriceHistoryConfig.taxonsExcludedFromShowingLowestPrice, {'remote_url': path('sylius_admin_ajax_taxon_by_name_phrase'), 'load_edit_url': path('sylius_admin_ajax_taxon_by_code')}) }} 88 |
89 | {% endif %} 90 |
91 |
92 | -------------------------------------------------------------------------------- /src/Resources/views/Admin/Channel/_noCommerceForm.html.twig: -------------------------------------------------------------------------------- 1 | {{ form_errors(form) }} 2 |
3 |
4 |

{{ 'sylius.ui.general'|trans }}

5 |
6 | {{ form_errors(form) }} 7 |
8 |
9 | {{ form_row(form.code) }} 10 |
11 |
12 | {{ form_row(form.name) }} 13 |
14 |
15 | {{ form_row(form.color) }} 16 |
17 |
18 | 19 | {{ form_row(form.enabled) }} 20 |
21 |
22 |
23 | {{ form_label(form.hostname) }} 24 |
25 |
https://
26 | {{ form_widget(form.hostname) }} 27 |
28 | {{ form_errors(form.hostname) }} 29 |
30 | {{ form_row(form.contactEmail) }} 31 | {{ form_row(form.description, {'attr': {'rows' : '3'}}) }} 32 |
33 |
34 | {{ form_row(form.countries) }} 35 |
36 | {# #} 37 | {#

{{ 'sylius.ui.money'|trans }}

#} 38 | {#
#} 39 | {#
#} 40 | {# {{ form_row(form.baseCurrency) }}#} 41 | {# {{ form_row(form.currencies) }}#} 42 | {#
#} 43 | {#
#} 44 | {#
#} 45 | {# {{ form_row(form.defaultTaxZone) }}#} 46 | {# {{ form_row(form.taxCalculationStrategy) }}#} 47 | {#
#} 48 |
49 |
50 | {#

{{ form_label(form.shopBillingData) }}

#} 51 | {#
#} 52 | {#
#} 53 | {# {{ form_row(form.shopBillingData.company) }}#} 54 | {# {{ form_row(form.shopBillingData.taxId) }}#} 55 | {#
#} 56 | {#
#} 57 | {# {{ form_row(form.shopBillingData.countryCode) }}#} 58 | {# {{ form_row(form.shopBillingData.street) }}#} 59 | {#
#} 60 | {#
#} 61 | {# {{ form_row(form.shopBillingData.city) }}#} 62 | {# {{ form_row(form.shopBillingData.postcode) }}#} 63 | {#
#} 64 | {#
#} 65 | {# #} 66 |

{{ 'sylius.ui.look_and_feel'|trans }}

67 |
68 | {{ form_row(form.themeName) }} 69 |
70 |
71 | {{ form_row(form.locales) }} 72 | {{ form_row(form.defaultLocale) }} 73 |
74 | {#
#} 75 | {# {{ form_row(form.menuTaxon) }}#} 76 | {#
#} 77 | 78 |
79 | {# {{ form_row(form.skippingShippingStepAllowed) }}#} 80 | {# {{ form_row(form.skippingPaymentStepAllowed) }}#} 81 | {{ form_row(form.accountVerificationRequired) }} 82 |
83 | {#
#} 84 | {# {{ form_row(form.channelPriceHistoryConfig.lowestPriceForDiscountedProductsVisible) }}#} 85 | {# {{ form_row(form.channelPriceHistoryConfig.lowestPriceForDiscountedProductsCheckingPeriod) }}#} 86 | {# {{ form_row(form.channelPriceHistoryConfig.taxonsExcludedFromShowingLowestPrice, {'remote_url': path('sylius_admin_ajax_taxon_by_name_phrase'), 'load_edit_url': path('sylius_admin_ajax_taxon_by_code')}) }}#} 87 | {#
#} 88 |
89 |
90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Banner of Sylius No Commerce plugin](docs/images/banner.jpg)](https://monsieurbiz.com/agence-web-experte-sylius) 2 | 3 |

No Commerce for Sylius

4 | 5 | [![No Commerce Plugin license](https://img.shields.io/github/license/monsieurbiz/SyliusNoCommercePlugin?public)](https://github.com/monsieurbiz/SyliusNoCommercePlugin/blob/master/LICENSE.txt) 6 | [![Tests Status](https://img.shields.io/github/actions/workflow/status/monsieurbiz/SyliusNoCommercePlugin/tests.yaml?branch=master&logo=github)](https://github.com/monsieurbiz/SyliusNoCommercePlugin/actions?query=workflow%3ATests) 7 | [![Recipe Status](https://img.shields.io/github/actions/workflow/status/monsieurbiz/SyliusNoCommercePlugin/recipe.yaml?branch=master&label=recipes&logo=github)](https://github.com/monsieurbiz/SyliusNoCommercePlugin/actions?query=workflow%3ASecurity) 8 | [![Security Status](https://img.shields.io/github/actions/workflow/status/monsieurbiz/SyliusNoCommercePlugin/security.yaml?branch=master&label=security&logo=github)](https://github.com/monsieurbiz/SyliusNoCommercePlugin/actions?query=workflow%3ASecurity) 9 | 10 | This plugin disables the e-commerce parts of Sylius. 11 | Basically it disables the routes and updates the admin and frontend templates. 12 | 13 | 14 | ## Compatibility 15 | 16 | | Sylius Version | PHP Version | 17 | |----------------|-----------------| 18 | | 1.12 | 8.1 - 8.2 - 8.3 | 19 | | 1.13 | 8.1 - 8.2 - 8.3 | 20 | | 1.14 | 8.1 - 8.2 - 8.3 | 21 | 22 | ## Installation 23 | 24 | If you want to use our recipes, you can configure your composer.json by running: 25 | 26 | ```bash 27 | composer config --no-plugins --json extra.symfony.endpoint '["https://api.github.com/repos/monsieurbiz/symfony-recipes/contents/index.json?ref=flex/master","flex://defaults"]' 28 | ``` 29 | 30 | ```bash 31 | composer require monsieurbiz/sylius-no-commerce-plugin 32 | ``` 33 | 34 |
For the installation without flex, follow these additional steps 35 |

36 | 37 | Change your `config/bundles.php` file to add this line for the plugin declaration: 38 | ```php 39 | ['all' => true], 44 | ]; 45 | ``` 46 | 47 | Then create the config file in `config/packages/monsieurbiz_sylius_nocommerce_plugin.yaml`: 48 | 49 | ```yaml 50 | imports: 51 | - { resource: "@MonsieurBizSyliusNoCommercePlugin/Resources/config/config.yaml" } 52 | ``` 53 | 54 |

55 |
56 | 57 | Add some annotations to your `src/Entity/Channel/Channel.php` entity to prevent error during Channel saving: 58 | 59 | ```diff 60 | /** 61 | * @ORM\Entity 62 | * @ORM\Table(name="sylius_channel") 63 | + * @ORM\AssociationOverrides({ 64 | + * @ORM\AssociationOverride(name="baseCurrency", 65 | + * joinColumns=@ORM\JoinColumn( 66 | + * name="base_currency_id", referencedColumnName="id", nullable=true 67 | + * ) 68 | + * ) 69 | + * }) 70 | */ 71 | #[ORM\Entity] 72 | #[ORM\Table(name: 'sylius_channel')] 73 | + #[ORM\AssociationOverrides([ 74 | + new ORM\AssociationOverride( 75 | + name: 'baseCurrency', 76 | + joinColumns: new ORM\JoinColumn(name: 'base_currency_id', referencedColumnName: 'id', nullable: true) 77 | + )] 78 | + )] 79 | class Channel extends BaseChannel 80 | ``` 81 | 82 | Use a different trait for your `src/Kernel.php`: 83 | 84 | ```diff 85 | - use MicroKernelTrait; 86 | + use SyliusNoCommerceKernelTrait; 87 | ``` 88 | 89 | (don't forget the `use MonsieurBiz\SyliusNoCommercePlugin\Kernel\SyliusNoCommerceKernelTrait;` statement or course). 90 | 91 | Copy the templates we override: 92 | 93 | ```bash 94 | cp -Rv vendor/monsieurbiz/sylius-no-commerce-plugin/src/Resources/templates/* templates/ 95 | ``` 96 | 97 | Create the new migrations, and run them: 98 | 99 | ``` 100 | ./bin/console doctrine:migrations:diff 101 | ./bin/console doctrine:migrations:migrate 102 | ``` 103 | 104 | ## Re-enable features 105 | 106 | In the config file `config/packages/monsieurbiz_sylius_nocommerce_plugin.yaml`, add this lines: 107 | 108 | ```yaml 109 | # ... 110 | monsieurbiz_sylius_nocommerce: 111 | config: 112 | allow_countries: false 113 | allow_customers: false 114 | allow_zones: false 115 | ``` 116 | 117 | You can allow different sections by changing the parameters to `true`. 118 | 119 | ## Ignore routes 120 | 121 | By default, the disable firewall listener will ignore the following routes for the developer toolbar. 122 | 123 | You can ignore additional routes, such as the preview route for error pages, by adding them to the `config/packages/monsieurbiz_sylius_nocommerce_plugin.yaml` file: 124 | 125 | ```yaml 126 | parameters: 127 | monsieurbiz_sylius_nocommerce.disable_firewall.ignored_routes: 128 | - "_preview_error" 129 | ``` 130 | 131 | ## Contributing 132 | 133 | You can open an issue or a Pull Request if you want! 😘 134 | Thank you! 135 | -------------------------------------------------------------------------------- /src/Registry/TemplateBlockRegistryDecorator.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace MonsieurBiz\SyliusNoCommercePlugin\Registry; 15 | 16 | use Laminas\Stdlib\SplPriorityQueue; 17 | use MonsieurBiz\SyliusNoCommercePlugin\Provider\FeaturesProviderInterface; 18 | use Sylius\Bundle\UiBundle\Registry\TemplateBlock; 19 | use Sylius\Bundle\UiBundle\Registry\TemplateBlockRegistryInterface; 20 | 21 | final class TemplateBlockRegistryDecorator implements TemplateBlockRegistryInterface 22 | { 23 | private TemplateBlockRegistryInterface $templateBlockRegistry; 24 | 25 | private FeaturesProviderInterface $featuresProvider; 26 | 27 | /** @var array|array[] */ 28 | private array $disableEvents = [ 29 | 'sylius.admin.dashboard.content' => [ 30 | 'before_header_legacy', 31 | 'after_header_legacy', 32 | 'statistics', 33 | 'after_statistics_legacy', 34 | 'menu', 35 | 'after_menu_legacy', 36 | 'latest', 37 | 'after_content_legacy', 38 | ], 39 | 'sylius.shop.layout.header.grid' => [ 40 | 'cart', 41 | ], 42 | 'sylius.shop.layout.header' => [ 43 | 'menu', 44 | ], 45 | 'sylius.shop.homepage' => [ 46 | 'latest_products', 47 | 'latest_products_carousel', 48 | 'products_grid', 49 | ], 50 | 'sylius.admin.customer.show.content' => [ 51 | 'statistics', 52 | ], 53 | 'sylius.admin.customer.show.address' => [ 54 | 'header', 55 | 'content', 56 | ], 57 | 'sylius.admin.layout.topbar_left' => [ 58 | 'search', 59 | ], 60 | ]; 61 | 62 | public function __construct( 63 | TemplateBlockRegistryInterface $templateBlockRegistry, 64 | FeaturesProviderInterface $featuresProvider 65 | ) { 66 | $this->templateBlockRegistry = $templateBlockRegistry; 67 | $this->featuresProvider = $featuresProvider; 68 | } 69 | 70 | public function findEnabledForEvents(array $eventNames): array 71 | { 72 | // No need to sort blocks again if there's only one event because we have them sorted already 73 | if (1 === \count($eventNames)) { 74 | $eventName = reset($eventNames); 75 | 76 | $arrayBlocks = $this->all()[$eventName] ?? []; 77 | $arrayBlocks = $this->removeNoCommerceBlocks($eventName, $arrayBlocks); 78 | 79 | return array_values(array_filter( 80 | $arrayBlocks, 81 | static fn (TemplateBlock $templateBlock): bool => $templateBlock->isEnabled(), 82 | )); 83 | } 84 | 85 | $enabledFinalizedTemplateBlocks = array_filter( 86 | $this->findFinalizedForEvents($eventNames), 87 | static fn (TemplateBlock $templateBlock): bool => $templateBlock->isEnabled(), 88 | ); 89 | 90 | $templateBlocksPriorityQueue = new SplPriorityQueue(); 91 | foreach ($enabledFinalizedTemplateBlocks as $templateBlock) { 92 | $templateBlocksPriorityQueue->insert($templateBlock, $templateBlock->getPriority()); 93 | } 94 | 95 | return $templateBlocksPriorityQueue->toArray(); 96 | } 97 | 98 | public function all(): array 99 | { 100 | return $this->templateBlockRegistry->all(); 101 | } 102 | 103 | private function findFinalizedForEvents(array $eventNames): array 104 | { 105 | /** 106 | * @var TemplateBlock[] $finalizedTemplateBlocks 107 | * 108 | * @psalm-var array $finalizedTemplateBlocks 109 | */ 110 | $finalizedTemplateBlocks = []; 111 | $reversedEventNames = array_reverse($eventNames); 112 | 113 | foreach ($reversedEventNames as $eventName) { 114 | $templateBlocks = $this->all()[$eventName] ?? []; 115 | $templateBlocks = $this->removeNoCommerceBlocks($eventName, $templateBlocks); 116 | foreach ($templateBlocks as $blockName => $templateBlock) { 117 | if (\array_key_exists($blockName, $finalizedTemplateBlocks)) { 118 | $templateBlock = $finalizedTemplateBlocks[$blockName]->overwriteWith($templateBlock); 119 | } 120 | 121 | $finalizedTemplateBlocks[$blockName] = $templateBlock; 122 | } 123 | } 124 | 125 | return $finalizedTemplateBlocks; 126 | } 127 | 128 | /** 129 | * @return TemplateBlock[] 130 | */ 131 | private function removeNoCommerceBlocks(string $eventName, array $arrayBlocks): array 132 | { 133 | // Remove block from no Commerce 134 | if ($this->featuresProvider->isNoCommerceEnabledForChannel()) { 135 | if (isset($this->disableEvents[$eventName])) { 136 | foreach ($this->disableEvents[$eventName] as $block) { 137 | unset($arrayBlocks[$block]); 138 | } 139 | } 140 | } 141 | 142 | return $arrayBlocks; 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/Collector/NoCommerceSyliusCollector.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace MonsieurBiz\SyliusNoCommercePlugin\Collector; 15 | 16 | use MonsieurBiz\SyliusNoCommercePlugin\Context\NoCurrencyContext; 17 | use MonsieurBiz\SyliusNoCommercePlugin\Provider\FeaturesProviderInterface; 18 | use Sylius\Bundle\CoreBundle\Application\Kernel; 19 | use Sylius\Component\Channel\Context\ChannelNotFoundException; 20 | use Sylius\Component\Core\Context\ShopperContextInterface; 21 | use Sylius\Component\Core\Model\ChannelInterface; 22 | use Sylius\Component\Currency\Context\CurrencyNotFoundException; 23 | use Sylius\Component\Locale\Context\LocaleNotFoundException; 24 | use Symfony\Component\HttpFoundation\Request; 25 | use Symfony\Component\HttpFoundation\Response; 26 | use Symfony\Component\HttpKernel\DataCollector\DataCollector; 27 | use Throwable; 28 | 29 | final class NoCommerceSyliusCollector extends DataCollector 30 | { 31 | private ShopperContextInterface $shopperContext; 32 | 33 | private FeaturesProviderInterface $featuresProvider; 34 | 35 | /** 36 | * @SuppressWarnings(PHPMD.CyclomaticComplexity) 37 | */ 38 | public function __construct( 39 | ShopperContextInterface $shopperContext, 40 | array $bundles, 41 | string $defaultLocaleCode, 42 | FeaturesProviderInterface $featuresProvider 43 | ) { 44 | $this->shopperContext = $shopperContext; 45 | $this->featuresProvider = $featuresProvider; 46 | $this->data = [ 47 | 'version' => Kernel::VERSION . ($this->featuresProvider->isNoCommerceEnabledForChannel() ? ' NoCommerce' : ''), 48 | 'base_currency_code' => null, 49 | 'currency_code' => null, 50 | 'default_locale_code' => $defaultLocaleCode, 51 | 'locale_code' => null, 52 | 'extensions' => [], 53 | ]; 54 | 55 | // If the NoCommerce Plugin is enabled we change some data 56 | if ($this->featuresProvider->isNoCommerceEnabledForChannel()) { 57 | $this->data['base_currency_code'] = NoCurrencyContext::NONE_CURRENCY_CODE; 58 | $this->data['currency_code'] = NoCurrencyContext::NONE_CURRENCY_CODE; 59 | $this->data['extensions']['MonsieurBizNoCommercePlugin'] = ['name' => 'NoCommerce', 'enabled' => true]; 60 | } 61 | 62 | $this->data['extensions'] += [ 63 | 'SyliusAdminApiBundle' => ['name' => 'API', 'enabled' => false], 64 | 'SyliusAdminBundle' => ['name' => 'Admin', 'enabled' => false], 65 | 'SyliusShopBundle' => ['name' => 'Shop', 'enabled' => false], 66 | ]; 67 | 68 | foreach (array_keys($this->data['extensions']) as $bundleName) { 69 | if (isset($bundles[$bundleName])) { 70 | $this->data['extensions'][$bundleName]['enabled'] = true; 71 | } 72 | } 73 | } 74 | 75 | public function getVersion(): string 76 | { 77 | return $this->data['version']; 78 | } 79 | 80 | public function getExtensions(): array 81 | { 82 | return $this->data['extensions']; 83 | } 84 | 85 | public function getCurrencyCode(): ?string 86 | { 87 | return $this->data['currency_code']; 88 | } 89 | 90 | public function getLocaleCode(): ?string 91 | { 92 | return $this->data['locale_code']; 93 | } 94 | 95 | public function getDefaultCurrencyCode(): ?string 96 | { 97 | return $this->data['base_currency_code']; 98 | } 99 | 100 | public function getDefaultLocaleCode(): ?string 101 | { 102 | return $this->data['default_locale_code']; 103 | } 104 | 105 | /** 106 | * @SuppressWarnings(PHPMD.UnusedFormalParameter) 107 | * @SuppressWarnings(PHPMD.EmptyCatchBlock) 108 | * @SuppressWarnings(PHPMD.CyclomaticComplexity) 109 | */ 110 | public function collect(Request $request, Response $response, ?Throwable $exception = null): void 111 | { 112 | try { 113 | /** @var ChannelInterface $channel */ 114 | $channel = $this->shopperContext->getChannel(); 115 | 116 | if (!$this->featuresProvider->isNoCommerceEnabledForChannel()) { 117 | $baseCurrency = $channel->getBaseCurrency(); 118 | $this->data['base_currency_code'] = $baseCurrency ? $baseCurrency->getCode() : NoCurrencyContext::NONE_CURRENCY_CODE; 119 | $this->data['currency_code'] = $this->shopperContext->getCurrencyCode(); 120 | } 121 | } catch (ChannelNotFoundException|CurrencyNotFoundException $e) { 122 | } 123 | 124 | try { 125 | $this->data['locale_code'] = $this->shopperContext->getLocaleCode(); 126 | } catch (LocaleNotFoundException $e) { 127 | } 128 | } 129 | 130 | public function reset(): void 131 | { 132 | $this->data['base_currency_code'] = NoCurrencyContext::NONE_CURRENCY_CODE; 133 | $this->data['currency_code'] = NoCurrencyContext::NONE_CURRENCY_CODE; 134 | $this->data['locale_code'] = null; 135 | } 136 | 137 | public function getName(): string 138 | { 139 | return 'sylius_core'; 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/Model/ConfigInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace MonsieurBiz\SyliusNoCommercePlugin\Model; 15 | 16 | interface ConfigInterface 17 | { 18 | public const ADMIN_ROUTE_GROUP_MATCHER = '_admin'; 19 | 20 | public const ROUTES_BY_GROUP = [ 21 | /** 22 | * Customers & Account & Users. 23 | */ 24 | 'customer_admin' => [ 25 | 'sylius_admin_partial_customer', 26 | 'sylius_admin_customer', 27 | ], 28 | 'customer_shop' => [ 29 | 'sylius_shop_log', 30 | 'sylius_shop_register', 31 | 'sylius_shop_request_password_reset_token', 32 | 'sylius_shop_password_reset', 33 | 'sylius_shop_user_request_verification_token', 34 | 'sylius_shop_user_verification', 35 | 'sylius_shop_account', 36 | 'sylius_shop_ajax_user_check_action', 37 | ], 38 | 'customer_api' => [ 39 | 'api_customer', 40 | 'api_register_shop_users_post_collection', 41 | 'sylius_api_shop_authentication_token', 42 | ], 43 | /** 44 | * Catalog. 45 | */ 46 | 'catalog_admin' => [ 47 | 'sylius_admin_product', 48 | 'sylius_admin_ajax_product', 49 | 'sylius_admin_partial_product', 50 | 'sylius_admin_ajax_generate_product_slug', 51 | 'sylius_admin_partial_taxon', 52 | 'sylius_admin_ajax_taxon', 53 | 'sylius_admin_taxon', 54 | 'sylius_admin_ajax_generate_taxon_slug', 55 | 'sylius_admin_get_attribute_types', 56 | 'sylius_admin_get_product_attributes', 57 | 'sylius_admin_render_attribute_forms', 58 | 'sylius_admin_inventory', 59 | 'sylius_admin_tax_', 60 | 'sylius_admin_api_tax_', 61 | ], 62 | 'catalog_shop' => [ 63 | 'sylius_shop_partial_product', 64 | 'sylius_shop_product', 65 | 'sylius_shop_partial_taxon', 66 | 'sylius_shop_partial_channel_menu_taxon_index', 67 | ], 68 | 'catalog_api' => [ 69 | 'sylius_admin_api_product', 70 | 'api_product', 71 | 'sylius_admin_api_taxon', 72 | 'api_taxon', 73 | 'api_tax', 74 | ], 75 | /** 76 | * Addresses. 77 | */ 78 | 'address_shop' => [ 79 | 'sylius_shop_account_address', 80 | 'sylius_shop_ajax_render_province_form', 81 | ], 82 | /** 83 | * Orders. 84 | */ 85 | 'order_admin' => [ 86 | 'sylius_admin_order', 87 | 'sylius_admin_partial_order', 88 | 'sylius_admin_customer_order', 89 | 'sylius_admin_partial_address', 90 | 'sylius_admin_partial_promotion', 91 | 'sylius_admin_promotion', 92 | 'sylius_admin_catalog_promotion', 93 | 'sylius_admin_partial_shipment', 94 | 'sylius_admin_ship', 95 | 'sylius_admin_payment', 96 | 'sylius_admin_get_payment', 97 | 'sylius_admin_api_cart', 98 | ], 99 | 'order_shop' => [ 100 | 'sylius_shop_account_order', 101 | 'sylius_shop_order', 102 | 'payum_', 103 | 'sylius_paypal', 104 | 'sylius_shop_ajax_cart', 105 | 'sylius_shop_partial_cart', 106 | 'sylius_shop_cart', 107 | 'sylius_shop_checkout', 108 | 'sylius_shop_register_after_checkout', 109 | ], 110 | 'order_api' => [ 111 | 'sylius_admin_api_adjustment', 112 | 'sylius_admin_api_order', 113 | 'sylius_admin_api_customer_order', 114 | 'api_order', 115 | 'api_adjustment', 116 | 'sylius_admin_api_promotion', 117 | 'api_promo', 118 | 'sylius_admin_api_ship', 119 | 'api_ship', 120 | 'sylius_admin_api_payment', 121 | 'api_pay', 122 | 'api_cart', 123 | 'sylius_admin_api_checkout', 124 | ], 125 | /** 126 | * Currencies. 127 | */ 128 | 'currency_admin' => [ 129 | 'sylius_admin_currency', 130 | 'sylius_admin_api_currency', 131 | ], 132 | 'currency_shop' => [ 133 | 'sylius_shop_switch_currency', 134 | ], 135 | 'currency_api' => [ 136 | 'api_currencies', 137 | ], 138 | /** 139 | * Exchange rates. 140 | */ 141 | 'exchange_admin' => [ 142 | 'sylius_admin_exchange', 143 | 'sylius_admin_api_exchange', 144 | 'api_exchange', 145 | ], 146 | 'exchange_api' => [ 147 | 'api_exchange', 148 | ], 149 | /** 150 | * Zones. 151 | */ 152 | 'zone_admin' => [ 153 | 'sylius_admin_zone', 154 | 'sylius_admin_api_zone', 155 | ], 156 | 'zone_api' => [ 157 | 'api_zone', 158 | ], 159 | /** 160 | * Countries. 161 | */ 162 | 'country_admin' => [ 163 | 'sylius_admin_country', 164 | 'sylius_admin_api_country', 165 | ], 166 | 'country_api' => [ 167 | 'api_countries', 168 | ], 169 | /** 170 | * Province. 171 | */ 172 | 'province_admin' => [ 173 | 'sylius_admin_api_province', 174 | 'sylius_admin_ajax_render_province_form', 175 | ], 176 | 'province_api' => [ 177 | 'api_province', 178 | ], 179 | /** 180 | * Dashboard. 181 | */ 182 | 'dashboard' => [ 183 | 'sylius_admin_dashboard_statistics', 184 | ], 185 | /** 186 | * Billing data. 187 | */ 188 | 'billing_data' => [ 189 | 'api_shop_billing', 190 | 'api_channels_shop', 191 | ], 192 | ]; 193 | 194 | public function areCountriesAllowed(): bool; 195 | 196 | public function areCustomersAllowed(): bool; 197 | 198 | public function areZonesAllowed(): bool; 199 | } 200 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .DEFAULT_GOAL := help 2 | SHELL=/bin/bash 3 | APP_DIR=tests/Application 4 | SYLIUS_VERSION=1.14.0 5 | SYMFONY=cd ${APP_DIR} && symfony 6 | COMPOSER=symfony composer 7 | CONSOLE=${SYMFONY} console 8 | export COMPOSE_PROJECT_NAME=no-commerce 9 | export MIGRATIONS_NAMESPACE=MonsieurBiz\\SyliusNoCommercePlugin\\Migrations 10 | export USER_UID=$(shell id -u) 11 | PLUGIN_NAME=sylius-${COMPOSE_PROJECT_NAME}-plugin 12 | COMPOSE=docker compose 13 | YARN=yarn 14 | 15 | ### 16 | ### DEVELOPMENT 17 | ### ¯¯¯¯¯¯¯¯¯¯¯ 18 | 19 | install: application platform sylius ## Install the plugin 20 | .PHONY: install 21 | 22 | up: docker.up server.start ## Up the project (start docker, start symfony server) 23 | stop: server.stop docker.stop ## Stop the project (stop docker, stop symfony server) 24 | down: server.stop docker.down ## Down the project (removes docker containers, stop symfony server) 25 | 26 | reset: ## Stop docker and remove dependencies 27 | ${MAKE} docker.down || true 28 | rm -rf ${APP_DIR}/node_modules ${APP_DIR}/yarn.lock 29 | rm -rf ${APP_DIR} 30 | rm -rf vendor composer.lock 31 | .PHONY: reset 32 | 33 | dependencies: composer.lock node_modules ## Setup the dependencies 34 | .PHONY: dependencies 35 | 36 | .php-version: .php-version.dist 37 | rm -f .php-version 38 | ln -s .php-version.dist .php-version 39 | 40 | php.ini: php.ini.dist 41 | rm -f php.ini 42 | ln -s php.ini.dist php.ini 43 | 44 | composer.lock: composer.json 45 | ${COMPOSER} install --no-scripts --no-plugins 46 | 47 | yarn.install: ${APP_DIR}/yarn.lock 48 | 49 | ${APP_DIR}/yarn.lock: 50 | ln -sf ${APP_DIR}/node_modules node_modules 51 | cd ${APP_DIR} && ${YARN} install && ${YARN} build 52 | # No CSS and JS on this plugin yet 53 | # ${YARN} install 54 | # ${YARN} encore prod 55 | 56 | node_modules: ${APP_DIR}/node_modules ## Install the Node dependencies using yarn 57 | 58 | ${APP_DIR}/node_modules: yarn.install 59 | 60 | ### 61 | ### TEST APPLICATION 62 | ### ¯¯¯¯¯ 63 | 64 | application: .php-version php.ini ${APP_DIR} setup_application ${APP_DIR}/docker-compose.yaml 65 | 66 | ${APP_DIR}: 67 | (${COMPOSER} create-project --no-interaction --prefer-dist --no-scripts --no-progress --no-install sylius/sylius-standard="~${SYLIUS_VERSION}" ${APP_DIR}) 68 | 69 | setup_application: 70 | rm -f ${APP_DIR}/yarn.lock 71 | (cd ${APP_DIR} && ${COMPOSER} config repositories.plugin '{"type": "path", "url": "../../"}') 72 | (cd ${APP_DIR} && ${COMPOSER} config extra.symfony.allow-contrib true) 73 | (cd ${APP_DIR} && ${COMPOSER} config minimum-stability dev) 74 | (cd ${APP_DIR} && ${COMPOSER} config --no-plugins allow-plugins true) 75 | (cd ${APP_DIR} && ${COMPOSER} config --no-plugins --json extra.symfony.endpoint '["https://api.github.com/repos/monsieurbiz/symfony-recipes/contents/index.json?ref=flex/master","flex://defaults"]') 76 | (cd ${APP_DIR} && ${COMPOSER} require --no-install --no-scripts --no-progress sylius/sylius="~${SYLIUS_VERSION}") # Make sure to install the required version of sylius because the sylius-standard has a soft constraint 77 | $(MAKE) ${APP_DIR}/.php-version 78 | $(MAKE) ${APP_DIR}/php.ini 79 | (cd ${APP_DIR} && ${COMPOSER} install --no-interaction) 80 | $(MAKE) apply_dist 81 | (cd ${APP_DIR} && ${COMPOSER} require --no-progress --no-interaction monsieurbiz/${PLUGIN_NAME}="*@dev") 82 | rm -rf ${APP_DIR}/var/cache 83 | 84 | 85 | ${APP_DIR}/docker-compose.yaml: 86 | rm -f ${APP_DIR}/docker-compose.yml 87 | rm -f ${APP_DIR}/docker-compose.yaml 88 | rm -f ${APP_DIR}/compose.yml # Remove Sylius file about Docker 89 | rm -f ${APP_DIR}/compose.override.dist.yml # Remove Sylius file about Docker 90 | ln -s ../../docker-compose.yaml.dist ${APP_DIR}/docker-compose.yaml 91 | .PHONY: ${APP_DIR}/docker-compose.yaml 92 | 93 | ${APP_DIR}/.php-version: .php-version 94 | (cd ${APP_DIR} && ln -sf ../../.php-version) 95 | 96 | ${APP_DIR}/php.ini: php.ini 97 | (cd ${APP_DIR} && ln -sf ../../php.ini) 98 | 99 | apply_dist: 100 | # Don't use symlink for Kernel.php file otherwise the resource paths are incorrect 101 | ROOT_DIR=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))); \ 102 | for i in `cd dist && find . -type f`; do \ 103 | FILE_PATH=`echo $$i | sed 's|./||'`; \ 104 | FOLDER_PATH=`dirname $$FILE_PATH`; \ 105 | echo $$FILE_PATH; \ 106 | (cd ${APP_DIR} && rm -f $$FILE_PATH); \ 107 | (cd ${APP_DIR} && mkdir -p $$FOLDER_PATH); \ 108 | if [[ $$FILE_PATH != 'src/Kernel.php' ]]; then \ 109 | echo "Link $$FILE_PATH"; \ 110 | (cd ${APP_DIR} && ln -s $$ROOT_DIR/dist/$$FILE_PATH $$FILE_PATH); \ 111 | else \ 112 | echo "Copy $$FILE_PATH"; \ 113 | (cd ${APP_DIR} && cp $$ROOT_DIR/dist/$$FILE_PATH $$FILE_PATH); \ 114 | fi \ 115 | done 116 | 117 | ### 118 | ### TESTS 119 | ### ¯¯¯¯¯ 120 | 121 | test.all: test.composer test.phpstan test.phpmd test.phpunit test.phpspec test.phpcs test.yaml test.schema test.twig test.container ## Run all tests in once 122 | 123 | test.composer: ## Validate composer.json 124 | ${COMPOSER} validate --strict 125 | 126 | test.phpstan: ## Run PHPStan 127 | ${COMPOSER} phpstan 128 | 129 | test.phpmd: ## Run PHPMD 130 | ${COMPOSER} phpmd 131 | 132 | test.phpunit: ## Run PHPUnit 133 | ${COMPOSER} phpunit 134 | 135 | test.phpspec: ## Run PHPSpec 136 | ${COMPOSER} phpspec 137 | 138 | test.phpcs: ## Run PHP CS Fixer in dry-run 139 | ${COMPOSER} run -- phpcs --dry-run -v 140 | 141 | test.phpcs.fix: ## Run PHP CS Fixer and fix issues if possible 142 | ${COMPOSER} run -- phpcs -v 143 | 144 | test.container: ## Lint the symfony container 145 | ${CONSOLE} lint:container 146 | 147 | test.yaml: ## Lint the symfony Yaml files 148 | ${CONSOLE} lint:yaml ../../src/Resources/config --parse-tags 149 | 150 | test.schema: ## Validate MySQL Schema 151 | ${CONSOLE} doctrine:schema:validate 152 | 153 | test.twig: ## Validate Twig templates 154 | ${CONSOLE} lint:twig --no-debug templates/ ../../src/Resources/views/ 155 | 156 | ### 157 | ### SYLIUS 158 | ### ¯¯¯¯¯¯ 159 | 160 | sylius: dependencies sylius.database sylius.fixtures sylius.assets messenger.setup ## Install Sylius 161 | .PHONY: sylius 162 | 163 | sylius.database: ## Setup the database 164 | ${CONSOLE} doctrine:database:drop --if-exists --force 165 | ${CONSOLE} doctrine:database:create --if-not-exists 166 | ${CONSOLE} doctrine:migration:migrate -n 167 | 168 | sylius.fixtures: ## Run the fixtures 169 | ${CONSOLE} sylius:fixtures:load -n default 170 | 171 | sylius.assets: ## Install all assets with symlinks 172 | ${CONSOLE} assets:install --symlink 173 | ${CONSOLE} sylius:install:assets 174 | ${CONSOLE} sylius:theme:assets:install --symlink 175 | 176 | messenger.setup: ## Setup Messenger transports 177 | ${CONSOLE} messenger:setup-transports 178 | 179 | doctrine.diff: ## Doctrine diff 180 | ${CONSOLE} doctrine:migration:diff --namespace="${MIGRATIONS_NAMESPACE}" 181 | 182 | ### 183 | ### PLATFORM 184 | ### ¯¯¯¯¯¯¯¯ 185 | 186 | platform: .php-version up ## Setup the platform tools 187 | .PHONY: platform 188 | 189 | docker.pull: ## Pull the docker images 190 | cd ${APP_DIR} && ${COMPOSE} pull 191 | 192 | docker.up: ## Start the docker containers 193 | cd ${APP_DIR} && ${COMPOSE} up -d 194 | .PHONY: docker.up 195 | 196 | docker.stop: ## Stop the docker containers 197 | cd ${APP_DIR} && ${COMPOSE} stop 198 | .PHONY: docker.stop 199 | 200 | docker.down: ## Stop and remove the docker containers 201 | cd ${APP_DIR} && ${COMPOSE} down 202 | .PHONY: docker.down 203 | 204 | docker.logs: ## Logs the docker containers 205 | cd ${APP_DIR} && ${COMPOSE} logs -f 206 | .PHONY: docker.logs 207 | 208 | docker.dc: ARGS=ps 209 | docker.dc: ## Run docker-compose command. Use ARGS="" to pass parameters to docker-compose. 210 | cd ${APP_DIR} && ${COMPOSE} ${ARGS} 211 | .PHONY: docker.dc 212 | 213 | server.start: ## Run the local webserver using Symfony 214 | ${SYMFONY} local:server:start -d 215 | 216 | server.stop: ## Stop the local webserver 217 | ${SYMFONY} local:server:stop 218 | 219 | ### 220 | ### HELP 221 | ### ¯¯¯¯ 222 | 223 | help: SHELL=/bin/bash 224 | help: ## Dislay this help 225 | @IFS=$$'\n'; for line in `grep -h -E '^[a-zA-Z_#-]+:?.*?##.*$$' $(MAKEFILE_LIST)`; do if [ "$${line:0:2}" = "##" ]; then \ 226 | echo $$line | awk 'BEGIN {FS = "## "}; {printf "\033[33m %s\033[0m\n", $$2}'; else \ 227 | echo $$line | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m%s\n", $$1, $$2}'; fi; \ 228 | done; unset IFS; 229 | .PHONY: help 230 | -------------------------------------------------------------------------------- /.php-cs-fixer.dist.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.txt 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | $header = <<<'HEADER' 15 | This file is part of Monsieur Biz' No Commerce plugin for Sylius. 16 | 17 | (c) Monsieur Biz 18 | 19 | For the full copyright and license information, please view the LICENSE.txt 20 | file that was distributed with this source code. 21 | HEADER; 22 | 23 | $finder = PhpCsFixer\Finder::create() 24 | ->in(__DIR__) 25 | ->exclude( 26 | [ 27 | 'tests/Application', 28 | ] 29 | ) 30 | ; 31 | 32 | $config = new PhpCsFixer\Config(); 33 | $config 34 | ->setRiskyAllowed(true) 35 | ->setRules([ 36 | '@DoctrineAnnotation' => true, 37 | '@PHP71Migration' => true, 38 | '@PHP71Migration:risky' => true, 39 | '@PHPUnit60Migration:risky' => true, 40 | '@Symfony' => true, 41 | '@Symfony:risky' => true, 42 | 'align_multiline_comment' => [ 43 | 'comment_type' => 'phpdocs_like', 44 | ], 45 | 'array_indentation' => true, 46 | 'array_syntax' => [ 47 | 'syntax' => 'short', 48 | ], 49 | 'binary_operator_spaces' => true, 50 | 'blank_line_after_opening_tag' => true, 51 | 'blank_line_after_namespace' => true, 52 | 'blank_lines_before_namespace' => true, 53 | 'blank_line_before_statement' => true, 54 | 'cast_spaces' => true, 55 | 'class_attributes_separation' => true, 56 | 'class_definition' => [ 57 | 'single_item_single_line' => true, 58 | 'multi_line_extends_each_single_line' => true, 59 | ], 60 | 'combine_consecutive_issets' => true, 61 | 'combine_consecutive_unsets' => true, 62 | 'comment_to_phpdoc' => true, 63 | 'compact_nullable_type_declaration' => true, 64 | 'concat_space' => [ 65 | 'spacing' => 'one', 66 | ], 67 | 'constant_case' => [ 68 | 'case' => 'lower', 69 | ], 70 | 'declare_equal_normalize' => true, 71 | 'dir_constant' => true, 72 | 'declare_strict_types' => true, 73 | 'doctrine_annotation_array_assignment' => [ 74 | 'operator' => '=', 75 | ], 76 | 'doctrine_annotation_spaces' => [ 77 | 'after_array_assignments_equals' => false, 78 | 'before_array_assignments_equals' => false, 79 | ], 80 | 'elseif' => true, 81 | 'encoding' => true, 82 | 'ereg_to_preg' => true, 83 | 'error_suppression' => true, 84 | 'explicit_indirect_variable' => true, 85 | 'full_opening_tag' => true, 86 | 'fully_qualified_strict_types' => true, 87 | 'function_declaration' => true, 88 | 'function_to_constant' => true, 89 | 'general_phpdoc_tag_rename' => true, 90 | 'global_namespace_import' => [ 91 | 'import_classes' => true, 92 | 'import_constants' => false, 93 | 'import_functions' => false, 94 | ], 95 | 'header_comment' => [ 96 | 'header' => $header, 97 | 'location' => 'after_open', 98 | ], 99 | 'include' => true, 100 | 'increment_style' => [ 101 | 'style' => 'pre', 102 | ], 103 | 'indentation_type' => true, 104 | 'is_null' => true, 105 | 'line_ending' => true, 106 | 'list_syntax' => [ 107 | 'syntax' => 'short', 108 | ], 109 | 'logical_operators' => true, 110 | 'lowercase_cast' => true, 111 | 'lowercase_keywords' => true, 112 | 'lowercase_static_reference' => true, 113 | 'magic_constant_casing' => true, 114 | 'method_argument_space' => true, 115 | 'modernize_strpos' => false, 116 | 'modernize_types_casting' => true, 117 | 'multiline_comment_opening_closing' => true, 118 | 'multiline_whitespace_before_semicolons' => [ 119 | 'strategy' => 'new_line_for_chained_calls', 120 | ], 121 | 'native_constant_invocation' => true, 122 | 'native_function_casing' => true, 123 | 'new_with_parentheses' => true, 124 | 'no_alias_functions' => true, 125 | 'no_alternative_syntax' => true, 126 | 'no_blank_lines_after_class_opening' => true, 127 | 'no_blank_lines_after_phpdoc' => true, 128 | 'no_break_comment' => true, 129 | 'no_closing_tag' => true, 130 | 'no_empty_comment' => true, 131 | 'no_empty_phpdoc' => true, 132 | 'no_empty_statement' => true, 133 | 'no_extra_blank_lines' => [ 134 | 'tokens' => [ 135 | 'break', 136 | 'case', 137 | 'continue', 138 | 'curly_brace_block', 139 | 'default', 140 | 'extra', 141 | 'parenthesis_brace_block', 142 | 'return', 143 | 'square_brace_block', 144 | 'switch', 145 | 'throw', 146 | 'use', 147 | ], 148 | ], 149 | 'no_homoglyph_names' => true, 150 | 'no_leading_import_slash' => true, 151 | 'no_leading_namespace_whitespace' => true, 152 | 'no_mixed_echo_print' => [ 153 | 'use' => 'echo', 154 | ], 155 | 'no_multiline_whitespace_around_double_arrow' => true, 156 | 'no_null_property_initialization' => true, 157 | 'no_php4_constructor' => true, 158 | 'no_singleline_whitespace_before_semicolons' => true, 159 | 'no_short_bool_cast' => true, 160 | 'no_spaces_after_function_name' => true, 161 | 'no_spaces_around_offset' => true, 162 | 'spaces_inside_parentheses' => true, 163 | 'no_superfluous_elseif' => true, 164 | 'no_superfluous_phpdoc_tags' => [ 165 | 'allow_mixed' => true, 166 | ], 167 | 'no_unset_cast' => true, 168 | 'no_unneeded_control_parentheses' => true, 169 | 'no_unneeded_braces' => true, 170 | 'no_unneeded_final_method' => true, 171 | 'no_unset_on_property' => true, 172 | 'no_unused_imports' => true, 173 | 'no_useless_else' => true, 174 | 'no_useless_return' => true, 175 | 'no_trailing_comma_in_singleline' => true, 176 | 'no_trailing_whitespace' => true, 177 | 'no_trailing_whitespace_in_comment' => true, 178 | 'no_whitespace_before_comma_in_array' => true, 179 | 'no_whitespace_in_blank_line' => true, 180 | 'non_printable_character' => true, 181 | 'normalize_index_brace' => true, 182 | 'nullable_type_declaration_for_default_null_value' => false, 183 | 'object_operator_without_whitespace' => true, 184 | 'ordered_imports' => [ 185 | 'imports_order' => [ 186 | 'class', 187 | 'function', 188 | 'const', 189 | ], 190 | 'sort_algorithm' => 'alpha', 191 | ], 192 | 'php_unit_dedicate_assert' => true, 193 | 'php_unit_fqcn_annotation' => true, 194 | 'php_unit_method_casing' => [ 195 | 'case' => 'camel_case', 196 | ], 197 | 'php_unit_set_up_tear_down_visibility' => true, 198 | 'php_unit_test_annotation' => [ 199 | 'style' => 'prefix', 200 | ], 201 | 'phpdoc_align' => [ 202 | 'align' => 'left', 203 | ], 204 | 'phpdoc_add_missing_param_annotation' => [ 205 | 'only_untyped' => true, 206 | ], 207 | 'phpdoc_indent' => true, 208 | 'phpdoc_inline_tag_normalizer' => true, 209 | 'phpdoc_no_access' => true, 210 | 'phpdoc_no_alias_tag' => true, 211 | 'phpdoc_no_empty_return' => true, 212 | 'phpdoc_no_package' => true, 213 | 'phpdoc_no_useless_inheritdoc' => true, 214 | 'phpdoc_order' => true, 215 | 'phpdoc_return_self_reference' => true, 216 | 'phpdoc_scalar' => true, 217 | 'phpdoc_separation' => ['groups' => [ 218 | ['ORM\\*'], ['Assert\\*'], 219 | ]], 220 | 'phpdoc_single_line_var_spacing' => true, 221 | 'phpdoc_tag_type' => true, 222 | 'phpdoc_to_comment' => false, 223 | 'phpdoc_trim' => true, 224 | 'phpdoc_trim_consecutive_blank_line_separation' => true, 225 | 'phpdoc_types' => true, 226 | 'phpdoc_types_order' => [ 227 | 'null_adjustment' => 'always_last', 228 | 'sort_algorithm' => 'none', 229 | ], 230 | 'phpdoc_var_annotation_correct_order' => true, 231 | 'phpdoc_var_without_name' => true, 232 | 'pow_to_exponentiation' => true, 233 | 'protected_to_private' => true, 234 | 'return_assignment' => true, 235 | 'return_type_declaration' => true, 236 | 'self_accessor' => true, 237 | 'short_scalar_cast' => true, 238 | 'single_blank_line_at_eof' => true, 239 | 'single_class_element_per_statement' => true, 240 | 'single_import_per_statement' => true, 241 | 'single_line_after_imports' => true, 242 | 'single_line_comment_style' => true, 243 | 'single_quote' => true, 244 | 'space_after_semicolon' => true, 245 | 'standardize_not_equals' => true, 246 | 'strict_param' => true, 247 | 'switch_case_semicolon_to_colon' => true, 248 | 'switch_case_space' => true, 249 | 'ternary_operator_spaces' => true, 250 | 'ternary_to_null_coalescing' => true, 251 | 'trailing_comma_in_multiline' => [ 252 | 'elements' => ['arrays'], 253 | ], 254 | 'trim_array_spaces' => true, 255 | 'type_declaration_spaces' => true, 256 | 'unary_operator_spaces' => true, 257 | 'visibility_required' => [ 258 | 'elements' => [ 259 | 'const', 260 | 'property', 261 | 'method', 262 | ], 263 | ], 264 | 'void_return' => true, 265 | 'whitespace_after_comma_in_array' => true, // alerady in symfony set 266 | ]) 267 | ->setFinder($finder) 268 | ; 269 | 270 | return $config; 271 | -------------------------------------------------------------------------------- /symfony.lock: -------------------------------------------------------------------------------- 1 | { 2 | "aeon-php/calendar": { 3 | "version": "0.16.1" 4 | }, 5 | "alcohol/iso4217": { 6 | "version": "3.1.5" 7 | }, 8 | "amphp/amp": { 9 | "version": "v2.5.0" 10 | }, 11 | "amphp/byte-stream": { 12 | "version": "v1.8.0" 13 | }, 14 | "api-platform/core": { 15 | "version": "2.5", 16 | "recipe": { 17 | "repo": "github.com/symfony/recipes", 18 | "branch": "master", 19 | "version": "2.5", 20 | "ref": "a93061567140e386f107be75340ac2aee3f86cbf" 21 | }, 22 | "files": [ 23 | "config/packages/api_platform.yaml", 24 | "config/routes/api_platform.yaml", 25 | "src/Entity/.gitignore" 26 | ] 27 | }, 28 | "babdev/pagerfanta-bundle": { 29 | "version": "v2.11.0" 30 | }, 31 | "behat/behat": { 32 | "version": "v3.7.0" 33 | }, 34 | "behat/gherkin": { 35 | "version": "v4.6.2" 36 | }, 37 | "behat/mink-selenium2-driver": { 38 | "version": "v1.4.0" 39 | }, 40 | "behat/transliterator": { 41 | "version": "v1.3.0" 42 | }, 43 | "clue/stream-filter": { 44 | "version": "v1.4.1" 45 | }, 46 | "coduo/php-matcher": { 47 | "version": "4.0.0" 48 | }, 49 | "coduo/php-to-string": { 50 | "version": "3.0.0" 51 | }, 52 | "composer/semver": { 53 | "version": "1.7.0" 54 | }, 55 | "composer/xdebug-handler": { 56 | "version": "1.4.3" 57 | }, 58 | "dealerdirect/phpcodesniffer-composer-installer": { 59 | "version": "v0.7.0" 60 | }, 61 | "dmore/behat-chrome-extension": { 62 | "version": "1.3.0" 63 | }, 64 | "dmore/chrome-mink-driver": { 65 | "version": "2.7.0" 66 | }, 67 | "dnoegel/php-xdg-base-dir": { 68 | "version": "v0.1.1" 69 | }, 70 | "doctrine/annotations": { 71 | "version": "1.0", 72 | "recipe": { 73 | "repo": "github.com/symfony/recipes", 74 | "branch": "master", 75 | "version": "1.0", 76 | "ref": "a2759dd6123694c8d901d0ec80006e044c2e6457" 77 | }, 78 | "files": [ 79 | "config/routes/annotations.yaml" 80 | ] 81 | }, 82 | "doctrine/cache": { 83 | "version": "1.10.2" 84 | }, 85 | "doctrine/collections": { 86 | "version": "1.6.7" 87 | }, 88 | "doctrine/common": { 89 | "version": "2.13.3" 90 | }, 91 | "doctrine/data-fixtures": { 92 | "version": "1.4.4" 93 | }, 94 | "doctrine/dbal": { 95 | "version": "2.10.4" 96 | }, 97 | "doctrine/deprecations": { 98 | "version": "v0.5.3" 99 | }, 100 | "doctrine/doctrine-bundle": { 101 | "version": "1.12", 102 | "recipe": { 103 | "repo": "github.com/symfony/recipes", 104 | "branch": "master", 105 | "version": "1.12", 106 | "ref": "b11d5292f574a9cd092d506c899d05c79cf4d613" 107 | }, 108 | "files": [ 109 | "config/packages/doctrine.yaml", 110 | "config/packages/prod/doctrine.yaml", 111 | "src/Entity/.gitignore", 112 | "src/Repository/.gitignore" 113 | ] 114 | }, 115 | "doctrine/doctrine-cache-bundle": { 116 | "version": "1.4.0" 117 | }, 118 | "doctrine/doctrine-migrations-bundle": { 119 | "version": "2.2", 120 | "recipe": { 121 | "repo": "github.com/symfony/recipes", 122 | "branch": "master", 123 | "version": "2.2", 124 | "ref": "baaa439e3e3179e69e3da84b671f0a3e4a2f56ad" 125 | }, 126 | "files": [ 127 | "config/packages/doctrine_migrations.yaml", 128 | "migrations/.gitignore" 129 | ] 130 | }, 131 | "doctrine/event-manager": { 132 | "version": "1.1.1" 133 | }, 134 | "doctrine/inflector": { 135 | "version": "1.3.1" 136 | }, 137 | "doctrine/instantiator": { 138 | "version": "1.3.1" 139 | }, 140 | "doctrine/lexer": { 141 | "version": "1.2.1" 142 | }, 143 | "doctrine/migrations": { 144 | "version": "3.0.1" 145 | }, 146 | "doctrine/orm": { 147 | "version": "v2.7.3" 148 | }, 149 | "doctrine/persistence": { 150 | "version": "1.3.8" 151 | }, 152 | "doctrine/reflection": { 153 | "version": "1.2.1" 154 | }, 155 | "doctrine/sql-formatter": { 156 | "version": "1.1.1" 157 | }, 158 | "egulias/email-validator": { 159 | "version": "2.1.20" 160 | }, 161 | "fakerphp/faker": { 162 | "version": "v1.16.0" 163 | }, 164 | "felixfbecker/advanced-json-rpc": { 165 | "version": "v3.1.1" 166 | }, 167 | "felixfbecker/language-server-protocol": { 168 | "version": "v1.4.0" 169 | }, 170 | "fig/link-util": { 171 | "version": "1.1.1" 172 | }, 173 | "friends-of-behat/mink": { 174 | "version": "v1.8.0" 175 | }, 176 | "friends-of-behat/mink-browserkit-driver": { 177 | "version": "v1.4.0" 178 | }, 179 | "friends-of-behat/mink-extension": { 180 | "version": "v2.4.0" 181 | }, 182 | "friends-of-behat/page-object-extension": { 183 | "version": "v0.3.1" 184 | }, 185 | "friends-of-behat/symfony-extension": { 186 | "version": "2.0", 187 | "recipe": { 188 | "repo": "github.com/symfony/recipes-contrib", 189 | "branch": "master", 190 | "version": "2.0", 191 | "ref": "3d21344765fd3440a85bdd27d4cada186ec628bd" 192 | } 193 | }, 194 | "friends-of-behat/variadic-extension": { 195 | "version": "v1.3.0" 196 | }, 197 | "friendsofphp/php-cs-fixer": { 198 | "version": "3.0", 199 | "recipe": { 200 | "repo": "github.com/symfony/recipes", 201 | "branch": "master", 202 | "version": "3.0", 203 | "ref": "be2103eb4a20942e28a6dd87736669b757132435" 204 | }, 205 | "files": [ 206 | ".php-cs-fixer.dist.php" 207 | ] 208 | }, 209 | "friendsofphp/proxy-manager-lts": { 210 | "version": "v1.0.3" 211 | }, 212 | "friendsofsymfony/oauth-server-bundle": { 213 | "version": "1.6.2" 214 | }, 215 | "friendsofsymfony/oauth2-php": { 216 | "version": "1.3.0" 217 | }, 218 | "friendsofsymfony/rest-bundle": { 219 | "version": "2.2", 220 | "recipe": { 221 | "repo": "github.com/symfony/recipes-contrib", 222 | "branch": "master", 223 | "version": "2.2", 224 | "ref": "cad41ef93d6150067ae2bb3c7fd729492dff6f0a" 225 | } 226 | }, 227 | "fzaninotto/faker": { 228 | "version": "v1.9.1" 229 | }, 230 | "gedmo/doctrine-extensions": { 231 | "version": "v2.4.42" 232 | }, 233 | "guzzlehttp/guzzle": { 234 | "version": "6.5.5" 235 | }, 236 | "guzzlehttp/promises": { 237 | "version": "v1.3.1" 238 | }, 239 | "guzzlehttp/psr7": { 240 | "version": "1.6.1" 241 | }, 242 | "hamcrest/hamcrest-php": { 243 | "version": "v2.0.1" 244 | }, 245 | "hwi/oauth-bundle": { 246 | "version": "0.6", 247 | "recipe": { 248 | "repo": "github.com/symfony/recipes-contrib", 249 | "branch": "master", 250 | "version": "0.6", 251 | "ref": "20cacc9b2da49d96ea55c8a8dd31324c5be88bc9" 252 | } 253 | }, 254 | "imagine/imagine": { 255 | "version": "1.2.3" 256 | }, 257 | "instaclick/php-webdriver": { 258 | "version": "1.4.7" 259 | }, 260 | "jdorn/sql-formatter": { 261 | "version": "v1.2.17" 262 | }, 263 | "jean85/pretty-package-versions": { 264 | "version": "1.6.0" 265 | }, 266 | "jms/metadata": { 267 | "version": "1.7.0" 268 | }, 269 | "jms/parser-lib": { 270 | "version": "1.0.0" 271 | }, 272 | "jms/serializer": { 273 | "version": "1.14.1" 274 | }, 275 | "jms/serializer-bundle": { 276 | "version": "2.0", 277 | "recipe": { 278 | "repo": "github.com/symfony/recipes-contrib", 279 | "branch": "master", 280 | "version": "2.0", 281 | "ref": "fe60ce509ef04a3f40da96e3979bc8d9b13b2372" 282 | } 283 | }, 284 | "knplabs/gaufrette": { 285 | "version": "v0.8.3" 286 | }, 287 | "knplabs/knp-gaufrette-bundle": { 288 | "version": "v0.7.1" 289 | }, 290 | "knplabs/knp-menu": { 291 | "version": "v3.1.2" 292 | }, 293 | "knplabs/knp-menu-bundle": { 294 | "version": "v3.0.0" 295 | }, 296 | "laminas/laminas-code": { 297 | "version": "3.4.1" 298 | }, 299 | "laminas/laminas-eventmanager": { 300 | "version": "3.3.0" 301 | }, 302 | "laminas/laminas-stdlib": { 303 | "version": "3.6.0" 304 | }, 305 | "laminas/laminas-zendframework-bridge": { 306 | "version": "1.1.1" 307 | }, 308 | "lchrusciel/api-test-case": { 309 | "version": "v5.0.0" 310 | }, 311 | "lcobucci/clock": { 312 | "version": "2.0.0" 313 | }, 314 | "lcobucci/jwt": { 315 | "version": "3.3.3" 316 | }, 317 | "league/uri": { 318 | "version": "5.3.0" 319 | }, 320 | "league/uri-components": { 321 | "version": "1.8.2" 322 | }, 323 | "league/uri-hostname-parser": { 324 | "version": "1.1.1" 325 | }, 326 | "league/uri-interfaces": { 327 | "version": "1.1.1" 328 | }, 329 | "league/uri-manipulations": { 330 | "version": "1.5.0" 331 | }, 332 | "league/uri-parser": { 333 | "version": "1.4.1" 334 | }, 335 | "league/uri-schemes": { 336 | "version": "1.2.1" 337 | }, 338 | "lexik/jwt-authentication-bundle": { 339 | "version": "2.5", 340 | "recipe": { 341 | "repo": "github.com/symfony/recipes", 342 | "branch": "master", 343 | "version": "2.5", 344 | "ref": "5b2157bcd5778166a5696e42f552ad36529a07a6" 345 | }, 346 | "files": [ 347 | "config/packages/lexik_jwt_authentication.yaml" 348 | ] 349 | }, 350 | "liip/imagine-bundle": { 351 | "version": "1.8", 352 | "recipe": { 353 | "repo": "github.com/symfony/recipes-contrib", 354 | "branch": "master", 355 | "version": "1.8", 356 | "ref": "5a5bdc2d0e2533ed6935d5ae562f2b318a8fc1ee" 357 | } 358 | }, 359 | "marcj/topsort": { 360 | "version": "1.1.0" 361 | }, 362 | "matthiasnoback/symfony-config-test": { 363 | "version": "4.2.0" 364 | }, 365 | "matthiasnoback/symfony-dependency-injection-test": { 366 | "version": "4.1.1" 367 | }, 368 | "mikey179/vfsstream": { 369 | "version": "v1.6.8" 370 | }, 371 | "mockery/mockery": { 372 | "version": "1.4.2" 373 | }, 374 | "monolog/monolog": { 375 | "version": "1.25.5" 376 | }, 377 | "monsieurbiz/sylius-settings-plugin": { 378 | "version": "1.0", 379 | "recipe": { 380 | "repo": "github.com/symfony/recipes-contrib", 381 | "branch": "master", 382 | "version": "1.0", 383 | "ref": "fafa903dedd49e881d21be1236c3d002e45278ed" 384 | }, 385 | "files": [ 386 | "tests/Application/config/packages/monsieurbiz_settings_plugin.yaml", 387 | "tests/Application/config/routes/monsieurbiz_settings_plugin.yaml" 388 | ] 389 | }, 390 | "myclabs/deep-copy": { 391 | "version": "1.10.1" 392 | }, 393 | "namshi/jose": { 394 | "version": "7.2.3" 395 | }, 396 | "nelmio/alice": { 397 | "version": "3.2", 398 | "recipe": { 399 | "repo": "github.com/symfony/recipes", 400 | "branch": "master", 401 | "version": "3.2", 402 | "ref": "0b9900ece737bec7752e4155c0164639dd9b0cb0" 403 | }, 404 | "files": [ 405 | "config/packages/dev/nelmio_alice.yaml", 406 | "config/packages/test/nelmio_alice.yaml" 407 | ] 408 | }, 409 | "netresearch/jsonmapper": { 410 | "version": "v2.1.0" 411 | }, 412 | "nette/finder": { 413 | "version": "v2.5.2" 414 | }, 415 | "nette/robot-loader": { 416 | "version": "v3.4.1" 417 | }, 418 | "nette/utils": { 419 | "version": "v3.2.5" 420 | }, 421 | "nikic/php-parser": { 422 | "version": "v4.6.0" 423 | }, 424 | "ocramius/package-versions": { 425 | "version": "1.9.0" 426 | }, 427 | "ocramius/proxy-manager": { 428 | "version": "2.8.1" 429 | }, 430 | "openlss/lib-array2xml": { 431 | "version": "1.0.0" 432 | }, 433 | "pagerfanta/pagerfanta": { 434 | "version": "v2.4.1" 435 | }, 436 | "pamil/prophecy-common": { 437 | "version": "v0.1.0" 438 | }, 439 | "paragonie/random_compat": { 440 | "version": "v2.0.18" 441 | }, 442 | "payum/iso4217": { 443 | "version": "1.0.1" 444 | }, 445 | "payum/payum": { 446 | "version": "1.6.0" 447 | }, 448 | "payum/payum-bundle": { 449 | "version": "2.4", 450 | "recipe": { 451 | "repo": "github.com/symfony/recipes-contrib", 452 | "branch": "master", 453 | "version": "2.4", 454 | "ref": "72ad834a0f4a99175beddb5e2d049136f4a50a67" 455 | } 456 | }, 457 | "pdepend/pdepend": { 458 | "version": "2.10.0" 459 | }, 460 | "phar-io/manifest": { 461 | "version": "1.0.3" 462 | }, 463 | "phar-io/version": { 464 | "version": "2.0.1" 465 | }, 466 | "php": { 467 | "version": "7.4" 468 | }, 469 | "php-cs-fixer/diff": { 470 | "version": "v2.0.2" 471 | }, 472 | "php-http/client-common": { 473 | "version": "2.3.0" 474 | }, 475 | "php-http/discovery": { 476 | "version": "1.10.0" 477 | }, 478 | "php-http/guzzle6-adapter": { 479 | "version": "v2.0.1" 480 | }, 481 | "php-http/httplug": { 482 | "version": "2.2.0" 483 | }, 484 | "php-http/message": { 485 | "version": "1.9.0" 486 | }, 487 | "php-http/message-factory": { 488 | "version": "v1.0.2" 489 | }, 490 | "php-http/promise": { 491 | "version": "1.1.0" 492 | }, 493 | "phpcollection/phpcollection": { 494 | "version": "0.5.0" 495 | }, 496 | "phpdocumentor/reflection-common": { 497 | "version": "2.2.0" 498 | }, 499 | "phpdocumentor/reflection-docblock": { 500 | "version": "5.2.2" 501 | }, 502 | "phpdocumentor/type-resolver": { 503 | "version": "1.4.0" 504 | }, 505 | "phpmd/phpmd": { 506 | "version": "2.10.2" 507 | }, 508 | "phpoption/phpoption": { 509 | "version": "1.7.5" 510 | }, 511 | "phpspec/php-diff": { 512 | "version": "v1.1.3" 513 | }, 514 | "phpspec/phpspec": { 515 | "version": "6.2.1" 516 | }, 517 | "phpspec/prophecy": { 518 | "version": "1.11.1" 519 | }, 520 | "phpstan/phpdoc-parser": { 521 | "version": "0.4.9" 522 | }, 523 | "phpstan/phpstan": { 524 | "version": "0.12.29" 525 | }, 526 | "phpstan/phpstan-doctrine": { 527 | "version": "0.12.16" 528 | }, 529 | "phpstan/phpstan-webmozart-assert": { 530 | "version": "0.12.7" 531 | }, 532 | "phpunit/php-code-coverage": { 533 | "version": "7.0.10" 534 | }, 535 | "phpunit/php-file-iterator": { 536 | "version": "2.0.2" 537 | }, 538 | "phpunit/php-text-template": { 539 | "version": "1.2.1" 540 | }, 541 | "phpunit/php-timer": { 542 | "version": "2.1.2" 543 | }, 544 | "phpunit/php-token-stream": { 545 | "version": "3.1.1" 546 | }, 547 | "phpunit/phpunit": { 548 | "version": "4.7", 549 | "recipe": { 550 | "repo": "github.com/symfony/recipes", 551 | "branch": "master", 552 | "version": "4.7", 553 | "ref": "477e1387616f39505ba79715f43f124836020d71" 554 | }, 555 | "files": [ 556 | ".env.test", 557 | "phpunit.xml.dist", 558 | "tests/bootstrap.php" 559 | ] 560 | }, 561 | "polishsymfonycommunity/symfony-mocker-container": { 562 | "version": "v1.0.3" 563 | }, 564 | "psalm/plugin-mockery": { 565 | "version": "0.3.0" 566 | }, 567 | "psr/cache": { 568 | "version": "1.0.1" 569 | }, 570 | "psr/container": { 571 | "version": "1.0.0" 572 | }, 573 | "psr/event-dispatcher": { 574 | "version": "1.0.0" 575 | }, 576 | "psr/http-client": { 577 | "version": "1.0.1" 578 | }, 579 | "psr/http-factory": { 580 | "version": "1.0.1" 581 | }, 582 | "psr/http-message": { 583 | "version": "1.0.1" 584 | }, 585 | "psr/link": { 586 | "version": "1.0.0" 587 | }, 588 | "psr/log": { 589 | "version": "1.1.3" 590 | }, 591 | "psr/simple-cache": { 592 | "version": "1.0.1" 593 | }, 594 | "ralouphie/getallheaders": { 595 | "version": "3.0.3" 596 | }, 597 | "ramsey/uuid": { 598 | "version": "3.9.3" 599 | }, 600 | "sebastian/code-unit-reverse-lookup": { 601 | "version": "1.0.1" 602 | }, 603 | "sebastian/comparator": { 604 | "version": "3.0.2" 605 | }, 606 | "sebastian/diff": { 607 | "version": "3.0.2" 608 | }, 609 | "sebastian/environment": { 610 | "version": "4.2.3" 611 | }, 612 | "sebastian/exporter": { 613 | "version": "3.1.2" 614 | }, 615 | "sebastian/global-state": { 616 | "version": "3.0.0" 617 | }, 618 | "sebastian/object-enumerator": { 619 | "version": "3.0.3" 620 | }, 621 | "sebastian/object-reflector": { 622 | "version": "1.1.1" 623 | }, 624 | "sebastian/recursion-context": { 625 | "version": "3.0.0" 626 | }, 627 | "sebastian/resource-operations": { 628 | "version": "2.0.1" 629 | }, 630 | "sebastian/type": { 631 | "version": "1.1.3" 632 | }, 633 | "sebastian/version": { 634 | "version": "2.0.1" 635 | }, 636 | "slevomat/coding-standard": { 637 | "version": "6.4.0" 638 | }, 639 | "sonata-project/block-bundle": { 640 | "version": "4.2.0" 641 | }, 642 | "sonata-project/cache": { 643 | "version": "2.0.1" 644 | }, 645 | "sonata-project/doctrine-extensions": { 646 | "version": "1.9.1" 647 | }, 648 | "sonata-project/form-extensions": { 649 | "version": "1.0", 650 | "recipe": { 651 | "repo": "github.com/symfony/recipes-contrib", 652 | "branch": "master", 653 | "version": "1.0", 654 | "ref": "8273133183506fe6ec66895e8890227b0dfba1c7" 655 | } 656 | }, 657 | "sonata-project/twig-extensions": { 658 | "version": "1.4.1" 659 | }, 660 | "squizlabs/php_codesniffer": { 661 | "version": "3.0", 662 | "recipe": { 663 | "repo": "github.com/symfony/recipes-contrib", 664 | "branch": "master", 665 | "version": "3.0", 666 | "ref": "0dc9cceda799fd3a08b96987e176a261028a3709" 667 | } 668 | }, 669 | "stof/doctrine-extensions-bundle": { 670 | "version": "1.2", 671 | "recipe": { 672 | "repo": "github.com/symfony/recipes-contrib", 673 | "branch": "master", 674 | "version": "1.2", 675 | "ref": "6c1ceb662f8997085f739cd089bfbef67f245983" 676 | } 677 | }, 678 | "swiftmailer/swiftmailer": { 679 | "version": "v6.2.3" 680 | }, 681 | "sylius-labs/association-hydrator": { 682 | "version": "v1.1.2" 683 | }, 684 | "sylius-labs/coding-standard": { 685 | "version": "v3.2.1" 686 | }, 687 | "sylius-labs/doctrine-migrations-extra-bundle": { 688 | "version": "v0.1.3" 689 | }, 690 | "sylius-labs/polyfill-symfony-event-dispatcher": { 691 | "version": "v1.0.0" 692 | }, 693 | "sylius-labs/polyfill-symfony-framework-bundle": { 694 | "version": "v1.0.0" 695 | }, 696 | "sylius-labs/polyfill-symfony-security": { 697 | "version": "v1.0.0" 698 | }, 699 | "sylius/calendar": { 700 | "version": "v0.4.0" 701 | }, 702 | "sylius/fixtures-bundle": { 703 | "version": "v1.6.1" 704 | }, 705 | "sylius/grid-bundle": { 706 | "version": "v1.7.5" 707 | }, 708 | "sylius/mailer-bundle": { 709 | "version": "v1.5.1" 710 | }, 711 | "sylius/registry": { 712 | "version": "v1.5.1" 713 | }, 714 | "sylius/resource-bundle": { 715 | "version": "v1.6.4" 716 | }, 717 | "sylius/sylius": { 718 | "version": "v1.8.0" 719 | }, 720 | "sylius/theme-bundle": { 721 | "version": "v1.5.1" 722 | }, 723 | "symfony/asset": { 724 | "version": "v4.4.13" 725 | }, 726 | "symfony/browser-kit": { 727 | "version": "v4.4.13" 728 | }, 729 | "symfony/cache": { 730 | "version": "v4.4.13" 731 | }, 732 | "symfony/cache-contracts": { 733 | "version": "v2.2.0" 734 | }, 735 | "symfony/config": { 736 | "version": "v4.4.13" 737 | }, 738 | "symfony/console": { 739 | "version": "4.4", 740 | "recipe": { 741 | "repo": "github.com/symfony/recipes", 742 | "branch": "master", 743 | "version": "4.4", 744 | "ref": "ea8c0eda34fda57e7d5cd8cbd889e2a387e3472c" 745 | }, 746 | "files": [ 747 | "bin/console", 748 | "config/bootstrap.php" 749 | ] 750 | }, 751 | "symfony/css-selector": { 752 | "version": "v4.4.13" 753 | }, 754 | "symfony/debug": { 755 | "version": "v4.4.13" 756 | }, 757 | "symfony/debug-bundle": { 758 | "version": "4.1", 759 | "recipe": { 760 | "repo": "github.com/symfony/recipes", 761 | "branch": "master", 762 | "version": "4.1", 763 | "ref": "f8863cbad2f2e58c4b65fa1eac892ab189971bea" 764 | }, 765 | "files": [ 766 | "config/packages/dev/debug.yaml" 767 | ] 768 | }, 769 | "symfony/dependency-injection": { 770 | "version": "v4.4.13" 771 | }, 772 | "symfony/deprecation-contracts": { 773 | "version": "v2.2.0" 774 | }, 775 | "symfony/doctrine-bridge": { 776 | "version": "v4.4.13" 777 | }, 778 | "symfony/dom-crawler": { 779 | "version": "v5.1.5" 780 | }, 781 | "symfony/dotenv": { 782 | "version": "v4.4.13" 783 | }, 784 | "symfony/error-handler": { 785 | "version": "v4.4.13" 786 | }, 787 | "symfony/event-dispatcher": { 788 | "version": "v4.4.13" 789 | }, 790 | "symfony/event-dispatcher-contracts": { 791 | "version": "v1.1.9" 792 | }, 793 | "symfony/expression-language": { 794 | "version": "v4.4.13" 795 | }, 796 | "symfony/filesystem": { 797 | "version": "v4.4.13" 798 | }, 799 | "symfony/finder": { 800 | "version": "v4.4.13" 801 | }, 802 | "symfony/flex": { 803 | "version": "1.0", 804 | "recipe": { 805 | "repo": "github.com/symfony/recipes", 806 | "branch": "master", 807 | "version": "1.0", 808 | "ref": "c0eeb50665f0f77226616b6038a9b06c03752d8e" 809 | }, 810 | "files": [ 811 | ".env" 812 | ] 813 | }, 814 | "symfony/form": { 815 | "version": "v4.4.13" 816 | }, 817 | "symfony/framework-bundle": { 818 | "version": "4.4", 819 | "recipe": { 820 | "repo": "github.com/symfony/recipes", 821 | "branch": "master", 822 | "version": "4.4", 823 | "ref": "af2e2efad553bc959a0c61d9185e33ca9eec5c99" 824 | }, 825 | "files": [ 826 | "config/bootstrap.php", 827 | "config/packages/cache.yaml", 828 | "config/packages/framework.yaml", 829 | "config/packages/test/framework.yaml", 830 | "config/routes/dev/framework.yaml", 831 | "config/services.yaml", 832 | "public/index.php", 833 | "src/Controller/.gitignore", 834 | "src/Kernel.php" 835 | ] 836 | }, 837 | "symfony/http-client-contracts": { 838 | "version": "v2.3.1" 839 | }, 840 | "symfony/http-foundation": { 841 | "version": "v4.4.13" 842 | }, 843 | "symfony/http-kernel": { 844 | "version": "v4.4.13" 845 | }, 846 | "symfony/inflector": { 847 | "version": "v5.1.5" 848 | }, 849 | "symfony/intl": { 850 | "version": "v4.4.13" 851 | }, 852 | "symfony/messenger": { 853 | "version": "4.3", 854 | "recipe": { 855 | "repo": "github.com/symfony/recipes", 856 | "branch": "master", 857 | "version": "4.3", 858 | "ref": "8a2675c061737658bed85102e9241c752620e575" 859 | }, 860 | "files": [ 861 | "config/packages/messenger.yaml" 862 | ] 863 | }, 864 | "symfony/mime": { 865 | "version": "v5.1.5" 866 | }, 867 | "symfony/monolog-bridge": { 868 | "version": "v5.1.5" 869 | }, 870 | "symfony/monolog-bundle": { 871 | "version": "3.3", 872 | "recipe": { 873 | "repo": "github.com/symfony/recipes", 874 | "branch": "master", 875 | "version": "3.3", 876 | "ref": "d7249f7d560f6736115eee1851d02a65826f0a56" 877 | }, 878 | "files": [ 879 | "config/packages/dev/monolog.yaml", 880 | "config/packages/prod/deprecations.yaml", 881 | "config/packages/prod/monolog.yaml", 882 | "config/packages/test/monolog.yaml" 883 | ] 884 | }, 885 | "symfony/options-resolver": { 886 | "version": "v4.4.13" 887 | }, 888 | "symfony/password-hasher": { 889 | "version": "v5.3.8" 890 | }, 891 | "symfony/polyfill-ctype": { 892 | "version": "v1.18.1" 893 | }, 894 | "symfony/polyfill-iconv": { 895 | "version": "v1.18.1" 896 | }, 897 | "symfony/polyfill-intl-grapheme": { 898 | "version": "v1.18.1" 899 | }, 900 | "symfony/polyfill-intl-icu": { 901 | "version": "v1.18.1" 902 | }, 903 | "symfony/polyfill-intl-idn": { 904 | "version": "v1.18.1" 905 | }, 906 | "symfony/polyfill-intl-normalizer": { 907 | "version": "v1.18.1" 908 | }, 909 | "symfony/polyfill-mbstring": { 910 | "version": "v1.18.1" 911 | }, 912 | "symfony/polyfill-php56": { 913 | "version": "v1.18.1" 914 | }, 915 | "symfony/polyfill-php70": { 916 | "version": "v1.20.0" 917 | }, 918 | "symfony/polyfill-php72": { 919 | "version": "v1.18.1" 920 | }, 921 | "symfony/polyfill-php73": { 922 | "version": "v1.18.1" 923 | }, 924 | "symfony/polyfill-php80": { 925 | "version": "v1.18.1" 926 | }, 927 | "symfony/polyfill-php81": { 928 | "version": "v1.23.0" 929 | }, 930 | "symfony/process": { 931 | "version": "v4.4.13" 932 | }, 933 | "symfony/property-access": { 934 | "version": "v4.4.13" 935 | }, 936 | "symfony/property-info": { 937 | "version": "v5.1.5" 938 | }, 939 | "symfony/proxy-manager-bridge": { 940 | "version": "v4.4.13" 941 | }, 942 | "symfony/routing": { 943 | "version": "4.2", 944 | "recipe": { 945 | "repo": "github.com/symfony/recipes", 946 | "branch": "master", 947 | "version": "4.2", 948 | "ref": "683dcb08707ba8d41b7e34adb0344bfd68d248a7" 949 | }, 950 | "files": [ 951 | "config/packages/prod/routing.yaml", 952 | "config/packages/routing.yaml", 953 | "config/routes.yaml" 954 | ] 955 | }, 956 | "symfony/security-bundle": { 957 | "version": "4.4", 958 | "recipe": { 959 | "repo": "github.com/symfony/recipes", 960 | "branch": "master", 961 | "version": "4.4", 962 | "ref": "7b4408dc203049666fe23fabed23cbadc6d8440f" 963 | }, 964 | "files": [ 965 | "config/packages/security.yaml" 966 | ] 967 | }, 968 | "symfony/security-core": { 969 | "version": "v4.4.13" 970 | }, 971 | "symfony/security-csrf": { 972 | "version": "v4.4.13" 973 | }, 974 | "symfony/security-guard": { 975 | "version": "v4.4.13" 976 | }, 977 | "symfony/security-http": { 978 | "version": "v4.4.13" 979 | }, 980 | "symfony/serializer": { 981 | "version": "v5.1.5" 982 | }, 983 | "symfony/service-contracts": { 984 | "version": "v2.2.0" 985 | }, 986 | "symfony/stopwatch": { 987 | "version": "v5.1.5" 988 | }, 989 | "symfony/string": { 990 | "version": "v5.1.5" 991 | }, 992 | "symfony/swiftmailer-bundle": { 993 | "version": "2.5", 994 | "recipe": { 995 | "repo": "github.com/symfony/recipes", 996 | "branch": "master", 997 | "version": "2.5", 998 | "ref": "ae4d22af30bbd484506bc1817c5a3ef72c855b93" 999 | }, 1000 | "files": [ 1001 | "config/packages/dev/swiftmailer.yaml", 1002 | "config/packages/swiftmailer.yaml", 1003 | "config/packages/test/swiftmailer.yaml" 1004 | ] 1005 | }, 1006 | "symfony/templating": { 1007 | "version": "v4.4.13" 1008 | }, 1009 | "symfony/translation": { 1010 | "version": "3.3", 1011 | "recipe": { 1012 | "repo": "github.com/symfony/recipes", 1013 | "branch": "master", 1014 | "version": "3.3", 1015 | "ref": "2ad9d2545bce8ca1a863e50e92141f0b9d87ffcd" 1016 | }, 1017 | "files": [ 1018 | "config/packages/translation.yaml", 1019 | "translations/.gitignore" 1020 | ] 1021 | }, 1022 | "symfony/translation-contracts": { 1023 | "version": "v1.1.10" 1024 | }, 1025 | "symfony/twig-bridge": { 1026 | "version": "v4.4.13" 1027 | }, 1028 | "symfony/twig-bundle": { 1029 | "version": "4.4", 1030 | "recipe": { 1031 | "repo": "github.com/symfony/recipes", 1032 | "branch": "master", 1033 | "version": "4.4", 1034 | "ref": "15a41bbd66a1323d09824a189b485c126bbefa51" 1035 | }, 1036 | "files": [ 1037 | "config/packages/test/twig.yaml", 1038 | "config/packages/twig.yaml", 1039 | "templates/base.html.twig" 1040 | ] 1041 | }, 1042 | "symfony/validator": { 1043 | "version": "4.3", 1044 | "recipe": { 1045 | "repo": "github.com/symfony/recipes", 1046 | "branch": "master", 1047 | "version": "4.3", 1048 | "ref": "d902da3e4952f18d3bf05aab29512eb61cabd869" 1049 | }, 1050 | "files": [ 1051 | "config/packages/test/validator.yaml", 1052 | "config/packages/validator.yaml" 1053 | ] 1054 | }, 1055 | "symfony/var-dumper": { 1056 | "version": "v5.1.5" 1057 | }, 1058 | "symfony/var-exporter": { 1059 | "version": "v5.1.5" 1060 | }, 1061 | "symfony/web-link": { 1062 | "version": "v5.1.5" 1063 | }, 1064 | "symfony/web-profiler-bundle": { 1065 | "version": "3.3", 1066 | "recipe": { 1067 | "repo": "github.com/symfony/recipes", 1068 | "branch": "master", 1069 | "version": "3.3", 1070 | "ref": "6bdfa1a95f6b2e677ab985cd1af2eae35d62e0f6" 1071 | }, 1072 | "files": [ 1073 | "config/packages/dev/web_profiler.yaml", 1074 | "config/packages/test/web_profiler.yaml", 1075 | "config/routes/dev/web_profiler.yaml" 1076 | ] 1077 | }, 1078 | "symfony/yaml": { 1079 | "version": "v4.4.13" 1080 | }, 1081 | "symplify/autowire-array-parameter": { 1082 | "version": "8.3.48" 1083 | }, 1084 | "symplify/coding-standard": { 1085 | "version": "8.3.48" 1086 | }, 1087 | "symplify/console-color-diff": { 1088 | "version": "8.3.48" 1089 | }, 1090 | "symplify/easy-coding-standard": { 1091 | "version": "v8.1.19" 1092 | }, 1093 | "symplify/package-builder": { 1094 | "version": "8.3.48" 1095 | }, 1096 | "symplify/set-config-resolver": { 1097 | "version": "8.3.48" 1098 | }, 1099 | "symplify/smart-file-system": { 1100 | "version": "8.3.48" 1101 | }, 1102 | "symplify/symplify-kernel": { 1103 | "version": "8.3.48" 1104 | }, 1105 | "textalk/websocket": { 1106 | "version": "1.4.0" 1107 | }, 1108 | "theofidry/alice-data-fixtures": { 1109 | "version": "1.0", 1110 | "recipe": { 1111 | "repo": "github.com/symfony/recipes", 1112 | "branch": "master", 1113 | "version": "1.0", 1114 | "ref": "fe5a50faf580eb58f08ada2abe8afbd2d4941e05" 1115 | } 1116 | }, 1117 | "theseer/tokenizer": { 1118 | "version": "1.2.0" 1119 | }, 1120 | "twig/intl-extra": { 1121 | "version": "v2.13.1" 1122 | }, 1123 | "twig/twig": { 1124 | "version": "v2.13.1" 1125 | }, 1126 | "vimeo/psalm": { 1127 | "version": "3.16" 1128 | }, 1129 | "webimpress/safe-writer": { 1130 | "version": "2.1.0" 1131 | }, 1132 | "webmozart/assert": { 1133 | "version": "1.9.1" 1134 | }, 1135 | "webmozart/glob": { 1136 | "version": "4.4.0" 1137 | }, 1138 | "webmozart/path-util": { 1139 | "version": "2.3.0" 1140 | }, 1141 | "white-october/pagerfanta-bundle": { 1142 | "version": "v1.3.2" 1143 | }, 1144 | "willdurand/hateoas": { 1145 | "version": "2.12.0" 1146 | }, 1147 | "willdurand/hateoas-bundle": { 1148 | "version": "1.4", 1149 | "recipe": { 1150 | "repo": "github.com/symfony/recipes-contrib", 1151 | "branch": "master", 1152 | "version": "1.4", 1153 | "ref": "34df072c6edaa61ae19afb2f3a239f272fecab87" 1154 | } 1155 | }, 1156 | "willdurand/jsonp-callback-validator": { 1157 | "version": "v1.1.0" 1158 | }, 1159 | "willdurand/negotiation": { 1160 | "version": "v2.3.1" 1161 | }, 1162 | "winzou/state-machine": { 1163 | "version": "0.3.3" 1164 | }, 1165 | "winzou/state-machine-bundle": { 1166 | "version": "0.3.2" 1167 | }, 1168 | "zendframework/zend-hydrator": { 1169 | "version": "2.4.2" 1170 | }, 1171 | "zendframework/zend-stdlib": { 1172 | "version": "3.2.1" 1173 | } 1174 | } 1175 | --------------------------------------------------------------------------------