From 0f3fd315c78d2786e1b57dfc8e3a4fc8279379ff Mon Sep 17 00:00:00 2001 From: Etienne Gutbub Date: Tue, 6 Aug 2024 10:08:31 +0200 Subject: [PATCH] feat(AdminRoutes): Allow to enabled some routes for admin through configuration in BO --- src/Form/Type/Settings/NoCommerceType.php | 16 ++++ src/Kernel/SyliusNoCommerceKernelTrait.php | 2 +- src/Menu/AdminMenuListener.php | 64 ++++++++++++--- src/Provider/FeaturesProvider.php | 89 ++++++++++++++++++++- src/Provider/FeaturesProviderInterface.php | 2 + src/Resources/translations/messages.en.yaml | 2 + src/Resources/translations/messages.fr.yaml | 2 + src/Routing/NoCommerceRequestContext.php | 4 +- 8 files changed, 168 insertions(+), 13 deletions(-) diff --git a/src/Form/Type/Settings/NoCommerceType.php b/src/Form/Type/Settings/NoCommerceType.php index 5f717c6..6347a04 100644 --- a/src/Form/Type/Settings/NoCommerceType.php +++ b/src/Form/Type/Settings/NoCommerceType.php @@ -14,6 +14,7 @@ namespace MonsieurBiz\SyliusNoCommercePlugin\Form\Type\Settings; use MonsieurBiz\SyliusNoCommercePlugin\Firewall\RegistryInterface; +use MonsieurBiz\SyliusNoCommercePlugin\Provider\FeaturesProvider; use MonsieurBiz\SyliusSettingsPlugin\Form\AbstractSettingsType; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; @@ -60,5 +61,20 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'multiple' => true, 'choices' => $choices, ]); + $this->addWithDefaultCheckbox($builder, 're_enabled_admin_routes', ChoiceType::class, [ + 'label' => 'monsieurbiz.nocommerce.ui.form.field.re_enabled_admin_routes.label', + 'required' => false, + 'multiple' => true, + 'choices' => [ + 'sylius.ui.countries' => FeaturesProvider::COUNTRIES_KEY, + 'sylius.ui.currencies' => FeaturesProvider::CURRENCIES_KEY, + 'sylius.ui.inventory' => FeaturesProvider::INVENTORY_KEY, + 'sylius.ui.payment' => FeaturesProvider::PAYMENT_KEY, + 'sylius.menu.admin.main.catalog.header' => FeaturesProvider::CATALOG_KEY, + 'sylius.ui.shipping' => FeaturesProvider::SHIPPING_KEY, + 'sylius.ui.tax' => FeaturesProvider::TAX_KEY, + 'sylius.ui.zones' => FeaturesProvider::ZONES_KEY, + ], + ]); } } diff --git a/src/Kernel/SyliusNoCommerceKernelTrait.php b/src/Kernel/SyliusNoCommerceKernelTrait.php index 44dfd88..73fbc9e 100644 --- a/src/Kernel/SyliusNoCommerceKernelTrait.php +++ b/src/Kernel/SyliusNoCommerceKernelTrait.php @@ -216,7 +216,7 @@ public function loadRoutes(LoaderInterface $loader): RouteCollection foreach ($collection as $name => $route) { foreach ($routesToRemove as $routeToRemove) { if (false !== strpos($name, $routeToRemove)) { - $route->setCondition('not context.checkNoCommerce()'); + $route->setCondition('not context.checkNoCommerce(params)'); } } } diff --git a/src/Menu/AdminMenuListener.php b/src/Menu/AdminMenuListener.php index 46b29e4..116cb9b 100644 --- a/src/Menu/AdminMenuListener.php +++ b/src/Menu/AdminMenuListener.php @@ -41,7 +41,8 @@ public function __invoke(MenuBuilderEvent $event): void } $menu->removeChild('sales'); - $menu->removeChild('catalog'); + + $this->handleCatalogMenu($menu); $menu->removeChild('marketing'); if (!$this->config->areCustomersAllowed()) { @@ -55,19 +56,64 @@ public function __invoke(MenuBuilderEvent $event): void private function removeConfigurationChildren(ItemInterface $configuration): void { - $configuration->removeChild('currencies'); + $this->removeChildIfRoutesDisabled($configuration, 'currencies'); if (!$this->config->areZonesAllowed() && !$this->config->areCountriesAllowed()) { - $configuration->removeChild('countries'); + $this->removeChildIfRoutesDisabled($configuration, 'countries'); } if (!$this->config->areZonesAllowed()) { - $configuration->removeChild('zones'); + $this->removeChildIfRoutesDisabled($configuration, 'zones'); } + $configuration->removeChild('exchange_rates'); - $configuration->removeChild('payment_methods'); - $configuration->removeChild('shipping_methods'); - $configuration->removeChild('shipping_categories'); - $configuration->removeChild('tax_categories'); - $configuration->removeChild('tax_rates'); + $this->removeChildIfRoutesDisabled($configuration, 'payment_methods'); + $this->removeChildIfRoutesDisabled($configuration, 'shipping_methods'); + $this->removeChildIfRoutesDisabled($configuration, 'shipping_categories'); + $this->removeChildIfRoutesDisabled($configuration, 'tax_categories'); + $this->removeChildIfRoutesDisabled($configuration, 'tax_rates'); + } + + /** + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + */ + private function removeChildIfRoutesDisabled(ItemInterface $menu, string $menuName): void + { + $menuItem = $menu->getChild($menuName); + if (!$menuItem || null === $menuItem->getExtra('routes')) { + return; + } + + foreach ($menuItem->getExtra('routes') as $route) { + if (!isset($route['route'])) { + continue; + } + // If one route does not match the forced enabled routes, we remove the menu item + if (!$this->featuresProvider->isRouteForcedEnabled(['_route' => $route['route']])) { + $menu->removeChild($menuName); + } + } + } + + private function handleCatalogMenu(ItemInterface $menu): void + { + $catalogMenu = $menu->getChild('catalog'); + + if (null === $catalogMenu) { + return; + } + + $this->removeChildIfRoutesDisabled($catalogMenu, 'taxons'); + $this->removeChildIfRoutesDisabled($catalogMenu, 'products'); + $this->removeChildIfRoutesDisabled($catalogMenu, 'inventory'); + $this->removeChildIfRoutesDisabled($catalogMenu, 'attributes'); + $this->removeChildIfRoutesDisabled($catalogMenu, 'options'); + $this->removeChildIfRoutesDisabled($catalogMenu, 'association_types'); + + // We remove the catalog menu if it has no children + if ($catalogMenu->hasChildren()) { + return; + } + + $menu->removeChild('catalog'); } } diff --git a/src/Provider/FeaturesProvider.php b/src/Provider/FeaturesProvider.php index de70ad3..5a788f4 100644 --- a/src/Provider/FeaturesProvider.php +++ b/src/Provider/FeaturesProvider.php @@ -20,6 +20,60 @@ final class FeaturesProvider implements FeaturesProviderInterface { + public const COUNTRIES_KEY = 'countries'; + + public const CURRENCIES_KEY = 'currencies'; + + public const INVENTORY_KEY = 'inventory'; + + public const PAYMENT_KEY = 'payment'; + + public const CATALOG_KEY = 'catalog'; + + public const SHIPPING_KEY = 'shipping'; + + public const TAX_KEY = 'tax'; + + public const ZONES_KEY = 'zones'; + + public const ADMIN_ROUTES_THAT_CAN_BE_RE_ENABLED = [ + self::COUNTRIES_KEY => [ + 'sylius_admin_country', + 'sylius_admin_ajax_render_province_form', + ], + self::CURRENCIES_KEY => [ + 'sylius_admin_currency', + ], + self::INVENTORY_KEY => [ + 'sylius_admin_inventory', + ], + self::PAYMENT_KEY => [ + 'sylius_admin_payment_method', + ], + self::CATALOG_KEY => [ + 'sylius_admin_get_attribute_types', + 'sylius_admin_get_product_attributes', + 'sylius_admin_render_attribute_forms', + 'sylius_admin_product', + 'sylius_admin_ajax_product', + 'sylius_admin_partial_product', + 'sylius_admin_ajax_generate_product_slug', + 'sylius_admin_partial_taxon', + 'sylius_admin_ajax_taxon', + 'sylius_admin_taxon', + 'sylius_admin_ajax_generate_taxon_slug', + ], + self::SHIPPING_KEY => [ + 'sylius_admin_shipping', + ], + self::TAX_KEY => [ + 'sylius_admin_tax_', + ], + self::ZONES_KEY => [ + 'sylius_admin_zone', + ], + ]; + private ChannelContextInterface $channelContext; private SettingsInterface $nocommerceSettings; @@ -38,7 +92,7 @@ public function isNoCommerceEnabledForChannel(?ChannelInterface $channel = null) if (null === $channel) { $channel = $this->channelContext->getChannel(); } - // In case we are getting a channel that does not exists yet we return null to have the channel set properly + // In case we are getting a channel that does not exist yet, we return null to have the channel set properly if (null === $channel->getId()) { return true; } @@ -48,4 +102,37 @@ public function isNoCommerceEnabledForChannel(?ChannelInterface $channel = null) return (bool) $this->nocommerceSettings->getCurrentValue($channel, null, 'enabled'); } + + /** + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + */ + public function isRouteForcedEnabled(array $params = []): bool + { + if (!isset($params['_route'])) { + return false; + } + + $route = $params['_route']; + $channel = $this->channelContext->getChannel(); + /** @var ?array $reEnabledAdminRoutes */ + $reEnabledAdminRoutes = $this->nocommerceSettings->getCurrentValue($channel, null, 're_enabled_admin_routes'); + + if (empty($reEnabledAdminRoutes)) { + return false; + } + + // We are checking if we should re-enable the route + foreach ($reEnabledAdminRoutes as $reEnabledAdminSection) { + if (!isset(self::ADMIN_ROUTES_THAT_CAN_BE_RE_ENABLED[$reEnabledAdminSection])) { + continue; + } + foreach (self::ADMIN_ROUTES_THAT_CAN_BE_RE_ENABLED[$reEnabledAdminSection] as $reEnabledAdminRoute) { + if (false !== strpos($route, $reEnabledAdminRoute)) { + return true; + } + } + } + + return false; + } } diff --git a/src/Provider/FeaturesProviderInterface.php b/src/Provider/FeaturesProviderInterface.php index f7706fe..66e23e2 100644 --- a/src/Provider/FeaturesProviderInterface.php +++ b/src/Provider/FeaturesProviderInterface.php @@ -18,4 +18,6 @@ interface FeaturesProviderInterface { public function isNoCommerceEnabledForChannel(?ChannelInterface $channel = null): bool; + + public function isRouteForcedEnabled(array $params = []): bool; } diff --git a/src/Resources/translations/messages.en.yaml b/src/Resources/translations/messages.en.yaml index 5ae20d2..8e2982c 100644 --- a/src/Resources/translations/messages.en.yaml +++ b/src/Resources/translations/messages.en.yaml @@ -7,3 +7,5 @@ monsieurbiz: label: Firewalls to be disabled enabled: label: Enabled + re_enabled_admin_routes: + label: Admin routes to re-enable diff --git a/src/Resources/translations/messages.fr.yaml b/src/Resources/translations/messages.fr.yaml index 73fe436..6d0f060 100644 --- a/src/Resources/translations/messages.fr.yaml +++ b/src/Resources/translations/messages.fr.yaml @@ -7,3 +7,5 @@ monsieurbiz: label: Firewalls à désactiver enabled: label: Activer + re_enabled_admin_routes: + label: Routes à réactiver pour l'admin diff --git a/src/Routing/NoCommerceRequestContext.php b/src/Routing/NoCommerceRequestContext.php index 90710c9..fac318b 100644 --- a/src/Routing/NoCommerceRequestContext.php +++ b/src/Routing/NoCommerceRequestContext.php @@ -41,9 +41,9 @@ public function __construct( $this->featuresProvider = $featuresProvider; } - public function checkNoCommerce(): bool + public function checkNoCommerce(array $params = []): bool { - return $this->featuresProvider->isNoCommerceEnabledForChannel(); + return $this->featuresProvider->isNoCommerceEnabledForChannel() && !$this->featuresProvider->isRouteForcedEnabled($params); } /**