Laravel定制模型演员

时间:2016-09-26 20:08:58

标签: laravel laravel-5 eloquent

除了内置的模型演员之外,Laravel还有一种方法可以添加自己的自定义模型演员吗?

目前我可以使用getter和mutators但这些最终会在很多字段中重复出现。

3 个答案:

答案 0 :(得分:8)

所以我最终走下Traits路线以覆盖各种模型方法,结果证明不是因为属性转换已经深深植入模型的工作方式。

为了使这项工作适用于最常见的情况,即能够轻松添加自定义强制转换,需要对模型进行相当大的重写。

这是我写的添加时间表的特性:

<?php

namespace App\Models;

use Carbon\Carbon;

trait CustomCasts
{
    /**
     * Cast an attribute to a native PHP type.
     *
     * @param  string  $key
     * @param  mixed  $value
     * @return mixed
     */
    protected function castAttribute($key, $value)
    {
        if (is_null($value)) {
            return $value;
        }

        switch ($this->getCastType($key)) {
            case 'int':
            case 'integer':
                return (int) $value;
            case 'real':
            case 'float':
            case 'double':
                return (float) $value;
            case 'string':
                return (string) $value;
            case 'bool':
            case 'boolean':
                return (bool) $value;
            case 'object':
                return $this->fromJson($value, true);
            case 'array':
            case 'json':
                return $this->fromJson($value);
            case 'collection':
                return new BaseCollection($this->fromJson($value));
            case 'date':
            case 'datetime':
                return $this->asDateTime($value);
            case 'timestamp':
                return $this->asTimeStamp($value);
            case 'time':
                return $this->asTime($value);
            default:
                return $value;
        }
    }

    protected function asTime($value)
    {
        // If this value is already a Carbon instance, we shall just return it as is.
        // This prevents us having to re-instantiate a Carbon instance when we know
        // it already is one, which wouldn't be fulfilled by the DateTime check.
        if ($value instanceof Carbon) {
            return $value;
        }

         // If the value is already a DateTime instance, we will just skip the rest of
         // these checks since they will be a waste of time, and hinder performance
         // when checking the field. We will just return the DateTime right away.
        if ($value instanceof DateTimeInterface) {
            return new Carbon(
                $value->format('Y-m-d H:i:s.u'), $value->getTimeZone()
            );
        }

        // If this value is an integer, we will assume it is a UNIX timestamp's value
        // and format a Carbon object from this timestamp. This allows flexibility
        // when defining your date fields as they might be UNIX timestamps here.
        if (is_numeric($value)) {
            return Carbon::createFromTimestamp($value);
        }

        // If the value is in simply year, month, day format, we will instantiate the
        // Carbon instances from that format. Again, this provides for simple date
        // fields on the database, while still supporting Carbonized conversion.
        if (preg_match('/^(\d{1,2}):(\d{2}):(\d{2})$/', $value)) {
            return Carbon::createFromFormat('h:i:s', $value);
        }

        var_dump($value);

        // Finally, we will just assume this date is in the format used by default on
        // the database connection and use that format to create the Carbon object
        // that is returned back out to the developers after we convert it here.
        return Carbon::createFromFormat($this->getTimeFormat(), $value);
    }

    /**
     * Get the format for database stored dates.
     *
     * @return string
     */
    protected function getTimeFormat()
    {
        //return $this->timeFormat ?: $this->getConnection()->getQueryGrammar()->getTimeFormat();
        return $this->timeFormat ?: 'h:i:s';
    }

    /**
     * Set a given attribute on the model.
     *
     * @param  string  $key
     * @param  mixed  $value
     * @return $this
     */
    public function setAttribute($key, $value)
    {
        // First we will check for the presence of a mutator for the set operation
        // which simply lets the developers tweak the attribute as it is set on
        // the model, such as "json_encoding" an listing of data for storage.
        if ($this->hasSetMutator($key)) {
            $method = 'set'.Str::studly($key).'Attribute';

            return $this->{$method}($value);
        }

        // If an attribute is listed as a "date", we'll convert it from a DateTime
        // instance into a form proper for storage on the database tables using
        // the connection grammar's date format. We will auto set the values.
        elseif ($value && (in_array($key, $this->getDates()) || $this->isDateCastable($key))) {
            $value = $this->fromDateTime($value);
        }

        elseif ($value && ($this->isTimeCastable($key))) {
            $value = $this->fromTime($value);
        }

        if ($this->isJsonCastable($key) && ! is_null($value)) {
            $value = $this->asJson($value);
        }

        $this->attributes[$key] = $value;

        return $this;
    }

    /**
     * Convert a Carbon Time to a storable string.
     *
     * @param  \Carbon\Carbon|int  $value
     * @return string
     */
    public function fromTime($value)
    {
        $format = $this->getTimeFormat();

        $value = $this->asTime($value);

        return $value->format($format);
    }

    /**
     * Determine whether a value is Date / DateTime castable for inbound manipulation.
     *
     * @param  string  $key
     * @return bool
     */
    protected function isTimeCastable($key)
    {
        return $this->hasCast($key, ['time']);
    }
}

答案 1 :(得分:0)

如果有兴趣的人,我最近创建了Laravel软件包来处理这种问题。

您可以在这里找到软件包和说明:https://github.com/vkovic/laravel-custom-casts

答案 2 :(得分:0)

在 Laravel 7 及更高版本中,this is built in。自定义强制转换必须使用 set 和 get 方法实现 Illuminate\Contracts\Database\Eloquent\CastsAttributes 接口:

App/Casts/YourCast.php

namespace App\Casts;


use Illuminate\Contracts\Database\Eloquent\CastsAttributes;

class YourCast implements CastsAttributes
{

    public function get($model, string $key, $value, array $attributes)
    {
        return json_decode($value,true);
    }

    public function set($model, string $key, $value, array $attributes)
    {
       return json_encode($value);
    }

}

应用/模型/您的模型

protected $casts = [
    'attribute' => \App\Casts\YourCast::class,
]