非公開ノードの代替HTTPコードを返す


8

Drupal 8の非公開ノードに対して、403応答ではなく404ページを返そうとしています。

カーネル応答サブスクライバーをテストし ましたが、使用しているコードではステータスコードが403から404に変更されるだけで、実際には404ページが表示されないことがわかりました。だから誰かが私に404ページのResponseオブジェクトを生成する方法を教えてもらえますか?

これは私が使っていたコードです:

class ResponseSubscriber implements EventSubscriberInterface {

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    return [KernelEvents::RESPONSE => [['alterResponse']]];
  }

  /**
   * Change status code to 404 from 403 if page is an unpublished node.
   *
   * @param FilterResponseEvent $event
   *   The route building event.
   */
  public function alterResponse(FilterResponseEvent $event) {
    if ($event->getResponse()->getStatusCode() == 403) {
      /** @var \Symfony\Component\HttpFoundation\Request $request */
      $request = $event->getRequest();
      $node = $request->attributes->get('node');
      if ($node instanceof Node && !$node->isPublished()) {
        $response = $event->getResponse();
        // This changes the code, but doesn't return a 404 page.
        $response->setStatusCode(404);

        $event->setResponse($response);
      }
    }
  }

}

私は最終的にこの応答サブスクライバーを完全に削除することに頼り、次のようにhook_node_accessを使用しました:

use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Drupal\Core\Access\AccessResult;

function unpublished_404_node_access(\Drupal\node\NodeInterface $node, $op, \Drupal\Core\Session\AccountInterface $account) {

  if ($op == 'view' && !$node->isPublished()) {
    if (\Drupal::moduleHandler()->moduleExists('workbench_moderation') && $account->hasPermission('view any unpublished content')) {
      return AccessResult::neutral();
    }
    elseif (\Drupal::routeMatch()->getRouteName() == 'entity.node.canonical' && \Drupal::routeMatch()->getRawParameter('node') == $node->id()) {
      throw new NotFoundHttpException();
      return AccessResult::neutral();
    }
  }

  return AccessResult::neutral();
}

これは、Drupal 7に関するこのサイトのいくつかの回答と一致しているようです。私がやりたいことは、ノードが403を返しているかどうかをテストし、404ページと404ステータスコードで新しい応答を生成することです。どうすればいいのかわかりません。

回答:


6

これは、応答サブスクライバーの代わりに、例外の前半で試行できます。Extend HttpExceptionSubscriberBaseなので、これを行うために必要なコードは少なくなります。次に、メソッドで403を404例外に置き換えます$event->setException()

/src/EventSubscriber/Unpublished404Subscriber.php

<?php

namespace Drupal\mymodule\EventSubscriber;

use Drupal\Core\EventSubscriber\HttpExceptionSubscriberBase;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

class Unpublished404Subscriber extends HttpExceptionSubscriberBase {

  protected static function getPriority() {
    // set priority higher than 50 if you want to log "page not found"
    return 0;
  }

  protected function getHandledFormats() {
    return ['html'];
  }

  public function on403(GetResponseForExceptionEvent $event) {
    $request = $event->getRequest();
    if ($request->attributes->get('_route') == 'entity.node.canonical') {
      $event->setException(new NotFoundHttpException());
    }
  }

}

mymodule.services.yml:

services:
  mymodule.404:
    class: Drupal\mymodule\EventSubscriber\Unpublished404Subscriber
    arguments: []
    tags:
      - { name: event_subscriber }

これにより、正規ノードルートのすべての403例外が置き換えられます。$request->attributes->get('node')これが本当にノードが非公開になっているためかどうかを確認したい場合は、ノードオブジェクトを取得できます。


ありがとう、私はそれをテストしました、そしてそれは素晴らしい働きをします!これはまさに私が探していたものです。
oknate 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.