Traits with PhP and Laravel -


i using laravel 5.1 , access array on model trait when model before model uses appends array.

i add items appends array if exists trait. don't want edit model in order achieve this. traits usable in scenario or should use inheritance?

array_push($this->appends, 'saucedbycurrentuser'); 

here how current setup works.

trait

<?php namespace app;  trait awesomesaucetrait {    /**    * collection of sauce on record    */   public function awesomesauced()   {     return $this->morphmany('app\awesomesauce', 'sauceable')->latest();   }   public function getsaucedbycurrentuserattribute()   {     if(\auth::guest()){         return false;     }     $i = $this->awesomesauced()->whereuserid(\auth::user()->id)->count();     if ($i > 0){         return true;     }     return false;   } } 

model

<?php namespace app;  use app\awesomesaucetrait; use illuminate\database\eloquent\model;  class fairlyblandmodel extends model {     use awesomesaucetrait;      protected $appends = array('age','saucedbycurrentuser');  } 

what achieve same effect extending class. have few similar traits, using inheritance gets ugly.

trait awesomesaucetrait {  function __construct() {      parent::__construct();      array_push($this->appends, 'saucedbycurrentuser');  } } 

i have seen workarounds this, none of them seem better/cleaner adding item array manually. ideas appreciated.

update


i discovered way of accomplishing need 1 trait, works 1 trait , don't see advantage of using on inheritance.

trait

protected $awesomesauceappends = ['sauced_by_current_user'];  protected function getarrayableappends() {     array_merge($this->appends, $this->awesomesauceappends);     parent::getarrayableappends(); } 

how handling model, worth.

model

public function __construct() {     array_merge($this->appends, $this->awesomesauceappends); } 

traits described "compiler-assisted copy-and-paste"; result of using trait can written out valid class in own right. there therefore no notion of parent in trait, because once trait has been applied, methods indistinguishable defined in class itself, or imported other traits @ same time.

similarly, the php docs say:

if 2 traits insert method same name, fatal error produced, if conflict not explicitly resolved.

as such, not suitable situations want mix in multiple variants of same piece of behaviour, because there no way base functionality , mixed in functionality talk each other in generic way.

in understanding problem you're trying solve this:

  • add custom accessors , mutators eloquent model class
  • add additional items protected $appends array matching these methods

one approach continue use traits, , use reflection dynamically discover methods have been added. however, beware reflection has reputation being rather slow.

to this, first implement constructor loop can hook naming method in particular way. can placed trait of own (alternatively, sub-class eloquent model class own enhanced version):

trait appendingglue {   public function __construct() {     // parent refers not class being mixed into, parent     parent::__construct();      // find , execute methods beginning 'extraconstruct'     $mirror = new reflectionclass($this);     foreach ( $mirror->getmethods() $method ) {       if ( strpos($method->getname(), 'extraconstruct') === 0 ) {         $method->invoke($this);       }     }   } } 

then number of traits implementing differently named extraconstruct methods:

trait awesomesauce {   public function extraconstructawesomesauce() {     $this->appends[] = 'awesome_sauce';   }    public function doawesomesaucestuff() {   } }  trait chocolatesprinkles {   public function extraconstructchocolatesprinkles() {     $this->appends[] = 'chocolate_sprinkles';   }    public function dochocolatesprinklesstuff() {   } } 

finally, mix in traits plain model, , check result:

class basemodel {   protected $appends = array('base');    public function __construct() {     echo "base constructor run ok.\n";   }    public function getappends() {     return $this->appends;   } }  class decoratedmodel extends basemodel {   use appendingglue, awesomesauce, chocolatesprinkles; }  $dm = new decoratedmodel; print_r($dm->getappends()); 

we can set initial content of $appends inside decorated model itself, , replace basemodel definition, not interrupt other traits:

class redecoratedmodel extends basemodel {   use appendingglue, awesomesauce, chocolatesprinkles;    protected $appends = ['switched_base']; } 

however, if over-ride constructor @ same time mixing in appendingglue, need bit of work, discussed in previous answer. it's similar calling parent::__construct in inheritance situation, have alias trait's constructor in order access it:

class reconstructedmodel extends basemodel {   use appendingglue { __construct private appendingglueconstructor; }   use awesomesauce, chocolatesprinkles;    public function __construct() {     // call mixed-in constructor explicitly, parent     // note call real parent well, though grand-parent     $this->appendingglueconstructor();      echo "new constructor executed!\n";   } } 

this can avoided inheriting class either exists instead of appendingglue trait, or uses it:

class gluedmodel extends basemodel {   use appendingglue; } class reconstructedgluedmodel extends gluedmodel {   use awesomesauce, chocolatesprinkles;    public function __construct() {     // standard call parent constructor     parent::__construct();     echo "new constructor executed!\n";   } } 

here's live demo of of put together.


Comments

Popular posts from this blog

PHP DOM loadHTML() method unusual warning -

python - How to create jsonb index using GIN on SQLAlchemy? -

c# - TransactionScope not rolling back although no complete() is called -