web-dev-qa-db-fra.com

Rechercher un objet par slug et non par id

Je suis un débutant relatif avec Laravel (en utilisant la version 5.2.3)) et j'ai travaillé à travers des tutoriels sur les Laracasts puis j'ai fait un peu de mes propres expérimentations.

J'ai configuré avec succès un itinéraire qui récupère un élément d'une table par son ID, comme indiqué ci-dessous

Route::get('/wiseweasel/{id}', 'WiseweaselController@singleArticle');

Pour plus de simplicité, le contrôleur dd est simplement l'article

public function singleArticle($id)
{
  $article = ww_articles::find($id);
  dd($article);
}

Cela fonctionne très bien - je visite par exemple /wiseweasel/2 et j'obtiens le contenu de l'enregistrement avec id2.

Donc, je voulais ensuite utiliser le champ slug de l'enregistrement au lieu de l'id. Depuis que je sais que la méthode ID fonctionnait, j'ai juste essayé de modifier cette route et ce contrôleur (également essayé de créer à nouveau, ni travaillé). J'ai donc maintenant:

Route::get('/wiseweasel/{slug}', 'WiseweaselController@singleArticle');

et

public function singleArticle($slug)
{
  $article = ww_articles::find($slug);
  dd($article);
}

Le slug pour le deuxième record est "secondarticle". Donc, en visitant l'url/sagesse/deuxième article, je m'attendrais à voir le même enregistrement que précédemment. Au lieu de cela, je me retrouve avec null.

Encore plus étrange, l'utilisation de la route id d'origine (/ sagesweasel/2) renvoie toujours l'enregistrement ... quand j'ai supprimé toute trace de cela des routes et du contrôleur, donc je m'attends à ce que cela échoue ...

Cela me fait me demander si cela pourrait être un problème de mise en cache étrange? J'ai essayé

php route artisanale: clair

au cas où l'itinéraire était mis en cache. J'ai également essayé de redémarrer Apache et MySql (j'utilise XAMMP pour les deux).

Toujours pas de chance cependant ... je ne sais pas si j'ai mal compris comment quelque chose fonctionne ou ce qui se passe ... donc si quelqu'un a des suggestions sur ce que j'ai pu faire de mal ou quoi que ce soit à essayer, je serais très reconnaissant! :)

11
Roxy Walsh

Laravel ne saura pas automatiquement que pour slug il devrait rechercher les enregistrements de différentes manières.

Lorsque vous utilisez:

$article = ww_articles::find($slug);

vous dites Laravel - trouver l'enregistrement de www_articles par ID. (peu importe que vous appeliez cet id $ slug).

Pour réaliser ce que vous voulez changer:

$article = ww_articles::find($slug);

dans

$article = ww_articles::where('slug', $slug)->first();

Cela fera l'affaire (pour slug mettre le nom de la colonne dans la table dans la base de données). Bien sûr, rappelez-vous que dans ce cas, le slug doit être unique dans tous les enregistrements, sinon vous ne pourrez pas obtenir tous les slugs.

10
Marcin Nabiałek

Vous avez également la possibilité d'utiliser la liaison de modèle d'itinéraire pour vous en occuper et injecter l'instance résolue dans vos méthodes.

Avec la nouvelle liaison implicite de modèle de route, vous pouvez indiquer au modèle quelle clé il doit utiliser pour la liaison de route.

// routes
Route::get('/wiseweasel/{article}', 'WiseweaselController@singleArticle');


// Article model
public function getRouteKeyName()
{
    return 'slug';
}

// controller
public function singleArticle(Article $article)
{
    dd($article);
}

Laravel Docs - Route Model Binding

34
lagbox

Il est peut-être un peu tard pour la réponse, mais il existe un autre moyen de continuer à utiliser la méthode find et d'utiliser slug comme identifiant de table. Vous devez définir la propriété protégée $ primaryKey sur 'slug' dans votre modèle.

class ww_articles extends Model
{
    protected $primaryKey = 'slug';
    ...
}

Cela fonctionnera car la méthode find utilise en interne la méthode getQualifiedKeyName de la classe Model qui utilise la propriété $ primaryKey.

6

Mieux utiliser SCOPE, facile et pratique.

public function scopeSlug($query, $slug)
{
    return $query->where("slug", $slug);
}

Maintenant, nous pouvons l'utiliser comme ceci:

$article = ww_articles::slug($slug)->first();

Application des portées mondiales

0
Abbas Arif

Si vous avez les deux itinéraires comme celui-ci

Route::get('/wiseweasel/{id}', 'WiseweaselController@singleArticle');
Route::get('/wiseweasel/{slug}', 'WiseweaselController@singleArticle');

il utilisera toujours le premier. Évidemment, il n'y a pas d'id 'secondarticle', donc il retourne null (bien que dans ce cas cela n'a pas d'importance, ils pointent tous les deux vers la même méthode).

La raison est que route recherchera les routes possibles jusqu'à ce qu'il trouve une correspondance, qui est toujours celle avec {id}. Pourquoi? Vous ne dites pas à Route que {id} doit correspondre à un entier!

Vous pouvez vous assurer que {id} est compris comme un entier, mais je suggère d'utiliser des URL comme celle-ci est une meilleure option

/wiseweasel/{id}/{slug?}

Une autre suggestion. N'utilisez pas de noms tels que xx_articles pour un modèle, mais plutôt Article. De cette façon, vous pouvez utiliser la nouvelle liaison de route implicite . Ainsi, l'utilisation de la liaison implicite de votre URL ressemblerait à ceci (en supposant que votre modèle s'appelle Article)

Route::get('/wiseweasel/{article}', 'WiseweaselController@singleArticle');
0
Bojan Kogoj