From e24feefa85b0c7a31ef207af2ebbb02e8afa6a16 Mon Sep 17 00:00:00 2001
From: florenttorregrosa <florenttorregrosa@2388214.no-reply.drupal.org>
Date: Wed, 29 Nov 2017 16:38:49 +0100
Subject: [PATCH] Issue #2923632 by rbmboogie, Grimreaper: Allow references to
 be removed on sync

---
 .../src/Service/JsonapiHelper.php                  | 86 +++++++++++++---------
 1 file changed, 52 insertions(+), 34 deletions(-)

diff --git a/modules/entity_share_client/src/Service/JsonapiHelper.php b/modules/entity_share_client/src/Service/JsonapiHelper.php
index 8d38227..fd5794e 100644
--- a/modules/entity_share_client/src/Service/JsonapiHelper.php
+++ b/modules/entity_share_client/src/Service/JsonapiHelper.php
@@ -8,6 +8,8 @@ use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface;
 use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Field\EntityReferenceFieldItemListInterface;
+use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Language\LanguageManager;
 use Drupal\Core\Language\LanguageManagerInterface;
 use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
@@ -219,7 +221,8 @@ class JsonapiHelper implements JsonapiHelperInterface {
     if (isset($data['relationships'])) {
       // Reference fields.
       foreach ($data['relationships'] as $field_name => $field_data) {
-        if ($this->relationshipHandleable($field_data)) {
+        $field = $entity->get($field_name);
+        if ($this->relationshipHandleable($field)) {
           $field_values = [];
 
           if (isset($field_data['links']) && isset($field_data['links']['related'])) {
@@ -231,7 +234,6 @@ class JsonapiHelper implements JsonapiHelperInterface {
             if (!isset($referenced_entities_json['errors'])) {
               $referenced_entities_ids = $this->importEntityListData($referenced_entities_json['data']);
 
-              $field = $entity->get($field_name);
               $main_property = $field->getItemDefinition()->getMainPropertyName();
 
               // Add field metadatas.
@@ -329,6 +331,11 @@ class JsonapiHelper implements JsonapiHelperInterface {
         ->getStorage($parsed_type[0])
         ->loadByProperties(['uuid' => $entity_data['attributes'][$entity_keys['uuid']]]);
 
+      // Here is the supposition that we are importing a list of content
+      // entities. Currently this is ensured by the fact that it is not possible
+      // to make a channel on config entities and on users. And that in the
+      // relationshipHandleable() method we prevent handling config entities and
+      // users relationships.
       /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
       $entity = $this->extractEntity($entity_data);
 
@@ -500,47 +507,38 @@ class JsonapiHelper implements JsonapiHelperInterface {
   /**
    * Check if a relationship is handleable.
    *
-   * Filter on fields:
-   * - with data only
-   * - not targeting config entities or users.
+   * Filter on fields not targeting config entities or users.
    *
-   * @param array $field_data
-   *   The array of relationship field data.
+   * @param \Drupal\Core\Field\FieldItemListInterface $field
+   *   The field item list.
    *
    * @return bool
    *   TRUE if the relationship is handleable.
    */
-  protected function relationshipHandleable(array $field_data) {
-    // Check empty field.
-    if ($field_data['data'] == NULL) {
-      return FALSE;
-    }
-
-    if ($this->isNumericArray($field_data['data'])) {
-      $type = $field_data['data'][0]['type'];
-    }
-    else {
-      $type = $field_data['data']['type'];
-    }
+  protected function relationshipHandleable(FieldItemListInterface $field) {
+    $relationship_handleable = FALSE;
 
-    $type_data = explode('--', $type);
-    $entity_type_id = $type_data[0];
+    if ($field instanceof EntityReferenceFieldItemListInterface) {
+      $settings = $field->getItemDefinition()->getSettings();
 
-    // User.
-    if ($entity_type_id == 'user') {
-      return FALSE;
-    }
-    // Unknown entity type.
-    elseif (!isset($this->entityDefinitions[$entity_type_id])) {
-      drupal_set_message($this->t('There is a reference to an unknown entity type %entity_type.', ['%entity_type' => $entity_type_id]), 'warning');
-      return FALSE;
-    }
-    // Config entity type.
-    elseif ($this->entityDefinitions[$entity_type_id]->getGroup() == 'configuration') {
-      return FALSE;
+      // TODO: Other field types that inherit from entity reference should be
+      // handled automatically or using a plugin/event system if possible.
+      // Entity reference and Entity reference revisions.
+      if (isset($settings['target_type'])) {
+        $relationship_handleable = !$this->isUserOrConfigEntity($settings['target_type']);
+      }
+      // Dynamic entity reference.
+      elseif (isset($settings['entity_type_ids'])) {
+        foreach ($settings['entity_type_ids'] as $entity_type_id) {
+          $relationship_handleable = !$this->isUserOrConfigEntity($entity_type_id);
+          if (!$relationship_handleable) {
+            break;
+          }
+        }
+      }
     }
 
-    return TRUE;
+    return $relationship_handleable;
   }
 
   /**
@@ -725,4 +723,24 @@ class JsonapiHelper implements JsonapiHelperInterface {
     return $status_info;
   }
 
+  /**
+   * Helper function to check if an entity type id is a user or a config entity.
+   *
+   * @param string $entity_type_id
+   *   The entity type id.
+   *
+   * @return bool
+   *   TRUE if the entity type is user or a config entity. FALSE otherwise.
+   */
+  protected function isUserOrConfigEntity($entity_type_id) {
+    if ($entity_type_id == 'user') {
+      return TRUE;
+    }
+    elseif ($this->entityDefinitions[$entity_type_id]->getGroup() == 'configuration') {
+      return TRUE;
+    }
+
+    return FALSE;
+  }
+
 }
-- 
1.9.1

