2016-04-09 15 views
0

Ich erlebe ein seltsames Problem mit eloquent.Laravel eloquent ungeschützt während der Seeding

Ich habe zwei beredte Modelle, ein Benutzermodell und ein Profilmodell, die beide separate Tabellen haben und eine Eins-zu-eins-Beziehung haben.

Ich habe ein einzelnes Formular, in dem die Daten für diese beiden Modelle übergeben werden. Daher sind Daten, die zu Benutzer und Profil gehören, im Formular vorhanden.

Ich habe versucht, die Einsätze so sauber wie möglich von der Steuerung auszuführen:

$user = $this->users->createUser($request->all()); 

die createUser Funktion wird definiert, wie diese

public function createUser(array $data) 
{ 
    $user = new User($data); 
    // set some non relevant user options here... 
    $user->save(); 

    $profile = new Profile($data); 
    $user->profile()->save($profile); 

    return $user; 
} 

Aber dies erzeugt ein SQL-Fehler, weil eloquent alle zuweist Die Werte von der Form zu beiden Modellen, so dass Benutzer und Profil beide die gleichen Eigenschaften erhalten, versucht also eloquent, in Spalten einzufügen, die für das gegebene Modell nicht existieren.

Ich dachte, dass das $fillable Feld verwendet wurde, diese Art der Sache zu verhindern, aber ich habe die $fillable Felder in beiden Modellen definiert:

// User 
protected $fillable = ['email', 'password', ...]; 

// Profile 
protected $fillable = ['first_name', 'last_name', ...]; 

ich auch schon versucht, diese habe: (new User)->fill($data) aber die funktioniert nicht, noch sollte es seit der fill Methode wird auch aus dem Model Konstruktor aufgerufen.

In meinen Gedanken ist dies nicht das erwartete Verhalten, aber dann wieder habe ich möglicherweise das Konzept von befüllbar verstanden. Jeder Einblick würde geschätzt werden. Ich weiß, dass dies gelöst werden kann, indem jeder Schlüssel, den ich an den Konstruktor senden möchte, deklariert wird, aber das scheint mir sehr unordentlich zu sein. Auch ich bin mit Laravel v5.2.29

EDIT

Nach weiteren Tests ich zu dem Schluss gekommen, dass dies nur im Innern passiert, wenn ich die Datenbank seeders laufen, wo ich diese Funktionen tun verwenden. Wenn ich tiefer greife, sehe ich, dass dies vollkommen sinnvoll ist, da das Ausführen des Seed-Befehls die Basismodell-Klasse "schützt". Das ist also das erwartete Verhalten.

Meine Frage ist, gibt es eine Möglichkeit, diesen Standard zu überschreiben, so dass die Modelle nicht "unbewacht" beim Ausführen des Startbefehls, so dass ich meine Hilfsfunktionen zum Auffüllen meiner Testdatenbank verwenden kann oder tun Ich muss jeden Datensatz in den Seeder-Klassen manuell richtig definieren?

+0

Haben Sie Konstruktor in Ihrem Modell haben? Sie übergeben Benutzer und profilieren ein Array. Stellen Sie sicher, dass ein Konstruktor für die Verarbeitung vorhanden ist. –

+0

Sowohl der Benutzer als auch das Profil erben von der Basismodellklasse, und ich überschreibe den Konstruktor nicht. Ich habe das Problem eingegrenzt (siehe meine Bearbeitung), bin mir aber nicht sicher, wie ich das sauber umgehen kann. – Pavlin

+0

warum nicht zu phpmyadmin oder was auch immer gehen und dort Daten einfügen? –

Antwort

2

Ja, von einigen Versionen von Laravel 5.2 bei Verwendung von Seeding-Modellen sind unbewacht, wie Sie bemerkt haben. In der Tat ist es ziemlich vernünftig, es ist unbewacht, aber wenn Sie es ändern wollen, ist es möglich, aber nicht so einfach.

Hier sind Schritte, die Sie, das erreichen tun sollen: mit Ihrer eigenen ConsoleSupportServiceProvider Klasse

  1. Kommentar in config/app.php Linie Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class, add Linie.

  2. erstellen diese Klasse wie Original ConsoleSupportServiceProvider (Sie tatsächlich verlängern können), aber in $providers Eigenschaftsänderung Illuminate\Database\SeedServiceProvider in benutzerdefinierte ein

  3. Wieder erstellen individuelle SeedServiceProvider, die wieder individuelle SeedCommand Original SeedServiceProvider und nun außer Kraft setzen registerSeedCommand erstellen erstreckt Klasse

  4. benutzerdefinierte SeedCommand Klasse erstellen, die ursprüngliche SeedCommand erweitert und jetzt alles, was Sie brauchen, ändert sich:

    public function fire() 
    { 
        if (! $this->confirmToProceed()) { 
         return; 
        } 
    
        $this->resolver->setDefaultConnection($this->getDatabase()); 
    
        Model::unguarded(function() { 
         $this->getSeeder()->run(); 
        }); 
    } 
    

    in

    public function fire() 
    { 
        if (! $this->confirmToProceed()) { 
         return; 
        } 
    
        $this->resolver->setDefaultConnection($this->getDatabase()); 
    
        $this->getSeeder()->run(); 
    
    } 
    
+1

Danke für die Klärung. Es macht Sinn, dass die Datenbank während des Seeding-Prozesses nicht geschützt wird, also habe ich am Ende meinen Samen geändert. Ich habe versucht, meinen eigenen Seed-Befehl zu implementieren, aber es hat nicht funktioniert, und jetzt verstehe ich, warum - ich habe keine Dienstanbieter geändert. Danke für die tolle Antwort! – Pavlin