diff --git a/core/lib/Drupal/Core/File/File.php b/core/lib/Drupal/Core/File/File.php index b35f5ee..9a08a7d 100644 --- a/core/lib/Drupal/Core/File/File.php +++ b/core/lib/Drupal/Core/File/File.php @@ -22,6 +22,13 @@ class File extends Entity { public $fid; /** + * The file UUID. + * + * @var integer + */ + public $uuid; + + /** * The file language code. * * @var string diff --git a/core/lib/Drupal/Core/File/FileStorageController.php b/core/lib/Drupal/Core/File/FileStorageController.php index 940e1fd..0ec948c 100644 --- a/core/lib/Drupal/Core/File/FileStorageController.php +++ b/core/lib/Drupal/Core/File/FileStorageController.php @@ -9,6 +9,8 @@ namespace Drupal\Core\File; use Drupal\entity\DatabaseStorageController; use Drupal\entity\EntityInterface; +use Drupal\Component\Uuid\Uuid; + /** * File storage controller for files. @@ -28,7 +30,16 @@ class FileStorageController extends DatabaseStorageController { if (!isset($values['filemime']) && isset($values['uri'])) { $values['filemime'] = file_get_mimetype($values['uri']); } - return parent::create($values); + + // Create file object via parent class constructor. + $file = parent::create($values); + + // Generate and add UUID. + $uuid = new Uuid(); + $file->uuid = $uuid->generate(); + + + return $file; } /** diff --git a/core/modules/comment/comment.install b/core/modules/comment/comment.install index 4b3c9fc..24b1832 100644 --- a/core/modules/comment/comment.install +++ b/core/modules/comment/comment.install @@ -91,6 +91,13 @@ function comment_schema() { 'not null' => TRUE, 'description' => 'Primary Key: Unique comment ID.', ), + 'uuid' => array( + 'description' => 'The universally unique identifier for a comment.', + 'type' => 'varchar', + 'length' => 36, + 'not null' => TRUE, + 'default' => '', + ), 'pid' => array( 'type' => 'int', 'not null' => TRUE, @@ -181,6 +188,7 @@ function comment_schema() { 'comment_uid' => array('uid'), 'comment_nid_langcode' => array('nid', 'langcode'), 'comment_created' => array('created'), + 'uuid' => array('uuid'), ), 'primary key' => array('cid'), 'foreign keys' => array( @@ -282,6 +290,30 @@ function comment_update_8000() { } /** + * Create an uuid column for comment table. + * + * @ToDo: Batch generate uuids for all existing comments without a uuid. + */ +function comment_update_8001() { + db_add_field( + 'comment', + 'uuid', + array( + 'description' => 'The universally unique identifier for a comment.', + 'type' => 'varchar', + 'length' => 36, + 'not null' => TRUE, + 'default' => '', + ), + array( + 'indexes' => array( + 'uuid' => array('uuid'), + ) + ) + ); +} + +/** * @} End of "addtogroup updates-7.x-to-8.x". * The next series of updates should start at 9000. */ diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module index 7c96247..348f95d 100644 --- a/core/modules/comment/comment.module +++ b/core/modules/comment/comment.module @@ -109,6 +109,7 @@ function comment_entity_info() { 'id' => 'cid', 'bundle' => 'node_type', 'label' => 'subject', + 'uuid' => 'uuid', ), 'bundles' => array(), 'view modes' => array( diff --git a/core/modules/comment/lib/Drupal/comment/Comment.php b/core/modules/comment/lib/Drupal/comment/Comment.php index 101a679..1603de7 100644 --- a/core/modules/comment/lib/Drupal/comment/Comment.php +++ b/core/modules/comment/lib/Drupal/comment/Comment.php @@ -22,6 +22,13 @@ class Comment extends Entity { public $cid; /** + * The comment UUID. + * + * @var integer + */ + public $uuid; + + /** * The parent comment ID if this is a reply to a comment. * * @var integer diff --git a/core/modules/comment/lib/Drupal/comment/CommentStorageController.php b/core/modules/comment/lib/Drupal/comment/CommentStorageController.php index b041ebd..2bfa752 100644 --- a/core/modules/comment/lib/Drupal/comment/CommentStorageController.php +++ b/core/modules/comment/lib/Drupal/comment/CommentStorageController.php @@ -9,6 +9,8 @@ namespace Drupal\comment; use Drupal\entity\EntityInterface; use Drupal\entity\DatabaseStorageController; +use Drupal\Component\Uuid\Uuid; + /** * Defines the controller class for comments. @@ -19,6 +21,19 @@ use Drupal\entity\DatabaseStorageController; class CommentStorageController extends DatabaseStorageController { /** + * Overrides Drupal\entity\DatabaseStorageController::create(). + */ + public function create(array $values) { + $comment = parent::create($values); + + // Generate and add UUID. + $uuid = new Uuid(); + $comment->uuid = $uuid->generate(); + + return $comment; + } + + /** * Overrides Drupal\entity\DatabaseStorageController::buildQuery(). */ protected function buildQuery($ids, $conditions = array(), $revision_id = FALSE) { diff --git a/core/modules/entity/entity.api.php b/core/modules/entity/entity.api.php index 37263a6..1d9462a 100644 --- a/core/modules/entity/entity.api.php +++ b/core/modules/entity/entity.api.php @@ -77,6 +77,9 @@ * 'subject' should be specified here. If complex logic is required to * build the label, a 'label callback' should be defined instead (see * the 'label callback' section above for details). + * - uuid (optional): The name of the property that contains the universally + * unique identifier of the entity, which is used to distinctly identify + * an entity across different Drupal installations. * - bundle keys: An array describing how the Field API can extract the * information it needs from the bundle objects for this type (e.g * $vocabulary objects for terms; not applicable for nodes). This entry can @@ -148,6 +151,7 @@ function hook_entity_info() { 'id' => 'nid', 'revision' => 'vid', 'bundle' => 'type', + 'uuid' => 'uuid', ), 'bundle keys' => array( 'bundle' => 'type', diff --git a/core/modules/entity/entity.module b/core/modules/entity/entity.module index daaa9f6..a339df7 100644 --- a/core/modules/entity/entity.module +++ b/core/modules/entity/entity.module @@ -217,6 +217,54 @@ function entity_load($entity_type, $id, $reset = FALSE) { } /** + * Load entity from the database by given UUID. + * + * If an entity type supports a UUID-type entity identifier, this function can + * find an entity by that UUID-type entity identifier. + * Not all entities support that kind of UUID-type entity identifier + * (which can be defined in hook_entity_info). + * + * @param string $entity_type + * The entity type to load, e.g. node or user. + * @param string $uuid + * The uuid of the entity to load. + * @param bool $reset + * Whether to reset the internal cache for the requested entity type. + * + * @return EntityInterface|FALSE + * The entity object, or FALSE if there is no entity with the given UUID. + * + * @see hook_entity_info() + * + */ +function entity_load_by_uuid($entity_type, $uuid, $reset = FALSE) { + $entity = FALSE; + + // Only consider entities that have a "uuid"-type key declared via + // hook_entity_info. + $entity_info = entity_get_info($entity_type); + if (is_array($entity_info) && isset($entity_info['entity keys']) && isset($entity_info['entity keys']['uuid'])) { + $uuid_key_name = $entity_info['entity keys']['uuid']; + + // Retrieve entity record for given uuid to get its entity id. + $entity_query = new Drupal\entity\EntityFieldQuery(); + $entity_query_result = $entity_query->entityCondition('entity_type', $entity_type) + ->propertyCondition($uuid_key_name, $uuid) + ->range(0, 1) + ->execute(); + + // Mine result for entity id and load the entity by its id. + if (is_array($entity_query_result) && isset($entity_query_result[$entity_type])) { + $entity_ids = array_keys($entity_query_result[$entity_type]); + $entity_id = array_shift($entity_ids); + $entity = entity_load($entity_type, $entity_id, $reset); + } + } + + return $entity; +} + +/** * Loads multiple entities from the database. * * This function should be used whenever you need to load more than one entity diff --git a/core/modules/node/lib/Drupal/node/Node.php b/core/modules/node/lib/Drupal/node/Node.php index 1aac6fb..9694624 100644 --- a/core/modules/node/lib/Drupal/node/Node.php +++ b/core/modules/node/lib/Drupal/node/Node.php @@ -29,6 +29,13 @@ class Node extends Entity { public $vid; /** + * The node UUID. + * + * @var integer + */ + public $uuid; + + /** * The node content type (bundle). * * @var string diff --git a/core/modules/node/lib/Drupal/node/NodeStorageController.php b/core/modules/node/lib/Drupal/node/NodeStorageController.php index aa52582..b5958fa 100644 --- a/core/modules/node/lib/Drupal/node/NodeStorageController.php +++ b/core/modules/node/lib/Drupal/node/NodeStorageController.php @@ -10,6 +10,7 @@ namespace Drupal\node; use Drupal\entity\DatabaseStorageController; use Drupal\entity\EntityInterface; use Drupal\entity\EntityStorageException; +use Drupal\Component\Uuid\Uuid; use Exception; /** @@ -31,6 +32,10 @@ class NodeStorageController extends DatabaseStorageController { $node->created = REQUEST_TIME; } + // Generate and add UUID. + $uuid = new Uuid(); + $node->uuid = $uuid->generate(); + return $node; } diff --git a/core/modules/node/node.install b/core/modules/node/node.install index 6f806e9..34aebd8 100644 --- a/core/modules/node/node.install +++ b/core/modules/node/node.install @@ -27,6 +27,13 @@ function node_schema() { 'not null' => FALSE, 'default' => NULL, ), + 'uuid' => array( + 'description' => 'The universally unique identifier for a node.', + 'type' => 'varchar', + 'length' => 36, + 'not null' => TRUE, + 'default' => '', + ), 'type' => array( 'description' => 'The {node_type}.type of this node.', 'type' => 'varchar', @@ -114,6 +121,7 @@ function node_schema() { 'uid' => array('uid'), 'tnid' => array('tnid'), 'translate' => array('translate'), + 'uuid' => array('uuid'), ), 'unique keys' => array( 'vid' => array('vid'), @@ -543,6 +551,31 @@ function node_update_8002() { } /** + * Create an uuid column for node table. + * + * @ToDo: Batch generate uuids for all existing nodes without a uuid. + */ +function node_update_8003() { + db_add_field( + 'node', + 'uuid', + array( + 'description' => 'The universally unique identifier for a node.', + 'type' => 'varchar', + 'length' => 36, + 'not null' => TRUE, + 'default' => '', + ), + array( + 'indexes' => array( + 'uuid' => array('uuid'), + ) + ) + ); +} + + +/** * @} End of "addtogroup updates-7.x-to-8.x". * The next series of updates should start at 9000. */ diff --git a/core/modules/node/node.module b/core/modules/node/node.module index e787c7d..8c8a482 100644 --- a/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -204,6 +204,7 @@ function node_entity_info() { 'revision' => 'vid', 'bundle' => 'type', 'label' => 'title', + 'uuid' => 'uuid', ), 'bundle keys' => array( 'bundle' => 'type', diff --git a/core/modules/system/system.install b/core/modules/system/system.install index 9ba7c4c..7f84ced 100644 --- a/core/modules/system/system.install +++ b/core/modules/system/system.install @@ -866,6 +866,13 @@ function system_schema() { 'unsigned' => TRUE, 'not null' => TRUE, ), + 'uuid' => array( + 'description' => 'The universally unique identifier for a file.', + 'type' => 'varchar', + 'length' => 36, + 'not null' => TRUE, + 'default' => '', + ), 'uid' => array( 'description' => 'The {users}.uid of the user who is associated with the file.', 'type' => 'int', @@ -929,6 +936,7 @@ function system_schema() { 'uid' => array('uid'), 'status' => array('status'), 'timestamp' => array('timestamp'), + 'uuid' => array('uuid'), ), 'unique keys' => array( 'uri' => array('uri'), @@ -1925,6 +1933,30 @@ function system_update_8010() { } /** + * Create an uuid column for file_managed table. + * + * @ToDo: Batch generate uuids for all existing files without a uuid. + */ +function system_update_8011() { + db_add_field( + 'file_managed', + 'uuid', + array( + 'description' => 'The universally unique identifier for a file.', + 'type' => 'varchar', + 'length' => 36, + 'not null' => TRUE, + 'default' => '', + ), + array( + 'indexes' => array( + 'uuid' => array('uuid'), + ) + ) + ); +} + +/** * @} End of "defgroup updates-7.x-to-8.x". * The next series of updates should start at 9000. */ diff --git a/core/modules/system/system.module b/core/modules/system/system.module index 73236f7..bdde02a 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -276,6 +276,7 @@ function system_entity_info() { 'entity keys' => array( 'id' => 'fid', 'label' => 'filename', + 'uuid' => 'uuid', ), 'static cache' => FALSE, ), diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Term.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Term.php index f036f18..418dc8f 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Term.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Term.php @@ -22,6 +22,13 @@ class Term extends Entity { public $tid; /** + * The term UUID. + * + * @var integer + */ + public $uuid; + + /** * The taxonomy vocabulary ID this term belongs to. * * @var integer diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/TermStorageController.php b/core/modules/taxonomy/lib/Drupal/taxonomy/TermStorageController.php index 09b0d80..c8da41d 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/TermStorageController.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/TermStorageController.php @@ -9,6 +9,7 @@ namespace Drupal\taxonomy; use Drupal\entity\EntityInterface; use Drupal\entity\DatabaseStorageController; +use Drupal\Component\Uuid\Uuid; /** * Defines a Controller class for taxonomy terms. @@ -36,6 +37,11 @@ class TermStorageController extends DatabaseStorageController { if (!isset($entity->parent)) { $entity->parent = array(0); } + + // Generate and add UUID. + $uuid = new Uuid(); + $entity->uuid = $uuid->generate(); + return $entity; } diff --git a/core/modules/taxonomy/taxonomy.install b/core/modules/taxonomy/taxonomy.install index 14b6956..87dde70 100644 --- a/core/modules/taxonomy/taxonomy.install +++ b/core/modules/taxonomy/taxonomy.install @@ -32,6 +32,13 @@ function taxonomy_schema() { 'not null' => TRUE, 'description' => 'Primary Key: Unique term ID.', ), + 'uuid' => array( + 'description' => 'The universally unique identifier for a term.', + 'type' => 'varchar', + 'length' => 36, + 'not null' => TRUE, + 'default' => '', + ), 'vid' => array( 'type' => 'int', 'unsigned' => TRUE, @@ -85,6 +92,7 @@ function taxonomy_schema() { 'taxonomy_tree' => array('vid', 'weight', 'name'), 'vid_name' => array('vid', 'name'), 'name' => array('name'), + 'uuid' => array('uuid'), ), ); @@ -300,3 +308,27 @@ function taxonomy_update_8001() { } } } + +/** + * Create an uuid column for taxonomy_term_data table. + * + * @ToDo: Batch generate uuids for all existing terms without a uuid. + */ +function taxonomy_update_8002() { + db_add_field( + 'taxonomy_term_data', + 'uuid', + array( + 'description' => 'The universally unique identifier for a term.', + 'type' => 'varchar', + 'length' => 36, + 'not null' => TRUE, + 'default' => '', + ), + array( + 'indexes' => array( + 'uuid' => array('uuid'), + ) + ) + ); +} diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module index ba74a9a..ce93f07 100644 --- a/core/modules/taxonomy/taxonomy.module +++ b/core/modules/taxonomy/taxonomy.module @@ -120,6 +120,7 @@ function taxonomy_entity_info() { 'id' => 'tid', 'bundle' => 'vocabulary_machine_name', 'label' => 'name', + 'uuid' => 'uuid', ), 'bundle keys' => array( 'bundle' => 'machine_name', diff --git a/core/modules/user/lib/Drupal/user/User.php b/core/modules/user/lib/Drupal/user/User.php index 992923c..c503118 100644 --- a/core/modules/user/lib/Drupal/user/User.php +++ b/core/modules/user/lib/Drupal/user/User.php @@ -22,6 +22,13 @@ class User extends Entity { public $uid; /** + * The user UUID. + * + * @var integer + */ + public $uuid; + + /** * The unique user name. * * @var string diff --git a/core/modules/user/lib/Drupal/user/UserStorageController.php b/core/modules/user/lib/Drupal/user/UserStorageController.php index bde430c..32b53a0 100644 --- a/core/modules/user/lib/Drupal/user/UserStorageController.php +++ b/core/modules/user/lib/Drupal/user/UserStorageController.php @@ -10,6 +10,8 @@ namespace Drupal\user; use Drupal\entity\EntityInterface; use Drupal\entity\EntityMalformedException; use Drupal\entity\DatabaseStorageController; +use Drupal\Component\Uuid\Uuid; + /** * Controller class for users. @@ -69,7 +71,14 @@ class UserStorageController extends DatabaseStorageController { // Users always have the authenticated user role. $values['roles'][DRUPAL_AUTHENTICATED_RID] = 'authenticated user'; - return parent::create($values); + // Create user via parent class constructor. + $user = parent::create($values); + + // Generate and add UUID. + $uuid = new Uuid(); + $user->uuid = $uuid->generate(); + + return $user; } /** diff --git a/core/modules/user/user.install b/core/modules/user/user.install index 5ec57da..9b1956f 100644 --- a/core/modules/user/user.install +++ b/core/modules/user/user.install @@ -132,6 +132,13 @@ function user_schema() { 'description' => 'Primary Key: Unique user ID.', 'default' => 0, ), + 'uuid' => array( + 'description' => 'The universally unique identifier for a user.', + 'type' => 'varchar', + 'length' => 36, + 'not null' => TRUE, + 'default' => '', + ), 'name' => array( 'type' => 'varchar', 'length' => 60, @@ -244,6 +251,7 @@ function user_schema() { 'created' => array('created'), 'mail' => array('mail'), 'picture' => array('picture'), + 'uuid' => array('uuid'), ), 'unique keys' => array( 'name' => array('name'), @@ -442,5 +450,29 @@ function user_update_8002() { } /** + * Create an uuid column for users table. + * + * @ToDo: Batch generate uuids for all existing users without a uuid. + */ +function user_update_8003() { + db_add_field( + 'users', + 'uuid', + array( + 'description' => 'The universally unique identifier for a user.', + 'type' => 'varchar', + 'length' => 36, + 'not null' => TRUE, + 'default' => '', + ), + array( + 'indexes' => array( + 'uuid' => array('uuid'), + ) + ) + ); +} + +/** * @} End of "addtogroup updates-7.x-to-8.x". */ diff --git a/core/modules/user/user.module b/core/modules/user/user.module index 6f21c5c..ce441de 100644 --- a/core/modules/user/user.module +++ b/core/modules/user/user.module @@ -154,6 +154,7 @@ function user_entity_info() { 'entity class' => 'Drupal\user\User', 'entity keys' => array( 'id' => 'uid', + 'uuid' => 'uuid', ), 'bundles' => array( 'user' => array(