Méthodes De Modélisation Sur Mesure De Laravel
chaque fois que j'ajoute de la logique aux modèles éloquents, je finis par en faire un static
méthode (c'est-à-dire moins qu'idéale) pour l'appeler de la façade du modèle. J'ai essayé de chercher beaucoup sur la façon de le faire de la bonne façon et à peu près tous les résultats parlent de créer des méthodes qui renvoient des portions d'une interface de constructeur de requête. J'essaie de trouver comment ajouter des méthodes qui peuvent rapporter n'importe quoi et être appelées en utilisant la façade du modèle.
par exemple, disons que un modèle est appelé Car
et vous voulez les faire toutes:
$cars = Car::all();
très bien, sauf que pour l'instant, disons que je veux pour trier le résultat dans un tableau multidimensionnel en faire donc mon résultat peut ressembler à ceci:
$cars = array(
'Ford' => array(
'F-150' => '...',
'Escape' => '...',
),
'Honda' => array(
'Accord' => '...',
'Civic' => '...',
),
);
en prenant cet exemple théorique, je suis tenté de créer une méthode qui peut s'appeler comme:
$cars = Car::getAllSortedByMake();
pour un instant, oublions le nom terrible de la méthode et le fait qu'elle est étroitement liée à la structure des données. Si je fais une méthode comme cela dans le modèle:
public function getAllSortedByMake()
{
// Process and return resulting array
return array('...');
}
Et enfin l'appeler dans mon contrôleur, je vais obtenir cette Exception levée:
la méthode non-statique Car:: getAllSortedByMake () ne doit pas être appelée statiquement, en supposant $ceci du contexte incompatible
TL;DR: Comment puis-je ajouter une fonctionnalité personnalisée qui a du sens d'être dans le modèle sans en faire une méthode statique et l'appeler en utilisant le modèle façade?
Edit:
C'est un exemple théorique. Peut-être reformuler la question aurait plus de sens. Pourquoi certaines méthodes non statiques telles que all()
ou which()
disponible sur la façade D'un modèle éloquent, mais pas de méthodes supplémentaires ajoutées au modèle? Cela signifie que l' __call
magie méthode est utilisée, mais comment puis-je faire reconnaître mes propres fonctions dans le modèle?
probablement un meilleur exemple "tri" est si j'nécessaires à l'exécution d'un calcul ou d'un algorithme sur un morceau de données:
$validSPG = Chemical::isValidSpecificGravity(-1.43);
pour moi, il est logique que quelque chose comme ça soit dans le modèle puisqu'il est spécifique à un domaine.
3 réponses
ma question est à un niveau plus fondamental tel que Pourquoi est tout() accessible par la façade?
si vous regardez le noyau Laravel-all () est en fait une fonction statique
public static function all($columns = array('*'))
Vous avez deux options:
public static function getAllSortedByMake()
{
return Car::where('....')->get();
}
ou
public function scopeGetAllSortedByMake($query)
{
return $query->where('...')->get();
}
les Deux vous permettront de le faire
Car::getAllSortedByMake();
pour une meilleure dynamique de code, plutôt que d'utiliser le Modèle de nom de la classe "Voiture",
suffit d'utiliser "statique" ou "auto"
public static function getAllSortedByMake()
{
//to return "Illuminate\Database\Query\Builder" class object you can add another where as you want
return static::where('...');
//or return already as collection object
return static::where('...')->get();
}
en fait, vous pouvez étendre Eloquent Builder et y mettre des méthodes personnalisées.
Mesures pour prolonger le constructeur :
1.Créer constructeur personnalisé
<?php
namespace App;
class CustomBuilder extends \Illuminate\Database\Eloquent\Builder
{
public function test()
{
$this->where(['id' => 1]);
return $this;
}
}
2.Ajoutez cette méthode à votre modèle de base:
public function newEloquentBuilder($query)
{
return new CustomBuilder($query);
}
3.Exécuter la requête avec des méthodes à l'intérieur de votre constructeur personnalisé :
User::where('first_name', 'like', 'a')
->test()
->get();
pour le code ci-dessus généré requête mysql sera :
select * from `users` where `first_name` like ? and (`id` = ?) and `users`.`deleted_at` is null
PS:
Première Laurence exemple de code est plus approprié pour vous référentiel qui n'est pas pour modèle, mais aussi vous ne pouvez pas le tuyau des méthodes avec cette approche :
public static function getAllSortedByMake()
{
return Car::where('....')->get();
}
Deuxième Laurence l'exemple est le pire événement.
public function scopeGetAllSortedByMake($query)
{
return $query->where('...')->get();
}
beaucoup de gens suggèrent d'utiliser des scopes pour étendre la construction de laravel, mais c'est en fait une mauvaise solution parce que les scopes sont isolés par eloquent builder et vous n'obtiendrez pas la même requête avec les mêmes commandes à l'intérieur de vs en dehors de la portée. J'ai proposé le PR pour changer si scopes devait être isolé mais Taylor m'a ignoré.
plus d'explications : Par exemple, si vous avez des étendues comme ceci :
public function scopeWhereTest($builder, $column, $operator = null, $value = null, $boolean = 'and')
{
$builder->where($column, $operator, $value, $boolean);
}
et deux questions éloquentes:
User::where(function($query){
$query->where('first_name', 'like', 'a');
$query->where('first_name', 'like', 'b');
})->get();
et
User::where(function($query){
$query->where('first_name', 'like', 'a');
$query->whereTest('first_name', 'like', 'b');
})->get();
les requêtes générées seraient :
select * from `users` where (`first_name` like ? and `first_name` like ?) and `users`.`deleted_at` is null
et
select * from `users` where (`first_name` like ? and (`id` = ?)) and `users`.`deleted_at` is null
à première vue, les requêtes semblent identiques, mais il n'y en a pas. Pour cette simple requête peut-être qu'il n'a pas d'importance mais pour les requêtes compliquées, il le fait, alors s'il vous plaît ne pas utiliser de portées pour étendre builder :)