Passing posted data from a form in further steps

Let’s say we have a situation similar to this wiki:

http://www.yiiframework.com/wiki/19/how-to-use-a-single-form-to-collect-data-for-two-or-more-models

In my situation I have multiple classes:




$classes[] = "Prosopo";

		$classes[] = "Class1";

		$classes[] = "Class2";

		$classes[] = "Class3";

		$classes[] = "Class4";

		

		$allset = true;		//check if set only for the models that matter

		foreach($classes as $class)

		{

			$models[$class] = new $class;

			$allset = $allset && isset($_POST[$class]);

		}



As you can see the models are instantiated and at the same time we check if we have posted data for all of them!

The problem is with the first class ‘Class1’

In case the corresponding "textbox" contains exactly the same text as a previous post (meaning already exists in the database) then this line fails:


 if( !$model->save() )	throw new Exception;	//save class1 

The NOT accepted transparent solution: Validate first and if the record already exists in the database try to load this model instead of trying to save a new one (which will fail because is the same). So it is seamless to the user whether the content of this textbox exists already in the database or not. Unfortunately this behaviour of the interface is not accepted

The UGLY solution: In case the record already exists in the database I take all the data from $_POST (note I already have a function to convert an array to a valid url) and redirect the user to a simple form which will be a simple question.

"This class1 text already exists. Do you wish to continue?"

with a "yes" and "no" buttons

I think you already see the security problems of such a solution.

Please note: AJAX solutions are not accepted

Do you have any other ideas on how to give a more concrete solution to this problem?

please do not hesitate to ask me to elaborate on my explanation :)

Forget the multiple classes

Lets say you have only one class and a simple form… and somebody enters data that already exists in the database…

How would you solve this?

This is up to you and your situation need… will you update the existing record or prevent duplicates by showing an error to the client?

Now back to the multiple classes… check again the code in the wiki you linked above… it first validates all data… and only if all classes validates without errors it saves the data…

Yes mdomba I agree with you!

So in case I would like to show an error to the client how would I store the data, to use them later?

  1. Store them in their corresponding tables inside database and then perhaps delete them if the user chooses "no"? (high probability for an error)

  2. Create a temporary table for ALL the data with the correct columns and then retrieve them from there in a next step?

  3. How would I pass all the $_POST data to a next step without loading them in the $_GET ? (this is what the ‘redirect’ function does)

  4. Could I keep the transaction alive and continue in another form? (right now when I do not perform a commit NOR a rollback no data is saved which is the same as a rollback, which seems like a logical implementation)

  5. Any other solution which I cannot think of right now? (session variables seem too much right?!)

Thank you!

Regarding transactions… as I wrote before…

You don’t save any data until all validations are OK… so you don’t initialize any transaction !

How to pass the data back to the view?

In the controller you create all 4 classes and assign them the $_POST data right?.. So you can just call render and all the data entered by the user is there

After a little research let me elaborate on my problem to make it more clear.

Before read thoroughly please do a skim read because I strongly believe that this matter has been already solved. Maybe a wiki which I cannot find ?..

No in fact I do not want to pass the data to the view. I do most of the job inside the controller.

Consider this scenario:

Fill form1 -> submit form1 -> textbox1 inside form1 has a value already inside the database -> redirect the user to form2 -> user submits "yes" (meaning that the textbox1 value in form1 is indeed valid) -> store all the data inside the database -> generate a report with the saved data back to the user

As you can see during the step "redirect the user to form2" all the data that the user has inserted are lost ! (the option to pass the data as a second parameter to the redirect function, in other words to use the $_GET, is NOT accepted)

After my little research I have found that there are two ways to save the data:

  1. Client side: use form elements which are hidden and store each previous step inside there (not very safe solution)

  2. Server side: use session variables to store the data on the server

Would you believe you could also save the data temporarily inside the database in some temporary table perhaps?

If you generalise it, is the problem where you have consecutive forms and you only want to save the data at the last form

Does Yii framework offers a solution about this situation as I have seen in some java frameworks?

If there is already a solution, just send me a link of it.

Thanks again for your time! Maybe if there isn’t one, it is time to write a wiki about this ;)

You could store all the data in a temporary table, in the session for the user or anyplace you like and then pull it at each stage that you receive new data from the user, OR you could pass the data back to each form as you draw it and re-post it each time … it absolutely depends on how your models are set up and how they’re related.

If you’re wanting to keep the data in those form fields, then I believe you do in fact want to send the data back to the view, if you want your data to render within the view again in your hidden fields, then you have to pass it back to be drawn in them. It has nothing to do with using $_GET. If you’re using separate actions for each portion of the display, then you could either store the model to the controller and use $this->forward(‘nextaction’) OR you could store your model to the user’s session and use the $this->redirect();

The core of the problem is how the data is related to one another. It sounds like you really are treating it as several distinct models, and you need to think of storing each step and providing a key to access the previously stored data to the next form.

Have you looked in the wiki at stateful forms?

Check if any of these can help:

http://www.yiiframework.com/extension/wizard-behavior

http://www.yiiframework.com/extension/simpleworkflow

/Tommy

Then again… If I understood you right… your problem is that a user could enter some value that is already in the database…

If you set a validator that will check this… the validation would fail… no data would be saved…

Thanks everybody for the help!

A quick answer to mdomba: The only difference is that even if it fails I still want to use the existing model

In other words, either inserting a new record in the database or using the existing record works just fine. I just want to tell the user to be aware that he is filling information related to a model that already exists :)

Dana: I understand what you said about that all models are related to each other. I could in fact use the id of the model with which all the other models are related but this model has an id which is created only after insertion to the table. Yep! it is an auto_increment column and the fact is that saving to the database is wrong at this point. I would first like to check that all the data from all models are ok and then save them at the end.

Many thanks to Tri since the "wizard" is what I was looking for. And one more thank you since the simple workflow seems like an extension which will come in hand in the near future.

In fact I have a workflow in my current project, which is not modelled in any other way than just by using foreign keys between the tables to ensure the existence of the previous step before proceeding to the new one :P

Thankfully this more complex functionality that the simple workflow extesions offers is not necessary in this project.

PS: How could I notify the participants of the current thread that I have posted a new one? (except the obvious way to post a link, which I believe is not an accustomed to do this)

There is no other way than posting the link… but that is bad practice…

Anybody reading the forum… will see your new post…