Commit b702bd0b authored by Dropa's avatar Dropa Committed by RoSk0

Issue #2709315 by RoSk0, Dropa, edurenye: Decouple the orphaned activities cleanup.

parent a63671be
......@@ -4,3 +4,78 @@
* @file
* Provides an entity for recording a contact's activities.
*/
use Drupal\Core\Entity\EntityInterface;
/**
* Implements hook_entity_predelete() for CRM Core Contact entities.
*/
function crm_core_activity_entity_predelete(EntityInterface $entity) {
switch ($entity->getEntityTypeId()) {
case 'crm_core_individual':
crm_core_activity_pre_delete_checker($entity);
break;
case 'crm_core_organization':
crm_core_activity_pre_delete_checker($entity);
break;
}
}
/**
* Looks for activities to be removed.
*
* Separate function for running for both Individual and Organization.
* If current entity to be deleted was only participant in Activity, that
* activity will be removed.
*
* @param Drupal\Core\Entity\EntityInterface $entity
* The entity ID to be looked for from participants.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Core\Entity\EntityStorageException
*/
function crm_core_activity_pre_delete_checker(EntityInterface $entity) {
$activities_to_remove = [];
$entity_id = $entity->id();
$entity_type = $entity->getEntityTypeId();
$activity_storage = \Drupal::entityTypeManager()->getStorage('crm_core_activity');
$query = \Drupal::entityQuery('crm_core_activity');
$activity_ids = $query
->condition('activity_participants.target_id', $entity_id)
->condition('activity_participants.target_type', $entity_type)
->execute();
if (empty($activity_ids)) {
// No related Activities.
return;
}
// Load fully populated Activity objects to analyze/update.
$crm_core_activities = $activity_storage->loadMultiple($activity_ids);
foreach ($crm_core_activities as $crm_core_activity) {
/** @var \Drupal\crm_core_activity\Entity\Activity $crm_core_activity */
$participants = $crm_core_activity->get('activity_participants')->getValue();
// Remove Individual from participants array.
$participants = array_diff(array_column($participants, 'target_id'), [$entity_id]);
if (empty($participants)) {
// Last main participant was deleted, so we should kill entire activity.
$activities_to_remove[] = $crm_core_activity->id();
}
else {
// Save Activity with renewed list.
$crm_core_activity->set('activity_participants', $participants);
$crm_core_activity->save();
}
}
if (!empty($activities_to_remove)) {
$activities = $activity_storage->loadMultiple($activities_to_remove);
\Drupal::logger('crm_core_activity')->info('Deleted @count activities due to deleting @type id=%individual_id.', [
'@count' => count($activities_to_remove),
'@type' => $entity_type,
'%individual_id' => $entity_id,
]);
$activity_storage->delete($activities);
}
}
<?php
namespace Drupal\Tests\crm_core_activity\Kernel;
use Drupal\crm_core_activity\Entity\Activity;
use Drupal\crm_core_activity_plugin_test\Plugin\crm_core_activity\ActivityType\ActivityTypeWithConfig;
use Drupal\crm_core_activity\Plugin\crm_core_activity\ActivityType\Generic;
use Drupal\crm_core_contact\Entity\Individual;
use Drupal\KernelTests\KernelTestBase;
/**
* Tests crm_core_activity_entity_predelete().
*
* @group crm_core
* @covers crm_core_activity_entity_predelete
*/
class ActivityEntityPreDeleteTest extends KernelTestBase {
/**
* Plugin manager for ActivityType.
*
* @var \Drupal\crm_core_activity\ActivityTypePluginManager
*/
protected $pluginManager;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = [
'crm_core_activity_plugin_test',
'user',
'crm_core_activity',
'crm_core_contact',
'text',
'dynamic_entity_reference',
'datetime',
'name',
'options',
];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('crm_core_activity');
$this->installEntitySchema('crm_core_individual');
$this->pluginManager = $this->container->get('plugin.manager.crm_core_activity.activity_type');
}
/**
* Tests activity type plugin.
*/
public function testContactPreDelete() {
/** @var \Drupal\crm_core_activity\Entity\ActivityType $activity_type */
$activity_type = $this->container->get('entity_type.manager')
->getStorage('crm_core_activity_type')
->create(
[
'name' => 'Test type',
'type' => 'test_type',
'description' => 'Test type description.',
'plugin_id' => 'generic',
]
);
$activity_type->save();
$individual_1 = Individual::create([
'type' => 'customer',
'name' => ['given' => 'John', 'family' => 'Smith'],
'email_value' => 'test1@example.com',
'email_type' => 'private',
]);
$individual_1->save();
$individual_2 = Individual::create([
'type' => 'customer',
'name' => ['given' => 'Mark', 'family' => 'Jones'],
'email_value' => 'test2@example.com',
'email_type' => 'corporate',
]);
$individual_2->save();
$activity_1 = Activity::create([
'type' => 'test_type',
'title' => 'Activity title',
'activity_participants' => [$individual_1, $individual_2],
]);
$activity_1->save();
$activity_2 = Activity::create([
'type' => 'test_type',
'title' => 'Activity title 2',
'activity_participants' => [$individual_2],
]);
$activity_2->save();
$individual_2->delete();
$loaded_activity = Activity::load($activity_2->id());
$this->assertNull($loaded_activity, 'Activity 2 was deleted.');
$loaded_activity = Activity::load($activity_1->id());
$this->assertTrue((bool) $loaded_activity, 'Activity 1 was loaded.');
$individual_1->delete();
$loaded_activity = Activity::load($activity_1->id());
$this->assertNull($loaded_activity, 'Activity 1 was deleted.');
}
}
......@@ -7,7 +7,6 @@ use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\crm_core\EntityOwnerTrait;
use Drupal\crm_core_activity\Entity\Activity;
use Drupal\crm_core_contact\IndividualInterface;
use Drupal\field\FieldStorageConfigInterface;
use Drupal\entity\Revision\RevisionableContentEntityBase;
......@@ -221,55 +220,6 @@ class Individual extends RevisionableContentEntityBase implements IndividualInte
$record->uid = $account->id();
}
/**
* {@inheritdoc}
*/
public static function preDelete(EntityStorageInterface $storage, array $entities) {
parent::preDelete($storage, $entities);
$query = \Drupal::entityQuery('crm_core_activity');
$activity_ids = $query
->condition('activity_participants.target_id', array_keys($entities), 'IN')
->condition('activity_participants.target_type', 'crm_core_individual')
->execute();
if (empty($activity_ids)) {
// No related Activities.
return;
}
// Load fully populated Activity objects to analyze/update.
$crm_core_activities = Activity::loadMultiple($activity_ids);
$activities_to_remove = [];
foreach ($crm_core_activities as $crm_core_activity) {
/** @var \Drupal\crm_core_activity\Entity\Activity $crm_core_activity */
$participants = $crm_core_activity->get('activity_participants')->getValue();
// Remove Individual from participants array.
$participants = array_diff(array_column($participants, 'target_id'), array_keys($entities));
if (empty($participants)) {
// Last main participant was deleted, so we should kill entire activity.
$activities_to_remove[] = $crm_core_activity->id();
}
else {
// Save Activity with renewed list.
$crm_core_activity->set('activity_participants', $participants);
$crm_core_activity->save();
}
}
if (!empty($activities_to_remove)) {
$crm_core_activity_storage = \Drupal::entityTypeManager()->getStorage('crm_core_activity');
$activities = $crm_core_activity_storage->loadMultiple($activities_to_remove);
$ids = array_keys($entities);
\Drupal::logger('crm_core_activity')->info('Deleted @count activities due to deleting individual id=%individual_id.', [
'@count' => count($activities_to_remove),
'%individual_id' => reset($ids),
]);
$crm_core_activity_storage->delete($activities);
}
}
/**
* Gets the primary address.
*
......
......@@ -3,7 +3,6 @@
namespace Drupal\crm_core_contact\Entity;
use Drupal\Core\Entity\EntityChangedTrait;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\crm_core\EntityOwnerTrait;
......@@ -109,57 +108,6 @@ class Organization extends RevisionableContentEntityBase implements ContactInter
return $fields;
}
/**
* {@inheritdoc}
*/
public static function preDelete(EntityStorageInterface $storage, array $entities) {
parent::preDelete($storage, $entities);
$query = \Drupal::entityQuery('crm_core_activity');
$activity_ids = $query
->condition('activity_participants.target_id', array_keys($entities), 'IN')
->condition('activity_participants.target_type', 'crm_core_organization')
->execute();
if (empty($activity_ids)) {
// No related Activities.
return;
}
$crm_core_activity_storage = \Drupal::entityTypeManager()->getStorage('crm_core_activity');
// Load fully populated Activity objects to analyze/update.
$crm_core_activities = $crm_core_activity_storage->loadMultiple($activity_ids);
$activities_to_remove = [];
foreach ($crm_core_activities as $crm_core_activity) {
/** @var \Drupal\crm_core_activity\Entity\Activity $crm_core_activity */
$participants = $crm_core_activity->get('activity_participants')->getValue();
// Remove Organization from participants array.
$participants = array_diff(array_column($participants, 'target_id'), array_keys($entities));
if (empty($participants)) {
// Last main participant was deleted, so we should kill entire activity.
$activities_to_remove[] = $crm_core_activity->id();
}
else {
// Save Activity with renewed list.
$crm_core_activity->set('activity_participants', $participants);
$crm_core_activity->save();
}
}
if (!empty($activities_to_remove)) {
$activities = $crm_core_activity_storage->loadMultiple($activities_to_remove);
$ids = array_keys($entities);
\Drupal::logger('crm_core_activity')->info('Deleted @count activities due to deleting organization id=%organization_id.', [
'@count' => count($activities_to_remove),
'%organization_id' => reset($ids),
]);
$crm_core_activity_storage->delete($activities);
}
}
/**
* Gets the primary address.
*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment