I found a temporary solution. Not sure if this is a bug in Flag that needs to be addressed by the module maintainers, or if this is working as intended, since this is a REST response, and not a typical Drupal call for a view or display mode.
In the ModuleRestResource.php file (In my case, the ModuleRestResource.php file is located at:
{{DRUPAL_ROOT}}/web/modules/custom/{{Module_Name}}/src/Plugin/rest/resource/{{Module_Name}}RestResource.php):
use Drupal\rest\ModifiedResourceResponse;
use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Entity\EntityInterface;
use Drupal\flag\FlagService;
use Drupal\Core\Render\RenderContext;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
class ModuleRestResource extends ResourceBase {
/**
* A current user instance.
*
* @var \Drupal\Core\Session\AccountProxyInterface
*/
protected $currentUser;
/**
* @var $entityTypeManager \Drupal\Core\Entity\EntityTypeManager
*/
protected $entityTypeManager;
/**
* @var \Drupal\flag\FlagService
*/
protected $flagService;
/**
* @var Drupal\Core\Access\CsrfTokenGenerator
*/
protected $csrfService;
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
$instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
$instance->logger = $container->get('logger.factory')->get('module');
$instance->currentUser = $container->get('current_user');
$instance->entityTypeManager = $container->get('entity_type.manager');
$instance->flagService = $container->get('flag');
$instance->csrfService = $container->get('csrf_token');
return $instance;
}
/**
* Responds to GET requests.
*
* @param string $payload
*
* @return \Drupal\rest\ResourceResponse
* The HTTP response object.
*
* @throws \Symfony\Component\HttpKernel\Exception\HttpException
* Throws exception expected.
*/
public function get($payload) {
// You must to implement the logic of your REST Resource here.
// Use current user after pass authentication to validate access.
if (!$this->currentUser->hasPermission('access content')) {
throw new AccessDeniedHttpException();
}
if (!is_numeric($payload)) {
throw new BadRequestHttpException();
}
/*
* This is the object that will be returned with the node details.
*/
$obj = new \stdClass();
// First load our node.
/**
* @var \Drupal\Core\Entity\EntityInterface
*/
$node = $this->entityTypeManager->getStorage('node')->load($payload);
/**
* FIX STARTS HERE !!!!!
*/
/**
* Because we are rending code early in the process, we need to wrap in executeInRenderContext
*/
$render_context = new RenderContext();
$fl = \Drupal::service('renderer')->executeInRenderContext($render_context, function() use ($node, $payload) {
/**
* Get the flag we need and check if the selected node has been flagged by the current user
*
* Set the path to create a token. This is the value that is missing by default that creates an
* invalid CSRF Token. Important to note that the leading slash should be left off for token generation
* and then added to to the links href attribute
*
*/
$flag = $this->flagService->getFlagById('bookmark');
$is_flagged = (bool) $this->flagService->getEntityFlaggings($flag, $node, \Drupal::currentUser() );
$path = 'flag/'. ($is_flagged ? 'un' : '') .'flag/bookmark/' . $node->id();
$token = $this->csrfService->get($path);
$flag_link = $flag->getLinkTypePlugin()->getAsFlagLink($flag, $node);
$flag_link['#attributes']['href'] = '/' . $path . '?destination&token=' . $token;
/**
* Render the link into HTML
*/
return \Drupal::service('renderer')->render($flag_link);
});
/**
* This is required to bubble metadata
*/
if (!$render_context->isEmpty()) {
$bubbleable_metadata = $render_context->pop();
\Drupal\Core\Render\BubbleableMetadata::createFromObject($fl)
->merge($bubbleable_metadata);
}
/*
* !!!!! FIX ENDS HERE !!!!!
*/
$obj->flag_link = $fl;
return new ResourceResponse((array)$obj, 200);
}
}
Anyone who can get module maintainers to address this would be nice.