Commit 5b0594eb authored by marcvangend's avatar marcvangend

cache and make fieldblocks available using the render cache and #post_render_cache

parent cb8730eb
......@@ -64,29 +64,37 @@ function fieldblock_field_display_submit($form, FormStateInterface $form_state)
}
}
$view_mode_config->save();
// Invalidate the block cache to update fielblock derivatives.
if (\Drupal::moduleHandler()->moduleExists('block')) {
\Drupal::service('plugin.manager.block')->clearCachedDefinitions();
}
}
/**
* Implements hook_entity_view_alter().
* Stores specific fields on the current entity, to be retrieved later when the
* fieldblock is built, and hides the field from the renderable array.
*
* @todo: This should be in a post_render_cache callback. See setFieldBlock();
* Takes fields out of the current entity and cached them in a post render cache
* context. The #post_render_cache callback makes this data available to the
* fieldblock when it is built, We also hide the field from the render array.
* @see \Drupal\fieldblock\Plugin\Block\FieldBlock::fieldBlockPostRenderCache
* @see https://www.drupal.org/node/2151609
*/
function fieldblock_entity_view_alter(array &$build, Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) {
$fieldblock_settings = $display->getThirdPartySettings('fieldblock');
$display_id = $display->get('id');
$cache_tags = array();
if (isset($build['#cache']['tags'])) {
$cache_tags = $build['#cache']['tags'];
}
foreach ($fieldblock_settings as $field_name => $field_label) {
$fieldblock_id = $display_id . ':' . $field_name;
if (count(\Drupal\Core\Render\Element::children($build[$field_name]))) {
FieldBlock::setFieldBlock($build[$field_name], $fieldblock_id, $cache_tags);
// This is where we take out the field and cache it in a post render
// cache context.
//
$build['#post_render_cache']['Drupal\fieldblock\Plugin\Block\FieldBlock::fieldBlockPostRenderCache'][] = array(
'build' => $build[$field_name],
'fieldblock_id' => $fieldblock_id,
);
hide($build[$field_name]);
}
else {
......@@ -94,12 +102,3 @@ function fieldblock_entity_view_alter(array &$build, Drupal\Core\Entity\EntityIn
}
}
}
///**
// * Give fieldblocks a meaningful html id in spite of the hashed block deltas.
// */
//function fieldblock_preprocess_block(&$variables) {
// if ($variables['block']->module == 'fieldblock') {
// $variables['block_html_id'] = drupal_html_id('block-' . $variables['block']->fieldblock_name);
// }
//}
......@@ -30,33 +30,48 @@ class FieldBlock extends BlockBase {
}
/**
* Stores a the render array of a field for use as fieldblock.
*
* @param array $build
* @param string $fieldblock_id
* @param array $cache_tags
*
* @todo: The current storage approach does not work because its too hard to control the visibility of the block.
* Do we have to switch to storing in a static property, called from a post_render_cache callback?
* @var array Static storage for fields that are grabbed from the entity's
* render array, to be retrieved when fieldblocks are built.
*/
public static function setFieldBlock($build, $fieldblock_id, $cache_tags) {
$cid = 'fieldblock:' . $fieldblock_id;
\Drupal::cache()->set($cid, $build, CacheBackendInterface::CACHE_PERMANENT, $cache_tags);
}
protected static $fieldBlocks;
/**
* @param string $block_id
* The identifier of the fieldblock.
* @return array | false
* The render array of the field that is published as block or false if the
* field is not available.
*/
public static function getFieldBlock($block_id) {
$cid = 'fieldblock:' . $block_id;
if ($cache = \Drupal::cache()->get($cid)) {
return $cache->data;
if (isset(self::$fieldBlocks[$block_id])) {
return self::$fieldBlocks[$block_id];
}
else {
return FALSE;
}
}
public static function unsetFieldBlock($fieldblock_id) {
$cid = 'fieldblock:' . $fieldblock_id;
\Drupal::cache()->delete($cid);
/**
* #post_render_cache callback, temporarily stores a field's render array in a
* static variable and returns the original element as post render cache
* callbacks are supposed to do.
*
* Note that this is an atypical way to use the post render cache mechanism.
* Post render cache is meant to allow modules to dynamically alter pieces of
* cached content. Here we use it as some kind of context-aware cache, because
* the cached field will only be retrieved and displayed as a block when the
* entity is viewed.
*
* @param array $element
* The element (entity) being rendered.
* @param array $context
* Array containing the fieldblock ID and the field's render array.
* @return array
* The render array of the entity.
*/
public static function fieldBlockPostRenderCache(array $element, array $context) {
self::$fieldBlocks[$context['fieldblock_id']] = $context['build'];
return $element;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment