diff --git a/core/modules/entity/tests/modules/entity_test/lib/Drupal/entity_test/EntityTest.php b/core/modules/entity/tests/modules/entity_test/lib/Drupal/entity_test/EntityTest.php new file mode 100644 index 0000000000000000000000000000000000000000..6c95f75dedfa5d8b5c2b35f0f1e7073b2c33e7f5 --- /dev/null +++ b/core/modules/entity/tests/modules/entity_test/lib/Drupal/entity_test/EntityTest.php @@ -0,0 +1,143 @@ +<?php + +/** + * @file + * Definition of Drupal\entity_test\EntityTest. + */ + +namespace Drupal\entity_test; + +use InvalidArgumentException; + +use Drupal\entity\Entity; + +/** + * Defines the test entity class. + */ +class EntityTest extends Entity { + + /** + * An array keyed by language code where the entity properties are stored. + * + * @var array + */ + protected $properties; + + /** + * An array of allowed language codes. + * + * @var array + */ + protected static $langcodes; + + /** + * Constructs a new entity object. + */ + public function __construct(array $values, $entity_type) { + parent::__construct($values, $entity_type); + + if (!isset(self::$langcodes)) { + // The allowed languages are simply all the available ones in the system. + self::$langcodes = drupal_map_assoc(array_keys(language_list(LANGUAGE_ALL))); + } + + // Initialize the original entity language with the provided value or fall + // back to LANGUAGE_NOT_SPECIFIED if none was specified. We do not check + // against allowed languages here, since throwing an exception would make an + // entity created in a subsequently uninstalled language not instantiable. + $this->langcode = !empty($values['langcode']) ? $values['langcode'] : LANGUAGE_NOT_SPECIFIED; + + // Set initial values ensuring that only real properties are stored. + // @todo For now we have no way to mark a property as multlingual hence we + // just assume that all of them are. + unset($values['id'], $values['uuid'], $values['default_langcode']); + $this->setProperties($values, $this->langcode); + } + + /** + * Sets the entity original langcode. + * + * @param $langcode + */ + public function setLangcode($langcode) { + // If the original language is changed the related properties must change + // their language accordingly. + $prev_langcode = $this->langcode; + if (isset($this->properties[$prev_langcode])) { + $this->properties[$langcode] = $this->properties[$prev_langcode]; + unset($this->properties[$prev_langcode]); + } + $this->langcode = $langcode; + } + + /** + * Overrides EntityInterface::get(). + */ + public function get($property_name, $langcode = NULL) { + $langcode = !empty($langcode) ? $langcode : $this->langcode; + $entity_info = $this->entityInfo(); + if ($entity_info['fieldable'] && field_info_instance($this->entityType, $property_name, $this->bundle())) { + return parent::get($property_name, $langcode); + } + elseif (isset($this->properties[$langcode][$property_name])) { + return $this->properties[$langcode][$property_name]; + } + else { + // @todo Remove this. All properties should be stored in the $properties + // array once we have a Property API in place. + return property_exists($this, $property_name) ? $this->{$property_name} : NULL; + } + } + + /** + * Overrides EntityInterface::set(). + */ + public function set($property_name, $value, $langcode = NULL) { + $langcode = !empty($langcode) ? $langcode : $this->langcode; + if (!isset(self::$langcodes[$langcode])) { + throw new InvalidArgumentException("Detected an invalid language '$langcode' while setting '$property_name' to '$value'."); + } + $entity_info = $this->entityInfo(); + if ($entity_info['fieldable'] && field_info_instance($this->entityType, $property_name, $this->bundle())) { + parent::set($property_name, $value, $langcode); + } + else { + $this->properties[$langcode][$property_name] = $value; + } + } + + /** + * Overrides EntityInterface::translations(). + */ + public function translations() { + $translations = !empty($this->properties) ? $this->properties : array(); + $languages = array_intersect_key(self::$langcodes, $translations); + unset($languages[$this->langcode]); + return $languages + parent::translations(); + } + + /** + * Returns the property array for the given language. + * + * @param string $langcode + * (optional) The language code to be used to retrieve the properties. + */ + public function getProperties($langcode = NULL) { + $langcode = !empty($langcode) ? $langcode : $this->langcode; + return isset($this->properties[$langcode]) ? $this->properties[$langcode] : array(); + } + + /** + * Sets the property array for the given language. + * + * @param array $properties + * A keyed array of properties to be set with their 'langcode' as one of the + * keys. If no language is provided the entity language is used. + * @param string $langcode + * (optional) The language code to be used to set the properties. + */ + public function setProperties(array $properties, $langcode = NULL) { + $langcode = !empty($langcode) ? $langcode : $this->langcode; + $this->properties[$langcode] = $properties; + } +} diff --git a/core/modules/entity/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestStorageController.php b/core/modules/entity/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestStorageController.php new file mode 100644 index 0000000000000000000000000000000000000000..147f030647a818c95b67f7134bc1ef943f4de9bc --- /dev/null +++ b/core/modules/entity/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestStorageController.php @@ -0,0 +1,123 @@ +<?php + +/** + * @file + * Definition of Drupal\entity_test\EntityTestStorageController. + */ + +namespace Drupal\entity_test; + +use PDO; + +use Drupal\entity\EntityInterface; +use Drupal\entity\DatabaseStorageController; + +/** + * Defines the controller class for the test entity. + * + * This extends the Drupal\entity\DatabaseStorageController class, adding + * required special handling for test entities. + */ +class EntityTestStorageController extends DatabaseStorageController { + + /** + * Overrides Drupal\entity\DatabaseStorageController::buildQuery(). + */ + protected function buildQuery($ids, $conditions = array(), $revision_id = FALSE) { + $query = parent::buildQuery($ids, $conditions, $revision_id); + + if ($conditions) { + // Reset conditions as the default storage controller applies them to the + // base table. + $query_conditions = &$query->conditions(); + $query_conditions = array('#conjunction' => 'AND'); + + // Restore id conditions. + if ($ids) { + $query->condition("base.{$this->idKey}", $ids, 'IN'); + } + + // Conditions need to be applied the property data table. + $query->addJoin('inner', 'entity_test_property_data', 'data', "base.{$this->idKey} = data.{$this->idKey}"); + $query->distinct(TRUE); + + // @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', $conditions)) { + $conditions['default_langcode'] = 1; + } + // If the 'default_langcode' flag is esplicitly not set, we do not care + // whether the queried values are in the original entity language or not. + elseif ($conditions['default_langcode'] === NULL) { + unset($conditions['default_langcode']); + } + + foreach ($conditions as $field => $value) { + $query->condition('data.' . $field, $value); + } + } + + return $query; + } + + /** + * Overrides Drupal\entity\DatabaseStorageController::attachLoad(). + */ + protected function attachLoad(&$queried_entities, $revision_id = FALSE) { + $data = db_select('entity_test_property_data', 'data', array('fetch' => PDO::FETCH_ASSOC)) + ->fields('data') + ->condition('id', array_keys($queried_entities)) + ->orderBy('data.id') + ->execute(); + + foreach ($data as $values) { + $entity = $queried_entities[$values['id']]; + $langcode = $values['langcode']; + if (!empty($values['default_langcode'])) { + $entity->setLangcode($langcode); + } + // Make sure only real properties are stored. + unset($values['id'], $values['default_langcode']); + $entity->setProperties($values, $langcode); + } + + parent::attachLoad($queried_entities, $revision_id); + } + + /** + * Overrides Drupal\entity\DatabaseStorageController::postSave(). + */ + protected function postSave(EntityInterface $entity, $update) { + $default_langcode = ($language = $entity->language()) ? $language->langcode : LANGUAGE_NOT_SPECIFIED; + $langcodes = array_keys($entity->translations()); + $langcodes[] = $default_langcode; + + foreach ($langcodes as $langcode) { + $properties = $entity->getProperties($langcode); + + $values = array( + 'id' => $entity->id(), + 'langcode' => $langcode, + 'default_langcode' => intval($default_langcode == $langcode), + ) + $properties; + + db_merge('entity_test_property_data') + ->fields($values) + ->condition('id', $values['id']) + ->condition('langcode', $values['langcode']) + ->execute(); + } + } + + /** + * Overrides Drupal\entity\DatabaseStorageController::postDelete(). + */ + protected function postDelete($entities) { + db_delete('entity_test_property_data') + ->condition('id', array_keys($entities)) + ->execute(); + } +}