diff --git a/src/Drupal/Driver/BaseDriver.php b/src/Drupal/Driver/BaseDriver.php index ff8d3b5d..f4bb3f6e 100644 --- a/src/Drupal/Driver/BaseDriver.php +++ b/src/Drupal/Driver/BaseDriver.php @@ -116,6 +116,13 @@ public function roleDelete($rid) { throw new UnsupportedDriverActionException($this->errorString('delete roles'), $this); } + /** + * {@inheritDoc} + */ + public function isField($entity_type, $field_name) { + return FALSE; + } + /** * Error printing exception * diff --git a/src/Drupal/Driver/Cores/AbstractCore.php b/src/Drupal/Driver/Cores/AbstractCore.php new file mode 100644 index 00000000..21162ba5 --- /dev/null +++ b/src/Drupal/Driver/Cores/AbstractCore.php @@ -0,0 +1,49 @@ +getShortName(); + $field_types = $this->getEntityFieldTypes($entity_type); + $camelized_type = Container::camelize($field_types[$field_name]); + $default_class = sprintf('\Drupal\Driver\Fields\%s\DefaultHandler', $core_namespace); + $class_name = sprintf('\Drupal\Driver\Fields\%s\%sHandler', $core_namespace, $camelized_type); + if (class_exists($class_name)) { + return new $class_name($entity_type, $field_name); + } + return new $default_class($entity_type, $field_name); + } + + /** + * Given a entity, expand fields to match the format expected by entity_save(). + * + * @param \stdClass $entity + * Entity object. + * @return \stdClass + * Entity object. + */ + protected function expandEntityFields($entity_type, \stdClass $entity) { + + $field_types = $this->getEntityFieldTypes($entity_type); + foreach ($field_types as $field_name => $type) { + if (isset($entity->$field_name)) { + $entity->$field_name = $this->getFieldHandler($entity_type, $field_name)->expand($entity->$field_name); + } + } + } + +} diff --git a/src/Drupal/Driver/Cores/CoreInterface.php b/src/Drupal/Driver/Cores/CoreInterface.php index 1557abdf..e3cc7488 100644 --- a/src/Drupal/Driver/Cores/CoreInterface.php +++ b/src/Drupal/Driver/Cores/CoreInterface.php @@ -117,4 +117,33 @@ public function roleCreate(array $permissions); */ public function roleDelete($role_name); + /** + * Get FieldHandler class. + * + * @param $entity_type + * Entity type machine name. + * @param $field_name + * Field machine name. + * @return \Drupal\Driver\Fields\FieldHandlerInterface + */ + public function getFieldHandler($entity_type, $field_name); + + /** + * Check if the specified field is an actual Drupal field. + * + * @param $entity_type + * @param $field_name + * @return boolean + */ + public function isField($entity_type, $field_name); + + /** + * Return array of field types for the specified entity + * keyed by their field names. + * + * @param $entity_type + * @return array + */ + public function getEntityFieldTypes($entity_type); + } diff --git a/src/Drupal/Driver/Cores/Drupal7.php b/src/Drupal/Driver/Cores/Drupal7.php index 2373f746..b2046c11 100644 --- a/src/Drupal/Driver/Cores/Drupal7.php +++ b/src/Drupal/Driver/Cores/Drupal7.php @@ -4,11 +4,12 @@ use Drupal\Component\Utility\Random; use Drupal\Driver\Exception\BootstrapException; +use Symfony\Component\DependencyInjection\Container; /** * Drupal 7 core. */ -class Drupal7 implements CoreInterface { +class Drupal7 extends AbstractCore { /** * System path to the Drupal installation. * @@ -97,7 +98,7 @@ public function nodeCreate($node) { $this->expandEntityProperties($node); // Attempt to decipher any fields that may be specified. - $node = $this->expandEntityFields($node); + $this->expandEntityFields('node', $node); // Set defaults that haven't already been set. $defaults = clone $node; @@ -135,7 +136,10 @@ public function userCreate(\stdClass $user) { // hashed password. $account = clone $user; - user_save($account, (array) $user); + // Attempt to decipher any fields that may be specified. + $this->expandEntityFields('user', $account); + + user_save($account, (array) $account); // Store UID. $user->uid = $account->uid; @@ -286,85 +290,6 @@ public function validateDrupalSite() { } } - /** - * Given a node object, expand fields to match the format expected by node_save(). - * - * @param stdClass $entity - * Entity object. - * @param string $entityType - * Entity type, defaults to node. - * @param string $bundle - * Entity bundle. - */ - protected function expandEntityFields(\stdClass $entity, $entityType = 'node', $bundle = '') { - if ($entityType === 'node' && !$bundle) { - $bundle = $entity->type; - } - - $new_entity = clone $entity; - foreach ($entity as $param => $value) { - if ($info = field_info_field($param)) { - foreach ($info['bundles'] as $type => $bundles) { - if ($type == $entityType) { - foreach ($bundles as $target_bundle) { - if ($bundle === $target_bundle) { - unset($new_entity->{$param}); - - // Use the first defined column. @todo probably breaks things. - $column_names = array_keys($info['columns']); - $column = array_shift($column_names); - - // Special handling for date fields (start/end). - // @todo generalize this - if ('date' === $info['module']) { - // Dates passed in separated by a comma are start/end dates. - $dates = explode(',', $value); - $value = trim($dates[0]); - if (!empty($dates[1])) { - $column2 = array_shift($column_names); - $new_entity->{$param}[LANGUAGE_NONE][0][$column2] = trim($dates[1]); - } - $new_entity->{$param}[LANGUAGE_NONE][0][$column] = $value; - } - // Special handling for term references. - elseif ('taxonomy' === $info['module']) { - $terms = explode(',', $value); - $i = 0; - foreach ($terms as $term) { - $tid = taxonomy_get_term_by_name($term); - if (!$tid) { - throw new \Exception(sprintf("No term '%s' exists.", $term)); - } - - $new_entity->{$param}[LANGUAGE_NONE][$i][$column] = array_shift($tid)->tid; - $i++; - } - } - - elseif (is_array($value)) { - foreach ($value as $key => $data) { - if (is_int($key) && (isset($value[$key+1]) || isset($value[$key-1]))) { - $new_entity->{$param}[LANGUAGE_NONE][$key] = $data; - } else { - $new_entity->{$param}[LANGUAGE_NONE][0][$key] = $data; - } - } - } - - - else { - $new_entity->{$param}[LANGUAGE_NONE][0][$column] = $value; - } - } - } - } - } - } - } - - return $new_entity; - } - /** * Given an entity object, expand any property fields to the expected structure. */ @@ -423,6 +348,9 @@ public function termCreate(\stdClass $term) { throw new \Exception(sprintf('No "%s" vocabulary found.')); } + // Attempt to decipher any fields that may be specified. + $this->expandEntityFields('taxonomy_term', $term); + // Protect against a failure from hook_taxonomy_term_insert() in pathauto. $current_path = getcwd(); chdir(DRUPAL_ROOT); @@ -471,4 +399,25 @@ public function getModuleList() { return module_list(); } + /** + * {@inheritDoc} + */ + public function getEntityFieldTypes($entity_type) { + $return = array(); + $fields = field_info_field_map(); + foreach ($fields as $field_name => $field) { + if ($this->isField($entity_type, $field_name)) { + $return[$field_name] = $field['type']; + } + } + return $return; + } + + /** + * {@inheritDoc} + */ + public function isField($entity_type, $field_name) { + $map = field_info_field_map(); + return isset($map[$field_name]); + } } diff --git a/src/Drupal/Driver/Cores/Drupal8.php b/src/Drupal/Driver/Cores/Drupal8.php index 035f7d72..2eb4c02e 100644 --- a/src/Drupal/Driver/Cores/Drupal8.php +++ b/src/Drupal/Driver/Cores/Drupal8.php @@ -4,6 +4,7 @@ use Drupal\Component\Utility\Random; use Drupal\Driver\Exception\BootstrapException; +use Drupal\field\Entity\FieldStorageConfig; use Drupal\node\Entity\Node; use Drupal\node\NodeInterface; use Drupal\taxonomy\Entity\Term; @@ -11,7 +12,7 @@ /** * Drupal 8 core. */ -class Drupal8 implements CoreInterface { +class Drupal8 extends AbstractCore { /** * System path to the Drupal installation. * @@ -94,6 +95,7 @@ public function nodeCreate($node) { if (!isset($node->status)) { $node->status = 1; } + $this->expandEntityFields('node', $node); $entity = entity_create('node', (array) $node); $entity->save(); @@ -130,6 +132,7 @@ public function userCreate(\stdClass $user) { // Clone user object, otherwise user_save() changes the password to the // hashed password. + $this->expandEntityFields('user', $user); $account = entity_create('user', (array) $user); $account->save(); @@ -326,6 +329,7 @@ public function validateDrupalSite() { */ public function termCreate(\stdClass $term) { $term->vid = $term->vocabulary_machine_name; + $this->expandEntityFields('taxonomy_term', $term); $entity = Term::create((array) $term); $entity->save(); @@ -348,4 +352,26 @@ public function getModuleList() { return \Drupal::moduleHandler()->getModuleList(); } + /** + * {@inheritDoc} + */ + public function getEntityFieldTypes($entity_type) { + $return = array(); + $fields = \Drupal::entityManager()->getFieldStorageDefinitions($entity_type); + foreach ($fields as $field_name => $field) { + if ($this->isField($entity_type, $field_name)) { + $return[$field_name] = $field->getType(); + } + } + return $return; + } + + /** + * {@inheritDoc} + */ + public function isField($entity_type, $field_name) { + $fields = \Drupal::entityManager()->getFieldStorageDefinitions($entity_type); + return (isset($fields[$field_name]) && $fields[$field_name] instanceof FieldStorageConfig); + } + } diff --git a/src/Drupal/Driver/DriverInterface.php b/src/Drupal/Driver/DriverInterface.php index 306f4259..87fff58a 100644 --- a/src/Drupal/Driver/DriverInterface.php +++ b/src/Drupal/Driver/DriverInterface.php @@ -129,4 +129,12 @@ public function roleCreate(array $permissions); */ public function roleDelete($rid); + /** + * Check if the specified field is an actual Drupal field. + * + * @param $entity_type + * @param $field_name + * @return boolean + */ + public function isField($entity_type, $field_name); } diff --git a/src/Drupal/Driver/DrupalDriver.php b/src/Drupal/Driver/DrupalDriver.php index f7a39ced..190d8abf 100644 --- a/src/Drupal/Driver/DrupalDriver.php +++ b/src/Drupal/Driver/DrupalDriver.php @@ -142,7 +142,6 @@ public function getSubDriverPaths() { // Active profile // @todo - return $paths; } @@ -276,4 +275,11 @@ public function roleDelete($rid) { $this->getCore()->roleDelete($rid); } + /** + * {@inheritDoc} + */ + public function isField($entity_type, $field_name) { + return $this->getCore()->isField($entity_type, $field_name); + } + } diff --git a/src/Drupal/Driver/Fields/Drupal7/AbstractHandler.php b/src/Drupal/Driver/Fields/Drupal7/AbstractHandler.php new file mode 100644 index 00000000..f8b97f60 --- /dev/null +++ b/src/Drupal/Driver/Fields/Drupal7/AbstractHandler.php @@ -0,0 +1,29 @@ +field_info = field_info_field($field_name); + } + +} diff --git a/src/Drupal/Driver/Fields/Drupal7/DatetimeHandler.php b/src/Drupal/Driver/Fields/Drupal7/DatetimeHandler.php new file mode 100644 index 00000000..170e3ca5 --- /dev/null +++ b/src/Drupal/Driver/Fields/Drupal7/DatetimeHandler.php @@ -0,0 +1,37 @@ +field_info['columns']['value2'])) { + foreach ($values as $value) { + $return[LANGUAGE_NONE][] = array( + 'value' => $value[0], + 'value2' => $value[1], + ); + } + } + else { + foreach ($values as $value) { + $return[LANGUAGE_NONE][] = array('value' => $value); + } + } + return $return; + } +} diff --git a/src/Drupal/Driver/Fields/Drupal7/DefaultHandler.php b/src/Drupal/Driver/Fields/Drupal7/DefaultHandler.php new file mode 100644 index 00000000..548a5db7 --- /dev/null +++ b/src/Drupal/Driver/Fields/Drupal7/DefaultHandler.php @@ -0,0 +1,27 @@ + $value); + } + return $return; + } +} diff --git a/src/Drupal/Driver/Fields/Drupal7/EntityreferenceHandler.php b/src/Drupal/Driver/Fields/Drupal7/EntityreferenceHandler.php new file mode 100644 index 00000000..46d2dd68 --- /dev/null +++ b/src/Drupal/Driver/Fields/Drupal7/EntityreferenceHandler.php @@ -0,0 +1,40 @@ +field_info['settings']['target_type']; + $entity_info = entity_get_info($entity_type); + // For users set label to username. + if ($entity_type == 'user') { + $entity_info['entity keys']['label'] = 'name'; + } + + $return = array(); + foreach ($values as $value) { + $target_id = db_select($entity_info['base table'], 't') + ->fields('t', array($entity_info['entity keys']['id'])) + ->condition('t.' . $entity_info['entity keys']['label'], $value) + ->execute()->fetchField(); + if ($target_id) { + $return[LANGUAGE_NONE][] = array('target_id' => $target_id); + } + } + return $return; + } +} diff --git a/src/Drupal/Driver/Fields/Drupal7/LinkFieldHandler.php b/src/Drupal/Driver/Fields/Drupal7/LinkFieldHandler.php new file mode 100644 index 00000000..0025a653 --- /dev/null +++ b/src/Drupal/Driver/Fields/Drupal7/LinkFieldHandler.php @@ -0,0 +1,30 @@ + $value[0], + 'url' => $value[1], + ); + } + return $return; + } +} diff --git a/src/Drupal/Driver/Fields/Drupal7/ListTextHandler.php b/src/Drupal/Driver/Fields/Drupal7/ListTextHandler.php new file mode 100644 index 00000000..82451f68 --- /dev/null +++ b/src/Drupal/Driver/Fields/Drupal7/ListTextHandler.php @@ -0,0 +1,28 @@ +field_info['settings']['allowed_values']); + foreach ($values as $value) { + $return[LANGUAGE_NONE][] = array('value' => $allowed_values[$value]); + } + return $return; + } +} diff --git a/src/Drupal/Driver/Fields/Drupal7/TaxonomyTermReferenceHandler.php b/src/Drupal/Driver/Fields/Drupal7/TaxonomyTermReferenceHandler.php new file mode 100644 index 00000000..983b0fed --- /dev/null +++ b/src/Drupal/Driver/Fields/Drupal7/TaxonomyTermReferenceHandler.php @@ -0,0 +1,31 @@ + array_shift($terms)->tid); + } + return $return; + } +} diff --git a/src/Drupal/Driver/Fields/Drupal8/AbstractHandler.php b/src/Drupal/Driver/Fields/Drupal8/AbstractHandler.php new file mode 100644 index 00000000..9ca1a224 --- /dev/null +++ b/src/Drupal/Driver/Fields/Drupal8/AbstractHandler.php @@ -0,0 +1,30 @@ +getFieldStorageDefinitions($entity_type); + $this->field_info = $fields[$field_name]; + } + +} diff --git a/src/Drupal/Driver/Fields/Drupal8/DatetimeHandler.php b/src/Drupal/Driver/Fields/Drupal8/DatetimeHandler.php new file mode 100644 index 00000000..c3cf77d7 --- /dev/null +++ b/src/Drupal/Driver/Fields/Drupal8/DatetimeHandler.php @@ -0,0 +1,25 @@ + $value) { + $values[$key] = str_replace(' ', 'T', $value); + } + return $values; + } +} diff --git a/src/Drupal/Driver/Fields/Drupal8/DefaultHandler.php b/src/Drupal/Driver/Fields/Drupal8/DefaultHandler.php new file mode 100644 index 00000000..99be7772 --- /dev/null +++ b/src/Drupal/Driver/Fields/Drupal8/DefaultHandler.php @@ -0,0 +1,22 @@ +field_info->getSetting('target_type'); + $entity_definition = \Drupal::entityManager()->getDefinition($entity_type_id); + $label = $entity_definition->getKey('label'); + foreach ($values as $value) { + $entities = \Drupal::entityManager() + ->getStorage($entity_type_id) + ->loadByProperties(array($label => $value)); + if ($entities) { + $return[] = array_shift($entities)->id(); + } + else { + throw new \Exception(sprintf("No entity '%s' of type '%s' exists.", $value, $entity_type_id)); + } + } + return $return; + } +} diff --git a/src/Drupal/Driver/Fields/Drupal8/LinkHandler.php b/src/Drupal/Driver/Fields/Drupal8/LinkHandler.php new file mode 100644 index 00000000..165e2928 --- /dev/null +++ b/src/Drupal/Driver/Fields/Drupal8/LinkHandler.php @@ -0,0 +1,33 @@ + array(), + 'title' => $value[0], + 'uri' => $value[1], + ); + } + return $return; + } +} diff --git a/src/Drupal/Driver/Fields/Drupal8/TaxonomyTermReferenceHandler.php b/src/Drupal/Driver/Fields/Drupal8/TaxonomyTermReferenceHandler.php new file mode 100644 index 00000000..c2acff6f --- /dev/null +++ b/src/Drupal/Driver/Fields/Drupal8/TaxonomyTermReferenceHandler.php @@ -0,0 +1,35 @@ +getStorage('taxonomy_term') + ->loadByProperties(array('name' => $name)); + if ($terms) { + $return[] = array_shift($terms)->id(); + } + else { + throw new \Exception(sprintf("No term '%s' exists.", $name)); + } + } + return $return; + } +} diff --git a/src/Drupal/Driver/Fields/FieldHandlerInterface.php b/src/Drupal/Driver/Fields/FieldHandlerInterface.php new file mode 100644 index 00000000..995c06dc --- /dev/null +++ b/src/Drupal/Driver/Fields/FieldHandlerInterface.php @@ -0,0 +1,24 @@ +