Mengembalikan kode HTTP alternatif untuk simpul yang tidak dipublikasikan


8

Saya mencoba mengembalikan halaman 404 alih-alih 403 respons untuk node yang tidak dipublikasikan di Drupal 8.

Saya menguji pelanggan respons kernel , tetapi menemukan kode yang saya gunakan hanya akan mengubah kode status menjadi 404 dari 403, tidak benar-benar menampilkan halaman 404. Jadi, mungkin seseorang dapat menunjukkan kepada saya cara membuat objek Respons 404 halaman di sana?

Ini adalah kode yang saya gunakan:

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

}

Saya akhirnya terpaksa menghapus pelanggan respons ini sepenuhnya dan menggunakan hook_node_access seperti ini:

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

Ini tampaknya sejalan dengan beberapa jawaban di situs ini untuk Drupal 7. Tapi saya ingin melihat apakah ada yang punya cara yang lebih baik untuk melakukan ini baik dengan pelanggan KernelEvent, daripada hook_node_access. Sepertinya yang ingin saya lakukan adalah menguji apakah sebuah node mengembalikan 403 dan kemudian menghasilkan respons baru dengan halaman 404 dan kode status 404. Saya tidak yakin bagaimana melakukan itu.

Jawaban:


6

Anda dapat mencoba melakukan ini lebih awal dalam pengecualian daripada pelanggan respons. Perluas HttpExceptionSubscriberBase, jadi Anda perlu lebih sedikit kode untuk melakukan ini. Kemudian ganti 403 dengan pengecualian 404 dengan metode$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 }

Ini menggantikan semua 403 pengecualian untuk rute simpul kanonik. Anda bisa mendapatkan objek node $request->attributes->get('node')jika Anda ingin memeriksa apakah ini benar-benar karena node tidak dipublikasikan.


Terima kasih, saya telah mengujinya dan itu berhasil! Ini hanya hal yang saya cari.
oknate
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.