During development of a module for DRUPAL I met some problems
with generation of 'Preview' of a node. The following text is not
call for support cause I solved my problem (I'll discuss the
solution later) but it is rather discussion of the 'Preview'
problem generally.
The problem with preview seem to be deeper than you think at first sight. See for example:
http://drupal.org/node/104047
http://drupal.org/node/109204
Personally I think that the problem is that the Preview generation is slightly inconsistent with the generation of node's view. I will try to explain this on the real problem I met during last days.
The task is:
The format of the data the user enter/see is different from the format in which the data are stored in database.
- I have a field with number of players (
nop). - The user should enter something like this '1, 2, 6'
- Then the data should be converted into the number, where every number of player is represented by the value of corresponding bit, thus for the previous example the conversion should produce b'00100011'=35
- The data are stored in database as integer
- For node-view purposes the data needs to be converted back into the human readable form
If you don't use 'Preview' everything is - I think - perfectly designed:
- When you submit the node then the
hook_submitis called first. There you plug the conversion of the data. - Afterwards either
hook_insertorhook_updateprovide the real save of the data into the database. During this stepnopis already number. - If you go to edit/add page of the node then at first step
hook_loadis called and thenhook_prepareshould make conversion as is recommended by documentation (see e.g. http://drupal.org/node/71962). -
hook_prepareis provided only for purposes of editing not viewing. Thus if you 'View' existing node, then after load of node byhook_loadthehook_viewhas to do its own conversion suitable to view the node.
And now we come to the problematic point! From the first point of view this model could seem strange. Why the hook_prepare is not called before hook_view?
But this design is really great. It allows separate the data representation for the purposes of value entering and how they are presented to a reader.
Moreover, the hook_prepare is much more powerful than you think. It does not have to only manipulate loaded data but (see for example image.module) it can be used, e.g., for files upload.
The inconsistent part of this model is - as I think - the preview mode. What happens when you 'click' button 'Preview'?
- the form is sent
- the
hook_submitandhook_insert(hook_update) are skipped - then
hook_loadis invoked and followed byhook_prepare. But! But 'prepare operations' are performed for "old" data (from database) and these are overwritten with new data. -
These data are sent to
hook_view.
What happens in our real example:
- Enter new value, let say '2,4' and press 'Preview button. The form is sent.
- The
hook_loadloads data from database, i.e., 35 (see example above). - The
hook_preparethen converts number to '1, 2, 6' - But finally the data are updated with the values from the form (sorry, I don't know which function performs this exactly), thus the value of
nopis '2, 4'. - Finally the
hook_viewinvokes rendering. But the view function normally suppose that the provided data are from database and thehook_preparedoes not make conversion. Thushook_viewmake conversion for it selves which is not made for valid data becausenopcontains string '2, 4' instead of number!
Solution:
This could be solved, sure. For example you can test whether you are in preview mode by testing $node->in_preview (function node_preview set this variable). E.g. if you are in preview node don't make conversion in hook_view:
if ((!isset($node->in_preview)) || !($node->in_preview)) {
$node->nop=_number_to_nop($node->nop);
}
Discussion:
- I don't know right know how to solve this problem according to DRUPAL's module philosophy. I think that for 'Preview' must be simulated complete process made during submit. But its really waste of resources to do fake writings to database.
- At the first, it seems
hook_prepareandhook_submitcould solve the problem. But as I said already. They can perform other tasks then then data conversion from/to database. - Finaly, I'm not really sure that the solution I have proposed is optimal. From one point of view it is simple but on the other hand I feel that it is somehow fragile ...
By the way, thanks to this problem I understand the DRUPAL's core much more better ;] But that it prise lot of hours of code reading ;]]
Alladjex }I{
Comments
DRUPAL version 4.7.6
I'm sorry. I forgot to mention that I'm running DRUPAL 4.7.6 (and testing v. 5). But the text is mainly based on the study of v. 4.7.6