May 29, 2013

Expanding CakePHP multistep forms with dynamic fields and serialized data

As a sequel to the post about multistep forms with CakePHP, I’d like to add a little bit of complexity to that sample. This time we’ll add some dynamically generated fields and, in general, serialized data.

Dynamically generated fields can be used, for example, when the name and type of the fields is not known in advance, and therefore cannot be hardcoded in the script. Another situation where serialized data is a good solution is when you have a form with lots of fields for whose you don’t want/need to create the relative database field.
The process of asking input to the user (output the input/select tags) is usually not a big issue. How to store that data may be a little harder decision. There are various ways to resolve this kind of situation: for example, you could create a database table to hold field label and value as two distinct fields or, and this is what this post is about, you can create a field in your model that stores serialized data.
The choice heavily depends on the project complexity and usage of the data. If you need to query the table using one of the fields that has been serialized, this is surely not the best solution.

What is serialized data

PHP provides a function, called serialize(), to convert array/objects (or any other variable) into a plain text string and vice versa, using unserialize(). This means that you can save an array as a string into a database (or send to another application), and that data can be retrieved like any other field, and converted back to the same original array. It’s the same concept as JSON.
Since CakePHP stores each form submission as an array, we can easily convert some of the fields into a serialized string and store that in the database. When we need to retrieve that data (eg. when editing), we just need to unserialize it and pass to the form.

Model: a longtext to store serialized data

To keep this post simple and focused on the concept, let’s suppose we want to add ten text fields to Step 4 of the multistep form example. In each field the user can enter one of his interests. On the model part, this doesn’t need much explanation: add a longtext field in your database table to store the serialized string.

View: fields output

In the view, generate the fields with some code like this:
for ($i = 0; $i <10; $i++) {
    echo $this->Form->input('serial_data.Interest_'.$i);
}
The dot between serial_data and Interest_n makes each interest field a value of the serial_data array. In other words, when the user submits the form, the serial_data field will be passed as an array containing all the values of the Interest_n fields. This is a key feature when dealing with serialized data: you can create any number of “sub fields” that can easily be stored and retrieved from the database.

Controller: serialize and unserialize

To convert our array into a string, we’ll use the serialize() function right before saving to the database:
$currentSessionData['User']['serial_data'] = serialize($currentSessionData['serial_data']);
$this->User->save($currentSessionData);
$this->Session->setFlash('Account created!');
$this->redirect('/users/msf_index');
Check your serial_data field in the database and you should see a string like this:
a:10:{s:10:"Interest_0";s:1:"a";s:10:"Interest_1";s:1:"b";s:10:"Interest_2";s:1:"c";s:10:"Interest_3";s:1:"d";s:10:"Interest_4";s:1:"e";s:10:"Interest_5";s:1:"f";s:10:"Interest_6";s:1:"h";s:10:"Interest_7";s:1:"i";s:10:"Interest_8";s:1:"l";s:10:"Interest_9";s:1:"m";} 
 When you need to display that data, use the unserialize function:
$user = $this->User->findById($id);
$user['User']['serial_data'] = unserialize($user['User']['serial_data']);
 That’s all. These are the basics of serialized data handling in CakePHP. If you liked this post, please share and follow me on Facebook!

No comments:

Post a Comment