Commit 201d175c authored by fago's avatar fago

#988780 API Change: merged both modules into a single one. Read...

 #988780 API Change: merged both modules into a single one. Read http://drupal.org/node/988780#comment-3834560 for a detailed description of the changes.
parent 2e208097
$Id$
Entity APIs
------------
Entity API module
-----------------
by Wolfgang Ziegler, nuppla@zites.net
This are API modules. You only need to enable them, if a module depends on one
of them or you are interested in using them for development.
This module extends the entity API of Drupal core in order to provide a unified
way to deal with entities and their properties. Additionally, it provides an
entity CRUD controller, which helps simplifying the creation of new entity types.
This is an API module. You only need to enable it if a module depends on it or
you are interested in using it for development.
This README is for interested developers. If you are not interested in developing,
you may stop reading now.
--------------------------------------------------------------------------------
Entity CRUD API
Entity API
--------------------------------------------------------------------------------
* To use the API you have to introduce a dependency on the "entity" module.
* The module provides API functions allowing modules to create, save, delete
or to determine access for entities based on any entity type, for which the
necessary metadata is available. The module comes with integration for all
core entity types, as well as for entities provided via the Entity CRUD API
(see below). However for any other entity type implemented by a contrib
module, the module integration has to be provided the contrib module itself.
* Thus the module provides API functions like entity_save(), entity_create(),
entity_delete(), entity_view() and entity_access() among others.
entity_load(), entity_label() and entity_uri() are already provided by
Drupal core.
* For more information about how to provide this metadata, have a look at the
API documentation, i.e. entity_metadata_hook_entity_info().
--------------------------------------------------------------------------------
Entity CRUD API - Providing new entity types
--------------------------------------------------------------------------------
* The provided controller implements full CRUD functionality, which may be used
via the provided helpers entity_create(), entity_save(), entity_delete().
* This API helps you defining a new entity type. It provides an entity
controller, which implements full CRUD functionality for your entities.
* To make use of the CRUD functionality you may just use the API functions
entity_create(), entity_delete() and entity_save().
Alternatively you may specify a class to use for your entities, for which the
"Entity" class is provided. In particular, it is useful to extend this class
in order to apply any necessary customizations.
in order to easily customize the entity type, e.g. saving.
* The controller supports fieldable entities as well as exportable entities,
however it does not yet support revisions.
* The Entity CRUD API helps with providing addition module integration too,
* The Entity CRUD API helps with providing additional module integration too,
e.g. exportable entities are automatically integrate with the Features
module. These module integrations are implemented in separate controller
classes, which may be overridden and deactivated on their own.
......@@ -36,34 +59,33 @@ you may stop reading now.
* There is also an optional ui controller class, which assits with providing an
administrative UI for managing entities of a certain type.
* For more details check out the documentation in the drupal.org handbook:
http://drupal.org/node/878804
* For more details check out the documentation in the drupal.org handbook
http://drupal.org/node/878804 as well as the API documentation, i.e.
entity_crud_hook_entity_info().
How to add a new entity type?
------------------------------
Basic steps to add a new entity type:
---------------------------------------
* You might want to study the code of the "entity_test.module".
* Describe your entities db table as usual in hook_schema().
* You may use the entity classes directly or extend it with your own class.
* Just use the "Entity" directly or extend it with your own class.
To see how to provide a separate class have a look at the "EntityClass" from
the "entity_test.module".
* Implement hook_entity_info() for your entity. At least specifiy the
controller class of this API, your db table and your object's primary key
field. Optionally also set the 'entity class' to Entity or your extended
class.
controller class of this API, your db table and your entity's keys.
Again just look at "entity_test.module"'s hook_entity_info() for guidance.
* If you want your entity to be fieldable just set 'fieldable' in
hook_entity_info() to TRUE. The field API attachers are called automatically
in the entity CRUD functions then.
* The entity API is able to deal with bundle objects too (e.g. the node type
object). For that just specify an entity type for the bundle objects and
set the 'bundle of' property appropriate.
object). For that just specify another entity type for the bundle objects
and set the 'bundle of' property for it.
Again just look at "entity_test.module"'s hook_entity_info() for guidance.
* Schema fields marked as 'serialzed' are automatically unserialized upon
......@@ -75,35 +97,27 @@ you may stop reading now.
--------------------------------------------------------------------------------
Entity Metadata
Entity Properties & Entity metadata wrappers
--------------------------------------------------------------------------------
* This module introduces a unique place for metadata about entities and their
properties. For that hook_entity_info() already used by core is extended,
and hook_entity_property_info() got introduced, whereas hook_entity_property_info()
may be placed in your module's {YOUR_MODULE}.info.inc include file. For details
have a look at the doxygen documentation and at http://drupal.org/node/878876.
* The module provides API functions allowing modules to create, save, delete
or to determine access for entities based on any entity type, for which the
necessary metadata is available. The module comes with metadata for all
core entity types, contrib modules are supposed to provide metadata on their
own.
* The metadata about entity properties contains information about the
data type and callbacks for how to get and set the data of property. That
way the data of an entity can be easily reused, e.g. to export into other
data formats like XML.
* This module introduces a unique place for metadata about entity properties:
hook_entity_property_info(), whereas hook_entity_property_info() may be
placed in your module's {YOUR_MODULE}.info.inc include file. For details
have a look at the API documentation, i.e. hook_entity_property_info() and
at http://drupal.org/node/878876.
* The information about entity properties contains the data type and callbacks
for how to get and set the data of property. That way the data of an entity
can be easily re-used, e.g. to export it into other data formats like XML.
* For making use of this metadata the module provides some wrapper classes
which ease getting and setting values. The wrapper support chained usage for
retrieving wrappers of entity properties, e.g. to get a node author's mail
address one could use:
* For making use of this information (metadata) the module provides some
wrapper classes which ease getting and setting values. The wrapper supports
chained usage for retrieving wrappers of entity properties, e.g. to get a
node author's mail address one could use:
$wrapper = entity_metadata_wrapper('node', $node);
$wrapper->author->mail->value();
To update the user's mail address one could use
$wrapper->author->mail->set('sepp@example.com');
......@@ -112,26 +126,30 @@ you may stop reading now.
$wrapper->author->mail = 'sepp@example.com';
The wrappers always return the data as described in the metadata, which may
be retrieved directly from hook_entity_info() for from the wrapper:
The wrappers always return the data as described in the property
information, which may be retrieved directly via entity_get_property_info()
or from the wrapper:
$mail_info = $wrapper->author->mail->info();
However to force getting a sanitized value one can use
In order to force getting a textual value sanitized for output one can use,
e.g.
$wrapper->title->value(array('sanitize' => TRUE));
to get the sanitized node title. When data is already sanitized, like the
node body, one possible wants to get the data as output in the browser. For
that one can enable 'decode', so for sanitized data the tags are stripped
and the data is decoded before it is returned:
to get the sanitized node title. When a property is already returned
sanitized by default, like the node body, one possibly wants to get the
not-sanitized data as it would appear in a browser for other use-cases.
To do so one can enable the 'decode' option, which ensures for any sanitized
data the tags are stripped and HTML entities are decoded before the property
is returned:
$wrapper->body->value->value(array('decode' => TRUE));
That way one always gets the data as shown to the user. However if you
really want to get the raw value, even for sanitized textual data, you can
do so:
really want to get the raw, unprocessed value, even for sanitized textual
data, you can do so via:
$wrapper->body->value->raw();
\ No newline at end of file
; $Id$
name = Entity API
description = Enables modules to work with any entity type and to provide entities.
core = 7.x
files[] = includes/entity.controller.inc
files[] = includes/entity.inc
files[] = includes/entity.property.inc
files[] = includes/entity.ui.inc
files[] = includes/entity.wrapper.inc
files[] = entity.features.inc
files[] = entity.info.inc
files[] = entity.module
files[] = entity.rules.inc
files[] = entity.test
......@@ -3,11 +3,55 @@
/**
* @file
* Provides Entity metadata integration for entities provided via the CRUD API.
* Provides basic entity property info for entities provided via the CRUD API,
* as well as property info for all entity types defined by core. For that
* the respective modules/MODULE.info.inc files are included.
*/
/**
* Default controller for generating some basic metadata.
* Implements hook_entity_property_info().
*/
function entity_entity_property_info() {
$items = array();
// Add in info about entities provided by the CRUD API.
foreach (entity_crud_get_info() as $type => $info) {
$info += array('metadata controller class' => 'EntityDefaultMetadataController');
if ($info['metadata controller class']) {
$controller = new $info['metadata controller class']($type);
$items += $controller->entityPropertyInfo();
}
}
// Add in info for all core entities.
foreach (_entity_metadata_core_modules() as $module) {
module_load_include('inc', 'entity', "modules/$module.info");
if (function_exists($function = "entity_metadata_{$module}_entity_property_info")) {
if ($return = $function()) {
$items = array_merge_recursive($items, $return);
}
}
}
return $items;
}
/**
* Implements hook_entity_property_info_alter().
*/
function entity_entity_property_info_alter(&$entity_info) {
// Add in info for all core entities.
foreach (_entity_metadata_core_modules() as $module) {
module_load_include('inc', 'entity', "modules/$module.info");
if (function_exists($function = "entity_metadata_{$module}_entity_property_info_alter")) {
$function($entity_info);
}
}
}
function _entity_metadata_core_modules() {
return array_filter(array('book', 'comment', 'field', 'node', 'taxonomy', 'user', 'system'), 'module_exists');
}
/**
* Default controller for generating some basic metadata for CRUD entity types.
*/
class EntityDefaultMetadataController {
......@@ -70,16 +114,44 @@ class EntityDefaultMetadataController {
}
/**
* Implements hook_entity_property_info().
* Converts the schema information available for the given table to property info.
*
* @param $table
* The name of the table as used in hook_schema().
* @return
* An array of property info as suiting for hook_entity_property_info().
*/
function entity_entity_property_info() {
$items = array();
foreach (entity_crud_get_info() as $type => $info) {
$info += array('metadata controller class' => 'EntityDefaultMetadataController');
if ($info['metadata controller class']) {
$controller = new $info['metadata controller class']($type);
$items += $controller->entityPropertyInfo();
function entity_metadata_convert_schema($table) {
$schema = drupal_get_schema($table);
$properties = array();
foreach ($schema['fields'] as $name => $info) {
if ($type = _entity_metadata_convert_schema_type($info['type'])) {
$properties[$name] = array(
'type' => $type,
'label' => drupal_ucfirst($name),
'query callback' => 'entity_metadata_table_query',
// As we cannot know about any setter access, leave out the setter
// callback. For getting usually no further access callback is needed.
);
if ($type == 'serial') {
$properties[$name]['validation callback'] = 'entity_metadata_validate_integer_positive';
}
}
}
return $items;
return $properties;
}
function _entity_metadata_convert_schema_type($type) {
switch ($type) {
case 'int':
case 'serial':
return 'integer';
case 'float':
case 'numeric':
return 'decimal';
case 'char':
case 'varchar':
case 'text':
return 'text';
}
}
<?php
// $Id$
/**
* @file
* Install file for the entity API.
*/
/**
* The entity API modules have been merged into a single module.
*/
function entity_update_7000() {
// This empty update is required such that all caches are cleared as
// necessary.
}
\ No newline at end of file
This diff is collapsed.
<?php
// $Id$
/**
* @file
* Hooks provided by the entity API.
*/
/**
* @addtogroup hooks
* @{
*/
/**
* This is just placeholder for describing further keys for describing entities
* in hook_entity_info(), which are introduced by the entity API:
* - entity class: Optionally a class the controller will use for instantiating
* entities.
* - 'bundle of': Optionally if the entity describes bundles of another entity
* specify the entity, for which this is a bundle of, here. If done so, the
* API will automatically invoke the field API bundle attachers. For this to
* work you also have to set the bundle key for the referred entity.
* - module: The module providing the entity type. Optionally, but suggested.
* - exportable: Whether the entity is exportable. Defaults to FALSE.
* - 'entity keys' An array of keys as defined by core. The following additional
* keys are used by the entity CRUD API:
* - name: An optional name of a property that contains a unique name of the
* entity. If specified, this is used as uniform identifier of the entity
* while the 'id' key is only used to refer to the entity internally, e.g.
* in the database. If not specified, this defaults to the 'id' key.
* For exportable entities, it's strongly recommended to use a machine name
* here as those are more portable across systems.
* - module: Optional. A key for the module property used by the entity CRUD
* API to provide the source module name for exportable entities, which are
* provided in code. Defaults to 'module'.
* - status: Optional. The name of the entity property used by the entity CRUD
* API to provide the exportable entity status using defined bit flags.
* Defaults to 'status'.
* - export: An array of optional information used for exporting. For ctools
* exportables compatibility any export-keys supported by ctools may be added
* to this array too.
* - default hook: What hook to invoke to find exportable entities that are
* currently defined. This hook is automatically called by the CRUD
* controller during entity_load(). Defaults to 'default_' . $entity_type.
* - admin ui: An array of optional information used for providing an
* administrative user interface. To enable the UI at least the path must be
* given. Apart from that, the 'access callback' (see below) is required for
* the entity, and at least a loader function ENTITY_TYPE_load() has to
* be defined, as well as the 'ENTITY_TYPE_form' for editing, adding and
* cloning. The form gets the entity and the operation ('edit', 'add' or
* 'clone') passed. See entity_ui_get_form() for more details.
* Known keys are:
* - path: a path where the UI should show up as expected by hook_menu().
* - controller class: An optional controller class name for providing the
* UI. Defaults to EntityDefaultUIController.
* For customizing the UI inherit from the default class and overide methods
* as suiting and specify your class as controller class.
* - file: Optionally, the name of the file in which the entity form resides
* as it is required by hook_menu().
* - file path: Optionally, the path to the file as required by hook_menu. If
* not set, it defaults to entity module's path, thus the entity types
* 'module' key is required.
* - 'menu wildcard': The wildcard to use in paths of the hook_menu() items.
* Defaults to %ENTITY_TYPE, for which a respective loader function
* ENTITY_TYPE_load() has to be defined by the implementing module.
* - 'rules controller class': An optional controller class for providing Rules
* integration. The given class has to inherit from the default class being
* EntityDefaultRulesController. Set it to FALSE to disable this feature.
* - 'metadata controller class': A controller class for providing Entity meta-
* data module integration, i.e. entity property info. By default some meta-
* data is generated from your hook_schema() information and *read access* is
* granted to that properties. From that the Entity metadata module also
* generates token integration for you, once activated.
* Override the controller class to adapt the defaults and to improve and
* complete the generated metadata. Set it to FALSE to disable this feature.
* Defaults to the EntityDefaultMetadataController class.
* - 'features controller class': A controller class for providing Features
* module integration for exportable entities. The given class has to inherit
* from the default class being EntityDefaultFeaturesController. Set it to
* FALSE to disable this feature.
* - access callback: Specify a callback that returns access permissions for the
* operations 'create', 'updated', 'delete' and 'view'. The callback gets
* optionally the entity and the user account to check for passed. See
* entity_metadata_no_hook_node_access() for an example.
* Optional, but suggested for the Rules integration, and required for the
* admin ui (see above).
*
* @see hook_entity_info()
*/
function entity_hook_entity_info() {
$return = array(
'entity_test' => array(
'label' => t('Test Entity'),
'entity class' => 'Entity',
'controller class' => 'EntityAPIController',
'base table' => 'entity_test',
'module' => 'entity_test',
'fieldable' => TRUE,
'entity keys' => array(
'id' => 'pid',
'name' => 'name',
'bundle' => 'type',
),
'bundles' => array(),
),
);
foreach (entity_test_get_types() as $name => $info) {
$return['entity_test']['bundles'][$name] = array(
'label' => $info['label'],
);
}
return $return;
}
/**
* Act when exportable entities are enabled.
*
* This hook is invoked for exportable entities regardless of their export
* status as soon as new enabled entities are available to the system - either
* as a new entity has been saved to the database or modules with entities in
* code have been enabled.
*
* Note that there is no reliable way to react on configuration changes, as
* entities in code may be updated anytime.
*
* @param $entities
* The entities keyed by entity ID.
* @param $entity_type
* The type of entities being enabled (i.e. profile2_type, rules_config, ..).
*/
function hook_entity_enabled($entities, $entity_type) {
mymodule_initialize($entities, $entity_type);
}
/**
* Act when exportable entities are disabled.
*
* This hook is invoked for exportable entities regardless of their export
* status as soon as entities are unavailable to the system - either as an
* customly created entity has been deleted from the database or modules with
* entities in code have been disabled.
*
* @param $entities
* The entities keyed by entity ID.
* @param $entity_type
* The type of entities being disabled (i.e. profile2_type, rules_config, ..).
*/
function hook_entity_disabled($entities, $entity_type) {
mymodule_deactivate($entities, $entity_type);
}
/**
* @} End of "addtogroup hooks".
*/
......@@ -3,7 +3,10 @@
/**
* @file
* Provides a base class for entities.
* Deprecated. This is only here to ease upgrading from previous versions of the
* entity API, which shipped with this file. This is required, such that the
* Entity class can be loaded during the drupal bootstrap when updating. After
* updating, this file and its directory can be safely removed.
*/
/**
......
; $Id$
name = Entity CRUD API
description = CRUD API for entities.
core = 7.x
files[] = entity.controller.inc
files[] = entity.db.inc
files[] = entity.features.inc
files[] = entity.info.inc
files[] = entity.module
files[] = entity.rules.inc
files[] = entity.test
files[] = entity.ui.inc
; This file is deprecated and may be removed.
\ No newline at end of file
This diff is collapsed.
; $Id$
name = Entity Metadata
description = Provides more metadata for entities and a useful API to allow modules making use of it.
description = (deprecated) Provides more metadata for entities and a useful API to allow modules making use of it.
core = 7.x
files[] = entity_metadata.info.inc
files[] = entity_metadata.module
files[] = entity_metadata.test
files[] = entity_metadata.tokens.inc
files[] = entity_metadata.wrapper.inc
\ No newline at end of file
dependencies[] = entity
\ No newline at end of file
<?php
// $Id$
/**
* @file
* Info include file. Includes further module.info.inc files for core modules,
* for which we provide metadata.
*/
function _entity_metadata_core_modules() {
return array_filter(array('book', 'comment', 'field', 'node', 'taxonomy', 'user', 'system'), 'module_exists');
}
/**
* Implements hook_entity_property_info().
*/
function entity_metadata_entity_property_info() {
$items = array();
foreach (_entity_metadata_core_modules() as $module) {
module_load_include('inc', 'entity_metadata', "modules/$module.info");
if (function_exists($function = "entity_metadata_{$module}_entity_property_info")) {
if ($return = $function()) {
$items = array_merge_recursive($items, $return);
}
}
}
return $items;
}
/**
* Implements hook_entity_property_info_alter().
*/
function entity_metadata_entity_property_info_alter(&$entity_info) {
foreach (_entity_metadata_core_modules() as $module) {
module_load_include('inc', 'entity_metadata', "modules/$module.info");
if (function_exists($function = "entity_metadata_{$module}_entity_property_info_alter")) {
$function($entity_info);
}
}
}
\ No newline at end of file
* An empty file to ease upgrading. This has been moved into entity.info.inc.
*/
\ No newline at end of file
This diff is collapsed.
; $Id$
name = Entity tokens
description = Provides token replacements for all properties that have no tokens and are known to the entity API.
core = 7.x
files[] = entity_token.tokens.inc
files[] = entity_token.module
dependencies[] = entity
<?php
// $Id$
/**
* @file
* Module file for the entity tokens module. Drupal needs this file.
*/
......@@ -12,8 +12,8 @@
* @return
* An array mapping token types to the usual (entity) type names.
*/
function entity_metadata_token_types() {
$return = entity_metadata_token_types_chained();
function entity_token_types() {
$return = entity_token_types_chained();
return $return + drupal_map_assoc(array('text', 'integer', 'decimal', 'duration', 'boolean', 'uri', 'site'));
}
......@@ -23,9 +23,9 @@ function entity_metadata_token_types() {
* @return
* If a type is given, whether the given type needs to be chained. Else a full
* list of token types to be chained as returned by
* entity_metadata_token_types().
* entity_token_token_types().
*/
function entity_metadata_token_types_chained($type = NULL) {
function entity_token_types_chained($type = NULL) {
// Add entities.
foreach (entity_get_info() as $entity_type => $info) {
if ($token_type = isset($info['token type']) ? $info['token type'] : $entity_type) {
......@@ -40,14 +40,14 @@ function entity_metadata_token_types_chained($type = NULL) {
/**
* Implements hook_token_info_alter().
*/
function entity_metadata_token_info_alter(&$info) {
$valid_types = entity_metadata_token_types();
function entity_token_token_info_alter(&$info) {
$valid_types = entity_token_types();
$entity_info = entity_get_info();
foreach ($valid_types as $token_type => $type) {
// Just add all properties regardless whether its in a bundle only if there
// is no token of the property yet.
foreach (entity_metadata_get_properties($type) as $name => $property) {
foreach (entity_get_all_property_info($type) as $name => $property) {
$name = str_replace('_', '-', $name);
if (!isset($info['tokens'][$token_type][$name]) && (!isset($property['type']) || in_array($property['type'], $valid_types))) {
......@@ -55,7 +55,7 @@ function entity_metadata_token_info_alter(&$info) {
'name' => $property['label'],
'type' => isset($property['type']) ? array_search($property['type'], $valid_types) : 'text',
// Mark the token so we know we have to provide the value afterwards.
'entity metadata' => TRUE,
'entity-token' => TRUE,
);
$info['tokens'][$token_type][$name]['description'] = isset($property['description']) ? $property['description'] : $property['label'];
}
......@@ -74,8 +74,8 @@ function entity_metadata_token_info_alter(&$info) {
/**
* Implements hook_tokens().
*/
function entity_metadata_tokens($type, $tokens, array $data = array(), array $options = array()) {
$token_types = entity_metadata_token_types();
function entity_token_tokens($type, $tokens, array $data = array(), array $options = array()) {
$token_types = entity_token_types();
if (isset($token_types[$type]) && (!empty($data[$type]) || $type == 'site')) {
$data += array($type => FALSE);
$replacements = array();
......@@ -83,17 +83,17 @@ function entity_metadata_tokens($type, $tokens, array $data = array(), array $op
$info = token_info();
foreach ($tokens as $name => $original) {
// Provide the token for all properties marked to stem from us.
if (!empty($info['tokens'][$type][$name]['entity metadata'])) {
$wrapper = !isset($wrapper) ? _entity_metadata_token_wrap_data($type, $token_types[$type], $data[$type], $options) : $wrapper;
if (!empty($info['tokens'][$type][$name]['entity-token'])) {
$wrapper = !isset($wrapper) ? _entity_token_wrap_data($type, $token_types[$type], $data[$type], $options) : $wrapper;
$property_name = str_replace('-', '_', $name);
$replacements[$original] = _entity_metadata_get_token($wrapper->$property_name, $options);
$replacements[$original] = _entity_token_get_token($wrapper->$property_name, $options);
}
}
// Properly chain everything of a type marked as needs chaining.
foreach ($info['tokens'][$type] as $name => $token_info) {
if (!empty($token_info['entity metadata']) && isset($token_info['type']) && entity_metadata_token_types_chained($token_info['type'])) {
if (!empty($token_info['entity-token']) && isset($token_info['type']) && entity_token_types_chained($token_info['type'])) {
if ($chained_tokens = token_find_with_prefix($tokens, $name)) {
$wrapper = !isset($wrapper) ? _entity_metadata_token_wrap_data($type, $token_types[$type], $data[$type], $options) : $wrapper;
$wrapper = !isset($wrapper) ? _entity_token_wrap_data($type, $token_types[$type], $data[$type], $options) : $wrapper;
$property_name = str_replace('-', '_', $name);
$replacements += token_generate($token_info['type'], $chained_tokens, array($token_info['type'] => $wrapper->$property_name->value()), $options);
}
......@@ -103,7 +103,10 @@ function entity_metadata_tokens($type, $tokens, array $data = array(), array $op
}
}
function _entity_metadata_token_wrap_data($token_type, $type, $data, $options) {
/**
* Wraps the given data by correctly obeying the options.
*/
function _entity_token_wrap_data($token_type, $type, $data, $options) {
$wrapper = ($type == 'site') ? entity_metadata_site_wrapper() : entity_metadata_wrapper($type, $data);
if (isset($options['language'])) {
$wrapper->language($options['language']->language);
......@@ -111,7 +114,10 @@ function _entity_metadata_token_wrap_data($token_type, $type, $data, $options) {
return $wrapper;
}
function _entity_metadata_get_token($wrapper, $options) {
/**
* Gets the token replacement by correctly obeying the options.
*/
function _entity_token_get_token($wrapper, $options) {
if (empty($options['sanitize'])) {
// When we don't need sanitized tokens decode already sanitizied texts.
$options['decode'] = TRUE;
......
<?php
// $Id$
/**
* @file
* Provides a base class for entities.
*/
/**
* A common class for entities.
*
* It's suggested, but not required, to extend this class and to override
* __construct() in order to specify a fixed entity type.
*
* It is suggested to also implement the label() and uri() methods for the
* respective callbacks in hook_entity_info(). For that case the provided
* callbacks entity_class_label() and entity_class_uri() may be specified.
*/
class <