I just wanted to thank both of you for working through this and figuring it out. Nearly five years later, CakePHP still has this issue with version 2 and this code worked flawlessly. You guys rock!
On Wednesday, December 17, 2008 1:04:52 PM UTC-5, Martin Westin wrote: > > thanks for the modifications. I am happy it works for you too. > > /Martin > > On Dec 17, 5:56 pm, Matt Huggins <[email protected]> wrote: > > Your solution worked flawlessly! I ended up making two small > > changes. First, I changed your references for 'id' to $this->primaryKey > so that it can work with any model. Second, I put the > > > > afterFind/_afterFind into app_model.php so that it will call the > > doAfterFind of any model that implements it, as per the following: > > > > class AppModel extends Model { > > /** > > * sigh... $primary doesn't work as designed in CakePHP RC2 :( > > * this hack will manually go through and tear shit up > > */ > > public function afterFind($results, $primary = false) { > > if (method_exists($this, 'doAfterFind')) { > > if ($primary) { > > foreach ($results as $key => $val) { > > if (isset($val[$this->alias])) { > > > $results[$key][$this->alias] = $this->doAfterFind > > ($results[$key][$this->alias]); > > } > > } > > } else { > > if (isset($results[$this->primaryKey])) > { > > $results = > $this->doAfterFind($results); > > } else { > > foreach ($results as $key => > $val) { > > if > (isset($val[$this->alias])) { > > if > (isset($val[$this->alias][$this->primaryKey])) > > { > > > $results[$key][$this->alias] = $this->doAfterFind > > ($results[$key][$this->alias]); > > } else { > > foreach > ($results[$key][$this->alias] as $key2 > > => $val2) { > > > $results[$key][$this->alias][$key2] = > $this->doAfterFind($results[$key][$this->alias][$key2]); > > > > } > > } > > } > > } > > } > > } > > } > > return $results; > > } > > > > } > > > > On Dec 17, 5:36 am, "[email protected]" > > > > <[email protected]> wrote: > > > Hi Matt, > > > I ended up creating a special set of functions for this. > > > > > afterFind() calls _afterFind() > > > _afterFind() locates the data and calls doAfterFind() > > > > > This works for what I use afterFind for. > > > I will only have one place to edit if the data-structires change or I > > > find I have missed something. > > > It makes my models a lot more readable. > > > > > The relevant code if you should find it useful: > > > > > in SomeModel: > > > > > // this just calls the "real" afterFind > > > function afterFind($data, $primary) { > > > return $this->_afterFind($data, $primary); > > > > > } > > > > > // receives data as a flat array of fields, no Modelname or anything. > > > // run from _afterFind splits datetime-field sendat into senddate and > > > sendtime > > > function doAfterFind($data) { > > > > > if ( !isset($data['senddate']) ) { > > > $timestamp = strtotime($data['sendat']); > > > $data['senddate'] = date('Y-m-d', $timestamp); > > > $data['sendtime'] = date('H', $timestamp); > > > } > > > > > return $data; > > > > > } > > > > > // AppModel::_afterFind() > > > function _afterFind($data, $primary) { > > > > > if ( $primary ) { > > > > > foreach ( $data as $key => $val ) { > > > if ( isset($val[$this->alias]) ) { > > > $data[$key][$this->alias] = $this->doAfterFind( $data > > > [$key][$this->alias] ); > > > } > > > } > > > > > } else { > > > > > if ( isset($data['id']) ) { > > > $data = $this->doAfterFind( $data ); > > > } else { > > > > > foreach ( $data as $key => $val ) { > > > if ( isset($val[$this->alias]) ) { > > > if ( isset($val[$this->alias]['id']) ) { > > > $data[$key][$this->alias] = $this->doAfterFind > > > ( $data[$key][$this->alias] ); > > > } else { > > > foreach ( $data[$key][$this->alias] as $key2 > > > => $val2 ) { > > > $data[$key][$this->alias][$key2] = > $this->doAfterFind( $data[$key][$this->alias][$key2] ); > > > > > } > > > } > > > } > > > } > > > } > > > > > } > > > return $data; > > > > > } > > > > > On Dec 17, 12:55 am, Matt Huggins <[email protected]> wrote: > > > > > > I'm having the same issue, and I have yet to find a solution. The > > > > Cake documentation is wrong and/or the implementation is incorrect. > > > > > > On Oct 23, 1:58 am, "[email protected]" > > > > > > <[email protected]> wrote: > > > > > I compiled a list of the variations I have encountered in > different > > > > > associations. I have not checked how behaviors are called. > > > > > > > When primary is set this is the structure I get just as in the > > > > > Cookbook: > > > > > array( > > > > > '0' => array( > > > > > 'Model' => array( > > > > > 'id' => 1 > > > > > ) > > > > > ) > > > > > ) > > > > > > > When primary is not set I get a subset of these for each > association: > > > > > > > hasOne > > > > > array( > > > > > 'id' => 1 > > > > > ) > > > > > > > habtm > > > > > array( > > > > > '0' => array( > > > > > 'id' => 1 > > > > > ) > > > > > ) > > > > > > > hasOne, hasMany, belongsTo > > > > > array( > > > > > '0' => array( > > > > > 'Model' => array( > > > > > 'id' => 1 > > > > > ) > > > > > ) > > > > > ) > > > > > > > habtm, hasMany > > > > > array( > > > > > '0' => array( > > > > > 'Model' => array( > > > > > '0' => array( > > > > > 'id' => 1 > > > > > ) > > > > > ) > > > > > ) > > > > > ) > > > > > > > This makes the number of ifs and fors quite many in order the > catch > > > > > them all. And since more than one is sometimes called for the same > > > > > record in the same request, you also have to check is you have > already > > > > > manipulated your data. At least if you do something "destructive" > to > > > > > it like encryption/decryption or serialization. > > > > > > > My orignal question still stands. What is the best way to write an > > > > > afterFind in order to: 1. not miss converting data in some queries > 2. > > > > > not double-convert the data ? > > > > > > > regards, > > > > > /Martin > > > > > > > On Oct 22, 5:16 pm, "[email protected]" > > > > > > > <[email protected]> wrote: > > > > > > Hi, > > > > > > I thought I'd ask this here. (see why below) > > > > > > How do I write afterFind() to modify a field. > > > > > > > > For example just something simple like this (just an example): > > > > > > > > function afterFind($data) { > > > > > > foreach ($data as $key => $val) { > > > > > > if ( isset($val[$this->alias]['name']) ) { > > > > > > $data[$key][$this->alias]['name2'] = > $val[$this->alias] > > > > > > ['name']; > > > > > > } > > > > > > } > > > > > > debug($data); > > > > > > return $data; > > > > > > > > } > > > > > > > > What I want to know is how to pick out the field from the passed > data > > > > > > array. There are so many different ways the data is formatted > that I > > > > > > end up with a quite messy series of for's and if's and I still > don't > > > > > > fell 100% sure I got them all. I feel there must be some > sure-fire way > > > > > > to write these. > > > > > > > > The Cookbook is not complete compared to what I get. > http://book.cakephp.org/view/681/afterFind > > > > > > > > The API does not mention much about this. > > > > > > > > I did not find any test in the core that helped me. > > > > > > > > I did not find anything on Google that dealt with anything but > basic > > > > > > "primary" data. > > > > > > > > I noticed that sometimes afterFind() is called more than once > with > > > > > > different data-structure each time. I asked about that here: > http://groups.google.com/group/cake-php/browse_thread/thread/c83e5f40... > > > > > > > > I'd love some clarification of this callback. Thans in advance. > > > > > > /Martin -- Like Us on FaceBook https://www.facebook.com/CakePHP Find us on Twitter http://twitter.com/CakePHP --- You received this message because you are subscribed to the Google Groups "CakePHP" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at http://groups.google.com/group/cake-php?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
