From 2580ff8f38a00f5782ab0cbe8d1f5eb69119568b Mon Sep 17 00:00:00 2001 From: "Christopher O. Caldwell" Date: Tue, 5 Mar 2024 17:07:40 -0700 Subject: [PATCH 1/3] Enhance entity creation with base field expansion and dynamic id key gh-270 --- src/Drupal/Driver/Cores/Drupal8.php | 93 ++++++++++++++--------------- 1 file changed, 45 insertions(+), 48 deletions(-) diff --git a/src/Drupal/Driver/Cores/Drupal8.php b/src/Drupal/Driver/Cores/Drupal8.php index ddbdf18..d079170 100644 --- a/src/Drupal/Driver/Cores/Drupal8.php +++ b/src/Drupal/Driver/Cores/Drupal8.php @@ -97,13 +97,8 @@ public function nodeCreate($node) { $node->uid = $user->id(); } } - $this->expandEntityFields('node', $node); - $entity = Node::create((array) $node); - $entity->save(); - $node->nid = $entity->id(); - - return $node; + return $this->entityCreate('node', $node); } /** @@ -134,14 +129,7 @@ public function userCreate(\stdClass $user) { $user->status = 1; } - // Clone user object, otherwise user_save() changes the password to the - // hashed password. - $this->expandEntityFields('user', $user); - $account = \Drupal::entityTypeManager()->getStorage('user')->create((array) $user); - $account->save(); - - // Store UID. - $user->uid = $account->id(); + return $this->entityCreate('user', $user); } /** @@ -344,12 +332,7 @@ public function termCreate(\stdClass $term) { } } - $this->expandEntityFields('taxonomy_term', $term); - $entity = Term::create((array) $term); - $entity->save(); - - $term->tid = $entity->id(); - return $term; + return $this->entityCreate('taxonomy_term', $term); } /** @@ -383,20 +366,6 @@ public function getExtensionPathList() { return $paths; } - /** - * Expands specified base fields on the entity object. - * - * @param string $entity_type - * The entity type for which to return the field types. - * @param \StdClass $entity - * Entity object. - * @param array $base_fields - * Base fields to be expanded in addition to user defined fields. - */ - public function expandEntityBaseFields($entity_type, \StdClass $entity, array $base_fields) { - $this->expandEntityFields($entity_type, $entity, $base_fields); - } - /** * {@inheritdoc} */ @@ -496,31 +465,56 @@ public function configSet($name, $key, $value) { * {@inheritdoc} */ public function entityCreate($entity_type, $entity) { + if (empty($entity_type)) { + throw new \Exception("You must specify an entity type to create an entity."); + } + + $entity_type_definition = \Drupal::entityTypeManager() + ->getDefinition($entity_type); + $id_key = $entity_type_definition + ->getKey('id'); + $bundle_key = $entity_type_definition + ->getKey('bundle'); + // If the bundle field is empty, put the inferred bundle value in it. - $bundle_key = \Drupal::entityTypeManager()->getDefinition($entity_type)->getKey('bundle'); - if (!isset($entity->$bundle_key) && isset($entity->step_bundle)) { - $entity->$bundle_key = $entity->step_bundle; + // Try first for step_bundle. Use entity type as last resort. + if (!isset($entity->$bundle_key)) { + $entity->$bundle_key = $entity->step_bundle ?? $entity_type; } // Throw an exception if a bundle is specified but does not exist. - if (isset($entity->$bundle_key) && ($entity->$bundle_key !== NULL)) { - /** @var \Drupal\Core\Entity\EntityTypeBundleInfo $bundle_info */ - $bundle_info = \Drupal::service('entity_type.bundle.info'); - $bundles = $bundle_info->getBundleInfo($entity_type); + if (isset($entity->$bundle_key)) { + $bundles = \Drupal::service('entity_type.bundle.info') + ->getBundleInfo($entity_type); if (!in_array($entity->$bundle_key, array_keys($bundles))) { throw new \Exception("Cannot create entity because provided bundle '$entity->$bundle_key' does not exist."); } } - if (empty($entity_type)) { - throw new \Exception("You must specify an entity type to create an entity."); + + // Determine which base fields are set on the source entity object so we + // can include them when expanding field values. + $base_fields = []; + foreach (array_keys(\Drupal::service('entity_field.manager')->getBaseFieldDefinitions($entity_type)) as $base_field_name) { + // The bundle field does not need expanding, so we exclude it even if set. + if (property_exists($entity, $base_field_name) && $base_field_name !== $bundle_key) { + $base_fields[] = $base_field_name; + } } - $this->expandEntityFields($entity_type, $entity); - $createdEntity = \Drupal::entityTypeManager()->getStorage($entity_type)->create((array) $entity); - $createdEntity->save(); + // Expand all fields that are set on the source entity object into a new + // values object we'll use to create the actual entity. This keeps the + // source entity object in the simpler format expected by related methods. + $values = clone $entity; + $this->expandEntityFields($entity_type, $values, $base_fields); - $entity->id = $createdEntity->id(); + // Create the new entity. + $createdEntity = \Drupal::entityTypeManager() + ->getStorage($entity_type) + ->create((array) $values); + $createdEntity->save(); + // Store the ID of the new entity into our source entity and return it. + $entity->$id_key = $createdEntity->id(); return $entity; } @@ -528,7 +522,10 @@ public function entityCreate($entity_type, $entity) { * {@inheritdoc} */ public function entityDelete($entity_type, $entity) { - $entity = $entity instanceof EntityInterface ? $entity : \Drupal::entityTypeManager()->getStorage($entity_type)->load($entity->id); + $id_key = \Drupal::entityTypeManager() + ->getDefinition($entity_type) + ->getKey('id'); + $entity = $entity instanceof EntityInterface ? $entity : \Drupal::entityTypeManager()->getStorage($entity_type)->load($entity->$id_key); if ($entity instanceof EntityInterface) { $entity->delete(); } From b31df4bf62d028bbc96edf6b30da0a93fd548d6a Mon Sep 17 00:00:00 2001 From: "Christopher O. Caldwell" Date: Wed, 6 Mar 2024 17:13:30 -0700 Subject: [PATCH 2/3] Remove double-expansion when $node->author is translated to $node->uid gh-270 --- src/Drupal/Driver/Cores/Drupal8.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Drupal/Driver/Cores/Drupal8.php b/src/Drupal/Driver/Cores/Drupal8.php index d079170..9ff3854 100644 --- a/src/Drupal/Driver/Cores/Drupal8.php +++ b/src/Drupal/Driver/Cores/Drupal8.php @@ -91,11 +91,7 @@ public function nodeCreate($node) { } // If 'author' is set, remap it to 'uid'. if (isset($node->author)) { - $user = user_load_by_name($node->author); - /** @var \Drupal\user\Entity\User $user */ - if ($user) { - $node->uid = $user->id(); - } + $node->uid = $node->author; } return $this->entityCreate('node', $node); From 7a642b84e7f4aa765fa04b26abf6a83827ab3af2 Mon Sep 17 00:00:00 2001 From: "Christopher O. Caldwell" Date: Thu, 7 Mar 2024 09:54:56 -0700 Subject: [PATCH 3/3] Consistently pass an array of field values to field handlers for expansion Per FieldHandlerInterface::expand(), field handlers expect an array of field values. The source entity object passed into expandEntityFields() often has an inconsistent structure across its various field properties, sometimes holding a single value, sometimes holding an array of values (as expected), and sometimes holding an array of composite field parts for a single field value. Consistently providing field handlers the field values in the structure they expect allows them to expand each field value correctly. gh-270 --- src/Drupal/Driver/Cores/AbstractCore.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Drupal/Driver/Cores/AbstractCore.php b/src/Drupal/Driver/Cores/AbstractCore.php index 89b1e01..4520bc1 100644 --- a/src/Drupal/Driver/Cores/AbstractCore.php +++ b/src/Drupal/Driver/Cores/AbstractCore.php @@ -81,6 +81,9 @@ protected function expandEntityFields($entity_type, \stdClass $entity, array $ba $field_types = $this->getEntityFieldTypes($entity_type, $base_fields); foreach ($field_types as $field_name => $type) { if (isset($entity->$field_name)) { + // Consistently expand into an array of field values. + $entity->$field_name = !isset($entity->$field_name[0]) ? [$entity->$field_name] : $entity->$field_name; + // Expand array of field values using appropriate field handler. $entity->$field_name = $this->getFieldHandler($entity, $entity_type, $field_name) ->expand($entity->$field_name); }