数据透视模型

时间:2017-07-28 16:27:30

标签: laravel pivot-table laravel-5.4 php-carbon

情境:我有一个模型(让我们称之为Pivot),声明如下:

class Pivot extends Model
{
    public $timestamps = false;
    .....
}

它有5个字段:idnotification_iddevice_idcreated_atread_at

此模型用作NotificationDevice之间的数据透视表:

// Notification.php
public function devices()
{
    return $this->belongsToMany(Device::class)
        ->withPivot(['id','created_at','notification_id','device_id', 'read_at']); 
}

public function pivots() {
    return $this->hasMany(Pivot::class);
}

我在Device类中做了同样的事情。

我的MySQL的时区(Europe\Rome)与UTC不同,我无法更改它,因为它已被不同项目使用。

问题:如何设置created_at字段才能正常工作?

我尝试使用默认时间戳,它可以工作但是它还会添加updated_at列而我无法使用它(它会添加太多冗余)。

所以我设置了public $timestamps = false;,我在数据库中创建了这样的字段:

$table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP'));

这个问题的原因在于,如前所述,MySQL的时区错误(Europe\Rome),所以当我从这个表中读取数据时,created_at值会从原版的。当我还设置read_at属性时,这是一个问题,因为它会创建在创建之前读取通知的情况。

我的最后一个想法是在创建事件中设置created_at。我跟着this laracast guide,但显然,如果数据是作为sync方法的数据透视表插入的,则不会调用事件(它们对我没有用)。

你有其他想法吗?当然有一些丑陋的黑客可以工作(比如在创建的Pivot上迭代并手动设置它们),但我想使用更好的解决方案。

编辑:@Maraboc提出的解决方案完美无缺。我在config/database.php中设置了MySQL配置数组的timezone属性:

'mysql' => [
        'driver' => 'mysql',
        'host' => env('DB_HOST', '127.0.0.1'),
        'port' => env('DB_PORT', '3306'),
        'database' => env('DB_DATABASE', 'forge'),
        'username' => env('DB_USERNAME', 'forge'),
        'password' => env('DB_PASSWORD', ''),
        'unix_socket' => env('DB_SOCKET', ''),
        'charset' => 'utf8mb4',
        'collation' => 'utf8mb4_unicode_ci',
        'prefix' => '',
        'strict' => true,
        'engine' => null,
        'timezone' => '+00:00',
    ],

1 个答案:

答案 0 :(得分:0)

使用model events设置创建模型时的时间戳。您可以将字段和时区设置在一起。

class Pivot extends Model
{
    public $timestamps = false;

    protected static function boot()
    {
        static::creating(function($model) {
            $model->create_at = Carbon::now('Europe\Rome');
        });

        parent::boot();
    }
}

不要忘记parent::boot(),否则将无法在模型上启动特征。