Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
project
drupal
Commits
691a5762
Commit
691a5762
authored
Sep 30, 2013
by
Alex Pott
Browse files
Issue
#1994140
by Berdir, yched, fgm, smiletrl: Unify entity field access and Field API access.
parent
ef02f36a
Changes
25
Hide whitespace changes
Inline
Side-by-side
core/lib/Drupal/Core/Entity/EntityAccessController.php
View file @
691a5762
...
...
@@ -7,7 +7,9 @@
namespace
Drupal\Core\Entity
;
use
Drupal\Core\Entity\Field\FieldItemListInterface
;
use
Drupal\Core\Extension\ModuleHandlerInterface
;
use
Drupal\Core\Entity\Field\FieldDefinitionInterface
;
use
Drupal\Core\Language\Language
;
use
Drupal\Core\Session\AccountInterface
;
...
...
@@ -268,4 +270,42 @@ public function setModuleHandler(ModuleHandlerInterface $module_handler) {
return
$this
;
}
/**
* {@inheritdoc}
*/
public
function
fieldAccess
(
$operation
,
FieldDefinitionInterface
$field_definition
,
AccountInterface
$account
=
NULL
,
FieldItemListInterface
$items
=
NULL
)
{
$account
=
$this
->
prepareUser
(
$account
);
// Get the default access restriction that lives within this field.
$default
=
$items
?
$items
->
defaultAccess
(
$operation
,
$account
)
:
TRUE
;
// Invoke hook and collect grants/denies for field access from other
// modules. Our default access flag is masked under the ':default' key.
$grants
=
array
(
':default'
=>
$default
);
$hook_implementations
=
$this
->
moduleHandler
->
getImplementations
(
'entity_field_access'
);
foreach
(
$hook_implementations
as
$module
)
{
$grants
=
array_merge
(
$grants
,
array
(
$module
=>
$this
->
moduleHandler
->
invoke
(
$module
,
'entity_field_access'
,
array
(
$operation
,
$field_definition
,
$account
,
$items
))));
}
// Also allow modules to alter the returned grants/denies.
$context
=
array
(
'operation'
=>
$operation
,
'field_definition'
=>
$field_definition
,
'items'
=>
$items
,
'account'
=>
$account
,
);
$this
->
moduleHandler
->
alter
(
'entity_field_access'
,
$grants
,
$context
);
// One grant being FALSE is enough to deny access immediately.
if
(
in_array
(
FALSE
,
$grants
,
TRUE
))
{
return
FALSE
;
}
// At least one grant has the explicit opinion to allow access.
if
(
in_array
(
TRUE
,
$grants
,
TRUE
))
{
return
TRUE
;
}
// All grants are NULL and have no opinion - deny access in that case.
return
FALSE
;
}
}
core/lib/Drupal/Core/Entity/EntityAccessControllerInterface.php
View file @
691a5762
...
...
@@ -7,7 +7,9 @@
namespace
Drupal\Core\Entity
;
use
Drupal\Core\Entity\Field\FieldItemListInterface
;
use
Drupal\Core\Extension\ModuleHandlerInterface
;
use
Drupal\Core\Entity\Field\FieldDefinitionInterface
;
use
Drupal\Core\Language\Language
;
use
Drupal\Core\Session\AccountInterface
;
...
...
@@ -70,4 +72,22 @@ public function resetCache();
*/
public
function
setModuleHandler
(
ModuleHandlerInterface
$module_handler
);
/**
* Checks access to an operation on a given entity field.
*
* @param string $operation
* The operation access should be checked for.
* Usually one of "view" or "edit".
* @param \Drupal\Core\Entity\Field\FieldDefinitionInterface $field_definition
* The field definition.
* @param \Drupal\Core\Session\AccountInterface $account
* (optional) The user session for which to check access, or NULL to check
* access for the current user. Defaults to NULL.
* @param \Drupal\Core\Entity\Field\FieldItemListInterface $items
* (optional) The field values for which to check access, or NULL if access
* is checked for the field definition, without any specific value
* available. Defaults to NULL.
*/
public
function
fieldAccess
(
$operation
,
FieldDefinitionInterface
$field_definition
,
AccountInterface
$account
=
NULL
,
FieldItemListInterface
$items
=
NULL
);
}
core/lib/Drupal/Core/Entity/Field/FieldDefinition.php
0 → 100644
View file @
691a5762
<?php
/**
* @file
* Contains \Drupal\Core\Entity\Field\FieldDefinition.
*/
namespace
Drupal\Core\Entity\Field
;
use
Drupal\Core\Entity\EntityInterface
;
/**
* A class for defining entity fields.
*/
class
FieldDefinition
implements
FieldDefinitionInterface
{
/**
* The array holding values for all definition keys.
*
* @var array
*/
protected
$definition
=
array
();
/**
* Constructs a new FieldDefinition object.
*
* @param array $definition
* (optional) If given, a definition represented as array.
*/
public
function
__construct
(
array
$definition
=
array
())
{
$this
->
definition
=
$definition
;
}
/**
* {@inheritdoc}
*/
public
function
getFieldName
()
{
return
$this
->
definition
[
'field_name'
];
}
/**
* Sets the field name.
*
* @param string $name
* The field name to set.
*
* @return \Drupal\Core\Entity\Field\FieldDefinition
* The object itself for chaining.
*/
public
function
setFieldName
(
$name
)
{
$this
->
definition
[
'field_name'
]
=
$name
;
return
$this
;
}
/**
* {@inheritdoc}
*/
public
function
getFieldType
()
{
// Cut of the leading field_item: prefix from 'field_item:FIELD_TYPE'.
$parts
=
explode
(
':'
,
$this
->
definition
[
'type'
]);
return
$parts
[
1
];
}
/**
* Sets the field type.
*
* @param string $type
* The field type to set.
*
* @return \Drupal\Core\Entity\Field\FieldDefinition
* The object itself for chaining.
*/
public
function
setFieldType
(
$type
)
{
$this
->
definition
[
'type'
]
=
'field_item:'
.
$type
;
return
$this
;
}
/**
* Sets a field setting.
*
* @param string $type
* The field type to set.
*
* @return \Drupal\Core\Entity\Field\FieldDefinition
* The object itself for chaining.
*/
public
function
setFieldSetting
(
$setting_name
,
$value
)
{
$this
->
definition
[
'settings'
][
$setting_name
]
=
$value
;
return
$this
;
}
/**
* {@inheritdoc}
*/
public
function
getFieldSettings
()
{
return
$this
->
definition
[
'settings'
];
}
/**
* {@inheritdoc}
*/
public
function
getFieldSetting
(
$setting_name
)
{
return
isset
(
$this
->
definition
[
'settings'
][
$setting_name
])
?
$this
->
definition
[
'settings'
][
$setting_name
]
:
NULL
;
}
/**
* {@inheritdoc}
*/
public
function
getFieldPropertyNames
()
{
return
array_keys
(
\
Drupal
::
typedData
()
->
create
(
$this
->
definition
[
'type'
])
->
getPropertyDefinitions
());
}
/**
* {@inheritdoc}
*/
public
function
isFieldTranslatable
()
{
return
!
empty
(
$this
->
definition
[
'translatable'
]);
}
/**
* Sets whether the field is translatable.
*
* @param bool $translatable
* Whether the field is translatable.
*
* @return \Drupal\Core\Entity\Field\FieldDefinition
* The object itself for chaining.
*/
public
function
setTranslatable
(
$translatable
)
{
$this
->
definition
[
'translatable'
]
=
$translatable
;
return
$this
;
}
/**
* {@inheritdoc}
*/
public
function
getFieldLabel
()
{
return
$this
->
definition
[
'label'
];
}
/**
* Sets the field label.
*
* @param string $label
* The field label to set.
*
* @return \Drupal\Core\Entity\Field\FieldDefinition
* The object itself for chaining.
*/
public
function
setFieldLabel
(
$label
)
{
$this
->
definition
[
'label'
]
=
$label
;
return
$this
;
}
/**
* {@inheritdoc}
*/
public
function
getFieldDescription
()
{
return
$this
->
definition
[
'description'
];
}
/**
* Sets the field label.
*
* @param string $description
* The field label to set.
*
* @return \Drupal\Core\Entity\Field\FieldDefinition
* The object itself for chaining.
*/
public
function
setFieldDescription
(
$description
)
{
$this
->
definition
[
'description'
]
=
$description
;
return
$this
;
}
/**
* {@inheritdoc}
*/
public
function
getFieldCardinality
()
{
// @todo: Allow to control this.
return
isset
(
$this
->
definition
[
'cardinality'
])
?
$this
->
definition
[
'cardinality'
]
:
1
;
}
/**
* {@inheritdoc}
*/
public
function
isFieldRequired
()
{
return
!
empty
(
$this
->
definition
[
'required'
]);
}
/**
* Sets whether the field is required.
*
* @param bool $required
* TRUE if the field is required, FALSE otherwise.
*
* @return \Drupal\Core\Entity\Field\FieldDefinition
* The object itself for chaining.
*/
public
function
setFieldRequired
(
$required
)
{
$this
->
definition
[
'required'
]
=
$required
;
return
$this
;
}
/**
* Sets constraints for a given field item property.
*
* @param string $name
* The name of the property to set constraints for.
* @param array $constraints
* The constraints to set.
*
* @return \Drupal\Core\Entity\Field\FieldDefinition
* The object itself for chaining.
*/
public
function
setPropertyConstraints
(
$name
,
array
$constraints
)
{
$this
->
definition
[
'item_definition'
][
'constraints'
][
'ComplexData'
][
$name
]
=
$constraints
;
return
$this
;
}
/**
* {@inheritdoc}
*/
public
function
isFieldConfigurable
()
{
return
FALSE
;
}
/**
* {@inheritdoc}
*/
public
function
getFieldDefaultValue
(
EntityInterface
$entity
)
{
return
$this
->
getFieldSetting
(
'default_value'
);
}
}
core/lib/Drupal/Core/Entity/Field/FieldDefinitionInterface.php
View file @
691a5762
...
...
@@ -68,10 +68,9 @@ public function getFieldName();
* Returns the field type.
*
* @return string
* The field type.
* The field type
, i.e. the id of a field type plugin. For example 'text'
.
*
* @todo Provide more information about field types after
* https://drupal.org/node/1969728 is implemented.
* @see \Drupal\Core\Entity\Field\FieldTypePluginManager
*/
public
function
getFieldType
();
...
...
@@ -122,6 +121,13 @@ public function getFieldPropertyNames();
*/
public
function
isFieldTranslatable
();
/**
* Determines whether the field is configurable via field.module.
*
* @return bool
*/
public
function
isFieldConfigurable
();
/**
* Returns the human-readable label for the field.
*
...
...
core/lib/Drupal/Core/Entity/Field/FieldItemList.php
View file @
691a5762
...
...
@@ -47,6 +47,7 @@ class FieldItemList extends ItemList implements FieldItemListInterface {
*/
public
function
__construct
(
array
$definition
,
$name
=
NULL
,
TypedDataInterface
$parent
=
NULL
)
{
parent
::
__construct
(
$definition
,
$name
,
$parent
);
$this
->
definition
[
'field_name'
]
=
$name
;
// Always initialize one empty item as most times a value for at least one
// item will be present. That way prototypes created by
// \Drupal\Core\TypedData\TypedDataManager::getPropertyInstance() will
...
...
@@ -79,8 +80,7 @@ public function getLangcode() {
* {@inheritdoc}
*/
public
function
getFieldDefinition
()
{
// @todo https://drupal.org/node/1988612
return
NULL
;
return
new
FieldDefinition
(
$this
->
definition
);
}
/**
...
...
@@ -195,52 +195,15 @@ public function __unset($property_name) {
}
/**
*
Implements \Drupal\Core\TypedData\AccessibleInterface::access().
*
{@inheritdoc}
*/
public
function
access
(
$operation
=
'view'
,
AccountInterface
$account
=
NULL
)
{
global
$user
;
if
(
!
isset
(
$account
))
{
$account
=
$user
;
}
// Get the default access restriction that lives within this field.
$access
=
$this
->
defaultAccess
(
$operation
,
$account
);
// Invoke hook and collect grants/denies for field access from other
// modules. Our default access flag is masked under the ':default' key.
$grants
=
array
(
':default'
=>
$access
);
$hook_implementations
=
\
Drupal
::
moduleHandler
()
->
getImplementations
(
'entity_field_access'
);
foreach
(
$hook_implementations
as
$module
)
{
$grants
=
array_merge
(
$grants
,
array
(
$module
=>
module_invoke
(
$module
,
'entity_field_access'
,
$operation
,
$this
,
$account
)));
}
// Also allow modules to alter the returned grants/denies.
$context
=
array
(
'operation'
=>
$operation
,
'field'
=>
$this
,
'account'
=>
$account
,
);
drupal_alter
(
'entity_field_access'
,
$grants
,
$context
);
// One grant being FALSE is enough to deny access immediately.
if
(
in_array
(
FALSE
,
$grants
,
TRUE
))
{
return
FALSE
;
}
// At least one grant has the explicit opinion to allow access.
if
(
in_array
(
TRUE
,
$grants
,
TRUE
))
{
return
TRUE
;
}
// All grants are NULL and have no opinion - deny access in that case.
return
FALSE
;
$access_controller
=
\
Drupal
::
entityManager
()
->
getAccessController
(
$this
->
getParent
()
->
entityType
());
return
$access_controller
->
fieldAccess
(
$operation
,
$this
->
getFieldDefinition
(),
$account
,
$this
);
}
/**
* Contains the default access logic of this field.
*
* See \Drupal\Core\TypedData\AccessibleInterface::access() for the parameter
* doucmentation. This method can be overriden by field sub classes to provide
* a different default access logic. That allows them to inherit the complete
* access() method which contains the access hook invocation logic.
*
* @return bool
* TRUE if access to this field is allowed per default, FALSE otherwise.
* {@inheritdoc}
*/
public
function
defaultAccess
(
$operation
=
'view'
,
AccountInterface
$account
=
NULL
)
{
// Grant access per default.
...
...
core/lib/Drupal/Core/Entity/Field/FieldItemListInterface.php
View file @
691a5762
...
...
@@ -7,6 +7,7 @@
namespace
Drupal\Core\Entity\Field
;
use
Drupal\Core\Session\AccountInterface
;
use
Drupal\Core\TypedData\AccessibleInterface
;
use
Drupal\Core\TypedData\ListInterface
;
...
...
@@ -59,6 +60,17 @@ public function getLangcode();
*/
public
function
getFieldDefinition
();
/**
* Contains the default access logic of this field.
*
* See \Drupal\Core\Entity\EntityAccessControllerInterface::fieldAccess() for
* the parameter documentation.
*
* @return bool
* TRUE if access to this field is allowed per default, FALSE otherwise.
*/
public
function
defaultAccess
(
$operation
=
'view'
,
AccountInterface
$account
=
NULL
);
/**
* Filters out empty field items and re-numbers the item deltas.
*/
...
...
core/modules/edit/lib/Drupal/edit/Access/EditEntityFieldAccessCheck.php
View file @
691a5762
...
...
@@ -71,8 +71,7 @@ public function access(Route $route, Request $request) {
* {@inheritdoc}
*/
public
function
accessEditEntityField
(
EntityInterface
$entity
,
$field_name
)
{
$entity_type
=
$entity
->
entityType
();
return
$entity
->
access
(
'update'
)
&&
(
$field
=
$this
->
fieldInfo
->
getField
(
$entity_type
,
$field_name
))
&&
field_access
(
'edit'
,
$field
,
$entity_type
,
$entity
);
return
$entity
->
access
(
'update'
)
&&
$entity
->
get
(
$field_name
)
->
access
(
'edit'
);
}
/**
...
...
core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceController.php
View file @
691a5762
...
...
@@ -12,6 +12,8 @@
use
Symfony\Component\HttpFoundation\Request
;
use
Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
;
use
Drupal\Core\DependencyInjection\ContainerInjectionInterface
;
use
Drupal\Core\Controller\ControllerInterface
;
use
Drupal\Core\Entity\EntityManager
;
/**
* Defines route controller for entity reference.
...
...
@@ -25,14 +27,24 @@ class EntityReferenceController implements ContainerInjectionInterface {
*/
protected
$entityReferenceAutocomplete
;
/**
* The entity manager.
*
* @var \Drupal\Core\Entity\EntityManager
*/
protected
$entityManager
;
/**
* Constructs a EntityReferenceController object.
*
* @param \Drupal\entity_reference\EntityReferenceAutocomplete $entity_reference_autcompletion
* The autocompletion helper for entity references
* The autocompletion helper for entity references.
* @param \Drupal\Core\Entity\EntityManager êntity_manager
* The entity manager.
*/
public
function
__construct
(
EntityReferenceAutocomplete
$entity_reference_autcompletion
)
{
public
function
__construct
(
EntityReferenceAutocomplete
$entity_reference_autcompletion
,
EntityManager
$entity_manager
)
{
$this
->
entityReferenceAutocomplete
=
$entity_reference_autcompletion
;
$this
->
entityManager
=
$entity_manager
;
}
/**
...
...
@@ -40,7 +52,8 @@ public function __construct(EntityReferenceAutocomplete $entity_reference_autcom
*/
public
static
function
create
(
ContainerInterface
$container
)
{
return
new
static
(
$container
->
get
(
'entity_reference.autocomplete'
)
$container
->
get
(
'entity_reference.autocomplete'
),
$container
->
get
(
'entity.manager'
)
);
}
...
...
@@ -77,7 +90,8 @@ public function handleAutocomplete(Request $request, $type, $field_name, $entity
throw
new
AccessDeniedHttpException
();
}
if
(
$field
[
'type'
]
!=
'entity_reference'
||
!
field_access
(
'edit'
,
$field
,
$entity_type
))
{
$access_controller
=
$this
->
entityManager
->
getAccessController
(
$entity_type
);
if
(
$field
[
'type'
]
!=
'entity_reference'
||
!
$access_controller
->
fieldAccess
(
'edit'
,
$instance
))
{
throw
new
AccessDeniedHttpException
();
}
...
...
core/modules/field/field.api.php
View file @
691a5762
...
...
@@ -572,33 +572,6 @@ function hook_field_purge_instance($instance) {
* @} End of "addtogroup field_crud".
*/
/**
* Determine whether the user has access to a given field.
*
* This hook is invoked from field_access() to let modules block access to
* operations on fields. If no module returns FALSE, the operation is allowed.
*
* @param $op
* The operation to be performed. Possible values: 'edit', 'view'.
* @param \Drupal\field\FieldInterface $field
* The field on which the operation is to be performed.
* @param $entity_type
* The type of $entity; for example, 'node' or 'user'.
* @param $entity
* (optional) The entity for the operation.
* @param $account
* (optional) The account to check; if not given use currently logged in user.
*
* @return
* TRUE if the operation is allowed, and FALSE if the operation is denied.
*/
function
hook_field_access
(
$op
,
\
Drupal\field\FieldInterface
$field
,
$entity_type
,
$entity
,
$account
)
{
if
(
$field
[
'field_name'
]
==
'field_of_interest'
&&
$op
==
'edit'
)
{
return
$account
->
hasPermission
(
'edit field of interest'
);
}
return
TRUE
;
}
/**
* @} End of "addtogroup hooks".
*/
core/modules/field/field.deprecated.inc
View file @
691a5762
...
...
@@ -829,3 +829,32 @@ function field_get_items(EntityInterface $entity, $field_name, $langcode = NULL)
function
field_get_default_value
(
EntityInterface
$entity
,
$field
,
$instance
,
$langcode
=
NULL
)
{
return
$instance
->
getFieldDefaultValue
(
$entity
);
}
/**
* Determines whether the user has access to a given field.
*
* @param string $op
* The operation to be performed. Possible values:
* - edit
* - view
* @param \Drupal\field\FieldInterface $field
* The field on which the operation is to be performed.
* @param $entity_type
* The type of $entity; for example, 'node' or 'user'.
* @param $entity
* (optional) The entity for the operation.
* @param $account
* (optional) The account to check, if not given use currently logged in user.
*
* @return
* TRUE if the operation is allowed; FALSE if the operation is denied.
*
* @deprecated as of Drupal 8.0. Use
* Drupal\Core\Entity\EntityAccessControllerInterface::fieldAccess()
*/
function
field_access
(
$op
,
FieldInterface
$field
,
$entity_type
,
$entity
=
NULL
,
$account
=
NULL
)
{
$access_controller
=
\
Drupal
::
entityManager
()
->
getAccessController
(
$entity_type
);
$items
=
$entity
?
$entity
->
get
(
$field
->
id
())
:
NULL
;
return
$access_controller
->
fieldAccess
(
$op
,
$field
,
$account
,
$items
);
}
core/modules/field/field.module
View file @
691a5762
...
...
@@ -592,42 +592,6 @@ function field_view_field(EntityInterface $entity, $field_name, $display_options
return
$output
;
}
/**
* Determines whether the user has access to a given field.
*
* @param string $op
* The operation to be performed. Possible values:
* - edit
* - view
* @param \Drupal\field\FieldInterface $field
* The field on which the operation is to be performed.
* @param $entity_type
* The type of $entity; for example, 'node' or 'user'.
* @param $entity
* (optional) The entity for the operation.
* @param $account
* (optional) The account to check, if not given use currently logged in user.
*
* @return
* TRUE if the operation is allowed; FALSE if the operation is denied.
*/