Wikiartikel: Wie Nutzt Man 1 Formular Um 2 Models Zu Speichern

Hallo zusammen,

mich beschäftigt gerade der Wiki-Artikel: http://www.yiiframework.com/wiki/19/how-to-use-a-single-form-to-collect-data-for-two-or-more-models/

2 Klassen sind verbunden mit einer Beziehung 1:n, ein Primary Key und ein Foreign Key

In einem Formular sollen für 2 Models die Attribute gefüllt werden.

Mein Fehler besteht in dem Validierungsschritt der 2.Klasse!

1.Klasse ist a

2.Klasse ist b

Wird in Klasse b der Foreign Key benötigt, sprich hat in rules ein required stehen, dann sollte folgendes eine Lösung sein:




$valid=$a->validate();

 

if($valid)  

     {  

          if($a->save(false))  

                {  

                    $b->a_id = $a->id;  

                    if ($b->save()) // not false because it hasn't been validated

                    {  

                       $this->redirect(array('somewhere'));

                    }

    }

So. Wenn der Benutzer alles richtig eintippt funktionierts. Sagen wir der Benutzer vertippt sich und gibt bei Klasse b etwas falsches ein. Folgendes tritt ein: ein Element der Klasse a wird gespeichert, das Formular sagt Validierungsfehler an Stelle XY bitte richtige Eingabe machen. So. Benutzer macht korrekte Eingabe.

Ergebnis: In der Tabelle existieren zu Klasse a zwei Elemente, von denen natürlich das letztere richtig ist wo die Validierung keinen Fehler geworfen hat.

Wie setzt man die save() und validate() Funktionen um keine doppelten Klasse a Einträge zu bekommen?

Man könnte den ersten wieder löschen vor dem redirect, was totaler Humbug ist. Denn erst erstellt man a dann macht b fehler löscht a wieder, erstellt a, b ist korrekt, speichert b. Da laufen die Id Nummern in zweier Schritten, gar nicht schön gelöst.

Ich habe mich auch an der Lösung mit den scenario’s beschäftigt. Funktioniert leider auch nicht…

Dazu sieht die rules()-Methode so aus:


array('attribut-aus-b, b-Id', 'required'),

array('attribut-aus-b', 'numerical'),

array('attribut-aus-b','unsafe', 'on' => 'errors_check'),

...

Dazu existiert im Klasse a Controller


$preis->scenario='errors_check';

um das Scenario anwenden zu lassen. Hab’s mal vor dem b->safe und vor dem b->validate probiert. Doch läuft leider nicht rund. Immer noch doppelte Einträge, wenn in den Feldern aus b was falsches getippt wird.

Dann hatte ich auch mal a und b validiert, somit funktionierte der redirect nicht mehr, obwohl durch die Validierung alles grün war, keine Fehler - er hats nicht gespeichert. In der Ausgabe habe ich gesehen, dass für model a validate=1 war doch im zweiten Schritt für model b blieb $valid leider auf NULL - war nichts abgespeichert.

Transactions haben auch nicht gewirkt, daher bin ich am Ende mit meinem Latein für heute.

Könnte jemand aushelfen und mir erklären was in welcher Reihenfolge in der actionCreate() passieren muss?

Hast du b.a_id in der required-rule?

nimm das mal raus, das setzt du doch per code

Hi,

also ich hab das b-a_id Feld aus der required rules herausgenommen. So sieht’s aus:


public function rules()

	{

		return array(

			array('b-attributX', 'required'),

			array('b-attribut, b-a_id', 'numerical', 'integerOnly'=>true),

			array('b-attributX', 'numerical'),

			array('b-attribut', 'safe'),

			array('b-attribute, b-a_id', 'safe', 'on'=>'search'),

                        array('b-attributX','unsafe', 'on' => 'errors_check'),

		);

	}

Dann habe ich es im Controller mit der actionCreate so probiert:


$b=new B('errors_check');

	...

if(isset($_POST['A'], $_POST['B'])) {

                    $a->attributes=$_POST['A'];

                    $b->attributes=$_POST['B'];

                    

                    # return bool, whether the validation is successful without any error

                    $valid=$a->validate();

                    

                     if($valid) {  

                        # use false parameter to disable validation

                        if($a->save(false)) {  

                            $b->a_id = $a->id;  

                            

                            #$b->scenario='errors_check';

                            if($b->save()) // not false because it hasn't been validated

                            {  

                               $this->redirect(array('view','id'=>$a->id));

                            }

                        }

                    }...

Funktioniert nicht, wenn man in den Feldern der Klasse b (z.B. b-attributX) etwas falsches eintippt. Funktioniert auch nicht bei korrekten Eingaben. Validierung sagt immer: b-attribut cannot be blank. Jedoch wird bei jedem Versuch schon ein Objekt a in die Datenbank geschrieben…

Danach hab ichs so gestellt, damit das speichern wenigstens wieder funktioniert:


$b=new B;

	...

	if(isset($_POST['A'], $_POST['B'])) {

                    $a->attributes=$_POST['A'];

                    $b->attributes=$_POST['B'];

                    

                    # return bool, whether the validation is successful without any error

                    $valid=$a->validate();

                    

                     if($valid) {  

                        # use false parameter to disable validation

                        if($a->save(false)) {  

                            $b->a_id = $a->id;  

                            

                            $b->scenario='errors_check';

                            if($b->save()) // not false because it hasn't been validated

                            {  

                               $this->redirect(array('view','id'=>$a->id));

                            }

                        }

                    } ...

Funktioniert, bei korrekter Eingabe wird eins gespeichert. Bei falscher Eingabe in ein Klasse b (b-attributX) Feld, kommt b must be a number. Nach dem Ändern in eine richtige Eingabe, wird der redirect auch ausgeführt. In der Datenbank stehen leider wieder 2 Einträge.

In meinem Forumlar habe ich nur noch b-attributX drin stehen, als Feld das wirklich benötigt wird vom Benutzer. Mit dem Feld teste ich die Validierung.

ja, bevor du a speicherst, muss auch b valid sein

warum nimmst du den code aus dem wikiArtikel nicht?

Ich hatte anfangs den Code aus dem Artikel, da ich aber einen Fremdschlüssel habe der auch noch benötigt wird, bin ich auf die Varianten aus den Kommentaren umgestiegen.

Habe jetzt so wie im Wikiartikel selbst es umgesetzt. a und b erst validieren, dann a speichern, die id von a an b geben, um jetzt b speichern zu können…!


$b=new B;

        ...

        if(isset($_POST['A'], $_POST['B'])) {

                    $a->attributes=$_POST['A'];

                    $b->attributes=$_POST['B'];

                    

                    $valid=$a->validate();

                    $valid=$b->validate() && $valid;

                    

                     if($valid) {  

                        $a->save(false);

                        $b->a_id= $a->id; 

                        $b->save(false);

                        $this->redirect(array('view','id'=>$a->id));

                    }

Es funktioniert! Keine doppelten Einträge mehr! Danke mbi für deine Hilfe!

:lol: