From 06c0c8eabb515875a840f3876145f2f533b9f374 Mon Sep 17 00:00:00 2001
From: "Andrew Crook (Somersoft)" <andrew.crook@somersoft.co.uk>
Date: Tue, 6 May 2025 17:13:43 +0100
Subject: [PATCH] For Issue #3198011 Add the patch found at
 https://www.drupal.org/files/issues/2023-01-03/rules-field_item_list_management-3198011-7.patch
 Found that the Add functionality removed list items as it checked to see if
 the item was present. Updated the code to not remove them

---
 src/Plugin/RulesAction/FieldItemListAdd.php   | 95 +++++++++++++++++++
 .../RulesAction/FieldItemListRemove.php       | 55 +++++++++++
 2 files changed, 150 insertions(+)
 create mode 100644 src/Plugin/RulesAction/FieldItemListAdd.php
 create mode 100644 src/Plugin/RulesAction/FieldItemListRemove.php

diff --git a/src/Plugin/RulesAction/FieldItemListAdd.php b/src/Plugin/RulesAction/FieldItemListAdd.php
new file mode 100644
index 00000000..05226703
--- /dev/null
+++ b/src/Plugin/RulesAction/FieldItemListAdd.php
@@ -0,0 +1,95 @@
+<?php
+
+namespace Drupal\rules\Plugin\RulesAction;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\rules\Core\RulesActionBase;
+
+/**
+ * Provides an 'Add to field item list' action.
+ *
+ * @RulesAction(
+ *   id = "rules_field_list_item_add",
+ *   label = @Translation("Add to field item list"),
+ *   category = @Translation("Data"),
+ *   context_definitions = {
+ *     "list" = @ContextDefinition("list",
+ *       label = @Translation("List"),
+ *       description = @Translation("The field item list, to which an item is to be added."),
+ *       assignment_restriction = "selector"
+ *     ),
+ *     "item" = @ContextDefinition("any",
+ *       label = @Translation("Item"),
+ *       description = @Translation("Item to add.")
+ *     ),
+ *     "unique" = @ContextDefinition("boolean",
+ *       label = @Translation("Enforce uniqueness"),
+ *       description = @Translation("Only add the item to the list if it is not yet contained."),
+ *       default_value = FALSE,
+ *       required = FALSE
+ *     ),
+ *     "position" = @ContextDefinition("string",
+ *       label = @Translation("Insert position"),
+ *       description = @Translation("Position to insert the item."),
+ *       default_value = "end",
+ *       required = FALSE
+ *     ),
+ *   }
+ * )
+ *
+ * @todo Add access callback information from Drupal 7?
+ */
+class FieldItemListAdd extends RulesActionBase {
+
+  /**
+   * Add an item to a list.
+   *
+   * @param \Drupal\Core\Field\FieldItemListInterface $list
+   *   A list to which an item is added.
+   * @param \Drupal\Core\Entity\EntityInterface $item
+   *   An item being added to the list.
+   * @param bool $unique
+   *   (optional) Whether or not we can add duplicate items.
+   * @param string $position
+   *   (optional) Determines if item will be added at beginning or end.
+   *   Allowed values:
+   *   - "start": Add to beginning of the list.
+   *   - "end": Add to end of the list.
+   */
+  protected function doExecute(FieldItemListInterface $list, EntityInterface $item, $unique = FALSE, $position = 'end') {
+    if ($list->isEmpty()) {
+      $list->appendItem($item);
+    }
+    else {
+      if ($unique) {
+        // Optionally, only add the list item if it is not yet contained.
+        $id = $item->id();
+        $filtered_list = clone $list;
+        $filtered_list->filter(function ($list_item) use ($id) {
+          return $list_item->get($list_item->mainPropertyName())
+            ->getValue() == $id;
+        });
+        if ($filtered_list->isEmpty()) {
+          if ($position === 'start') {
+            array_unshift($list, $item);
+          }
+          else {
+            $list->appendItem($item);
+          }
+        }
+      }
+      else {
+        if ($position === 'start') {
+          array_unshift($list, $item);
+        }
+        else {
+          $list->appendItem($item);
+        }
+      }
+    }
+
+    $this->setContextValue('list', $list);
+  }
+
+}
diff --git a/src/Plugin/RulesAction/FieldItemListRemove.php b/src/Plugin/RulesAction/FieldItemListRemove.php
new file mode 100644
index 00000000..623c1024
--- /dev/null
+++ b/src/Plugin/RulesAction/FieldItemListRemove.php
@@ -0,0 +1,55 @@
+<?php
+
+namespace Drupal\rules\Plugin\RulesAction;
+
+use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\rules\Core\RulesActionBase;
+
+/**
+ * Provides a 'Remove item from list' action.
+ *
+ * @RulesAction(
+ *   id = "rules_field_list_item_remove",
+ *   label = @Translation("Remove item from field item list"),
+ *   category = @Translation("Data"),
+ *   context_definitions = {
+ *     "list" = @ContextDefinition("list",
+ *       label = @Translation("List"),
+ *       description = @Translation("The field list from which an item is to be removed."),
+ *       assignment_restriction = "selector"
+ *     ),
+ *     "item" = @ContextDefinition("any",
+ *       label = @Translation("Item"),
+ *       description = @Translation("Item to remove.")
+ *     ),
+ *   }
+ * )
+ *
+ * @todo Add access callback information from Drupal 7.
+ */
+class FieldItemListRemove extends RulesActionBase {
+
+  /**
+   * Removes an item from a list.
+   *
+   * @param \Drupal\Core\Field\FieldItemListInterface $list
+   *   An array to remove an item from.
+   * @param \Drupal\Core\Entity\EntityInterface $item
+   *   An item to remove from the array.
+   */
+  protected function doExecute(FieldItemListInterface $list, EntityInterface $item) {
+    if (!$list->isEmpty()) {
+      $id = $item->id();
+      foreach ($list->getIterator() as $key => $value) {
+        if ($value->get($value->mainPropertyName())->getValue() == $id) {
+          $list->removeItem($key);
+          break;
+        }
+      }
+    }
+
+    $this->setContextValue('list', $list);
+  }
+
+}
-- 
GitLab