security update core+modules
This commit is contained in:
@@ -95,9 +95,12 @@
|
||||
* - path: A path where the UI should show up as expected by hook_menu().
|
||||
* - controller class: (optional) A controller class name for providing the
|
||||
* UI. Defaults to EntityDefaultUIController, which implements an admin UI
|
||||
* suiting for managing configuration entities.
|
||||
* For customizing the UI inherit from the default class and overide methods
|
||||
* as suiting and specify your class as controller class.
|
||||
* suiting for managing configuration entities. Other provided controllers
|
||||
* suiting for content entities are EntityContentUIController or
|
||||
* EntityBundleableUIController (which work fine despite the poorly named
|
||||
* 'admin ui' key).
|
||||
* For customizing the UI inherit from the default class and override
|
||||
* methods as suiting and specify your class as controller class.
|
||||
* - file: (optional) The name of the file in which the entity form resides
|
||||
* as it is required by hook_menu().
|
||||
* - file path: (optional) The path to the file as required by hook_menu. If
|
||||
@@ -119,6 +122,13 @@
|
||||
* 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.
|
||||
* - extra fields controller class: (optional) A controller class for providing
|
||||
* field API extra fields. Defaults to none.
|
||||
* The class must implement the EntityExtraFieldsControllerInterface. Display
|
||||
* extra fields that are exposed that way are rendered by default by the
|
||||
* EntityAPIController. The EntityDefaultExtraFieldsController class may be
|
||||
* used to generate extra fields based upon property metadata, which in turn
|
||||
* get rendered by default by the EntityAPIController.
|
||||
* - features controller class: (optional) A controller class for providing
|
||||
* Features module integration for exportable entities. The given class has to
|
||||
* inherit from the default class being EntityDefaultFeaturesController. Set
|
||||
@@ -145,10 +155,11 @@
|
||||
* edit form for your entity type. See entity_form().
|
||||
* In case the 'admin ui' is used, no callback needs to be specified.
|
||||
* - entity cache: (optional) Whether entities should be cached using the cache
|
||||
* system. Requires the entitycache module to be installed and enabled. As
|
||||
* cached entities are only retrieved by id key, the cache would not apply to
|
||||
* exportable entities retrieved by name key. If enabled, 'field cache' is
|
||||
* obsolete and should be disabled. Defaults to FALSE.
|
||||
* system. Requires the entitycache module to be installed and enabled and the
|
||||
* module key to be specified. As cached entities are only retrieved by id key,
|
||||
* the cache would not apply to exportable entities retrieved by name key.
|
||||
* If enabled and the entitycache module is active, 'field cache' is obsolete
|
||||
* and is automatically disabled. Defaults to FALSE.
|
||||
*
|
||||
* @see hook_entity_info()
|
||||
* @see entity_metadata_hook_entity_info()
|
||||
@@ -325,7 +336,7 @@ function entity_metadata_hook_entity_info() {
|
||||
* entity_property_values_create_entity().
|
||||
* - field: (optional) A boolean indicating whether a property is stemming
|
||||
* from a field.
|
||||
* - computed: (optional) A boolean indiciating whether a property is
|
||||
* - computed: (optional) A boolean indicating whether a property is
|
||||
* computed, i.e. the property value is not stored or loaded by the
|
||||
* entity's controller but determined on the fly by the getter callback.
|
||||
* Defaults to FALSE.
|
||||
@@ -370,7 +381,7 @@ function entity_metadata_hook_entity_info() {
|
||||
* the same way as the entity properties array.
|
||||
*
|
||||
* @see hook_entity_property_info_alter()
|
||||
* @see entity_metadata_get_info()
|
||||
* @see entity_get_property_info()
|
||||
* @see entity_metadata_wrapper()
|
||||
*/
|
||||
function hook_entity_property_info() {
|
||||
|
@@ -148,7 +148,11 @@ function entity_features_api() {
|
||||
/**
|
||||
* Features component callback.
|
||||
*/
|
||||
function entity_features_export_options($entity_type) {
|
||||
function entity_features_export_options($a1, $a2 = NULL) {
|
||||
// Due to a change in the Features API the first parameter might be a feature
|
||||
// object or an entity type, depending on the Features version. This check is
|
||||
// for backwards compatibility.
|
||||
$entity_type = is_string($a1) ? $a1 : $a2;
|
||||
return entity_features_get_controller($entity_type)->export_options();
|
||||
}
|
||||
|
||||
|
@@ -25,9 +25,9 @@ files[] = views/handlers/entity_views_handler_field_uri.inc
|
||||
files[] = views/handlers/entity_views_handler_relationship_by_bundle.inc
|
||||
files[] = views/handlers/entity_views_handler_relationship.inc
|
||||
files[] = views/plugins/entity_views_plugin_row_entity_view.inc
|
||||
; Information added by drupal.org packaging script on 2012-12-25
|
||||
version = "7.x-1.0"
|
||||
; Information added by Drupal.org packaging script on 2015-02-25
|
||||
version = "7.x-1.6"
|
||||
core = "7.x"
|
||||
project = "entity"
|
||||
datestamp = "1356471145"
|
||||
datestamp = "1424876582"
|
||||
|
||||
|
@@ -169,6 +169,7 @@ function _entity_metadata_convert_schema_type($type) {
|
||||
switch ($type) {
|
||||
case 'int':
|
||||
case 'serial':
|
||||
case 'date':
|
||||
return 'integer';
|
||||
case 'float':
|
||||
case 'numeric':
|
||||
@@ -179,3 +180,86 @@ function _entity_metadata_convert_schema_type($type) {
|
||||
return 'text';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for extra fields controller.
|
||||
*
|
||||
* Note: Displays extra fields exposed by this controller are rendered by
|
||||
* default by the EntityAPIController.
|
||||
*/
|
||||
interface EntityExtraFieldsControllerInterface {
|
||||
|
||||
/**
|
||||
* Returns extra fields for this entity type.
|
||||
*
|
||||
* @see hook_field_extra_fields().
|
||||
*/
|
||||
public function fieldExtraFields();
|
||||
}
|
||||
|
||||
/**
|
||||
* Default controller for generating extra fields based on property metadata.
|
||||
*
|
||||
* By default a display extra field for each property not being a field, ID or
|
||||
* bundle is generated.
|
||||
*/
|
||||
class EntityDefaultExtraFieldsController implements EntityExtraFieldsControllerInterface {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $entityType;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $entityInfo;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct($type) {
|
||||
$this->entityType = $type;
|
||||
$this->entityInfo = entity_get_info($type);
|
||||
$this->propertyInfo = entity_get_property_info($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements EntityExtraFieldsControllerInterface::fieldExtraFields().
|
||||
*/
|
||||
public function fieldExtraFields() {
|
||||
$extra = array();
|
||||
foreach ($this->propertyInfo['properties'] as $name => $property_info) {
|
||||
// Skip adding the ID or bundle.
|
||||
if ($this->entityInfo['entity keys']['id'] == $name || $this->entityInfo['entity keys']['bundle'] == $name) {
|
||||
continue;
|
||||
}
|
||||
$extra[$this->entityType][$this->entityType]['display'][$name] = $this->generateExtraFieldInfo($name, $property_info);
|
||||
}
|
||||
|
||||
// Handle bundle properties.
|
||||
$this->propertyInfo += array('bundles' => array());
|
||||
foreach ($this->propertyInfo['bundles'] as $bundle_name => $info) {
|
||||
foreach ($info['properties'] as $name => $property_info) {
|
||||
if (empty($property_info['field'])) {
|
||||
$extra[$this->entityType][$bundle_name]['display'][$name] = $this->generateExtraFieldInfo($name, $property_info);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $extra;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the display field info for a given property.
|
||||
*/
|
||||
protected function generateExtraFieldInfo($name, $property_info) {
|
||||
$info = array(
|
||||
'label' => $property_info['label'],
|
||||
'weight' => 0,
|
||||
);
|
||||
if (!empty($property_info['description'])) {
|
||||
$info['description'] = $property_info['description'];
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
}
|
||||
|
@@ -5,6 +5,14 @@
|
||||
* Install file for the entity API.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_enable().
|
||||
*/
|
||||
function entity_enable() {
|
||||
// Create cache tables for entities that support Entity cache module.
|
||||
entity_entitycache_installed_modules();
|
||||
}
|
||||
|
||||
/**
|
||||
* The entity API modules have been merged into a single module.
|
||||
*/
|
||||
@@ -26,3 +34,101 @@ function entity_update_7001() {
|
||||
function entity_update_7002() {
|
||||
// Do nothing, update.php clears cache for us in case there is an update.
|
||||
}
|
||||
|
||||
/**
|
||||
* Create cache tables for entities that support Entity cache module.
|
||||
*/
|
||||
function entity_update_7003() {
|
||||
entity_entitycache_installed_modules();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create cache tables for entities of modules that support Entity cache module.
|
||||
*
|
||||
* @param $modules
|
||||
* (optional) An array of module names that have been installed.
|
||||
* If not specified, try to add cache tables for all modules.
|
||||
*/
|
||||
function entity_entitycache_installed_modules($modules = NULL) {
|
||||
if (!module_exists('entitycache')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If no modules are specified or if entitycache is being installed,
|
||||
// try to add entitycache tables for supporting entities of all modules.
|
||||
if (!isset($modules) || in_array('entitycache', $modules)) {
|
||||
$modules = module_list();
|
||||
}
|
||||
|
||||
// Get all installed modules that support entity cache.
|
||||
$entitycache_module_info = _entity_entitycache_get_module_info($modules);
|
||||
|
||||
// For uninstallation of modules, we need to keep a list of tables we created
|
||||
// per module providing the entity type.
|
||||
$tables_created = variable_get('entity_cache_tables_created');
|
||||
|
||||
foreach ($entitycache_module_info as $module => $module_entitycache_entities) {
|
||||
foreach ($module_entitycache_entities as $entity_type => $entity_info) {
|
||||
// Do not break modules that create the cache tables for themselves.
|
||||
if (!db_table_exists('cache_entity_' . $entity_type)) {
|
||||
$schema = drupal_get_schema_unprocessed('system', 'cache');
|
||||
$schema['description'] = 'Cache table used to store' . $entity_type . ' entity records.';
|
||||
db_create_table('cache_entity_' . $entity_type, $schema);
|
||||
$tables_created[$module][] = 'cache_entity_' . $entity_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
variable_set('entity_cache_tables_created', $tables_created);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove entity cache tables for entity types of uninstalled modules.
|
||||
*
|
||||
* @param $modules
|
||||
* (optional) An array of uninstalled modules. If not specified, try to remove
|
||||
* cache tables for all modules.
|
||||
*/
|
||||
function entity_entitycache_uninstalled_modules($modules = NULL) {
|
||||
// If no modules are specified or if entitycache is being uninstalled,
|
||||
// try to remove entitycache tables for supporting entities of all modules.
|
||||
if (!isset($modules) || in_array('entitycache', $modules)) {
|
||||
$modules = module_list();
|
||||
}
|
||||
$tables_created = variable_get('entity_cache_tables_created');
|
||||
foreach ($modules as $module) {
|
||||
if (!empty($tables_created[$module])) {
|
||||
foreach ($tables_created[$module] as $table) {
|
||||
db_drop_table($table);
|
||||
}
|
||||
unset($tables_created[$module]);
|
||||
}
|
||||
}
|
||||
variable_set('entity_cache_tables_created', $tables_created);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to fetch entity info about entity types that use caching.
|
||||
*/
|
||||
function _entity_entitycache_get_module_info($modules) {
|
||||
// Prepare a keyed array of all modules with their entity types and infos.
|
||||
// Structure: [module][entity][info]
|
||||
$entity_crud_info = entity_crud_get_info();
|
||||
$info = array();
|
||||
foreach ($entity_crud_info as $entity_name => $entity_info) {
|
||||
// Make sure that the entity info specifies a module and supports entitycache.
|
||||
if (!isset($entity_info['module']) || empty($entity_info['entity cache'])) {
|
||||
continue;
|
||||
}
|
||||
$module = $entity_info['module'];
|
||||
// Only treat installed modules.
|
||||
if (!in_array($module, $modules)) {
|
||||
continue;
|
||||
}
|
||||
// Add the entity info to the module key.
|
||||
if (!isset($info[$module])) {
|
||||
$info[$module] = array();
|
||||
}
|
||||
$info[$module][$entity_name] = $entity_info;
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
@@ -113,6 +113,102 @@ function entity_object_load($entity_id, $entity_type) {
|
||||
return reset($entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Page callback to show links to add an entity of a specific bundle.
|
||||
*
|
||||
* Entity modules that provide a further description to their bundles may wish
|
||||
* to implement their own version of this to show these.
|
||||
*
|
||||
* @param $entity_type
|
||||
* The type of the entity.
|
||||
*/
|
||||
function entity_ui_bundle_add_page($entity_type) {
|
||||
// Set the title, as we're a MENU_LOCAL_ACTION and hence just get tab titles.
|
||||
module_load_include('inc', 'entity', 'includes/entity.ui');
|
||||
drupal_set_title(entity_ui_get_action_title('add', $entity_type));
|
||||
|
||||
// Get entity info for our bundles.
|
||||
$info = entity_get_info($entity_type);
|
||||
$items = array();
|
||||
foreach ($info['bundles'] as $bundle_name => $bundle_info) {
|
||||
// Create an empty entity with just the bundle set to check for access.
|
||||
$dummy_entity = entity_create($entity_type, array(
|
||||
$info['entity keys']['bundle'] => $bundle_name,
|
||||
));
|
||||
// If modules use a uid, they can default to the current-user
|
||||
// in their create() method on the storage controller.
|
||||
if (entity_access('create', $entity_type, $dummy_entity, $account = NULL)) {
|
||||
$add_path = $info['admin ui']['path'] . '/add/' . $bundle_name;
|
||||
$items[] = l(t('Add @label', array('@label' => $bundle_info['label'])), $add_path);
|
||||
}
|
||||
}
|
||||
return theme('item_list', array('items' => $items));
|
||||
}
|
||||
|
||||
/**
|
||||
* Page callback to add an entity of a specific bundle.
|
||||
*
|
||||
* @param $entity_type
|
||||
* The type of the entity.
|
||||
* @param $bundle_name
|
||||
* The bundle machine name.
|
||||
*/
|
||||
function entity_ui_get_bundle_add_form($entity_type, $bundle_name) {
|
||||
$info = entity_get_info($entity_type);
|
||||
$bundle_key = $info['entity keys']['bundle'];
|
||||
|
||||
// Make a stub entity of the right bundle to pass to the entity_ui_get_form().
|
||||
$values = array(
|
||||
$bundle_key => $bundle_name,
|
||||
);
|
||||
$entity = entity_create($entity_type, $values);
|
||||
|
||||
return entity_ui_get_form($entity_type, $entity, 'add');
|
||||
}
|
||||
|
||||
/**
|
||||
* Page callback for viewing an entity.
|
||||
*
|
||||
* @param Entity $entity
|
||||
* The entity to be rendered.
|
||||
*
|
||||
* @return array
|
||||
* A renderable array of the entity in full view mode.
|
||||
*/
|
||||
function entity_ui_entity_page_view($entity) {
|
||||
module_load_include('inc', 'entity', 'includes/entity.ui');
|
||||
return $entity->view('full', NULL, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the page title for the passed operation.
|
||||
*/
|
||||
function entity_ui_get_page_title($op, $entity_type, $entity = NULL) {
|
||||
module_load_include('inc', 'entity', 'includes/entity.ui');
|
||||
$label = entity_label($entity_type, $entity);
|
||||
switch ($op) {
|
||||
case 'view':
|
||||
return $label;
|
||||
case 'edit':
|
||||
return t('Edit @label', array('@label' => $label));
|
||||
case 'clone':
|
||||
return t('Clone @label', array('@label' => $label));
|
||||
case 'revert':
|
||||
return t('Revert @label', array('@label' => $label));
|
||||
case 'delete':
|
||||
return t('Delete @label', array('@label' => $label));
|
||||
case 'export':
|
||||
return t('Export @label', array('@label' => $label));
|
||||
}
|
||||
if (isset($entity)) {
|
||||
list(, , $bundle) = entity_extract_ids($entity_type, $entity);
|
||||
}
|
||||
else {
|
||||
$bundle = NULL;
|
||||
}
|
||||
return entity_ui_get_action_title($op, $entity_type, $bundle);
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper around entity_load() to load a single entity by name or numeric id.
|
||||
*
|
||||
@@ -529,7 +625,15 @@ function entity_view($entity_type, $entities, $view_mode = 'full', $langcode = N
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given user has access to an entity.
|
||||
* Determines whether the given user can perform actions on an entity.
|
||||
*
|
||||
* For create operations, the pattern is to create an entity and then
|
||||
* check if the user has create access.
|
||||
*
|
||||
* @code
|
||||
* $node = entity_create('node', array('type' => 'page'));
|
||||
* $access = entity_access('create', 'node', $node, $account);
|
||||
* @endcode
|
||||
*
|
||||
* @param $op
|
||||
* The operation being performed. One of 'view', 'update', 'create' or
|
||||
@@ -828,7 +932,12 @@ function _entity_defaults_rebuild($entity_type) {
|
||||
// implementations.
|
||||
$originals[$name] = $entity->original;
|
||||
|
||||
$entity->{$keys['status']} |= ENTITY_IN_CODE;
|
||||
if (!isset($entity->{$keys['status']})) {
|
||||
$entity->{$keys['status']} = ENTITY_IN_CODE;
|
||||
}
|
||||
else {
|
||||
$entity->{$keys['status']} |= ENTITY_IN_CODE;
|
||||
}
|
||||
$entity->is_rebuild = TRUE;
|
||||
entity_save($entity_type, $entity);
|
||||
unset($entity->is_rebuild);
|
||||
@@ -842,6 +951,22 @@ function _entity_defaults_rebuild($entity_type) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_modules_installed().
|
||||
*/
|
||||
function entity_modules_installed($modules) {
|
||||
module_load_install('entity');
|
||||
entity_entitycache_installed_modules($modules);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_modules_uninstalled().
|
||||
*/
|
||||
function entity_modules_uninstalled($modules) {
|
||||
module_load_install('entity');
|
||||
entity_entitycache_uninstalled_modules($modules);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_modules_enabled().
|
||||
*/
|
||||
@@ -954,19 +1079,46 @@ function entity_flush_caches() {
|
||||
if (current_path() != 'admin/modules/list/confirm') {
|
||||
entity_defaults_rebuild();
|
||||
}
|
||||
|
||||
// Care about entitycache tables.
|
||||
if (module_exists('entitycache')) {
|
||||
$tables = array();
|
||||
foreach (entity_crud_get_info() as $entity_type => $entity_info) {
|
||||
if (isset($entity_info['module']) && !empty($entity_info['entity cache'])) {
|
||||
$tables[] = 'cache_entity_' . $entity_type;
|
||||
}
|
||||
}
|
||||
return $tables;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_theme().
|
||||
*/
|
||||
function entity_theme() {
|
||||
// Build a pattern in the form of "(type1|type2|...)(\.|__)" such that all
|
||||
// templates starting with an entity type or named like the entity type
|
||||
// are found.
|
||||
// This has to match the template suggestions provided in
|
||||
// template_preprocess_entity().
|
||||
$types = array_keys(entity_crud_get_info());
|
||||
$pattern = '(' . implode('|', $types) . ')(\.|__)';
|
||||
|
||||
return array(
|
||||
'entity_status' => array(
|
||||
'variables' => array('status' => NULL, 'html' => TRUE),
|
||||
'file' => 'theme/entity.theme.inc',
|
||||
),
|
||||
'entity' => array(
|
||||
'render element' => 'elements',
|
||||
'template' => 'entity',
|
||||
'pattern' => $pattern,
|
||||
'path' => drupal_get_path('module', 'entity') . '/theme',
|
||||
'file' => 'entity.theme.inc',
|
||||
),
|
||||
'entity_property' => array(
|
||||
'render element' => 'elements',
|
||||
'file' => 'theme/entity.theme.inc',
|
||||
),
|
||||
'entity_ui_overview_item' => array(
|
||||
'variables' => array('label' => NULL, 'entity_type' => NULL, 'url' => FALSE, 'name' => FALSE),
|
||||
@@ -975,90 +1127,6 @@ function entity_theme() {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Themes the exportable status of an entity.
|
||||
*/
|
||||
function theme_entity_status($variables) {
|
||||
$status = $variables['status'];
|
||||
$html = $variables['html'];
|
||||
if (($status & ENTITY_FIXED) == ENTITY_FIXED) {
|
||||
$label = t('Fixed');
|
||||
$help = t('The configuration is fixed and cannot be changed.');
|
||||
return $html ? "<span class='entity-status-fixed' title='$help'>" . $label . "</span>" : $label;
|
||||
}
|
||||
elseif (($status & ENTITY_OVERRIDDEN) == ENTITY_OVERRIDDEN) {
|
||||
$label = t('Overridden');
|
||||
$help = t('This configuration is provided by a module, but has been changed.');
|
||||
return $html ? "<span class='entity-status-overridden' title='$help'>" . $label . "</span>" : $label;
|
||||
}
|
||||
elseif ($status & ENTITY_IN_CODE) {
|
||||
$label = t('Default');
|
||||
$help = t('A module provides this configuration.');
|
||||
return $html ? "<span class='entity-status-default' title='$help'>" . $label . "</span>" : $label;
|
||||
}
|
||||
elseif ($status & ENTITY_CUSTOM) {
|
||||
$label = t('Custom');
|
||||
$help = t('A custom configuration by a user.');
|
||||
return $html ? "<span class='entity-status-custom' title='$help'>" . $label . "</span>" : $label;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process variables for entity.tpl.php.
|
||||
*/
|
||||
function template_preprocess_entity(&$variables) {
|
||||
$variables['view_mode'] = $variables['elements']['#view_mode'];
|
||||
$entity_type = $variables['elements']['#entity_type'];
|
||||
$variables['entity_type'] = $entity_type;
|
||||
$entity = $variables['elements']['#entity'];
|
||||
$variables[$variables['elements']['#entity_type']] = $entity;
|
||||
$info = entity_get_info($entity_type);
|
||||
|
||||
$variables['title'] = check_plain(entity_label($entity_type, $entity));
|
||||
|
||||
$uri = entity_uri($entity_type, $entity);
|
||||
$variables['url'] = $uri ? url($uri['path'], $uri['options']) : FALSE;
|
||||
|
||||
if (isset($variables['elements']['#page'])) {
|
||||
// If set by the caller, respect the page property.
|
||||
$variables['page'] = $variables['elements']['#page'];
|
||||
}
|
||||
else {
|
||||
// Else, try to automatically detect it.
|
||||
$variables['page'] = $uri && $uri['path'] == $_GET['q'];
|
||||
}
|
||||
|
||||
// Helpful $content variable for templates.
|
||||
$variables['content'] = array();
|
||||
foreach (element_children($variables['elements']) as $key) {
|
||||
$variables['content'][$key] = $variables['elements'][$key];
|
||||
}
|
||||
|
||||
if (!empty($info['fieldable'])) {
|
||||
// Make the field variables available with the appropriate language.
|
||||
field_attach_preprocess($entity_type, $entity, $variables['content'], $variables);
|
||||
}
|
||||
list(, , $bundle) = entity_extract_ids($entity_type, $entity);
|
||||
|
||||
// Gather css classes.
|
||||
$variables['classes_array'][] = drupal_html_class('entity-' . $entity_type);
|
||||
$variables['classes_array'][] = drupal_html_class($entity_type . '-' . $bundle);
|
||||
|
||||
// Add RDF type and about URI.
|
||||
if (module_exists('rdf')) {
|
||||
$variables['attributes_array']['about'] = empty($uri['path']) ? NULL: url($uri['path']);
|
||||
$variables['attributes_array']['typeof'] = empty($entity->rdf_mapping['rdftype']) ? NULL : $entity->rdf_mapping['rdftype'];
|
||||
}
|
||||
|
||||
// Add suggestions.
|
||||
$variables['theme_hook_suggestions'][] = $entity_type;
|
||||
$variables['theme_hook_suggestions'][] = $entity_type . '__' . $bundle;
|
||||
$variables['theme_hook_suggestions'][] = $entity_type . '__' . $bundle . '__' . $variables['view_mode'];
|
||||
if ($id = entity_id($entity_type, $entity)) {
|
||||
$variables['theme_hook_suggestions'][] = $entity_type . '__' . $id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Label callback that refers to the entity classes label method.
|
||||
*/
|
||||
@@ -1209,6 +1277,37 @@ function entity_ui_get_form($entity_type, $entity, $op = 'edit', $form_state = a
|
||||
return drupal_build_form($form_id, $form_state);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the page/menu title for local action operations.
|
||||
*
|
||||
* @param $op
|
||||
* The current operation. One of 'add' or 'import'.
|
||||
* @param $entity_type
|
||||
* The entity type.
|
||||
* @param $bundle_name
|
||||
* (Optional) The name of the bundle. May be NULL if the bundle name is not
|
||||
* relevant to the current page. If the entity type has only one bundle, or no
|
||||
* bundles, this will be the same as the entity type.
|
||||
*/
|
||||
function entity_ui_get_action_title($op, $entity_type, $bundle_name = NULL) {
|
||||
$info = entity_get_info($entity_type);
|
||||
switch ($op) {
|
||||
case 'add':
|
||||
if (isset($bundle_name) && $bundle_name != $entity_type) {
|
||||
return t('Add @bundle_name @entity_type', array(
|
||||
'@bundle_name' => drupal_strtolower($info['bundles'][$bundle_name]['label']),
|
||||
'@entity_type' => drupal_strtolower($info['label']),
|
||||
));
|
||||
}
|
||||
else {
|
||||
return t('Add @entity_type', array('@entity_type' => drupal_strtolower($info['label'])));
|
||||
}
|
||||
case 'import':
|
||||
return t('Import @entity_type', array('@entity_type' => drupal_strtolower($info['label'])));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for using i18n_string().
|
||||
*
|
||||
@@ -1236,6 +1335,39 @@ function entity_views_api() {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_extra_fields().
|
||||
*/
|
||||
function entity_field_extra_fields() {
|
||||
// Invoke specified controllers for entity types provided by the CRUD API.
|
||||
$items = array();
|
||||
foreach (entity_crud_get_info() as $type => $info) {
|
||||
if (!empty($info['extra fields controller class'])) {
|
||||
$items = array_merge_recursive($items, entity_get_extra_fields_controller($type)->fieldExtraFields());
|
||||
}
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the extra field controller class for a given entity type.
|
||||
*
|
||||
* @return EntityExtraFieldsControllerInterface|false
|
||||
* The controller for the given entity type or FALSE if none is specified.
|
||||
*/
|
||||
function entity_get_extra_fields_controller($type = NULL) {
|
||||
$static = &drupal_static(__FUNCTION__);
|
||||
|
||||
if (!isset($static[$type])) {
|
||||
$static[$type] = FALSE;
|
||||
$info = entity_get_info($type);
|
||||
if (!empty($info['extra fields controller class'])) {
|
||||
$static[$type] = new $info['extra fields controller class']($type);
|
||||
}
|
||||
}
|
||||
return $static[$type];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a property wrapper for the given data.
|
||||
*
|
||||
@@ -1338,6 +1470,13 @@ function entity_entity_info_alter(&$entity_info) {
|
||||
if (!isset($info['configuration'])) {
|
||||
$entity_info[$type]['configuration'] = !empty($info['exportable']);
|
||||
}
|
||||
|
||||
if (isset($info['controller class']) && in_array('EntityAPIControllerInterface', class_implements($info['controller class']))) {
|
||||
// Automatically disable field cache when entity cache is used.
|
||||
if (!empty($info['entity cache']) && module_exists('entitycache')) {
|
||||
$entity_info[$type]['field cache'] = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1358,7 +1497,10 @@ function _entity_info_add_metadata(&$entity_info) {
|
||||
// Set access callbacks.
|
||||
$entity_info['node']['access callback'] = 'entity_metadata_no_hook_node_access';
|
||||
$entity_info['user']['access callback'] = 'entity_metadata_user_access';
|
||||
$entity_info['file']['access callback'] = 'entity_metadata_file_access';
|
||||
// File entity has it's own entity_access function.
|
||||
if (!module_exists('file_entity')) {
|
||||
$entity_info['file']['access callback'] = 'entity_metadata_file_access';
|
||||
}
|
||||
|
||||
// CRUD function callbacks.
|
||||
$entity_info['node']['creation callback'] = 'entity_metadata_create_node';
|
||||
@@ -1375,6 +1517,11 @@ function _entity_info_add_metadata(&$entity_info) {
|
||||
$entity_info['node']['form callback'] = 'entity_metadata_form_node';
|
||||
$entity_info['user']['form callback'] = 'entity_metadata_form_user';
|
||||
|
||||
// URI callbacks.
|
||||
if (!isset($entity_info['file']['uri callback'])) {
|
||||
$entity_info['file']['uri callback'] = 'entity_metadata_uri_file';
|
||||
}
|
||||
|
||||
// View callbacks.
|
||||
$entity_info['node']['view callback'] = 'entity_metadata_view_node';
|
||||
$entity_info['user']['view callback'] = 'entity_metadata_view_single';
|
||||
|
@@ -535,6 +535,57 @@ class EntityAPIRulesIntegrationTestCase extends EntityWebTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests comments with node access.
|
||||
*/
|
||||
class EntityAPICommentNodeAccessTestCase extends CommentHelperCase {
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Entity API comment node access',
|
||||
'description' => 'Test viewing comments on nodes with node access.',
|
||||
'group' => 'Entity API',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
DrupalWebTestCase::setUp('comment', 'entity', 'node_access_test');
|
||||
node_access_rebuild();
|
||||
|
||||
// Create test node and user with simple node access permission. The
|
||||
// 'node test view' permission is implemented and granted by the
|
||||
// node_access_test module.
|
||||
$this->accessUser = $this->drupalCreateUser(array('access comments', 'post comments', 'edit own comments', 'node test view'));
|
||||
$this->noAccessUser = $this->drupalCreateUser(array('administer comments'));
|
||||
$this->node = $this->drupalCreateNode(array('type' => 'article', 'uid' => $this->accessUser->uid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests comment access when node access is enabled.
|
||||
*/
|
||||
function testCommentNodeAccess() {
|
||||
// Post comment.
|
||||
$this->drupalLogin($this->accessUser);
|
||||
$comment_text = $this->randomName();
|
||||
$comment = $this->postComment($this->node, $comment_text);
|
||||
$comment_loaded = comment_load($comment->id);
|
||||
$this->assertTrue($this->commentExists($comment), 'Comment found.');
|
||||
$this->drupalLogout();
|
||||
|
||||
// Check access to node and associated comment for access user.
|
||||
$this->assertTrue(entity_access('view', 'node', $this->node, $this->accessUser), 'Access to view node was granted for access user');
|
||||
$this->assertTrue(entity_access('view', 'comment', $comment_loaded, $this->accessUser), 'Access to view comment was granted for access user');
|
||||
$this->assertTrue(entity_access('update', 'comment', $comment_loaded, $this->accessUser), 'Access to update comment was granted for access user');
|
||||
$this->assertFalse(entity_access('delete', 'comment', $comment_loaded, $this->accessUser), 'Access to delete comment was denied for access user');
|
||||
|
||||
// Check access to node and associated comment for no access user.
|
||||
$this->assertFalse(entity_access('view', 'node', $this->node, $this->noAccessUser), 'Access to view node was denied for no access user');
|
||||
$this->assertFalse(entity_access('view', 'comment', $comment_loaded, $this->noAccessUser), 'Access to view comment was denied for no access user');
|
||||
$this->assertFalse(entity_access('update', 'comment', $comment_loaded, $this->noAccessUser), 'Access to update comment was denied for no access user');
|
||||
$this->assertFalse(entity_access('delete', 'comment', $comment_loaded, $this->noAccessUser), 'Access to delete comment was denied for no access user');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the i18n integration.
|
||||
*/
|
||||
@@ -946,6 +997,36 @@ class EntityMetadataTestCase extends EntityWebTestCase {
|
||||
|
||||
// Test field level access.
|
||||
$this->assertTrue($wrapper->{$this->field_name}->access('view'), 'Field access granted.');
|
||||
|
||||
// Create node owned by anonymous and test access() method on each of its
|
||||
// properties.
|
||||
$node = $this->drupalCreateNode(array('type' => 'page', 'uid' => 0));
|
||||
$wrapper = entity_metadata_wrapper('node', $node->nid);
|
||||
foreach ($wrapper as $name => $property) {
|
||||
$property->access('view');
|
||||
}
|
||||
|
||||
// Property access of entity references takes entity access into account.
|
||||
$node = $this->drupalCreateNode(array('type' => 'article'));
|
||||
$wrapper = entity_metadata_wrapper('node', $node);
|
||||
$unprivileged_user = $this->drupalCreateUser();
|
||||
$privileged_user = $this->drupalCreateUser(array('access user profiles'));
|
||||
|
||||
$this->assertTrue($wrapper->author->access('view', $privileged_user));
|
||||
$this->assertFalse($wrapper->author->access('view', $unprivileged_user));
|
||||
|
||||
// Ensure the same works with multiple entity references by testing the
|
||||
// $node->field_tags example.
|
||||
$privileged_user = $this->drupalCreateUser(array('administer taxonomy'));
|
||||
// Terms are view-able with access content, so make sure to remove this
|
||||
// permission first.
|
||||
user_role_revoke_permissions(DRUPAL_ANONYMOUS_RID, array('access content'));
|
||||
$unprivileged_user = drupal_anonymous_user();
|
||||
|
||||
$this->assertTrue($wrapper->field_tags->access('view', $privileged_user), 'Privileged user has access.');
|
||||
$this->assertTrue($wrapper->field_tags->access('view', $unprivileged_user), 'Unprivileged user has access.');
|
||||
$this->assertTrue($wrapper->field_tags[0]->access('view', $privileged_user), 'Privileged user has access.');
|
||||
$this->assertFalse($wrapper->field_tags[0]->access('view', $unprivileged_user), 'Unprivileged user has no access.');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1036,6 +1117,231 @@ class EntityMetadataTestCase extends EntityWebTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests basic entity_access() functionality for nodes.
|
||||
*
|
||||
* This code is a modified version of NodeAccessTestCase.
|
||||
*
|
||||
* @see NodeAccessTestCase
|
||||
*/
|
||||
class EntityMetadataNodeAccessTestCase extends EntityWebTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Entity Metadata Node Access',
|
||||
'description' => 'Test entity_access() for nodes',
|
||||
'group' => 'Entity API',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts node_access() correctly grants or denies access.
|
||||
*/
|
||||
function assertNodeMetadataAccess($ops, $node, $account) {
|
||||
foreach ($ops as $op => $result) {
|
||||
$msg = t("entity_access() returns @result with operation '@op'.", array('@result' => $result ? 'TRUE' : 'FALSE', '@op' => $op));
|
||||
$access = entity_access($op, 'node', $node, $account);
|
||||
$this->assertEqual($result, $access, $msg);
|
||||
}
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('entity', 'node');
|
||||
// Clear permissions for authenticated users.
|
||||
db_delete('role_permission')
|
||||
->condition('rid', DRUPAL_AUTHENTICATED_RID)
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs basic tests for entity_access() function.
|
||||
*/
|
||||
function testNodeMetadataAccess() {
|
||||
// Author user.
|
||||
$node_author_account = $this->drupalCreateUser(array());
|
||||
// Make a node object.
|
||||
$settings = array(
|
||||
'uid' => $node_author_account->uid,
|
||||
'type' => 'page',
|
||||
'title' => 'Node ' . $this->randomName(32),
|
||||
);
|
||||
$node = $this->drupalCreateNode($settings);
|
||||
|
||||
// Ensures user without 'access content' permission can do nothing.
|
||||
$web_user1 = $this->drupalCreateUser(array('create page content', 'edit any page content', 'delete any page content'));
|
||||
$this->assertNodeMetadataAccess(array('create' => FALSE, 'view' => FALSE, 'update' => FALSE, 'delete' => FALSE), $node, $web_user1);
|
||||
|
||||
// Ensures user with 'bypass node access' permission can do everything.
|
||||
$web_user2 = $this->drupalCreateUser(array('bypass node access'));
|
||||
$this->assertNodeMetadataAccess(array('create' => TRUE, 'view' => TRUE, 'update' => TRUE, 'delete' => TRUE), $node, $web_user2);
|
||||
|
||||
// User cannot 'view own unpublished content'.
|
||||
$web_user3 = $this->drupalCreateUser(array('access content'));
|
||||
// Create an unpublished node.
|
||||
$settings = array('type' => 'page', 'status' => 0, 'uid' => $web_user3->uid);
|
||||
$node_unpublished = $this->drupalCreateNode($settings);
|
||||
$this->assertNodeMetadataAccess(array('view' => FALSE), $node_unpublished, $web_user3);
|
||||
// User cannot create content without permission.
|
||||
$this->assertNodeMetadataAccess(array('create' => FALSE), $node, $web_user3);
|
||||
|
||||
// User can 'view own unpublished content', but another user cannot.
|
||||
$web_user4 = $this->drupalCreateUser(array('access content', 'view own unpublished content'));
|
||||
$web_user5 = $this->drupalCreateUser(array('access content', 'view own unpublished content'));
|
||||
$node4 = $this->drupalCreateNode(array('status' => 0, 'uid' => $web_user4->uid));
|
||||
$this->assertNodeMetadataAccess(array('view' => TRUE, 'update' => FALSE), $node4, $web_user4);
|
||||
$this->assertNodeMetadataAccess(array('view' => FALSE), $node4, $web_user5);
|
||||
|
||||
// Tests the default access provided for a published node.
|
||||
$node5 = $this->drupalCreateNode();
|
||||
$this->assertNodeMetadataAccess(array('view' => TRUE, 'update' => FALSE, 'delete' => FALSE, 'create' => FALSE), $node5, $web_user3);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test user permissions for node creation.
|
||||
*/
|
||||
class EntityMetadataNodeCreateAccessTestCase extends EntityWebTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Entity Metadata Node Create Access',
|
||||
'description' => 'Test entity_access() for nodes',
|
||||
'group' => 'Entity API',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('entity', 'node');
|
||||
}
|
||||
|
||||
/**
|
||||
* Addresses the special case of 'create' access for nodes.
|
||||
*/
|
||||
public function testNodeMetadataCreateAccess() {
|
||||
// Create some users. One with super-powers, one with create perms,
|
||||
// and one with no perms, and a different one to author the node.
|
||||
$admin_account = $this->drupalCreateUser(array(
|
||||
'bypass node access',
|
||||
));
|
||||
$creator_account = $this->drupalCreateUser(array(
|
||||
'create page content',
|
||||
));
|
||||
$auth_only_account = $this->drupalCreateUser(array());
|
||||
$node_author_account = $this->drupalCreateUser(array());
|
||||
|
||||
// Make a node object with Entity API (contrib)
|
||||
$settings = array(
|
||||
'uid' => $node_author_account->uid,
|
||||
'type' => 'page',
|
||||
'title' => $this->randomName(32),
|
||||
'body' => array(LANGUAGE_NONE => array(array($this->randomName(64)))),
|
||||
);
|
||||
$node = entity_create('node', $settings);
|
||||
|
||||
// Test the populated wrapper.
|
||||
$wrapper = entity_metadata_wrapper('node', $node);
|
||||
$this->assertTrue($wrapper->entityAccess('create', $admin_account), 'Create access allowed for ADMIN, for populated wrapper.');
|
||||
$this->assertTrue($wrapper->entityAccess('create', $creator_account), 'Create access allowed for CREATOR, for populated wrapper.');
|
||||
$this->assertFalse($wrapper->entityAccess('create', $auth_only_account), 'Create access denied for USER, for populated wrapper.');
|
||||
|
||||
// Test entity_acces().
|
||||
$this->assertTrue(entity_access('create', 'node', $node, $admin_account), 'Create access allowed for ADMIN, for entity_access().');
|
||||
$this->assertTrue(entity_access('create', 'node', $node, $creator_account), 'Create access allowed for CREATOR, for entity_access().');
|
||||
$this->assertFalse(entity_access('create', 'node', $node, $auth_only_account), 'Create access denied for USER, for entity_access().');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests user permissions for node revisions.
|
||||
*
|
||||
* Based almost entirely on NodeRevisionPermissionsTestCase.
|
||||
*/
|
||||
class EntityMetadataNodeRevisionAccessTestCase extends DrupalWebTestCase {
|
||||
protected $node_revisions = array();
|
||||
protected $accounts = array();
|
||||
|
||||
// Map revision permission names to node revision access ops.
|
||||
protected $map = array(
|
||||
'view' => 'view revisions',
|
||||
'update' => 'revert revisions',
|
||||
'delete' => 'delete revisions',
|
||||
);
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Entity Metadata Node Revision Access',
|
||||
'description' => 'Tests user permissions for node revision operations.',
|
||||
'group' => 'Entity API',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('entity', 'node');
|
||||
|
||||
// Create a node with several revisions.
|
||||
$node = $this->drupalCreateNode();
|
||||
$this->node_revisions[] = $node;
|
||||
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
// Create a revision for the same nid and settings with a random log.
|
||||
$revision = node_load($node->nid);
|
||||
$revision->revision = 1;
|
||||
$revision->log = $this->randomName(32);
|
||||
node_save($revision);
|
||||
$this->node_revisions[] = node_load($revision->nid);
|
||||
}
|
||||
|
||||
// Create three users, one with each revision permission.
|
||||
foreach ($this->map as $op => $permission) {
|
||||
// Create the user.
|
||||
$account = $this->drupalCreateUser(
|
||||
array(
|
||||
'access content',
|
||||
'edit any page content',
|
||||
'delete any page content',
|
||||
$permission,
|
||||
)
|
||||
);
|
||||
$account->op = $op;
|
||||
$this->accounts[] = $account;
|
||||
}
|
||||
|
||||
// Create an admin account (returns TRUE for all revision permissions).
|
||||
$admin_account = $this->drupalCreateUser(array('access content', 'administer nodes'));
|
||||
$admin_account->is_admin = TRUE;
|
||||
$this->accounts['admin'] = $admin_account;
|
||||
|
||||
// Create a normal account (returns FALSE for all revision permissions).
|
||||
$normal_account = $this->drupalCreateUser();
|
||||
$normal_account->op = FALSE;
|
||||
$this->accounts[] = $normal_account;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the entity_access() function for revisions.
|
||||
*/
|
||||
function testNodeRevisionAccess() {
|
||||
// $node_revisions[1] won't be the latest revision.
|
||||
$revision = $this->node_revisions[1];
|
||||
|
||||
$parameters = array(
|
||||
'op' => array_keys($this->map),
|
||||
'account' => $this->accounts,
|
||||
);
|
||||
|
||||
$permutations = $this->generatePermutations($parameters);
|
||||
$entity_type = 'node';
|
||||
foreach ($permutations as $case) {
|
||||
if (!empty($case['account']->is_admin) || $case['op'] == $case['account']->op) {
|
||||
$access = entity_access($case['op'], $entity_type, $revision, $case['account']);
|
||||
$this->assertTrue($access, "{$this->map[$case['op']]} granted on $entity_type.");
|
||||
}
|
||||
else {
|
||||
$access = entity_access($case['op'], $entity_type, $revision, $case['account']);
|
||||
$this->assertFalse($access, "{$this->map[$case['op']]} NOT granted on $entity_type.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests provided entity property info of the core modules.
|
||||
*/
|
||||
@@ -1137,6 +1443,11 @@ class EntityMetadataIntegrationTestCase extends EntityWebTestCase {
|
||||
$this->assertTrue($wrapper->$name->value() === NULL, 'Property ' . check_plain($name) . ' is empty.');
|
||||
}
|
||||
|
||||
protected function assertEmptyArray($wrapper, $name) {
|
||||
$this->assertTrue(isset($wrapper->$name), 'Property ' . check_plain($name) . ' exists.');
|
||||
$this->assertTrue($wrapper->$name->value() === array(), 'Property ' . check_plain($name) . ' is an empty array.');
|
||||
}
|
||||
|
||||
protected function assertValue($wrapper, $key) {
|
||||
$this->assertTrue($wrapper->$key->value() !== NULL, check_plain($key) . ' property returned.');
|
||||
$info = $wrapper->$key->info();
|
||||
@@ -1151,18 +1462,21 @@ class EntityMetadataIntegrationTestCase extends EntityWebTestCase {
|
||||
*/
|
||||
function testBookModule() {
|
||||
$title = 'Book 1';
|
||||
$node = $this->drupalCreateNode(array('title' => $title, 'type' => 'book'));
|
||||
$node2 = $this->drupalCreateNode(array('type' => 'book', 'book' => array('bid' => $node->nid)));
|
||||
$node = $this->drupalCreateNode(array('title' => $title, 'type' => 'book', 'book' => array('bid' => 'new')));
|
||||
$book = array('bid' => $node->nid, 'plid' => $node->book['mlid']);
|
||||
$node2 = $this->drupalCreateNode(array('type' => 'book', 'book' => $book));
|
||||
$node3 = $this->drupalCreateNode(array('type' => 'page'));
|
||||
|
||||
// Test whether the properties work.
|
||||
$wrapper = entity_metadata_wrapper('node', $node2);
|
||||
$this->assertEqual("Book 1", $wrapper->book->title->value(), "Book title returned.");
|
||||
$this->assertEqual($title, $wrapper->book->title->value(), "Book title returned.");
|
||||
$this->assertEqual(array($node->nid), $wrapper->book_ancestors->value(array('identifier' => TRUE)), "Book ancestors returned.");
|
||||
$this->assertEqual($node->nid, $wrapper->book->nid->value(), "Book id returned.");
|
||||
|
||||
// Try using book properties for no book nodes.
|
||||
$wrapper = entity_metadata_wrapper('node', $node3);
|
||||
$this->assertException($wrapper, 'book');
|
||||
$this->assertEmpty($wrapper, 'book');
|
||||
$this->assertEmptyArray($wrapper, 'book_ancestors');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1171,11 +1485,11 @@ class EntityMetadataIntegrationTestCase extends EntityWebTestCase {
|
||||
function testComments() {
|
||||
$title = 'Node 1';
|
||||
$node = $this->drupalCreateNode(array('title' => $title, 'type' => 'page'));
|
||||
$account = $this->drupalCreateUser();
|
||||
$author = $this->drupalCreateUser(array('access comments', 'post comments', 'edit own comments'));
|
||||
$comment = (object)array(
|
||||
'subject' => 'topic',
|
||||
'nid' => $node->nid,
|
||||
'uid' => $account->uid,
|
||||
'uid' => $author->uid,
|
||||
'cid' => FALSE,
|
||||
'pid' => 0,
|
||||
'homepage' => '',
|
||||
@@ -1191,6 +1505,71 @@ class EntityMetadataIntegrationTestCase extends EntityWebTestCase {
|
||||
}
|
||||
}
|
||||
$this->assertEmpty($wrapper, 'parent');
|
||||
|
||||
// Test comment entity access.
|
||||
$admin_user = $this->drupalCreateUser(array('access comments', 'administer comments', 'access user profiles'));
|
||||
// Also grant access to view user accounts to test the comment author
|
||||
// property.
|
||||
$unprivileged_user = $this->drupalCreateUser(array('access comments', 'access user profiles'));
|
||||
// Published comments can be viewed and edited by the author.
|
||||
$this->assertTrue($wrapper->access('view', $author), 'Comment author is allowed to view the published comment.');
|
||||
$this->assertTrue($wrapper->access('edit', $author), 'Comment author is allowed to edit the published comment.');
|
||||
// We cannot use $wrapper->access('delete') here because it only understands
|
||||
// view and edit.
|
||||
$this->assertFalse(entity_access('delete', 'comment', $comment, $author), 'Comment author is not allowed to delete the published comment.');
|
||||
|
||||
// Administrators can do anything with published comments.
|
||||
$this->assertTrue($wrapper->access('view', $admin_user), 'Comment administrator is allowed to view the published comment.');
|
||||
$this->assertTrue($wrapper->access('edit', $admin_user), 'Comment administrator is allowed to edit the published comment.');
|
||||
$this->assertTrue(entity_access('delete', 'comment', $comment, $admin_user), 'Comment administrator is allowed to delete the published comment.');
|
||||
|
||||
// Unpriviledged users can only view the published comment.
|
||||
$this->assertTrue($wrapper->access('view', $unprivileged_user), 'Unprivileged user is allowed to view the published comment.');
|
||||
$this->assertFalse($wrapper->access('edit', $unprivileged_user), 'Unprivileged user is not allowed to edit the published comment.');
|
||||
$this->assertFalse(entity_access('delete', 'comment', $comment, $unprivileged_user), 'Unprivileged user is not allowed to delete the published comment.');
|
||||
|
||||
// Test property view access.
|
||||
$view_access = array('name', 'homepage', 'subject', 'created', 'author', 'node', 'parent', 'url', 'edit_url');
|
||||
foreach ($view_access as $property_name) {
|
||||
$this->assertTrue($wrapper->{$property_name}->access('view', $unprivileged_user), "Unpriviledged user can view the $property_name property.");
|
||||
}
|
||||
|
||||
$view_denied = array('hostname', 'mail', 'status');
|
||||
foreach ($view_denied as $property_name) {
|
||||
$this->assertFalse($wrapper->{$property_name}->access('view', $unprivileged_user), "Unpriviledged user can not view the $property_name property.");
|
||||
$this->assertTrue($wrapper->{$property_name}->access('view', $admin_user), "Admin user can view the $property_name property.");
|
||||
}
|
||||
|
||||
// The author is allowed to edit the comment subject if they have the
|
||||
// 'edit own comments' permission.
|
||||
$this->assertTrue($wrapper->subject->access('edit', $author), "Author can edit the subject property.");
|
||||
$this->assertFalse($wrapper->subject->access('edit', $unprivileged_user), "Unpriviledged user cannot edit the subject property.");
|
||||
$this->assertTrue($wrapper->subject->access('edit', $admin_user), "Admin user can edit the subject property.");
|
||||
|
||||
$edit_denied = array('hostname', 'mail', 'status', 'name', 'homepage', 'created', 'parent', 'node', 'author');
|
||||
foreach ($edit_denied as $property_name) {
|
||||
$this->assertFalse($wrapper->{$property_name}->access('edit', $author), "Author cannot edit the $property_name property.");
|
||||
$this->assertTrue($wrapper->{$property_name}->access('edit', $admin_user), "Admin user can edit the $property_name property.");
|
||||
}
|
||||
|
||||
// Test access to unpublished comments.
|
||||
$comment->status = COMMENT_NOT_PUBLISHED;
|
||||
comment_save($comment);
|
||||
|
||||
// Unpublished comments cannot be accessed by the author.
|
||||
$this->assertFalse($wrapper->access('view', $author), 'Comment author is not allowed to view the unpublished comment.');
|
||||
$this->assertFalse($wrapper->access('edit', $author), 'Comment author is not allowed to edit the unpublished comment.');
|
||||
$this->assertFalse(entity_access('delete', 'comment', $comment, $author), 'Comment author is not allowed to delete the unpublished comment.');
|
||||
|
||||
// Administrators can do anything with unpublished comments.
|
||||
$this->assertTrue($wrapper->access('view', $admin_user), 'Comment administrator is allowed to view the unpublished comment.');
|
||||
$this->assertTrue($wrapper->access('edit', $admin_user), 'Comment administrator is allowed to edit the unpublished comment.');
|
||||
$this->assertTrue(entity_access('delete', 'comment', $comment, $admin_user), 'Comment administrator is allowed to delete the unpublished comment.');
|
||||
|
||||
// Unpriviledged users cannot access unpublished comments.
|
||||
$this->assertFalse($wrapper->access('view', $unprivileged_user), 'Unprivileged user is not allowed to view the unpublished comment.');
|
||||
$this->assertFalse($wrapper->access('edit', $unprivileged_user), 'Unprivileged user is not allowed to edit the unpublished comment.');
|
||||
$this->assertFalse(entity_access('delete', 'comment', $comment, $unprivileged_user), 'Unprivileged user is not allowed to delete the unpublished comment.');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1201,14 +1580,33 @@ class EntityMetadataIntegrationTestCase extends EntityWebTestCase {
|
||||
$node = $this->drupalCreateNode(array('title' => $title, 'type' => 'page'));
|
||||
$wrapper = entity_metadata_wrapper('node', $node);
|
||||
foreach ($wrapper as $key => $value) {
|
||||
if ($key != 'book' && $key != 'source' && $key != 'last_view') {
|
||||
if ($key != 'book' && $key != 'book_ancestors' && $key != 'source' && $key != 'last_view') {
|
||||
$this->assertValue($wrapper, $key);
|
||||
}
|
||||
}
|
||||
$this->assertException($wrapper, 'book');
|
||||
$this->assertEmpty($wrapper, 'book');
|
||||
$this->assertEmptyArray($wrapper, 'book_ancestors');
|
||||
$this->assertEmpty($wrapper, 'source');
|
||||
$this->assertException($wrapper->source, 'title');
|
||||
$this->assertEmpty($wrapper, 'last_view');
|
||||
|
||||
// Test statistics module integration access.
|
||||
$unpriviledged_user = $this->drupalCreateUser(array('access content'));
|
||||
$this->assertTrue($wrapper->access('view', $unpriviledged_user), 'Unpriviledged user can view the node.');
|
||||
$this->assertFalse($wrapper->access('edit', $unpriviledged_user), 'Unpriviledged user can not edit the node.');
|
||||
$count_access_user = $this->drupalCreateUser(array('view post access counter'));
|
||||
$admin_user = $this->drupalCreateUser(array('access content', 'view post access counter', 'access statistics'));
|
||||
|
||||
$this->assertFalse($wrapper->views->access('view', $unpriviledged_user), "Unpriviledged user cannot view the statistics counter property.");
|
||||
$this->assertTrue($wrapper->views->access('view', $count_access_user), "Count access user can view the statistics counter property.");
|
||||
$this->assertTrue($wrapper->views->access('view', $admin_user), "Admin user can view the statistics counter property.");
|
||||
|
||||
$admin_properties = array('day_views', 'last_view');
|
||||
foreach ($admin_properties as $property_name) {
|
||||
$this->assertFalse($wrapper->{$property_name}->access('view', $unpriviledged_user), "Unpriviledged user cannot view the $property_name property.");
|
||||
$this->assertFalse($wrapper->{$property_name}->access('view', $count_access_user), "Count access user cannot view the $property_name property.");
|
||||
$this->assertTrue($wrapper->{$property_name}->access('view', $admin_user), "Admin user can view the $property_name property.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1303,13 +1701,44 @@ class EntityMetadataIntegrationTestCase extends EntityWebTestCase {
|
||||
* Test all properties of a user.
|
||||
*/
|
||||
function testUserProperties() {
|
||||
$account = $this->drupalCreateUser();
|
||||
$account = $this->drupalCreateUser(array('access user profiles', 'change own username'));
|
||||
$account->login = REQUEST_TIME;
|
||||
$account->access = REQUEST_TIME;
|
||||
$wrapper = entity_metadata_wrapper('user', $account);
|
||||
foreach ($wrapper as $key => $value) {
|
||||
$this->assertValue($wrapper, $key);
|
||||
}
|
||||
|
||||
// Test property view access.
|
||||
$unpriviledged_user = $this->drupalCreateUser(array('access user profiles'));
|
||||
$admin_user = $this->drupalCreateUser(array('administer users'));
|
||||
$this->assertTrue($wrapper->access('view', $unpriviledged_user), 'Unpriviledged account can view the user.');
|
||||
$this->assertFalse($wrapper->access('edit', $unpriviledged_user), 'Unpriviledged account can not edit the user.');
|
||||
|
||||
$view_access = array('name', 'url', 'edit_url', 'created');
|
||||
foreach ($view_access as $property_name) {
|
||||
$this->assertTrue($wrapper->{$property_name}->access('view', $unpriviledged_user), "Unpriviledged user can view the $property_name property.");
|
||||
}
|
||||
|
||||
$view_denied = array('mail', 'last_access', 'last_login', 'roles', 'status', 'theme');
|
||||
foreach ($view_denied as $property_name) {
|
||||
$this->assertFalse($wrapper->{$property_name}->access('view', $unpriviledged_user), "Unpriviledged user can not view the $property_name property.");
|
||||
$this->assertTrue($wrapper->{$property_name}->access('view', $admin_user), "Admin user can view the $property_name property.");
|
||||
}
|
||||
|
||||
// Test property edit access.
|
||||
$edit_own_allowed = array('name', 'mail');
|
||||
foreach ($edit_own_allowed as $property_name) {
|
||||
$this->assertTrue($wrapper->{$property_name}->access('edit', $account), "Account owner can edit the $property_name property.");
|
||||
}
|
||||
|
||||
$this->assertTrue($wrapper->roles->access('view', $account), "Account owner can view their own roles.");
|
||||
|
||||
$edit_denied = array('last_access', 'last_login', 'created', 'roles', 'status', 'theme');
|
||||
foreach ($edit_denied as $property_name) {
|
||||
$this->assertFalse($wrapper->{$property_name}->access('edit', $account), "Account owner cannot edit the $property_name property.");
|
||||
$this->assertTrue($wrapper->{$property_name}->access('edit', $admin_user), "Admin user can edit the $property_name property.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -5,9 +5,9 @@ files[] = entity_token.tokens.inc
|
||||
files[] = entity_token.module
|
||||
dependencies[] = entity
|
||||
|
||||
; Information added by drupal.org packaging script on 2012-12-25
|
||||
version = "7.x-1.0"
|
||||
; Information added by Drupal.org packaging script on 2015-02-25
|
||||
version = "7.x-1.6"
|
||||
core = "7.x"
|
||||
project = "entity"
|
||||
datestamp = "1356471145"
|
||||
datestamp = "1424876582"
|
||||
|
||||
|
@@ -180,9 +180,11 @@ function entity_token_tokens($type, $tokens, array $data = array(), array $optio
|
||||
$wrapper = !isset($wrapper) ? _entity_token_wrap_data($type, $token_types[$type], $data[$type], $options) : $wrapper;
|
||||
$property_name = str_replace('-', '_', $name);
|
||||
try {
|
||||
$replacement = _entity_token_get_token($wrapper->$property_name, $options);
|
||||
if (isset($replacement)) {
|
||||
$replacements[$original] = $replacement;
|
||||
if (isset($wrapper->$property_name)) {
|
||||
$replacement = _entity_token_get_token($wrapper->$property_name, $options);
|
||||
if (isset($replacement)) {
|
||||
$replacements[$original] = $replacement;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (EntityMetadataWrapperException $e) {
|
||||
@@ -294,7 +296,7 @@ function _entity_token_wrap_data($token_type, $type, $data, $options) {
|
||||
*/
|
||||
function _entity_token_get_token($wrapper, $options) {
|
||||
|
||||
if ($wrapper->value() === NULL) {
|
||||
if (!$wrapper || $wrapper->value() === NULL) {
|
||||
// Do not provide a replacement if there is no value.
|
||||
return NULL;
|
||||
}
|
||||
|
@@ -171,7 +171,7 @@ class EntityAPIController extends DrupalDefaultEntityController implements Entit
|
||||
if ($this->revisionKey) {
|
||||
// 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, $this->defaultRevisionKey);
|
||||
$query->addExpression('CASE WHEN base.' . $this->revisionKey . ' = revision.' . $this->revisionKey . ' THEN 1 ELSE 0 END', $this->defaultRevisionKey);
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
@@ -373,10 +373,7 @@ class EntityAPIController extends DrupalDefaultEntityController implements Entit
|
||||
// Do nothing, in case invalid or no ids have been passed.
|
||||
return;
|
||||
}
|
||||
// This transaction causes troubles on MySQL, see
|
||||
// http://drupal.org/node/1007830. So we deactivate this by default until
|
||||
// is shipped in a point release.
|
||||
// $transaction = isset($transaction) ? $transaction : db_transaction();
|
||||
$transaction = isset($transaction) ? $transaction : db_transaction();
|
||||
|
||||
try {
|
||||
$ids = array_keys($entities);
|
||||
@@ -400,9 +397,7 @@ class EntityAPIController extends DrupalDefaultEntityController implements Entit
|
||||
db_ignore_slave();
|
||||
}
|
||||
catch (Exception $e) {
|
||||
if (isset($transaction)) {
|
||||
$transaction->rollback();
|
||||
}
|
||||
$transaction->rollback();
|
||||
watchdog_exception($this->entityType, $e);
|
||||
throw $e;
|
||||
}
|
||||
@@ -587,6 +582,30 @@ class EntityAPIController extends DrupalDefaultEntityController implements Entit
|
||||
$entity->content = $content;
|
||||
$langcode = isset($langcode) ? $langcode : $GLOBALS['language_content']->language;
|
||||
|
||||
// Allow modules to change the view mode.
|
||||
$context = array(
|
||||
'entity_type' => $this->entityType,
|
||||
'entity' => $entity,
|
||||
'langcode' => $langcode,
|
||||
);
|
||||
drupal_alter('entity_view_mode', $view_mode, $context);
|
||||
// Make sure the used view-mode gets stored.
|
||||
$entity->content += array('#view_mode' => $view_mode);
|
||||
|
||||
// By default add in properties for all defined extra fields.
|
||||
if ($extra_field_controller = entity_get_extra_fields_controller($this->entityType)) {
|
||||
$wrapper = entity_metadata_wrapper($this->entityType, $entity);
|
||||
$extra = $extra_field_controller->fieldExtraFields();
|
||||
$type_extra = &$extra[$this->entityType][$this->entityType]['display'];
|
||||
$bundle_extra = &$extra[$this->entityType][$wrapper->getBundle()]['display'];
|
||||
|
||||
foreach ($wrapper as $name => $property) {
|
||||
if (isset($type_extra[$name]) || isset($bundle_extra[$name])) {
|
||||
$this->renderEntityProperty($wrapper, $name, $property, $view_mode, $langcode, $entity->content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add in fields.
|
||||
if (!empty($this->entityInfo['fieldable'])) {
|
||||
// Perform the preparation tasks if they have not been performed yet.
|
||||
@@ -608,6 +627,24 @@ class EntityAPIController extends DrupalDefaultEntityController implements Entit
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a single entity property.
|
||||
*/
|
||||
protected function renderEntityProperty($wrapper, $name, $property, $view_mode, $langcode, &$content) {
|
||||
$info = $property->info();
|
||||
|
||||
$content[$name] = array(
|
||||
'#label_hidden' => FALSE,
|
||||
'#label' => $info['label'],
|
||||
'#entity_wrapped' => $wrapper,
|
||||
'#theme' => 'entity_property',
|
||||
'#property_name' => $name,
|
||||
'#access' => $property->access('view'),
|
||||
'#entity_type' => $this->entityType,
|
||||
);
|
||||
$content['#attached']['css']['entity.theme'] = drupal_get_path('module', 'entity') . '/theme/entity.theme.css';
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements EntityAPIControllerInterface.
|
||||
*/
|
||||
|
@@ -30,6 +30,8 @@ class Entity {
|
||||
protected $entityType;
|
||||
protected $entityInfo;
|
||||
protected $idKey, $nameKey, $statusKey;
|
||||
protected $defaultLabel = FALSE;
|
||||
protected $wrapper;
|
||||
|
||||
/**
|
||||
* Creates a new entity.
|
||||
@@ -55,7 +57,7 @@ class Entity {
|
||||
$this->entityInfo = entity_get_info($this->entityType);
|
||||
$this->idKey = $this->entityInfo['entity keys']['id'];
|
||||
$this->nameKey = isset($this->entityInfo['entity keys']['name']) ? $this->entityInfo['entity keys']['name'] : $this->idKey;
|
||||
$this->statusKey = empty($info['entity keys']['status']) ? 'status' : $info['entity keys']['status'];
|
||||
$this->statusKey = empty($this->entityInfo['entity keys']['status']) ? 'status' : $this->entityInfo['entity keys']['status'];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,6 +112,23 @@ class Entity {
|
||||
return !empty($this->entityInfo['entity keys']['bundle']) ? $this->{$this->entityInfo['entity keys']['bundle']} : $this->entityType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the EntityMetadataWrapper of the entity.
|
||||
*
|
||||
* @return EntityDrupalWrapper
|
||||
* An EntityMetadataWrapper containing the entity.
|
||||
*/
|
||||
public function wrapper() {
|
||||
if (empty($this->wrapper)) {
|
||||
$this->wrapper = entity_metadata_wrapper($this->entityType, $this);
|
||||
}
|
||||
elseif ($this->wrapper->value() !== $this) {
|
||||
// Wrapper has been modified outside, so let's better create a new one.
|
||||
$this->wrapper = entity_metadata_wrapper($this->entityType, $this);
|
||||
}
|
||||
return $this->wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the label of the entity.
|
||||
*
|
||||
@@ -119,10 +138,18 @@ class Entity {
|
||||
* @see entity_label()
|
||||
*/
|
||||
public function label() {
|
||||
if (isset($this->entityInfo['label callback']) && $this->entityInfo['label callback'] == 'entity_class_label') {
|
||||
// If the default label flag is enabled, this is being invoked recursively.
|
||||
// In this case we need to use our default label callback directly. This may
|
||||
// happen if a module provides a label callback implementation different
|
||||
// from ours, but then invokes Entity::label() or entity_class_label() from
|
||||
// there.
|
||||
if ($this->defaultLabel || (isset($this->entityInfo['label callback']) && $this->entityInfo['label callback'] == 'entity_class_label')) {
|
||||
return $this->defaultLabel();
|
||||
}
|
||||
return entity_label($this->entityType, $this);
|
||||
$this->defaultLabel = TRUE;
|
||||
$label = entity_label($this->entityType, $this);
|
||||
$this->defaultLabel = FALSE;
|
||||
return $label;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -253,7 +280,8 @@ class Entity {
|
||||
*/
|
||||
public function getTranslation($property, $langcode = NULL) {
|
||||
$all_info = entity_get_all_property_info($this->entityType);
|
||||
$property_info = $all_info[$property];
|
||||
// Assign by reference to avoid triggering notices if metadata is missing.
|
||||
$property_info = &$all_info[$property];
|
||||
|
||||
if (!empty($property_info['translatable'])) {
|
||||
if (!empty($property_info['field'])) {
|
||||
|
@@ -251,7 +251,11 @@ function entity_property_verify_data_type($data, $type) {
|
||||
return TRUE;
|
||||
}
|
||||
elseif (isset($info[$type]['entity keys']['name'])) {
|
||||
return entity_property_verify_data_type($data, 'token');
|
||||
// Read the data type of the name key from the metadata if available.
|
||||
$key = $info[$type]['entity keys']['name'];
|
||||
$property_info = entity_get_property_info($type);
|
||||
$property_type = isset($property_info['properties'][$key]['type']) ? $property_info['properties'][$key]['type'] : 'token';
|
||||
return entity_property_verify_data_type($data, $property_type);
|
||||
}
|
||||
return entity_property_verify_data_type($data, empty($info[$type]['fieldable']) ? 'text' : 'integer');
|
||||
}
|
||||
@@ -392,7 +396,12 @@ function entity_property_verbatim_get($data, array $options, $name, $type, $info
|
||||
*/
|
||||
function entity_property_verbatim_date_get($data, array $options, $name, $type, $info) {
|
||||
$name = isset($info['schema field']) ? $info['schema field'] : $name;
|
||||
return is_numeric($data[$name]) ? $data[$name] : strtotime($data[$name], REQUEST_TIME);
|
||||
if (is_array($data) || (is_object($data) && $data instanceof ArrayAccess)) {
|
||||
return is_numeric($data[$name]) ? $data[$name] : strtotime($data[$name], REQUEST_TIME);
|
||||
}
|
||||
elseif (is_object($data)) {
|
||||
return is_numeric($data->$name) ? $data->$name : strtotime($data->$name, REQUEST_TIME);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -503,6 +512,8 @@ function entity_property_text_formatted_info() {
|
||||
'label' => t('Text format'),
|
||||
'options list' => 'entity_metadata_field_text_formats',
|
||||
'getter callback' => 'entity_property_verbatim_get',
|
||||
'setter callback' => 'entity_property_verbatim_set',
|
||||
'setter permissions' => 'administer filters',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@@ -6,12 +6,16 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Default controller for providing UI.
|
||||
* Default UI controller providing admin UI.
|
||||
*
|
||||
* This controller suites best for managing configuration entities.
|
||||
* For a controller suiting content entities, see EntityContentUIController.
|
||||
*/
|
||||
class EntityDefaultUIController {
|
||||
|
||||
protected $entityType;
|
||||
protected $entityInfo, $path;
|
||||
protected $id_count;
|
||||
|
||||
/**
|
||||
* Defines the number of entries to show per page in overview table.
|
||||
@@ -30,7 +34,8 @@ class EntityDefaultUIController {
|
||||
*/
|
||||
public function hook_menu() {
|
||||
$items = array();
|
||||
$id_count = count(explode('/', $this->path));
|
||||
// Set this on the object so classes that extend hook_menu() can use it.
|
||||
$this->id_count = count(explode('/', $this->path));
|
||||
$wildcard = isset($this->entityInfo['admin ui']['menu wildcard']) ? $this->entityInfo['admin ui']['menu wildcard'] : '%entity_object';
|
||||
$plural_label = isset($this->entityInfo['plural label']) ? $this->entityInfo['plural label'] : $this->entityInfo['label'] . 's';
|
||||
|
||||
@@ -60,12 +65,12 @@ class EntityDefaultUIController {
|
||||
$items[$this->path . '/manage/' . $wildcard] = array(
|
||||
'title' => 'Edit',
|
||||
'title callback' => 'entity_label',
|
||||
'title arguments' => array($this->entityType, $id_count + 1),
|
||||
'title arguments' => array($this->entityType, $this->id_count + 1),
|
||||
'page callback' => 'entity_ui_get_form',
|
||||
'page arguments' => array($this->entityType, $id_count + 1),
|
||||
'page arguments' => array($this->entityType, $this->id_count + 1),
|
||||
'load arguments' => array($this->entityType),
|
||||
'access callback' => 'entity_access',
|
||||
'access arguments' => array('update', $this->entityType, $id_count + 1),
|
||||
'access arguments' => array('update', $this->entityType, $this->id_count + 1),
|
||||
);
|
||||
$items[$this->path . '/manage/' . $wildcard . '/edit'] = array(
|
||||
'title' => 'Edit',
|
||||
@@ -77,7 +82,7 @@ class EntityDefaultUIController {
|
||||
$items[$this->path . '/manage/' . $wildcard . '/clone'] = array(
|
||||
'title' => 'Clone',
|
||||
'page callback' => 'entity_ui_get_form',
|
||||
'page arguments' => array($this->entityType, $id_count + 1, 'clone'),
|
||||
'page arguments' => array($this->entityType, $this->id_count + 1, 'clone'),
|
||||
'load arguments' => array($this->entityType),
|
||||
'access callback' => 'entity_access',
|
||||
'access arguments' => array('create', $this->entityType),
|
||||
@@ -85,10 +90,10 @@ class EntityDefaultUIController {
|
||||
// Menu item for operations like revert and delete.
|
||||
$items[$this->path . '/manage/' . $wildcard . '/%'] = array(
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array($this->entityType . '_operation_form', $this->entityType, $id_count + 1, $id_count + 2),
|
||||
'page arguments' => array($this->entityType . '_operation_form', $this->entityType, $this->id_count + 1, $this->id_count + 2),
|
||||
'load arguments' => array($this->entityType),
|
||||
'access callback' => 'entity_access',
|
||||
'access arguments' => array('delete', $this->entityType, $id_count + 1),
|
||||
'access arguments' => array('delete', $this->entityType, $this->id_count + 1),
|
||||
'file' => 'includes/entity.ui.inc',
|
||||
);
|
||||
|
||||
@@ -492,6 +497,128 @@ class EntityDefaultUIController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* UI controller providing UI for content entities.
|
||||
*
|
||||
* For a controller providing UI for bundleable content entities, see
|
||||
* EntityBundleableUIController.
|
||||
* For a controller providing admin UI for configuration entities, see
|
||||
* EntityDefaultUIController.
|
||||
*/
|
||||
class EntityContentUIController extends EntityDefaultUIController {
|
||||
|
||||
/**
|
||||
* Provides definitions for implementing hook_menu().
|
||||
*/
|
||||
public function hook_menu() {
|
||||
$items = parent::hook_menu();
|
||||
$wildcard = isset($this->entityInfo['admin ui']['menu wildcard']) ? $this->entityInfo['admin ui']['menu wildcard'] : '%entity_object';
|
||||
|
||||
// Unset the manage entity path, as the provided UI is for admin entities.
|
||||
unset($items[$this->path]);
|
||||
|
||||
$defaults = array(
|
||||
'file' => $this->entityInfo['admin ui']['file'],
|
||||
'file path' => isset($this->entityInfo['admin ui']['file path']) ? $this->entityInfo['admin ui']['file path'] : drupal_get_path('module', $this->entityInfo['module']),
|
||||
);
|
||||
|
||||
// Add view, edit and delete menu items for content entities.
|
||||
$items[$this->path . '/' . $wildcard] = array(
|
||||
'title callback' => 'entity_ui_get_page_title',
|
||||
'title arguments' => array('view', $this->entityType, $this->id_count),
|
||||
'page callback' => 'entity_ui_entity_page_view',
|
||||
'page arguments' => array($this->id_count),
|
||||
'load arguments' => array($this->entityType),
|
||||
'access callback' => 'entity_access',
|
||||
'access arguments' => array('view', $this->entityType, $this->id_count),
|
||||
) + $defaults;
|
||||
$items[$this->path . '/' . $wildcard . '/view'] = array(
|
||||
'title' => 'View',
|
||||
'type' => MENU_DEFAULT_LOCAL_TASK,
|
||||
'load arguments' => array($this->entityType),
|
||||
'weight' => -10,
|
||||
) + $defaults;
|
||||
$items[$this->path . '/' . $wildcard . '/edit'] = array(
|
||||
'page callback' => 'entity_ui_get_form',
|
||||
'page arguments' => array($this->entityType, $this->id_count),
|
||||
'load arguments' => array($this->entityType),
|
||||
'access callback' => 'entity_access',
|
||||
'access arguments' => array('edit', $this->entityType, $this->id_count),
|
||||
'title' => 'Edit',
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
|
||||
) + $defaults;
|
||||
$items[$this->path . '/' . $wildcard . '/delete'] = array(
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array($this->entityType . '_operation_form', $this->entityType, $this->id_count, 'delete'),
|
||||
'load arguments' => array($this->entityType),
|
||||
'access callback' => 'entity_access',
|
||||
'access arguments' => array('delete', $this->entityType, $this->id_count),
|
||||
'title' => 'Delete',
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'context' => MENU_CONTEXT_INLINE,
|
||||
'file' => $this->entityInfo['admin ui']['file'],
|
||||
'file path' => isset($this->entityInfo['admin ui']['file path']) ? $this->entityInfo['admin ui']['file path'] : drupal_get_path('module', $this->entityInfo['module']),
|
||||
) + $defaults;
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Operation form submit callback.
|
||||
*/
|
||||
public function operationFormSubmit($form, &$form_state) {
|
||||
parent::operationFormSubmit($form, $form_state);
|
||||
// The manage entity path is unset for the content entity UI.
|
||||
$form_state['redirect'] = '<front>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* UI controller providing UI for bundleable content entities.
|
||||
*
|
||||
* Adds a bundle selection page to the entity/add path, analogously to the
|
||||
* node/add path.
|
||||
*/
|
||||
class EntityBundleableUIController extends EntityContentUIController {
|
||||
|
||||
/**
|
||||
* Provides definitions for implementing hook_menu().
|
||||
*/
|
||||
public function hook_menu() {
|
||||
$items = parent::hook_menu();
|
||||
|
||||
// Extend the 'add' path.
|
||||
$items[$this->path . '/add'] = array(
|
||||
'title callback' => 'entity_ui_get_action_title',
|
||||
'title arguments' => array('add', $this->entityType),
|
||||
'page callback' => 'entity_ui_bundle_add_page',
|
||||
'page arguments' => array($this->entityType),
|
||||
'access callback' => 'entity_access',
|
||||
'access arguments' => array('create', $this->entityType),
|
||||
'type' => MENU_LOCAL_ACTION,
|
||||
);
|
||||
$items[$this->path . '/add/%'] = array(
|
||||
'title callback' => 'entity_ui_get_action_title',
|
||||
'title arguments' => array('add', $this->entityType, $this->id_count + 1),
|
||||
'page callback' => 'entity_ui_get_bundle_add_form',
|
||||
'page arguments' => array($this->entityType, $this->id_count + 1),
|
||||
'access callback' => 'entity_access',
|
||||
'access arguments' => array('create', $this->entityType),
|
||||
);
|
||||
|
||||
if (!empty($this->entityInfo['admin ui']['file'])) {
|
||||
// Add in the include file for the entity form.
|
||||
foreach (array('/add', '/add/%') as $path_end) {
|
||||
$items[$this->path . $path_end]['file'] = $this->entityInfo['admin ui']['file'];
|
||||
$items[$this->path . $path_end]['file path'] = isset($this->entityInfo['admin ui']['file path']) ? $this->entityInfo['admin ui']['file path'] : drupal_get_path('module', $this->entityInfo['module']);
|
||||
}
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Form builder function for the overview form.
|
||||
*
|
||||
@@ -597,39 +724,6 @@ function entity_ui_controller_form_submit($form, &$form_state) {
|
||||
entity_ui_controller($form_state['entity_type'])->$method($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the page title for the passed operation.
|
||||
*/
|
||||
function entity_ui_get_page_title($op, $entity_type, $entity = NULL) {
|
||||
$label = entity_label($entity_type, $entity);
|
||||
switch ($op) {
|
||||
case 'edit':
|
||||
return t('Edit @label', array('@label' => $label));
|
||||
case 'clone':
|
||||
return t('Clone @label', array('@label' => $label));
|
||||
case 'revert':
|
||||
return t('Revert @label', array('@label' => $label));
|
||||
case 'delete':
|
||||
return t('Delete @label', array('@label' => $label));
|
||||
case 'export':
|
||||
return t('Export @label', array('@label' => $label));
|
||||
}
|
||||
return entity_ui_get_action_title($op, $entity_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the page/menu title for local action operations.
|
||||
*/
|
||||
function entity_ui_get_action_title($op, $entity_type) {
|
||||
$info = entity_get_info($entity_type);
|
||||
switch ($op) {
|
||||
case 'add':
|
||||
return t('Add @entity_type', array('@entity_type' => drupal_strtolower($info['label'])));
|
||||
case 'import':
|
||||
return t('Import @entity_type', array('@entity_type' => drupal_strtolower($info['label'])));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit builder for the main entity form, which extracts the form values and updates the entity.
|
||||
*
|
||||
@@ -670,3 +764,4 @@ function theme_entity_ui_overview_item($variables) {
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
|
@@ -228,10 +228,6 @@ abstract class EntityMetadataWrapper {
|
||||
* If there is no access information for this property, TRUE is returned.
|
||||
*/
|
||||
public function access($op, $account = NULL) {
|
||||
if (empty($this->info['parent']) && $this instanceof EntityDrupalWrapper) {
|
||||
// If there is no parent just incorporate entity based access.
|
||||
return $this->entityAccess($op == 'edit' ? 'update' : 'view', $account);
|
||||
}
|
||||
return !empty($this->info['parent']) ? $this->info['parent']->propertyAccess($this->info['name'], $op, $account) : TRUE;
|
||||
}
|
||||
|
||||
@@ -500,19 +496,15 @@ class EntityStructureWrapper extends EntityMetadataWrapper implements IteratorAg
|
||||
|
||||
protected function propertyAccess($name, $op, $account = NULL) {
|
||||
$info = $this->getPropertyInfo($name);
|
||||
// If the property should be accessed and it's an entity, make sure the user
|
||||
// is allowed to view that entity.
|
||||
if ($op == 'view' && $this->$name instanceof EntityDrupalWrapper && !$this->$name->entityAccess($op, $account)) {
|
||||
return FALSE;
|
||||
}
|
||||
// If a property should be edited and this is an entity, make sure the user
|
||||
// has update access for this entity.
|
||||
|
||||
// If a property should be edited and this is part of an entity, make sure
|
||||
// the user has update access for this entity.
|
||||
if ($op == 'edit') {
|
||||
$entity = $this;
|
||||
while (!($entity instanceof EntityDrupalWrapper) && isset($entity->info['parent'])) {
|
||||
$entity = $entity->info['parent'];
|
||||
}
|
||||
if ($entity instanceof EntityDrupalWrapper && !$entity->entityAccess('update', $account)) {
|
||||
if ($entity instanceof EntityDrupalWrapper && $entity->entityAccess('update', $account) === FALSE) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
@@ -523,6 +515,7 @@ class EntityStructureWrapper extends EntityMetadataWrapper implements IteratorAg
|
||||
elseif ($op == 'edit' && isset($info['setter permission'])) {
|
||||
return user_access($info['setter permission'], $account);
|
||||
}
|
||||
// If access is unknown, we return TRUE.
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -662,7 +655,7 @@ class EntityDrupalWrapper extends EntityStructureWrapper {
|
||||
$this->bundle = $this->type;
|
||||
}
|
||||
// Detect the bundle if not set yet and add in properties from the bundle.
|
||||
elseif (!$this->bundle && !empty($this->entityInfo['fieldable']) && $load && $this->dataAvailable()) {
|
||||
elseif (!$this->bundle && $load && $this->dataAvailable()) {
|
||||
try {
|
||||
if ($entity = $this->value()) {
|
||||
list($id, $vid, $bundle) = entity_extract_ids($this->type, $entity);
|
||||
@@ -766,7 +759,7 @@ class EntityDrupalWrapper extends EntityStructureWrapper {
|
||||
elseif ($this->id === FALSE && !$this->data) {
|
||||
$this->updateParent(NULL);
|
||||
}
|
||||
elseif ($previous_id != $this->id) {
|
||||
elseif ($previous_id !== $this->id) {
|
||||
$this->updateParent($this->id);
|
||||
}
|
||||
return $this;
|
||||
@@ -804,6 +797,34 @@ class EntityDrupalWrapper extends EntityStructureWrapper {
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Note that this method checks property access, but can be used for checking
|
||||
* entity access *only* if the wrapper is not a property (i.e. has no parent
|
||||
* wrapper).
|
||||
* To be safe, better use EntityDrupalWrapper::entityAccess() for checking
|
||||
* entity access.
|
||||
*/
|
||||
public function access($op, $account = NULL) {
|
||||
if (!empty($this->info['parent'])) {
|
||||
// If this is a property, make sure the user is able to view the
|
||||
// currently referenced entity also.
|
||||
if ($this->entityAccess('view', $account) === FALSE) {
|
||||
return FALSE;
|
||||
}
|
||||
if (parent::access($op, $account) === FALSE) {
|
||||
return FALSE;
|
||||
}
|
||||
// If access is unknown, we return TRUE.
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
// This is not a property, so fallback on entity access.
|
||||
return $this->entityAccess($op == 'edit' ? 'update' : 'view', $account);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the operation $op is allowed on the entity.
|
||||
*
|
||||
@@ -811,6 +832,12 @@ class EntityDrupalWrapper extends EntityStructureWrapper {
|
||||
*/
|
||||
public function entityAccess($op, $account = NULL) {
|
||||
$entity = $this->dataAvailable() ? $this->value() : NULL;
|
||||
// The value() method could return FALSE on entities such as user 0, so we
|
||||
// need to use NULL instead to conform to the expectations of
|
||||
// entity_access().
|
||||
if ($entity === FALSE) {
|
||||
$entity = NULL;
|
||||
}
|
||||
return entity_access($op, $this->type, $entity, $account);
|
||||
}
|
||||
|
||||
@@ -1025,8 +1052,11 @@ class EntityListWrapper extends EntityMetadataWrapper implements IteratorAggrega
|
||||
// Support setting lists of fully loaded entities.
|
||||
if ($this->isEntityList && $values && is_object(reset($values))) {
|
||||
foreach ($values as $key => $value) {
|
||||
list($id, $vid, $bundle) = entity_extract_ids($this->itemType, $value);
|
||||
$values[$key] = $id;
|
||||
// Ignore outdated NULL value references in lists of entities.
|
||||
if (isset($value)) {
|
||||
list($id, $vid, $bundle) = entity_extract_ids($this->itemType, $value);
|
||||
$values[$key] = $id;
|
||||
}
|
||||
}
|
||||
}
|
||||
return parent::set($values);
|
||||
|
@@ -20,4 +20,11 @@ function entity_metadata_book_entity_property_info_alter(&$info) {
|
||||
'description' => t("If part of a book, the book to which this book page belongs."),
|
||||
'getter callback' => 'entity_metadata_book_get_properties',
|
||||
);
|
||||
}
|
||||
$properties['book_ancestors'] = array(
|
||||
'label' => t("Book ancestors"),
|
||||
'type' => 'list<node>',
|
||||
'computed' => TRUE,
|
||||
'description' => t("If part of a book, a list of all book pages upwards in the book hierarchy."),
|
||||
'getter callback' => 'entity_metadata_book_get_properties',
|
||||
);
|
||||
}
|
||||
|
@@ -20,10 +20,22 @@ function entity_metadata_entity_get_properties($entity, array $options, $name, $
|
||||
* @see entity_metadata_book_entity_info_alter()
|
||||
*/
|
||||
function entity_metadata_book_get_properties($node, array $options, $name, $entity_type) {
|
||||
if (!isset($node->book['bid'])) {
|
||||
throw new EntityMetadataWrapperException('This node is no book page.');
|
||||
switch ($name) {
|
||||
case 'book':
|
||||
if (isset($node->book['bid'])) {
|
||||
return $node->book['bid'];
|
||||
}
|
||||
return NULL;
|
||||
|
||||
case 'book_ancestors':
|
||||
$ancestors = array();
|
||||
while (!empty($node->book['plid'])) {
|
||||
$link = book_link_load($node->book['plid']);
|
||||
array_unshift($ancestors, $link['nid']);
|
||||
$node = node_load($link['nid']);
|
||||
}
|
||||
return $ancestors;
|
||||
}
|
||||
return $node->book['bid'];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,6 +92,12 @@ function entity_metadata_comment_get_node_properties($node, array $options, $nam
|
||||
|
||||
case 'comment_count_new':
|
||||
return comment_num_new($node->nid);
|
||||
|
||||
case 'comments':
|
||||
$select = db_select('comment', 'c')
|
||||
->fields('c', array('cid'))
|
||||
->condition('c.nid', $node->nid);
|
||||
return array_keys($select->execute()->fetchAllKeyed(0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,6 +143,9 @@ function entity_metadata_node_get_properties($node, array $options, $name, $enti
|
||||
|
||||
case 'edit_url':
|
||||
return url('node/' . $node->nid . '/edit', $options);
|
||||
|
||||
case 'author':
|
||||
return !empty($node->uid) ? $node->uid : drupal_anonymous_user();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,6 +212,16 @@ function entity_metadata_statistics_node_get_properties($node, array $options, $
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Access callback for restricted node statistics properties.
|
||||
*/
|
||||
function entity_metadata_statistics_properties_access($op, $property, $entity = NULL, $account = NULL) {
|
||||
if ($property == 'views' && user_access('view post access counter', $account)) {
|
||||
return TRUE;
|
||||
}
|
||||
return user_access('access statistics', $account);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for getting site-wide properties.
|
||||
* @see entity_metadata_system_entity_info_alter()
|
||||
@@ -388,7 +419,7 @@ function entity_metadata_language_list() {
|
||||
$list = array();
|
||||
$list[LANGUAGE_NONE] = t('Language neutral');
|
||||
foreach (language_list() as $language) {
|
||||
$list[$language->language] = $language->name;
|
||||
$list[$language->language] = t($language->name);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
@@ -418,7 +449,7 @@ function entity_metadata_field_property_get($entity, array $options, $name, $ent
|
||||
/**
|
||||
* Callback for setting field property values.
|
||||
*/
|
||||
function entity_metadata_field_property_set($entity, $name, $value, $langcode, $entity_type) {
|
||||
function entity_metadata_field_property_set($entity, $name, $value, $langcode, $entity_type, $info) {
|
||||
$field = field_info_field($name);
|
||||
$columns = array_keys($field['columns']);
|
||||
$langcode = entity_metadata_field_get_language($entity_type, $entity, $field, $langcode);
|
||||
@@ -428,6 +459,10 @@ function entity_metadata_field_property_set($entity, $name, $value, $langcode, $
|
||||
foreach ($values as $delta => $value) {
|
||||
if (isset($value)) {
|
||||
$items[$delta][$columns[0]] = $value;
|
||||
if ($info['type'] == 'boolean' || $info['type'] == 'list<boolean>') {
|
||||
// Convert boolean values back to an integer for writing.
|
||||
$items[$delta][$columns[0]] = (integer) $items[$delta][$columns[0]] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
$entity->{$name}[$langcode] = $items;
|
||||
@@ -456,8 +491,15 @@ function entity_metadata_field_options_list($name, $info) {
|
||||
// No data available.
|
||||
$entity = NULL;
|
||||
}
|
||||
$instance = $wrapper->getBundle() ? field_info_instance($wrapper->type(), $name, $wrapper->getBundle()) : NULL;
|
||||
return (array) module_invoke($field['module'], 'options_list', $field, $instance, $wrapper->type(), $entity);
|
||||
|
||||
// Support translating labels via i18n field.
|
||||
if (module_exists('i18n_field') && ($translate = i18n_field_type_info($field['type'], 'translate_options'))) {
|
||||
return $translate($field);
|
||||
}
|
||||
else {
|
||||
$instance = $wrapper->getBundle() ? field_info_instance($wrapper->type(), $name, $wrapper->getBundle()) : NULL;
|
||||
return (array) module_invoke($field['module'], 'options_list', $field, $instance, $wrapper->type(), $entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -576,7 +618,7 @@ function entity_metadata_field_file_set(&$item, $property_name, $value) {
|
||||
*/
|
||||
function entity_metadata_field_file_create_item($property_name, $context) {
|
||||
// 'fid' is required, so 'file' has to be set as initial property.
|
||||
return array('display' => $context['field']['settings']['display_default']);
|
||||
return array('display' => isset($context['field']['settings']['display_default']) ? $context['field']['settings']['display_default'] : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -608,23 +650,51 @@ function entity_metadata_field_file_validate_item($items, $context) {
|
||||
*
|
||||
* This function does not implement hook_node_access(), thus it may not be
|
||||
* called entity_metadata_node_access().
|
||||
*
|
||||
* @see entity_access()
|
||||
*
|
||||
* @param $op
|
||||
* The operation being performed. One of 'view', 'update', 'create' or
|
||||
* 'delete'.
|
||||
* @param $node
|
||||
* A node to check access for. Must be a node object. Must have nid,
|
||||
* except in the case of 'create' operations.
|
||||
* @param $account
|
||||
* The user to check for. Leave it to NULL to check for the global user.
|
||||
*
|
||||
* @throws EntityMalformedException
|
||||
*
|
||||
* @return boolean
|
||||
* TRUE if access is allowed, FALSE otherwise.
|
||||
*/
|
||||
function entity_metadata_no_hook_node_access($op, $node = NULL, $account = NULL) {
|
||||
// First deal with the case where a $node is provided.
|
||||
if (isset($node)) {
|
||||
if ($op == 'create') {
|
||||
if (isset($node->type)) {
|
||||
return node_access($op, $node->type, $account);
|
||||
}
|
||||
else {
|
||||
throw new EntityMalformedException('Permission to create a node was requested but no node type was given.');
|
||||
}
|
||||
}
|
||||
// If a non-default revision is given, incorporate revision access.
|
||||
$default_revision = node_load($node->nid);
|
||||
if ($node->vid != $default_revision->vid) {
|
||||
return _node_revision_access($node, $op);
|
||||
if ($node->vid !== $default_revision->vid) {
|
||||
return _node_revision_access($node, $op, $account);
|
||||
}
|
||||
else {
|
||||
return node_access($op, $node, $account);
|
||||
}
|
||||
}
|
||||
// Is access to all nodes allowed?
|
||||
// No node is provided. Check for access to all nodes.
|
||||
if (user_access('bypass node access', $account)) {
|
||||
return TRUE;
|
||||
}
|
||||
if (!user_access('access content', $account)) {
|
||||
return FALSE;
|
||||
}
|
||||
if (user_access('bypass node access', $account) || (!isset($account) && $op == 'view' && node_access_view_all_nodes())) {
|
||||
if ($op == 'view' && node_access_view_all_nodes($account)) {
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
@@ -633,13 +703,14 @@ function entity_metadata_no_hook_node_access($op, $node = NULL, $account = NULL)
|
||||
/**
|
||||
* Access callback for the user entity.
|
||||
*/
|
||||
function entity_metadata_user_access($op, $entity = NULL, $account = NULL, $entity_type) {
|
||||
function entity_metadata_user_access($op, $entity = NULL, $account = NULL, $entity_type = NULL) {
|
||||
$account = isset($account) ? $account : $GLOBALS['user'];
|
||||
// Grant access to the users own user account and to the anonymous one.
|
||||
if (isset($entity) && $op != 'delete' && (($entity->uid == $account->uid && $entity->uid) || (!$entity->uid && $op == 'view'))) {
|
||||
if (isset($entity->uid) && $op != 'delete' && (($entity->uid == $account->uid && $entity->uid) || (!$entity->uid && $op == 'view'))) {
|
||||
return TRUE;
|
||||
}
|
||||
if (user_access('administer users', $account) || user_access('access user profiles', $account) && $op == 'view' && $entity->status) {
|
||||
if (user_access('administer users', $account)
|
||||
|| user_access('access user profiles', $account) && $op == 'view' && (empty($entity) || !empty($entity->status))) {
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
@@ -654,7 +725,7 @@ function entity_metadata_user_properties_access($op, $property, $entity = NULL,
|
||||
}
|
||||
$account = isset($account) ? $account : $GLOBALS['user'];
|
||||
// Flag to indicate if this user entity is the own user account.
|
||||
$is_own_account = isset($entity) && $account->uid == $entity->uid;
|
||||
$is_own_account = isset($entity->uid) && $account->uid == $entity->uid;
|
||||
switch ($property) {
|
||||
case 'name':
|
||||
// Allow view access to anyone with access to the entity.
|
||||
@@ -677,19 +748,54 @@ function entity_metadata_user_properties_access($op, $property, $entity = NULL,
|
||||
* Access callback for the comment entity.
|
||||
*/
|
||||
function entity_metadata_comment_access($op, $entity = NULL, $account = NULL) {
|
||||
if (isset($entity) && !isset($account) && comment_access($op, $entity)) {
|
||||
// When determining access to a comment, 'comment_access' does not take any
|
||||
// access restrictions to the comment's associated node into account. If a
|
||||
// comment has an associated node, the user must be able to view it in order
|
||||
// to access the comment.
|
||||
if (isset($entity->nid)) {
|
||||
if (!entity_access('view', 'node', node_load($entity->nid), $account)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// Comment administrators are allowed to perform all operations on all
|
||||
// comments.
|
||||
if (user_access('administer comments', $account)) {
|
||||
return TRUE;
|
||||
}
|
||||
if (user_access('administer comments', $account) || user_access('access comments', $account) && $op == 'view') {
|
||||
|
||||
// Unpublished comments can never be accessed by non-admins.
|
||||
if (isset($entity->status) && $entity->status == COMMENT_NOT_PUBLISHED) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (isset($entity) && $op == 'update') {
|
||||
// Because 'comment_access' only checks the current user, we need to do our
|
||||
// own access checking if an account was specified.
|
||||
if (!isset($account)) {
|
||||
return comment_access('edit', $entity);
|
||||
}
|
||||
else {
|
||||
return $account->uid && $account->uid == $entity->uid && user_access('edit own comments', $account);
|
||||
}
|
||||
}
|
||||
if (user_access('access comments', $account) && $op == 'view') {
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Access callback for restricted comment properties.
|
||||
*/
|
||||
function entity_metadata_comment_properties_access($op, $property, $entity = NULL, $account = NULL) {
|
||||
return user_access('administer comments', $account);
|
||||
}
|
||||
|
||||
/**
|
||||
* Access callback for the taxonomy entities.
|
||||
*/
|
||||
function entity_metadata_taxonomy_access($op, $entity = NULL, $account = NULL, $entity_type) {
|
||||
function entity_metadata_taxonomy_access($op, $entity = NULL, $account = NULL, $entity_type = NULL) {
|
||||
if ($entity_type == 'taxonomy_vocabulary') {
|
||||
return user_access('administer taxonomy', $account);
|
||||
}
|
||||
@@ -873,10 +979,17 @@ function entity_metadata_form_comment($comment) {
|
||||
* Callback to get the form of a user account.
|
||||
*/
|
||||
function entity_metadata_form_user($account) {
|
||||
// Pre-populate the form-state with the right form include.
|
||||
// If $account->uid is set then we want a user edit form.
|
||||
// Otherwise we want the user register form.
|
||||
if (isset($account->uid)) {
|
||||
$form_id = 'user_profile_form';
|
||||
form_load_include($form_state, 'inc', 'user', 'user.pages');
|
||||
}
|
||||
else {
|
||||
$form_id = 'user_register_form';
|
||||
}
|
||||
$form_state['build_info']['args'] = array($account);
|
||||
form_load_include($form_state, 'inc', 'user', 'user.pages');
|
||||
return drupal_build_form('user_profile_form', $form_state);
|
||||
return drupal_build_form($form_id, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -892,11 +1005,11 @@ function entity_metadata_form_taxonomy_term($term) {
|
||||
/**
|
||||
* Callback to get the form of a vocabulary.
|
||||
*/
|
||||
function entity_metadata_form_taxonomy_vocabulary($term) {
|
||||
function entity_metadata_form_taxonomy_vocabulary($vocab) {
|
||||
// Pre-populate the form-state with the right form include.
|
||||
$form_state['build_info']['args'] = array($term);
|
||||
$form_state['build_info']['args'] = array($vocab);
|
||||
form_load_include($form_state, 'inc', 'taxonomy', 'taxonomy.admin');
|
||||
return drupal_build_form('taxonomy_form_term', $form_state);
|
||||
return drupal_build_form('taxonomy_form_vocabulary', $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -952,3 +1065,12 @@ function entity_metadata_field_query($entity_type, $property, $value, $limit) {
|
||||
$result = $query->execute();
|
||||
return !empty($result[$entity_type]) ? array_keys($result[$entity_type]) : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements entity_uri() callback for file entities.
|
||||
*/
|
||||
function entity_metadata_uri_file($file) {
|
||||
return array(
|
||||
'path' => file_create_url($file->uri),
|
||||
);
|
||||
}
|
||||
|
@@ -24,6 +24,7 @@ function entity_metadata_comment_entity_property_info() {
|
||||
$properties['hostname'] = array(
|
||||
'label' => t("IP Address"),
|
||||
'description' => t("The IP address of the computer the comment was posted from."),
|
||||
'access callback' => 'entity_metadata_comment_properties_access',
|
||||
'schema field' => 'hostname',
|
||||
);
|
||||
$properties['name'] = array(
|
||||
@@ -40,8 +41,8 @@ function entity_metadata_comment_entity_property_info() {
|
||||
'description' => t("The email address left by the comment author."),
|
||||
'getter callback' => 'entity_metadata_comment_get_properties',
|
||||
'setter callback' => 'entity_property_verbatim_set',
|
||||
'setter permission' => 'administer comments',
|
||||
'validation callback' => 'valid_email_address',
|
||||
'access callback' => 'entity_metadata_comment_properties_access',
|
||||
'schema field' => 'mail',
|
||||
);
|
||||
$properties['homepage'] = array(
|
||||
@@ -56,7 +57,6 @@ function entity_metadata_comment_entity_property_info() {
|
||||
'label' => t("Subject"),
|
||||
'description' => t("The subject of the comment."),
|
||||
'setter callback' => 'entity_property_verbatim_set',
|
||||
'setter permission' => 'administer comments',
|
||||
'sanitize' => 'filter_xss',
|
||||
'required' => TRUE,
|
||||
'schema field' => 'subject',
|
||||
@@ -88,6 +88,7 @@ function entity_metadata_comment_entity_property_info() {
|
||||
'description' => t("The comment's parent, if comment threading is active."),
|
||||
'type' => 'comment',
|
||||
'getter callback' => 'entity_metadata_comment_get_properties',
|
||||
'setter permission' => 'administer comments',
|
||||
'schema field' => 'pid',
|
||||
);
|
||||
$properties['node'] = array(
|
||||
@@ -116,7 +117,7 @@ function entity_metadata_comment_entity_property_info() {
|
||||
// it is an integer, so we follow the schema definition.
|
||||
'type' => 'integer',
|
||||
'options list' => 'entity_metadata_status_options_list',
|
||||
'setter permission' => 'administer comments',
|
||||
'access callback' => 'entity_metadata_comment_properties_access',
|
||||
'schema field' => 'status',
|
||||
);
|
||||
return $info;
|
||||
@@ -136,6 +137,13 @@ function entity_metadata_comment_entity_property_info_alter(&$info) {
|
||||
'setter permission' => 'administer comments',
|
||||
'type' => 'integer',
|
||||
);
|
||||
$properties['comments'] = array(
|
||||
'label' => t("Comments"),
|
||||
'type' => 'list<comment>',
|
||||
'description' => t("The node comments."),
|
||||
'getter callback' => 'entity_metadata_comment_get_node_properties',
|
||||
'computed' => TRUE,
|
||||
);
|
||||
$properties['comment_count'] = array(
|
||||
'label' => t("Comment count"),
|
||||
'description' => t("The number of comments posted on a node."),
|
||||
|
@@ -51,7 +51,10 @@ function entity_metadata_field_default_property_callback(&$info, $entity_type, $
|
||||
$property = &$info[$entity_type]['bundles'][$instance['bundle']]['properties'][$name];
|
||||
$instance += array('property info' => array());
|
||||
$property = $instance['property info'] + array(
|
||||
'label' => $instance['label'],
|
||||
// Since the label will be exposed via hook_token_info() and it is not
|
||||
// clearly defined if that should be sanitized already we prevent XSS
|
||||
// right here (field labels are user provided text).
|
||||
'label' => filter_xss_admin($instance['label']),
|
||||
'type' => $field_type['property_type'],
|
||||
'description' => t('Field "@name".', array('@name' => $name)),
|
||||
'getter callback' => 'entity_metadata_field_property_get',
|
||||
@@ -164,7 +167,7 @@ function entity_metadata_field_image_callback(&$info, $entity_type, $field, $ins
|
||||
if (empty($instance['settings']['alt_field'])) {
|
||||
unset($property['property info']['alt']);
|
||||
}
|
||||
if (empty($field['settings']['title_field'])) {
|
||||
if (empty($instance['settings']['title_field'])) {
|
||||
unset($property['property info']['title']);
|
||||
}
|
||||
}
|
||||
|
@@ -118,6 +118,7 @@ function entity_metadata_node_entity_property_info() {
|
||||
'label' => t("Author"),
|
||||
'type' => 'user',
|
||||
'description' => t("The author of the node."),
|
||||
'getter callback' => 'entity_metadata_node_get_properties',
|
||||
'setter callback' => 'entity_property_verbatim_set',
|
||||
'setter permission' => 'administer nodes',
|
||||
'required' => TRUE,
|
||||
|
@@ -19,6 +19,7 @@ function entity_metadata_statistics_entity_property_info_alter(&$info) {
|
||||
'type' => 'integer',
|
||||
'getter callback' => 'entity_metadata_statistics_node_get_properties',
|
||||
'computed' => TRUE,
|
||||
'access callback' => 'entity_metadata_statistics_properties_access',
|
||||
);
|
||||
$properties['day_views'] = array(
|
||||
'label' => t("Views today"),
|
||||
@@ -26,6 +27,7 @@ function entity_metadata_statistics_entity_property_info_alter(&$info) {
|
||||
'type' => 'integer',
|
||||
'getter callback' => 'entity_metadata_statistics_node_get_properties',
|
||||
'computed' => TRUE,
|
||||
'access callback' => 'entity_metadata_statistics_properties_access',
|
||||
);
|
||||
$properties['last_view'] = array(
|
||||
'label' => t("Last view"),
|
||||
@@ -33,5 +35,6 @@ function entity_metadata_statistics_entity_property_info_alter(&$info) {
|
||||
'type' => 'date',
|
||||
'getter callback' => 'entity_metadata_statistics_node_get_properties',
|
||||
'computed' => TRUE,
|
||||
'access callback' => 'entity_metadata_statistics_properties_access',
|
||||
);
|
||||
}
|
||||
|
@@ -59,6 +59,7 @@ function entity_metadata_user_entity_property_info() {
|
||||
'description' => t("The date the user last accessed the site."),
|
||||
'getter callback' => 'entity_metadata_user_get_properties',
|
||||
'type' => 'date',
|
||||
'access callback' => 'entity_metadata_user_properties_access',
|
||||
'schema field' => 'access',
|
||||
);
|
||||
$properties['last_login'] = array(
|
||||
@@ -66,6 +67,7 @@ function entity_metadata_user_entity_property_info() {
|
||||
'description' => t("The date the user last logged in to the site."),
|
||||
'getter callback' => 'entity_metadata_user_get_properties',
|
||||
'type' => 'date',
|
||||
'access callback' => 'entity_metadata_user_properties_access',
|
||||
'schema field' => 'login',
|
||||
);
|
||||
$properties['created'] = array(
|
||||
@@ -73,6 +75,7 @@ function entity_metadata_user_entity_property_info() {
|
||||
'description' => t("The date the user account was created."),
|
||||
'type' => 'date',
|
||||
'schema field' => 'created',
|
||||
'setter permission' => 'administer users',
|
||||
);
|
||||
$properties['roles'] = array(
|
||||
'label' => t("User roles"),
|
||||
@@ -80,7 +83,6 @@ function entity_metadata_user_entity_property_info() {
|
||||
'type' => 'list<integer>',
|
||||
'getter callback' => 'entity_metadata_user_get_properties',
|
||||
'setter callback' => 'entity_metadata_user_set_properties',
|
||||
'setter permission' => 'administer users',
|
||||
'options list' => 'entity_metadata_user_roles',
|
||||
'access callback' => 'entity_metadata_user_properties_access',
|
||||
);
|
||||
@@ -92,7 +94,7 @@ function entity_metadata_user_entity_property_info() {
|
||||
// it is an integer, so we follow the schema definition.
|
||||
'type' => 'integer',
|
||||
'options list' => 'entity_metadata_user_status_options_list',
|
||||
'setter permission' => 'administer users',
|
||||
'access callback' => 'entity_metadata_user_properties_access',
|
||||
'schema field' => 'status',
|
||||
);
|
||||
$properties['theme'] = array(
|
||||
|
@@ -6,9 +6,9 @@ files[] = entity_feature.module
|
||||
dependencies[] = entity_test
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by drupal.org packaging script on 2012-12-25
|
||||
version = "7.x-1.0"
|
||||
; Information added by Drupal.org packaging script on 2015-02-25
|
||||
version = "7.x-1.6"
|
||||
core = "7.x"
|
||||
project = "entity"
|
||||
datestamp = "1356471145"
|
||||
datestamp = "1424876582"
|
||||
|
||||
|
@@ -7,9 +7,9 @@ files[] = entity_test.install
|
||||
dependencies[] = entity
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by drupal.org packaging script on 2012-12-25
|
||||
version = "7.x-1.0"
|
||||
; Information added by Drupal.org packaging script on 2015-02-25
|
||||
version = "7.x-1.6"
|
||||
core = "7.x"
|
||||
project = "entity"
|
||||
datestamp = "1356471145"
|
||||
datestamp = "1424876582"
|
||||
|
||||
|
@@ -51,8 +51,14 @@ function entity_test_schema() {
|
||||
'uid' => array('uid'),
|
||||
),
|
||||
'foreign keys' => array(
|
||||
'uid' => array('users' => 'uid'),
|
||||
'name' => array('entity_test_types' => 'name'),
|
||||
'uid' => array(
|
||||
'table' => 'users',
|
||||
'columns' => array('uid' => 'uid')
|
||||
),
|
||||
'name' => array(
|
||||
'table' => 'entity_test_types',
|
||||
'columns' => array('name' => 'name')
|
||||
),
|
||||
),
|
||||
'primary key' => array('pid'),
|
||||
);
|
||||
|
@@ -267,8 +267,15 @@ function entity_test_entity_getter($node) {
|
||||
if (empty($node->entity)) {
|
||||
$node->entity = array('type' => 'user', 'id' => $node->uid);
|
||||
}
|
||||
|
||||
// We have to return the entity wrapped.
|
||||
return entity_metadata_wrapper($node->entity['type'], $node->entity['id']);
|
||||
// Special handling for anonymous user.
|
||||
if ($node->entity['type'] === 'user' && empty($node->entity['id'])) {
|
||||
return entity_metadata_wrapper('user', drupal_anonymous_user());
|
||||
}
|
||||
else {
|
||||
return entity_metadata_wrapper($node->entity['type'], $node->entity['id']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -5,9 +5,9 @@ dependencies[] = i18n_string
|
||||
package = Multilingual - Internationalization
|
||||
core = 7.x
|
||||
hidden = TRUE
|
||||
; Information added by drupal.org packaging script on 2012-12-25
|
||||
version = "7.x-1.0"
|
||||
; Information added by Drupal.org packaging script on 2015-02-25
|
||||
version = "7.x-1.6"
|
||||
core = "7.x"
|
||||
project = "entity"
|
||||
datestamp = "1356471145"
|
||||
datestamp = "1424876582"
|
||||
|
||||
|
4
sites/all/modules/entity/theme/entity.theme.css
Normal file
4
sites/all/modules/entity/theme/entity.theme.css
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
.entity-property-label {
|
||||
font-weight: bold;
|
||||
}
|
212
sites/all/modules/entity/theme/entity.theme.inc
Normal file
212
sites/all/modules/entity/theme/entity.theme.inc
Normal file
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Holds entity module's theme functions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns HTML for an entity property.
|
||||
*
|
||||
* This is the default theme implementation to display the value of a property.
|
||||
* This function can be overridden with varying levels of specificity. For
|
||||
* example, for a property named 'title' displayed on the 'article' bundle,
|
||||
* any of the following functions will override this default implementation.
|
||||
* The first of these functions that exists is used:
|
||||
* - THEMENAME_property__body__article()
|
||||
* - THEMENAME_property__article()
|
||||
* - THEMENAME_property__body()
|
||||
* - THEMENAME_property()
|
||||
*
|
||||
* @param $variables
|
||||
* An associative array containing:
|
||||
* - label: A boolean indicating to show or hide the property label.
|
||||
* - title_attributes: A string containing the attributes for the title.
|
||||
* - label: The label for the property.
|
||||
* - content_attributes: A string containing the attributes for the content's
|
||||
* div.
|
||||
* - content: The rendered property value.
|
||||
* - attributes: A string containing the attributes for the wrapping div.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_entity_property($variables) {
|
||||
$output = '';
|
||||
|
||||
// Render the label, if it's not hidden.
|
||||
if (!$variables['label_hidden']) {
|
||||
$output .= '<div' . $variables['title_attributes'] . '>' . $variables['label'] . ': </div>';
|
||||
}
|
||||
|
||||
// Render the content.
|
||||
$content_suffix = '';
|
||||
if (!$variables['label_hidden'] || $variables['content_attributes']) {
|
||||
$output .= '<div' . $variables['content_attributes'] . '>';
|
||||
$content_suffix = '</div>';
|
||||
}
|
||||
$output .= $variables['content'] . $content_suffix;
|
||||
|
||||
// Render the top-level DIV.
|
||||
return '<div' . $variables['attributes'] . '>' . $output . '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme preprocess function for theme_entity_property().
|
||||
*
|
||||
* @see theme_entity_property()
|
||||
*/
|
||||
function template_preprocess_entity_property(&$variables, $hook) {
|
||||
$element = $variables['elements'];
|
||||
|
||||
$variables += array(
|
||||
'theme_hook_suggestions' => array(),
|
||||
'attributes_array' => array(),
|
||||
);
|
||||
// Generate variables from element properties.
|
||||
foreach (array('label_hidden', 'label', 'property_name') as $name) {
|
||||
$variables[$name] = check_plain($element['#' . $name]);
|
||||
}
|
||||
$variables['title_attributes_array']['class'][] = 'entity-property-label';
|
||||
$variables['attributes_array'] = array_merge($variables['attributes_array'], isset($element['#attributes']) ? $element['#attributes'] : array());
|
||||
|
||||
$variables['property_name_css'] = strtr($element['#property_name'], '_', '-');
|
||||
$variables['attributes_array']['class'][] = 'entity-property';
|
||||
$variables['attributes_array']['class'][] = 'entity-property-' . $variables['property_name_css'];
|
||||
|
||||
// Add specific suggestions that can override the default implementation.
|
||||
$variables['theme_hook_suggestions'] += array(
|
||||
'entity_property__' . $element['#property_name'],
|
||||
'entity_property__' . $element['#entity_type'] . '__' . $element['#property_name'],
|
||||
);
|
||||
|
||||
// Populate the content with sensible defaults.
|
||||
if (!isset($variables['content'])) {
|
||||
$variables['content'] = entity_property_default_render_value_by_type($element['#entity_wrapped']->{$element['#property_name']});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a property using simple defaults based upon the property type.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function entity_property_default_render_value_by_type(EntityMetadataWrapper $property) {
|
||||
// If there is an options list or entity label, render that by default.
|
||||
if ($label = $property->label()) {
|
||||
if ($property instanceof EntityDrupalWrapper && $uri = entity_uri($property->type(), $property->value())) {
|
||||
return l($label, $uri['path'], $uri['options']);
|
||||
}
|
||||
else {
|
||||
return check_plain($label);
|
||||
}
|
||||
}
|
||||
switch ($property->type()) {
|
||||
case 'boolean':
|
||||
return $property->value() ? t('yes') : t('no');
|
||||
default:
|
||||
return check_plain($property->value());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme process function for theme_entity_property().
|
||||
*
|
||||
* Taken over from template_process_field()
|
||||
*
|
||||
* @see theme_entity_property()
|
||||
*/
|
||||
function template_process_entity_property(&$variables, $hook) {
|
||||
$element = $variables['elements'];
|
||||
// The default theme implementation is a function, so template_process() does
|
||||
// not automatically run, so we need to flatten the classes and attributes
|
||||
// here. For best performance, only call drupal_attributes() when needed, and
|
||||
// note that template_preprocess_field() does not initialize the
|
||||
// *_attributes_array variables.
|
||||
$variables['attributes'] = empty($variables['attributes_array']) ? '' : drupal_attributes($variables['attributes_array']);
|
||||
$variables['title_attributes'] = empty($variables['title_attributes_array']) ? '' : drupal_attributes($variables['title_attributes_array']);
|
||||
$variables['content_attributes'] = empty($variables['content_attributes_array']) ? '' : drupal_attributes($variables['content_attributes_array']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Themes the exportable status of an entity.
|
||||
*/
|
||||
function theme_entity_status($variables) {
|
||||
$status = $variables['status'];
|
||||
$html = $variables['html'];
|
||||
if (($status & ENTITY_FIXED) == ENTITY_FIXED) {
|
||||
$label = t('Fixed');
|
||||
$help = t('The configuration is fixed and cannot be changed.');
|
||||
return $html ? "<span class='entity-status-fixed' title='$help'>" . $label . "</span>" : $label;
|
||||
}
|
||||
elseif (($status & ENTITY_OVERRIDDEN) == ENTITY_OVERRIDDEN) {
|
||||
$label = t('Overridden');
|
||||
$help = t('This configuration is provided by a module, but has been changed.');
|
||||
return $html ? "<span class='entity-status-overridden' title='$help'>" . $label . "</span>" : $label;
|
||||
}
|
||||
elseif ($status & ENTITY_IN_CODE) {
|
||||
$label = t('Default');
|
||||
$help = t('A module provides this configuration.');
|
||||
return $html ? "<span class='entity-status-default' title='$help'>" . $label . "</span>" : $label;
|
||||
}
|
||||
elseif ($status & ENTITY_CUSTOM) {
|
||||
$label = t('Custom');
|
||||
$help = t('A custom configuration by a user.');
|
||||
return $html ? "<span class='entity-status-custom' title='$help'>" . $label . "</span>" : $label;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process variables for entity.tpl.php.
|
||||
*/
|
||||
function template_preprocess_entity(&$variables) {
|
||||
$variables['view_mode'] = $variables['elements']['#view_mode'];
|
||||
$entity_type = $variables['elements']['#entity_type'];
|
||||
$variables['entity_type'] = $entity_type;
|
||||
$entity = $variables['elements']['#entity'];
|
||||
$variables[$variables['elements']['#entity_type']] = $entity;
|
||||
$info = entity_get_info($entity_type);
|
||||
|
||||
$variables['title'] = check_plain(entity_label($entity_type, $entity));
|
||||
|
||||
$uri = entity_uri($entity_type, $entity);
|
||||
$variables['url'] = $uri && !empty($uri['path']) ? url($uri['path'], $uri['options']) : FALSE;
|
||||
|
||||
if (isset($variables['elements']['#page'])) {
|
||||
// If set by the caller, respect the page property.
|
||||
$variables['page'] = $variables['elements']['#page'];
|
||||
}
|
||||
else {
|
||||
// Else, try to automatically detect it.
|
||||
$variables['page'] = $uri && !empty($uri['path']) && $uri['path'] == $_GET['q'];
|
||||
}
|
||||
|
||||
// Helpful $content variable for templates.
|
||||
$variables['content'] = array();
|
||||
foreach (element_children($variables['elements']) as $key) {
|
||||
$variables['content'][$key] = $variables['elements'][$key];
|
||||
}
|
||||
|
||||
if (!empty($info['fieldable'])) {
|
||||
// Make the field variables available with the appropriate language.
|
||||
field_attach_preprocess($entity_type, $entity, $variables['content'], $variables);
|
||||
}
|
||||
list(, , $bundle) = entity_extract_ids($entity_type, $entity);
|
||||
|
||||
// Gather css classes.
|
||||
$variables['classes_array'][] = drupal_html_class('entity-' . $entity_type);
|
||||
$variables['classes_array'][] = drupal_html_class($entity_type . '-' . $bundle);
|
||||
|
||||
// Add RDF type and about URI.
|
||||
if (module_exists('rdf')) {
|
||||
$variables['attributes_array']['about'] = empty($uri['path']) ? NULL: url($uri['path']);
|
||||
$variables['attributes_array']['typeof'] = empty($entity->rdf_mapping['rdftype']) ? NULL : $entity->rdf_mapping['rdftype'];
|
||||
}
|
||||
|
||||
// Add suggestions.
|
||||
$variables['theme_hook_suggestions'][] = $entity_type;
|
||||
$variables['theme_hook_suggestions'][] = $entity_type . '__' . $bundle;
|
||||
$variables['theme_hook_suggestions'][] = $entity_type . '__' . $bundle . '__' . $variables['view_mode'];
|
||||
if ($id = entity_id($entity_type, $entity)) {
|
||||
$variables['theme_hook_suggestions'][] = $entity_type . '__' . $id;
|
||||
}
|
||||
}
|
@@ -379,6 +379,7 @@ class EntityDefaultViewsController {
|
||||
$label = isset($this->info['plural label']) ? $this->info['plural label'] : $this->info['label'];
|
||||
$data[$table]['table']['base'] = array(
|
||||
'field' => $this->info['entity keys']['id'],
|
||||
'access query tag' => $this->type . '_access',
|
||||
'title' => drupal_ucfirst($label),
|
||||
'help' => isset($this->info['description']) ? $this->info['description'] : '',
|
||||
);
|
||||
@@ -388,6 +389,50 @@ class EntityDefaultViewsController {
|
||||
// Add in any reverse-relationships which have been determined.
|
||||
$data += $this->relationships;
|
||||
}
|
||||
if (!empty($this->info['revision table']) && !empty($this->info['entity keys']['revision'])) {
|
||||
$revision_table = $this->info['revision table'];
|
||||
|
||||
$data[$table]['table']['default_relationship'] = array(
|
||||
$revision_table => array(
|
||||
'table' => $revision_table,
|
||||
'field' => $this->info['entity keys']['revision'],
|
||||
),
|
||||
);
|
||||
|
||||
// Define the base group of this table. Fields that don't
|
||||
// have a group defined will go into this field by default.
|
||||
$data[$revision_table]['table']['group'] = drupal_ucfirst($this->info['label']) . ' ' . t('Revisions');
|
||||
$data[$revision_table]['table']['entity type'] = $this->type;
|
||||
|
||||
// If the plural label isn't available, use the regular label.
|
||||
$label = isset($this->info['plural label']) ? $this->info['plural label'] : $this->info['label'];
|
||||
$data[$revision_table]['table']['base'] = array(
|
||||
'field' => $this->info['entity keys']['revision'],
|
||||
'access query tag' => $this->type . '_access',
|
||||
'title' => drupal_ucfirst($label) . ' ' . t('Revisions'),
|
||||
'help' => (isset($this->info['description']) ? $this->info['description'] . ' ' : '') . t('Revisions'),
|
||||
);
|
||||
$data[$revision_table]['table']['entity type'] = $this->type;
|
||||
$data[$revision_table] += $this->schema_revision_fields();
|
||||
|
||||
// Add in any reverse-relationships which have been determined.
|
||||
$data += $this->relationships;
|
||||
|
||||
// For other base tables, explain how we join.
|
||||
$data[$revision_table]['table']['join'] = array(
|
||||
// Directly links to base table.
|
||||
$table => array(
|
||||
'left_field' => $this->info['entity keys']['revision'],
|
||||
'field' => $this->info['entity keys']['revision'],
|
||||
),
|
||||
);
|
||||
$data[$revision_table]['table']['default_relationship'] = array(
|
||||
$table => array(
|
||||
'table' => $table,
|
||||
'field' => $this->info['entity keys']['id'],
|
||||
),
|
||||
);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -410,6 +455,27 @@ class EntityDefaultViewsController {
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to come up with some views fields with the help of the revision schema
|
||||
* and the entity property information.
|
||||
*/
|
||||
protected function schema_revision_fields() {
|
||||
$data = array();
|
||||
if (!empty($this->info['revision table'])) {
|
||||
$schema = drupal_get_schema($this->info['revision table']);
|
||||
$properties = entity_get_property_info($this->type) + array('properties' => array());
|
||||
|
||||
foreach ($properties['properties'] as $name => $property_info) {
|
||||
if (isset($property_info['schema field']) && isset($schema['fields'][$property_info['schema field']])) {
|
||||
if ($views_info = $this->map_from_schema_info($name, $schema['fields'][$property_info['schema field']], $property_info)) {
|
||||
$data[$name] = $views_info;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Comes up with views information based on the given schema and property
|
||||
* info.
|
||||
|
@@ -196,8 +196,14 @@ class EntityFieldHandlerHelper {
|
||||
if ($handler->relationship) {
|
||||
$current_handler = $handler;
|
||||
$view = $current_handler->view;
|
||||
while (!empty($current_handler->relationship) && !empty($view->relationship[$current_handler->relationship])) {
|
||||
$current_handler = $view->relationship[$current_handler->relationship];
|
||||
$relationships = array();
|
||||
// Collect all relationships, keyed by alias.
|
||||
foreach ($view->relationship as $key => $relationship) {
|
||||
$key = $relationship->alias ? $relationship->alias : $key;
|
||||
$relationships[$key] = $relationship;
|
||||
}
|
||||
while (!empty($current_handler->relationship) && !empty($relationships[$current_handler->relationship])) {
|
||||
$current_handler = $relationships[$current_handler->relationship];
|
||||
$return = $current_handler->real_field . ($return ? ":$return" : '');
|
||||
}
|
||||
}
|
||||
@@ -337,7 +343,7 @@ class EntityFieldHandlerHelper {
|
||||
$values->_entity_properties[$selector] = $wrapper->value();
|
||||
}
|
||||
else {
|
||||
$values->_entity_properties[$selector] = isset($wrapper->$field) ? $wrapper->$field->value(array('identifier' => TRUE)) : $default;
|
||||
$values->_entity_properties[$selector] = isset($wrapper->$field) ? $wrapper->$field->value(array('identifier' => TRUE, 'sanitize' => TRUE)) : $default;
|
||||
}
|
||||
}
|
||||
catch (EntityMetadataWrapperException $e) {
|
||||
|
@@ -10,6 +10,7 @@ class entity_views_handler_area_entity extends views_handler_area {
|
||||
$options['entity_type'] = array('default' => 'node');
|
||||
$options['entity_id'] = array('default' => '');
|
||||
$options['view_mode'] = array('default' => 'full');
|
||||
$options['bypass_access'] = array('default' => FALSE);
|
||||
return $options;
|
||||
}
|
||||
|
||||
@@ -73,6 +74,12 @@ class entity_views_handler_area_entity extends views_handler_area {
|
||||
);
|
||||
}
|
||||
}
|
||||
$form['bypass_access'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Bypass access checks'),
|
||||
'#description' => t('If enabled, access permissions for rendering the entity are not checked.'),
|
||||
'#default_value' => !empty($this->options['bypass_access']),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
@@ -99,10 +106,12 @@ class entity_views_handler_area_entity extends views_handler_area {
|
||||
*/
|
||||
public function render_entity($entity_type, $entity_id, $view_mode) {
|
||||
if (!empty($entity_type) && !empty($entity_id) && !empty($view_mode)) {
|
||||
$entities = entity_load($entity_type, array($entity_id));
|
||||
$render = entity_view($entity_type, $entities, $view_mode);
|
||||
$render_entity = reset($render);
|
||||
return drupal_render($render_entity);
|
||||
$entity = entity_load_single($entity_type, $entity_id);
|
||||
if (!empty($this->options['bypass_access']) || entity_access('view', $entity_type, $entity)) {
|
||||
$render = entity_view($entity_type, array($entity), $view_mode);
|
||||
$render_entity = reset($render);
|
||||
return drupal_render($render_entity);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return '';
|
||||
|
@@ -122,8 +122,10 @@ class entity_views_handler_field_duration extends views_handler_field {
|
||||
if ($this->options['format_interval']) {
|
||||
$value = format_interval($value, (int) $this->options['granularity']);
|
||||
}
|
||||
// Value sanitization is handled by the wrapper, see
|
||||
// EntityFieldHandlerHelper::get_value().
|
||||
return $this->sanitize_value($this->options['prefix'], 'xss') .
|
||||
$this->sanitize_value($value) .
|
||||
$value .
|
||||
$this->sanitize_value($this->options['suffix'], 'xss');
|
||||
}
|
||||
|
||||
|
@@ -80,6 +80,7 @@ class entity_views_handler_field_entity extends views_handler_field {
|
||||
$options['display'] = array('default' => 'label');
|
||||
$options['link_to_entity']['default'] = TRUE;
|
||||
$options['view_mode'] = array('default' => 'default');
|
||||
$options['bypass_access'] = array('default' => FALSE);
|
||||
|
||||
return $options;
|
||||
}
|
||||
@@ -134,6 +135,12 @@ class entity_views_handler_field_entity extends views_handler_field {
|
||||
'#value' => $options ? key($options) : 'default',
|
||||
);
|
||||
}
|
||||
$form['bypass_access'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Bypass access checks'),
|
||||
'#description' => t('If enabled, access permissions for rendering the entity are not checked.'),
|
||||
'#default_value' => !empty($this->options['bypass_access']),
|
||||
);
|
||||
}
|
||||
|
||||
public function render($values) {
|
||||
@@ -175,7 +182,8 @@ class entity_views_handler_field_entity extends views_handler_field {
|
||||
if (!is_object($entity) && isset($entity) && $entity !== FALSE) {
|
||||
$entity = entity_load_single($type, $entity);
|
||||
}
|
||||
if (!$entity) {
|
||||
// Make sure the entity exists and access is either given or bypassed.
|
||||
if (!$entity || !(!empty($this->options['bypass_access']) || entity_access('view', $type, $entity))) {
|
||||
return '';
|
||||
}
|
||||
|
||||
|
@@ -112,8 +112,9 @@ class entity_views_handler_field_options extends views_handler_field {
|
||||
if ($this->options['format_name'] && isset($this->option_list[$value])) {
|
||||
$value = $this->option_list[$value];
|
||||
}
|
||||
|
||||
return $this->sanitize_value($value);
|
||||
// Sanitization is handled by the wrapper, see
|
||||
// EntityFieldHandlerHelper::get_value().
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -93,7 +93,9 @@ class entity_views_handler_field_text extends views_handler_field {
|
||||
* Render a single field value.
|
||||
*/
|
||||
public function render_single_value($value, $values) {
|
||||
return $this->sanitize_value($value, 'xss');
|
||||
// Sanitization is handled by the wrapper, see
|
||||
// EntityFieldHandlerHelper::get_value().
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -93,7 +93,7 @@ class entity_views_handler_relationship_by_bundle extends views_handler_relation
|
||||
$def['extra'] = array(
|
||||
array(
|
||||
// The table and the IN operator are implicit.
|
||||
'field' => $entity_info['bundle keys']['bundle'],
|
||||
'field' => $entity_info['entity keys']['bundle'],
|
||||
'value' => $this->options['bundle_types'],
|
||||
),
|
||||
);
|
||||
|
Reference in New Issue
Block a user