How To Cast Eloquent Pivot Parameters?

前端 未结 5 1871
萌比男神i
萌比男神i 2020-12-14 08:11

I have the following Eloquent Models with relationships:

class Lead extends Model 
{
    public function contacts() 
    {
        return $this->belongsTo         


        
5条回答
  •  不思量自难忘°
    2020-12-14 08:34

    The answer provided by @patricus above is absolutely correct, however, if like me you're looking to also benefit from casting out from JSON-encoded strings inside a pivot table then read on.

    The Problem

    I believe that there's a bug in Laravel at this stage. The problem is that when you instantiate a pivot model, it uses the native Illuminate-Model setAttributes method to "copy" the values of the pivot record table over to the pivot model.

    This is fine for most attributes, but gets sticky when it sees the $casts array contains a JSON-style cast - it actually double-encodes the data.

    A Solution

    The way I overcame this is as follows:

    1. Set up your own Pivot base class from which to extend your pivot subclasses (more on this in a bit)

    2. In your new Pivot base class, redefine the setAttribute method, commenting out the lines that handle JSON-castable attributes

    class MyPivot extends Pivot {
      public function setAttribute($key, $value)
      {
        if ($this->hasSetMutator($key))
        {
          $method = 'set'.studly_case($key).'Attribute';
    
          return $this->{$method}($value);
        }
        elseif (in_array($key, $this->getDates()) && $value)
        {
          $value = $this->fromDateTime($value);
        }
    
        /*
        if ($this->isJsonCastable($key))
        {
          $value = json_encode($value);
        }
        */
    
        $this->attributes[$key] = $value;
      }
    }
    

    This highlights the removal of the isJsonCastable method call, which will return true for any attributes you have casted as json, array, object or collection in your whizzy pivot subclasses.

    3. Create your pivot subclasses using some sort of useful naming convention (I do {PivotTable}Pivot e.g. FeatureProductPivot)

    4. In your base model class, change/create your newPivot method override to something a little more useful

    Mine looks like this:

    public function newPivot(Model $parent, array $attributes, $table, $exists)
    {
      $class = 'App\Models\\' . studly_case($table) . 'Pivot';
    
      if ( class_exists( $class ) )
      {
        return new $class($parent, $attributes, $table, $exists);
      }
      else
      {
        return parent::newPivot($parent, $attributes, $table, $exists);
      }
    }
    

    Then just make sure you Models extend from your base model and you create your pivot-table "models" to suit your naming convention and voilà you will have working JSON casts on pivot table columns on the way out of the DB!

    NB: This hasn't been thoroughly tested and may have problems saving back to the DB.

提交回复
热议问题