Devolución de códigos HTTP alternativos para el nodo no publicado

8

Estoy tratando de devolver la página 404 en lugar de la respuesta 403 para nodos no publicados en Drupal 8.

Probé suscriptor respuesta kernel , pero encontré el código que estaba usando solamente cambiaría el código de estado a partir de 404 403, en realidad no mostrar la página 404. Entonces, ¿tal vez alguien pueda mostrarme cómo generar un objeto de respuesta de 404 páginas allí?

Este es el código que estaba usando:

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

}

Finalmente recurrí a eliminar este suscriptor de respuesta por completo y usé hook_node_access de esta manera:

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

Esto parece estar en línea con varias respuestas en este sitio para Drupal 7. Pero quería ver si alguien tiene una mejor manera de hacerlo, ya sea con un suscriptor de KernelEvent, en lugar de hook_node_access. Parece que lo que quiero hacer es probar si un nodo está devolviendo un 403 y luego generar una nueva respuesta con la página 404 y el código de estado 404. No estoy seguro de cómo hacer eso.

oknate
fuente

Respuestas:

6

Puede intentar hacer esto antes en una excepción en lugar de un suscriptor de respuesta. Extienda HttpExceptionSubscriberBase, por lo que necesita menos código para hacer esto. Luego reemplace el 403 con una excepción 404 con el método$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 }

Esto reemplaza todas las 403 excepciones para rutas de nodos canónicos. Puede obtener el objeto de nodo $request->attributes->get('node')si desea verificar si esto es realmente porque el nodo no está publicado.

4k4
fuente
Gracias, lo he probado y funciona muy bien. Este es justo el tipo de cosas que estaba buscando.
Oknate