Rückgabe alternativer HTTP-Codes für unveröffentlichte Knoten

8

Ich versuche, die 404-Seite anstelle der 403-Antwort für unveröffentlichte Knoten in Drupal 8 zurückzugeben.

Ich habe den Kernel-Antwort-Abonnenten getestet , aber festgestellt, dass der von mir verwendete Code nur den Statuscode von 403 in 404 ändert und nicht die 404-Seite anzeigt. Vielleicht kann mir jemand zeigen, wie man dort ein 404-seitiges Antwortobjekt generiert?

Dies ist der Code, den ich verwendet habe:

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);
      }
    }
  }

}

Ich habe schließlich darauf zurückgegriffen, diesen Antwortteilnehmer vollständig zu entfernen, und habe hook_node_access wie folgt verwendet:

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();
}

Dies scheint mit mehreren Antworten auf dieser Site für Drupal 7 übereinzustimmen. Aber ich wollte sehen, ob jemand eine bessere Möglichkeit hat, dies entweder mit einem KernelEvent-Abonnenten zu tun, als mit hook_node_access. Anscheinend möchte ich testen, ob ein Knoten einen 403 zurückgibt, und dann eine neue Antwort mit der 404-Seite und dem 404-Statuscode generieren. Ich bin mir nicht sicher, wie ich das machen soll.

oknate
quelle

Antworten:

6

Sie können versuchen, dies früher in einer Ausnahme anstelle eines Antwortteilnehmers zu tun. Erweitern Sie HttpExceptionSubscriberBase, damit Sie dafür weniger Code benötigen. Ersetzen Sie dann den 403 durch eine 404-Ausnahme durch die Methode$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 }

Dies ersetzt alle 403 Ausnahmen für kanonische Knotenrouten. Sie können das Knotenobjekt abrufen, $request->attributes->get('node')wenn Sie überprüfen möchten, ob dies wirklich darauf zurückzuführen ist, dass der Knoten nicht veröffentlicht wurde.

4k4
quelle
Danke, ich habe es getestet und es funktioniert großartig! Das ist genau das, wonach ich gesucht habe.
oknate