diff --git a/src/Form/PanelsAddBlockForm.php b/src/Form/PanelsAddBlockForm.php index c36f884..35fa3b5 100644 --- a/src/Form/PanelsAddBlockForm.php +++ b/src/Form/PanelsAddBlockForm.php @@ -4,6 +4,8 @@ namespace Drupal\panels\Form; use Drupal\Component\Plugin\PluginManagerInterface; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Language\LanguageManagerInterface; +use Drupal\Core\Plugin\Context\ContextRepositoryInterface; use Drupal\user\SharedTempStoreFactory; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Request; @@ -25,11 +27,17 @@ class PanelsAddBlockForm extends PanelsBlockConfigureFormBase { * * @param \Drupal\user\SharedTempStoreFactory $tempstore * The tempstore factory. + * @param \Drupal\Component\Plugin\PluginManagerInterface $condition_manager + * The condition plugin manager. + * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager + * The language manager. + * @param \Drupal\Core\Plugin\Context\ContextRepositoryInterface $context_repository + * The context repository. * @param \Drupal\Component\Plugin\PluginManagerInterface $block_manager * The block plugin manager. */ - public function __construct(SharedTempStoreFactory $tempstore, PluginManagerInterface $block_manager) { - parent::__construct($tempstore); + public function __construct(SharedTempStoreFactory $tempstore, PluginManagerInterface $condition_manager, LanguageManagerInterface $language_manager, ContextRepositoryInterface $context_repository, PluginManagerInterface $block_manager) { + parent::__construct($tempstore, $condition_manager, $language_manager, $context_repository); $this->blockManager = $block_manager; } @@ -39,6 +47,9 @@ class PanelsAddBlockForm extends PanelsBlockConfigureFormBase { public static function create(ContainerInterface $container) { return new static( $container->get('user.shared_tempstore'), + $container->get('plugin.manager.condition'), + $container->get('language_manager'), + $container->get('context.repository'), $container->get('plugin.manager.block') ); } diff --git a/src/Form/PanelsBlockConfigureFormBase.php b/src/Form/PanelsBlockConfigureFormBase.php index 6755687..529153f 100644 --- a/src/Form/PanelsBlockConfigureFormBase.php +++ b/src/Form/PanelsBlockConfigureFormBase.php @@ -2,11 +2,17 @@ namespace Drupal\panels\Form; +use Drupal\Component\Plugin\PluginManagerInterface; +use Drupal\Core\Condition\ConditionPluginCollection; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormState; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Form\SubformState; +use Drupal\Core\Language\LanguageManagerInterface; +use Drupal\Core\Plugin\Context\ContextRepositoryInterface; use Drupal\Core\Plugin\ContextAwarePluginAssignmentTrait; use Drupal\Core\Plugin\ContextAwarePluginInterface; +use Drupal\page_manager_ui\Form\VisibilitySubform; use Drupal\panels\CachedValuesGetterTrait; use Drupal\user\SharedTempStoreFactory; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -48,13 +54,42 @@ abstract class PanelsBlockConfigureFormBase extends FormBase { protected $block; /** + * The condition plugin manager. + * + * @var \Drupal\Component\Plugin\PluginManagerInterface + */ + protected $conditionManager; + + /** + * The visibility condition plugin collection. + * + * @var \Drupal\Core\Condition\ConditionPluginCollection + */ + protected $visibilityCollection; + + /** + * The visibility condition plugin UI helper object. + * + * @var \Drupal\page_manager_ui\Form\VisibilitySubform + */ + protected $visibilitySubform; + + /** * Constructs a new VariantPluginConfigureBlockFormBase. * * @param \Drupal\user\SharedTempStoreFactory $tempstore * The tempstore factory. + * @param \Drupal\Component\Plugin\PluginManagerInterface $condition_manager + * The condition plugin manager. + * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager + * The language manager. + * @param \Drupal\Core\Plugin\Context\ContextRepositoryInterface $context_repository + * The context repository. */ - public function __construct(SharedTempStoreFactory $tempstore) { + public function __construct(SharedTempStoreFactory $tempstore, PluginManagerInterface $condition_manager, LanguageManagerInterface $language_manager, ContextRepositoryInterface $context_repository) { $this->tempstore = $tempstore; + $this->conditionManager = $condition_manager; + $this->visibilitySubform = new VisibilitySubform($condition_manager, $language_manager, $context_repository); } /** @@ -62,7 +97,10 @@ abstract class PanelsBlockConfigureFormBase extends FormBase { */ public static function create(ContainerInterface $container) { return new static( - $container->get('user.shared_tempstore') + $container->get('user.shared_tempstore'), + $container->get('plugin.manager.condition'), + $container->get('language_manager'), + $container->get('context.repository') ); } @@ -136,6 +174,7 @@ abstract class PanelsBlockConfigureFormBase extends FormBase { '#default_value' => $this->variantPlugin->getRegionAssignment($this->block->getConfiguration()['uuid']), '#required' => TRUE, ]; + $form['visibility'] = $this->visibilitySubform->build([], $form_state, $this->getVisibility()); $form['actions']['submit'] = [ '#type' => 'submit', @@ -158,6 +197,9 @@ abstract class PanelsBlockConfigureFormBase extends FormBase { $this->block->validateConfigurationForm($form, $settings); // Update the original form values. $form_state->setValue('settings', $settings->getValues()); + // Call the condition plugin validate handlers. + $subform_state = SubformState::createForSubform($form['visibility'], $form, $form_state); + $this->visibilitySubform->validate($form['visibility'], $subform_state); } /** diff --git a/src/Plugin/DisplayBuilder/StandardDisplayBuilder.php b/src/Plugin/DisplayBuilder/StandardDisplayBuilder.php index 20fbb61..b28a93a 100644 --- a/src/Plugin/DisplayBuilder/StandardDisplayBuilder.php +++ b/src/Plugin/DisplayBuilder/StandardDisplayBuilder.php @@ -2,16 +2,22 @@ namespace Drupal\panels\Plugin\DisplayBuilder; +use Drupal\Component\Plugin\PluginManagerInterface; use Drupal\Component\Utility\Html; -use Drupal\Core\Extension\ModuleHandlerInterface; +use Drupal\Core\Access\AccessResult; +use Drupal\Core\Block\BlockPluginInterface; use Drupal\Core\Cache\CacheableMetadata; +use Drupal\Core\Condition\ConditionPluginCollection; +use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\Plugin\Context\ContextHandlerInterface; +use Drupal\Core\Plugin\Context\ContextRepositoryInterface; use Drupal\Core\Plugin\ContextAwarePluginInterface; use Drupal\Core\Render\Element; use Drupal\Core\Session\AccountInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\ctools\Plugin\PluginWizardInterface; +use Drupal\page_manager\ConditionAccessResolver; use Drupal\panels\Form\LayoutChangeRegions; use Drupal\panels\Form\LayoutChangeSettings; use Drupal\panels\Form\LayoutPluginSelector; @@ -66,10 +72,11 @@ class StandardDisplayBuilder extends DisplayBuilderBase implements PluginWizardI * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * The module handler. */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, ContextHandlerInterface $context_handler, AccountInterface $account, ModuleHandlerInterface $module_handler) { + public function __construct(array $configuration, $plugin_id, $plugin_definition, ContextHandlerInterface $context_handler, ContextRepositoryInterface $context_repository, AccountInterface $account, PluginManagerInterface $condition_manager, ModuleHandlerInterface $module_handler) { parent::__construct($configuration, $plugin_id, $plugin_definition); $this->contextHandler = $context_handler; + $this->contextRepository = $context_repository; $this->account = $account; $this->moduleHandler = $module_handler; } @@ -83,7 +90,9 @@ class StandardDisplayBuilder extends DisplayBuilderBase implements PluginWizardI $plugin_id, $plugin_definition, $container->get('context.handler'), + $container->get('context.repository'), $container->get('current_user'), + $container->get('plugin.manager.condition'), $container->get('module_handler') ); } @@ -102,6 +111,7 @@ class StandardDisplayBuilder extends DisplayBuilderBase implements PluginWizardI */ protected function buildRegions(array $regions, array $contexts) { $build = []; + $cacheability = CacheableMetadata::createFromRenderArray($build); foreach ($regions as $region => $blocks) { if (!$blocks) { continue; @@ -117,7 +127,10 @@ class StandardDisplayBuilder extends DisplayBuilderBase implements PluginWizardI if ($block instanceof ContextAwarePluginInterface) { $this->contextHandler->applyContextMapping($block, $contexts); } - if ($block->access($this->account)) { + $visibility = $this->checkVisibility($block); + $access = $visibility->andIf($block->access($this->account, TRUE)); + $cacheability->addCacheableDependency($access); + if ($access->isAllowed()) { $block_render_array = [ '#theme' => 'block', '#attributes' => [], @@ -162,6 +175,8 @@ class StandardDisplayBuilder extends DisplayBuilderBase implements PluginWizardI } } } + + $cacheability->applyTo($build); return $build; } @@ -192,4 +207,24 @@ class StandardDisplayBuilder extends DisplayBuilderBase implements PluginWizardI return $operations; } + /** + * Performs a visibility check with condition plugins. + * + * @param \Drupal\Core\Block\BlockPluginInterface + * Block plugin. + * + * @return \Drupal\Core\Access\AccessResultInterface + * AccessResult::allowed() if all conditions have their contexts and return + * TRUE; AccessResult::forbidden() otherwise. + */ + protected function checkVisibility(BlockPluginInterface $block) { + $configuration = $block->getConfiguration(); + if (empty($configuration['visibility'])) { + return AccessResult::allowed(); + } + $resolver = new ConditionAccessResolver($this->contextRepository, $this->contextHandler); + $conditions = new ConditionPluginCollection($this->conditionManager, $configuration['visibility']); + return $resolver->checkAccess($conditions); + } + }