Framework: [5.4] Methods for updating/inserting related (attach, updateExistingPivot etc.) models don't honor the pivot casts

Created on 28 Mar 2017  路  6Comments  路  Source: laravel/framework

  • Laravel Version: 5.4.16
  • PHP Version: 7.0.16
  • Database Driver & Version: MariaDB 10.2.4

Description:

I opened issue #18135 a while back regarding the casts property on custom pivot not being properly honored. This problem was fixed in 5.4.14 by using fromRawAttributes in the newPivot method of \Illuminate\Database\Eloquent\Model.

However, it was pointed out to me recently that the methods used to conveniently update/insert related models, particularly those for BelongsToMany relationships that allow the user to provide the attributes for the pivot (attach, sync, syncWithoutDetaching, save, updateExistingPivot etc.) do not honor the casts property on the custom pivot model.

Steps To Reproduce:

Client model

class Client extends Model
{
    public function networks()
    {
        return $this->belongsToMany(Network::class)
            ->using(ClientNetworkPivot::class)
            ->withPivot(['settings']);
    }
}

Network model

class Network extends Model
{
    public function clients()
    {
        return $this->belongsToMany(Client::class)
            ->using(ClientNetworkPivot::class)
            ->withPivot(['settings']);
    }
}

ClientNetworkPivot

class ClientNetworkPivot extends Pivot
{
    protected $casts = [
        'settings' => 'array'
    ];
}

Steps

$client = Client::find(1);
$network = Network::find(1);

$client->networks()->attach($network, [
    'settings' => ['This', 'is', 'an', 'array']
]);

$client->networks()->sync([
    1 => ['settings' => ['This', 'is', 'an', 'array']]
]);

$client->networks()->syncWithoutDetaching([
    2 => ['settings' => ['This', 'is', 'an', 'array']]
]);

$client->networks()->save($network, [
    'settings' => ['This', 'is', 'an', 'array']
]);

$client->networks()->updateExistingPivot(3, [
    'settings' => ['This', 'is', 'an', 'array']
]);

Expected results

In all of the above examples I would expect to see the attributes array passed into each method, have their respective casts honored. In this instance I would have expected to see the ['This', 'is', 'an', 'array'] array for the settings cast to JSON and be inserted/updated in the database.

Actual results

In every example above I get the same QueryException error:

Array to string conversion (SQL: insert into client_network (client_id, created_at, network_id, settings, updated_at) values (1, 2017-03-28 09:36:02, 1, This, 2017-03-28 09:36:02))`

bug

Most helpful comment

Fixing in 5.5.

All 6 comments

I second that there's an issue: In my case I'm using 2 models that use strings as IDs (varchar in database).

I'm attempting to use $myModel->theRelationship()->sync(["10212624279364351")] it attempts to save it as a string rather than respect the $keyType. I have even attempted it with the $casts.

Also if it's of any use when I create the relationship manually with ::create([...]); there's no problem at all

Thanks for opening this, @jrhenderson1988. Can confirm this behavior; it would be nice to have attach-ability on pivot models that respects the casts array.

Having the same issue.. Trying to set an array on the pivot model. Got the same error saving it.

Same issue here; I have an array on the pivot model, which I'm currently having to json_encode manually because of this. Would be great to just use casts like standard models.

Fixing in 5.5.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

CupOfTea696 picture CupOfTea696  路  3Comments

shopblocks picture shopblocks  路  3Comments

iivanov2 picture iivanov2  路  3Comments

RomainSauvaire picture RomainSauvaire  路  3Comments

gabriellimo picture gabriellimo  路  3Comments