覆盖强制转换方法,无法保存到数据库

I have below model:

Document.php

/**
 * Get all of the documents field content.
 *
 * @return Illuminate\Database\Eloquent\Model
 */
public function fields()
{
    return $this->morphToMany(Field::class, 'fieldable')
    ->using('App\FieldablePivot')
    ->withPivot(['content', 'type'])
    ->withTimestamps();
}

public function cropped()
{
     return $this->hasMany(CroppedDocumentField::class);
}

So in my fieldables table, I have a content and type column. The content can be either an array or a string. This is determinted by the type column.

In order to make sure that Laravel casts the correct type when getting the data, I use below code on the FieldablePivot model:

public function hasCast($key, $types = null)
{
    if ($key === 'content') {
        return true;
    }
    return parent::hasCast($key, $types);
}

protected function getCastType($key)
{
    if ($key == 'content' && !empty($this->type)) {
        return $this->type;
    }
    return parent::getCastType($key);
}

Now when I do:

foreach($document->fields as $field){
       dd($field->pivot->content);
}

It returns either an array or string.

However, when I want to save data to the database, like:

$document->cropped()->create([
   'field_id' => 8,
   'content' => "A string",
   'type' => 'string'
]);

I get below error:

A four digit year could not be found Data missing

The issue is that your hasCasts() override is not taking into account the $types passed in. This causes Laravel to believe that your content attribute can be cast to a date (isDateCastable() will always return true for content), which it attempts to do and fails.

To avoid this, you could just override the getCasts() method instead of the hasCast() and getCastType() methods.

public function getCasts()
{
    $casts = parent::getCasts();

    // Add your dynamic cast type to the returned $casts array.
    if (!empty($this->type)) {
        $casts['content'] = $this->type;
    }

    return $casts;
}

Now all the other functions will behave as if your content attribute were added to the model's casts array.

You could also attempt to use model mutators and accessors, however you would end up having to write the casting functionality yourself, and I don't know if mutators and accessors are taken into account on pivot tables.