In a block controller, concrete5 takes care of storing and retrieving simple data items like numbers or strings automatically. But what can you do with arrays?
First off, to create an array in the $_POST
data an html form should declare a list of values (You need to imagine a 'less than' angle bracket preceding the 'input' as an html tag. At the time of the current update, the markdown editor will not accept 'less than' or translate the escape code for it):
< input name="my_array[]" ...>
< input name="my_array[]" ...>
< input name="my_array[]" ...>
Wherever PHP sees "[]
" in an input name, it will automatically be converted to an array. This is a php thing, not a concrete5 thing.
So in a block save()
method, you can get the php array as:
public function save($data){
$my_array = $data['my_array'];
}
Or as:
public function save(){
$my_array = $_POST['my_array'];
}
Now we need to save this array into our block database table. Because database tables have a fixed number of columns, we have 2 basic strategies available.
Have a second table associated with the block where each element of
$my_array
has its own row of the second table.Turn
$my_array
into something that fits into a single column of the main block table, perhaps an 'X' or 'X2' column ``
Option (1) is certainly the purest solution, but it involves a lot of code. Not just code to save and retrieve the data, you need code to handle whenever there is a new block version and code to handle when the block is copied or deleted to keep the secondary table in step.
So, unless you actually need to search for and work with individual items of secondary data, (2) is usually an option that involves a lot less work and has the advantage that the array of data will always be matched to its parent block by concrete5.
The process of turning an array into a string is called serialisation. Turning it back again is called unserialisation. Php provides a matched set of serialize() / unserialize() functions that know about php data structures and can do this easily for us.
public function save($data){
$data['my_array'] = serialize($data['my_array']);
parent::save($data);
}
Then, at the bottom of the save()
method, we call the parent::save()
method to take care of actually saving $data
into the database. If we didn't have our own save()
method, the parent method would be called anyway by object inheritance. Because we have our own save()
method, we now have to make sure the parent is called.
In the edit()
and view()
methods, we then need to do the reverse, so the edit.php and view.php will receive actual arrays.
public function edit(){
$this->set('my_array', unserialize($this->my_array));
}
public function view(){
$this->set('my_array', unserialize($this->my_array));
}
Its not quite that simple; we also need to handle the case of empty arrays, usually by including a condition in the save()
method and/or conditions in the edit()
and view()
methods to create empty arrays.
The php seriaze()
and unserialize()
functions are not the only way to handle such data. Simple data can be imploded and exploded with implode() and explode()
$my_string = implode(',',$my_array);
$my_array = explode(',', $my_string);
The separator can be any character or string, just as long as you are consistent and it does not appear naturally in your data. The pipe character '|', colons ':', semicolons';' and newlines '\n' are also commonly used.
For more complex data we can also use JSON, JavaScript Object Notation. Php has native JSON commands, but in concrete5 you should use the JSON helper.
$jh = Loader::helper('json');
$my_json_string = $jh->encode($my_array);
$my_array = $jh->decode($my_json_string, true);
In concrete5.6.2+, the second 'true
' parameter to decode tells it to return an array rather than an object. For earlier versions of concrete5 you will need to turn the object back into an array as described in Converting JSON to an array.
Despite the apparent complexity, JSON comes in useful when JavaScript is using your data or it is being communicated with other systems because JSON is a universal format.