diff --git a/Event/Subscriber/CheckReferenceDataOnRemovalSubscriber.php b/Event/Subscriber/CheckReferenceDataOnRemovalSubscriber.php index 1ae0a39e..c5631f3b 100644 --- a/Event/Subscriber/CheckReferenceDataOnRemovalSubscriber.php +++ b/Event/Subscriber/CheckReferenceDataOnRemovalSubscriber.php @@ -2,8 +2,11 @@ namespace Pim\Bundle\CustomEntityBundle\Event\Subscriber; +use Akeneo\Channel\Component\Repository\ChannelRepositoryInterface; +use Akeneo\Channel\Component\Repository\LocaleRepositoryInterface; use Akeneo\Pim\Enrichment\Component\Product\Query\Filter\Operators; use Akeneo\Pim\Enrichment\Component\Product\Query\ProductQueryBuilderFactoryInterface; +use Akeneo\Pim\Structure\Component\Model\AttributeInterface; use Akeneo\Tool\Component\StorageUtils\Event\RemoveEvent; use Akeneo\Tool\Component\StorageUtils\StorageEvents; use Doctrine\ORM\EntityManagerInterface; @@ -36,22 +39,34 @@ class CheckReferenceDataOnRemovalSubscriber implements EventSubscriberInterface /** @var EntityManagerInterface */ protected $em; + /** @var LocaleRepositoryInterface */ + private $localeRepository; + + /** @var ChannelRepositoryInterface */ + private $channelRepository; + /** * @param AttributeRepository $attributeRepository * @param ProductQueryBuilderFactoryInterface $pqbFactory * @param Registry $configRegistry * @param EntityManagerInterface $em + * @param LocaleRepositoryInterface $localeRepository + * @param ChannelRepositoryInterface $channelRepository */ public function __construct( AttributeRepository $attributeRepository, ProductQueryBuilderFactoryInterface $pqbFactory, Registry $configRegistry, - EntityManagerInterface $em + EntityManagerInterface $em, + LocaleRepositoryInterface $localeRepository, + ChannelRepositoryInterface $channelRepository ) { $this->attributeRepository = $attributeRepository; $this->pqbFactory = $pqbFactory; $this->configRegistry = $configRegistry; $this->em = $em; + $this->channelRepository = $channelRepository; + $this->localeRepository = $localeRepository; } /** @@ -120,19 +135,63 @@ public function checkReferenceDataUsage(RemoveEvent $event) protected function checkProductLink($attributes, array $referenceDataCode) { foreach ($attributes as $attribute) { - $pqb = $this->pqbFactory->create(); - $pqb->addFilter($attribute->getCode(), Operators::IN_LIST, $referenceDataCode); - $count = $pqb->execute()->count(); - - if (0 !== $count) { - throw new NonRemovableEntityException( - sprintf( - 'Reference data cannot be removed. It is linked to %s product(s) with the attribute "%s"', - $count, - $attribute->getCode() - ) - ); + $channelCodes = $this->channelRepository->getChannelCodes(); + $localeCodes = $this->localeRepository->getActivatedLocaleCodes(); + + if ($attribute->isScopable() && $attribute->isLocalizable()) { + //loop channels and locales + foreach ($channelCodes as $channelCode) { + foreach ($localeCodes as $localeCode) { + $context = [ + 'scope' => $channelCode, + 'locale' => $localeCode, + ]; + + $this->executeQueryWithFilter($referenceDataCode, $attribute, $context); + } + } + + return; } + + if ($attribute->isScopable()) { + //loop channels + foreach ($channelCodes as $channelCode) { + $context['scope'] = $channelCode; + $this->executeQueryWithFilter($referenceDataCode, $attribute, $context); + } + + return; + } + + if ($attribute->isLocalizable()) { + //loop locales + foreach ($localeCodes as $localeCode) { + $context['locale'] = $localeCode; + $this->executeQueryWithFilter($referenceDataCode, $attribute, $context); + } + + return; + } + + $this->executeQueryWithFilter($referenceDataCode, $attribute); + } + } + + private function executeQueryWithFilter($referenceDataCode, AttributeInterface $attribute, $context = []) + { + $pqb = $this->pqbFactory->create(); + $pqb->addFilter($attribute->getCode(), Operators::IN_LIST, $referenceDataCode, $context); + $count = $pqb->execute()->count(); + + if (0 !== $count) { + throw new NonRemovableEntityException( + sprintf( + 'Reference data cannot be removed. It is linked to %s product(s) with the attribute "%s"', + $count, + $attribute->getCode() + ) + ); } } } diff --git a/Resources/config/event_listeners.yml b/Resources/config/event_listeners.yml index 3f3b50f0..02b4eef1 100644 --- a/Resources/config/event_listeners.yml +++ b/Resources/config/event_listeners.yml @@ -24,5 +24,7 @@ services: - '@pim_catalog.query.product_and_product_model_query_builder_factory' - '@pim_custom_entity.configuration.registry' - '@doctrine.orm.entity_manager' + - '@pim_catalog.repository.locale' + - '@pim_catalog.repository.channel' tags: - { name: kernel.event_subscriber } diff --git a/Resources/config/requirejs.yml b/Resources/config/requirejs.yml index 797ac5c1..dc3ba2e6 100644 --- a/Resources/config/requirejs.yml +++ b/Resources/config/requirejs.yml @@ -12,6 +12,7 @@ config: custom_entity/controller/edit: pimcustomentity/js/controller/custom_entity-edit custom_entity/fetcher: pimcustomentity/js/fetcher/custom_entity-fetcher custom_entity/remover/reference-data: pimcustomentity/js/remover/reference-data-remover + oro/datagrid/delete-action: pimcustomentity/js/datagrid/action/delete-action config: pim/fetcher-registry: diff --git a/Resources/public/js/datagrid/action/delete-action.js b/Resources/public/js/datagrid/action/delete-action.js new file mode 100644 index 00000000..b2be22ec --- /dev/null +++ b/Resources/public/js/datagrid/action/delete-action.js @@ -0,0 +1,120 @@ +/* global define */ +define([ + 'underscore', + 'oro/messenger', + 'oro/translator', + 'pim/dialog', + 'oro/datagrid/model-action', + 'oro/mediator', + 'pim/user-context', + 'oro/datagrid/delete-confirm', + 'pim/fetcher-registry', +], function(_, messenger, __, Dialog, ModelAction, mediator, userContext, DeleteConfirm, FetcherRegistry) { + 'use strict'; + + /** + * Delete action with confirm dialog, triggers REST DELETE request + * + * @export oro/datagrid/delete-action + * @class oro.datagrid.DeleteAction + * @extends oro.datagrid.ModelAction + */ + return ModelAction.extend({ + errorModal: undefined, + + confirmModal: undefined, + + /** + * Initialize view + * + * @param {Object} options + * @param {Backbone.Model} options.model Optional parameter + * @throws {TypeError} If model is undefined + */ + initialize: function(options) { + options = options || {}; + + this.gridName = options.datagrid.name; + + ModelAction.prototype.initialize.apply(this, arguments); + }, + + /** + * Execute delete model + */ + execute: function() { + this.getConfirmDialog(); + }, + + /** + * Confirm delete item + */ + doDelete: function() { + this.model.id = true; + this.model.destroy({ + url: this.getLink(), + wait: true, + error: function(element, response) { + let contentType = response.getResponseHeader('content-type'); + let message = ''; + //Need to check if it is a json because the backend can return an error + if (contentType.indexOf('application/json') !== -1) { + const decodedResponse = JSON.parse(response.responseText); + if (undefined !== decodedResponse.message) { + message = decodedResponse.message; + } else { + message = response.responseJSON; + } + } + + this.showErrorFlashMessage(message); + }.bind(this), + success: function() { + var messageText = __('pim_enrich.entity.' + this.getEntityCode() + '.flash.delete.success'); + messenger.notify('success', messageText); + userContext.initialize(); + + mediator.trigger('grid_action_execute:product-grid:delete'); + mediator.trigger('datagrid:doRefresh:' + this.gridName); + if (this.gridName === 'association-type-grid') { + FetcherRegistry.getFetcher('association-type').clear(); + } + }.bind(this), + }); + }, + + /** + * Get view for confirm modal + */ + getConfirmDialog: function() { + this.confirmModal = DeleteConfirm.getConfirmDialog( + this.getEntityCode(), + this.doDelete.bind(this), + this.getEntityHint(true) + ); + + return this.confirmModal; + }, + + /** + * Get view for error modal + * + * @return {oro.Modal} + */ + showErrorFlashMessage: function(response) { + let message = ''; + + if (typeof response === 'string') { + message = response; + } else { + try { + message = JSON.parse(response).message; + } catch (e) { + message = __('pim_enrich.entity.' + this.getEntityHint() + '.flash.delete.fail'); + } + } + + messenger.notify('error', '' === message ? __('error.removing.' + this.getEntityHint()) : message); + }, + }); +});