Friday, April 19, 2013

Re: How to modify a field in afterFind()

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 <matt.hugg...@gmail.com> 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, "martin.westin...@gmail.com"
>
> <martin.westin...@gmail.com> 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 <matt.hugg...@gmail.com> 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, "martin.westin...@gmail.com"
>
> > > <martin.westin...@gmail.com> 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, "martin.westin...@gmail.com"
>
> > > > <martin.westin...@gmail.com> 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 cake-php+unsubscribe@googlegroups.com.
To post to this group, send email to cake-php@googlegroups.com.
Visit this group at http://groups.google.com/group/cake-php?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

No comments: