Commit c972b3ee authored by catch's avatar catch

Issue #2190313 by pfrenssen, Berdir, amateescu, ianthomas_uk: Add...

Issue #2190313 by pfrenssen, Berdir, amateescu, ianthomas_uk: Add $EntityType::load() and loadMultiple() to simplify loading entities.
parent 21fbb5dd
......@@ -13,6 +13,8 @@
use Drupal\Component\Utility\String;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Config\Entity\Exception\ConfigEntityIdLengthException;
use Drupal\Core\Entity\Exception\AmbiguousEntityClassException;
use Drupal\Core\Entity\Exception\NoCorrespondingEntityClassException;
use Drupal\Core\Entity\Exception\UndefinedLinkTemplateException;
use Drupal\Core\Language\Language;
use Drupal\Core\Session\AccountInterface;
......@@ -415,6 +417,74 @@ public function getListCacheTags() {
return array($this->entityTypeId . 's' => TRUE);
}
/**
* {@inheritdoc}
*/
public static function load($id) {
return \Drupal::entityManager()->getStorage(static::getEntityTypeFromStaticClass())->load($id);
}
/**
* {@inheritdoc}
*/
public static function loadMultiple(array $ids = NULL) {
return \Drupal::entityManager()->getStorage(static::getEntityTypeFromStaticClass())->loadMultiple($ids);
}
/**
* Returns the entity type ID based on the class that is called on.
*
* Compares the class this is called on against the known entity classes
* and returns the entity type ID of a direct match or a subclass as fallback,
* to support entity type definitions that were altered.
*
* @return string
* The entity type ID.
*
* @throws \Drupal\Core\Entity\Exception\AmbiguousEntityClassException
* Thrown when multiple subclasses correspond to the called class.
* @throws \Drupal\Core\Entity\Exception\NoCorrespondingEntityClassException
* Thrown when no entity class corresponds to the called class.
*
* @see \Drupal\Core\Entity\Entity::load()
* @see \Drupal\Core\Entity\Entity::loadMultiple()
*/
protected static function getEntityTypeFromStaticClass() {
$called_class = get_called_class();
$subclasses = 0;
$same_class = 0;
$entity_type_id = NULL;
$subclass_entity_type_id = NULL;
foreach (\Drupal::entityManager()->getDefinitions() as $entity_type) {
// Check if this is the same class, throw an exception if there is more
// than one match.
if ($entity_type->getClass() == $called_class) {
$entity_type_id = $entity_type->id();
if ($same_class++) {
throw new AmbiguousEntityClassException($called_class);
}
}
// Check for entity types that are subclasses of the called class, but
// throw an exception if we have multiple matches.
elseif (is_subclass_of($entity_type->getClass(), $called_class)) {
$subclass_entity_type_id = $entity_type->id();
if ($subclasses++) {
throw new AmbiguousEntityClassException($called_class);
}
}
}
// Return the matching entity type ID or the subclass match if there is one
// as a secondary priority.
if ($entity_type_id) {
return $entity_type_id;
}
if ($subclass_entity_type_id) {
return $subclass_entity_type_id;
}
throw new NoCorrespondingEntityClassException($called_class);
}
/**
* Acts on an entity after it was saved or deleted.
*/
......
......@@ -171,6 +171,28 @@ public function hasLinkTemplate($key);
*/
public function uriRelationships();
/**
* Loads an entity.
*
* @param mixed $id
* The id of the entity to load.
*
* @return static
* The entity object or NULL if there is no entity with the given ID.
*/
public static function load($id);
/**
* Loads one or more entities.
*
* @param array $ids
* An array of entity IDs, or NULL to load all entities.
*
* @return static[]
* An array of entity objects indexed by their IDs.
*/
public static function loadMultiple(array $ids = NULL);
/**
* Saves an entity permanently.
*
......
<?php
/**
* @file
* Contains \Drupal\Core\Entity\Exception\AmbiguousEntityClassException.
*/
namespace Drupal\Core\Entity\Exception;
/**
* Exception thrown if multiple subclasses exist for an entity.
*
* This might occur if an entity is subclassed multiple times and the base
* class is altered to use one of the subclasses instead. If a static method on
* the base class is then invoked it is impossible to determine which of the
* subclasses is responsible for it.
*
* @see hook_entity_info_alter()
* @see \Drupal\Core\Entity\Entity::getEntityTypeFromStaticClass()
*/
class AmbiguousEntityClassException extends \Exception {
/**
* Constructs an AmbiguousEntityClassException.
*
* @param string $class
* The entity parent class.
*/
public function __construct($class) {
$message = sprintf('Multiple subclasses provide an entity type for %s.', $class);
parent::__construct($message);
}
}
<?php
/**
* @file
* Contains \Drupal\Core\Entity\Exception\NoCorrespondingEntityClassException.
*/
namespace Drupal\Core\Entity\Exception;
/**
* Exception thrown if an entity type is not represented by a class.
*
* This might occur by calling a static method on an abstract class.
*
* @see \Drupal\Core\Entity\Entity::getEntityTypeFromStaticClass()
*/
class NoCorrespondingEntityClassException extends \Exception {
/**
* Constructs an NoCorrespondingEntityClassException.
*
* @param string $class
* The class which does not correspond to an entity type.
*/
public function __construct($class) {
$message = sprintf('The %s class does not correspond to an entity type.', $class);
parent::__construct($message);
}
}
......@@ -5,6 +5,7 @@
* Used to aggregate syndicated content (RSS, RDF, and Atom).
*/
use Drupal\aggregator\Entity\Feed;
use Drupal\aggregator\FeedInterface;
use Drupal\Component\Utility\Xss;
use Symfony\Component\HttpFoundation\Request;
......@@ -113,9 +114,8 @@ function aggregator_permission() {
function aggregator_cron() {
$queue = \Drupal::queue('aggregator_feeds');
$result = \Drupal::entityManager()->getStorage('aggregator_feed')->getFeedIdsToRefresh();
foreach ($result as $fid) {
$feed = aggregator_feed_load($fid);
$ids = \Drupal::entityManager()->getStorage('aggregator_feed')->getFeedIdsToRefresh();
foreach (Feed::loadMultiple($ids) as $feed) {
if ($queue->createItem($feed)) {
// Add timestamp to avoid queueing item more than once.
$feed->setQueuedTime(REQUEST_TIME);
......@@ -124,12 +124,12 @@ function aggregator_cron() {
}
// Delete queued timestamp after 6 hours assuming the update has failed.
$result = \Drupal::entityQuery('aggregator_feed')
$ids = \Drupal::entityQuery('aggregator_feed')
->condition('queued', REQUEST_TIME - (3600 * 6), '<')
->execute();
if ($result) {
$feeds = entity_load_multiple('aggregator_feed', $result);
if ($ids) {
$feeds = Feed::loadMultiple($ids);
foreach ($feeds as $feed) {
$feed->setQueuedTime(0);
$feed->save();
......@@ -153,19 +153,6 @@ function aggregator_queue_info() {
return $queues;
}
/**
* Loads an aggregator feed.
*
* @param int $fid
* The feed id.
*
* @return \Drupal\aggregator\FeedInterface
* An object describing the feed.
*/
function aggregator_feed_load($fid) {
return entity_load('aggregator_feed', $fid);
}
/**
* Renders the HTML content safely, as allowed.
*
......
......@@ -7,6 +7,7 @@
namespace Drupal\aggregator\Tests;
use Drupal\aggregator\Entity\Feed;
use Drupal\Core\Language\Language;
use Drupal\simpletest\WebTestBase;
use Drupal\aggregator\FeedInterface;
......@@ -58,7 +59,7 @@ function createFeed($feed_url = NULL, array $edit = array()) {
$fid = db_query("SELECT fid FROM {aggregator_feed} WHERE title = :title AND url = :url", array(':title' => $edit['title[0][value]'], ':url' => $edit['url[0][value]']))->fetchField();
$this->assertTrue(!empty($fid), 'The feed found in database.');
return aggregator_feed_load($fid);
return Feed::load($fid);
}
/**
......
......@@ -6,6 +6,7 @@
*/
namespace Drupal\aggregator\Tests;
use Drupal\aggregator\Entity\Feed;
/**
* Tests functionality of updating a feed item in the Aggregator module.
......@@ -48,7 +49,7 @@ function testUpdateFeedItem() {
$this->assertRaw(t('The feed %name has been added.', array('%name' => $edit['title[0][value]'])), format_string('The feed !name has been added.', array('!name' => $edit['title[0][value]'])));
$fid = db_query("SELECT fid FROM {aggregator_feed} WHERE url = :url", array(':url' => $edit['url[0][value]']))->fetchField();
$feed = aggregator_feed_load($fid);
$feed = Feed::load($fid);
$feed->refreshItems();
$before = db_query('SELECT timestamp FROM {aggregator_item} WHERE fid = :fid', array(':fid' => $feed->id()))->fetchField();
......
......@@ -6,7 +6,6 @@
*/
use Drupal\block\BlockInterface;
use Drupal\Component\Plugin\Exception\PluginException;
use Drupal\language\Entity\Language;
use Drupal\system\Entity\Menu;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
......@@ -295,21 +294,6 @@ function block_list($region) {
return $blocks[$region];
}
/**
* Loads a block instance.
*
* This should only be used when entity_load() cannot be used directly.
*
* @param string $entity_id
* The block ID.
*
* @return \Drupal\block\Entity\Block
* The loaded block object.
*/
function block_load($entity_id) {
return entity_load('block', $entity_id);
}
/**
* Implements hook_rebuild().
*/
......
......@@ -5,8 +5,6 @@
* Allows the creation of custom blocks through the user interface.
*/
use Drupal\custom_block\Entity\CustomBlockType;
use Drupal\custom_block\Entity\CustomBlock;
use Symfony\Component\HttpFoundation\Request;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldInstanceConfig;
......@@ -53,32 +51,6 @@ function custom_block_theme($existing, $type, $theme, $path) {
);
}
/**
* Loads a custom block type.
*
* @param int $id
* The ID of the custom block type to load.
*
* @return \Drupal\custom_block\Entity\CustomBlockType|null
* A CustomBlockType object or NULL if the requested $id does not exist.
*/
function custom_block_type_load($id) {
return entity_load('custom_block_type', $id);
}
/**
* Loads a custom block.
*
* @param int $id
* The id of the custom block.
*
* @return \Drupal\custom_block\Entity\CustomBlock|null
* A CustomBlock object or NULL if the requested $id does not exist.
*/
function custom_block_load($id) {
return entity_load('custom_block', $id);
}
/**
* Implements hook_entity_type_alter().
*/
......
......@@ -35,7 +35,7 @@ public function form(array $form, array &$form_state) {
'#type' => 'machine_name',
'#default_value' => $block_type->id(),
'#machine_name' => array(
'exists' => 'custom_block_type_load',
'exists' => '\Drupal\custom_block\Entity\CustomBlockType::load',
),
'#maxlength' => EntityTypeInterface::BUNDLE_MAX_LENGTH,
'#disabled' => !$block_type->isNew(),
......
......@@ -8,6 +8,7 @@
namespace Drupal\custom_block\Tests;
use Drupal\Core\Database\Database;
use Drupal\custom_block\Entity\CustomBlock;
/**
* Tests creating and saving a block.
......@@ -180,7 +181,7 @@ public function testBlockDelete() {
$url = 'admin/structure/block/add/custom_block:' . $block->uuid() . '/' . \Drupal::config('system.theme')->get('default');
$this->drupalPostForm($url, $instance, t('Save block'));
$block = custom_block_load(1);
$block = CustomBlock::load(1);
// Test getInstances method.
$this->assertEqual(1, count($block->getInstances()));
......
......@@ -8,6 +8,7 @@
namespace Drupal\custom_block\Tests;
use Drupal\Core\Language\Language;
use Drupal\custom_block\Entity\CustomBlock;
/**
* Tests block save related functionality.
......@@ -63,7 +64,7 @@ public function testImport() {
$this->assertEqual($block->id(), $test_id, 'Block imported using provide id');
// Test the import saved.
$block_by_id = custom_block_load($test_id);
$block_by_id = CustomBlock::load($test_id);
$this->assertTrue($block_by_id, 'Custom block load by block ID.');
$this->assertIdentical($block_by_id->body->value, $block_array['body']['value']);
}
......@@ -93,7 +94,7 @@ public function testDeterminingChanges() {
$this->assertEqual($block->getChangedTime(), 979534800, 'Saving a custom block uses "changed" timestamp set in presave hook.');
// Test the static block load cache to be cleared.
$block = custom_block_load($block->id());
$block = CustomBlock::load($block->id());
$this->assertEqual($block->label(), 'updated_presave', 'Static cache has been cleared.');
}
......
......@@ -86,7 +86,7 @@ public function form(array $form, array &$form_state) {
'#description' => $this->t('A unique name for this block instance. Must be alpha-numeric and underscore separated.'),
'#default_value' => !$entity->isNew() ? $entity->id() : $this->getUniqueMachineName($entity),
'#machine_name' => array(
'exists' => 'block_load',
'exists' => '\Drupal\block\Entity\Block::load',
'replace_pattern' => '[^a-z0-9_.]+',
'source' => array('settings', 'label'),
),
......
......@@ -39,22 +39,6 @@ function breakpoint_help($route_name, Request $request) {
}
}
/**
* Load one breakpoint by its identifier.
*
* @param int $id
* The id of the breakpoint to load.
*
* @return \Drupal\breakpoint\Entity\Breakpoint|null
* The entity object, or NULL if there is no entity with the given id.
*
* @todo Remove this in a follow-up issue.
* @see http://drupal.org/node/1798214
*/
function breakpoint_load($id) {
return entity_load('breakpoint', $id);
}
/**
* Load all breakpoint groups as select options.
*
......@@ -63,7 +47,7 @@ function breakpoint_load($id) {
*/
function breakpoint_group_select_options() {
$options = array();
$breakpoint_groups = entity_load_multiple('breakpoint_group');
$breakpoint_groups = BreakpointGroup::loadMultiple();
foreach ($breakpoint_groups as $breakpoint_group) {
$options[$breakpoint_group->id()] = $breakpoint_group->label();
}
......@@ -79,7 +63,7 @@ function breakpoint_group_select_options() {
*/
function breakpoint_select_options() {
$options = array();
$breakpoints = entity_load_multiple('breakpoint');
$breakpoints = Breakpoint::loadMultiple();
foreach ($breakpoints as $breakpoint) {
$options[$breakpoint->id()] = $breakpoint->label() . ' (' . $breakpoint->source . ' - ' . $breakpoint->sourceType . ') [' . $breakpoint->mediaQuery . ']';
}
......
......@@ -157,7 +157,7 @@ public function isValid() {
*/
public function addBreakpointFromMediaQuery($name, $media_query) {
// Use the existing breakpoint if it exists.
$breakpoint = entity_load('breakpoint', $this->sourceType . '.' . $this->name . '.' . $name);
$breakpoint = Breakpoint::load($this->sourceType . '.' . $this->name . '.' . $name);
if (!$breakpoint) {
// Build a new breakpoint.
$breakpoint = entity_create('breakpoint', array(
......@@ -191,7 +191,7 @@ public function addBreakpoints($breakpoints) {
public function getBreakpoints() {
if (empty($this->breakpoints)) {
foreach ($this->breakpoint_ids as $breakpoint_id) {
$breakpoint = breakpoint_load($breakpoint_id);
$breakpoint = Breakpoint::load($breakpoint_id);
if ($breakpoint) {
$this->breakpoints[$breakpoint_id] = $breakpoint;
}
......
......@@ -37,10 +37,10 @@ public function testBreakpointCRUD() {
$this->verifyBreakpoint($breakpoint);
// Test breakpoint_load_all
$all_breakpoints = entity_load_multiple('breakpoint');
// Test BreakPoint::loadMultiple().
$all_breakpoints = Breakpoint::loadMultiple();
$config_name = $breakpoint->id();
$this->assertTrue(isset($all_breakpoints[$config_name]), 'breakpoint_load_all: New breakpoint is present when loading all breakpoints.');
$this->assertTrue(isset($all_breakpoints[$config_name]), 'New breakpoint is present when loading all breakpoints.');
$this->verifyBreakpoint($breakpoint, $all_breakpoints[$config_name]);
// Update the breakpoint.
......@@ -51,6 +51,6 @@ public function testBreakpointCRUD() {
// Delete the breakpoint.
$breakpoint->delete();
$this->assertFalse(breakpoint_load($config_name), 'breakpoint_load: Loading a deleted breakpoint returns false.', 'Breakpoints API');
$this->assertNull(Breakpoint::load($config_name), 'Loading a deleted breakpoint returns null.', 'Breakpoints API');
}
}
......@@ -38,14 +38,14 @@ public function verifyBreakpoint(Breakpoint $breakpoint, Breakpoint $compare_bre
'multipliers',
);
// Verify breakpoint_load().
$compare_breakpoint = is_null($compare_breakpoint) ? breakpoint_load($breakpoint->id()) : $compare_breakpoint;
// Verify Breakpoint::load().
$compare_breakpoint = is_null($compare_breakpoint) ? Breakpoint::load($breakpoint->id()) : $compare_breakpoint;
foreach ($properties as $property) {
$t_args = array(
'%breakpoint' => $breakpoint->label(),
'%property' => $property,
);
$this->assertEqual($compare_breakpoint->{$property}, $breakpoint->{$property}, format_string('breakpoint_load: Proper %property for breakpoint %breakpoint.', $t_args), 'Breakpoint API');
$this->assertEqual($compare_breakpoint->{$property}, $breakpoint->{$property}, format_string('Proper %property for breakpoint %breakpoint.', $t_args), 'Breakpoint API');
}
}
}
......@@ -11,6 +11,7 @@
*/
use Drupal\comment\CommentInterface;
use Drupal\comment\Entity\Comment;
use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\entity\Entity\EntityViewDisplay;
......@@ -1049,8 +1050,8 @@ function comment_user_predelete($account) {
/**
* Loads comment entities from the database.
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use entity_load_multiple('comment', $cids).
* @deprecated in Drupal 8.x, will be removed before Drupal 9.0.
* Use \Drupal\comment\Entity\Comment::loadMultiple().
*
* @param array $cids
* (optional) An array of entity IDs. If omitted, all entities are loaded.
......@@ -1064,7 +1065,10 @@ function comment_user_predelete($account) {
* @see \Drupal\Core\Entity\Query\QueryInterface
*/
function comment_load_multiple(array $cids = NULL, $reset = FALSE) {
return entity_load_multiple('comment', $cids, $reset);
if ($reset) {
\Drupal::entityManager()->getStorage('comment')->resetCache($cids);
}
return Comment::loadMultiple($cids);
}
/**
......@@ -1077,9 +1081,15 @@ function comment_load_multiple(array $cids = NULL, $reset = FALSE) {
*
* @return \Drupal\comment\CommentInterface
* The comment object.
*
* @deprecated in Drupal 8.x, will be removed before Drupal 9.0.
* Use \Drupal\comment\Entity\Comment::load().
*/
function comment_load($cid, $reset = FALSE) {
return entity_load('comment', $cid, $reset);
if ($reset) {
\Drupal::entityManager()->getStorage('comment')->resetCache(array($cid));
}
return Comment::load($cid);
}
/**
......
......@@ -115,19 +115,6 @@ function contact_entity_extra_field_info() {
return $fields;
}
/**
* Loads a contact category.
*
* @param $id
* The ID of the contact category to load.
*
* @return \Drupal\contact\Entity\Category|null
* A Category object or NULL if the requested $id does not exist.
*/
function contact_category_load($id) {
return entity_load('contact_category', $id);
}
/**
* Implements hook_mail().
*/
......
......@@ -37,7 +37,7 @@ public function form(array $form, array &$form_state) {
'#default_value' => $category->id(),
'#maxlength' => EntityTypeInterface::BUNDLE_MAX_LENGTH,
'#machine_name' => array(
'exists' => 'contact_category_load',
'exists' => '\Drupal\contact\Entity\Category::load',
),
'#disabled' => !$category->isNew(),
);
......
......@@ -83,13 +83,19 @@ function file_element_info() {
* @return array
* An array of file entities, indexed by fid.
*
* @deprecated in Drupal 8.x, will be removed before Drupal 9.0.
* Use \Drupal\file\Entity\File::loadMultiple().
*
* @see hook_file_load()
* @see file_load()
* @see entity_load()
* @see \Drupal\Core\Entity\Query\EntityQueryInterface
*/
function file_load_multiple(array $fids = NULL, $reset = FALSE) {
return entity_load_multiple('file', $fids, $reset);
if ($reset) {
\Drupal::entityManager()->getStorage('file')->resetCache($fids);
}
return File::loadMultiple($fids);
}
/**
......@@ -103,11 +109,17 @@ function file_load_multiple(array $fids = NULL, $reset = FALSE) {
* @return \Drupal\file\FileInterface
* A file entity or NULL if the file was not found.
*
* @deprecated in Drupal 8.x, will be removed before Drupal 9.0.
* Use \Drupal\file\Entity\File::load().
*
* @see hook_file_load()
* @see file_load_multiple()
*/
function file_load($fid, $reset = FALSE) {
return entity_load('file', $fid, $reset);
if ($reset) {
\Drupal::entityManager()->getStorage('file')->resetCache(array($fid));
}
return File::load($fid);
}
/**
......
......@@ -7,8 +7,6 @@
use Drupal\Core\Entity\EntityInterface;
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldInstanceConfig;
use Drupal\file\Entity\File;
use Drupal\field\FieldConfigInterface;
use Drupal\field\FieldInstanceConfigInterface;
......@@ -245,16 +243,6 @@ function image_path_flush($path) {
}
}
/**
* Loads an ImageStyle object.
*
* @param string $name
* The ID of the ImageStyle object to load.
*/
function image_style_load($name) {
return entity_load('image_style', $name);
}
/**
* Gets an array of image styles suitable for using as select list options.
*
......
......@@ -45,9 +45,15 @@ function menu_link_uri(MenuLink $menu_link) {
*
* @return \Drupal\menu_link\Entity\MenuLink|null
* A menu link entity, or NULL if there is no entity with the given ID.
*
* @deprecated in Drupal 8.x, will be removed before Drupal 9.0.
* Use \Drupal\menu_link\Entity\MenuLink::load().
*/
function menu_link_load($mlid = NULL, $reset = FALSE) {
return entity_load('menu_link', $mlid, $reset);
if ($reset) {
\Drupal::entityManager()->getStorage('menu_link')->resetCache(array($mlid));
}
return MenuLink::load($mlid);
}
/**
......@@ -63,9 +69,15 @@ function menu_link_load($mlid = NULL, $reset = FALSE) {
*
* @see menu_link_load()
* @see entity_load_multiple()
*
* @deprecated in Drupal 8.x, will be removed before Drupal 9.0.
* Use \Drupal\menu_link\Entity\MenuLink::loadMultiple().
*/
function menu_link_load_multiple(array $mlids = NULL, $reset = FALSE) {
return entity_load_multiple('menu_link', $mlids, $reset);
if ($reset) {
\Drupal::entityManager()->getStorage('menu_link')->resetCache($mlids);
}
return MenuLink::loadMultiple($mlids);
}
/**
......
......@@ -238,7 +238,7 @@ public function save(array $form, array &$form_state) {
*
* This form constructor can be integrated as a section into another form. It
* relies on the following keys in $form_state:
* - menu: A loaded menu definition, as returned by menu_ui_load().
* - menu: A menu entity.
* - menu_overview_form_parents: An array containing the parent keys to this
* form.
* Forms integrating this section should call menu_overview_form_submit() from
......
......@@ -9,6 +9,7 @@
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Language\Language;
use Drupal\system\Entity\Menu;
/**
* Defines a test class for testing menu language functionality.
......@@ -174,7 +175,7 @@ function testMenuLanguageRemovedEnglish() {
$this->drupalPostForm('admin/structure/menu/add', $edit, t('Save'));
// Check that the language settings were saved.
$menu = menu_ui_load($menu_name);
$menu = Menu::load($menu_name);
$this->assertEqual($menu->langcode, 'en');
// Remove English language. To do that another language has to be set as
......@@ -186,7 +187,7 @@ function testMenuLanguageRemovedEnglish() {