4
votes

Zend Framework 3 - route basée sur une chaîne de requête

Dans Zend Framework 3, est-il possible de router vers un contrôleur selon qu'une URL contient une chaîne de requête?

Par exemple, j'ai ces deux URL:

/users
/users?name=Bob

Je voudrais que la première route appelle un UsersController et la deuxième route appelle un NameController.

Est-ce possible?


0 commentaires

3 Réponses :


7
votes

Mon commentaire se transformait en réponse. Alors, voilà.

La prochaine fois, assurez-vous de suivre la Comment demander .


Veuillez lire le Documentation ZF3 sur le routeur et éventuellement RFC 3986 Chapitre 3 - Composants de la syntaxe a > qui montre quel est le chemin et quelle est la requête.

De RFC 3986 Chapitre 3 - Composants de syntaxe p>

Voici deux exemples d'URI et leurs composants:

$name = $this->params()->fromQuery('name', null);

if ($name) {
    // dispatch

    if ($dispatchResult) {
        // return special
    }
} 

// redirect

La configuration de la route ZF3 est généralement la configuration sur un chemin. (Ceci est également vrai pour pratiquement tous les frameworks courants.) Oui, les variables peuvent faire partie d'un chemin. En tant que tels, ils sont configurés dans la configuration de l'itinéraire. La configuration avancée du routage du framework permet souvent également des changements / exigences dans les schémas et les autorités.

Les parties «requête» et «fragment» ne font pas partie des configurations de routage.

Si vous voulez faire quelque chose, par exemple attraper une paire clé / valeur «nom» et faire le routage en conséquence, vous allez devoir créer un «receveur» (ou quel que soit son nom) sur le chemin et déterminer vous-même la redirection.

Par exemple, vous pouvez faire quelque chose comme cette réponse . Si votre instance de contrôleur étend la classe par défaut de Zend Framework AbstractActionController , alors vous devriez avoir la forward plugin disponible. À partir de la documentation:

Forward renvoie les résultats de l'envoi du contrôleur demandé; c'est au développeur de déterminer ce qu'il doit faire, le cas échéant ces résultats. Une recommandation est de les agréger dans n'importe quel retour valeur du contrôleur appelant.

À titre d'exemple:

return $this->redirect()->toRoute('login-success');

Bien sûr, vous pouvez le retourner immédiatement.

Une autre option est la redirect code > plugin (même lien).

 $foo = $this->forward()->dispatch('foo', ['action' => 'process']);
 return [
     'somekey' => $somevalue,
     'foo'     => $foo,
 ];

Avec tout cela, vous pouvez faire quelque chose comme:

     foo://example.com:8042/over/there?name=ferret#nose
     \_/   \______________/\_________/ \_________/ \__/
      |           |            |            |        |
   scheme     authority       path        query   fragment
      |   _____________________|__
     / \ /                        \
     urn:example:animal:ferret:nose

Où vous redirigez vers un nom de route (c'est-à-dire configuré chemin)


1 commentaires

Merci pour les informations sur les plugins forward () et redirect () .



-1
votes

Comme rkeet mentionné , la chaîne de requête ne fait pas partie de l'itinéraire. Par conséquent, nous avons simplement ajouté un ternaire au tableau de configuration de la route:

'users' => [ 
    'type'    => Literal::class,
    'options' => [ 
        'route'    => '/users',
        'defaults' => [
            'controller' => isset($_GET['name'])
                          ? NameController::class
                          : UsersController::class,
            'action'     => 'index',
        ],   
    ],   
    'may_terminate' => true,
],

Cela va de soi, mais fondamentalement, le contrôleur distribué dépend du fait qu'une valeur est définie dans la chaîne de requête. p>

Nous avons décidé de ne pas utiliser le plugin forward () car nous ne voulons pas instancier un contrôleur supplémentaire de manière superflue.


1 commentaires

Bien que cela fonctionne, cela rompt le modèle d'une seule action sur un seul itinéraire. Quelque chose qui est fait explicitement dans ZF. Je déconseillerais sérieusement cela, car cela crée de la magie, que vous connaissez aujourd'hui, mais qui vous grattera la tête dans un an. Là encore, cela fonctionnerait ...



-1
votes

Même si la réponse de rkeet est techniquement correcte, j'éviterais cette solution car elle transforme une seule requête HTTP en deux (le GET initial et le transfert / redirection).

Je configurerais les chemins de route afin d'avoir deux routes différentes:

/users
/users/Bob (option 1)
/users/name/Bob (option 2)

Avec cette configuration, vous pouvez accéder aux URL suivantes

'router' => [
    'routes' => [
        'users' => [
            'type' => Literal::class,
            'options' => [
                'route' => '/users',
                'defaults' => [
                    'controller' => UsersController::class,
                    'action' => 'index'
                ],
                'may_terminate' => true,
                'child_routes' => [
                    'name' => [ // This is the subroute name
                        'type' => Segment::class,
                        'options' => [
                            'route' => '/:name', // Option 1
                            // 'route' => '/name/:name', // Option 2
                            'defaults' => [
                                'controller' => NameController::class,
                                'action' => 'index'
                            ],
                            'constraints' => [
                                'name' => '[a-zA-Z]+',
                            ]
                        ]
                    ]
                ]
            ]
        ]
    ]
]


2 commentaires

Nous avons en fait utilisé cette structure d'itinéraire au départ. Cependant, le paramètre : name contient souvent des caractères qui ne conviennent pas aux URL, tels que des barres obliques. Ainsi, le paramètre : name doit être un paramètre de requête plutôt qu'un segment d'une route.


La question ne concernait pas la configuration de la route sur la partie "chemin" (comme indiqué dans ma réponse), mais dans la partie requête (après un ? dans l'URL complète). Votre réponse montre la configuration de base de la configuration de l'itinéraire, comme expliqué également dans la documentation J'avais déjà lié.