Framework: [5.1] Custom pivot $casts

Created on 8 Oct 2015  路  15Comments  路  Source: laravel/framework

My project laravel version is v5.1.19.

I think this issue is related to #8972.

class Custom extends Pivot
{
    protected $casts = [
        'json' => 'array',
    ];
}

class User extends Model
{
    public function products()
    {
        return $this->belongsToMany(Product::class)->withPivot('json');
    }

    public function newPivot(Model $parent, array $attributes, $table, $exists)
    {
        if ($parent instanceof Product) {
            return new Custom($parent, $attributes, $table, $exists);
        }

        return parent::newPivot($parent, $attributes, $table, $exists);
    }
}

class Product extends Model
{
    public function users()
    {
        return $this->belongsToMany(User::class)->withPivot('json');
    }

    public function newPivot(Model $parent, array $attributes, $table, $exists)
    {
        if ($parent instanceof User) {
            return new Custom($parent, $attributes, $table, $exists);
        }

        return parent::newPivot($parent, $attributes, $table, $exists);
    }
}

$user = User::find(1);
$product = $user->products->first();

$json = $product->pivot->json;
# Expect array ['category' => 'sample']
# Result string {"category":"sample"}

Thanks.

Most helpful comment

I have also found this to not be working. Laravel Framework version 5.3.

Example of what I am doing:

class Round extends Model
{
    /**
     * @var string
     */
    protected $table = 'rounds';

    /**
     * @var array
     */
    protected $casts = [
        'emailTemplates.pivot.send_at' => 'date',
    ];

    /**
     * Relation to EmailTemplate(s) tied to a given board round
     *
     * @return \Illuminate\Database\Eloquent\Relations\belongsToMany
     */
    public function emailTemplates()
    {
        return $this->belongsToMany('App\Models\EmailTemplate', 'rounds_email_templates')
            ->withPivot('send_at', 'status')
            ->withTimestamps();
    }
}

This does not recognize that send_at should be a date. Keeps getting passed as a string.

All 15 comments

I don't think this is intended to work?

You need to put the casts on the Product class.

@GrahamCampbell But the attribute is in the pivot.

This is a valid issue.

Would be great if we could do something like this in parent model:

class Campaign extends Model {

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = ['providers.pivot.json_field' => 'array'];

    /**
     * Define a many-to-many relationship.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
     */
    public function providers()
    {
        return $this->belongsToMany(Provider::class, 'campaign_providers', 'campaign_id', 'provider_id')->withPivot('json_field');
    }
}

Fixed.

the problem continues: Laravel Framework version 5.2.45

I have also found this to not be working. Laravel Framework version 5.3.

Example of what I am doing:

class Round extends Model
{
    /**
     * @var string
     */
    protected $table = 'rounds';

    /**
     * @var array
     */
    protected $casts = [
        'emailTemplates.pivot.send_at' => 'date',
    ];

    /**
     * Relation to EmailTemplate(s) tied to a given board round
     *
     * @return \Illuminate\Database\Eloquent\Relations\belongsToMany
     */
    public function emailTemplates()
    {
        return $this->belongsToMany('App\Models\EmailTemplate', 'rounds_email_templates')
            ->withPivot('send_at', 'status')
            ->withTimestamps();
    }
}

This does not recognize that send_at should be a date. Keeps getting passed as a string.

I have the same issue as @diogoazevedos, using Laravel v5.3.22.
Having a custom pivot (App\Models\MemberPanelPivot), with a

protected $casts = [ 'custom_fields' => 'array' ];

the field still comes through as string, and not as array:

       App\Models\Panel {#915
         id: "197534e2-25c9-40d5-a601-a21f670ea9fd",
         customer_id: "0a01e4d9-585e-49e1-92f6-9ce3506daaea",
         created_at: "2016-11-08 12:23:48",
         updated_at: "2016-11-08 12:23:48",
         pivot: App\Models\MemberPanelPivot {#894
           member_id: "79b0dc9e-c0e6-4d4c-8cb5-de81da6c288b",
           panel_id: "197534e2-25c9-40d5-a601-a21f670ea9fd",
           custom_fields: "{}",
           created_at: "2016-11-08 12:23:50",
           updated_at: "2016-11-08 12:23:50",
         },
       },

@taylorotwell , can you elaborate please, what was fixed?
It's a bit ambiguous :)

Cheers, Sebi

I'm having the same issue as @diogoazevedos --- problem does not appear to be fixed. I have a custom pivot that:

    protected $casts = [
        'data' => 'array'
    ];

However data returns a json string instead of a php array when I access that pivot:

$user->roles->first()->pivot->data;

# Expect: array ['test' => 'serialization']

# Actual: string {"test":"serialization"}

Hi,
I am using laravel 5.3
Is that working with sync?

Same issue here in 5.3.28. I am trying to cast data on a pivot to an array (JSON). Can't get it to work. A bit frustrating. What was fixed?

@taylorotwell what was fixed and how is it used?

If you use a custom Pivot model and cast the specific attribute, it works.

Consider this relation. A category belongs to many items.

Example of relation Category model:

// Inside Category model
public function items(): BelongsToMany
{
    return $this->belongsToMany(Item::class)
        ->using(CategoryItem::class)
        ->withPivot('provider_data')
        ->withTimestamps();
}

The custom pivot model would then look like this:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Relations\Pivot;

class CategoryItem extends Pivot
{
    /** @var array */
    protected $casts = [
        'provider_data' => 'array',
    ];
}

Was this page helpful?
0 / 5 - 0 ratings

Related issues

robjbrain picture robjbrain  路  64Comments

Demers94 picture Demers94  路  88Comments

thewinterwind picture thewinterwind  路  63Comments

nkeena picture nkeena  路  75Comments

mnpenner picture mnpenner  路  72Comments