2
votes

Vérifiez si le modèle existe et continuez le routage s'il n'est pas trouvé dans Laravel

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.


1 commentaires

Cela peut-il être fait avec un middleware comme indiqué dans cette réponse - stackoverflow.com/a/42216547/2341298 ?


3 Réponses :


2
votes

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à.


1 commentaires

Comment donneriez-vous les noms de ces routes?



6
votes

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.


2 commentaires

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?



0
votes

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.


0 commentaires