Skip to content
Closed
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
55 changes: 3 additions & 52 deletions modules/custom/activity_creator/activity_creator.install
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
* Installation code for the activity_creator module.
*/

use Drupal\activity_creator\ActivityInterface;
use Drupal\Core\Database\Database;
use Drupal\Core\Site\Settings;

/**
* Implements hook_schema().
Expand Down Expand Up @@ -142,56 +140,9 @@ function activity_creator_update_8801() {

/**
* Remove activities notification status if related entity not exist.
*
* @see activity_creator_post_update_8802_remove_activities_with_no_related_entities()
*/
function activity_creator_update_8802(&$sandbox) {
$database = Drupal::database();
if (!isset($sandbox['total'])) {
$query = $database->select('activity_notification_status', 'ans');
$query->addExpression('COUNT(*)');
$count = $query->execute()->fetchField();
$sandbox['total'] = $count;
$sandbox['current'] = 0;
}

// Activities per one batch operation.
$activities_per_batch = Settings::get('activity_update_batch_size', 100);

// Get activity IDs.
$aids = $database
->select('activity_notification_status', 'ans')
->fields('ans', ['aid'])
->range($sandbox['current'], $sandbox['current'] + $activities_per_batch)
->execute()
->fetchCol();

// Get activity storage.
$activity_storage = $activity = Drupal::entityTypeManager()
->getStorage('activity');

foreach ($aids as $aid) {
/** @var \Drupal\activity_creator\ActivityInterface $activity */
$activity = $activity_storage->load($aid);

if (!$activity instanceof ActivityInterface) {
$aids_for_delete[] = $aid;
}
elseif (is_null($activity->getRelatedEntity())) {
$activity_storage->delete([$activity]);
$aids_for_delete[] = $aid;
}

$sandbox['current']++;
}

if (!empty($aids_for_delete)) {
Drupal::service('activity_creator.activity_notifications')
->deleteNotificationsbyIds($aids_for_delete);
}

if ($sandbox['total'] == 0) {
$sandbox['#finished'] = 1;
}
else {
$sandbox['#finished'] = ($sandbox['current'] / $sandbox['total']);
}
// Removed in https://www.drupal.org/project/social/issues/3171563.
}
124 changes: 124 additions & 0 deletions modules/custom/activity_creator/activity_creator.post_update.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
* Contains post update hook implementations.
*/

use Drupal\activity_creator\ActivityInterface;
use Drupal\Core\Site\Settings;

/**
* Migrate all the activity status information to new table.
*
Expand Down Expand Up @@ -67,3 +70,124 @@ function activity_creator_post_update_8001_one_to_many_activities(&$sandbox) {
// Print some progress.
return t('@count activities data has been migrated to activity_notification_table.', ['@count' => $sandbox['current']]);
}

/**
* Remove activities notification status if related entity not exist.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
* @throws \Drupal\Core\Entity\EntityStorageException
*/
function activity_creator_post_update_8802_remove_activities_with_no_related_entities(&$sandbox) {
// On the first run, we gather all of our initial
// data as well as initialize all of our sandbox variables to be used in
// managing the future batch requests.
if (!isset($sandbox['progress'])) {
// To set up our batch process, we need to collect all of the
// necessary data during this initialization step, which will
// only ever be run once.
// We start the batch by running some SELECT queries up front
// as concisely as possible. The results of these expensive queries
// will be cached by the Batch API so we do not have to look up
// this data again during each iteration of the batch.
$database = \Drupal::database();

// Get activity IDs.
/** @var \Drupal\Core\Database\Query\Select $query */
$activity_ids = $database->select('activity_notification_status', 'ans')
->fields('ans', ['aid'])
->execute()
->fetchCol();

// Now we initialize the sandbox variables.
// These variables will persist across the Batch API’s subsequent calls
// to our update hook, without us needing to make those initial
// expensive SELECT queries above ever again.
// 'max' is the number of total records we’ll be processing.
$sandbox['max'] = count($activity_ids);
// If 'max' is empty, we have nothing to process.
if (empty($sandbox['max'])) {
$sandbox['#finished'] = 1;
return;
}

// 'progress' will represent the current progress of our processing.
$sandbox['progress'] = 0;

// 'activities_per_batch' is a custom amount that we’ll use to limit
// how many activities we’re processing in each batch.
// This is a large part of how we limit expensive batch operations.
$sandbox['activities_per_batch'] = Settings::get('activity_update_batch_size', 100);

// 'activities_id' will store the activity IDs from activity notification
// table that we just queried for above during this initialization phase.
$sandbox['activities_id'] = $activity_ids;
}

// Initialization code done. The following code will always run:
// both during the first run AND during any subsequent batches.
// Now let’s remove the missing activity ids.
$activity_storage = \Drupal::entityTypeManager()->getStorage('activity');

// Calculates current batch range.
$range_end = $sandbox['progress'] + $sandbox['activities_per_batch'];
if ($range_end > $sandbox['max']) {
$range_end = $sandbox['max'];
}

// Loop over current batch range, creating a new BAR node each time.
for ($i = $sandbox['progress']; $i < $range_end; $i++) {

// Take activity ids from $sandbox['activities_id'].
$activity_id = $sandbox['activities_id'][$i];

/** @var \Drupal\activity_creator\ActivityInterface $activity */
$activity = $activity_storage->load($activity_id);

// Add invalid ids for deletion.
if (!$activity instanceof ActivityInterface) {
$aids_for_delete[] = $activity_id;
}
// Add not required $activity.
elseif (is_null($activity->getRelatedEntity())) {
$entity_ids[] = $activity_id;
$activities_for_delete[$activity_id] = $activity;
}
else {
// If the database has more than 100K of activities to be processed
// Drupal will generate a lot of static cache, as we are using load
// function above. So, it is necessary to reset cache in order to
// prevent memory outage.
$activity_storage->resetCache([$activity_id]);
}
}

// Remove notifications.
if (!empty($aids_for_delete)) {
\Drupal::service('activity_creator.activity_notifications')
->deleteNotificationsbyIds($aids_for_delete);
}

// Delete not required activity entities.
if (!empty($activities_for_delete)) {
$activity_storage->delete($activities_for_delete);
}

// Update the batch variables to track our progress.
// We can calculate our current progress via a mathematical fraction.
// Drupal’s Batch API will stop executing our update hook as soon as
// $sandbox['#finished'] == 1 (viz., it evaluates to TRUE).
$sandbox['progress'] = $range_end;
$progress_fraction = $sandbox['progress'] / $sandbox['max'];
$sandbox['#finished'] = empty($sandbox['max']) ? 1 : $progress_fraction;

// While processing our batch requests, we can send a helpful message
// to the command line, so developers can track the batch progress.
if (function_exists('drush_print')) {
drush_print('Progress: ' . (round($progress_fraction * 100)) . '% (' .
$sandbox['progress'] . ' of ' . $sandbox['max'] . ' activities processed)');
}

// That’s it!
// The update hook and Batch API manage the rest of the process.
}