diff --git a/sites/all/modules/contrib/dev/entity/README.txt b/sites/all/modules/contrib/dev/entity/README.txt index ed048e42..745dd7fe 100644 --- a/sites/all/modules/contrib/dev/entity/README.txt +++ b/sites/all/modules/contrib/dev/entity/README.txt @@ -11,7 +11,15 @@ entity CRUD controller, which helps simplifying the creation of new entity types This is an API module. You only need to enable it if a module depends on it or you are interested in using it for development. -This README is for interested developers. If you are not interested in +Advanced usage: +--------------- +You can optimize cache clearing performance by setting the variable +'entity_rebuild_on_flush' to FALSE. This skips rebuilding of feature +components and exported entities during cache flushing. Instead, it is triggered +by the features module only; e.g., when features are reverted. + + +The README below is for interested developers. If you are not interested in developing, you may stop reading now. -------------------------------------------------------------------------------- diff --git a/sites/all/modules/contrib/dev/entity/ctools/relationships/entity_property.inc b/sites/all/modules/contrib/dev/entity/ctools/relationships/entity_property.inc new file mode 100644 index 00000000..6869146f --- /dev/null +++ b/sites/all/modules/contrib/dev/entity/ctools/relationships/entity_property.inc @@ -0,0 +1,153 @@ + t('Entity property or field (via Entity Metadata Wrapper)'), + 'description' => t('Creates any kind of context for entity properties and fields.'), + 'context' => 'entity_entity_property_context', + 'required context' => new ctools_context_required(t('Entity'), 'entity'), + 'edit form' => 'entity_entity_property_edit_form', + 'edit form validate' => 'entity_entity_property_edit_form_validate', + 'defaults' => array( + 'selector' => '', + 'target_context' => 'entity', + 'concatenator' => ',' + ), +); + +/** + * Return a new context based on an existing context. + */ +function entity_entity_property_context($context, $conf) { + $plugin = $conf['name']; + + // If unset it wants a generic, unfilled context, which is just NULL. + if (empty($context->data)) { + return ctools_context_create_empty(isset($conf['target_context']) ? $conf['target_context'] : 'entity', NULL); + } + + list($part1, $entity_type) = explode(':', $context->plugin); + + if (isset($context->data) && $entity = $context->data) { + // Apply the selector. + $wrapper = entity_metadata_wrapper($entity_type, $entity); + $parts = explode(':', $conf['selector']); + + try { + foreach ($parts as $part) { + if (!($wrapper instanceof EntityStructureWrapper || $wrapper instanceof EntityListWrapper)) { + $wrapper = NULL; + $value = NULL; + continue; + } + $wrapper = $wrapper->get($part); + } + } + catch (EntityMetadataWrapperException $e) { + $wrapper = NULL; + $value = NULL; + } + + if (isset($wrapper)) { + $value = $wrapper->value(); + } + + // Massage list values. + if ($wrapper instanceof EntityListWrapper) { + $value = $wrapper[0]->value(); + $argument = implode($conf['concatenator'], $wrapper->value(array('identifier' => TRUE))); + } + elseif ($wrapper instanceof EntityDrupalWrapper) { + $argument = $wrapper->getIdentifier(); + } + + // Bail out if we were unable to retrieve the value. + if (!isset($value)) { + return ctools_context_create_empty(isset($conf['target_context']) ? $conf['target_context'] : 'entity', NULL); + } + + $context = ctools_context_create($conf['target_context'], $value); + // Provide a suiting argument if context is used as argument. + if (isset($argument)) { + $context->argument = $argument; + } + return $context; + } +} + +function entity_entity_property_edit_form($form, &$form_state) { + $conf = $form_state['conf']; + + $form['selector'] = array( + '#type' => 'textfield', + '#title' => t('Data selector'), + '#description' => t('Any valid data selector, e.g. "title" to select a node\'s title, or "field_tags:1" to select the second tag.'), + '#default_value' => $conf['selector'], + '#required' => TRUE, + ); + $form['concatenator'] = array( + '#title' => t('Concatenator (if multiple)'), + '#type' => 'select', + '#options' => array(',' => ', (AND)', '+' => '+ (OR)'), + '#default_value' => $conf['concatenator'], + '#prefix' => '
', + '#suffix' => '
', + '#description' => t("When the resulting value is multiple valued and the context is passed on to a view as argument, the value can be concatenated in the form of 1+2+3 (for OR) or 1,2,3 (for AND)."), + ); + return $form; +} + +function entity_entity_property_edit_form_validate($form, &$form_state) { + $context_key = $form_state['values']['context']; + $context = $form_state['contexts'][$context_key]; + $entity_type = $context->type[2]; + + try { + $all_properties = entity_get_all_property_info($entity_type); + $wrapper = entity_metadata_wrapper($entity_type, NULL, array('property info' => $all_properties)); + $parts = explode(':', $form_state['values']['selector']); + foreach ($parts as $part) { + if (!($wrapper instanceof EntityStructureWrapper || $wrapper instanceof EntityListWrapper)) { + form_set_error('selector', t('Unable to apply the data selector part %key.'. array('%key' => $part))); + continue; + } + $wrapper = $wrapper->get($part); + } + $type = entity_entity_property_map_data_type($wrapper->type()); + $form_state['conf']['target_context'] = $type; + } + catch (EntityMetadataWrapperException $e) { + form_set_error('selector', t('Unable to apply the data selector on entity type %type. @reason', array('@reason' => $e->getMessage(), '%type' => $entity_type))); + } + + // Auto-generate a sane identifier. + if ($form_state['values']['identifier'] == $form['identifier']['#default_value']) { + $form_state['values']['identifier'] = 'Entity property ' . $entity_type . ':' . check_plain($form_state['values']['selector']); + } +} + +/** + * Maps an entity-property data type to ctools types. + */ +function entity_entity_property_map_data_type($type) { + // Remove list<> wrappers from types. + while ($item_type = entity_property_list_extract_type($type)) { + $type = $item_type; + } + // Massage data type of entites to c + if (entity_get_info($type)) { + $type = "entity:$type"; + } + if ($type == 'text') { + $type = 'string'; + } + return $type; +} diff --git a/sites/all/modules/contrib/dev/entity/entity.features.inc b/sites/all/modules/contrib/dev/entity/entity.features.inc index e266aaf5..0ec3e618 100644 --- a/sites/all/modules/contrib/dev/entity/entity.features.inc +++ b/sites/all/modules/contrib/dev/entity/entity.features.inc @@ -7,6 +7,12 @@ /** * Returns the configured entity features controller. + * + * @param string $type + * The entity type to get the controller for. + * + * @return EntityDefaultFeaturesController + * The configured entity features controller. */ function entity_features_get_controller($type) { $static = &drupal_static(__FUNCTION__); @@ -85,6 +91,7 @@ class EntityDefaultFeaturesController { $fields = field_info_instances($this->info['bundle of'], $entity->{$this->bundleKey}); foreach ($fields as $name => $field) { $pipe['field'][] = "{$field['entity_type']}-{$field['bundle']}-{$field['field_name']}"; + $pipe['field_instance'][] = "{$field['entity_type']}-{$field['bundle']}-{$field['field_name']}"; } } } @@ -125,9 +132,7 @@ class EntityDefaultFeaturesController { */ function revert($module = NULL) { if ($defaults = features_get_default($this->type, $module)) { - foreach ($defaults as $name => $entity) { - entity_delete($this->type, $name); - } + entity_delete_multiple($this->type, array_keys($defaults)); } } } @@ -146,6 +151,8 @@ function entity_features_api() { } /** + * Implements hook_features_export_options(). + * * Features component callback. */ function entity_features_export_options($a1, $a2 = NULL) { @@ -157,6 +164,8 @@ function entity_features_export_options($a1, $a2 = NULL) { } /** + * Implements hook_features_export(). + * * Features component callback. */ function entity_features_export($data, &$export, $module_name = '', $entity_type) { @@ -164,6 +173,8 @@ function entity_features_export($data, &$export, $module_name = '', $entity_type } /** + * Implements hook_features_export_render(). + * * Features component callback. */ function entity_features_export_render($module, $data, $export = NULL, $entity_type) { @@ -171,8 +182,23 @@ function entity_features_export_render($module, $data, $export = NULL, $entity_t } /** + * Implements hook_features_revert(). + * * Features component callback. */ function entity_features_revert($module = NULL, $entity_type) { return entity_features_get_controller($entity_type)->revert($module); } + +/** + * Implements hook_features_post_restore(). + * + * Rebuild all defaults when a features rebuild is triggered - even the ones not + * handled by features itself. + */ +function entity_features_post_restore($op, $items = array()) { + if ($op == 'rebuild') { + // Use features rebuild to rebuild the features independent exports too. + entity_defaults_rebuild(); + } +} diff --git a/sites/all/modules/contrib/dev/entity/entity.info b/sites/all/modules/contrib/dev/entity/entity.info index ff88ce54..787db138 100644 --- a/sites/all/modules/contrib/dev/entity/entity.info +++ b/sites/all/modules/contrib/dev/entity/entity.info @@ -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 2015-02-25 -version = "7.x-1.6" +; Information added by Drupal.org packaging script on 2016-09-22 +version = "7.x-1.8" core = "7.x" project = "entity" -datestamp = "1424876582" +datestamp = "1474546503" diff --git a/sites/all/modules/contrib/dev/entity/entity.install b/sites/all/modules/contrib/dev/entity/entity.install index f6f8cc2f..118820b8 100644 --- a/sites/all/modules/contrib/dev/entity/entity.install +++ b/sites/all/modules/contrib/dev/entity/entity.install @@ -13,6 +13,14 @@ function entity_enable() { entity_entitycache_installed_modules(); } +/** + * Implements hook_uninstall(). + */ +function entity_uninstall() { + // Delete variables. + variable_del('entity_rebuild_on_flush'); +} + /** * The entity API modules have been merged into a single module. */ diff --git a/sites/all/modules/contrib/dev/entity/entity.module b/sites/all/modules/contrib/dev/entity/entity.module index d4a882cd..d00afa46 100644 --- a/sites/all/modules/contrib/dev/entity/entity.module +++ b/sites/all/modules/contrib/dev/entity/entity.module @@ -184,8 +184,17 @@ function entity_ui_entity_page_view($entity) { * 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); + if (isset($entity)) { + module_load_include('inc', 'entity', 'includes/entity.ui'); + $label = entity_label($entity_type, $entity); + list(, , $bundle) = entity_extract_ids($entity_type, $entity); + } + else { + $info = entity_get_info($entity_type); + $label = $info['label']; + $bundle = NULL; + } + switch ($op) { case 'view': return $label; @@ -200,12 +209,7 @@ function entity_ui_get_page_title($op, $entity_type, $entity = NULL) { 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); } @@ -600,7 +604,7 @@ function entity_id($entity_type, $entity) { * content language of the current request. * @param $page * (optional) If set will control if the entity is rendered: if TRUE - * the entity will be rendered without its title, so that it can be embeded + * the entity will be rendered without its title, so that it can be embedded * in another context. If FALSE the entity will be displayed with its title * in a mode suitable for lists. * If unset, the page mode will be enabled if the current path is the URI @@ -1076,7 +1080,8 @@ function entity_flush_caches() { // case of enabling or disabling modules we already rebuild defaults in // entity_modules_enabled() and entity_modules_disabled(), so we do not need // to do it again. - if (current_path() != 'admin/modules/list/confirm') { + // Also check if rebuilding on cache flush is explicitly disabled. + if (current_path() != 'admin/modules/list/confirm' && variable_get('entity_rebuild_on_flush', TRUE)) { entity_defaults_rebuild(); } @@ -1372,7 +1377,7 @@ function entity_get_extra_fields_controller($type = NULL) { * Returns a property wrapper for the given data. * * If an entity is wrapped, the wrapper can be used to retrieve further wrappers - * for the entitity properties. For that the wrapper support chaining, e.g. you + * for the entity properties. For that the wrapper support chaining, e.g. you * can use a node wrapper to get the node authors mail address: * * @code @@ -1563,7 +1568,7 @@ function _entity_info_add_metadata(&$entity_info) { * Implements hook_ctools_plugin_directory(). */ function entity_ctools_plugin_directory($module, $plugin) { - if ($module == 'ctools' && $plugin == 'content_types') { - return 'ctools/content_types'; + if ($module == 'ctools') { + return "ctools/$plugin"; } } diff --git a/sites/all/modules/contrib/dev/entity/entity.test b/sites/all/modules/contrib/dev/entity/entity.test index 03c2551a..fd8cea12 100644 --- a/sites/all/modules/contrib/dev/entity/entity.test +++ b/sites/all/modules/contrib/dev/entity/entity.test @@ -1342,6 +1342,74 @@ class EntityMetadataNodeRevisionAccessTestCase extends DrupalWebTestCase { } } +/** + * Tests basic entity_access() functionality for taxonomy terms. + */ +class EntityMetadataTaxonomyAccessTestCase extends EntityWebTestCase { + public static function getInfo() { + return array( + 'name' => 'Entity Metadata Taxonomy Access', + 'description' => 'Test entity_access() for taxonomy terms', + 'group' => 'Entity API', + ); + } + + /** + * Asserts entity_access() correctly grants or denies access. + */ + function assertTaxonomyMetadataAccess($ops, $term, $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, 'taxonomy_term', $term, $account); + $this->assertEqual($result, $access, $msg); + } + } + + /** + * @inheritdoc + */ + function setUp() { + parent::setUp('entity', 'taxonomy'); + // Clear permissions for authenticated users. + db_delete('role_permission') + ->condition('rid', DRUPAL_AUTHENTICATED_RID) + ->execute(); + } + + /** + * Runs basic tests for entity_access() function. + */ + function testTaxonomyMetadataAccess() { + $vocab = $this->createVocabulary(); + $term = entity_property_values_create_entity('taxonomy_term', array( + 'name' => $this->randomName(), + 'vocabulary' => $vocab, + ))->save()->value(); + // Clear permissions static cache to get new taxonomy permissions. + drupal_static_reset('checkPermissions'); + + // Check assignment of view permissions. + $user1 = $this->drupalCreateUser(array('access content')); + $this->assertTaxonomyMetadataAccess(array('create' => FALSE, 'view' => TRUE, 'update' => FALSE, 'delete' => FALSE), $term, $user1); + + // Check assignment of edit permissions. + $user2 = $this->drupalCreateUser(array('edit terms in ' . $vocab->vid)); + $this->assertTaxonomyMetadataAccess(array('create' => FALSE, 'view' => FALSE, 'update' => TRUE, 'delete' => FALSE), $term, $user2); + + // Check assignment of delete permissions. + $user3 = $this->drupalCreateUser(array('delete terms in ' . $vocab->vid)); + $this->assertTaxonomyMetadataAccess(array('create' => FALSE, 'view' => FALSE, 'update' => FALSE, 'delete' => TRUE), $term, $user3); + + // Check assignment of view, edit, delete permissions. + $user4 = $this->drupalCreateUser(array('access content', 'edit terms in ' . $vocab->vid, 'delete terms in ' . $vocab->vid)); + $this->assertTaxonomyMetadataAccess(array('create' => FALSE, 'view' => TRUE, 'update' => TRUE, 'delete' => TRUE), $term, $user4); + + // Check assignment of administration permissions. + $user5 = $this->drupalCreateUser(array('administer taxonomy')); + $this->assertTaxonomyMetadataAccess(array('create' => TRUE, 'view' => TRUE, 'update' => TRUE, 'delete' => TRUE), $term, $user5); + } +} + /** * Tests provided entity property info of the core modules. */ @@ -1466,6 +1534,7 @@ class EntityMetadataIntegrationTestCase extends EntityWebTestCase { $book = array('bid' => $node->nid, 'plid' => $node->book['mlid']); $node2 = $this->drupalCreateNode(array('type' => 'book', 'book' => $book)); $node3 = $this->drupalCreateNode(array('type' => 'page')); + $node4 = $this->drupalCreateNode(array('type' => 'book', 'book' => array('bid' => 0, 'plid' => -1))); // Test whether the properties work. $wrapper = entity_metadata_wrapper('node', $node2); @@ -1477,6 +1546,10 @@ class EntityMetadataIntegrationTestCase extends EntityWebTestCase { $wrapper = entity_metadata_wrapper('node', $node3); $this->assertEmpty($wrapper, 'book'); $this->assertEmptyArray($wrapper, 'book_ancestors'); + + // Test a book node which is not contained in a hierarchy. + $wrapper = entity_metadata_wrapper('node', $node4); + $this->assertEmptyArray($wrapper, 'book_ancestors'); } /** diff --git a/sites/all/modules/contrib/dev/entity/entity_token.info b/sites/all/modules/contrib/dev/entity/entity_token.info index b579ced1..cc732945 100644 --- a/sites/all/modules/contrib/dev/entity/entity_token.info +++ b/sites/all/modules/contrib/dev/entity/entity_token.info @@ -5,9 +5,9 @@ files[] = entity_token.tokens.inc files[] = entity_token.module dependencies[] = entity -; Information added by Drupal.org packaging script on 2015-02-25 -version = "7.x-1.6" +; Information added by Drupal.org packaging script on 2016-09-22 +version = "7.x-1.8" core = "7.x" project = "entity" -datestamp = "1424876582" +datestamp = "1474546503" diff --git a/sites/all/modules/contrib/dev/entity/includes/entity.controller.inc b/sites/all/modules/contrib/dev/entity/includes/entity.controller.inc index f675a63a..5e86b529 100644 --- a/sites/all/modules/contrib/dev/entity/includes/entity.controller.inc +++ b/sites/all/modules/contrib/dev/entity/includes/entity.controller.inc @@ -107,7 +107,7 @@ interface EntityAPIControllerInterface extends DrupalEntityControllerInterface { * content language of the current request. * @param $page * (optional) If set will control if the entity is rendered: if TRUE - * the entity will be rendered without its title, so that it can be embeded + * the entity will be rendered without its title, so that it can be embedded * in another context. If FALSE the entity will be displayed with its title * in a mode suitable for lists. * If unset, the page mode will be enabled if the current path is the URI diff --git a/sites/all/modules/contrib/dev/entity/includes/entity.inc b/sites/all/modules/contrib/dev/entity/includes/entity.inc index be24499d..2f504f36 100644 --- a/sites/all/modules/contrib/dev/entity/includes/entity.inc +++ b/sites/all/modules/contrib/dev/entity/includes/entity.inc @@ -5,6 +5,168 @@ * Provides a base class for entities. */ +/** + * Interface for class based entities. + */ +interface EntityInterface { + + /** + * Returns the internal, numeric identifier. + * + * Returns the numeric identifier, even if the entity type has specified a + * name key. In the latter case, the numeric identifier is supposed to be used + * when dealing generically with entities or internally to refer to an entity, + * i.e. in a relational database. If unsure, use Entity:identifier(). + */ + public function internalIdentifier(); + + /** + * Returns the entity identifier, i.e. the entities name or numeric id. + * + * @return + * The identifier of the entity. If the entity type makes use of a name key, + * the name is returned, else the numeric id. + * + * @see entity_id() + */ + public function identifier(); + + /** + * Returns the info of the type of the entity. + * + * @see entity_get_info() + */ + public function entityInfo(); + + /** + * Returns the type of the entity. + */ + public function entityType(); + + /** + * Returns the bundle of the entity. + * + * @return + * The bundle of the entity. Defaults to the entity type if the entity type + * does not make use of different bundles. + */ + public function bundle(); + + /** + * Returns the EntityMetadataWrapper of the entity. + * + * @return EntityDrupalWrapper + * An EntityMetadataWrapper containing the entity. + */ + public function wrapper(); + + /** + * Returns the label of the entity. + * + * Modules may alter the label by specifying another 'label callback' using + * hook_entity_info_alter(). + * + * @see entity_label() + */ + public function label(); + + /** + * Returns the uri of the entity just as entity_uri(). + * + * Modules may alter the uri by specifying another 'uri callback' using + * hook_entity_info_alter(). + * + * @see entity_uri() + */ + public function uri(); + + /** + * Checks if the entity has a certain exportable status. + * + * @param $status + * A status constant, i.e. one of ENTITY_CUSTOM, ENTITY_IN_CODE, + * ENTITY_OVERRIDDEN or ENTITY_FIXED. + * + * @return bool + * For exportable entities TRUE if the entity has the status, else FALSE. + * In case the entity is not exportable, NULL is returned. + * + * @see entity_has_status() + */ + public function hasStatus($status); + + /** + * Permanently saves the entity. + * + * @see entity_save() + */ + public function save(); + + /** + * Permanently deletes the entity. + * + * @see entity_delete() + */ + public function delete(); + + /** + * Exports the entity. + * + * @see entity_export() + */ + public function export($prefix = ''); + + /** + * Generate an array for rendering the entity. + * + * @see entity_view() + */ + public function view($view_mode = 'full', $langcode = NULL, $page = NULL); + + /** + * Builds a structured array representing the entity's content. + * + * @see entity_build_content() + */ + public function buildContent($view_mode = 'full', $langcode = NULL); + + /** + * Gets the raw, translated value of a property or field. + * + * Supports retrieving field translations as well as i18n string translations. + * + * Note that this returns raw data values, which might not reflect what + * has been declared for hook_entity_property_info() as no 'getter callbacks' + * are invoked or no referenced entities are loaded. For retrieving values + * reflecting the property info make use of entity metadata wrappers, see + * entity_metadata_wrapper(). + * + * @param $property + * The name of the property to return; e.g., 'title'. + * @param $langcode + * (optional) The language code of the language to which the value should + * be translated. If set to NULL, the default display language is being + * used. + * + * @return + * The raw, translated property value; or the raw, un-translated value if no + * translation is available. + * + * @todo Implement an analogous setTranslation() method for updating. + */ + public function getTranslation($property, $langcode = NULL); + + /** + * Checks whether the entity is the default revision. + * + * @return Boolean + * + * @see entity_revision_is_default() + */ + public function isDefaultRevision(); + +} + /** * A common class for entities. * @@ -25,7 +187,7 @@ * public $count = 0; * @endcode */ -class Entity { +class Entity implements EntityInterface { protected $entityType; protected $entityInfo; @@ -34,9 +196,7 @@ class Entity { protected $wrapper; /** - * Creates a new entity. - * - * @see entity_create() + * {@inheritdoc} */ public function __construct(array $values = array(), $entityType = NULL) { if (empty($entityType)) { @@ -61,62 +221,42 @@ class Entity { } /** - * Returns the internal, numeric identifier. - * - * Returns the numeric identifier, even if the entity type has specified a - * name key. In the latter case, the numeric identifier is supposed to be used - * when dealing generically with entities or internally to refer to an entity, - * i.e. in a relational database. If unsure, use Entity:identifier(). + * {@inheritdoc} */ public function internalIdentifier() { return isset($this->{$this->idKey}) ? $this->{$this->idKey} : NULL; } /** - * Returns the entity identifier, i.e. the entities name or numeric id. - * - * @return - * The identifier of the entity. If the entity type makes use of a name key, - * the name is returned, else the numeric id. - * - * @see entity_id() + * {@inheritdoc} */ public function identifier() { return isset($this->{$this->nameKey}) ? $this->{$this->nameKey} : NULL; } /** - * Returns the info of the type of the entity. - * - * @see entity_get_info() + * {@inheritdoc} */ public function entityInfo() { return $this->entityInfo; } /** - * Returns the type of the entity. + * {@inheritdoc} */ public function entityType() { return $this->entityType; } /** - * Returns the bundle of the entity. - * - * @return - * The bundle of the entity. Defaults to the entity type if the entity type - * does not make use of different bundles. + * {@inheritdoc} */ public function bundle() { 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. + * {@inheritdoc} */ public function wrapper() { if (empty($this->wrapper)) { @@ -130,12 +270,7 @@ class Entity { } /** - * Returns the label of the entity. - * - * Modules may alter the label by specifying another 'label callback' using - * hook_entity_info_alter(). - * - * @see entity_label() + * {@inheritdoc} */ public function label() { // If the default label flag is enabled, this is being invoked recursively. @@ -165,12 +300,7 @@ class Entity { } /** - * Returns the uri of the entity just as entity_uri(). - * - * Modules may alter the uri by specifying another 'uri callback' using - * hook_entity_info_alter(). - * - * @see entity_uri() + * {@inheritdoc} */ public function uri() { if (isset($this->entityInfo['uri callback']) && $this->entityInfo['uri callback'] == 'entity_class_uri') { @@ -188,17 +318,7 @@ class Entity { } /** - * Checks if the entity has a certain exportable status. - * - * @param $status - * A status constant, i.e. one of ENTITY_CUSTOM, ENTITY_IN_CODE, - * ENTITY_OVERRIDDEN or ENTITY_FIXED. - * - * @return - * For exportable entities TRUE if the entity has the status, else FALSE. - * In case the entity is not exportable, NULL is returned. - * - * @see entity_has_status() + * {@inheritdoc} */ public function hasStatus($status) { if (!empty($this->entityInfo['exportable'])) { @@ -207,18 +327,14 @@ class Entity { } /** - * Permanently saves the entity. - * - * @see entity_save() + * {@inheritdoc} */ public function save() { return entity_get_controller($this->entityType)->save($this); } /** - * Permanently deletes the entity. - * - * @see entity_delete() + * {@inheritdoc} */ public function delete() { $id = $this->identifier(); @@ -228,55 +344,28 @@ class Entity { } /** - * Exports the entity. - * - * @see entity_export() + * {@inheritdoc} */ public function export($prefix = '') { return entity_get_controller($this->entityType)->export($this, $prefix); } /** - * Generate an array for rendering the entity. - * - * @see entity_view() + * {@inheritdoc} */ public function view($view_mode = 'full', $langcode = NULL, $page = NULL) { return entity_get_controller($this->entityType)->view(array($this), $view_mode, $langcode, $page); } /** - * Builds a structured array representing the entity's content. - * - * @see entity_build_content() + * {@inheritdoc} */ public function buildContent($view_mode = 'full', $langcode = NULL) { return entity_get_controller($this->entityType)->buildContent($this, $view_mode, $langcode); } /** - * Gets the raw, translated value of a property or field. - * - * Supports retrieving field translations as well as i18n string translations. - * - * Note that this returns raw data values, which might not reflect what - * has been declared for hook_entity_property_info() as no 'getter callbacks' - * are invoked or no referenced entities are loaded. For retrieving values - * reflecting the property info make use of entity metadata wrappers, see - * entity_metadata_wrapper(). - * - * @param $property_name - * The name of the property to return; e.g., 'title'. - * @param $langcode - * (optional) The language code of the language to which the value should - * be translated. If set to NULL, the default display language is being - * used. - * - * @return - * The raw, translated property value; or the raw, un-translated value if no - * translation is available. - * - * @todo Implement an analogous setTranslation() method for updating. + * {@inheritdoc} */ public function getTranslation($property, $langcode = NULL) { $all_info = entity_get_all_property_info($this->entityType); @@ -296,11 +385,7 @@ class Entity { } /** - * Checks whether the entity is the default revision. - * - * @return Boolean - * - * @see entity_revision_is_default() + * {@inheritdoc} */ public function isDefaultRevision() { if (!empty($this->entityInfo['entity keys']['revision'])) { diff --git a/sites/all/modules/contrib/dev/entity/includes/entity.property.inc b/sites/all/modules/contrib/dev/entity/includes/entity.property.inc index 38e4fd7b..e8714e67 100644 --- a/sites/all/modules/contrib/dev/entity/includes/entity.property.inc +++ b/sites/all/modules/contrib/dev/entity/includes/entity.property.inc @@ -69,7 +69,7 @@ function entity_property_info_defaults() { * (optiona) The entity type to return properties for. * * @return - * An array of info about properties. If the type is ommitted, all known + * An array of info about properties. If the type is omitted, all known * properties are returned. */ function entity_get_all_property_info($entity_type = NULL) { diff --git a/sites/all/modules/contrib/dev/entity/includes/entity.ui.inc b/sites/all/modules/contrib/dev/entity/includes/entity.ui.inc index 1826da40..24e3c2b9 100644 --- a/sites/all/modules/contrib/dev/entity/includes/entity.ui.inc +++ b/sites/all/modules/contrib/dev/entity/includes/entity.ui.inc @@ -127,8 +127,8 @@ class EntityDefaultUIController { * Use per bundle form ids if possible, such that easy per bundle alterations * are supported too. * - * Note that for performance reasons, this method is only invoked for forms, - * which receive the entity_type as first argument. Thus any forms added, must + * Note that for performance reasons, this method is invoked only for forms + * which receive the entity_type as first argument. Thus any forms added must * follow that pattern. * * @see entity_forms() @@ -645,7 +645,7 @@ function entity_ui_operation_form($form, &$form_state, $entity_type, $entity, $o */ function entity_ui_main_form_defaults($form, &$form_state, $entity = NULL, $op = NULL) { // Now equals entity_ui_form_defaults() but is still here to keep backward - // compatability. + // compatibility. return entity_ui_form_defaults($form, $form_state, $form_state['entity_type'], $entity, $op); } @@ -760,7 +760,7 @@ function entity_ui_validate_machine_name($element, &$form_state) { function theme_entity_ui_overview_item($variables) { $output = $variables['url'] ? l($variables['label'], $variables['url']['path'], $variables['url']['options']) : check_plain($variables['label']); if ($variables['name']) { - $output .= ' (' . t('Machine name') . ': ' . check_plain($variables['name']) . ')'; + $output .= ' (' . t('Machine name') . ': ' . check_plain($variables['name']) . ')'; } return $output; } diff --git a/sites/all/modules/contrib/dev/entity/includes/entity.wrapper.inc b/sites/all/modules/contrib/dev/entity/includes/entity.wrapper.inc index 06b89adf..6c262e69 100644 --- a/sites/all/modules/contrib/dev/entity/includes/entity.wrapper.inc +++ b/sites/all/modules/contrib/dev/entity/includes/entity.wrapper.inc @@ -119,7 +119,11 @@ abstract class EntityMetadataWrapper { */ public function set($value) { if (!$this->validate($value)) { - throw new EntityMetadataWrapperException('Invalid data value given. Be sure it matches the required data type and format.'); + throw new EntityMetadataWrapperException(t('Invalid data value given. Be sure it matches the required data type and format. Value at !location: !value.', array( + // An exception's message is output through check_plain(). + '!value' => is_array($value) || is_object($value) ? var_export($value) : $value, + '!location' => $this->debugIdentifierLocation(), + ))); } $this->clear(); $this->data = $value; @@ -231,6 +235,21 @@ abstract class EntityMetadataWrapper { return !empty($this->info['parent']) ? $this->info['parent']->propertyAccess($this->info['name'], $op, $account) : TRUE; } + /** + * Returns a string to use to identify this wrapper in error messages. + * + * @return + * A string that identifies this wrapper and its chain of ancestors, of the + * form 'grandparentidentifier->parentidentifier->identifier'. + */ + public function debugIdentifierLocation() { + $debug = $this->info['name']; + if (isset($this->info['parent'])) { + $debug = $this->info['parent']->debugIdentifierLocation() . '->' . $debug; + } + return $debug; + } + /** * Prepare for serializiation. */ @@ -734,7 +753,11 @@ class EntityDrupalWrapper extends EntityStructureWrapper { */ public function set($value) { if (!$this->validate($value)) { - throw new EntityMetadataWrapperException('Invalid data value given. Be sure it matches the required data type and format.'); + throw new EntityMetadataWrapperException(t('Invalid data value given. Be sure it matches the required data type and format. Value at !location: !value.', array( + // An exception's message is output through check_plain(). + '!value' => is_array($value) || is_object($value) ? var_export($value) : $value, + '!location' => $this->debugIdentifierLocation(), + ))); } if ($this->info['type'] == 'entity' && $value === $this) { // Nothing to do. @@ -821,7 +844,12 @@ class EntityDrupalWrapper extends EntityStructureWrapper { } else { // This is not a property, so fallback on entity access. - return $this->entityAccess($op == 'edit' ? 'update' : 'view', $account); + if ($op == 'edit') { + // If the operation is "edit" determine if its actually a "create" for + // new un-saved entities, or an "update" for existing ones. + return $this->entityAccess($this->getIdentifier() ? 'update' : 'create', $account); + } + return $this->entityAccess('view', $account); } } @@ -909,6 +937,27 @@ class EntityDrupalWrapper extends EntityStructureWrapper { } } + /** + * Returns a string to use to identify this wrapper in error messages. + */ + public function debugIdentifierLocation() { + // An entity wrapper can be at the top of the chain or a part of it. + if (isset($this->info['name'])) { + // This wrapper is part of a chain, eg in the position node->author. + // Return the name. + $debug = $this->info['name']; + } + else { + // This is a wrapper for an actual entity: return its type and id. + $debug = $this->info['type'] . '(' . $this->getIdentifier() . ')'; + } + + if (isset($this->info['parent'])) { + $debug = $this->info['parent']->debugIdentifierLocation() . '->' . $debug; + } + return $debug; + } + /** * Prepare for serializiation. */ diff --git a/sites/all/modules/contrib/dev/entity/modules/callbacks.inc b/sites/all/modules/contrib/dev/entity/modules/callbacks.inc index 26f802e6..0c5c8eef 100644 --- a/sites/all/modules/contrib/dev/entity/modules/callbacks.inc +++ b/sites/all/modules/contrib/dev/entity/modules/callbacks.inc @@ -29,7 +29,7 @@ function entity_metadata_book_get_properties($node, array $options, $name, $enti case 'book_ancestors': $ancestors = array(); - while (!empty($node->book['plid'])) { + while (!empty($node->book['plid']) && $node->book['plid'] != -1) { $link = book_link_load($node->book['plid']); array_unshift($ancestors, $link['nid']); $node = node_load($link['nid']); @@ -670,9 +670,11 @@ function entity_metadata_field_file_validate_item($items, $context) { 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 (empty($node->vid) && in_array($op, array('create', 'update'))) { + // This is a new node or the original node. if (isset($node->type)) { - return node_access($op, $node->type, $account); + $op = !empty($node->is_new) && $node->is_new ? 'create' : 'update'; + return node_access($op, $op == 'create' ? $node->type : $node, $account); } else { throw new EntityMalformedException('Permission to create a node was requested but no node type was given.'); @@ -796,14 +798,35 @@ function entity_metadata_comment_properties_access($op, $property, $entity = NUL * Access callback for the taxonomy entities. */ function entity_metadata_taxonomy_access($op, $entity = NULL, $account = NULL, $entity_type = NULL) { - if ($entity_type == 'taxonomy_vocabulary') { - return user_access('administer taxonomy', $account); - } - if (isset($entity) && $op == 'update' && !isset($account) && taxonomy_term_edit_access($entity)) { + // If user has administer taxonomy permission then no further checks. + if (user_access('administer taxonomy', $account)) { return TRUE; } - if (user_access('administer taxonomy', $account) || user_access('access content', $account) && $op == 'view') { - return TRUE; + switch ($op) { + case "view": + if (user_access('access content', $account)) { + return TRUE; + } + break; + case "update": + if ($entity_type == 'taxonomy_term') { + return user_access("edit terms in $entity->vid", $account); + } + break; + case "create": + if ($entity_type == 'taxonomy_term') { + // Check for taxonomy_access_fix contrib module which adds additional + // permissions to create new terms in a given vocabulary. + if (function_exists('taxonomy_access_fix_access')) { + return taxonomy_access_fix_access('add terms', $entity->vocabulary_machine_name); + } + } + break; + case "delete": + if ($entity_type == 'taxonomy_term') { + return user_access("delete terms in $entity->vid", $account); + } + break; } return FALSE; } diff --git a/sites/all/modules/contrib/dev/entity/modules/node.info.inc b/sites/all/modules/contrib/dev/entity/modules/node.info.inc index 3512d9a0..f146a7e8 100644 --- a/sites/all/modules/contrib/dev/entity/modules/node.info.inc +++ b/sites/all/modules/contrib/dev/entity/modules/node.info.inc @@ -163,4 +163,10 @@ function entity_metadata_node_entity_property_info_alter(&$info) { 'auto creation' => 'entity_property_create_array', 'field' => TRUE, ); + + // Make it a list if cardinality is not 1. + $field_body = field_info_field('body'); + if (isset($field_body) && $field_body['cardinality'] != 1) { + $info['node']['properties']['body']['type'] = 'list'; + } } diff --git a/sites/all/modules/contrib/dev/entity/tests/entity_feature.info b/sites/all/modules/contrib/dev/entity/tests/entity_feature.info index 80d2a908..3e398961 100644 --- a/sites/all/modules/contrib/dev/entity/tests/entity_feature.info +++ b/sites/all/modules/contrib/dev/entity/tests/entity_feature.info @@ -6,9 +6,9 @@ files[] = entity_feature.module dependencies[] = entity_test hidden = TRUE -; Information added by Drupal.org packaging script on 2015-02-25 -version = "7.x-1.6" +; Information added by Drupal.org packaging script on 2016-09-22 +version = "7.x-1.8" core = "7.x" project = "entity" -datestamp = "1424876582" +datestamp = "1474546503" diff --git a/sites/all/modules/contrib/dev/entity/tests/entity_test.info b/sites/all/modules/contrib/dev/entity/tests/entity_test.info index d34326c9..f1562ac6 100644 --- a/sites/all/modules/contrib/dev/entity/tests/entity_test.info +++ b/sites/all/modules/contrib/dev/entity/tests/entity_test.info @@ -7,9 +7,9 @@ files[] = entity_test.install dependencies[] = entity hidden = TRUE -; Information added by Drupal.org packaging script on 2015-02-25 -version = "7.x-1.6" +; Information added by Drupal.org packaging script on 2016-09-22 +version = "7.x-1.8" core = "7.x" project = "entity" -datestamp = "1424876582" +datestamp = "1474546503" diff --git a/sites/all/modules/contrib/dev/entity/tests/entity_test.module b/sites/all/modules/contrib/dev/entity/tests/entity_test.module index 55855688..727797ae 100644 --- a/sites/all/modules/contrib/dev/entity/tests/entity_test.module +++ b/sites/all/modules/contrib/dev/entity/tests/entity_test.module @@ -2,7 +2,7 @@ /** * @file - * Test moduel for the entity API. + * Test module for the entity API. */ /** diff --git a/sites/all/modules/contrib/dev/entity/tests/entity_test_i18n.info b/sites/all/modules/contrib/dev/entity/tests/entity_test_i18n.info index 8adf04af..db1eb56a 100644 --- a/sites/all/modules/contrib/dev/entity/tests/entity_test_i18n.info +++ b/sites/all/modules/contrib/dev/entity/tests/entity_test_i18n.info @@ -5,9 +5,9 @@ dependencies[] = i18n_string package = Multilingual - Internationalization core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2015-02-25 -version = "7.x-1.6" +; Information added by Drupal.org packaging script on 2016-09-22 +version = "7.x-1.8" core = "7.x" project = "entity" -datestamp = "1424876582" +datestamp = "1474546503" diff --git a/sites/all/modules/contrib/dev/entity/theme/entity.theme.inc b/sites/all/modules/contrib/dev/entity/theme/entity.theme.inc index 9238dfdb..fc0ba7c1 100644 --- a/sites/all/modules/contrib/dev/entity/theme/entity.theme.inc +++ b/sites/all/modules/contrib/dev/entity/theme/entity.theme.inc @@ -80,9 +80,12 @@ function template_preprocess_entity_property(&$variables, $hook) { ); // Populate the content with sensible defaults. - if (!isset($variables['content'])) { + if (!isset($element['#content'])) { $variables['content'] = entity_property_default_render_value_by_type($element['#entity_wrapped']->{$element['#property_name']}); } + else { + $variables['content'] = $element['#content']; + } } /** diff --git a/sites/all/modules/contrib/dev/entity/views/entity.views.inc b/sites/all/modules/contrib/dev/entity/views/entity.views.inc index 59ebaa48..a0179c0c 100644 --- a/sites/all/modules/contrib/dev/entity/views/entity.views.inc +++ b/sites/all/modules/contrib/dev/entity/views/entity.views.inc @@ -605,6 +605,28 @@ class EntityDefaultViewsController { ); break; + case 'duration': + $return += $description + array( + 'field' => array( + 'real field' => $views_field_name, + 'handler' => 'entity_views_handler_field_duration', + 'click sortable' => TRUE, + ), + 'sort' => array( + 'real field' => $views_field_name, + 'handler' => 'views_handler_sort', + ), + 'filter' => array( + 'real field' => $views_field_name, + 'handler' => 'views_handler_filter_numeric', + ), + 'argument' => array( + 'real field' => $views_field_name, + 'handler' => 'views_handler_argument_numeric', + ), + ); + break; + case 'uri': $return += $description + array( 'field' => array( diff --git a/sites/all/modules/contrib/dev/entity/views/handlers/entity_views_field_handler_helper.inc b/sites/all/modules/contrib/dev/entity/views/handlers/entity_views_field_handler_helper.inc index 0077f4a3..6bb4fbff 100644 --- a/sites/all/modules/contrib/dev/entity/views/handlers/entity_views_field_handler_helper.inc +++ b/sites/all/modules/contrib/dev/entity/views/handlers/entity_views_field_handler_helper.inc @@ -18,7 +18,7 @@ class EntityFieldHandlerHelper { * Provide appropriate default options for a handler. */ public static function option_definition($handler) { - if (entity_property_list_extract_type($handler->definition['type'])) { + if (isset($handler->definition['type']) && entity_property_list_extract_type($handler->definition['type'])) { $options['list']['contains']['mode'] = array('default' => 'collapse'); $options['list']['contains']['separator'] = array('default' => ', '); $options['list']['contains']['type'] = array('default' => 'ul'); @@ -32,7 +32,7 @@ class EntityFieldHandlerHelper { * Provide an appropriate default option form for a handler. */ public static function options_form($handler, &$form, &$form_state) { - if (entity_property_list_extract_type($handler->definition['type'])) { + if (isset($handler->definition['type']) && entity_property_list_extract_type($handler->definition['type'])) { $form['list']['mode'] = array( '#type' => 'select', '#title' => t('List handling'), diff --git a/sites/all/modules/contrib/dev/entity/views/plugins/entity_views_plugin_row_entity_view.inc b/sites/all/modules/contrib/dev/entity/views/plugins/entity_views_plugin_row_entity_view.inc index db72b5f5..5e738a8c 100644 --- a/sites/all/modules/contrib/dev/entity/views/plugins/entity_views_plugin_row_entity_view.inc +++ b/sites/all/modules/contrib/dev/entity/views/plugins/entity_views_plugin_row_entity_view.inc @@ -88,6 +88,9 @@ class entity_views_plugin_row_entity_view extends views_plugin_row { public function render($values) { if ($entity = $this->get_value($values)) { + // Add the view object as views_plugin_row_node_view::render() would. + // Otherwise the views theme suggestions won't work properly. + $entity->view = $this->view; $render = $this->rendered_content[entity_id($this->entity_type, $entity)]; return drupal_render($render); }