diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index d488664..4bf2981 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -2521,7 +2521,15 @@ function state() {
* @return Drupal\Core\TypedData\TypedDataManager
*/
function typed_data() {
- return drupal_container()->get('typed_data');
+ // Use the advanced drupal_static() pattern, since this is called very often.
+ static $drupal_static_fast;
+ if (!isset($drupal_static_fast)) {
+ $drupal_static_fast['manager'] = &drupal_static(__FUNCTION__);
+ }
+ if (!isset($drupal_static_fast['manager'])) {
+ $drupal_static_fast['manager'] = drupal_container()->get('typed_data');
+ }
+ return $drupal_static_fast['manager'];
}
/**
diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
index 330f39c..26b5b30 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
@@ -110,4 +110,18 @@ public static function sort($a, $b) {
}
return ($a_weight < $b_weight) ? -1 : 1;
}
+
+ /**
+ * Implements Drupal\Core\Entity\EntityInterface::getBCEntity().
+ */
+ public function getBCEntity() {
+ return $this;
+ }
+
+ /**
+ * Implements Drupal\Core\Entity\EntityInterface::getOriginalEntity().
+ */
+ public function getOriginalEntity() {
+ return $this;
+ }
}
diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
index 267e10c..bec638a 100644
--- a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
+++ b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
@@ -30,6 +30,7 @@ class DatabaseStorageController implements EntityStorageControllerInterface {
*/
protected $entityCache;
+
/**
* Entity type for this controller instance.
*
@@ -56,6 +57,13 @@ class DatabaseStorageController implements EntityStorageControllerInterface {
protected $entityFieldInfo;
/**
+ * Static cache of field definitions per bundle.
+ *
+ * @var array
+ */
+ protected $fieldDefinitions;
+
+ /**
* Additional arguments to pass to hook_TYPE_load().
*
* Set before calling Drupal\Core\Entity\DatabaseStorageController::attachLoad().
@@ -552,13 +560,16 @@ protected function saveRevision(EntityInterface $entity) {
$record = (array) $entity;
// When saving a new revision, set any existing revision ID to NULL so as to
- // ensure that a new revision will actually be created, then store the old
- // revision ID in a separate property for use by hook implementations.
+ // ensure that a new revision will actually be created.
if ($entity->isNewRevision() && $record[$this->revisionKey]) {
$record[$this->revisionKey] = NULL;
}
+ // Cast to object as preSaveRevision() expects one to be compatible with the
+ // upcoming NG storage controller.
+ $record = (object) $record;
$this->preSaveRevision($record, $entity);
+ $record = (array) $record;
if ($entity->isNewRevision()) {
drupal_write_record($this->revisionTable, $record);
@@ -613,12 +624,12 @@ protected function postDelete($entities) { }
/**
* Act on a revision before being saved.
*
- * @param array $record
- * The revision array.
+ * @param \stdClass $record
+ * The revision object.
* @param Drupal\Core\Entity\EntityInterface $entity
* The entity object.
*/
- protected function preSaveRevision(array &$record, EntityInterface $entity) { }
+ protected function preSaveRevision(\stdClass $record, EntityInterface $entity) { }
/**
* Invokes a hook on behalf of the entity.
@@ -677,15 +688,17 @@ public function getFieldDefinitions(array $constraints) {
}
}
- $definitions = $this->entityFieldInfo['definitions'];
+ $bundle = !empty($constraints['bundle']) ? $constraints['bundle'] : FALSE;
// Add in per-bundle properties.
- // @todo: Should this be statically cached as well?
- if (!empty($constraints['bundle']) && isset($this->entityFieldInfo['bundle map'][$constraints['bundle']])) {
- $definitions += array_intersect_key($this->entityFieldInfo['optional'], array_flip($this->entityFieldInfo['bundle map'][$constraints['bundle']]));
- }
+ if (!isset($this->fieldDefinitions[$bundle])) {
+ $this->fieldDefinitions[$bundle] = $this->entityFieldInfo['definitions'];
- return $definitions;
+ if ($bundle && isset($this->entityFieldInfo['bundle map'][$constraints['bundle']])) {
+ $this->fieldDefinitions[$bundle] += array_intersect_key($this->entityFieldInfo['optional'], array_flip($this->entityFieldInfo['bundle map'][$constraints['bundle']]));
+ }
+ }
+ return $this->fieldDefinitions[$bundle];
}
/**
diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
index 6f22d83..721b15d 100644
--- a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
+++ b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
@@ -9,6 +9,7 @@
use PDO;
+use Drupal\Core\Entity\Query\QueryInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\DatabaseStorageController;
use Drupal\Core\Entity\EntityStorageException;
@@ -37,6 +38,13 @@ class DatabaseStorageControllerNG extends DatabaseStorageController {
protected $bundleKey;
/**
+ * The table that stores properties, if the entity has multilingual support.
+ *
+ * @var string
+ */
+ protected $dataTable;
+
+ /**
* Overrides DatabaseStorageController::__construct().
*/
public function __construct($entityType) {
@@ -44,6 +52,11 @@ public function __construct($entityType) {
$this->bundleKey = !empty($this->entityInfo['entity_keys']['bundle']) ? $this->entityInfo['entity_keys']['bundle'] : FALSE;
$this->entityClass = $this->entityInfo['class'];
+ // Check if the entity type has a dedicated table for properties.
+ if (!empty($this->entityInfo['data_table'])) {
+ $this->dataTable = $this->entityInfo['data_table'];
+ }
+
// Work-a-round to let load() get stdClass storage records without having to
// override it. We map storage records to entities in
// DatabaseStorageControllerNG:: mapFromStorageRecords().
@@ -77,13 +90,10 @@ public function __construct($entityType) {
* A new entity object.
*/
public function create(array $values) {
- $entity = new $this->entityClass(array(), $this->entityType);
+ // We have to determine the bundle first.
+ $bundle = $this->bundleKey ? $values[$this->bundleKey] : FALSE;
+ $entity = new $this->entityClass(array(), $this->entityType, $bundle);
- // Make sure to set the bundle first.
- if ($this->bundleKey) {
- $entity->{$this->bundleKey} = $values[$this->bundleKey];
- unset($values[$this->bundleKey]);
- }
// Set all other given values.
foreach ($values as $name => $value) {
$entity->$name = $value;
@@ -98,6 +108,121 @@ public function create(array $values) {
}
/**
+ * Builds an entity query.
+ *
+ * @param \Drupal\Core\Entity\Query\QueryInterface $entity_query
+ * EntityQuery instance.
+ * @param array $values
+ * An associative array of properties of the entity, where the keys are the
+ * property names and the values are the values those properties must have.
+ */
+ protected function buildPropertyQuery(QueryInterface $entity_query, array $values) {
+ if ($this->dataTable) {
+ // @todo We should not be using a condition to specify whether conditions
+ // apply to the default language or not. We need to move this to a
+ // separate parameter during the following API refactoring.
+ // Default to the original entity language if not explicitly specified
+ // otherwise.
+ if (!array_key_exists('default_langcode', $values)) {
+ $values['default_langcode'] = 1;
+ }
+ // If the 'default_langcode' flag is explicitly not set, we do not care
+ // whether the queried values are in the original entity language or not.
+ elseif ($values['default_langcode'] === NULL) {
+ unset($values['default_langcode']);
+ }
+ }
+
+ parent::buildPropertyQuery($entity_query, $values);
+ }
+
+ /**
+ * Builds the query to load the entity.
+ *
+ * This has full revision support. For entities requiring special queries,
+ * the class can be extended, and the default query can be constructed by
+ * calling parent::buildQuery(). This is usually necessary when the object
+ * being loaded needs to be augmented with additional data from another
+ * table, such as loading node type into comments or vocabulary machine name
+ * into terms, however it can also support $conditions on different tables.
+ * See Drupal\comment\CommentStorageController::buildQuery() or
+ * Drupal\taxonomy\TermStorageController::buildQuery() for examples.
+ *
+ * @param array|null $ids
+ * An array of entity IDs, or NULL to load all entities.
+ * @param $revision_id
+ * The ID of the revision to load, or FALSE if this query is asking for the
+ * most current revision(s).
+ *
+ * @return SelectQuery
+ * A SelectQuery object for loading the entity.
+ */
+ protected function buildQuery($ids, $revision_id = FALSE) {
+ $query = db_select($this->entityInfo['base_table'], 'base');
+
+ $query->addTag($this->entityType . '_load_multiple');
+
+ if ($revision_id) {
+ $query->join($this->revisionTable, 'revision', "revision.{$this->idKey} = base.{$this->idKey} AND revision.{$this->revisionKey} = :revisionId", array(':revisionId' => $revision_id));
+ }
+ elseif ($this->revisionKey) {
+ $query->join($this->revisionTable, 'revision', "revision.{$this->revisionKey} = base.{$this->revisionKey}");
+ }
+
+ if (!empty($this->dataTable)) {
+ $query->join($this->dataTable, 'data', "data.{$this->idKey} = base.{$this->idKey}");
+ }
+
+ // Add fields from the {entity} table.
+ $entity_fields = $this->entityInfo['schema_fields_sql']['base_table'];
+
+ if ($this->revisionKey) {
+ // Add all fields from the {entity_revision} table.
+ $entity_revision_fields = drupal_map_assoc($this->entityInfo['schema_fields_sql']['revision_table']);
+ // The id field is provided by entity, so remove it.
+ unset($entity_revision_fields[$this->idKey]);
+
+ // Remove all fields from the base table that are also fields by the same
+ // name in the revision table.
+ $entity_field_keys = array_flip($entity_fields);
+ foreach ($entity_revision_fields as $key => $name) {
+ if (isset($entity_field_keys[$name])) {
+ unset($entity_fields[$entity_field_keys[$name]]);
+ }
+ }
+ $query->fields('revision', $entity_revision_fields);
+
+ // Compare revision id of the base and revision table, if equal then this
+ // is the default revision.
+ $query->addExpression('base.' . $this->revisionKey . ' = revision.' . $this->revisionKey, 'isDefaultRevision');
+ }
+
+ // Add fields from the entity data_table.
+ if (!empty($this->dataTable)) {
+ // Add all fields from the {entity_data} table.
+ $entity_data_fields = drupal_map_assoc($this->entityInfo['schema_fields_sql']['data_table']);
+ // The id field is provided by entity, so remove it.
+ unset($entity_data_fields[$this->idKey]);
+
+ if (!isset($entity_revision_fields)) {
+ $entity_revision_fields = array();
+ }
+
+ // Only add fields not covered by the base or the revision.
+ $entity_data_fields = array_diff($entity_data_fields, $entity_fields, $entity_revision_fields);
+ $query->fields('data', $entity_data_fields);
+ }
+
+ $query->fields('base', $entity_fields);
+
+ if ($ids) {
+ $query->condition("base.{$this->idKey}", $ids, 'IN');
+ }
+
+ return $query;
+ }
+
+ /**
* Overrides DatabaseStorageController::attachLoad().
*
* Added mapping from storage records to entities.
@@ -105,23 +230,24 @@ public function create(array $values) {
protected function attachLoad(&$queried_entities, $load_revision = FALSE) {
// Now map the record values to the according entity properties and
// activate compatibility mode.
- $queried_entities = $this->mapFromStorageRecords($queried_entities);
+ $queried_entities = $this->mapFromStorageRecords($queried_entities, $load_revision);
// Attach fields.
if ($this->entityInfo['fieldable']) {
+ // Prepare BC compatible entities for field API.
+ $bc_entities = array();
+ foreach ($queried_entities as $key => $entity) {
+ $bc_entities[$key] = $entity->getBCEntity();
+ }
+
if ($load_revision) {
- field_attach_load_revision($this->entityType, $queried_entities);
+ field_attach_load_revision($this->entityType, $bc_entities);
}
else {
- field_attach_load($this->entityType, $queried_entities);
+ field_attach_load($this->entityType, $bc_entities);
}
}
- // Loading is finished, so disable compatibility mode now.
- foreach ($queried_entities as $entity) {
- $entity->setCompatibilityMode(FALSE);
- }
-
// Call hook_entity_load().
foreach (module_implements('entity_load') as $module) {
$function = $module . '_entity_load';
@@ -139,24 +265,79 @@ protected function attachLoad(&$queried_entities, $load_revision = FALSE) {
/**
* Maps from storage records to entity objects.
*
+ * @param array $records
+ * Associative array of query results, keyed on the entity ID.
+ * @param boolean $load_revision
+ * (optional) TRUE if the revision should be loaded, defaults to FALSE.
+ *
* @return array
* An array of entity objects implementing the EntityInterface.
*/
- protected function mapFromStorageRecords(array $records) {
+ protected function mapFromStorageRecords(array $records, $load_revision = FALSE) {
- foreach ($records as $id => $record) {
- $entity = new $this->entityClass(array(), $this->entityType);
- $entity->setCompatibilityMode(TRUE);
+ $property_values = array();
+ if ($this->dataTable) {
+ // Load data of translatable properties.
+ $property_values = $this->getPropertyValues($records, $load_revision);
+ }
+ foreach ($records as $id => $record) {
+ $values = array();
+ if (isset($property_values[$id])) {
+ $values = $property_values[$id];
+ }
foreach ($record as $name => $value) {
- $entity->{$name}[LANGUAGE_DEFAULT][0]['value'] = $value;
+ if (!isset($values[$name][LANGUAGE_DEFAULT])) {
+ // Avoid unnecessary array hierarchies to save memory.
+ $values[$name][LANGUAGE_DEFAULT] = $value;
+ }
+ }
+ $bundle = FALSE;
+ if ($this->bundleKey) {
+ $bundle = $record->{$this->bundleKey};
}
- $records[$id] = $entity;
+ // Turn the record into an entity class.
+ $records[$id] = new $this->entityClass($values, $this->entityType, $bundle);
}
return $records;
}
/**
+ * Fetches the property data in all languages for translatable properties.
+ */
+ protected function getPropertyValues($records, $load_revision = FALSE) {
+ $query = db_select($this->dataTable, 'data', array('fetch' => PDO::FETCH_ASSOC))
+ ->fields('data')
+ ->condition($this->idKey, array_keys($records))
+ ->orderBy('data.' . $this->idKey);
+ if ($load_revision) {
+ // Get revision id's.
+ $revision_ids = array();
+ foreach ($records as $id => $entity) {
+ $revision_ids[] = $entity->{$this->revisionKey};
+ }
+ $query->condition($this->revisionKey, $revision_ids);
+ }
+ $data = $query->execute();
+
+ $property_values = array();
+
+ foreach ($data as $values) {
+ // Field values in default language are stored with
+ // LANGUAGE_DEFAULT as key.
+ $langcode = LANGUAGE_DEFAULT;
+ if(empty($values['default_langcode'])) {
+ $langcode = $values['langcode'];
+ }
+
+ foreach ($this->entityInfo['schema_fields_sql']['data_table'] as $name) {
+ $property_values[$values[$this->idKey]][$name][$langcode]['value'] = $values[$name];
+ }
+ }
+ return $property_values;
+ }
+
+ /**
* Overrides DatabaseStorageController::save().
*
* Added mapping from entities to storage records before saving.
@@ -174,28 +355,45 @@ public function save(EntityInterface $entity) {
// Create the storage record to be saved.
$record = $this->maptoStorageRecord($entity);
- // Update the original values so that the compatibility mode works with
- // the update values, what is required by field API attachers.
- // @todo Once field API has been converted to use the Field API, move
- // this after insert/update hooks.
- $entity->updateOriginalValues();
if (!$entity->isNew()) {
- $return = drupal_write_record($this->entityInfo['base_table'], $record, $this->idKey);
+ if ($entity->isDefaultRevision()) {
+ $return = drupal_write_record($this->entityInfo['base_table'], $record, $this->idKey);
+ }
+ else {
+ // @todo, should a different value be returned when saving an entity
+ // with $isDefaultRevision = FALSE?
+ $return = FALSE;
+ }
+ if ($this->revisionKey) {
+ $record->{$this->revisionKey} = $this->saveRevision($entity);
+ }
+ if ($this->dataTable) {
+ $this->saveData($entity);
+ }
$this->resetCache(array($entity->id()));
$this->postSave($entity, TRUE);
$this->invokeHook('update', $entity);
}
else {
$return = drupal_write_record($this->entityInfo['base_table'], $record);
+ if ($this->revisionKey) {
+ $entity->{$this->idKey}->value = $record->{$this->idKey};
+ $record->{$this->revisionKey} = $this->saveRevision($entity);
+ }
+ $entity->{$this->idKey}->value = $record->{$this->idKey};
+ if ($this->dataTable) {
+ $this->saveData($entity);
+ }
+
// Reset general caches, but keep caches specific to certain entities.
$this->resetCache(array());
- $entity->{$this->idKey}->value = $record->{$this->idKey};
$entity->enforceIsNew(FALSE);
$this->postSave($entity, FALSE);
$this->invokeHook('insert', $entity);
}
+ $entity->updateOriginalValues();
// Ignore slave server temporarily.
db_ignore_slave();
@@ -211,16 +409,84 @@ public function save(EntityInterface $entity) {
}
/**
+ * Saves an entity revision.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $entity
+ * The entity object.
+ *
+ * @return integer
+ * The revision id.
+ */
+ protected function saveRevision(EntityInterface $entity) {
+ $record = $this->mapToRevisionStorageRecord($entity);
+
+ // When saving a new revision, set any existing revision ID to NULL so as to
+ // ensure that a new revision will actually be created.
+ if ($entity->isNewRevision() && isset($record->{$this->revisionKey})) {
+ $record->{$this->revisionKey} = NULL;
+ }
+
+ $this->preSaveRevision($record, $entity);
+
+ if ($entity->isNewRevision()) {
+ drupal_write_record($this->revisionTable, $record);
+ if ($entity->isDefaultRevision()) {
+ db_update($this->entityInfo['base_table'])
+ ->fields(array($this->revisionKey => $record->{$this->revisionKey}))
+ ->condition($this->idKey, $record->{$this->idKey})
+ ->execute();
+ }
+ $entity->setNewRevision(FALSE);
+ }
+ else {
+ drupal_write_record($this->revisionTable, $record, $this->revisionKey);
+ }
+ // Make sure to update the new revision key for the entity.
+ $entity->{$this->revisionKey}->value = $record->{$this->revisionKey};
+ return $record->{$this->revisionKey};
+ }
+
+ /**
+ * Saves the entity property data language aware.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $entity
+ * The entity object.
+ */
+ protected function saveData(EntityInterface $entity) {
+ // Delete and insert to handle removed values.
+ db_delete($this->dataTable)
+ ->condition($this->idKey, $entity->id())
+ ->execute();
+
+ $query = db_insert($this->dataTable);
+
+ foreach ($entity->getTranslationLanguages() as $langcode => $language) {
+ $record = $this->mapToDataStorageRecord($entity, $langcode);
+
+ $values = (array) $record;
+ $query
+ ->fields(array_keys($values))
+ ->values($values);
+ }
+
+ $query->execute();
+ }
+
+ /**
* Overrides DatabaseStorageController::invokeHook().
*
* Invokes field API attachers in compatibility mode and disables it
* afterwards.
*/
protected function invokeHook($hook, EntityInterface $entity) {
- if (!empty($this->entityInfo['fieldable']) && function_exists($function = 'field_attach_' . $hook)) {
- $entity->setCompatibilityMode(TRUE);
- $function($this->entityType, $entity);
- $entity->setCompatibilityMode(FALSE);
+ $function = 'field_attach_' . $hook;
+ // @todo: field_attach_delete_revision() is named the wrong way round,
+ // consider renaming it.
+ if ($function == 'field_attach_revision_delete') {
+ $function = 'field_attach_delete_revision';
+ }
+ if (!empty($this->entityInfo['fieldable']) && function_exists($function)) {
+ $function($this->entityType, $entity->getBCEntity());
}
// Invoke the hook.
@@ -235,8 +501,96 @@ protected function invokeHook($hook, EntityInterface $entity) {
protected function mapToStorageRecord(EntityInterface $entity) {
$record = new \stdClass();
foreach ($this->entityInfo['schema_fields_sql']['base_table'] as $name) {
+ switch ($entity->$name->get('value')->getType()) {
+ // Store dates using timestamps.
+ case 'date':
+ $record->$name = $entity->$name->value->getTimestamp();
+ break;
+ default:
+ $record->$name = $entity->$name->value;
+ break;
+ }
+ }
+ return $record;
+ }
+
+ /**
+ * Maps from an entity object to the storage record of the revision table.
+ */
+ protected function mapToRevisionStorageRecord(EntityInterface $entity) {
+ $record = new \stdClass();
+ foreach ($this->entityInfo['schema_fields_sql']['revision_table'] as $name) {
$record->$name = $entity->$name->value;
}
+
return $record;
}
+
+ /**
+ * Maps from an entity object to the storage record of the data table.
+ */
+ protected function mapToDataStorageRecord(EntityInterface $entity, $langcode) {
+ $default_langcode = $entity->language()->langcode;
+ // Don't use strict mode, that way there's no need to do checks here.
+ $translation = $entity->getTranslation($langcode, FALSE);
+
+ $record = new \stdClass();
+ foreach ($this->entityInfo['schema_fields_sql']['data_table'] as $name) {
+ $record->$name = $translation->$name->value;
+ }
+ $record->langcode = $langcode;
+ $record->default_langcode = intval($default_langcode == $langcode);
+
+ return $record;
+ }
+
+ /**
+ * Overwrites Drupal\Core\Entity\DatabaseStorageController::delete().
+ */
+ public function delete(array $entities) {
+ if (!$entities) {
+ // If no IDs or invalid IDs were passed, do nothing.
+ return;
+ }
+ $transaction = db_transaction();
+
+ try {
+ $this->preDelete($entities);
+ foreach ($entities as $id => $entity) {
+ $this->invokeHook('predelete', $entity);
+ }
+ $ids = array_keys($entities);
+
+ db_delete($this->entityInfo['base_table'])
+ ->condition($this->idKey, $ids, 'IN')
+ ->execute();
+
+ if ($this->revisionKey) {
+ db_delete($this->revisionTable)
+ ->condition($this->idKey, $ids, 'IN')
+ ->execute();
+ }
+
+ if ($this->dataTable) {
+ db_delete($this->dataTable)
+ ->condition($this->idKey, $ids)
+ ->execute();
+ }
+
+ // Reset the cache as soon as the changes have been applied.
+ $this->resetCache($ids);
+
+ $this->postDelete($entities);
+ foreach ($entities as $id => $entity) {
+ $this->invokeHook('delete', $entity);
+ }
+ // Ignore slave server temporarily.
+ db_ignore_slave();
+ }
+ catch (Exception $e) {
+ $transaction->rollback();
+ watchdog_exception($this->entityType, $e);
+ throw new EntityStorageException($e->getMessage, $e->getCode, $e);
+ }
+ }
}
diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php
index c6e041e..918e58e 100644
--- a/core/lib/Drupal/Core/Entity/Entity.php
+++ b/core/lib/Drupal/Core/Entity/Entity.php
@@ -370,4 +370,18 @@ public function isDefaultRevision($new_value = NULL) {
}
return $return;
}
+
+ /**
+ * Implements Drupal\Core\Entity\EntityInterface::getBCEntity().
+ */
+ public function getBCEntity() {
+ return $this;
+ }
+
+ /**
+ * Implements Drupal\Core\Entity\EntityInterface::getOriginalEntity().
+ */
+ public function getOriginalEntity() {
+ return $this;
+ }
}
diff --git a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
new file mode 100644
index 0000000..9c8b267
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
@@ -0,0 +1,321 @@
+values and $entity->fields
+ * to references itself as well, which is problematic during __clone() (this is
+ * something that would not be easy to fix as an unset() on the variable is
+ * problematic with the magic getter/setter then).
+ */
+class EntityBCDecorator implements IteratorAggregate, EntityInterface {
+
+ /**
+ * The EntityInterface object being decorated.
+ *
+ * @var \Drupal\Core\Entity\EntityInterface
+ */
+ protected $decorated;
+
+ /**
+ * Constructs a Drupal\Core\Entity\EntityCompatibilityDecorator object.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $decorated
+ * The decorated entity.
+ */
+ function __construct(EntityNG $decorated) {
+ $this->decorated = $decorated;
+ }
+
+ /**
+ * Overrides Entity::getOriginalEntity().
+ */
+ public function getOriginalEntity() {
+ return $this->decorated;
+ }
+
+ /**
+ * Overrides Entity::getBCEntity().
+ */
+ public function getBCEntity() {
+ return $this;
+ }
+
+ /**
+ * Allows direct access to the plain values, as done in Drupal 7.
+ */
+ public function &__get($name) {
+ // Make sure $this->decorated->values reflects the latest values.
+ if (!empty($this->decorated->fields[$name])) {
+ foreach ($this->decorated->fields[$name] as $langcode => $field) {
+ $this->decorated->values[$name][$langcode] = $field->getValue();
+ }
+ // Values might be changed by reference, so remove the field object to
+ // avoid them becoming out of sync.
+ unset($this->decorated->fields[$name]);
+ }
+ // Allow accessing field values in entity default languages other than
+ // LANGUAGE_DEFAULT by mapping the values to LANGUAGE_DEFAULT.
+ $langcode = $this->decorated->language()->langcode;
+ if ($langcode != LANGUAGE_DEFAULT && isset($this->decorated->values[$name][LANGUAGE_DEFAULT]) && !isset($this->decorated->values[$name][$langcode])) {
+ $this->decorated->values[$name][$langcode] = &$this->decorated->values[$name][LANGUAGE_DEFAULT];
+ }
+
+ if (!isset($this->decorated->values[$name])) {
+ $this->decorated->values[$name] = NULL;
+ }
+ return $this->decorated->values[$name];
+ }
+
+ /**
+ * Allows directly writing to the plain values, as done in Drupal 7.
+ */
+ public function __set($name, $value) {
+ if (is_array($value) && $definition = $this->decorated->getPropertyDefinition($name)) {
+ // If field API sets a value with a langcode in entity language, move it
+ // to LANGUAGE_DEFAULT.
+ foreach ($value as $langcode => $data) {
+ if ($langcode != LANGUAGE_DEFAULT && $langcode == $this->decorated->language()->langcode) {
+ $value[LANGUAGE_DEFAULT] = $data;
+ unset($value[$langcode]);
+ }
+ }
+ }
+ $this->decorated->values[$name] = $value;
+ unset($this->decorated->fields[$name]);
+ }
+
+ /**
+ * Magic method.
+ */
+ public function __isset($name) {
+ $value = $this->__get($name);
+ return isset($value);
+ }
+
+ /**
+ * Magic method.
+ */
+ public function __unset($name) {
+ $value = &$this->__get($name);
+ $value = array();
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function access(\Drupal\user\User $account = NULL) {
+ return $this->decorated->access($account);
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function get($property_name) {
+ return $this->decorated->get($property_name);
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function set($property_name, $value) {
+ return $this->decorated->set($property_name, $value);
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function getProperties($include_computed = FALSE) {
+ return $this->decorated->getProperties($include_computed);
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function getPropertyValues() {
+ return $this->decorated->getPropertyValues();
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function setPropertyValues($values) {
+ return $this->decorated->setPropertyValues($values);
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function getPropertyDefinition($name) {
+ return $this->decorated->getPropertyDefinition($name);
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function getPropertyDefinitions() {
+ return $this->decorated->getPropertyDefinitions();
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function isEmpty() {
+ return $this->decorated->isEmpty();
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function getIterator() {
+ return $this->decorated->getIterator();
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function id() {
+ return $this->decorated->id();
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function uuid() {
+ return $this->decorated->uuid();
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function isNew() {
+ return $this->decorated->isNew();
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function isNewRevision() {
+ return $this->decorated->isNewRevision();
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function setNewRevision($value = TRUE) {
+ return $this->decorated->setNewRevision($value);
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function enforceIsNew($value = TRUE) {
+ return $this->decorated->enforceIsNew($value);
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function entityType() {
+ return $this->decorated->entityType();
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function bundle() {
+ return $this->decorated->bundle();
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function label($langcode = NULL) {
+ return $this->decorated->label();
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function uri() {
+ return $this->decorated->uri();
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function save() {
+ return $this->decorated->save();
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function delete() {
+ return $this->decorated->delete();
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function createDuplicate() {
+ return $this->decorated->createDuplicate();
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function entityInfo() {
+ return $this->decorated->entityInfo();
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function getRevisionId() {
+ return $this->decorated->getRevisionId();
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function isDefaultRevision($new_value = NULL) {
+ return $this->decorated->isDefaultRevision();
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function language() {
+ return $this->decorated->language();
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function getTranslationLanguages($include_default = TRUE) {
+ return $this->decorated->getTranslationLanguages($include_default);
+ }
+
+ /**
+ * Forwards the call to the decorated entity.
+ */
+ public function getTranslation($langcode, $strict = TRUE) {
+ return $this->decorated->getTranslation($langcode, $strict);
+ }
+}
diff --git a/core/lib/Drupal/Core/Entity/EntityFormControllerNG.php b/core/lib/Drupal/Core/Entity/EntityFormControllerNG.php
index 812a192..51bc911 100644
--- a/core/lib/Drupal/Core/Entity/EntityFormControllerNG.php
+++ b/core/lib/Drupal/Core/Entity/EntityFormControllerNG.php
@@ -23,9 +23,7 @@ public function form(array $form, array &$form_state, EntityInterface $entity) {
// entity properties.
$info = $entity->entityInfo();
if (!empty($info['fieldable'])) {
- $entity->setCompatibilityMode(TRUE);
- field_attach_form($entity->entityType(), $entity, $form, $form_state, $this->getFormLangcode($form_state));
- $entity->setCompatibilityMode(FALSE);
+ field_attach_form($entity->entityType(), $entity->getBCEntity(), $form, $form_state, $this->getFormLangcode($form_state));
}
return $form;
}
@@ -40,9 +38,7 @@ public function validate(array $form, array &$form_state) {
$info = $entity->entityInfo();
if (!empty($info['fieldable'])) {
- $entity->setCompatibilityMode(TRUE);
- field_attach_form_validate($entity->entityType(), $entity, $form, $form_state);
- $entity->setCompatibilityMode(FALSE);
+ field_attach_form_validate($entity->entityType(), $entity->getBCEntity(), $form, $form_state);
}
// @todo Remove this.
@@ -82,9 +78,7 @@ public function buildEntity(array $form, array &$form_state) {
// Copy field values to the entity.
if ($info['fieldable']) {
- $entity->setCompatibilityMode(TRUE);
- field_attach_submit($entity_type, $entity, $form, $form_state);
- $entity->setCompatibilityMode(FALSE);
+ field_attach_submit($entity_type, $entity->getBCEntity(), $form, $form_state);
}
return $entity;
}
diff --git a/core/lib/Drupal/Core/Entity/EntityInterface.php b/core/lib/Drupal/Core/Entity/EntityInterface.php
index 9b751d4..e7e46fc 100644
--- a/core/lib/Drupal/Core/Entity/EntityInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityInterface.php
@@ -181,4 +181,22 @@ public function getRevisionId();
* $new_value was passed, the previous value is returned.
*/
public function isDefaultRevision($new_value = NULL);
+
+ /**
+ * Gets a backward compatibility decorator entity.
+ *
+ * @see \Drupal\Core\Entity\EntityInterface::getOriginalEntity()
+ *
+ * @return \Drupal\Core\Entity\EntityInterface
+ */
+ public function getBCEntity();
+
+ /**
+ * Removes any possibly (backward compatibility) decorator in use.
+ *
+ * @see \Drupal\Core\Entity\EntityInterface::getBCEntity()
+ *
+ * @return \Drupal\Core\Entity\EntityInterface
+ */
+ public function getOriginalEntity();
}
diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php
index e34adb6..9d95f96 100644
--- a/core/lib/Drupal/Core/Entity/EntityManager.php
+++ b/core/lib/Drupal/Core/Entity/EntityManager.php
@@ -285,6 +285,9 @@ protected function processDefinition(&$definition, $plugin_id) {
// Drupal\Core\Entity\DatabaseStorageControllerInterface::buildQuery().
if (isset($definition['base_table'])) {
$definition['schema_fields_sql']['base_table'] = drupal_schema_fields_sql($definition['base_table']);
+ if (isset($definition['data_table'])) {
+ $definition['schema_fields_sql']['data_table'] = drupal_schema_fields_sql($definition['data_table']);
+ }
if (isset($definition['revision_table'])) {
$definition['schema_fields_sql']['revision_table'] = drupal_schema_fields_sql($definition['revision_table']);
}
diff --git a/core/lib/Drupal/Core/Entity/EntityNG.php b/core/lib/Drupal/Core/Entity/EntityNG.php
index 35ef89d..76ed23d 100644
--- a/core/lib/Drupal/Core/Entity/EntityNG.php
+++ b/core/lib/Drupal/Core/Entity/EntityNG.php
@@ -26,6 +26,13 @@
class EntityNG extends Entity {
/**
+ * Local cache holding the value of the bundle field.
+ *
+ * @var string
+ */
+ protected $bundle = FALSE;
+
+ /**
* The plain data values of the contained fields.
*
* This always holds the original, unchanged values of the entity. The values
@@ -50,22 +57,60 @@ class EntityNG extends Entity {
protected $fields = array();
/**
- * Whether the entity is in pre-Entity Field API compatibility mode.
+ * An instance of the backward compatibility decorator.
+ *
+ * @var EntityBCDecorator
+ */
+ protected $bcEntity;
+
+ /**
+ * Local cache for field definitions.
*
- * If set to TRUE, field values are written directly to $this->values, thus
- * must be plain property values keyed by language code. This must be enabled
- * when calling legacy field API attachers.
+ * @see self::getPropertyDefinitions()
*
- * @var bool
+ * @var array
*/
- protected $compatibilityMode = FALSE;
+ protected $fieldDefinitions;
+ /**
+ * Overrides Entity::__construct().
+ */
+ public function __construct(array $values, $entity_type, $bundle = FALSE) {
+ $this->entityType = $entity_type;
+ $this->bundle = $bundle ? $bundle : $this->entityType;
+ foreach ($values as $key => $value) {
+ $this->values[$key] = $value;
+ }
+ $this->init();
+ }
/**
- * Overrides Entity::id().
+ * Initialize the object. Invoked upon construction and wake up.
+ */
+ protected function init() {
+ // We unset all defined properties, so magic getters apply.
+ unset($this->langcode);
+ }
+
+ /**
+ * Magic __wakeup() implemenation.
+ */
+ public function __wakeup() {
+ $this->init();
+ }
+
+ /**
+ * Implements Drupal\Core\Entity\EntityInterface::id().
*/
public function id() {
- return $this->get('id')->value;
+ return $this->id->value;
+ }
+
+ /**
+ * Implements Drupal\Core\Entity\EntityInterface::bundle().
+ */
+ public function bundle() {
+ return $this->bundle;
}
/**
@@ -105,7 +150,10 @@ protected function getTranslatedField($property_name, $langcode) {
$this->fields[$property_name][$langcode] = $this->getTranslatedField($property_name, LANGUAGE_DEFAULT);
}
else {
- $value = isset($this->values[$property_name][$langcode]) ? $this->values[$property_name][$langcode] : NULL;
+ $value = NULL;
+ if (isset($this->values[$property_name][$langcode])) {
+ $value = $this->values[$property_name][$langcode];
+ }
$context = array('parent' => $this, 'name' => $property_name);
$this->fields[$property_name][$langcode] = typed_data()->create($definition, $value, $context);
}
@@ -144,18 +192,14 @@ public function getIterator() {
* Implements ComplexDataInterface::getPropertyDefinition().
*/
public function getPropertyDefinition($name) {
- // First try getting property definitions which apply to all entities of
- // this type. Then if this fails add in definitions of optional properties
- // as well. That way we can use property definitions of base properties
- // when determining the optional properties of an entity.
- $definitions = entity_get_controller($this->entityType)->getFieldDefinitions(array());
-
- if (isset($definitions[$name])) {
- return $definitions[$name];
+ if (!isset($this->fieldDefinitions)) {
+ $this->getPropertyDefinitions();
+ }
+ if (isset($this->fieldDefinitions[$name])) {
+ return $this->fieldDefinitions[$name];
}
- // Add in optional properties if any.
- if ($definitions = $this->getPropertyDefinitions()) {
- return isset($definitions[$name]) ? $definitions[$name] : FALSE;
+ else {
+ return FALSE;
}
}
@@ -163,10 +207,13 @@ public function getPropertyDefinition($name) {
* Implements ComplexDataInterface::getPropertyDefinitions().
*/
public function getPropertyDefinitions() {
- return entity_get_controller($this->entityType)->getFieldDefinitions(array(
- 'entity type' => $this->entityType,
- 'bundle' => $this->bundle(),
- ));
+ if (!isset($this->fieldDefinitions)) {
+ $this->fieldDefinitions = entity_get_controller($this->entityType)->getFieldDefinitions(array(
+ 'entity type' => $this->entityType,
+ 'bundle' => $this->bundle,
+ ));
+ }
+ return $this->fieldDefinitions;
}
/**
@@ -208,7 +255,13 @@ public function isEmpty() {
* Implements TranslatableInterface::language().
*/
public function language() {
- return $this->get('langcode')->language;
+ $language = $this->get('langcode')->language;
+ if (!$language) {
+ // Make sure we return a proper language object.
+ // @todo Refactor this, see: http://drupal.org/node/1834542.
+ $language = language_default();
+ }
+ return $language;
}
/**
@@ -256,58 +309,67 @@ public function getTranslation($langcode, $strict = TRUE) {
*/
public function getTranslationLanguages($include_default = TRUE) {
$translations = array();
- // Build an array with the translation langcodes set as keys.
+ // Build an array with the translation langcodes set as keys. Empty
+ // translations must be filtered out.
foreach ($this->getProperties() as $name => $property) {
- if (isset($this->values[$name])) {
- $translations += $this->values[$name];
+ // @todo Figure out why we get localized non-translatable properties here
+ // and thus have to filter them!
+ $definition = $property->getDefinition();
+ if (!empty($definition['translatable'])) {
+ foreach ($this->fields[$name] as $langcode => $field) {
+ if (!$field->isEmpty()) {
+ $translations[$langcode] = TRUE;
+ }
+ if (isset($this->values[$name])) {
+ foreach ($this->values[$name] as $langcode => $values) {
+ if ($values && !(isset($this->fields[$name][$langcode]) && $this->fields[$name][$langcode]->isEmpty())) {
+ $translations[$langcode] = TRUE;
+ }
+ }
+ }
+ }
}
- $translations += $this->fields[$name];
}
unset($translations[LANGUAGE_DEFAULT]);
if ($include_default) {
$translations[$this->language()->langcode] = TRUE;
}
-
- // Now get languages based upon translation langcodes. Empty languages must
- // be filtered out as they concern empty/unset properties.
- $languages = array_intersect_key(language_list(LANGUAGE_ALL), array_filter($translations));
- return $languages;
+ // Now get languages based upon translation langcodes.
+ return array_intersect_key(language_list(LANGUAGE_ALL), $translations);
}
/**
- * Enables or disable the compatibility mode.
+ * Overrides Entity::translations().
*
- * @param bool $enabled
- * Whether to enable the mode.
- *
- * @see EntityNG::compatibilityMode
+ * @todo: Remove once Entity::translations() gets removed.
*/
- public function setCompatibilityMode($enabled) {
- $this->compatibilityMode = (bool) $enabled;
- if ($enabled) {
- $this->updateOriginalValues();
- $this->fields = array();
- }
+ public function translations() {
+ return $this->getTranslationLanguages(FALSE);
}
/**
- * Returns whether the compatibility mode is active.
+ * Overrides Entity::getBCEntity().
*/
- public function getCompatibilityMode() {
- return $this->compatibilityMode;
+ public function getBCEntity() {
+ if (!isset($this->bcEntity)) {
+ $this->bcEntity = new EntityBCDecorator($this);
+ }
+ return $this->bcEntity;
}
/**
* Updates the original values with the interim changes.
- *
- * Note: This should be called by the storage controller during a save
- * operation.
*/
public function updateOriginalValues() {
- foreach ($this->fields as $name => $properties) {
- foreach ($properties as $langcode => $property) {
- $this->values[$name][$langcode] = $property->getValue();
+ if (!$this->fields) {
+ return;
+ }
+ foreach ($this->getPropertyDefinitions() as $name => $definition) {
+ if (empty($definition['computed']) && !empty($this->fields[$name])) {
+ foreach ($this->fields[$name] as $langcode => $field) {
+ $this->values[$name][$langcode] = $field->getValue();
+ }
}
}
}
@@ -318,23 +380,24 @@ public function updateOriginalValues() {
* For compatibility mode to work this must return a reference.
*/
public function &__get($name) {
- if ($this->compatibilityMode) {
- if (!isset($this->values[$name])) {
- $this->values[$name] = NULL;
- }
- return $this->values[$name];
- }
if (isset($this->fields[$name][LANGUAGE_DEFAULT])) {
return $this->fields[$name][LANGUAGE_DEFAULT];
}
if ($this->getPropertyDefinition($name)) {
- $return = $this->get($name);
+ $return = $this->getTranslatedField($name, LANGUAGE_DEFAULT);
return $return;
}
- if (!isset($this->$name)) {
- $this->$name = NULL;
+ // Allow the EntityBCDecorator to directly access the values and fields.
+ // @todo: Remove once the EntityBCDecorator gets removed.
+ if ($name == 'values' || $name == 'fields') {
+ return $this->$name;
+ }
+ // Else directly read/write plain values. That way, fields not yet converted
+ // to the entity field API can always be directly accessed.
+ if (!isset($this->values[$name])) {
+ $this->values[$name] = NULL;
}
- return $this->$name;
+ return $this->values[$name];
}
/**
@@ -346,17 +409,16 @@ public function __set($name, $value) {
$value = $value->getValue();
}
- if ($this->compatibilityMode) {
- $this->values[$name] = $value;
- }
- elseif (isset($this->fields[$name][LANGUAGE_DEFAULT])) {
+ if (isset($this->fields[$name][LANGUAGE_DEFAULT])) {
$this->fields[$name][LANGUAGE_DEFAULT]->setValue($value);
}
elseif ($this->getPropertyDefinition($name)) {
- $this->get($name)->setValue($value);
+ $this->getTranslatedField($name, LANGUAGE_DEFAULT)->setValue($value);
}
+ // Else directly read/write plain values. That way, fields not yet converted
+ // to the entity field API can always be directly accessed.
else {
- $this->$name = $value;
+ $this->values[$name] = $value;
}
}
@@ -364,24 +426,24 @@ public function __set($name, $value) {
* Magic method.
*/
public function __isset($name) {
- if ($this->compatibilityMode) {
- return isset($this->values[$name]);
- }
- elseif ($this->getPropertyDefinition($name)) {
+ if ($this->getPropertyDefinition($name)) {
return (bool) count($this->get($name));
}
+ else {
+ return isset($this->values[$name]);
+ }
}
/**
* Magic method.
*/
public function __unset($name) {
- if ($this->compatibilityMode) {
- unset($this->values[$name]);
- }
- elseif ($this->getPropertyDefinition($name)) {
+ if ($this->getPropertyDefinition($name)) {
$this->get($name)->setValue(array());
}
+ else {
+ unset($this->values[$name]);
+ }
}
/**
@@ -404,6 +466,8 @@ public function createDuplicate() {
* Implements a deep clone.
*/
public function __clone() {
+ $this->bcEntity = NULL;
+
foreach ($this->fields as $name => $properties) {
foreach ($properties as $langcode => $property) {
$this->fields[$name][$langcode] = clone $property;
@@ -413,4 +477,19 @@ public function __clone() {
}
}
}
+
+ /**
+ * Overrides Entity::label() to access the label field with the new API.
+ */
+ public function label($langcode = NULL) {
+ $label = NULL;
+ $entity_info = $this->entityInfo();
+ if (isset($entity_info['label_callback']) && function_exists($entity_info['label_callback'])) {
+ $label = $entity_info['label_callback']($this->entityType, $this, $langcode);
+ }
+ elseif (!empty($entity_info['entity_keys']['label']) && isset($this->{$entity_info['entity_keys']['label']})) {
+ $label = $this->{$entity_info['entity_keys']['label']}->value;
+ }
+ return $label;
+ }
}
diff --git a/core/lib/Drupal/Core/Entity/EntityRenderController.php b/core/lib/Drupal/Core/Entity/EntityRenderController.php
index 2cd0578..6ccb5b9 100644
--- a/core/lib/Drupal/Core/Entity/EntityRenderController.php
+++ b/core/lib/Drupal/Core/Entity/EntityRenderController.php
@@ -37,29 +37,15 @@ public function buildContent(array $entities = array(), $view_mode = 'full', $la
drupal_alter('entity_view_mode', $view_mode, $entity, $context);
$entity->content['#view_mode'] = $view_mode;
- $prepare[$view_mode][$key] = $entity;
+ $prepare[$view_mode][$entity->id()] = $entity;
}
// Prepare and build field content, grouped by view mode.
foreach ($prepare as $view_mode => $prepare_entities) {
- $call = array();
- // To ensure hooks are only run once per entity, check for an
- // entity_view_prepared flag and only process items without it.
- foreach ($prepare_entities as $entity) {
- if (empty($entity->entity_view_prepared)) {
- // Add this entity to the items to be prepared.
- $call[$entity->id()] = $entity;
-
- // Mark this item as prepared.
- $entity->entity_view_prepared = TRUE;
- }
- }
+ field_attach_prepare_view($this->entityType, $prepare_entities, $view_mode, $langcode);
+ module_invoke_all('entity_prepare_view', $prepare_entities, $this->entityType);
- if (!empty($call)) {
- field_attach_prepare_view($this->entityType, $call, $view_mode, $langcode);
- module_invoke_all('entity_prepare_view', $call, $this->entityType);
- }
- foreach ($entities as $entity) {
+ foreach ($prepare_entities as $entity) {
$entity->content += field_attach_view($this->entityType, $entity, $view_mode, $langcode);
}
}
diff --git a/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php b/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php
index 5c71aa3..b20b8c4 100644
--- a/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php
+++ b/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php
@@ -22,6 +22,12 @@
* Entity field items making use of this base class have to implement
* ComplexDataInterface::getPropertyDefinitions().
*
+ * Available settings (below the definition's 'settings' key) are:
+ * - property {NAME}: An array containing definition overrides for the
+ * property with the name {NAME}. For example, this can be used by a
+ * computed field to easily override the 'class' key of single field value
+ * only.
+ *
* @see \Drupal\Core\Entity\Field\FieldItemInterface
*/
abstract class FieldItemBase extends TypedData implements IteratorAggregate, FieldItemInterface {
@@ -62,6 +68,12 @@ public function __construct(array $definition) {
// references on non-computed properties during construction.
$step2 = array();
foreach ($this->getPropertyDefinitions() as $name => $definition) {
+
+ // Apply any per-property definition overrides.
+ if (isset($this->definition['settings']['property ' . $name])) {
+ $definition = $this->definition['settings']['property ' . $name] + $definition;
+ }
+
if (empty($definition['computed'])) {
$context = array('name' => $name, 'parent' => $this);
$this->properties[$name] = typed_data()->create($definition, NULL, $context);
@@ -96,14 +108,19 @@ public function getValue() {
*/
public function setValue($values) {
// Treat the values as property value of the first property, if no array is
- // given and we only have one property.
- if (!is_array($values) && count($this->properties) == 1) {
+ // given.
+ if (!is_array($values)) {
$keys = array_keys($this->properties);
$values = array($keys[0] => $values);
}
foreach ($this->properties as $name => $property) {
- $property->setValue(isset($values[$name]) ? $values[$name] : NULL);
+ if (isset($values[$name])) {
+ $property->setValue($values[$name]);
+ }
+ else {
+ $property->setValue(NULL);
+ }
}
// @todo: Throw an exception for invalid values once conversion is
// totally completed.
@@ -249,7 +266,12 @@ public function getIterator() {
*/
public function getPropertyDefinition($name) {
$definitions = $this->getPropertyDefinitions();
- return isset($definitions[$name]) ? $definitions[$name] : FALSE;
+ if (isset($definitions[$name])) {
+ return $definitions[$name];
+ }
+ else {
+ return FALSE;
+ }
}
/**
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/BooleanItem.php b/core/lib/Drupal/Core/Entity/Field/Type/BooleanItem.php
index 131d0a2..b6f9df6 100644
--- a/core/lib/Drupal/Core/Entity/Field/Type/BooleanItem.php
+++ b/core/lib/Drupal/Core/Entity/Field/Type/BooleanItem.php
@@ -11,11 +11,17 @@
/**
* Defines the 'boolean_field' entity field item.
+ *
+ * Available settings (below the definition's 'settings' key) are:
+ * - property {NAME}: An array containing definition overrides for the
+ * property with the name {NAME}. For example, this can be used by a
+ * computed field to easily override the 'class' key of single field value
+ * only.
*/
class BooleanItem extends FieldItemBase {
/**
- * Field definitions of the contained properties.
+ * Definitions of the contained properties.
*
* @see self::getPropertyDefinitions()
*
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/DateItem.php b/core/lib/Drupal/Core/Entity/Field/Type/DateItem.php
index eb1ab12..20d7437 100644
--- a/core/lib/Drupal/Core/Entity/Field/Type/DateItem.php
+++ b/core/lib/Drupal/Core/Entity/Field/Type/DateItem.php
@@ -11,11 +11,17 @@
/**
* Defines the 'date_field' entity field item.
+ *
+ * Available settings (below the definition's 'settings' key) are:
+ * - property {NAME}: An array containing definition overrides for the
+ * property with the name {NAME}. For example, this can be used by a
+ * computed field to easily override the 'class' key of single field value
+ * only.
*/
class DateItem extends FieldItemBase {
/**
- * Field definitions of the contained properties.
+ * Definitions of the contained properties.
*
* @see self::getPropertyDefinitions()
*
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/EntityReferenceItem.php b/core/lib/Drupal/Core/Entity/Field/Type/EntityReferenceItem.php
index a60e65e..fede62f 100644
--- a/core/lib/Drupal/Core/Entity/Field/Type/EntityReferenceItem.php
+++ b/core/lib/Drupal/Core/Entity/Field/Type/EntityReferenceItem.php
@@ -13,13 +13,17 @@
/**
* Defines the 'entityreference_field' entity field item.
*
- * Required settings (below the definition's 'settings' key) are:
- * - entity type: The entity type to reference.
+ * Available settings (below the definition's 'settings' key) are:
+ * - entity type: (required) The entity type to reference.
+ * - property {NAME}: An array containing definition overrides for the
+ * property with the name {NAME}. For example, this can be used by a
+ * computed field to easily override the 'class' key of single field value
+ * only.
*/
class EntityReferenceItem extends FieldItemBase {
/**
- * Field definitions of the contained properties.
+ * Definitions of the contained properties.
*
* @see self::getPropertyDefinitions()
*
@@ -71,8 +75,11 @@ public function setValue($values) {
if (isset($values['value'])) {
$this->properties['value']->setValue($values['value']);
}
+ elseif (isset($values['entity'])) {
+ $this->properties['entity']->setValue($values['entity']);
+ }
else {
- $this->properties['entity']->setValue(isset($values['entity']) ? $values['entity'] : NULL);
+ $this->properties['entity']->setValue(NULL);
}
unset($values['entity'], $values['value']);
if ($values) {
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/EntityTranslation.php b/core/lib/Drupal/Core/Entity/Field/Type/EntityTranslation.php
index 0db4657..2ec798c 100644
--- a/core/lib/Drupal/Core/Entity/Field/Type/EntityTranslation.php
+++ b/core/lib/Drupal/Core/Entity/Field/Type/EntityTranslation.php
@@ -186,7 +186,12 @@ public function getIterator() {
*/
public function getPropertyDefinition($name) {
$definitions = $this->getPropertyDefinitions();
- return isset($definitions[$name]) ? $definitions[$name] : FALSE;
+ if (isset($definitions[$name])) {
+ return $definitions[$name];
+ }
+ else {
+ return FALSE;
+ }
}
/**
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/EntityWrapper.php b/core/lib/Drupal/Core/Entity/Field/Type/EntityWrapper.php
index 97449e7..d7c2f59 100644
--- a/core/lib/Drupal/Core/Entity/Field/Type/EntityWrapper.php
+++ b/core/lib/Drupal/Core/Entity/Field/Type/EntityWrapper.php
@@ -70,7 +70,7 @@ class EntityWrapper extends TypedData implements IteratorAggregate, ComplexDataI
* Implements TypedDataInterface::__construct().
*/
public function __construct(array $definition) {
- $this->definition = $definition + array('constraints' => array());
+ $this->definition = $definition;
$this->entityType = isset($this->definition['constraints']['entity type']) ? $this->definition['constraints']['entity type'] : NULL;
}
@@ -120,8 +120,10 @@ public function setValue($value) {
* Implements TypedDataInterface::getString().
*/
public function getString() {
- $entity = $this->getValue();
- return $entity ? $entity->label() : '';
+ if ($entity = $this->getValue()) {
+ return $entity->label();
+ }
+ return '';
}
/**
@@ -135,17 +137,20 @@ public function validate($value = NULL) {
* Implements IteratorAggregate::getIterator().
*/
public function getIterator() {
- $entity = $this->getValue();
- return $entity ? $entity->getIterator() : new ArrayIterator(array());
+ if ($entity = $this->getValue()) {
+ return $entity->getIterator();
+ }
+ return new ArrayIterator(array());
}
/**
* Implements ComplexDataInterface::get().
*/
public function get($property_name) {
- $entity = $this->getValue();
// @todo: Allow navigating through the tree without data as well.
- return $entity ? $entity->get($property_name) : NULL;
+ if ($entity = $this->getValue()) {
+ return $entity->get($property_name);
+ }
}
/**
@@ -187,8 +192,10 @@ public function setParent($parent) {
* Implements ComplexDataInterface::getProperties().
*/
public function getProperties($include_computed = FALSE) {
- $entity = $this->getValue();
- return $entity ? $entity->getProperties($include_computed) : array();
+ if ($entity = $this->getValue()) {
+ return $entity->getProperties($include_computed);
+ }
+ return array();
}
/**
@@ -196,7 +203,12 @@ public function getProperties($include_computed = FALSE) {
*/
public function getPropertyDefinition($name) {
$definitions = $this->getPropertyDefinitions();
- return isset($definitions[$name]) ? $definitions[$name] : FALSE;
+ if (isset($definitions[$name])) {
+ return $definitions[$name];
+ }
+ else {
+ return FALSE;
+ }
}
/**
@@ -211,8 +223,10 @@ public function getPropertyDefinitions() {
* Implements ComplexDataInterface::getPropertyValues().
*/
public function getPropertyValues() {
- $entity = $this->getValue();
- return $entity ? $entity->getPropertyValues() : array();
+ if ($entity = $this->getValue()) {
+ return $entity->getPropertyValues();
+ }
+ return array();
}
/**
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/Field.php b/core/lib/Drupal/Core/Entity/Field/Type/Field.php
index e7a5960..3756249 100644
--- a/core/lib/Drupal/Core/Entity/Field/Type/Field.php
+++ b/core/lib/Drupal/Core/Entity/Field/Type/Field.php
@@ -56,7 +56,12 @@ class Field extends TypedData implements IteratorAggregate, FieldInterface {
public function getValue() {
$values = array();
foreach ($this->list as $delta => $item) {
- $values[$delta] = !$item->isEmpty() ? $item->getValue() : NULL;
+ if (!$item->isEmpty()) {
+ $values[$delta] = $item->getValue();
+ }
+ else {
+ $values[$delta] = NULL;
+ }
}
return $values;
}
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/IntegerItem.php b/core/lib/Drupal/Core/Entity/Field/Type/IntegerItem.php
index 1f4b4e6..2ddc4d5 100644
--- a/core/lib/Drupal/Core/Entity/Field/Type/IntegerItem.php
+++ b/core/lib/Drupal/Core/Entity/Field/Type/IntegerItem.php
@@ -11,11 +11,17 @@
/**
* Defines the 'integer_field' entity field item.
+ *
+ * Available settings (below the definition's 'settings' key) are:
+ * - property {NAME}: An array containing definition overrides for the
+ * property with the name {NAME}. For example, this can be used by a
+ * computed field to easily override the 'class' key of single field value
+ * only.
*/
class IntegerItem extends FieldItemBase {
/**
- * Field definitions of the contained properties.
+ * Definitions of the contained properties.
*
* @see self::getPropertyDefinitions()
*
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/LanguageItem.php b/core/lib/Drupal/Core/Entity/Field/Type/LanguageItem.php
index f7b2a91..4527375 100644
--- a/core/lib/Drupal/Core/Entity/Field/Type/LanguageItem.php
+++ b/core/lib/Drupal/Core/Entity/Field/Type/LanguageItem.php
@@ -12,13 +12,19 @@
/**
* Defines the 'language_field' entity field item.
+ *
+ * Available settings (below the definition's 'settings' key) are:
+ * - property {NAME}: An array containing definition overrides for the
+ * property with the name {NAME}. For example, this can be used by a
+ * computed field to easily override the 'class' key of single field value
+ * only.
*/
class LanguageItem extends FieldItemBase {
/**
- * Array of property definitions of contained properties.
+ * Definitions of the contained properties.
*
- * @see PropertyEntityReferenceItem::getPropertyDefinitions()
+ * @see self::getPropertyDefinitions()
*
* @var array
*/
@@ -61,8 +67,11 @@ public function setValue($values) {
if (!empty($values['value'])) {
$this->properties['value']->setValue($values['value']);
}
+ elseif (isset($values['language'])) {
+ $this->properties['language']->setValue($values['language']);
+ }
else {
- $this->properties['language']->setValue(isset($values['language']) ? $values['language'] : NULL);
+ $this->properties['language']->setValue(NULL);
}
unset($values['language'], $values['value']);
if ($values) {
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/StringItem.php b/core/lib/Drupal/Core/Entity/Field/Type/StringItem.php
index 7c8c57a..bd22984 100644
--- a/core/lib/Drupal/Core/Entity/Field/Type/StringItem.php
+++ b/core/lib/Drupal/Core/Entity/Field/Type/StringItem.php
@@ -11,11 +11,17 @@
/**
* Defines the 'string_field' entity field item.
+ *
+ * Available settings (below the definition's 'settings' key) are:
+ * - property {NAME}: An array containing definition overrides for the
+ * property with the name {NAME}. For example, this can be used by a
+ * computed field to easily override the 'class' key of single field value
+ * only.
*/
class StringItem extends FieldItemBase {
/**
- * Field definitions of the contained properties.
+ * Definitions of the contained properties.
*
* @see self::getPropertyDefinitions()
*
diff --git a/core/lib/Drupal/Core/Plugin/Discovery/CacheDecorator.php b/core/lib/Drupal/Core/Plugin/Discovery/CacheDecorator.php
index 7a57395..33ec432 100644
--- a/core/lib/Drupal/Core/Plugin/Discovery/CacheDecorator.php
+++ b/core/lib/Drupal/Core/Plugin/Discovery/CacheDecorator.php
@@ -64,8 +64,13 @@ public function __construct(DiscoveryInterface $decorated, $cache_key, $cache_bi
* Implements Drupal\Component\Plugin\Discovery\DicoveryInterface::getDefinition().
*/
public function getDefinition($plugin_id) {
- $definitions = $this->getDefinitions();
- return isset($definitions[$plugin_id]) ? $definitions[$plugin_id] : NULL;
+ if (!isset($this->definitions)) {
+ // Initialize definitions.
+ $this->getDefinitions();
+ }
+ if (isset($this->definitions[$plugin_id])) {
+ return $this->definitions[$plugin_id];
+ }
}
/**
diff --git a/core/lib/Drupal/Core/TypedData/Type/Language.php b/core/lib/Drupal/Core/TypedData/Type/Language.php
index 67f4df8..11cd1d1 100644
--- a/core/lib/Drupal/Core/TypedData/Type/Language.php
+++ b/core/lib/Drupal/Core/TypedData/Type/Language.php
@@ -82,7 +82,9 @@ public function setParent($parent) {
public function getValue() {
$source = $this->getLanguageCodeSource();
$langcode = $source ? $source->getValue() : $this->langcode;
- return $langcode ? language_load($langcode) : NULL;
+ if ($langcode) {
+ return language_load($langcode);
+ }
}
/**
diff --git a/core/lib/Drupal/Core/TypedData/TypedDataFactory.php b/core/lib/Drupal/Core/TypedData/TypedDataFactory.php
index d245157..57f0c34 100644
--- a/core/lib/Drupal/Core/TypedData/TypedDataFactory.php
+++ b/core/lib/Drupal/Core/TypedData/TypedDataFactory.php
@@ -7,6 +7,7 @@
namespace Drupal\Core\TypedData;
+use InvalidArgumentException;
use Drupal\Component\Plugin\Factory\DefaultFactory;
use Drupal\Component\Plugin\Exception\PluginException;
@@ -29,24 +30,25 @@ class TypedDataFactory extends DefaultFactory {
* @return Drupal\Core\TypedData\TypedDataInterface
*/
public function createInstance($plugin_id, array $configuration) {
+
$type_definition = $this->discovery->getDefinition($plugin_id);
- // Allow per-data definition overrides of the used classes and generally
- // default to the data type definition.
- $definition = $configuration + $type_definition;
+ if (!isset($type_definition)) {
+ throw new InvalidArgumentException(format_string('Invalid data type %plugin_id has been given.', array('%plugin_id' => $plugin_id)));
+ }
- if (empty($definition['list'])) {
- if (empty($definition['class'])) {
- throw new PluginException(sprintf('The plugin (%s) did not specify an instance class.', $plugin_id));
- }
- $plugin_class = $definition['class'];
+ // Allow per-data definition overrides of the used classes.
+ $key = empty($configuration['list']) ? 'class' : 'list class';
+ if (isset($configuration[$key])) {
+ $class = $configuration[$key];
}
- else {
- if (empty($definition['list class'])) {
- throw new PluginException(sprintf('The plugin (%s) did not specify a list instance class.', $plugin_id));
- }
- $plugin_class = $definition['list class'];
+ elseif (isset($type_definition[$key])) {
+ $class = $type_definition[$key];
+ }
+
+ if (!isset($class)) {
+ throw new PluginException(sprintf('The plugin (%s) did not specify an instance class.', $plugin_id));
}
- return new $plugin_class($definition, $plugin_id, $this->discovery);
+ return new $class($configuration, $plugin_id);
}
}
diff --git a/core/lib/Drupal/Core/TypedData/TypedDataManager.php b/core/lib/Drupal/Core/TypedData/TypedDataManager.php
index a1522d8..d7f4ee1 100644
--- a/core/lib/Drupal/Core/TypedData/TypedDataManager.php
+++ b/core/lib/Drupal/Core/TypedData/TypedDataManager.php
@@ -94,7 +94,7 @@ public function createInstance($plugin_id, array $configuration) {
* @see Drupal\Core\Entity\Field\EntityWrapper
*/
function create(array $definition, $value = NULL, array $context = array()) {
- $wrapper = $this->createInstance($definition['type'], $definition);
+ $wrapper = $this->factory->createInstance($definition['type'], $definition);
if (isset($value)) {
$wrapper->setValue($value);
}
diff --git a/core/modules/ban/ban.module b/core/modules/ban/ban.module
index 9e9ed0f..12405ba 100644
--- a/core/modules/ban/ban.module
+++ b/core/modules/ban/ban.module
@@ -71,3 +71,30 @@ function ban_menu() {
function ban_ip_load($iid) {
return db_query("SELECT * FROM {ban_ip} WHERE iid = :iid", array(':iid' => $iid))->fetchAssoc();
}
+
+/**
+ * Implements hook_action_info().
+ */
+function ban_action_info() {
+ return array(
+ 'ban_ip_action' => array(
+ 'type' => 'user',
+ 'label' => t('Ban IP address of current user'),
+ 'configurable' => FALSE,
+ 'triggers' => array('any'),
+ ),
+ );
+}
+
+/**
+ * Bans the current user's IP address.
+ *
+ * @ingroup actions
+ */
+function ban_ip_action() {
+ $ip = ip_address();
+ db_insert('ban_ip')
+ ->fields(array('ip' => $ip))
+ ->execute();
+ watchdog('action', 'Banned IP address %ip', array('%ip' => $ip));
+}
diff --git a/core/modules/comment/comment.admin.inc b/core/modules/comment/comment.admin.inc
index 26e9c8b..7de5d39 100644
--- a/core/modules/comment/comment.admin.inc
+++ b/core/modules/comment/comment.admin.inc
@@ -109,34 +109,33 @@ function comment_admin_overview($form, &$form_state, $arg) {
foreach ($comments as $comment) {
// Remove the first node title from the node_titles array and attach to
// the comment.
- $comment->node_title = array_shift($node_titles);
- $comment_body = field_get_items('comment', $comment, 'comment_body');
- $options[$comment->cid] = array(
+ $node_title = array_shift($node_titles);
+ $options[$comment->cid->value] = array(
'subject' => array(
'data' => array(
'#type' => 'link',
- '#title' => $comment->subject,
- '#href' => 'comment/' . $comment->cid,
- '#options' => array('attributes' => array('title' => truncate_utf8($comment_body[0]['value'], 128)), 'fragment' => 'comment-' . $comment->cid),
+ '#title' => $comment->subject->value,
+ '#href' => 'comment/' . $comment->id(),
+ '#options' => array('attributes' => array('title' => truncate_utf8($comment->comment_body->value, 128)), 'fragment' => 'comment-' . $comment->id()),
),
),
- 'author' => theme('username', array('account' => $comment)),
+ 'author' => theme('username', array('account' => comment_prepare_author($comment))),
'posted_in' => array(
'data' => array(
'#type' => 'link',
- '#title' => $comment->node_title,
- '#href' => 'node/' . $comment->nid,
+ '#title' => $node_title,
+ '#href' => 'node/' . $comment->nid->value,
),
),
- 'changed' => format_date($comment->changed, 'short'),
+ 'changed' => format_date($comment->changed->value->getTimestamp(), 'short'),
);
$links = array();
$links['edit'] = array(
'title' => t('edit'),
- 'href' => 'comment/' . $comment->cid . '/edit',
+ 'href' => 'comment/' . $comment->cid->value . '/edit',
'query' => $destination,
);
- $options[$comment->cid]['operations']['data'] = array(
+ $options[$comment->cid->value]['operations']['data'] = array(
'#type' => 'operations',
'#links' => $links,
);
@@ -187,10 +186,10 @@ function comment_admin_overview_submit($form, &$form_state) {
$comment = comment_load($value);
if ($operation == 'unpublish') {
- $comment->status = COMMENT_NOT_PUBLISHED;
+ $comment->status->value = COMMENT_NOT_PUBLISHED;
}
elseif ($operation == 'publish') {
- $comment->status = COMMENT_PUBLISHED;
+ $comment->status->value = COMMENT_PUBLISHED;
}
comment_save($comment);
}
@@ -219,7 +218,7 @@ function comment_multiple_delete_confirm($form, &$form_state) {
$comment_counter = 0;
foreach (array_filter($edit['comments']) as $cid => $value) {
$comment = comment_load($cid);
- if (is_object($comment) && is_numeric($comment->cid)) {
+ if (is_object($comment) && is_numeric($comment->cid->value)) {
$subject = db_query('SELECT subject FROM {comment} WHERE cid = :cid', array(':cid' => $cid))->fetchField();
$form['comments'][$cid] = array('#type' => 'hidden', '#value' => $cid, '#prefix' => '
', '#suffix' => check_plain($subject) . '');
$comment_counter++;
@@ -283,11 +282,11 @@ function comment_confirm_delete_page($cid) {
function comment_confirm_delete($form, &$form_state, Comment $comment) {
$form_state['comment'] = $comment;
// Always provide entity id in the same form key as in the entity edit form.
- $form['cid'] = array('#type' => 'value', '#value' => $comment->cid);
+ $form['cid'] = array('#type' => 'value', '#value' => $comment->cid->value);
return confirm_form(
$form,
- t('Are you sure you want to delete the comment %title?', array('%title' => $comment->subject)),
- 'node/' . $comment->nid,
+ t('Are you sure you want to delete the comment %title?', array('%title' => $comment->subject->value)),
+ 'node/' . $comment->nid->value,
t('Any replies to this comment will be lost. This action cannot be undone.'),
t('Delete'),
t('Cancel'),
@@ -300,11 +299,11 @@ function comment_confirm_delete($form, &$form_state, Comment $comment) {
function comment_confirm_delete_submit($form, &$form_state) {
$comment = $form_state['comment'];
// Delete the comment and its replies.
- comment_delete($comment->cid);
+ comment_delete($comment->cid->value);
drupal_set_message(t('The comment and all its replies have been deleted.'));
- watchdog('content', 'Deleted comment @cid and its replies.', array('@cid' => $comment->cid));
+ watchdog('content', 'Deleted comment @cid and its replies.', array('@cid' => $comment->cid->value));
// Clear the cache so an anonymous user sees that his comment was deleted.
cache_invalidate(array('content' => TRUE));
- $form_state['redirect'] = "node/$comment->nid";
+ $form_state['redirect'] = "node/{$comment->nid->value}";
}
diff --git a/core/modules/comment/comment.api.php b/core/modules/comment/comment.api.php
index 95c3e1d..c8548a3 100644
--- a/core/modules/comment/comment.api.php
+++ b/core/modules/comment/comment.api.php
@@ -23,7 +23,7 @@
*/
function hook_comment_presave(Drupal\comment\Comment $comment) {
// Remove leading & trailing spaces from the comment subject.
- $comment->subject = trim($comment->subject);
+ $comment->subject->value = trim($comment->subject->value);
}
/**
@@ -34,7 +34,7 @@ function hook_comment_presave(Drupal\comment\Comment $comment) {
*/
function hook_comment_insert(Drupal\comment\Comment $comment) {
// Reindex the node when comments are added.
- search_touch_node($comment->nid);
+ search_touch_node($comment->nid->value);
}
/**
@@ -45,7 +45,7 @@ function hook_comment_insert(Drupal\comment\Comment $comment) {
*/
function hook_comment_update(Drupal\comment\Comment $comment) {
// Reindex the node when comments are updated.
- search_touch_node($comment->nid);
+ search_touch_node($comment->nid->value);
}
/**
@@ -75,7 +75,7 @@ function hook_comment_load(Drupal\comment\Comment $comments) {
*/
function hook_comment_view(Drupal\comment\Comment $comment, $view_mode, $langcode) {
// how old is the comment
- $comment->time_ago = time() - $comment->changed;
+ $comment->time_ago->value = time() - $comment->changed->value->getTimestamp();
}
/**
@@ -117,7 +117,7 @@ function hook_comment_view_alter(&$build, Drupal\comment\Comment $comment) {
* The comment the action is being performed on.
*/
function hook_comment_publish(Drupal\comment\Comment $comment) {
- drupal_set_message(t('Comment: @subject has been published', array('@subject' => $comment->subject)));
+ drupal_set_message(t('Comment: @subject has been published', array('@subject' => $comment->subject->value)));
}
/**
@@ -127,7 +127,7 @@ function hook_comment_publish(Drupal\comment\Comment $comment) {
* The comment the action is being performed on.
*/
function hook_comment_unpublish(Drupal\comment\Comment $comment) {
- drupal_set_message(t('Comment: @subject has been unpublished', array('@subject' => $comment->subject)));
+ drupal_set_message(t('Comment: @subject has been unpublished', array('@subject' => $comment->subject->value)));
}
/**
@@ -147,7 +147,7 @@ function hook_comment_unpublish(Drupal\comment\Comment $comment) {
function hook_comment_predelete(Drupal\comment\Comment $comment) {
// Delete a record associated with the comment in a custom table.
db_delete('example_comment_table')
- ->condition('cid', $comment->cid)
+ ->condition('cid', $comment->cid->value)
->execute();
}
@@ -166,7 +166,7 @@ function hook_comment_predelete(Drupal\comment\Comment $comment) {
* @see entity_delete_multiple()
*/
function hook_comment_delete(Drupal\comment\Comment $comment) {
- drupal_set_message(t('Comment: @subject has been deleted', array('@subject' => $comment->subject)));
+ drupal_set_message(t('Comment: @subject has been deleted', array('@subject' => $comment->subject->value)));
}
/**
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index 24f48ad..cec9727 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -147,8 +147,8 @@ function comment_node_type_load($name) {
*/
function comment_uri(Comment $comment) {
return array(
- 'path' => 'comment/' . $comment->cid,
- 'options' => array('fragment' => 'comment-' . $comment->cid),
+ 'path' => 'comment/' . $comment->cid->value,
+ 'options' => array('fragment' => 'comment-' . $comment->cid->value),
);
}
@@ -474,10 +474,10 @@ function comment_block_view($delta = '') {
* The comment listing set to the page on which the comment appears.
*/
function comment_permalink($cid) {
- if (($comment = comment_load($cid)) && ($node = node_load($comment->nid))) {
+ if (($comment = comment_load($cid)) && ($node = $comment->nid->entity)) {
// Find the current display page for this comment.
- $page = comment_get_display_page($comment->cid, $node->type);
+ $page = comment_get_display_page($comment->cid->value, $node->type);
// @todo: Cleaner sub request handling.
$request = drupal_container()->get('request');
@@ -906,7 +906,7 @@ function comment_prepare_thread(&$comments) {
$divs = 0;
foreach ($comments as $key => $comment) {
- if ($first_new && $comment->new != MARK_READ) {
+ if ($first_new && $comment->new->value != MARK_READ) {
// Assign the anchor only for the first new comment. This avoids duplicate
// id attributes on a page.
$first_new = FALSE;
@@ -915,7 +915,7 @@ function comment_prepare_thread(&$comments) {
// The $divs element instructs #prefix whether to add an indent div or
// close existing divs (a negative value).
- $comment->depth = count(explode('.', $comment->thread)) - 1;
+ $comment->depth = count(explode('.', $comment->thread->value)) - 1;
if ($comment->depth > $divs) {
$comment->divs = 1;
$divs++;
@@ -968,25 +968,25 @@ function comment_links(Comment $comment, Node $node) {
if (user_access('administer comments') && user_access('post comments')) {
$links['comment-delete'] = array(
'title' => t('delete'),
- 'href' => "comment/$comment->cid/delete",
+ 'href' => "comment/{$comment->cid->value}/delete",
'html' => TRUE,
);
$links['comment-edit'] = array(
'title' => t('edit'),
- 'href' => "comment/$comment->cid/edit",
+ 'href' => "comment/{$comment->cid->value}/edit",
'html' => TRUE,
);
$links['comment-reply'] = array(
'title' => t('reply'),
- 'href' => "comment/reply/$comment->nid/$comment->cid",
+ 'href' => "comment/reply/{$comment->nid->value}/{$comment->cid->value}",
'html' => TRUE,
);
- if ($comment->status == COMMENT_NOT_PUBLISHED) {
+ if ($comment->status->value == COMMENT_NOT_PUBLISHED) {
$links['comment-approve'] = array(
'title' => t('approve'),
- 'href' => "comment/$comment->cid/approve",
+ 'href' => "comment/{$comment->cid->value}/approve",
'html' => TRUE,
- 'query' => array('token' => drupal_get_token("comment/$comment->cid/approve")),
+ 'query' => array('token' => drupal_get_token("comment/{$comment->cid->value}/approve")),
);
}
}
@@ -994,13 +994,13 @@ function comment_links(Comment $comment, Node $node) {
if (comment_access('edit', $comment)) {
$links['comment-edit'] = array(
'title' => t('edit'),
- 'href' => "comment/$comment->cid/edit",
+ 'href' => "comment/{$comment->cid->value}/edit",
'html' => TRUE,
);
}
$links['comment-reply'] = array(
'title' => t('reply'),
- 'href' => "comment/reply/$comment->nid/$comment->cid",
+ 'href' => "comment/reply/{$comment->nid->value}/{$comment->cid->value}",
'html' => TRUE,
);
}
@@ -1347,7 +1347,7 @@ function comment_user_cancel($edit, $account, $method) {
case 'user_cancel_block_unpublish':
$comments = entity_load_multiple_by_properties('comment', array('uid' => $account->uid));
foreach ($comments as $comment) {
- $comment->status = 0;
+ $comment->status->value = 0;
comment_save($comment);
}
break;
@@ -1355,7 +1355,7 @@ function comment_user_cancel($edit, $account, $method) {
case 'user_cancel_reassign':
$comments = entity_load_multiple_by_properties('comment', array('uid' => $account->uid));
foreach ($comments as $comment) {
- $comment->uid = 0;
+ $comment->uid->value = 0;
comment_save($comment);
}
break;
@@ -1390,7 +1390,7 @@ function comment_access($op, Comment $comment) {
global $user;
if ($op == 'edit') {
- return ($user->uid && $user->uid == $comment->uid && $comment->status == COMMENT_PUBLISHED && user_access('edit own comments')) || user_access('administer comments');
+ return ($user->uid && $user->uid == $comment->uid->value && $comment->status->value == COMMENT_PUBLISHED && user_access('edit own comments')) || user_access('administer comments');
}
}
@@ -1570,7 +1570,7 @@ function comment_get_display_page($cid, $node_type) {
* @see comment_menu()
*/
function comment_edit_page(Comment $comment) {
- drupal_set_title(t('Edit comment %comment', array('%comment' => $comment->subject)), PASS_THROUGH);
+ drupal_set_title(t('Edit comment %comment', array('%comment' => $comment->subject->value)), PASS_THROUGH);
return entity_get_form($comment);
}
@@ -1584,29 +1584,25 @@ function comment_preview(Comment $comment) {
$preview_build = array();
if (!form_get_errors()) {
- $comment_body = field_get_items('comment', $comment, 'comment_body');
- $comment->format = $comment_body[0]['format'];
+ $comment->format = $comment->comment_body->format;
// Attach the user and time information.
- if (!empty($comment->name)) {
- $account = user_load_by_name($comment->name);
+ if (!empty($comment->name->value)) {
+ $account = user_load_by_name($comment->name->value);
}
elseif ($user->uid && empty($comment->is_anonymous)) {
$account = $user;
}
if (!empty($account->uid)) {
- $comment->uid = $account->uid;
- $comment->name = check_plain($account->name);
- $comment->signature = $account->signature;
- $comment->signature_format = $account->signature_format;
- $comment->picture = $account->picture;
+ $comment->uid->value = $account->uid;
+ $comment->name->value = check_plain($account->name);
}
- elseif (empty($comment->name)) {
- $comment->name = config('user.settings')->get('anonymous');
+ elseif (empty($comment->name->value)) {
+ $comment->name->value = config('user.settings')->get('anonymous');
}
- $comment->created = !empty($comment->created) ? $comment->created : REQUEST_TIME;
- $comment->changed = REQUEST_TIME;
+ $comment->created->value = !empty($comment->created->value) ? $comment->created->value : REQUEST_TIME;
+ $comment->changed->value = REQUEST_TIME;
$comment->in_preview = TRUE;
$comment_build = comment_view($comment);
$comment_build['#weight'] = -100;
@@ -1614,15 +1610,15 @@ function comment_preview(Comment $comment) {
$preview_build['comment_preview'] = $comment_build;
}
- if ($comment->pid) {
+ if ($comment->pid->value) {
$build = array();
- $comment = comment_load($comment->pid);
- if ($comment && $comment->status == COMMENT_PUBLISHED) {
+ $comment = $comment->pid->entity;
+ if ($comment && $comment->status->value == COMMENT_PUBLISHED) {
$build = comment_view($comment);
}
}
else {
- $build = node_view(node_load($comment->nid));
+ $build = node_view($comment->nid->entity);
}
$preview_build['comment_output_below'] = $build;
@@ -1641,6 +1637,22 @@ function comment_preprocess_block(&$variables) {
}
/**
+ * Prepares a user account object for rendering comment authors.
+ *
+ * This helper handles anonymous authors in addition to registered comment
+ * authors.
+ *
+ * @return \Drupal\user\User
+ * A user account, for use with theme_username() or the user_picture template.
+ */
+function comment_prepare_author(Comment $comment) {
+ if ($account = $comment->uid->entity) {
+ return $account;
+ }
+ return entity_create('user', array('uid' => 0, 'name' => $comment->name->value, 'homepage' => $comment->homepage->value));
+}
+
+/**
* Preprocesses variables for comment.tpl.php.
*
* @see comment.tpl.php
@@ -1650,31 +1662,38 @@ function template_preprocess_comment(&$variables) {
$node = $variables['elements']['#node'];
$variables['comment'] = $comment;
$variables['node'] = $node;
- $variables['author'] = theme('username', array('account' => $comment));
- $variables['created'] = format_date($comment->created);
- $variables['changed'] = format_date($comment->changed);
-
- $variables['new'] = !empty($comment->new) ? t('new') : '';
- $variables['user_picture'] = theme_get_setting('toggle_comment_user_picture') ? theme('user_picture', array('account' => $comment)) : '';
- $variables['signature'] = $comment->signature;
+ $account = comment_prepare_author($comment);
+ $variables['author'] = theme('username', array('account' => $account));
+ $variables['created'] = format_date($comment->created->value->getTimestamp());
+ $variables['changed'] = format_date($comment->changed->value->getTimestamp());
+ $variables['new'] = $comment->new->value ? t('new') : '';
+ $variables['user_picture'] = theme_get_setting('toggle_comment_user_picture') ? theme('user_picture', array('account' => $account)) : '';
+
+ if (config('user.settings')->get('signatures') && !empty($account->signature)) {
+ $variables['signature'] = check_markup($account->signature, $account->signature_format, '', TRUE) ;
+ }
+ else {
+ $variables['signature'] = '';
+ }
$uri = $comment->uri();
$uri['options'] += array('attributes' => array('class' => 'permalink', 'rel' => 'bookmark'));
- $variables['title'] = l($comment->subject, $uri['path'], $uri['options']);
+ $variables['title'] = l($comment->subject->value, $uri['path'], $uri['options']);
$variables['permalink'] = l(t('Permalink'), $uri['path'], $uri['options']);
$variables['submitted'] = t('Submitted by !username on !datetime', array('!username' => $variables['author'], '!datetime' => $variables['created']));
- if ($comment->pid > 0) {
+ if ($comment->pid->value) {
// Fetch and store the parent comment information for use in templates.
- $comment_parent = comment_load($comment->pid);
+ $comment_parent = $comment->pid->entity;
+ $account_parent = comment_prepare_author($comment);
$variables['parent_comment'] = $comment_parent;
- $variables['parent_author'] = theme('username', array('account' => $comment_parent));
- $variables['parent_created'] = format_date($comment_parent->created);
- $variables['parent_changed'] = format_date($comment_parent->changed);
+ $variables['parent_author'] = theme('username', array('account' => $account_parent));
+ $variables['parent_created'] = format_date($comment_parent->created->value->getTimestamp());
+ $variables['parent_changed'] = format_date($comment_parent->changed->value->getTimestamp());
$uri_parent = $comment_parent->uri();
$uri_parent['options'] += array('attributes' => array('class' => 'permalink', 'rel' => 'bookmark'));
- $variables['parent_title'] = l($comment_parent->subject, $uri_parent['path'], $uri_parent['options']);
+ $variables['parent_title'] = l($comment_parent->subject->value, $uri_parent['path'], $uri_parent['options']);
$variables['parent_permalink'] = l(t('Parent permalink'), $uri_parent['path'], $uri_parent['options']);
$variables['parent'] = t('In reply to !parent_title by !parent_username',
array('!parent_username' => $variables['parent_author'], '!parent_title' => $variables['parent_title']));
@@ -1690,7 +1709,7 @@ function template_preprocess_comment(&$variables) {
}
// Preprocess fields.
- field_attach_preprocess('comment', $comment, $variables['elements'], $variables);
+ field_attach_preprocess('comment', $comment->getBCEntity(), $variables['elements'], $variables);
// Helpful $content variable for templates.
foreach (element_children($variables['elements']) as $key) {
@@ -1702,7 +1721,7 @@ function template_preprocess_comment(&$variables) {
$variables['status'] = 'preview';
}
else {
- $variables['status'] = ($comment->status == COMMENT_NOT_PUBLISHED) ? 'unpublished' : 'published';
+ $variables['status'] = ($comment->status->value == COMMENT_NOT_PUBLISHED) ? 'unpublished' : 'published';
}
// Gather comment classes.
@@ -1713,14 +1732,14 @@ function template_preprocess_comment(&$variables) {
if ($variables['new']) {
$variables['attributes']['class'][] = 'new';
}
- if (!$comment->uid) {
+ if (!$comment->uid->value) {
$variables['attributes']['class'][] = 'by-anonymous';
}
else {
- if ($comment->uid == $variables['node']->uid) {
+ if ($comment->uid->value == $variables['node']->uid) {
$variables['attributes']['class'][] = 'by-node-author';
}
- if ($comment->uid == $variables['user']->uid) {
+ if ($comment->uid->value == $variables['user']->uid) {
$variables['attributes']['class'][] = 'by-viewer';
}
}
@@ -1882,9 +1901,9 @@ function comment_action_info() {
* @ingroup actions
*/
function comment_publish_action(Comment $comment = NULL, $context = array()) {
- if (isset($comment->subject)) {
- $subject = $comment->subject;
- $comment->status = COMMENT_PUBLISHED;
+ if (isset($comment->subject->value)) {
+ $subject = $comment->subject->value;
+ $comment->status->value = COMMENT_PUBLISHED;
}
else {
$cid = $context['cid'];
@@ -1909,9 +1928,9 @@ function comment_publish_action(Comment $comment = NULL, $context = array()) {
* @ingroup actions
*/
function comment_unpublish_action(Comment $comment = NULL, $context = array()) {
- if (isset($comment->subject)) {
- $subject = $comment->subject;
- $comment->status = COMMENT_NOT_PUBLISHED;
+ if (isset($comment->subject->value)) {
+ $subject = $comment->subject->value;
+ $comment->status->value = COMMENT_NOT_PUBLISHED;
}
else {
$cid = $context['cid'];
@@ -1942,8 +1961,8 @@ function comment_unpublish_by_keyword_action(Comment $comment, $context) {
foreach ($context['keywords'] as $keyword) {
$text = drupal_render($comment);
if (strpos($text, $keyword) !== FALSE) {
- $comment->status = COMMENT_NOT_PUBLISHED;
- watchdog('action', 'Unpublished comment %subject.', array('%subject' => $comment->subject));
+ $comment->status->value = COMMENT_NOT_PUBLISHED;
+ watchdog('action', 'Unpublished comment %subject.', array('%subject' => $comment->subject->value));
break;
}
}
@@ -1986,7 +2005,7 @@ function comment_unpublish_by_keyword_action_submit($form, $form_state) {
function comment_save_action(Comment $comment) {
comment_save($comment);
cache_invalidate(array('content' => TRUE));
- watchdog('action', 'Saved comment %title', array('%title' => $comment->subject));
+ watchdog('action', 'Saved comment %title', array('%title' => $comment->subject->value));
}
/**
@@ -2056,8 +2075,8 @@ function comment_rdf_mapping() {
*/
function comment_file_download_access($field, EntityInterface $entity, File $file) {
if ($entity->entityType() == 'comment') {
- if (user_access('access comments') && $entity->status == COMMENT_PUBLISHED || user_access('administer comments')) {
- $node = node_load($entity->nid);
+ if (user_access('access comments') && $entity->status->value == COMMENT_PUBLISHED || user_access('administer comments')) {
+ $node = $entity->nid->entity;
return node_access('view', $node);
}
return FALSE;
diff --git a/core/modules/comment/comment.pages.inc b/core/modules/comment/comment.pages.inc
index 6263660..e333dd7 100644
--- a/core/modules/comment/comment.pages.inc
+++ b/core/modules/comment/comment.pages.inc
@@ -56,18 +56,15 @@ function comment_reply(Node $node, $pid = NULL) {
if (user_access('access comments')) {
// Load the parent comment.
$comment = comment_load($pid);
- if ($comment->status == COMMENT_PUBLISHED) {
+ if ($comment->status->value == COMMENT_PUBLISHED) {
// If that comment exists, make sure that the current comment and the
// parent comment both belong to the same parent node.
- if ($comment->nid != $node->nid) {
+ if ($comment->nid->value != $node->nid) {
// Attempting to reply to a comment not belonging to the current nid.
drupal_set_message(t('The comment you are replying to does not exist.'), 'error');
drupal_goto("node/$node->nid");
}
// Display the parent comment
- $comment->node_type = 'comment_node_' . $node->type;
- field_attach_load('comment', array($comment->cid => $comment));
- $comment->name = $comment->uid ? $comment->registered_name : $comment->name;
$build['comment_parent'] = comment_view($comment);
}
else {
@@ -120,11 +117,11 @@ function comment_approve($cid) {
}
if ($comment = comment_load($cid)) {
- $comment->status = COMMENT_PUBLISHED;
+ $comment->status->value = COMMENT_PUBLISHED;
comment_save($comment);
drupal_set_message(t('Comment approved.'));
- drupal_goto('node/' . $comment->nid);
+ drupal_goto('node/' . $comment->nid->value);
}
throw new NotFoundHttpException();
}
diff --git a/core/modules/comment/comment.tokens.inc b/core/modules/comment/comment.tokens.inc
index c77cb67..4b93a71 100644
--- a/core/modules/comment/comment.tokens.inc
+++ b/core/modules/comment/comment.tokens.inc
@@ -122,79 +122,75 @@ function comment_tokens($type, $tokens, array $data = array(), array $options =
switch ($name) {
// Simple key values on the comment.
case 'cid':
- $replacements[$original] = $comment->cid;
+ $replacements[$original] = $comment->cid->value;
break;
// Poster identity information for comments
case 'hostname':
- $replacements[$original] = $sanitize ? check_plain($comment->hostname) : $comment->hostname;
+ $replacements[$original] = $sanitize ? check_plain($comment->hostname->value) : $comment->hostname->value;
break;
case 'name':
- $name = ($comment->uid == 0) ? config('user.settings')->get('anonymous') : $comment->name;
+ $name = ($comment->uid->value == 0) ? config('user.settings')->get('anonymous') : $comment->name->value;
$replacements[$original] = $sanitize ? filter_xss($name) : $name;
break;
case 'mail':
- if ($comment->uid != 0) {
- $account = user_load($comment->uid);
+ if ($comment->uid->value != 0) {
+ $account = user_load($comment->uid->value);
$mail = $account->mail;
}
else {
- $mail = $comment->mail;
+ $mail = $comment->mail->value;
}
$replacements[$original] = $sanitize ? check_plain($mail) : $mail;
break;
case 'homepage':
- $replacements[$original] = $sanitize ? check_url($comment->homepage) : $comment->homepage;
+ $replacements[$original] = $sanitize ? check_url($comment->homepage->value) : $comment->homepage->value;
break;
case 'title':
- $replacements[$original] = $sanitize ? filter_xss($comment->subject) : $comment->subject;
+ $replacements[$original] = $sanitize ? filter_xss($comment->subject->value) : $comment->subject->value;
break;
case 'body':
- if ($items = field_get_items('comment', $comment, 'comment_body', $langcode)) {
- $instance = field_info_instance('comment', 'body', 'comment_body');
- $field_langcode = field_language('comment', $comment, 'comment_body', $langcode);
- $replacements[$original] = $sanitize ? _text_sanitize($instance, $field_langcode, $items[0], 'value') : $items[0]['value'];
- }
+ $replacements[$original] = $sanitize ? $comment->comment_body->processed : $comment->comment_body->value;
break;
// Comment related URLs.
case 'url':
- $url_options['fragment'] = 'comment-' . $comment->cid;
- $replacements[$original] = url('comment/' . $comment->cid, $url_options);
+ $url_options['fragment'] = 'comment-' . $comment->cid->value;
+ $replacements[$original] = url('comment/' . $comment->cid->value, $url_options);
break;
case 'edit-url':
$url_options['fragment'] = NULL;
- $replacements[$original] = url('comment/' . $comment->cid . '/edit', $url_options);
+ $replacements[$original] = url('comment/' . $comment->cid->value . '/edit', $url_options);
break;
// Default values for the chained tokens handled below.
case 'author':
- $replacements[$original] = $sanitize ? filter_xss($comment->name) : $comment->name;
+ $replacements[$original] = $sanitize ? filter_xss($comment->name->value) : $comment->name->value;
break;
case 'parent':
- if (!empty($comment->pid)) {
- $parent = comment_load($comment->pid);
+ if (!empty($comment->pid->value)) {
+ $parent = comment_load($comment->pid->value);
$replacements[$original] = $sanitize ? filter_xss($parent->subject) : $parent->subject;
}
break;
case 'created':
- $replacements[$original] = format_date($comment->created, 'medium', '', NULL, $langcode);
+ $replacements[$original] = format_date($comment->created->value->getTimestamp(), 'medium', '', NULL, $langcode);
break;
case 'changed':
- $replacements[$original] = format_date($comment->changed, 'medium', '', NULL, $langcode);
+ $replacements[$original] = format_date($comment->changed->value->getTimestamp(), 'medium', '', NULL, $langcode);
break;
case 'node':
- $node = node_load($comment->nid);
+ $node = $comment->nid->entity;
$title = $node->label();
$replacements[$original] = $sanitize ? filter_xss($title) : $title;
break;
@@ -203,23 +199,23 @@ function comment_tokens($type, $tokens, array $data = array(), array $options =
// Chained token relationships.
if ($node_tokens = token_find_with_prefix($tokens, 'node')) {
- $node = node_load($comment->nid);
+ $node = $comment->nid->entity;
$replacements += token_generate('node', $node_tokens, array('node' => $node), $options);
}
if ($date_tokens = token_find_with_prefix($tokens, 'created')) {
- $replacements += token_generate('date', $date_tokens, array('date' => $comment->created), $options);
+ $replacements += token_generate('date', $date_tokens, array('date' => $comment->created->value->getTimestamp()), $options);
}
if ($date_tokens = token_find_with_prefix($tokens, 'changed')) {
- $replacements += token_generate('date', $date_tokens, array('date' => $comment->changed), $options);
+ $replacements += token_generate('date', $date_tokens, array('date' => $comment->changed->value->getTimestamp()), $options);
}
- if (($parent_tokens = token_find_with_prefix($tokens, 'parent')) && $parent = comment_load($comment->pid)) {
+ if (($parent_tokens = token_find_with_prefix($tokens, 'parent')) && $parent = $comment->pid->entity) {
$replacements += token_generate('comment', $parent_tokens, array('comment' => $parent), $options);
}
- if (($author_tokens = token_find_with_prefix($tokens, 'author')) && $account = user_load($comment->uid)) {
+ if (($author_tokens = token_find_with_prefix($tokens, 'author')) && $account = $comment->uid->entity) {
$replacements += token_generate('user', $author_tokens, array('user' => $account), $options);
}
}
diff --git a/core/modules/comment/lib/Drupal/comment/CommentFormController.php b/core/modules/comment/lib/Drupal/comment/CommentFormController.php
index f1f910e..ec47785 100644
--- a/core/modules/comment/lib/Drupal/comment/CommentFormController.php
+++ b/core/modules/comment/lib/Drupal/comment/CommentFormController.php
@@ -9,28 +9,26 @@
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\EntityFormController;
+use Drupal\Core\Entity\EntityFormControllerNG;
/**
* Base for controller for comment forms.
*/
-class CommentFormController extends EntityFormController {
+class CommentFormController extends EntityFormControllerNG {
/**
* Overrides Drupal\Core\Entity\EntityFormController::form().
*/
public function form(array $form, array &$form_state, EntityInterface $comment) {
global $user;
-
- $node = node_load($comment->nid);
- $form_state['comment']['node'] = $node;
+ $node = $comment->nid->entity;
// Use #comment-form as unique jump target, regardless of node type.
$form['#id'] = drupal_html_id('comment_form');
$form['#theme'] = array('comment_form__node_' . $node->type, 'comment_form');
$anonymous_contact = variable_get('comment_anonymous_' . $node->type, COMMENT_ANONYMOUS_MAYNOT_CONTACT);
- $is_admin = (!empty($comment->cid) && user_access('administer comments'));
+ $is_admin = (!empty($comment->cid->value) && user_access('administer comments'));
if (!$user->uid && $anonymous_contact != COMMENT_ANONYMOUS_MAYNOT_CONTACT) {
$form['#attached']['library'][] = array('system', 'jquery.cookie');
@@ -39,8 +37,8 @@ public function form(array $form, array &$form_state, EntityInterface $comment)
// If not replying to a comment, use our dedicated page callback for new
// comments on nodes.
- if (empty($comment->cid) && empty($comment->pid)) {
- $form['#action'] = url('comment/reply/' . $comment->nid);
+ if (empty($comment->cid->value) && empty($comment->pid->value)) {
+ $form['#action'] = url('comment/reply/' . $comment->nid->value);
}
if (isset($form_state['comment_preview'])) {
@@ -62,16 +60,16 @@ public function form(array $form, array &$form_state, EntityInterface $comment)
// Prepare default values for form elements.
if ($is_admin) {
- $author = (!$comment->uid && $comment->name ? $comment->name : $comment->registered_name);
- $status = (isset($comment->status) ? $comment->status : COMMENT_NOT_PUBLISHED);
- $date = (!empty($comment->date) ? $comment->date : format_date($comment->created, 'custom', 'Y-m-d H:i O'));
+ $author = $comment->name->value;
+ $status = (isset($comment->status->value) ? $comment->status->value : COMMENT_NOT_PUBLISHED);
+ $date = (!empty($comment->date) ? $comment->date : format_date($comment->created->value->getTimestamp(), 'custom', 'Y-m-d H:i O'));
}
else {
if ($user->uid) {
$author = $user->name;
}
else {
- $author = ($comment->name ? $comment->name : '');
+ $author = ($comment->name->value ? $comment->name->value : '');
}
$status = (user_access('skip comment approval') ? COMMENT_PUBLISHED : COMMENT_NOT_PUBLISHED);
$date = '';
@@ -116,7 +114,7 @@ public function form(array $form, array &$form_state, EntityInterface $comment)
$form['author']['mail'] = array(
'#type' => 'email',
'#title' => t('E-mail'),
- '#default_value' => $comment->mail,
+ '#default_value' => $comment->mail->value,
'#required' => (!$user->uid && $anonymous_contact == COMMENT_ANONYMOUS_MUST_CONTACT),
'#maxlength' => 64,
'#size' => 30,
@@ -127,7 +125,7 @@ public function form(array $form, array &$form_state, EntityInterface $comment)
$form['author']['homepage'] = array(
'#type' => 'url',
'#title' => t('Homepage'),
- '#default_value' => $comment->homepage,
+ '#default_value' => $comment->homepage->value,
'#maxlength' => 255,
'#size' => 30,
'#access' => $is_admin || (!$user->uid && $anonymous_contact != COMMENT_ANONYMOUS_MAYNOT_CONTACT),
@@ -158,36 +156,27 @@ public function form(array $form, array &$form_state, EntityInterface $comment)
'#type' => 'textfield',
'#title' => t('Subject'),
'#maxlength' => 64,
- '#default_value' => $comment->subject,
+ '#default_value' => $comment->subject->value,
'#access' => variable_get('comment_subject_field_' . $node->type, 1) == 1,
);
// Used for conditional validation of author fields.
$form['is_anonymous'] = array(
'#type' => 'value',
- '#value' => ($comment->cid ? !$comment->uid : !$user->uid),
+ '#value' => ($comment->cid->value ? !$comment->uid->value : !$user->uid),
);
- // Add internal comment properties.
- foreach (array('cid', 'pid', 'nid', 'uid') as $key) {
- $form[$key] = array('#type' => 'value', '#value' => $comment->$key);
- }
- $form['node_type'] = array('#type' => 'value', '#value' => 'comment_node_' . $node->type);
-
// Make the comment inherit the current content language unless specifically
// set.
if ($comment->isNew()) {
$language_content = language(LANGUAGE_TYPE_CONTENT);
- $comment->langcode = $language_content->langcode;
+ $comment->langcode->value = $language_content->langcode;
}
- $form['langcode'] = array(
- '#type' => 'value',
- '#value' => $comment->langcode,
- );
-
- // Attach fields.
- $comment->node_type = 'comment_node_' . $node->type;
+ // Add internal comment properties.
+ foreach (array('cid', 'pid', 'nid', 'uid', 'node_type', 'langcode') as $key) {
+ $form[$key] = array('#type' => 'value', '#value' => $comment->$key->value);
+ }
return parent::form($form, $form_state, $comment);
}
@@ -198,7 +187,7 @@ public function form(array $form, array &$form_state, EntityInterface $comment)
protected function actions(array $form, array &$form_state) {
$element = parent::actions($form, $form_state);
$comment = $this->getEntity($form_state);
- $node = $form_state['comment']['node'];
+ $node = $comment->nid->entity;
$preview_mode = variable_get('comment_preview_' . $node->type, DRUPAL_OPTIONAL);
// No delete action on the comment form.
@@ -206,7 +195,7 @@ protected function actions(array $form, array &$form_state) {
// Only show the save button if comment previews are optional or if we are
// already previewing the submission.
- $element['submit']['#access'] = ($comment->cid && user_access('administer comments')) || $preview_mode != DRUPAL_REQUIRED || isset($form_state['comment_preview']);
+ $element['submit']['#access'] = ($comment->cid->value && user_access('administer comments')) || $preview_mode != DRUPAL_REQUIRED || isset($form_state['comment_preview']);
$element['preview'] = array(
'#type' => 'submit',
@@ -268,46 +257,36 @@ public function validate(array $form, array &$form_state) {
public function submit(array $form, array &$form_state) {
$comment = parent::submit($form, $form_state);
- if (empty($comment->date)) {
- $comment->date = 'now';
- }
- $date = new DrupalDateTime($comment->date);
- $comment->created = $date->getTimestamp();
- $comment->changed = REQUEST_TIME;
+ // @todo: Move populating the entity over to self::buildEntity().
+ $date = !empty($form_state['values']['date']) ? $form_state['values']['date'] : 'now';
+ $comment->created->value = $date;
+ $comment->changed->value = REQUEST_TIME;
// If the comment was posted by a registered user, assign the author's ID.
// @todo Too fragile. Should be prepared and stored in comment_form()
// already.
- if (!$comment->is_anonymous && !empty($comment->name) && ($account = user_load_by_name($comment->name))) {
- $comment->uid = $account->uid;
+ if (!$comment->is_anonymous && !empty($comment->name->value) && ($account = user_load_by_name($comment->name->value))) {
+ $comment->uid->value = $account->uid;
}
// If the comment was posted by an anonymous user and no author name was
// required, use "Anonymous" by default.
- if ($comment->is_anonymous && (!isset($comment->name) || $comment->name === '')) {
- $comment->name = config('user.settings')->get('anonymous');
+ if ($comment->is_anonymous && (!isset($comment->name->value) || $comment->name->value === '')) {
+ $comment->name->value = config('user.settings')->get('anonymous');
}
// Validate the comment's subject. If not specified, extract from comment
// body.
- if (trim($comment->subject) == '') {
+ if (trim($comment->subject->value) == '') {
// The body may be in any format, so:
// 1) Filter it into HTML
// 2) Strip out all HTML tags
// 3) Convert entities back to plain-text.
- $field = field_info_field('comment_body');
- $langcode = field_is_translatable('comment', $field) ? $this->getFormLangcode($form_state) : LANGUAGE_NOT_SPECIFIED;
- $comment_body = $comment->comment_body[$langcode][0];
- if (isset($comment_body['format'])) {
- $comment_text = check_markup($comment_body['value'], $comment_body['format']);
- }
- else {
- $comment_text = check_plain($comment_body['value']);
- }
+ $comment_text = $comment->comment_body->processed;
$comment->subject = truncate_utf8(trim(decode_entities(strip_tags($comment_text))), 29, TRUE);
// Edge cases where the comment body is populated only by HTML tags will
// require a default subject.
- if ($comment->subject == '') {
- $comment->subject = t('(No subject)');
+ if ($comment->subject->value == '') {
+ $comment->subject->value = t('(No subject)');
}
}
@@ -343,13 +322,13 @@ public function save(array $form, array &$form_state) {
}
comment_save($comment);
- $form_state['values']['cid'] = $comment->cid;
+ $form_state['values']['cid'] = $comment->cid->value;
// Add an entry to the watchdog log.
- watchdog('content', 'Comment posted: %subject.', array('%subject' => $comment->subject), WATCHDOG_NOTICE, l(t('view'), 'comment/' . $comment->cid, array('fragment' => 'comment-' . $comment->cid)));
+ watchdog('content', 'Comment posted: %subject.', array('%subject' => $comment->subject->value), WATCHDOG_NOTICE, l(t('view'), 'comment/' . $comment->cid->value, array('fragment' => 'comment-' . $comment->cid->value)));
// Explain the approval queue if necessary.
- if ($comment->status == COMMENT_NOT_PUBLISHED) {
+ if ($comment->status->value == COMMENT_NOT_PUBLISHED) {
if (!user_access('administer comments')) {
drupal_set_message(t('Your comment has been queued for review by site administrators and will be published after approval.'));
}
@@ -359,16 +338,16 @@ public function save(array $form, array &$form_state) {
}
$query = array();
// Find the current display page for this comment.
- $page = comment_get_display_page($comment->cid, $node->type);
+ $page = comment_get_display_page($comment->cid->value, $node->type);
if ($page > 0) {
$query['page'] = $page;
}
// Redirect to the newly posted comment.
- $redirect = array('node/' . $node->nid, array('query' => $query, 'fragment' => 'comment-' . $comment->cid));
+ $redirect = array('node/' . $node->nid, array('query' => $query, 'fragment' => 'comment-' . $comment->cid->value));
}
else {
- watchdog('content', 'Comment: unauthorized comment submitted or comment submitted to a closed post %subject.', array('%subject' => $comment->subject), WATCHDOG_WARNING);
- drupal_set_message(t('Comment: unauthorized comment submitted or comment submitted to a closed post %subject.', array('%subject' => $comment->subject)), 'error');
+ watchdog('content', 'Comment: unauthorized comment submitted or comment submitted to a closed post %subject.', array('%subject' => $comment->subject->value), WATCHDOG_WARNING);
+ drupal_set_message(t('Comment: unauthorized comment submitted or comment submitted to a closed post %subject.', array('%subject' => $comment->subject->value)), 'error');
// Redirect the user to the node they are commenting on.
$redirect = 'node/' . $node->nid;
}
diff --git a/core/modules/comment/lib/Drupal/comment/CommentRenderController.php b/core/modules/comment/lib/Drupal/comment/CommentRenderController.php
index c614f8e..0ef2942 100644
--- a/core/modules/comment/lib/Drupal/comment/CommentRenderController.php
+++ b/core/modules/comment/lib/Drupal/comment/CommentRenderController.php
@@ -30,7 +30,7 @@ public function buildContent(array $entities = array(), $view_mode = 'full', $la
parent::buildContent($entities, $view_mode, $langcode);
foreach ($entities as $entity) {
- $node = node_load($entity->nid);
+ $node = $entity->nid->entity;
if (!$node) {
throw new \InvalidArgumentException(t('Invalid node for comment.'));
}
@@ -73,7 +73,7 @@ protected function alterBuild(array &$build, EntityInterface $comment, $view_mod
}
// Add anchor for each comment.
- $prefix .= "\n";
+ $prefix .= "\n";
$build['#prefix'] = $prefix;
// Close all open divs.
diff --git a/core/modules/comment/lib/Drupal/comment/CommentStorageController.php b/core/modules/comment/lib/Drupal/comment/CommentStorageController.php
index 4d447a5..24b32e0 100644
--- a/core/modules/comment/lib/Drupal/comment/CommentStorageController.php
+++ b/core/modules/comment/lib/Drupal/comment/CommentStorageController.php
@@ -8,7 +8,8 @@
namespace Drupal\comment;
use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\DatabaseStorageController;
+use Drupal\Core\Entity\DatabaseStorageControllerNG;
+use Drupal\Component\Uuid\Uuid;
use LogicException;
/**
@@ -17,7 +18,7 @@
* This extends the Drupal\Core\Entity\DatabaseStorageController class, adding
* required special handling for comment entities.
*/
-class CommentStorageController extends DatabaseStorageController {
+class CommentStorageController extends DatabaseStorageControllerNG {
/**
* The thread for which a lock was acquired.
*/
@@ -33,23 +34,46 @@ protected function buildQuery($ids, $revision_id = FALSE) {
$query->innerJoin('node', 'n', 'base.nid = n.nid');
$query->addField('n', 'type', 'node_type');
$query->innerJoin('users', 'u', 'base.uid = u.uid');
+ // @todo: Move to a computed 'name' field instead.
$query->addField('u', 'name', 'registered_name');
- $query->fields('u', array('uid', 'signature', 'signature_format', 'picture'));
return $query;
}
/**
* Overrides Drupal\Core\Entity\DatabaseStorageController::attachLoad().
*/
- protected function attachLoad(&$comments, $load_revision = FALSE) {
- // Set up standard comment properties.
- foreach ($comments as $key => $comment) {
- $comment->name = $comment->uid ? $comment->registered_name : $comment->name;
- $comment->new = node_mark($comment->nid, $comment->changed);
- $comment->node_type = 'comment_node_' . $comment->node_type;
- $comments[$key] = $comment;
+ protected function attachLoad(&$records, $load_revision = FALSE) {
+ // Prepare standard comment fields.
+ foreach ($records as $key => $record) {
+ $record->name = $record->uid ? $record->registered_name : $record->name;
+ $record->node_type = 'comment_node_' . $record->node_type;
+ $records[$key] = $record;
}
- parent::attachLoad($comments, $load_revision);
+ parent::attachLoad($records, $load_revision);
+ }
+
+ /**
+ * Overrides Drupal\Core\Entity\DatabaseStorageControllerNG::create().
+ */
+ public function create(array $values) {
+ // We have to determine the bundle first.
+ if (empty($values['node_type']) && !empty($values['nid'])) {
+ $node = node_load($values['nid']);
+ $values['node_type'] = 'comment_node_' . $node->type;
+ }
+ $comment = new $this->entityClass(array(), $this->entityType, $values['node_type']);
+
+ // Set all other given values.
+ foreach ($values as $name => $value) {
+ $comment->$name = $value;
+ }
+
+ // Assign a new UUID if there is none yet.
+ if ($this->uuidKey && !isset($comment->{$this->uuidKey})) {
+ $uuid = new Uuid();
+ $comment->{$this->uuidKey}->value = $uuid->generate();
+ }
+ return $comment;
}
/**
@@ -61,20 +85,19 @@ protected function attachLoad(&$comments, $load_revision = FALSE) {
protected function preSave(EntityInterface $comment) {
global $user;
- if (!isset($comment->status)) {
- $comment->status = user_access('skip comment approval') ? COMMENT_PUBLISHED : COMMENT_NOT_PUBLISHED;
+ if (!isset($comment->status->value)) {
+ $comment->status->value = user_access('skip comment approval') ? COMMENT_PUBLISHED : COMMENT_NOT_PUBLISHED;
}
// Make sure we have a proper bundle name.
- if (!isset($comment->node_type)) {
- $node = node_load($comment->nid);
- $comment->node_type = 'comment_node_' . $node->type;
+ if (!isset($comment->node_type->value)) {
+ $comment->node_type->value = 'comment_node_' . $comment->nid->entity->type;
}
- if (!$comment->cid) {
+ if ($comment->isNew()) {
// Add the comment to database. This next section builds the thread field.
// Also see the documentation for comment_view().
- if (!empty($comment->thread)) {
+ if (!empty($comment->thread->value)) {
// Allow calling code to set thread itself.
- $thread = $comment->thread;
+ $thread = $comment->thread->value;
}
else {
if ($this->threadLock) {
@@ -82,10 +105,10 @@ protected function preSave(EntityInterface $comment) {
// is extended in a faulty manner.
throw new LogicException('preSave is called again without calling postSave() or releaseThreadLock()');
}
- if ($comment->pid == 0) {
+ if ($comment->pid->value == 0) {
// This is a comment with no parent comment (depth 0): we start
// by retrieving the maximum thread level.
- $max = db_query('SELECT MAX(thread) FROM {comment} WHERE nid = :nid', array(':nid' => $comment->nid))->fetchField();
+ $max = db_query('SELECT MAX(thread) FROM {comment} WHERE nid = :nid', array(':nid' => $comment->nid->value))->fetchField();
// Strip the "/" from the end of the thread.
$max = rtrim($max, '/');
// We need to get the value at the correct depth.
@@ -98,14 +121,14 @@ protected function preSave(EntityInterface $comment) {
// the thread value at the proper depth.
// Get the parent comment:
- $parent = comment_load($comment->pid);
+ $parent = $comment->pid->entity;
// Strip the "/" from the end of the parent thread.
- $parent->thread = (string) rtrim((string) $parent->thread, '/');
- $prefix = $parent->thread . '.';
+ $parent->thread->value = (string) rtrim((string) $parent->thread->value, '/');
+ $prefix = $parent->thread->value . '.';
// Get the max value in *this* thread.
$max = db_query("SELECT MAX(thread) FROM {comment} WHERE thread LIKE :thread AND nid = :nid", array(
- ':thread' => $parent->thread . '.%',
- ':nid' => $comment->nid,
+ ':thread' => $parent->thread->value . '.%',
+ ':nid' => $comment->nid->value,
))->fetchField();
if ($max == '') {
@@ -119,7 +142,7 @@ protected function preSave(EntityInterface $comment) {
$max = rtrim($max, '/');
// Get the value at the correct depth.
$parts = explode('.', $max);
- $parent_depth = count(explode('.', $parent->thread));
+ $parent_depth = count(explode('.', $parent->thread->value));
$n = comment_alphadecimal_to_int($parts[$parent_depth]);
}
}
@@ -128,23 +151,23 @@ protected function preSave(EntityInterface $comment) {
// has the lock, just move to the next integer.
do {
$thread = $prefix . comment_int_to_alphadecimal(++$n) . '/';
- } while (!lock()->acquire("comment:$comment->nid:$thread"));
+ } while (!lock()->acquire("comment:{$comment->nid->value}:$thread"));
$this->threadLock = $thread;
}
- if (empty($comment->created)) {
- $comment->created = REQUEST_TIME;
+ if (empty($comment->created->value)) {
+ $comment->created->value = REQUEST_TIME;
}
- if (empty($comment->changed)) {
- $comment->changed = $comment->created;
+ if (empty($comment->changed->value)) {
+ $comment->changed->value = $comment->created->value;
}
// We test the value with '===' because we need to modify anonymous
// users as well.
- if ($comment->uid === $user->uid && isset($user->name)) {
- $comment->name = $user->name;
+ if ($comment->uid->value === $user->uid && isset($user->name)) {
+ $comment->name->value = $user->name;
}
// Add the values which aren't passed into the function.
- $comment->thread = $thread;
- $comment->hostname = ip_address();
+ $comment->thread->value = $thread;
+ $comment->hostname->value = ip_address();
}
}
@@ -154,8 +177,8 @@ protected function preSave(EntityInterface $comment) {
protected function postSave(EntityInterface $comment, $update) {
$this->releaseThreadLock();
// Update the {node_comment_statistics} table prior to executing the hook.
- $this->updateNodeStatistics($comment->nid);
- if ($comment->status == COMMENT_PUBLISHED) {
+ $this->updateNodeStatistics($comment->nid->value);
+ if ($comment->status->value == COMMENT_PUBLISHED) {
module_invoke_all('comment_publish', $comment);
}
}
@@ -172,7 +195,7 @@ protected function postDelete($comments) {
comment_delete_multiple($child_cids);
foreach ($comments as $comment) {
- $this->updateNodeStatistics($comment->nid);
+ $this->updateNodeStatistics($comment->nid->value);
}
}
@@ -246,4 +269,110 @@ protected function releaseThreadLock() {
$this->threadLock = '';
}
}
+
+ /**
+ * Implements \Drupal\Core\Entity\DataBaseStorageControllerNG::basePropertyDefinitions().
+ */
+ public function baseFieldDefinitions() {
+ $properties['cid'] = array(
+ 'label' => t('ID'),
+ 'description' => t('The comment ID.'),
+ 'type' => 'integer_field',
+ 'read-only' => TRUE,
+ );
+ $properties['uuid'] = array(
+ 'label' => t('UUID'),
+ 'description' => t('The comment UUID.'),
+ 'type' => 'string_field',
+ );
+ $properties['pid'] = array(
+ 'label' => t('Parent ID'),
+ 'description' => t('The parent comment ID if this is a reply to a comment.'),
+ 'type' => 'entityreference_field',
+ 'settings' => array('entity type' => 'comment'),
+ );
+ $properties['nid'] = array(
+ 'label' => t('Node ID'),
+ 'description' => t('The ID of the node of which this comment is a reply.'),
+ 'type' => 'entityreference_field',
+ 'settings' => array('entity type' => 'node'),
+ 'required' => TRUE,
+ );
+ $properties['langcode'] = array(
+ 'label' => t('Language code'),
+ 'description' => t('The comment language code.'),
+ 'type' => 'language_field',
+ );
+ $properties['subject'] = array(
+ 'label' => t('Subject'),
+ 'description' => t('The comment title or subject.'),
+ 'type' => 'string_field',
+ );
+ $properties['uid'] = array(
+ 'label' => t('User ID'),
+ 'description' => t('The user ID of the comment author.'),
+ 'type' => 'entityreference_field',
+ 'settings' => array('entity type' => 'user'),
+ );
+ $properties['name'] = array(
+ 'label' => t('Name'),
+ 'description' => t("The comment author's name."),
+ 'type' => 'string_field',
+ );
+ $properties['mail'] = array(
+ 'label' => t('e-mail'),
+ 'description' => t("The comment author's e-mail address."),
+ 'type' => 'string_field',
+ );
+ $properties['homepage'] = array(
+ 'label' => t('Homepage'),
+ 'description' => t("The comment author's home page address."),
+ 'type' => 'string_field',
+ );
+ $properties['hostname'] = array(
+ 'label' => t('Hostname'),
+ 'description' => t("The comment author's hostname."),
+ 'type' => 'string_field',
+ );
+ $properties['created'] = array(
+ 'label' => t('Created'),
+ 'description' => t('The time that the comment was created.'),
+ 'type' => 'date_field',
+ );
+ $properties['changed'] = array(
+ 'label' => t('Changed'),
+ 'description' => t('The time that the comment was last edited.'),
+ 'type' => 'date_field',
+ );
+ $properties['status'] = array(
+ 'label' => t('Publishing status'),
+ 'description' => t('A boolean indicating whether the comment is published.'),
+ 'type' => 'boolean_field',
+ );
+ $properties['thread'] = array(
+ 'label' => t('Thread place'),
+ 'description' => t("The alphadecimal representation of the comment's place in a thread, consisting of a base 36 string prefixed by an integer indicating its length."),
+ 'type' => 'string_field',
+ );
+ $properties['node_type'] = array(
+ // @todo: The bundle property should be stored so it's queryable.
+ 'label' => t('Node type'),
+ 'description' => t("The comment node type."),
+ 'type' => 'string_field',
+ 'queryable' => FALSE,
+ );
+ $properties['new'] = array(
+ 'label' => t('Comment new marker'),
+ 'description' => t("The comment 'new' marker for the current user (0 read, 1 new, 2 updated)."),
+ 'type' => 'integer_field',
+ 'computed' => TRUE,
+ 'settings' => array(
+ // Specify the class used for computing the field's value property.
+ 'property value' => array(
+ 'class' => '\Drupal\comment\FieldNewValue',
+ ),
+ ),
+ );
+ return $properties;
+ }
}
diff --git a/core/modules/comment/lib/Drupal/comment/FieldNewValue.php b/core/modules/comment/lib/Drupal/comment/FieldNewValue.php
new file mode 100644
index 0000000..5afd132
--- /dev/null
+++ b/core/modules/comment/lib/Drupal/comment/FieldNewValue.php
@@ -0,0 +1,90 @@
+name;
+ }
+
+ /**
+ * Implements ContextAwareInterface::setName().
+ */
+ public function setName($name) {
+ $this->name = $name;
+ }
+
+ /**
+ * Implements ContextAwareInterface::getParent().
+ *
+ * @return \Drupal\Core\Entity\Field\FieldItemInterface
+ */
+ public function getParent() {
+ return $this->parent;
+ }
+
+ /**
+ * Implements ContextAwareInterface::setParent().
+ */
+ public function setParent($parent) {
+ $this->parent = $parent;
+ }
+
+ /**
+ * Implements TypedDataInterface::getValue().
+ */
+ public function getValue($langcode = NULL) {
+ if (!isset($this->value)) {
+ if (!isset($this->parent)) {
+ throw new InvalidArgumentException('Computed properties require context for computation.');
+ }
+ $field = $this->parent->getParent();
+ $entity = $field->getParent();
+ $this->value = node_mark($entity->nid->value, $entity->changed->value->getTimestamp());
+ }
+ return $this->value;
+ }
+
+ /**
+ * Implements TypedDataInterface::setValue().
+ */
+ public function setValue($value) {
+ if (isset($value)) {
+ throw new ReadOnlyException('Unable to set a computed property.');
+ }
+ }
+}
diff --git a/core/modules/comment/lib/Drupal/comment/Plugin/Core/Entity/Comment.php b/core/modules/comment/lib/Drupal/comment/Plugin/Core/Entity/Comment.php
index e0bbfd9..7530ed0 100644
--- a/core/modules/comment/lib/Drupal/comment/Plugin/Core/Entity/Comment.php
+++ b/core/modules/comment/lib/Drupal/comment/Plugin/Core/Entity/Comment.php
@@ -8,7 +8,7 @@
namespace Drupal\comment\Plugin\Core\Entity;
use Drupal\Core\Entity\ContentEntityInterface;
-use Drupal\Core\Entity\Entity;
+use Drupal\Core\Entity\EntityNG;
use Drupal\Core\Annotation\Plugin;
use Drupal\Core\Annotation\Translation;
@@ -24,7 +24,7 @@
* form_controller_class = {
* "default" = "Drupal\comment\CommentFormController"
* },
- * translation_controller_class = "Drupal\comment\CommentTranslationController",
+ * translation_controller_class = "Drupal\translation_entity\EntityTranslationControllerNG",
* base_table = "comment",
* uri_callback = "comment_uri",
* fieldable = TRUE,
@@ -43,45 +43,51 @@
* }
* )
*/
-class Comment extends Entity implements ContentEntityInterface {
+class Comment extends EntityNG implements ContentEntityInterface {
/**
* The comment ID.
*
- * @var integer
+ * @todo Rename to 'id'.
+ *
+ * @var \Drupal\Core\Entity\Field\FieldInterface
*/
public $cid;
/**
* The comment UUID.
*
- * @var string
+ * @var \Drupal\Core\Entity\Field\FieldInterface
*/
public $uuid;
/**
* The parent comment ID if this is a reply to a comment.
*
- * @var integer
+ * @todo: Rename to 'parent_id'.
+ *
+ * @var \Drupal\Core\Entity\Field\FieldInterface
*/
public $pid;
/**
* The ID of the node to which the comment is attached.
+ *
+ * @var \Drupal\Core\Entity\Field\FieldInterface
*/
public $nid;
/**
* The comment language code.
*
- * @var string
+ * @var \Drupal\Core\Entity\Field\FieldInterface
*/
- public $langcode = LANGUAGE_NOT_SPECIFIED;
+ public $langcode;
/**
* The comment title.
*
- * @var string
+ * @var \Drupal\Core\Entity\Field\FieldInterface
*/
public $subject;
@@ -89,25 +95,25 @@ class Comment extends Entity implements ContentEntityInterface {
/**
* The comment author ID.
*
- * @var integer
+ * @var \Drupal\Core\Entity\Field\FieldInterface
*/
- public $uid = 0;
+ public $uid;
/**
* The comment author's name.
*
* For anonymous authors, this is the value as typed in the comment form.
*
- * @var string
+ * @var \Drupal\Core\Entity\Field\FieldInterface
*/
- public $name = '';
+ public $name;
/**
* The comment author's e-mail address.
*
* For anonymous authors, this is the value as typed in the comment form.
*
- * @var string
+ * @var \Drupal\Core\Entity\Field\FieldInterface
*/
public $mail;
@@ -116,21 +122,100 @@ class Comment extends Entity implements ContentEntityInterface {
*
* For anonymous authors, this is the value as typed in the comment form.
*
- * @var string
+ * @var \Drupal\Core\Entity\Field\FieldInterface
*/
public $homepage;
/**
- * Implements Drupal\Core\Entity\EntityInterface::id().
+ * The comment author's hostname.
+ *
+ * @var \Drupal\Core\Entity\Field\FieldInterface
*/
- public function id() {
- return $this->cid;
+ public $hostname;
+
+ /**
+ * The time that the comment was created.
+ *
+ * @var \Drupal\Core\Entity\Field\FieldInterface
+ */
+ public $created;
+
+ /**
+ * The time that the comment was last edited.
+ *
+ * @var \Drupal\Core\Entity\Field\FieldInterface
+ */
+ public $changed;
+
+ /**
+ * A boolean field indicating whether the comment is published.
+ *
+ * @var \Drupal\Core\Entity\Field\FieldInterface
+ */
+ public $status;
+
+ /**
+ * The alphadecimal representation of the comment's place in a thread.
+ *
+ * @var \Drupal\Core\Entity\Field\FieldInterface
+ */
+ public $thread;
+
+ /**
+ * The comment node type.
+ *
+ * @var \Drupal\Core\Entity\Field\FieldInterface
+ */
+ public $node_type;
+
+ /**
+ * The comment 'new' marker for the current user.
+ *
+ * @var \Drupal\Core\Entity\Field\FieldInterface
+ */
+ public $new;
+
+ /**
+ * The plain data values of the contained properties.
+ *
+ * Define default values.
+ *
+ * @var array
+ */
+ protected $values = array(
+ 'langcode' => array(LANGUAGE_DEFAULT => array(0 => array('value' => LANGUAGE_NOT_SPECIFIED))),
+ 'name' => array(LANGUAGE_DEFAULT => array(0 => array('value' => ''))),
+ 'uid' => array(LANGUAGE_DEFAULT => array(0 => array('value' => 0))),
+ );
+
+ /**
+ * Initialize the object. Invoked upon construction and wake up.
+ */
+ protected function init() {
+ parent::init();
+ // We unset all defined properties, so magic getters apply.
+ unset($this->cid);
+ unset($this->uuid);
+ unset($this->pid);
+ unset($this->nid);
+ unset($this->subject);
+ unset($this->uid);
+ unset($this->name);
+ unset($this->mail);
+ unset($this->homepage);
+ unset($this->hostname);
+ unset($this->created);
+ unset($this->changed);
+ unset($this->status);
+ unset($this->thread);
+ unset($this->node_type);
+ unset($this->new);
}
/**
- * Implements Drupal\Core\Entity\EntityInterface::bundle().
+ * Implements Drupal\Core\Entity\EntityInterface::id().
*/
- public function bundle() {
- return $this->node_type;
+ public function id() {
+ return $this->get('cid')->value;
}
}
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentActionsTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentActionsTest.php
index 4a2e9ca..a93d02c 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentActionsTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentActionsTest.php
@@ -35,28 +35,28 @@ function testCommentPublishUnpublishActions() {
$comment_text = $this->randomName();
$subject = $this->randomName();
$comment = $this->postComment($this->node, $comment_text, $subject);
- $comment = comment_load($comment->id);
+ $comment = comment_load($comment->id());
// Unpublish a comment (direct form: doesn't actually save the comment).
comment_unpublish_action($comment);
- $this->assertEqual($comment->status, COMMENT_NOT_PUBLISHED, 'Comment was unpublished');
+ $this->assertEqual($comment->status->value, COMMENT_NOT_PUBLISHED, 'Comment was unpublished');
$this->assertWatchdogMessage('Unpublished comment %subject.', array('%subject' => $subject), 'Found watchdog message');
$this->clearWatchdog();
// Unpublish a comment (indirect form: modify the comment in the database).
- comment_unpublish_action(NULL, array('cid' => $comment->cid));
- $this->assertEqual(comment_load($comment->cid)->status, COMMENT_NOT_PUBLISHED, 'Comment was unpublished');
+ comment_unpublish_action(NULL, array('cid' => $comment->cid->value));
+ $this->assertEqual(comment_load($comment->cid->value)->status->value, COMMENT_NOT_PUBLISHED, 'Comment was unpublished');
$this->assertWatchdogMessage('Unpublished comment %subject.', array('%subject' => $subject), 'Found watchdog message');
// Publish a comment (direct form: doesn't actually save the comment).
comment_publish_action($comment);
- $this->assertEqual($comment->status, COMMENT_PUBLISHED, 'Comment was published');
+ $this->assertEqual($comment->status->value, COMMENT_PUBLISHED, 'Comment was published');
$this->assertWatchdogMessage('Published comment %subject.', array('%subject' => $subject), 'Found watchdog message');
$this->clearWatchdog();
// Publish a comment (indirect form: modify the comment in the database).
- comment_publish_action(NULL, array('cid' => $comment->cid));
- $this->assertEqual(comment_load($comment->cid)->status, COMMENT_PUBLISHED, 'Comment was published');
+ comment_publish_action(NULL, array('cid' => $comment->cid->value));
+ $this->assertEqual(comment_load($comment->cid->value)->status->value, COMMENT_PUBLISHED, 'Comment was published');
$this->assertWatchdogMessage('Published comment %subject.', array('%subject' => $subject), 'Found watchdog message');
$this->clearWatchdog();
}
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentAnonymousTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentAnonymousTest.php
index 5e46be4..50a86b7 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentAnonymousTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentAnonymousTest.php
@@ -54,7 +54,7 @@ function testAnonymous() {
$this->setCommentAnonymous('1');
// Attempt to edit anonymous comment.
- $this->drupalGet('comment/' . $anonymous_comment1->id . '/edit');
+ $this->drupalGet('comment/' . $anonymous_comment1->id() . '/edit');
$edited_comment = $this->postComment(NULL, $this->randomName(), $this->randomName());
$this->assertTrue($this->commentExists($edited_comment, FALSE), 'Modified reply found.');
$this->drupalLogout();
@@ -99,7 +99,7 @@ function testAnonymous() {
// Make sure the user data appears correctly when editing the comment.
$this->drupalLogin($this->admin_user);
- $this->drupalGet('comment/' . $anonymous_comment3->id . '/edit');
+ $this->drupalGet('comment/' . $anonymous_comment3->id() . '/edit');
$this->assertRaw($author_name, "The anonymous user's name is correct when editing the comment.");
$this->assertRaw($author_mail, "The anonymous user's e-mail address is correct when editing the comment.");
@@ -107,19 +107,19 @@ function testAnonymous() {
$this->performCommentOperation($anonymous_comment3, 'unpublish');
$this->drupalGet('admin/content/comment/approval');
- $this->assertRaw('comments[' . $anonymous_comment3->id . ']', 'Comment was unpublished.');
+ $this->assertRaw('comments[' . $anonymous_comment3->id() . ']', 'Comment was unpublished.');
// Publish comment.
$this->performCommentOperation($anonymous_comment3, 'publish', TRUE);
$this->drupalGet('admin/content/comment');
- $this->assertRaw('comments[' . $anonymous_comment3->id . ']', 'Comment was published.');
+ $this->assertRaw('comments[' . $anonymous_comment3->id() . ']', 'Comment was published.');
// Delete comment.
$this->performCommentOperation($anonymous_comment3, 'delete');
$this->drupalGet('admin/content/comment');
- $this->assertNoRaw('comments[' . $anonymous_comment3->id . ']', 'Comment was deleted.');
+ $this->assertNoRaw('comments[' . $anonymous_comment3->id() . ']', 'Comment was deleted.');
$this->drupalLogout();
// Reset.
@@ -162,7 +162,7 @@ function testAnonymous() {
$this->assertFieldByName('subject', '', 'Subject field found.');
$this->assertFieldByName("comment_body[$langcode][0][value]", '', 'Comment field found.');
- $this->drupalGet('comment/reply/' . $this->node->nid . '/' . $anonymous_comment3->id);
+ $this->drupalGet('comment/reply/' . $this->node->nid . '/' . $anonymous_comment3->id());
$this->assertText('You are not authorized to view comments', 'Error attempting to post reply.');
$this->assertNoText($author_name, 'Comment not displayed.');
}
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentApprovalTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentApprovalTest.php
index 62a7812..e123fc4 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentApprovalTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentApprovalTest.php
@@ -47,7 +47,7 @@ function testApprovalAdminInterface() {
// Get unapproved comment id.
$this->drupalLogin($this->admin_user);
$anonymous_comment4 = $this->getUnapprovedComment($subject);
- $anonymous_comment4 = entity_create('comment', array('id' => $anonymous_comment4, 'subject' => $subject, 'comment' => $body));
+ $anonymous_comment4 = entity_create('comment', array('cid' => $anonymous_comment4, 'subject' => $subject, 'comment_body' => $body, 'nid' => $this->node->nid));
$this->drupalLogout();
$this->assertFalse($this->commentExists($anonymous_comment4), 'Anonymous comment was not published.');
@@ -69,8 +69,8 @@ function testApprovalAdminInterface() {
$this->drupalGet('admin/content/comment/approval');
$this->assertText(t('Unapproved comments (@count)', array('@count' => 2)), 'Two unapproved comments waiting for approval.');
$edit = array(
- "comments[{$comments[0]->id}]" => 1,
- "comments[{$comments[1]->id}]" => 1,
+ "comments[{$comments[0]->id()}]" => 1,
+ "comments[{$comments[1]->id()}]" => 1,
);
$this->drupalPost(NULL, $edit, t('Update'));
$this->assertText(t('Unapproved comments (@count)', array('@count' => 0)), 'All comments were approved.');
@@ -78,9 +78,9 @@ function testApprovalAdminInterface() {
// Delete multiple comments in one operation.
$edit = array(
'operation' => 'delete',
- "comments[{$comments[0]->id}]" => 1,
- "comments[{$comments[1]->id}]" => 1,
- "comments[{$anonymous_comment4->id}]" => 1,
+ "comments[{$comments[0]->id()}]" => 1,
+ "comments[{$comments[1]->id()}]" => 1,
+ "comments[{$anonymous_comment4->id()}]" => 1,
);
$this->drupalPost(NULL, $edit, t('Update'));
$this->assertText(t('Are you sure you want to delete these comments and all their children?'), 'Confirmation required.');
@@ -111,7 +111,7 @@ function testApprovalNodeInterface() {
// Get unapproved comment id.
$this->drupalLogin($this->admin_user);
$anonymous_comment4 = $this->getUnapprovedComment($subject);
- $anonymous_comment4 = entity_create('comment', array('id' => $anonymous_comment4, 'subject' => $subject, 'comment' => $body));
+ $anonymous_comment4 = entity_create('comment', array('cid' => $anonymous_comment4, 'subject' => $subject, 'comment_body' => $body, 'nid' => $this->node->nid));
$this->drupalLogout();
$this->assertFalse($this->commentExists($anonymous_comment4), 'Anonymous comment was not published.');
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentBlockTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentBlockTest.php
index 0ec3af2..6463737 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentBlockTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentBlockTest.php
@@ -85,10 +85,10 @@ function testRecentCommentBlock() {
$this->assertText($block['title'], 'Block was found.');
// Test the only the 2 latest comments are shown and in the proper order.
- $this->assertNoText($comment1->subject, 'Comment not found in block.');
- $this->assertText($comment2->subject, 'Comment found in block.');
- $this->assertText($comment3->comment, 'Comment found in block.');
- $this->assertTrue(strpos($this->drupalGetContent(), $comment3->comment) < strpos($this->drupalGetContent(), $comment2->subject), 'Comments were ordered correctly in block.');
+ $this->assertNoText($comment1->subject->value, 'Comment not found in block.');
+ $this->assertText($comment2->subject->value, 'Comment found in block.');
+ $this->assertText($comment3->comment_body->value, 'Comment found in block.');
+ $this->assertTrue(strpos($this->drupalGetContent(), $comment3->comment_body->value) < strpos($this->drupalGetContent(), $comment2->subject->value), 'Comments were ordered correctly in block.');
// Set the number of recent comments to show to 10.
$this->drupalLogout();
@@ -103,21 +103,21 @@ function testRecentCommentBlock() {
$comment4 = $this->postComment($this->node, $this->randomName(), $this->randomName());
// Test that all four comments are shown.
- $this->assertText($comment1->subject, 'Comment found in block.');
- $this->assertText($comment2->subject, 'Comment found in block.');
- $this->assertText($comment3->comment, 'Comment found in block.');
- $this->assertText($comment4->subject, 'Comment found in block.');
+ $this->assertText($comment1->subject->value, 'Comment found in block.');
+ $this->assertText($comment2->subject->value, 'Comment found in block.');
+ $this->assertText($comment3->comment_body->value, 'Comment found in block.');
+ $this->assertText($comment4->subject->value, 'Comment found in block.');
// Test that links to comments work when comments are across pages.
$this->setCommentsPerPage(1);
$this->drupalGet('');
- $this->clickLink($comment1->subject);
- $this->assertText($comment1->subject, 'Comment link goes to correct page.');
+ $this->clickLink($comment1->subject->value);
+ $this->assertText($comment1->subject->value, 'Comment link goes to correct page.');
$this->drupalGet('');
- $this->clickLink($comment2->subject);
- $this->assertText($comment2->subject, 'Comment link goes to correct page.');
- $this->clickLink($comment4->subject);
- $this->assertText($comment4->subject, 'Comment link goes to correct page.');
+ $this->clickLink($comment2->subject->value);
+ $this->assertText($comment2->subject->value, 'Comment link goes to correct page.');
+ $this->clickLink($comment4->subject->value);
+ $this->assertText($comment4->subject->value, 'Comment link goes to correct page.');
// Check that when viewing a comment page from a link to the comment, that
// rel="canonical" is added to the head of the document.
$this->assertRaw('randomName();
$comment_text = $this->randomName();
$comment = $this->postComment($this->node, $comment_text, $subject_text, TRUE);
- $comment_loaded = comment_load($comment->id);
+ $comment_loaded = comment_load($comment->id());
$this->assertTrue($this->commentExists($comment), 'Comment found.');
// Add the property to the content array and then see if it still exists on build.
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentInterfaceTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentInterfaceTest.php
index 1070107..00a4291 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentInterfaceTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentInterfaceTest.php
@@ -37,7 +37,6 @@ function testCommentInterface() {
$this->drupalLogin($this->web_user);
$comment_text = $this->randomName();
$comment = $this->postComment($this->node, $comment_text);
- $comment_loaded = comment_load($comment->id);
$this->assertTrue($this->commentExists($comment), 'Comment found.');
// Set comments to have subject and preview to required.
@@ -52,11 +51,10 @@ function testCommentInterface() {
$subject_text = $this->randomName();
$comment_text = $this->randomName();
$comment = $this->postComment($this->node, $comment_text, $subject_text, TRUE);
- $comment_loaded = comment_load($comment->id);
$this->assertTrue($this->commentExists($comment), 'Comment found.');
// Check comment display.
- $this->drupalGet('node/' . $this->node->nid . '/' . $comment->id);
+ $this->drupalGet('node/' . $this->node->nid . '/' . $comment->id());
$this->assertText($subject_text, 'Individual comment subject found.');
$this->assertText($comment_text, 'Individual comment body found.');
@@ -67,49 +65,49 @@ function testCommentInterface() {
$this->setCommentPreview(DRUPAL_OPTIONAL);
// Test changing the comment author to "Anonymous".
- $this->drupalGet('comment/' . $comment->id . '/edit');
- $comment = $this->postComment(NULL, $comment->comment, $comment->subject, array('name' => ''));
- $comment_loaded = comment_load($comment->id);
- $this->assertTrue(empty($comment_loaded->name) && $comment_loaded->uid == 0, 'Comment author successfully changed to anonymous.');
+ $this->drupalGet('comment/' . $comment->id() . '/edit');
+ $comment = $this->postComment(NULL, $comment->comment_body->value, $comment->subject->value, array('name' => ''));
+ $comment_loaded = comment_load($comment->id());
+ $this->assertTrue(empty($comment_loaded->name->value) && $comment_loaded->uid->value == 0, 'Comment author successfully changed to anonymous.');
// Test changing the comment author to an unverified user.
$random_name = $this->randomName();
- $this->drupalGet('comment/' . $comment->id . '/edit');
- $comment = $this->postComment(NULL, $comment->comment, $comment->subject, array('name' => $random_name));
+ $this->drupalGet('comment/' . $comment->id() . '/edit');
+ $comment = $this->postComment(NULL, $comment->comment_body->value, $comment->subject->value, array('name' => $random_name));
$this->drupalGet('node/' . $this->node->nid);
$this->assertText($random_name . ' (' . t('not verified') . ')', 'Comment author successfully changed to an unverified user.');
// Test changing the comment author to a verified user.
- $this->drupalGet('comment/' . $comment->id . '/edit');
- $comment = $this->postComment(NULL, $comment->comment, $comment->subject, array('name' => $this->web_user->name));
- $comment_loaded = comment_load($comment->id);
- $this->assertTrue($comment_loaded->name == $this->web_user->name && $comment_loaded->uid == $this->web_user->uid, 'Comment author successfully changed to a registered user.');
+ $this->drupalGet('comment/' . $comment->id() . '/edit');
+ $comment = $this->postComment(NULL, $comment->comment_body->value, $comment->subject->value, array('name' => $this->web_user->name));
+ $comment_loaded = comment_load($comment->id());
+ $this->assertTrue($comment_loaded->name->value == $this->web_user->name && $comment_loaded->uid->value == $this->web_user->uid, 'Comment author successfully changed to a registered user.');
$this->drupalLogout();
// Reply to comment #2 creating comment #3 with optional preview and no
// subject though field enabled.
$this->drupalLogin($this->web_user);
- $this->drupalGet('comment/reply/' . $this->node->nid . '/' . $comment->id);
+ $this->drupalGet('comment/reply/' . $this->node->nid . '/' . $comment->id());
$this->assertText($subject_text, 'Individual comment-reply subject found.');
$this->assertText($comment_text, 'Individual comment-reply body found.');
$reply = $this->postComment(NULL, $this->randomName(), '', TRUE);
- $reply_loaded = comment_load($reply->id);
+ $reply_loaded = comment_load($reply->id());
$this->assertTrue($this->commentExists($reply, TRUE), 'Reply found.');
- $this->assertEqual($comment->id, $reply_loaded->pid, 'Pid of a reply to a comment is set correctly.');
- $this->assertEqual(rtrim($comment_loaded->thread, '/') . '.00/', $reply_loaded->thread, 'Thread of reply grows correctly.');
+ $this->assertEqual($comment->id(), $reply_loaded->pid->value, 'Pid of a reply to a comment is set correctly.');
+ $this->assertEqual(rtrim($comment_loaded->thread->value, '/') . '.00/', $reply_loaded->thread->value, 'Thread of reply grows correctly.');
// Second reply to comment #3 creating comment #4.
- $this->drupalGet('comment/reply/' . $this->node->nid . '/' . $comment->id);
+ $this->drupalGet('comment/reply/' . $this->node->nid . '/' . $comment->id());
$this->assertText($subject_text, 'Individual comment-reply subject found.');
$this->assertText($comment_text, 'Individual comment-reply body found.');
$reply = $this->postComment(NULL, $this->randomName(), $this->randomName(), TRUE);
- $reply_loaded = comment_load($reply->id);
+ $reply_loaded = comment_load($reply->id());
$this->assertTrue($this->commentExists($reply, TRUE), 'Second reply found.');
- $this->assertEqual(rtrim($comment_loaded->thread, '/') . '.01/', $reply_loaded->thread, 'Thread of second reply grows correctly.');
+ $this->assertEqual(rtrim($comment_loaded->thread->value, '/') . '.01/', $reply_loaded->thread->value, 'Thread of second reply grows correctly.');
// Edit reply.
- $this->drupalGet('comment/' . $reply->id . '/edit');
+ $this->drupalGet('comment/' . $reply->id() . '/edit');
$reply = $this->postComment(NULL, $this->randomName(), $this->randomName(), TRUE);
$this->assertTrue($this->commentExists($reply, TRUE), 'Modified reply found.');
@@ -126,9 +124,9 @@ function testCommentInterface() {
$this->setCommentsPerPage(50);
// Attempt to reply to an unpublished comment.
- $reply_loaded->status = COMMENT_NOT_PUBLISHED;
+ $reply_loaded->status->value = COMMENT_NOT_PUBLISHED;
$reply_loaded->save();
- $this->drupalGet('comment/reply/' . $this->node->nid . '/' . $reply_loaded->cid);
+ $this->drupalGet('comment/reply/' . $this->node->nid . '/' . $reply_loaded->cid->value);
$this->assertText(t('The comment you are replying to does not exist.'), 'Replying to an unpublished comment');
// Attempt to post to node with comments disabled.
@@ -178,5 +176,4 @@ function testCommentInterface() {
$this->drupalLogin($this->admin_user);
$this->setCommentForm(FALSE);
}
-
}
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php
index a704fb7..aea8986 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php
@@ -127,9 +127,9 @@ function testCommentLanguage() {
->execute()
->fetchField();
$comment = comment_load($cid);
- $args = array('%node_language' => $node_langcode, '%comment_language' => $comment->langcode, '%langcode' => $langcode);
- $this->assertEqual($comment->langcode, $langcode, format_string('The comment posted with content language %langcode and belonging to the node with language %node_language has language %comment_language', $args));
- $this->assertEqual($comment->comment_body[$langcode][0]['value'], $comment_values[$node_langcode][$langcode], 'Comment body correctly stored.');
+ $args = array('%node_language' => $node_langcode, '%comment_language' => $comment->langcode->value, '%langcode' => $langcode);
+ $this->assertEqual($comment->langcode->value, $langcode, format_string('The comment posted with content language %langcode and belonging to the node with language %node_language has language %comment_language', $args));
+ $this->assertEqual($comment->comment_body->value, $comment_values[$node_langcode][$langcode], 'Comment body correctly stored.');
}
}
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentNodeAccessTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentNodeAccessTest.php
index 37809c6..7910196 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentNodeAccessTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentNodeAccessTest.php
@@ -52,7 +52,6 @@ function setUp() {
* Test that threaded comments can be viewed.
*/
function testThreadedCommentView() {
- $langcode = LANGUAGE_NOT_SPECIFIED;
// Set comments to have subject required and preview disabled.
$this->drupalLogin($this->admin_user);
$this->setCommentPreview(DRUPAL_DISABLED);
@@ -66,20 +65,18 @@ function testThreadedCommentView() {
$comment_text = $this->randomName();
$comment_subject = $this->randomName();
$comment = $this->postComment($this->node, $comment_text, $comment_subject);
- $comment_loaded = comment_load($comment->id);
$this->assertTrue($this->commentExists($comment), 'Comment found.');
// Check comment display.
- $this->drupalGet('node/' . $this->node->nid . '/' . $comment->id);
+ $this->drupalGet('node/' . $this->node->nid . '/' . $comment->id());
$this->assertText($comment_subject, 'Individual comment subject found.');
$this->assertText($comment_text, 'Individual comment body found.');
// Reply to comment, creating second comment.
- $this->drupalGet('comment/reply/' . $this->node->nid . '/' . $comment->id);
+ $this->drupalGet('comment/reply/' . $this->node->nid . '/' . $comment->id());
$reply_text = $this->randomName();
$reply_subject = $this->randomName();
$reply = $this->postComment(NULL, $reply_text, $reply_subject, TRUE);
- $reply_loaded = comment_load($reply->id);
$this->assertTrue($this->commentExists($reply, TRUE), 'Reply found.');
// Go to the node page and verify comment and reply are visible.
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentNodeChangesTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentNodeChangesTest.php
index b517d04..b27412c 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentNodeChangesTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentNodeChangesTest.php
@@ -26,8 +26,8 @@ public static function getInfo() {
function testNodeDeletion() {
$this->drupalLogin($this->web_user);
$comment = $this->postComment($this->node, $this->randomName(), $this->randomName());
- $this->assertTrue(comment_load($comment->id), 'The comment could be loaded.');
+ $this->assertTrue(comment_load($comment->id()), 'The comment could be loaded.');
node_delete($this->node->nid);
- $this->assertFalse(comment_load($comment->id), 'The comment could not be loaded after the node was deleted.');
+ $this->assertFalse(comment_load($comment->id()), 'The comment could not be loaded after the node was deleted.');
}
}
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentPagerTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentPagerTest.php
index 52f1e32..644001c 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentPagerTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentPagerTest.php
@@ -66,7 +66,7 @@ function testCommentPaging() {
// Post a reply to the oldest comment and test again.
$replies = array();
$oldest_comment = reset($comments);
- $this->drupalGet('comment/reply/' . $node->nid . '/' . $oldest_comment->id);
+ $this->drupalGet('comment/reply/' . $node->nid . '/' . $oldest_comment->id());
$reply = $this->postComment(NULL, $this->randomName(), $this->randomName(), TRUE);
$this->setCommentsPerPage(2);
@@ -114,19 +114,19 @@ function testCommentOrderingThreading() {
$comments[] = $this->postComment($node, $this->randomName(), $this->randomName(), TRUE);
// Post a reply to the second comment.
- $this->drupalGet('comment/reply/' . $node->nid . '/' . $comments[1]->id);
+ $this->drupalGet('comment/reply/' . $node->nid . '/' . $comments[1]->id());
$comments[] = $this->postComment(NULL, $this->randomName(), $this->randomName(), TRUE);
// Post a reply to the first comment.
- $this->drupalGet('comment/reply/' . $node->nid . '/' . $comments[0]->id);
+ $this->drupalGet('comment/reply/' . $node->nid . '/' . $comments[0]->id());
$comments[] = $this->postComment(NULL, $this->randomName(), $this->randomName(), TRUE);
// Post a reply to the last comment.
- $this->drupalGet('comment/reply/' . $node->nid . '/' . $comments[2]->id);
+ $this->drupalGet('comment/reply/' . $node->nid . '/' . $comments[2]->id());
$comments[] = $this->postComment(NULL, $this->randomName(), $this->randomName(), TRUE);
// Post a reply to the second comment.
- $this->drupalGet('comment/reply/' . $node->nid . '/' . $comments[3]->id);
+ $this->drupalGet('comment/reply/' . $node->nid . '/' . $comments[3]->id());
$comments[] = $this->postComment(NULL, $this->randomName(), $this->randomName(), TRUE);
// At this point, the comment tree is:
@@ -180,7 +180,7 @@ function assertCommentOrder(array $comments, array $expected_order) {
// First, rekey the expected order by cid.
foreach ($expected_order as $key) {
- $expected_cids[] = $comments[$key]->id;
+ $expected_cids[] = $comments[$key]->id();
}
$comment_anchors = $this->xpath('//a[starts-with(@id,"comment-")]');
@@ -188,8 +188,7 @@ function assertCommentOrder(array $comments, array $expected_order) {
foreach ($comment_anchors as $anchor) {
$result_order[] = substr($anchor['id'], 8);
}
-
- return $this->assertIdentical($expected_cids, $result_order, format_string('Comment order: expected @expected, returned @returned.', array('@expected' => implode(',', $expected_cids), '@returned' => implode(',', $result_order))));
+ return $this->assertEqual($expected_cids, $result_order, format_string('Comment order: expected @expected, returned @returned.', array('@expected' => implode(',', $expected_cids), '@returned' => implode(',', $result_order))));
}
/**
@@ -215,15 +214,15 @@ function testCommentNewPageIndicator() {
$comments[] = $this->postComment($node, $this->randomName(), $this->randomName(), TRUE);
// Post a reply to the second comment.
- $this->drupalGet('comment/reply/' . $node->nid . '/' . $comments[1]->id);
+ $this->drupalGet('comment/reply/' . $node->nid . '/' . $comments[1]->id());
$comments[] = $this->postComment(NULL, $this->randomName(), $this->randomName(), TRUE);
// Post a reply to the first comment.
- $this->drupalGet('comment/reply/' . $node->nid . '/' . $comments[0]->id);
+ $this->drupalGet('comment/reply/' . $node->nid . '/' . $comments[0]->id());
$comments[] = $this->postComment(NULL, $this->randomName(), $this->randomName(), TRUE);
// Post a reply to the last comment.
- $this->drupalGet('comment/reply/' . $node->nid . '/' . $comments[2]->id);
+ $this->drupalGet('comment/reply/' . $node->nid . '/' . $comments[2]->id());
$comments[] = $this->postComment(NULL, $this->randomName(), $this->randomName(), TRUE);
// At this point, the comment tree is:
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentPreviewTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentPreviewTest.php
index 44a38d5..f63c8bc 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentPreviewTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentPreviewTest.php
@@ -95,7 +95,7 @@ function testCommentEditPreviewSave() {
$expected_text_date = format_date($raw_date);
$expected_form_date = format_date($raw_date, 'custom', 'Y-m-d H:i O');
$comment = $this->postComment($this->node, $edit['subject'], $edit['comment_body[' . $langcode . '][0][value]'], TRUE);
- $this->drupalPost('comment/' . $comment->id . '/edit', $edit, t('Preview'));
+ $this->drupalPost('comment/' . $comment->id() . '/edit', $edit, t('Preview'));
// Check that the preview is displaying the subject, comment, author and date correctly.
$this->assertTitle(t('Preview comment | Drupal'), 'Page title is "Preview comment".');
@@ -111,11 +111,11 @@ function testCommentEditPreviewSave() {
$this->assertFieldByName('date', $edit['date'], 'Date field displayed.');
// Check that saving a comment produces a success message.
- $this->drupalPost('comment/' . $comment->id . '/edit', $edit, t('Save'));
+ $this->drupalPost('comment/' . $comment->id() . '/edit', $edit, t('Save'));
$this->assertText(t('Your comment has been posted.'), 'Comment posted.');
// Check that the comment fields are correct after loading the saved comment.
- $this->drupalGet('comment/' . $comment->id . '/edit');
+ $this->drupalGet('comment/' . $comment->id() . '/edit');
$this->assertFieldByName('subject', $edit['subject'], 'Subject field displayed.');
$this->assertFieldByName('comment_body[' . $langcode . '][0][value]', $edit['comment_body[' . $langcode . '][0][value]'], 'Comment field displayed.');
$this->assertFieldByName('name', $edit['name'], 'Author field displayed.');
@@ -127,14 +127,14 @@ function testCommentEditPreviewSave() {
$displayed['comment_body[' . $langcode . '][0][value]'] = (string) current($this->xpath("//textarea[@id='edit-comment-body-" . $langcode . "-0-value']"));
$displayed['name'] = (string) current($this->xpath("//input[@id='edit-name']/@value"));
$displayed['date'] = (string) current($this->xpath("//input[@id='edit-date']/@value"));
- $this->drupalPost('comment/' . $comment->id . '/edit', $displayed, t('Save'));
+ $this->drupalPost('comment/' . $comment->id() . '/edit', $displayed, t('Save'));
// Check that the saved comment is still correct.
- $comment_loaded = comment_load($comment->id);
- $this->assertEqual($comment_loaded->subject, $edit['subject'], 'Subject loaded.');
- $this->assertEqual($comment_loaded->comment_body[$langcode][0]['value'], $edit['comment_body[' . $langcode . '][0][value]'], 'Comment body loaded.');
- $this->assertEqual($comment_loaded->name, $edit['name'], 'Name loaded.');
- $this->assertEqual($comment_loaded->created, $raw_date, 'Date loaded.');
+ $comment_loaded = comment_load($comment->id());
+ $this->assertEqual($comment_loaded->subject->value, $edit['subject'], 'Subject loaded.');
+ $this->assertEqual($comment_loaded->comment_body->value, $edit['comment_body[' . $langcode . '][0][value]'], 'Comment body loaded.');
+ $this->assertEqual($comment_loaded->name->value, $edit['name'], 'Name loaded.');
+ $this->assertEqual($comment_loaded->created->value->getTimestamp(), $raw_date, 'Date loaded.');
}
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentStatisticsTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentStatisticsTest.php
index afdcba4..1bb8d48 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentStatisticsTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentStatisticsTest.php
@@ -39,7 +39,6 @@ function setUp() {
* Tests the node comment statistics.
*/
function testCommentNodeCommentStatistics() {
- $langcode = LANGUAGE_NOT_SPECIFIED;
// Set comments to have subject and preview disabled.
$this->drupalLogin($this->admin_user);
$this->setCommentPreview(DRUPAL_DISABLED);
@@ -58,8 +57,7 @@ function testCommentNodeCommentStatistics() {
// Post comment #1 as web_user2.
$this->drupalLogin($this->web_user2);
$comment_text = $this->randomName();
- $comment = $this->postComment($this->node, $comment_text);
- $comment_loaded = comment_load($comment->id);
+ $this->postComment($this->node, $comment_text);
// Checks the new values of node comment statistics with comment #1.
// The node needs to be reloaded with a node_load_multiple cache reset.
@@ -82,8 +80,7 @@ function testCommentNodeCommentStatistics() {
// Post comment #2 as anonymous (comment approval enabled).
$this->drupalGet('comment/reply/' . $this->node->nid);
- $anonymous_comment = $this->postComment($this->node, $this->randomName(), '', TRUE);
- $comment_unpublished_loaded = comment_load($anonymous_comment->id);
+ $this->postComment($this->node, $this->randomName(), '', TRUE);
// Checks the new values of node comment statistics with comment #2 and
// ensure they haven't changed since the comment has not been moderated.
@@ -104,13 +101,12 @@ function testCommentNodeCommentStatistics() {
// Post comment #3 as anonymous.
$this->drupalGet('comment/reply/' . $this->node->nid);
- $anonymous_comment = $this->postComment($this->node, $this->randomName(), '', array('name' => $this->randomName()));
- $comment_loaded = comment_load($anonymous_comment->id);
+ $comment_loaded = $this->postComment($this->node, $this->randomName(), '', array('name' => $this->randomName()));
// Checks the new values of node comment statistics with comment #3.
// The node needs to be reloaded with a node_load_multiple cache reset.
$node = node_load($this->node->nid, TRUE);
- $this->assertEqual($node->last_comment_name, $comment_loaded->name, 'The value of node last_comment_name is the name of the anonymous user.');
+ $this->assertEqual($node->last_comment_name, $comment_loaded->name->value, 'The value of node last_comment_name is the name of the anonymous user.');
$this->assertEqual($node->last_comment_uid, 0, 'The value of node last_comment_uid is zero.');
$this->assertEqual($node->comment_count, 2, 'The value of node comment_count is 2.');
}
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php
index e8bab5d..8792b65 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php
@@ -145,7 +145,10 @@ function postComment($node, $comment, $subject = '', $contact = NULL) {
}
if (isset($match[1])) {
- return entity_create('comment', array('id' => $match[1], 'subject' => $subject, 'comment' => $comment));
+ $entity = comment_load($match[1]);
+ $entity->subject->value = $subject;
+ $entity->comment_body->value = $comment;
+ return $entity;
}
}
@@ -163,9 +166,9 @@ function postComment($node, $comment, $subject = '', $contact = NULL) {
function commentExists(Comment $comment = NULL, $reply = FALSE) {
if ($comment) {
$regex = '/' . ($reply ? '