#6276: afterFind() called twice / documentation does not match behaviour
--------------------------------------------------+-------------------------
Reporter: nemosoft | Type: RFC
Status: new | Priority: Medium
Milestone: 1.2.x.x | Component: Model
Version: 1.2 Final | Severity: Normal
Keywords: afterFind primary data corruption | Php_version: PHP 5
Cake_version: 8120 |
--------------------------------------------------+-------------------------
SUMMARY
[[BR]]
* With hasMany relations, afterFind() is called twice on the same
data.[[br]]
* The example given in the manual for afterFind() will mess up your
data.[[br]]
[[BR]]
DESCRIPTION[[BR]]
I would like to have your opinion on the following problem I've
encountered using Model::afterFind(). It is the combination of afterFind's
behaviour and the documentation in the manual that causes corruption of
the data that is being read with a hasMany relation.[[BR]]
[[BR]]
See the attached example of a simple Tutor/Pupil/Course database. A Tutor
hasMany Pupils, and also hasMany Courses. When reading in a Tutor, Pupils
and Courses are automatically read as well, and their data is passed
through their respective afterFind() functions *twice*. Or rather,
afterFind() is called once for each individual record (the first pass),
and once more wtih all data combined (second pass). The problem is that
the data layout differs subtly between the first and second pass. The
second pass has the same data one layer deeper; if one follows blindly the
example given in the manual (http://book.cakephp.org/view/681/afterFind)
as I did, the data will be messed up during the second pass.[[BR]][[BR]]
The first pass formats data like this:
{{{
$results = array { [0] { [Pupil] { [id], [name], [tutor_id] } } }
}}}
This is called for each record retrieved from the database.[[BR]]
The second pass uses all data in a combined format:
{{{
$results = array { [0] { [Pupil] { [0] { [id] [name] [tutor_id] }, [1] {
... }, [2] { ... } } } }
}}}
In both cases, the $primary boolean is set to false.
[[BR]]
[[BR]]
There are multiple issues with this behaviour:
- Essentially the same data is passed twice through afterFind(); this is
inefficient and can introduce side effects (see below)[[BR]]
- It both cases $primary is false, but the data is in a different layout.
Moreover, it does not match the documentation!
[[BR]][[BR]]
Others have noticed this anomolous behaviour, see for example
[http://groups.google.com/group/cake-
php/browse_thread/thread/c83e5f40ac861caa/1d88bdb31fa3d12f?lnk=gst&q=afterFind#1d88bdb31fa3d12f
this Google Groups post] and [http://groups.google.com/group/cake-
php/browse_thread/thread/4b10a1d5ccd468d9/fb225acbdac9109d?lnk=gst&q=afterFind#fb225acbdac9109d
this one].
[[br]]
[[br]]
Some people have suggested solutions, like [http://groups.google.com/group
/cake-
php/browse_thread/thread/d1eea174c3143d83/6bada5f9fce6f714?lnk=gst&q=afterFind#6bada5f9fce6f714
this one] but in that case the data is processed twice. This could lead to
weird data behaviour, for example if one converts dates from database to
human format by string manipulation, concatenates strings, adds numbers,
etc. I've used a rot13() function in my example.
[[br]]
[[br]]
I think the behaviour stems from fixes for another problem where
afterFind() was not called at all for recursive retrievals (for example,
see changeset 7347). Now it's being called too many times.[[br]][[br]]
My questions are:[[br]]
* Is the observed behaviour of calling afterFind() twice intended? If so,
what's the reason behind passing different data layouts?[[br]]
* Could somebody please update the documentation for afterFind()? Either
mention that the function is called twice with hasMany relations, or fix
the example so that it won't work on the second pass.[[br]][[br]]
I'm of the opinion that the second call to afterFind() is an error. It
would make sense to process each record as it is being retrieved, but not
do it again on the combined data set. The former would also eliminate the
distinction between primary and non-primary retrievals, since the data
layout is the same now (my observation).[[br]][[br]]
Of course, a workaround would be to ignore the second pass, but I don't
think that burden should be placed on the developer...
--
Ticket URL: <https://trac.cakephp.org/ticket/6276>
CakePHP : The Rapid Development Framework for PHP <https://trac.cakephp.org/>
Cake is a rapid development framework for PHP which uses commonly known design
patterns like ActiveRecord, Association Data Mapping, Front Controller and MVC.
Our primary goal is to provide a structured framework that enables PHP users at
all levels to rapidly develop robust web applications, without any loss to
flexibility.
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"tickets cakephp" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/tickets-cakephp?hl=en
-~----------~----~----~----~------~----~------~--~---