Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 72 additions & 13 deletions Event/Subscriber/CheckReferenceDataOnRemovalSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

/**
Expand Down Expand Up @@ -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()
)
);
}
}
}
2 changes: 2 additions & 0 deletions Resources/config/event_listeners.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
1 change: 1 addition & 0 deletions Resources/config/requirejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
120 changes: 120 additions & 0 deletions Resources/public/js/datagrid/action/delete-action.js
Original file line number Diff line number Diff line change
@@ -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);
},
});
});