2016-11-21 3 views
2

Ich baue ein Paket, das stark auf einer Morph-Viele-Beziehung beruht. Wie üblich bei dieser Beziehung ist es erforderlich, die Beziehungen zu definieren, etwa so:Laravel 5 Dynamische Morph-Methode

public function foos() 
{ 
    return $this->morphToMany('App\Models\Foo', 'barable'); 
} 

Das funktioniert offensichtlich gut und es ist hier kein Problem.

Die Sache ist, dass es viele dieser Beziehungen gibt, die definiert werden müssen. Und ich möchte sie einfach durchlaufen und automatisch erstellen, um die Konfiguration des Pakets zu vereinfachen.

Ich habe folgendes versucht:

public function __get($name) 
{ 
    if($name == 'foos') { 
     return $this->morphToMany('App\Models\Foo', 'barable'); 
    } 
} 

Dies die Abfrage nicht initiieren, um die Daten abzurufen. Es wird aufgerufen, aber es gibt keine Daten zurück.

Die __call-Funktion erschien mir auch logisch, aber das bricht Laravel. Soweit ich das beurteilen kann, nimmt es alles auf, was in der Klasse aufgerufen wird.

Eine Alternative ist jetzt, ein Merkmal hinzuzufügen und den Programmierer diese Beziehungen in der publizierbaren Datei ausfüllen zu lassen, aber das fühlt sich einfach falsch an.

Irgendwelche Vorschläge?

Antwort

1

Es stellt sich heraus, dass es eine zweistufige Antwort ist. Sie benötigen einen Fix für das eifrige Laden und einen für das faule Laden.

Der eifrige Lader nimmt die __call() - Funktion, die in der model.php angegeben ist, und leitet sie weiter, wenn die Anweisung fehlschlägt.

public function __call($method, $arguments){ 
    if(in_array($method, ['bars'])) { 
     return $this->morphToMany('App\Bar', 'barable'); 
    } 
    return parent::__call($method, $arguments); 
} 

Der Lazy Loader prüft, ob die Methode existiert, was offensichtlich nicht der Fall ist. Wenn Sie es Ihrem Modell hinzufügen und eine ODER-Anweisung hinzufügen, werden diese auch funktionieren. Die ursprüngliche Funktion befindet sich auch in model.php. Hinzufügen:

|| in_array($key, $this->morphs) 

Wird die Funktion funktioniert wie erwartet und damit zu:

public function getRelationValue($key) 
{ 
    // If the key already exists in the relationships array, it just means the 
    // relationship has already been loaded, so we'll just return it out of 
    // here because there is no need to query within the relations twice. 
    if ($this->relationLoaded($key)) { 
     return $this->relations[$key]; 
    } 

    // If the "attribute" exists as a method on the model, we will just assume 
    // it is a relationship and will load and return results from the query 
    // and hydrate the relationship's value on the "relationships" array. 
    if (method_exists($this, $key) || in_array($key, $this->morphs)) { 
     return $this->getRelationshipFromMethod($key); 
    } 
}