J'ai deux modèles que je ne veux pas avoir de préfixe devant ses URL. Par exemple. Utilisateurs et publications
Si j'ai une URL https://example.com/title-of -the-post et https://example.com/username
Je vais faire quelque chose comme ceci dans le fichier de routes web.php
:
return; return false; return null; // and return nothing
Le problème auquel je suis confronté est que la première route est entrée et n'atteindra jamais la seconde même s'il n'y a pas de modèle avec un slug correspondant.
Comment puis-je quitter la route suivante (Post) si $ user
n'est pas trouvé?
Remarque: j'ai essayé de nombreuses stratégies de sortie différentes, mais aucune ne semble fonctionner.
// User Route::get('{slug}', function ($slug) { $user = User::whereSlug($slug)->get(); return view('users.show', $user); }); // Post Route::get('{slug}', function ($slug) { $post = Post::whereSlug($slug)->get(); return view('posts.show', $user); });
Merci d'avance!
MISE À JOUR :
Un autre problème est que si j'ai d'autres routes ressources
, elles sont également bloquées par la première route.
Par exemple Si j'ai Route :: resource ('cars', 'CarController')
, il génère un chemin / cars
qui correspond au {slug} et est également bloqué par le premier utilisateur itinéraire.
3 Réponses :
Vous devriez les vérifier tous les deux dans une seule route:
Route::get('{slug}', function ($slug) { $user = User::whereSlug($slug)->first(); if ($user) { return view('users.show', $user); } else { $post = Post::whereSlug($slug)->first(); if ($post) { return view('posts.show', $post); } else { abort(404); } } });
Cependant, cela peut être plus propre. Mais le concept est là.
Comment donneriez-vous les noms de ces routes?
Je pense que vous avez déjà eu l'idée, mais j'ai, en quelque sorte, une configuration similaire dans mon application et dans mon cas particulier, je devais aussi être capable de capturer des routes multi-segments.
Alors, voici comment j'ai fait il. Par exemple, la dernière route de mon web.php
est la suivante.
<?php namespace App\Http\Controllers; use App\Post; use App\User; use PostController; use UserController; use Illuminate\Http\Request; class HomeController extends Controller { private $postController; private $userController; /** * Create a new controller instance. * * @return void */ public function __construct(UserController $userController, PostController $postController) { $this->userController = $userController; $this->postController = $postController; } public function route(Request $request, string $slug) { $post = Post::where('slug', $slug)->first(); if(post) { return $this->postController->index($request); } $user = User::where('slug', $slug)->first(); if($user) { return $this->userController->index($request); } abort(404); } }
La classe where -> where ('catchall', '. *');
garantit que nous sommes également en mesure d'attraper les slugs qui ont plusieurs segments.
Par exemple, les itinéraires suivants seront tous mis en correspondance:
/blog/this-is-an-article /user/mozammil/articles
Ensuite, dans mon SlugRoutesController
, je peux injecter mes autres dépendances de contrôleur.
Route::get('{catchall}', 'SlugRoutesController@route')->where('catchall', '.*');
Mon contrôleur actuel est un peu plus complexe que cela, mais vous voyez l'idée.
C'est une solution plus élégante. J'espère toujours le faire avec un middleware. Si je ne le comprends pas bientôt, je devrai courir avec cette solution
Comment donneriez-vous les noms de ces routes?
Je ne sais pas si c'est la meilleure pratique, mais voici ce qui a été fait pour accomplir ce dont j'avais besoin.
Création d'une fonction sur le modèle Post qui vérifie si le slug appelle un post. Il utilise à la fois une expression régulière et une recherche dans la base de données.
if (\App\Models\Post::isRequestedPathAPost()) { Route::get('{slug}', 'PostController@show'); }
Ensuite, j'enveloppe la Route dans une instruction if
comme celle-ci.
public static function isRequestedPathAPost() { return !preg_match('/[^\w\d\-\_]+/', \Request::path()) && Post::->whereSlug(\Request::path())->exists(); }
Désormais, la route n'est utilisée que si elle existe réellement. Vous pouvez placer ceci au bas du fichier d'itinéraire pour réduire les recherches inutiles dans la base de données.
Cela peut-il être fait avec un middleware comme indiqué dans cette réponse - stackoverflow.com/a/42216547/2341298 ?