Methoden für benutzerdefinierte Laravel-Modelle

Lesezeit: 7 Minuten

Benutzeravatar von Jeremy Harris
Jeremy Harris

Immer wenn ich Eloquent-Modellen zusätzliche Logik hinzufüge, muss ich am Ende daraus eine machen static Methode (dh weniger als ideal), um sie von der Fassade des Modells aufzurufen. Ich habe versucht, viel zu suchen, wie man das richtig macht, und so ziemlich alle Ergebnisse sprechen über das Erstellen von Methoden, die Teile einer Query Builder-Schnittstelle zurückgeben. Ich versuche herauszufinden, wie man Methoden hinzufügt, die alles zurückgeben und mithilfe der Fassade des Modells aufgerufen werden können.

Sagen wir zum Beispiel, ich habe ein Modell namens Car und will sie alle haben:

$cars = Car::all();

Großartig, außer jetzt, sagen wir, ich möchte das Ergebnis per make in ein mehrdimensionales Array sortieren, damit mein Ergebnis so aussehen könnte:

$cars = array(
  'Ford' => array(
     'F-150' => '...',
     'Escape' => '...',
  ),
  'Honda' => array(
     'Accord' => '...',
     'Civic' => '...',
  ),
);

Anhand dieses theoretischen Beispiels bin ich versucht, eine Methode zu erstellen, die wie folgt aufgerufen werden kann:

$cars = Car::getAllSortedByMake();

Vergessen wir für einen Moment den schrecklichen Methodennamen und die Tatsache, dass er eng an die Datenstruktur gekoppelt ist. Wenn ich im Modell eine Methode wie diese mache:

public function getAllSortedByMake()
{
   // Process and return resulting array
   return array('...');
}

Und schließlich rufe ich es in meinem Controller auf, ich bekomme diese Ausnahme ausgelöst:

Die nichtstatische Methode Car::getAllSortedByMake() sollte nicht statisch aufgerufen werden, da $this von einem inkompatiblen Kontext ausgeht

TL;DR: Wie kann ich benutzerdefinierte Funktionen hinzufügen, die im Modell sinnvoll sind, ohne sie zu einer statischen Methode zu machen, und sie mithilfe der Fassade des Modells aufrufen?


Bearbeiten:

Dies ist ein theoretisches Beispiel. Vielleicht wäre eine Umformulierung der Frage sinnvoller. Warum sind bestimmte nicht statische Methoden wie z all() oder which() an der Fassade eines Eloquent-Modells verfügbar, aber keine zusätzlichen Methoden, die dem Modell hinzugefügt wurden? Dies bedeutet, dass die __call Magic-Methode wird verwendet, aber wie kann ich meine eigenen Funktionen im Modell erkennen lassen?

Wahrscheinlich ist ein besseres Beispiel für das “Sortieren”, wenn ich eine Berechnung oder einen Algorithmus für ein Datenelement ausführen musste:

$validSPG = Chemical::isValidSpecificGravity(-1.43);

Für mich ist es sinnvoll, dass so etwas im Modell enthalten ist, da es domänenspezifisch ist.

  • Beginnen Sie mit zwei Datentabellen: manufacturers und modelsAlso manufacturers enthält “Ford”, “Honda”, etc und models mit einer manufacturer_id Verknüpfung der model zum manufacturer und enthält “F-150”, “Escape”, “Accord”, “Civic” usw

    – Markus Bäcker

    14. Mai 2014 um 15:09 Uhr


  • @MarkBaker Dies war ein theoretisches Beispiel. Meine Frage ist eher auf einer grundlegenden Ebene, wie z. B. warum all() über die Fassade zugänglich? Es ist keine statische Methode, was bedeutet, dass die __call magische Methode verwendet wird. Aus diesem Grund, warum ist arbitraryMethodICreate() nicht zugänglich?

    – Jeremy Harris

    14. Mai 2014 um 15:30 Uhr

  • sehen Illuminate\Database\Eloquent\Model, all ist eine statische Methode

    – Jeff Lambert

    14. Mai 2014 um 15:34 Uhr

  • cillose: Der Grund dafür ist einfach: all() ist in der Tat eine statische Methode auf der Modelund __call wird in dieser Situation nicht aufgerufen. Es gibt mehr statische Methoden auf der Model Klasse und andere, die Sie übrigens verwenden können Model::method() werden verarbeitet von __callStatic dann __call magische Methoden und an die weitergegeben Eloquent Builder Klasse.

    – Jarek Tkaczyk

    14. Mai 2014 um 15:34 Uhr

  • Das könnte dir helfen codezen.io/most-useful-laravel-collection-methods

    – Sapnesh Naik

    8. Mai 2020 um 6:07 Uhr

Meine Frage ist eher auf einer grundlegenden Ebene, z. B. warum ist all () über die Fassade zugänglich?

Wenn Sie sich den Laravel Core ansehen, ist all() eigentlich eine statische Funktion

public static function all($columns = array('*'))

Sie haben zwei Möglichkeiten:

public static function getAllSortedByMake()
{
    return Car::where('....')->get();
}

oder

public function scopeGetAllSortedByMake($query)
{
    return $query->where('...')->get();
}

Beides wird Ihnen dies ermöglichen

Car::getAllSortedByMake();

  • Ahh, ich hatte in Eloquent von Bereichen gehört, sie aber noch nicht benutzt. Vielen Dank! Ich sehe das all() ist jetzt statisch (das bekomme ich, wenn ich es nicht verifiziere). Ich hatte immer gehört, dass diese Methoden nicht und nur Designmuster verwendet wurden erscheinen auf diese Weise für die Benutzerfreundlichkeit bei gleichzeitiger Aufrechterhaltung der Testbarkeit.

    – Jeremy Harris

    14. Mai 2014 um 15:40 Uhr


  • Ja – die meisten Funktionen sind nicht statisch – aus irgendeinem Grund nur einige der Modellfunktionen – wofür Taylor sicher einen guten Grund hat – aber das liegt über meinem Wissen.

    – Laurenz

    14. Mai 2014 um 15:43 Uhr

  • Beachten Sie, dass “Bereiche sollten immer eine Abfrage-Generator-Instanz zurückgeben”. Also, wenn Sie verwenden ->get() Sie sollten eine statische Methode und nicht die Scope-Variante verwenden. Beachten Sie auch, dass Bereiche verkettet werden können: Car::GetAllSortedByMake()->GetAllSortedByMake()->otherScopeYouHaveDefined()->where(...)->get().

    – Sawny

    3. Januar 2016 um 12:36 Uhr


  • Verwenden Sie keine Bereiche, da die Abfrage nicht identisch ist, da die Bereiche isoliert sind

    – fico7489

    7. August 2018 um 6:00 Uhr

Tatsächlich können Sie Eloquent Builder erweitern und dort benutzerdefinierte Methoden einfügen.

Schritte zum Erweitern des Builders:

1. Erstellen Sie einen benutzerdefinierten Builder

<?php

namespace App;

class CustomBuilder extends \Illuminate\Database\Eloquent\Builder
{
    public function test()
    {
        $this->where(['id' => 1]);

        return $this;
    }
}

2.Fügen Sie diese Methode zu Ihrem Basismodell hinzu:

public function newEloquentBuilder($query)
{
    return new CustomBuilder($query);
}

3. Führen Sie eine Abfrage mit Methoden in Ihrem benutzerdefinierten Builder aus:

User::where('first_name', 'like', 'a')
    ->test()
    ->get();

für den obigen Code generierte MySQL-Abfrage lautet:

select * from `users` where `first_name` like ? and (`id` = ?) and `users`.`deleted_at` is null

PS:

Erster Laurenz Beispiel ist Code, der besser für Ihr Repository geeignet ist, nicht für das Modell, aber Sie können mit diesem Ansatz auch keine weiteren Methoden leiten:

public static function getAllSortedByMake()
{
    return Car::where('....')->get();
}

Zweiter Laurenz Beispiel ist das schlimmste Ereignis.

public function scopeGetAllSortedByMake($query)
{
    return $query->where('...')->get();
}

Viele Leute schlagen vor, Bereiche zum Erweitern des Laravel-Builders zu verwenden, aber das ist eigentlich eine schlechte Lösung, da Bereiche vom eloquenten Builder isoliert werden und Sie nicht dieselbe Abfrage mit denselben Befehlen innerhalb und außerhalb des Bereichs erhalten. Ich schlug PR vor, um zu ändern, ob Bereiche isoliert werden sollten, aber Taylor ignorierte mich.

Weitere Erklärung: Zum Beispiel, wenn Sie Bereiche wie diesen haben:

public function scopeWhereTest($builder, $column, $operator = null, $value = null, $boolean = 'and')
{
    $builder->where($column, $operator, $value, $boolean);
}

und zwei beredte Fragen:

User::where(function($query){
    $query->where('first_name', 'like', 'a');
    $query->where('first_name', 'like', 'b');
})->get();

vs

User::where(function($query){
    $query->where('first_name', 'like', 'a');
    $query->whereTest('first_name', 'like', 'b');
})->get();

Generierte Abfragen wären:

select * from `users` where (`first_name` like ? and `first_name` like ?) and `users`.`deleted_at` is null

vs

select * from `users` where (`first_name` like ? and (`id` = ?)) and `users`.`deleted_at` is null

Auf den ersten Blick sehen Abfragen gleich aus, sind es aber nicht. Für diese einfache Abfrage spielt es vielleicht keine Rolle, aber für komplizierte Abfragen schon, also verwenden Sie bitte keine Bereiche zum Erweitern des Builders 🙂

für besseren dynamischen Code, anstatt den Modellklassennamen “Car” zu verwenden,

Verwenden Sie einfach “statisch” oder “selbst”.

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();
}

Benutzerdefinierte Methoden des Laravel-Modells -> Der beste Weg ist die Verwendung von Traits

  • Schritt Nr. 1: Erstellen Sie eine Eigenschaft
  • Schritt #2: Fügen Sie dem Modell die Eigenschaft hinzu
  • Schritt #3: Verwenden Sie die Methode
User::first()->confirmEmailNow()

app/Model/User.php

use App\Traits\EmailConfirmation;

class User extends Authenticatable
{
    use EmailConfirmation;
    //...
}

app/Traits/EmailConfirmation.php

<?php
namespace App\Traits;

trait EmailConfirmation
{
    /**
     * Set email_verified_at to now and save.
     *
     */
    public function confirmEmailNow()
    {
        $this->email_verified_at = now();
        $this->save();
        return $this;
    }
}

1412600cookie-checkMethoden für benutzerdefinierte Laravel-Modelle

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy