Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
T
twig_tweak-3219625
Manage
Activity
Members
Labels
Plan
Custom issue tracker
Code
Merge requests
0
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Model registry
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Issue forks
twig_tweak-3219625
Commits
f135078f
Commit
f135078f
authored
4 years ago
by
Ivan
Browse files
Options
Downloads
Patches
Plain Diff
Issue
#3116410
by larowlan: The module may not bubble access cacheability metadata
parent
3f5be90b
No related branches found
Branches containing commit
Tags
7.x-1.0-rc3
Tags containing commit
No related merge requests found
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
src/TwigExtension.php
+50
-14
50 additions, 14 deletions
src/TwigExtension.php
tests/src/Kernel/AccessTest.php
+212
-0
212 additions, 0 deletions
tests/src/Kernel/AccessTest.php
tests/twig_tweak_test/twig_tweak_test.module
+18
-0
18 additions, 0 deletions
tests/twig_tweak_test/twig_tweak_test.module
with
280 additions
and
14 deletions
src/TwigExtension.php
+
50
−
14
View file @
f135078f
...
...
@@ -2,7 +2,9 @@
namespace
Drupal\twig_tweak
;
use
Drupal\Core\Access\AccessResult
;
use
Drupal\Core\Block\TitleBlockPluginInterface
;
use
Drupal\Core\Cache\CacheableMetadata
;
use
Drupal\Core\Entity\EntityInterface
;
use
Drupal\Core\Site\Settings
;
use
Drupal\Core\Url
;
...
...
@@ -80,8 +82,16 @@ class TwigExtension extends \Twig_Extension {
public
function
drupalBlock
(
$id
,
$check_access
=
TRUE
)
{
$entity_type_manager
=
\Drupal
::
entityTypeManager
();
$block
=
$entity_type_manager
->
getStorage
(
'block'
)
->
load
(
$id
);
if
(
$block
&&
(
!
$check_access
||
$this
->
entityAccess
(
$block
)))
{
return
$entity_type_manager
->
getViewBuilder
(
'block'
)
->
view
(
$block
);
if
(
$block
)
{
$access
=
$check_access
?
$this
->
entityAccess
(
$block
)
:
AccessResult
::
allowed
();
if
(
$access
->
isAllowed
())
{
$build
=
$entity_type_manager
->
getViewBuilder
(
'block'
)
->
view
(
$block
);
CacheableMetadata
::
createFromRenderArray
(
$build
)
->
merge
(
CacheableMetadata
::
createFromObject
(
$block
))
->
merge
(
CacheableMetadata
::
createFromObject
(
$access
))
->
applyTo
(
$build
);
return
$build
;
}
}
}
...
...
@@ -108,9 +118,13 @@ class TwigExtension extends \Twig_Extension {
$build
=
[];
$cache_metadata
=
new
CacheableMetadata
();
/* @var $blocks \Drupal\block\BlockInterface[] */
foreach
(
$blocks
as
$id
=>
$block
)
{
if
(
$this
->
entityAccess
(
$block
))
{
$access
=
$this
->
entityAccess
(
$block
);
$cache_metadata
=
$cache_metadata
->
merge
(
CacheableMetadata
::
createFromObject
(
$access
));
if
(
$access
->
isAllowed
())
{
$block_plugin
=
$block
->
getPlugin
();
if
(
$block_plugin
instanceof
TitleBlockPluginInterface
)
{
$request
=
\Drupal
::
request
();
...
...
@@ -122,6 +136,10 @@ class TwigExtension extends \Twig_Extension {
}
}
if
(
$build
)
{
$cache_metadata
->
applyTo
(
$build
);
}
return
$build
;
}
...
...
@@ -146,9 +164,18 @@ class TwigExtension extends \Twig_Extension {
$entity
=
$id
?
$entity_type_manager
->
getStorage
(
$entity_type
)
->
load
(
$id
)
:
\Drupal
::
routeMatch
()
->
getParameter
(
$entity_type
);
if
(
$entity
&&
$this
->
entityAccess
(
$entity
))
{
$render_controller
=
$entity_type_manager
->
getViewBuilder
(
$entity_type
);
return
$render_controller
->
view
(
$entity
,
$view_mode
,
$langcode
);
if
(
$entity
)
{
$access
=
$this
->
entityAccess
(
$entity
);
if
(
$access
->
isAllowed
())
{
$build
=
$entity_type_manager
->
getViewBuilder
(
$entity_type
)
->
view
(
$entity
,
$view_mode
,
$langcode
);
CacheableMetadata
::
createFromRenderArray
(
$build
)
->
merge
(
CacheableMetadata
::
createFromObject
(
$entity
))
->
merge
(
CacheableMetadata
::
createFromObject
(
$access
))
->
applyTo
(
$build
);
return
$build
;
}
}
}
...
...
@@ -174,12 +201,20 @@ class TwigExtension extends \Twig_Extension {
$entity
=
$id
?
\Drupal
::
entityTypeManager
()
->
getStorage
(
$entity_type
)
->
load
(
$id
)
:
\Drupal
::
routeMatch
()
->
getParameter
(
$entity_type
);
if
(
$entity
&&
$this
->
entityAccess
(
$entity
))
{
if
(
$langcode
&&
$entity
->
hasTranslation
(
$langcode
))
{
$entity
=
$entity
->
getTranslation
(
$langcode
);
}
if
(
isset
(
$entity
->
{
$field_name
}))
{
return
$entity
->
{
$field_name
}
->
view
(
$view_mode
);
if
(
$entity
)
{
$access
=
$this
->
entityAccess
(
$entity
);
if
(
$access
->
isAllowed
())
{
if
(
$langcode
&&
$entity
->
hasTranslation
(
$langcode
))
{
$entity
=
$entity
->
getTranslation
(
$langcode
);
}
if
(
isset
(
$entity
->
{
$field_name
}))
{
$build
=
$entity
->
{
$field_name
}
->
view
(
$view_mode
);
CacheableMetadata
::
createFromRenderArray
(
$build
)
->
merge
(
CacheableMetadata
::
createFromObject
(
$access
))
->
merge
(
CacheableMetadata
::
createFromObject
(
$entity
))
->
applyTo
(
$build
);
return
$build
;
}
}
}
}
...
...
@@ -481,7 +516,7 @@ class TwigExtension extends \Twig_Extension {
* @param \Drupal\Core\Entity\EntityInterface $entity
* Entity to check access.
*
* @return
bool
* @return
\Drupal\Core\Access\AccessResultInterface
* The access check result.
*
* @TODO Remove "check_access" option in 9.x.
...
...
@@ -489,7 +524,8 @@ class TwigExtension extends \Twig_Extension {
protected
function
entityAccess
(
EntityInterface
$entity
)
{
// Prior version 8.x-1.7 entity access was not checked. The "check_access"
// option provides a workaround for possible BC issues.
return
!
Settings
::
get
(
'twig_tweak_check_access'
,
TRUE
)
||
$entity
->
access
(
'view'
);
return
Settings
::
get
(
'twig_tweak_check_access'
,
TRUE
)
?
$entity
->
access
(
'view'
,
NULL
,
TRUE
)
:
AccessResult
::
allowed
();
}
}
This diff is collapsed.
Click to expand it.
tests/src/Kernel/AccessTest.php
0 → 100644
+
212
−
0
View file @
f135078f
<?php
namespace
Drupal\Tests\twig_tweak\Kernel
;
use
Drupal\block\BlockViewBuilder
;
use
Drupal\block\Entity\Block
;
use
Drupal\Core\Access\AccessResult
;
use
Drupal\Core\Entity\EntityStorageInterface
;
use
Drupal\Core\Entity\EntityTypeManagerInterface
;
use
Drupal\Core\Session\AccountInterface
;
use
Drupal\KernelTests\KernelTestBase
;
use
Drupal\node\Entity\Node
;
use
Drupal\node\Entity\NodeType
;
use
Drupal\node\NodeInterface
;
use
Drupal\Tests\user\Traits\UserCreationTrait
;
/**
* Tests for the Twig Tweak access control.
*
* @group twig_tweak
*/
class
AccessTest
extends
KernelTestBase
{
use
UserCreationTrait
;
/**
* A node for testing.
*
* @var \Drupal\node\NodeInterface
*/
private
$node
;
/**
* The Twig extension.
*
* @var \Drupal\twig_tweak\TwigExtension
*/
private
$twigExtension
;
/**
* {@inheritdoc}
*/
public
static
$modules
=
[
'twig_tweak'
,
'twig_tweak_test'
,
'node'
,
'user'
,
'system'
,
];
/**
* {@inheritdoc}
*/
protected
function
setUp
()
{
parent
::
setUp
();
$this
->
installEntitySchema
(
'node'
);
$this
->
installEntitySchema
(
'user'
);
$this
->
installConfig
([
'system'
]);
$node_type
=
NodeType
::
create
([
'type'
=>
'article'
,
'name'
=>
'Article'
,
]);
$node_type
->
save
();
$values
=
[
'type'
=>
'article'
,
'status'
=>
NodeInterface
::
PUBLISHED
,
// @see twig_tweak_test_node_access()
'title'
=>
'Entity access test'
,
];
$this
->
node
=
Node
::
create
(
$values
);
$this
->
node
->
save
();
$this
->
twigExtension
=
$this
->
container
->
get
(
'twig_tweak.twig_extension'
);
}
/**
* Test callback.
*/
public
function
testDrupalEntity
()
{
// -- Unprivileged user.
$this
->
setUpCurrentUser
([
'name'
=>
'User 1'
]);
$build
=
$this
->
twigExtension
->
drupalEntity
(
'node'
,
$this
->
node
->
id
());
self
::
assertNull
(
$build
);
// -- Privileged user.
$this
->
setUpCurrentUser
([
'name'
=>
'User 2'
],
[
'access content'
]);
$build
=
$this
->
twigExtension
->
drupalEntity
(
'node'
,
$this
->
node
->
id
());
self
::
assertArrayHasKey
(
'#node'
,
$build
);
$expected_cache
=
[
'tags'
=>
[
'node:1'
,
'node_view'
,
'tag_from_twig_tweak_test_node_access'
,
],
'contexts'
=>
[
'user'
,
'user.permissions'
,
],
'max-age'
=>
50
,
];
self
::
assertSame
(
$expected_cache
,
$build
[
'#cache'
]);
}
/**
* Test callback.
*/
public
function
testDrupalField
()
{
// -- Unprivileged user.
$this
->
setUpCurrentUser
([
'name'
=>
'User 1'
]);
$build
=
$this
->
twigExtension
->
drupalField
(
'title'
,
'node'
,
$this
->
node
->
id
());
self
::
assertNull
(
$build
);
// -- Privileged user.
$this
->
setUpCurrentUser
([
'name'
=>
'User 2'
],
[
'access content'
]);
$build
=
$this
->
twigExtension
->
drupalField
(
'title'
,
'node'
,
$this
->
node
->
id
());
self
::
assertArrayHasKey
(
'#items'
,
$build
);
$expected_cache
=
[
'contexts'
=>
[
'user'
,
'user.permissions'
,
],
'tags'
=>
[
'node:1'
,
'tag_from_twig_tweak_test_node_access'
,
],
'max-age'
=>
50
,
];
self
::
assertSame
(
$expected_cache
,
$build
[
'#cache'
]);
}
/**
* Test callback.
*/
public
function
testDrupalRegion
()
{
// @codingStandardsIgnoreStart
$create_block
=
function
(
$id
)
{
return
new
class
([
'id'
=>
$id
],
'block'
)
extends
Block
{
public
function
access
(
$operation
,
AccountInterface
$account
=
NULL
,
$return_as_object
=
FALSE
)
{
$result
=
AccessResult
::
allowedIf
(
$this
->
id
==
'block_1'
);
$result
->
cachePerUser
();
$result
->
addCacheTags
([
'tag_for_'
.
$this
->
id
]);
$result
->
setCacheMaxAge
(
123
);
return
$return_as_object
?
$result
:
$result
->
isAllowed
();
}
public
function
getPlugin
()
{
return
NULL
;
}
};
};
// @codingStandardsIgnoreEnd
$storage
=
$this
->
createMock
(
EntityStorageInterface
::
class
);
$blocks
=
[
'block_1'
=>
$create_block
(
'block_1'
),
'block_2'
=>
$create_block
(
'block_2'
),
];
$storage
->
expects
(
$this
->
any
())
->
method
(
'loadByProperties'
)
->
willReturn
(
$blocks
);
$view_builder
=
$this
->
createMock
(
BlockViewBuilder
::
class
);
$content
=
[
'#markup'
=>
'foo'
,
'#cache'
=>
[
'tags'
=>
[
'tag_from_view'
],
],
];
$view_builder
->
expects
(
$this
->
any
())
->
method
(
'view'
)
->
willReturn
(
$content
);
$entity_type_manager
=
$this
->
createMock
(
EntityTypeManagerInterface
::
class
);
$entity_type_manager
->
expects
(
$this
->
any
())
->
method
(
'getStorage'
)
->
willReturn
(
$storage
);
$entity_type_manager
->
expects
(
$this
->
any
())
->
method
(
'getViewBuilder'
)
->
willReturn
(
$view_builder
);
$this
->
container
->
set
(
'entity_type.manager'
,
$entity_type_manager
);
$build
=
$this
->
twigExtension
->
drupalRegion
(
'bar'
);
$expected_build
=
[
'block_1'
=>
[
'#markup'
=>
'foo'
,
'#cache'
=>
[
'tags'
=>
[
'tag_from_view'
],
],
],
'#cache'
=>
[
'contexts'
=>
[
'user'
],
'tags'
=>
[
'tag_for_block_1'
,
'tag_for_block_2'
,
],
'max-age'
=>
123
,
],
];
self
::
assertSame
(
$expected_build
,
$build
);
}
}
This diff is collapsed.
Click to expand it.
tests/twig_tweak_test/twig_tweak_test.module
+
18
−
0
View file @
f135078f
...
...
@@ -5,6 +5,9 @@
* Primary module hooks for Twig Tweak test module.
*/
use
Drupal\Core\Access\AccessResult
;
use
Drupal\node\NodeInterface
;
/**
* Implements hook_page_bottom().
*/
...
...
@@ -25,3 +28,18 @@ function twig_tweak_test_theme() {
function
template_preprocess_twig_tweak_test
(
&
$vars
)
{
$vars
[
'node'
]
=
Drupal
::
routeMatch
()
->
getParameter
(
'node'
);
}
/**
* Implements hook_node_access().
*
* @see \Drupal\Tests\twig_tweak\Kernel\AccessTest
*/
function
twig_tweak_test_node_access
(
NodeInterface
$node
)
{
if
(
$node
->
getTitle
()
==
'Entity access test'
)
{
$result
=
AccessResult
::
allowed
();
$result
->
addCacheTags
([
'tag_from_'
.
__FUNCTION__
]);
$result
->
cachePerUser
();
$result
->
setCacheMaxAge
(
50
);
return
$result
;
}
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment