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.

32
demandé sur Jeremy Harris 2014-05-14 19:05:07

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();
48
répondu Laurence 2014-05-14 15:33:52

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();
}
0
répondu jalmatari 2017-08-30 23:25:53

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 :)

0
répondu fico7489 2018-08-07 06:27:59