Restituzione di codici HTTP alternativi per nodo non pubblicato


8

Sto cercando di restituire la pagina 404 anziché la risposta 403 per i nodi non pubblicati in Drupal 8.

Ho testato l' abbonato alla risposta del kernel , ma ho scoperto che il codice che stavo usando cambierebbe il codice di stato su 404 da 403, non in realtà visualizzava la pagina 404. Quindi forse qualcuno può mostrarmi come generare un oggetto Response 404 pagine lì?

Questo è il codice che stavo 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);
      }
    }
  }

}

Alla fine ho fatto ricorso alla rimozione completa di questo abbonato di risposta e ho usato hook_node_access in questo modo:

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

Questo sembra essere in linea con diverse risposte su questo sito per Drupal 7. Ma volevo vedere se qualcuno ha un modo migliore di farlo con un abbonato KernelEvent, piuttosto che hook_node_access. Sembra che ciò che voglio fare sia verificare se un nodo restituisce un 403 e quindi generare una nuova risposta con la pagina 404 e il codice di stato 404. Non sono sicuro di come farlo.

Risposte:


6

Puoi provare a farlo prima in un'eccezione anziché in un abbonato di risposta. Estendi HttpExceptionSubscriberBase, quindi hai bisogno di meno codice per farlo. Quindi sostituire il 403 con un'eccezione 404 con il metodo$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 }

Ciò sostituisce tutte le 403 eccezioni per le rotte dei nodi canonici. È possibile ottenere l'oggetto nodo $request->attributes->get('node')se si desidera verificare se ciò è realmente perché il nodo non è pubblicato.


Grazie, l'ho provato e funziona alla grande! Questo è proprio il tipo di cosa che stavo cercando.
Oknate
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.