#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 tickets-cakephp@googlegroups.com To unsubscribe from this group, send email to tickets-cakephp+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/tickets-cakephp?hl=en -~----------~----~----~----~------~----~------~--~---