Renvoyer des codes HTTP alternatifs pour le nœud non publié

8

J'essaie de renvoyer la page 404 au lieu de la réponse 403 pour les nœuds non publiés dans Drupal 8.

J'ai testé l' abonné de la réponse du noyau , mais j'ai trouvé que le code que j'utilisais ne faisait que changer le code d'état 404 de 403, et non pas afficher la page 404. Alors peut-être que quelqu'un peut me montrer comment générer un objet de réponse de 404 pages là-bas?

Voici le code que j'utilisais:

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

}

J'ai finalement eu recours à la suppression complète de cet abonné de réponse et j'ai utilisé hook_node_access comme ceci:

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

Cela semble correspondre à plusieurs réponses sur ce site pour Drupal 7. Mais je voulais voir si quelqu'un avait une meilleure façon de le faire avec un abonné KernelEvent, plutôt qu'avec hook_node_access. Il semble que ce que je veux faire, c'est tester si un nœud renvoie un 403, puis générer une nouvelle réponse avec la page 404 et le code d'état 404. Je ne sais pas comment faire ça.

oknate
la source

Réponses:

6

Vous pouvez essayer de le faire plus tôt dans une exception au lieu d'un abonné de réponse. Étendez HttpExceptionSubscriberBase, vous avez donc besoin de moins de code pour ce faire. Remplacez ensuite le 403 par une exception 404 par la méthode$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 }

Cela remplace les 403 exceptions pour les routes de nœuds canoniques. Vous pouvez obtenir l'objet nœud $request->attributes->get('node')si vous souhaitez vérifier si c'est vraiment parce que le nœud n'est pas publié.

4k4
la source
Merci, je l'ai testé et cela fonctionne très bien! C'est exactement le genre de chose que je cherchais.
2017