FieldRedirectionResultBuilder.php in Field Redirection 8.2
Namespace
Drupal\field_redirectionFile
src/FieldRedirectionResultBuilder.phpView source
<?php
namespace Drupal\field_redirection;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Path\PathMatcherInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\State\StateInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;
use Drupal\Core\Utility\Token;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Defines a service for evaluating the intended action for a field redirection.
*
* There are a large number of scenarios to consider in determining what action
* to take for a field redirection. The final result is conveyed with a field
* redirection result value object. This class is used to build the value object
* based on the field value and formatter settings.
*
* We use a separate helper class to the formatter so that we can kernel test
* the scenarios without needing to use a browser to redirect.
*
* @see \Drupal\field_redirection\FieldRedirectionResult
*/
class FieldRedirectionResultBuilder {
use StringTranslationTrait;
/**
* Path Matcher.
*
* @var \Drupal\Core\Path\PathMatcherInterface
*/
protected $pathMatcher;
/**
* Token service.
*
* @var \Drupal\Core\Utility\Token
*/
protected $token;
/**
* State service.
*
* @var \Drupal\Core\State\StateInterface
*/
protected $state;
/**
* Constructs a new FieldRedirectionResultBuilder.
*
* @param \Drupal\Core\Path\PathMatcherInterface $pathMatcher
* Path matcher.
* @param \Drupal\Core\Utility\Token $token
* Token service.
* @param \Drupal\Core\State\StateInterface $state
* State service.
*/
public function __construct(PathMatcherInterface $pathMatcher, Token $token, StateInterface $state) {
$this->pathMatcher = $pathMatcher;
$this->token = $token;
$this->state = $state;
}
/**
* Determine whether we should deny redirecting.
*
* @param \Drupal\Core\Field\FieldItemListInterface $items
* The field items.
* @param \Symfony\Component\HttpFoundation\Request $request
* The request.
* @param \Drupal\Core\Session\AccountInterface $account
* The account.
* @param array $settings
* The field settings.
*
* @return bool
* TRUE if we should deny redirecting.
*/
protected function shouldDeny(FieldItemListInterface $items, Request $request, AccountInterface $account, array $settings = []) {
// Return early if account has bypass permission.
if ($account
->hasPermission('bypass redirection')) {
return TRUE;
}
$current_url = Url::fromRoute('<current>');
$current_path = $current_url
->toString();
// Optionally control the list of pages this works on.
if (!empty($settings['page_restrictions']) && !empty($settings['pages'])) {
// Remove '1' from this value so it can be XOR'd later on.
$page_restrictions = $settings['page_restrictions'] - 1;
// Do raw token replacements.
$pages = $this->token
->replace($settings['pages'], [], [
'clear' => TRUE,
]);
// Normalise all paths to lower case.
$pages = mb_strtolower($pages);
$page_match = $this->pathMatcher
->matchPath($current_path, $pages);
$requestUri = $request
->getRequestUri();
if ($current_path != $requestUri) {
$page_match = $page_match || $this->pathMatcher
->matchPath($requestUri, $pages);
}
// Stop processing if the page restrictions have matched.
if (!($page_restrictions xor $page_match)) {
return TRUE;
}
}
// Don't do anything if the current page is running the normal cron script;
// this also supports Elysia Cron.
if (mb_strpos($current_path, '/cron') === 0) {
return TRUE;
}
// Don't do anything if the cron script is being executed from the admin
// status page.
if ($current_path === '/admin/reports/status/run-cron') {
return TRUE;
}
// Don't do anything if site is in maintenance mode.
if (defined('MAINTENANCE_MODE') || $this->state
->get('system.maintenance_mode')) {
return TRUE;
}
// Only redirect based on the first value of a field. Ignore other values.
if (!$items
->isEmpty()) {
/** @var \Drupal\link\Plugin\Field\FieldType\LinkItem $item */
$item = $items
->first();
}
elseif (isset($settings['404_if_empty']) && $settings['404_if_empty']) {
throw new NotFoundHttpException();
}
else {
return TRUE;
}
$redirect_url = $item
->getUrl();
// We need to check if the redirect URL is the same as:
//
// 1. The current (possibly an alias) path (relative).
// 2. The current path's internal path (relative). Url->toString()
// always returns an alias, so this is covered by point 1 above.
// 3. The current path's internal path (absolute).
// 4. The current path, which is also the home page.
//
// If any of these cases are true, then do not redirect.
//
// Current path (relative) and current internal path (relative).
if ($current_path == $redirect_url
->toString()) {
return TRUE;
}
// Current path (absolute).
$current_url
->setAbsolute(TRUE);
if ($current_url
->toString() === $redirect_url
->toString()) {
return TRUE;
}
// Current path is the home page.
if (!$redirect_url
->isExternal() && $redirect_url
->getRouteName() == '<front>' && $this->pathMatcher
->isFrontPage()) {
return TRUE;
}
return FALSE;
}
/**
* Builds a redirection result for a given set of values.
*
* @param \Drupal\Core\Field\FieldItemListInterface $items
* The field items.
* @param \Symfony\Component\HttpFoundation\Request $request
* The request.
* @param \Drupal\Core\Session\AccountInterface $account
* The account.
* @param array $settings
* The field settings.
*
* @return \Drupal\field_redirection\FieldRedirectionResult
* The redirection result.
*/
public function buildResult(FieldItemListInterface $items, Request $request, AccountInterface $account, array $settings = []) {
if ($this
->shouldDeny($items, $request, $account, $settings)) {
return FieldRedirectionResult::deny();
}
return FieldRedirectionResult::fromUrl($items
->first()
->getUrl());
}
}
Classes
Name | Description |
---|---|
FieldRedirectionResultBuilder | Defines a service for evaluating the intended action for a field redirection. |