Barra in un singolo parametro di percorso o in altri modi per gestire una coda di menu con un numero dinamico di parametri


8

Secondo la documentazione di Symfony , una route definita come di seguito dovrebbe attivare il controller specificato per entrambi /hello/bobe /hello/bob/bobby:

_hello:
  path:     /hello/{names}
  defaults: { _controller: \Drupal\mymodule\Controller\Main::Controller }
  requirements:
    _access: 'TRUE'
    names: .+

Nel caso di una richiesta per /hello/bob/bobbyil {names}parametro sarebbe "bob / bobby" (slash intatto) e sarebbe fino al controllore per rompere che verso il basso in più variabili o lasciare come una singola stringa. Il trucco è l'alterata regex (". +") Usata per filtrare quel {names}parametro.

Questo post StackOverflow implica anche che regex personalizzato può essere usato per consentire barre in un parametro di route (almeno in Symfony 2).

Se provo questo contro Drupal 8.0.0-beta15 lo fa , non il lavoro e il controller specificato viene attivato solo per una richiesta a /hello/bob. Tuttavia, posso confermare che questo utilizzato per il lavoro in versioni beta precedenti (credo fino ~ beta13).

È cambiato qualcosa nel modo in cui Drupal si integra con il componente di routing di Symfony che spiegherebbe questo? Forse c'è un modo alternativo per realizzare il passaggio di barre nei parametri di routing? So che c'è un movimento verso Symfony 3.0 nel core, ma non sono sicuro che ciò possa spiegare le cose.

So anche che gli abbonati al percorso sono disponibili per gestire strutture di percorso dinamiche. Tuttavia, il caso su cui sto lavorando richiede una combinazione / numero quasi infinito di parametri dinamici alla fine di un percorso di base (ma che sono banali da analizzare nel mio controller). Sto anche cercando di evitare le stringhe di query (ad esempio /hello?names[]=bob&names[]=bobby) per questo caso.

Principalmente sono solo confuso riguardo alla disconnessione con la documentazione di Symfony, che sembra affermare che ciò dovrebbe essere possibile.


Note aggiuntive

Dopo aver postato questa domanda ho scoperto questa discussione in code fondamentali D8: [Discussione] Goccia automatizzato passando di argomento extra: S / N . Sembra concludere che il supporto "menu tail" (che è essenzialmente quello che sto cercando) verrà ufficialmente abbandonato in D8. Quella discussione si è conclusa 3 anni fa e quindi posso solo immaginare che alcune delle specifiche di implementazione più generalizzate non siano state pienamente realizzate fino a poco tempo fa (~ beta13). Questo potrebbe spiegare perché ho notato solo ora questo cambiamento.

Immagino che Drupal (non Symfony) stia ora generando una risposta 404 basata sulla richiesta delimitata da barra grezza prima che una qualsiasi logica di routing specifica di Symfony analizzi ulteriormente il percorso (ed è regex specifico del parametro, ecc.). Se questo è il caso, potrebbe spiegare perché la tecnica sopra ha smesso di funzionare. Mi chiedo comunque se ci sono modi alternativi per far fronte a questa esigenza che evita l'utilizzo di parametri di query e abbonati personalizzati.


Da quello che so su Symfony mi aspetterei che / hello / {username} corrisponda a / hello / bob ma non a / hello / bob / smith. Se si desiderano parametri aggiuntivi, è necessario impostare i valori predefiniti per loro come in stackoverflow.com/questions/11980175/… . Ma forse non capisco la domanda.
cilefen,

La configurazione dei valori predefiniti funziona come previsto (ovvero è possibile impostare {names} come parametro opzionale). Quindi sì, suppongo che potrei avere un percorso come /hello/{arg1}/{arg2}/{arg3}/.../{argN}, che potrebbe funzionare con i parametri 0-N. Tuttavia, questo imposta un limite statico al numero di parametri e sembra piuttosto disordinato. La mia comprensione del fatto che dovrebbe essere possibile farlo diversamente, tramite delimitatori di barra in un singolo parametro, si basa sulla documentazione di Symfony ( symfony.com/doc/master/cookbook/routing/slash_in_parameter.html ) insieme alla precedente esperienza con Drupal precedente beta centrali.
rjacobs,

1
Non è chiaro cosa path: /hello/{names}e username: .+avere a che fare l'uno con l'altro.

@chx, mi spiace, avevo modificato la mia domanda subito dopo la pubblicazione nel tentativo di renderla più generica. In quel processo ho dimenticato di aggiornare lo snippet yml. L'ho risolto. Dovrebbe leggere "nomi:. +"
rjacobs,

Ho appena notato che il mio ultimo commento può dare l'impressione di aver risolto le cose. Si prega di notare che avevo solo un refuso nel mio post. La domanda / questione è ancora valida poiché è ora formulata.
rjacobs,

Risposte:


9

È possibile modificare il percorso aggiungendo una classe che implementa InboundPathProcessorInterface

namespace Drupal\mymodule\PathProcessor;

use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
use Symfony\Component\HttpFoundation\Request;

class HelloPathProcessor implements InboundPathProcessorInterface {

  public function processInbound($path, Request $request) {
    if (strpos($path, '/hello/') === 0) {
      $names = preg_replace('|^\/hello\/|', '', $path);
      $names = str_replace('/',':', $names);
      return "/hello/$names";
    }
    return $path;
  }

}

In questo modo il router interpreterà il percorso /hello/bob/bobbycome /hello/bob:bobbye otterrai i parametri separati da :(o da qualsiasi altro personaggio che non entrerà in conflitto con i parametri) nel tuo controller.

Dovrai anche registrare la classe come servizio in mymodule.services.yml (assicurati che la priorità sia impostata su un valore superiore a 200)

services:
  mymodule.path_processor:
    class: Drupal\mymodule\PathProcessor\HelloPathProcessor
    tags:
      - { name: path_processor_inbound, priority: 250 }

Sì, questo è un buon punto, e suppongo che sia lo stesso meccanismo usato per fare aliasing del percorso? Se percorrendo questa rotta suppongo che il percorso del router rimarrebbe invariato (/ hello / {names}) e quindi i "nomi" potrebbero ancora essere gestiti come un singolo parametro di rotta. Quindi, se un URL che utilizza questa route è stato generato a livello di codice, i nomi dovrebbero comunque essere costruiti con i delimitatori personalizzati (bob: bobby), ma il sistema sarebbe comunque compatibile con input di URL più "amichevoli" (bob / bobby)?
rjacobs,

1

È possibile effettuare le seguenti operazioni per recuperare i parametri del percorso: In questo caso, voglio recuperare tutto ciò che viene dopo / rest / come una matrice di stringhe.

Il tuo file yourmodule.routing.yml dovrebbe assomigliare a questo.

yourmodule.rest:
  path: /rest/{path_parms}
  defaults:
    _controller: 'Drupal\yourmodule\Controller\YourController::response'
    _title: 'Rest API Title'
  requirements:
    path_params: '^[^\?]*$'
    _permission: 'access content'

o nel percorso \ to \ yourmodule \ src \ Routing \ RouteProvider.php

/**
 * @file
 * Contains \Drupal\yourmodule\Routing\RouteProvider.
 */

namespace Drupal\yourmodule\Routing;

use Symfony\Component\Routing\Route;

/**
 * Defines dynamic routes.
 */
class RouteProvider
{
    /**
     * Returns all your module routes.
     *
     * @return RouteCollection
     */
    public function routes()
    {
        $routes = [];

        // This route leads to the JS REST controller
        $routes['yourmodule.rest'] = new Route(
            '/rest/{path_params}',
            [
              '_controller' => '\Drupal\yourmodule\Controller\YourController::response',
              '_title' => 'REST API Title',
            ],
            [
              'path_params' => '^[^\?]*$',
              '_permission' => 'access content',
            ]
        );

        \Drupal::service('router.builder')->setRebuildNeeded();

        return $routes;
    }
}

Quindi, aggiungi un processore Path al tuo modulo come segue. path \ to \ nomemodulo \ src \ PathProcessor \ YourModulePathProcessor.php

namespace Drupal\yourmodule\PathProcessor;

use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
use Symfony\Component\HttpFoundation\Request;

class YourModulePathProcessor implements InboundPathProcessorInterface {

    public function processInbound($path, Request $request) {
        // If a path begins with `/rest`
        if (strpos($path, '/rest/') === 0) {
            // Transform the rest of the path after `/rest`
            $names = preg_replace('|^\/rest\/|', '', $path);
            $names = str_replace('/',':', $names);

            return "/rest/$names";
        }

        return $path;
    }
}

Infine, nel tuo controller, fai questo: path \ to \ yourmodule \ src \ Controller \ YourController.php

namespace Drupal\yourmodule\Controller;

use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;

/**
 * Controller routines for test_api routes.
 */
class YourController extends ControllerBase {

    /**
     * Callback for `rest/{path_params}` API method.
     */
    public function response(Request $request) {
        $params = explode(':', $request->attributes->get('path_params'));

        // The rest of your logic goes here ...
    }

}

non funziona con Drupal 8.7.9
Ekta Puri,

Veramente? Hai trovato un'alternativa però?
GuruKay,

non ancora, se hai qualche soluzione per favore condividi
Ekta Puri

Mi dispiace che mi ci sia voluto così tanto tempo, ho aggiornato il mio post per mostrare cosa ho fatto finalmente per ottenere i parametri del percorso. Nel mio caso, ne avevo bisogno per la mia API REST personalizzata.
GuruKay

0

Soluzione alternativa:

Creare un parametro route che riceve un array json.


mymodule.routing.yml

_hello:
  path:     /hello/{names}
  defaults: { _controller: \Drupal\mymodule\Controller\Main::index }
  requirements:
    _access: 'TRUE'

\ Drupal \ mymodule \ Controller \ Main

public function index($names_json) {
  $names = Json::decode($names_json);
  // Do something with $names
}

Sì, la codifica di più argomenti in un parametro di route è sicuramente un'opzione. Presumo tu stia insinuando che il parametro "names" sarebbe un array php formale che è codificato / serializzato direttamente? In tal caso, non ci sarebbero opzioni di codifica più appropriate per un componente path che JSON? Si noti che ciò renderebbe anche un percorso molto meno user-friendly indipendentemente dalla tecnica di codifica (un potenziale problema per l'input umano, ma non necessariamente per la generazione di percorsi programmatici).
rjacobs,

Ovviamente puoi usare qualsiasi tecnica di codifica che desideri. Preferisco JSON in quanto è molto standardizzato con un codificatore (/ decodificatore) nella maggior parte delle lingue. Ciò renderebbe i percorsi molto meno intuitivi. Se il percorso è esposto all'esterno, penso che passare i nomi nella query (name [] = Ben & name [] = George) sia molto più leggibile.
Eyal,
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.