flag_lists-4.0.x-dev/src/Controller/ActionLinkController.php
src/Controller/ActionLinkController.php
<?php
namespace Drupal\flag_lists\Controller;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Url;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Component\Utility\UrlHelper;
use Drupal\flag\Ajax\ActionLinkFlashCommand;
use Drupal\flag\FlagInterface;
use Drupal\flag\FlagServiceInterface;
use Drupal\flag_lists\FlagListsServiceInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Component\Utility\Html;
/**
* Controller responses to flag and unflag action links.
*
* The response is a set of AJAX commands to update the
* link in the page.
*/
class ActionLinkController implements ContainerInjectionInterface {
/**
* The flag service.
*
* @var \Drupal\flag\FlagServiceInterface
*/
protected $flagService;
/**
* The flag lists service.
*
* @var \Drupal\flag\FlagListsServiceInterface
*/
protected $flagListsService;
/**
* The renderer service.
*
* @var \Drupal\Core\Render\RendererInterface
*/
protected $renderer;
/**
* Constructor.
*
* @param \Drupal\flag\FlagServiceInterface $flag
* The flag service.
* @param \Drupal\flag_lists\FlagListsServiceInterface $flag_lists
* The flag lists service.
* @param \Drupal\Core\Render\RendererInterface $renderer
* The Renderer service.
*/
public function __construct(
FlagServiceInterface $flag,
FlagListsServiceInterface $flag_lists,
RendererInterface $renderer
) {
$this->flagService = $flag;
$this->flagListsService = $flag_lists;
$this->renderer = $renderer;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('flag'),
$container->get('flaglists'),
$container->get('renderer')
);
}
/**
* Performs a flagging when called via a route.
*
* In addition to this it also handles the creation of a FlagListItem.
*
* @param \Drupal\flag\FlagInterface $flag
* The flag entity.
* @param int $entity_id
* The flaggable entity ID.
* @param string $view_mode
* The view mode to be used.
* @param string $flag_list
* The flag list from the link.
*
* @return \Drupal\Core\Ajax\AjaxResponse|null
* The response object, only if successful.
*
* @see \Drupal\flag\Plugin\Reload
* @see \Drupal\flag_lists\Entity\FlagListItem
*/
public function flag(FlagInterface $flag, $entity_id, $view_mode, $flag_list) {
/** @var \Drupal\Core\Entity\EntityInterface $entity */
$entity = $this->flagService->getFlaggableById($flag, $entity_id);
try {
$this->flagService->flag($flag, $entity);
}
catch (\LogicException $e) {
// Fail silently so we return to the entity, which will show an updated
// link for the existing state of the flag.
}
// Create the flag list item.
$actionLinkHelper = new ActionLinkHelper($this->flagListsService);
$actionLinkHelper->flagHelper($flag, $entity_id, $flag_list);
return $this->generateResponse($flag, $entity, $view_mode,
$flag_list, $flag->getMessage('flag'));
}
/**
* Performs a unflagging when called via a route.
*
* In addition to this it also handles the deletion of the
* related FlagListItem's.
*
* @param \Drupal\flag\FlagInterface $flag
* The flag entity.
* @param int $entity_id
* The flaggable entity ID.
* @param string $view_mode
* The view mode to be used.
* @param string $flag_list
* The flag list from the link.
*
* @return \Drupal\Core\Ajax\AjaxResponse|\Symfony\Component\HttpFoundation\RedirectResponse|null
* The response object, only if successful.
*
* @see \Drupal\flag\Plugin\Reload
* @see \Drupal\flag_lists\Entity\FlagListItem
*/
public function unflag(FlagInterface $flag, $entity_id, $view_mode, $flag_list) {
/** @var \Drupal\Core\Entity\EntityInterface $entity */
$entity = $this->flagService->getFlaggableById($flag, $entity_id);
try {
$this->flagService->unflag($flag, $entity);
}
catch (\LogicException $e) {
// Fail silently so we return to the entity, which will show an updated
// link for the existing state of the flag.
}
// Remove the flag list item.
$actionLinkHelper = new ActionLinkHelper($this->flagListsService);
$actionLinkHelper->unflagHelper($flag, $entity_id, $flag_list);
return $this->generateResponse($flag, $entity, $view_mode,
$flag_list, $flag->getMessage('unflag'));
}
/**
* Generates a response after the flag has been updated.
*
* The response is different from the Flag modules
* response as we add the flagging collection Id as well.
*
* @param \Drupal\flag\FlagInterface $flag
* The flag entity.
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity object.
* @param string $view_mode
* The view mode to be used.
* @param string $flag_list
* The flag list from the link.
* @param string $message
* (optional) The message to flash.
*
* @return \Drupal\Core\Ajax\AjaxResponse|\Symfony\Component\HttpFoundation\RedirectResponse
* The response object.
*
* @see \Drupal\flag_lists\Entity\FlaggingCollection
*/
private function generateResponse(FlagInterface $flag, EntityInterface $entity, $view_mode, $flag_list, $message) {
// Create a new AJAX response.
$response = new AjaxResponse();
// Get the link type plugin.
$link_type = $flag->getLinkTypePlugin();
// Generate the link render array.
$link = $link_type->getAsFlagLink($flag, $entity, $view_mode);
$flc = $this->flagListsService->getFlaggingCollectionById($flag_list);
$token_service = \Drupal::token();
$bubbleable_metadata = new BubbleableMetadata();
$link['#title']['#markup'] =
$token_service->replace($link['#title']['#markup'],
['flagging_collection' => $flc], [], $bubbleable_metadata);
$bubbleable_metadata
->applyTo($link);
$link['#flagging_collection'] = $flag_list;
// Add the flag_list to the link
// This is a messy method where everything is made by hand...
$options = UrlHelper::parse($link['#attributes']['href']);
$internalPath = '/' . Url::fromUri('internal:' . $options['path'])
->getInternalPath();
$uri = 'internal:' . $internalPath . '/' . $flag_list;
$path = ltrim($internalPath . '/' . $flag_list, '/');
// Create a token.
$generator = \Drupal::csrfToken();
$token = $generator->get($path);
unset($options['path']);
$options['query']['token'] = $token;
// Update the href.
$link['#attributes']['href'] = Url::fromUri($uri, $options)->toString();
// Generate a CSS selector to use in a JQuery Replace command.
$selector = '.js-flag-' . Html::cleanCssIdentifier($flag->id()) . '-' . $entity->id() . '-' . $flag_list;
// Create a new JQuery Replace command to update the link display.
$replace = new ReplaceCommand($selector, $this->renderer->renderPlain($link));
$response->addCommand($replace);
// Push a message pulsing command onto the stack.
$pulse = new ActionLinkFlashCommand($selector, $message);
$response->addCommand($pulse);
return $response;
}
}
