Newer
Older

Joris Vercammen
committed
<?php
namespace Drupal\facets\Controller;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\InvokeCommand;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Block\BlockManager;
use Drupal\Core\Block\Plugin\Block\Broken;

Joris Vercammen
committed
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Path\CurrentPathStack;
use Drupal\Core\PathProcessor\PathProcessorManager;
use Drupal\Core\Http\RequestStack as DrupalRequestStack;
use Drupal\Core\Render\RendererInterface;

Joris Vercammen
committed
use Drupal\Core\Routing\CurrentRouteMatch;

Jeffrey Bertoen
committed
use Drupal\facets\Plugin\Block\FacetBlock;

Joris Vercammen
committed
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack as SymfonyRequestStack;

Joris Vercammen
committed
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\RouterInterface;
/**
* Defines a controller to load a facet via AJAX.
*/
class FacetBlockAjaxController extends ControllerBase {
/**
* The entity storage for block.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $storage;

Jeffrey Bertoen
committed
/**
* The renderer.
*
* @var \Drupal\Core\Render\RendererInterface
*/
protected $renderer;

Jeffrey Bertoen
committed

Joris Vercammen
committed
/**
* The current path.
*
* @var \Drupal\Core\Path\CurrentPathStack
*/
protected $currentPath;
/**
* The dynamic router service.
*
* @var \Symfony\Component\Routing\Matcher\RequestMatcherInterface
*/
protected $router;
/**
* The path processor service.
*
* @var \Drupal\Core\PathProcessor\InboundPathProcessorInterface
*/
protected $pathProcessor;
/**
* The current route match service.
*
* @var \Drupal\Core\Routing\CurrentRouteMatch
*/
protected $currentRouteMatch;
/**
* The block manager service.
*
* @var \Drupal\Core\Block\BlockManager
*/
protected $blockManager;

Joris Vercammen
committed
/**
* Constructs a FacetBlockAjaxController object.
*

Jeffrey Bertoen
committed
* @param \Drupal\Core\Render\RendererInterface $renderer
- * The renderer service.

Joris Vercammen
committed
* @param \Drupal\Core\Path\CurrentPathStack $currentPath
* The current path service.
* @param \Symfony\Component\Routing\RouterInterface $router
* The router service.
* @param \Drupal\Core\PathProcessor\PathProcessorManager $pathProcessor
* The path processor manager.
* @param \Drupal\Core\Routing\CurrentRouteMatch $currentRouteMatch
* The current route match service.
* @param \Drupal\Core\Block\BlockManager $blockManager
* The block manager service.

Joris Vercammen
committed
*/

Jeffrey Bertoen
committed
public function __construct(RendererInterface $renderer, CurrentPathStack $currentPath, RouterInterface $router, PathProcessorManager $pathProcessor, CurrentRouteMatch $currentRouteMatch, BlockManager $blockManager) {

Joris Vercammen
committed
$this->storage = $this->entityTypeManager()->getStorage('block');

Jeffrey Bertoen
committed
$this->renderer = $renderer;

Joris Vercammen
committed
$this->currentPath = $currentPath;
$this->router = $router;
$this->pathProcessor = $pathProcessor;
$this->currentRouteMatch = $currentRouteMatch;
$this->blockManager = $blockManager;

Joris Vercammen
committed
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(

Joris Vercammen
committed
$container->get('path.current'),
$container->get('router'),
$container->get('path_processor_manager'),
$container->get('current_route_match'),
$container->get('plugin.manager.block')

Joris Vercammen
committed
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
);
}
/**
* Loads and renders the facet blocks via AJAX.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The current request object.
*
* @return \Drupal\Core\Ajax\AjaxResponse
* The ajax response.
*
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
* Thrown when the view was not found.
*/
public function ajaxFacetBlockView(Request $request) {
$response = new AjaxResponse();
// Rebuild the request and the current path, needed for facets.
$path = $request->request->get('facet_link');
$facets_blocks = $request->request->get('facets_blocks');
if (empty($path) || empty($facets_blocks)) {
throw new NotFoundHttpException('No facet link or facet blocks found.');
}
$new_request = Request::create($path);
// Support 9.3+
// @todo remove after 9.3 or greater is required.
if (class_exists(\Drupal\Core\Http\RequestStack::class)) {
$request_stack = new DrupalRequestStack();
}
// Legacy request stack.
else {
$request_stack = new SymfonyRequestStack();
}

Joris Vercammen
committed
$processed = $this->pathProcessor->processInbound($path, $new_request);
$this->currentPath->setPath($processed);

Joris Vercammen
committed
$request->attributes->add($this->router->matchRequest($new_request));

Tom van Etten
committed
$this->currentRouteMatch->resetRouteMatch();

Joris Vercammen
committed
$request_stack->push($new_request);
$container = \Drupal::getContainer();
$container->set('request_stack', $request_stack);
foreach ($facets_blocks as $block_selector => $block_id) {
// Facet block render array.
$block_view = NULL;
// Re prepare from css standarts.
$block_id = str_replace(['--', '-'], [':', '_'], $block_id);
// @todo We should not create an instance if we have already created one.
$block_instance = $this->blockManager->createInstance($block_id);
if ($block_instance && $block_instance instanceof FacetBlock) {
$block_view = $block_instance->build();
if ($block_view) {
// Replace content current ID selector.
$response->addCommand(new ReplaceCommand('#' . $block_selector, $block_view));
// Hide or show block.
$facet_id = explode(':', $block_id)[1];
$hide_show_selector = '[data-drupal-block-facet-id = "' . $facet_id . '"]';
if (!empty($block_view['facet_block']['#attributes']['class']) && in_array('hidden', $block_view['facet_block']['#attributes']['class'])) {
$response->addCommand(new InvokeCommand($hide_show_selector, 'addClass', ['hidden']));
}
else {
$response->addCommand(new InvokeCommand($hide_show_selector, 'removeClass', ['hidden']));
}
}

Joris Vercammen
committed
}
elseif ($block_instance instanceof Broken) {
$block_entity = $this->storage->load($block_id);
if ($block_entity) {
$block_view = $this->entityTypeManager
->getViewBuilder('block')
->view($block_entity);
$block_view = (string) $this->renderer->renderPlain($block_view);
$response->addCommand(new ReplaceCommand($block_selector, $block_view));
}
}

Joris Vercammen
committed
}
// Update filter summary block.
$update_summary_block = $request->request->get('update_summary_block');
if ($update_summary_block) {
$facet_summary_plugin_ids = $request->request->get('facet_summary_plugin_ids');
foreach ($facet_summary_plugin_ids as $block_selector => $summary_plugin_id) {
// Facet summary block render array.
$block_view = NULL;
// @todo We should not create an instance if we have already created one.
$block_instance = $this->blockManager->createInstance($summary_plugin_id);
if ($block_instance) {
$block_view = $block_instance->build();
if ($block_view) {
// Replace content facets summary plugin ID selector.
$response->addCommand(new ReplaceCommand('[data-drupal-facets-summary-plugin-id = "' . $summary_plugin_id . '"]', $block_view));
// Hide or show block.
$hide_show_selector = '[data-drupal-block-facet-summary-id = "' . $summary_plugin_id . '"]';
if (!empty($block_view['facets_summary']['#attributes']['class']) && in_array('hidden', $block_view['facets_summary']['#attributes']['class'])) {
$response->addCommand(new InvokeCommand($hide_show_selector, 'addClass', ['hidden']));
}
else {
$response->addCommand(new InvokeCommand($hide_show_selector, 'removeClass', ['hidden']));
}
}
}

Joris Vercammen
committed
}
}
return $response;
}
}