【问题标题】:Laravel - formatting all dates simultaneouslyLaravel - 同时格式化所有日期
【发布时间】:2020-01-05 18:47:27
【问题描述】:

我目前正在开发 POC,以展示使用 Laravel 创建 API 将相当轻松,但问题是数据库已经一成不变。

我遇到的一个问题是他们使用了在列名处创建和更新的自定义,例如对于car 表,created_at 列将为car_time,更新日期为cardata_time,这些都保存为unix 时间戳。

我知道您可以为每个模型设置 CREATED_AT 和 UPDATED_AT 列。我想更进一步,以 ISO 8601 格式返回所有日期。

我在我的模型和 Model 之间插入了一个名为 MasterModel 的类,我想做类似的事情

protected function getCreatedAtAttribute($value)
{
    $format = "Y-m-d\TH:i:s\Z";
    $datetime = new DateTime($value);
    return $datetime->format($format);
}

使在日期创建的所有内容都采用该格式。问题是我在和更新的列中创建的自定义意味着这永远不会被调用。

有没有一种方法可以让我用一种方法来同时更新所有在日期创建的列?


更新:我意识到我最初的问题不够清楚 - 我需要识别所有日期字段,而不仅仅是 created_at 和 updated_at,并以某种方式格式化它们。它们将始终是 unix 时间戳。不知道我会怎么做。

【问题讨论】:

  • 只有在获得模型的 JSON 表示时才需要 ISO 格式吗?
  • 为了明确起见,请添加一个示例,说明您期望获得的结果以及您当前获得的结果
  • 我认为您所指的内容在这里:laravel.com/docs/master/…。基本上@Skytigger 回答
  • @MohamedAllal Carbon::serializeUsing() 按照文档中的建议不起作用,请参见此处:github.com/laravel/framework/issues/21703 这个问题有一些有趣的答案:stackoverflow.com/questions/34074356/…
  • @Skytiger 你试过了吗?在线程中,他们修复了它。但是我认为在模型中覆盖 serializeDate 更好。使用 trait 会让事情变得简单。你有你的答案。也谢谢你。如果您尝试过碳方式,请告诉我。如果你有最后一个 laravel 版本。谢谢

标签: laravel datetime model attributes


【解决方案1】:

这里的答案将扩展 @caddy dz 的答案,他恰好和我坐在一起。

 所有需要知道的事情

取消自动管理时间戳

public $timestamps = false; // <-- deactivate the automatic handling

更改表属性名称

const CREATED_AT = 'creation_date'; // <--- change the names
const UPDATED_AT = 'last_update';

源文档: https://laravel.com/docs/5.8/eloquent#eloquent-model-conventions

默认情况下,Eloquent 期望 created_atupdated_at 列 存在于您的桌子上。如果您不希望有这些列 由 Eloquent 自动管理,将 $timestamps 属性设置为 你的模型是假的:

 创建访问器

class User extends Model
{
    /**
     * Get the user's first name.
     *
     * @param  string  $value
     * @return string
     */
    public function getFirstNameAttribute($value)
    {
        // do whatever you want here  (change and mutate the value)
        return ucfirst($value);
    }
}
  • 首先要知道,访问器是一个全局概念 雄辩,可以写所有属性,而不仅仅是 getCreatedAtAttributegetUpdatedAtAttribute

  • 要知道的第二件事是,无论列的名称是什么,即 在 camle case (firstName)with _ (first_name) 雄辩的知道 与之相匹配。访问器的格式应该是 get[NameOfATtribute]Attribute pascal case(camle case 但首先 字母也是大写的)。

  • 三个方法参数保存 题。下面是一个显示其使用方式的 sn-p

$user = App\User::find(1);

$firstName = $user->first_name; //|=> first_name => getFirstNameAttribute(columnVal)

分辨率清晰。

first_name(列名)=> getFirstNameAttribute(列值)

所有的 sn-ps 都来自文档:https://laravel.com/docs/5.8/eloquent-mutators#accessors-and-mutators

 让我们应用所有这些

首先,我们不需要在迁移中使用$table-&gt;timestamps(),因此我们对以下内容进行了更改。

Schema::create('cars', function (Blueprint $table) {
    $table->bigIncrements('id');
    $table->timestamp('cardata_time', 0)->nullable();
    $table->timestamp('car_time', 0)->nullable();
});

然后我们将修改应用于我们的模型: - 我们停用了时间戳的自动处理。 - 覆盖时间戳列名称。 - 并创建访问器。

这取决于我们想要什么。如果我们只想在此处执行上述操作,则 sn-p 表明:

// deactivate auto timestamps management
public $timestamps = false;

// change the columns names     
const CREATED_AT = 'car_time';
const UPDATED_AT = 'cardata_time';

// creating the accessors (respect the naming)

protected function getCarTimeAttribute($value) //car_time => CarTime
{
    // <-- do whatever you want here (example bellow)

    $format = "Y-m-d\TH:i:s\Z";
    $datetime = new DateTime($value);
    return $datetime->format($format);
}

protected function getCardataTimeAttribute($value) //cardata_time => CardataTime
{
    // <-- do whatever you want here

    $format = "Y-m-d\TH:i:s\Z";
    $datetime = new DateTime($value);
    return $datetime->format($format);
}

完全重命名属性

如果您想要使用另一个访问名称。然后我的朋友@caddy dz 所做的就是要走的路。碰巧和我坐在一起。并鼓励我扩展答案。 (hhhh)

你需要知道

$appends 和 $hidden

序列化 API 的一部分。
https://laravel.com/docs/master/eloquent-serialization#appending-values-to-json https://laravel.com/docs/master/eloquent-serialization#hiding-attributes-from-json

$appends 允许我们向模型添加属性。这在桌子上不存在。我们还需要为它们创建一个访问器

class User extends Model
{
    /**
     * The accessors to append to the model's array form.
     *
     * @var array
     */
    protected $appends = ['is_admin'];

    // ........

    /**
     * Get the administrator flag for the user.
     *
     * @return bool
     */
    public function getIsAdminAttribute()
    {
        return $this->attributes['admin'] == 'yes';
    }
}

$hidden 允许我们从模型中删除和限制属性。就像密码字段一样。

文档示例:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = ['password'];
}

因此,我们需要做的是隐藏持有时间的属性,这些属性想要更改为其他内容。

// remove the old attributes names
protected $hidden = ['car_time', 'cardata_time']; // renaming those 
// append the new one   \/                  \/    <- to those   
protected $appends = ['car_crated_at', 'cardata_created_at']; // names just for illustration

protected function getCarCreatedAtAttribute($value) // car_created_at => CarCreatedAt
{
    $format = "Y-m-d\TH:i:s\Z";
    $datetime = new DateTime($value);
    return $datetime->format($format);
}

protected function getCardataCreatedAtAttribute($value) // cardata_created_at => CardataCreatedAt
{
    $format = "Y-m-d\TH:i:s\Z";
    $datetime = new DateTime($value);
    return $datetime->format($format);
}

 将其应用于不同的模型

基本思想是创建一个基本模型,然后在创建模型时对其进行扩展。

无一例外地格式化模型的所有时间属性

如果您想要为模型中的所有时间属性应用格式。

然后覆盖serializeDate() 方法。在实践中写一个特征,然后你就可以应用它。否则为基础模型。

下面的答案很好地涵盖了它:

https://stackoverflow.com/a/41569026/7668448

从历史上看,这个线程很有趣:

https://github.com/laravel/framework/issues/21703

在碳级序列化

在 laravel 5.7 及更高版本的文档中(我检查了 [仅文档]): https://laravel.com/docs/master/eloquent-serialization#date-serialization

我们可以在碳序列化级别更改格式。但碰巧有一个过去的错误。通常是固定的,但我没有尝试。如果我没记错的话,错误在 5.7 中并在 5.7 中修复。上面的 git 链接讨论一下。

片段:

class AppServiceProvider extends ServiceProvider
{
    /**
     * Perform post-registration booting of services.
     *
     * @return void
     */
    public function boot()
    {
        Carbon::serializeUsing(function ($carbon) {
            return $carbon->format('U');
        });
    }

___THE_END ^ ^

【讨论】:

  • 谢谢,你们两个肯定帮我解决了一些问题!
  • @Skytiger Glade 听到了。谢谢
【解决方案2】:

不确定你在问什么,但如果你的表中有 cardata_timecar_time 是这样定义的

Schema::create('cars', function (Blueprint $table) {
     $table->bigIncrements('id');
     $table->timestamp('cardata_time', 0)->nullable();
     $table->timestamp('car_time', 0)->nullable();
});

还有这样的大师模型

/**
 * Indicates if the model should be timestamped.
 *
 * @var bool
 */
public $timestamps = false;

const CREATED_AT = 'created_at';
const UPDATED_AT = 'updated_at';

/**
 * The accessors to append to the model's array form.
 *
 * @var array
 */
protected $appends = ['created_at', 'updated_at'];

/**
 * The attributes that should be hidden for arrays.
 *
 * @var array
 */
protected $hidden = ['car_time', 'cardata_time'];

protected function getCreatedAtAttribute($value)
{
    $format = "Y-m-d\TH:i:s\Z";
    $datetime = new DateTime($value);
    return $datetime->format($format);
}

protected function getUpdatedAtAttribute($value)
{
    $format = "Y-m-d\TH:i:s\Z";
    $datetime = new DateTime($value);
    return $datetime->format($format);
}

结果:

{
  "id": 1,
  "created_at": "2019-09-02T20:31:38Z",
  "updated_at": "2019-09-02T20:31:38Z"
}

【讨论】:

  • 我不想在每次创建新类时都放下那么多样板文件,我希望能够将属性注册为日期并对其进行格式化。这也可能涵盖其他日期字段,不确定创建时间和更新时间。不过还是谢谢。
  • MasterModel 的意义不是要被所有其他模型而不是 Eloquent 扩展吗?您可以在基类中使用它并从中扩展所有其他模型
  • 我所有的模型都已经在扩展 MasterModel。 MasterModel 扩展了 Eloquent 的 Model 类。
【解决方案3】:

documentation。第一种方法。这需要在$dates 属性中定义日期。仅当模型为serialized 时才会触发。

public class YourModel extends Model
{
    protected $dateFormat = "Y-m-d\TH:i:s\Z";
}

您还可以在引导方法中的提供程序中定义it。这将在 Carbon 日期序列化时触发。

public function boot()
{
    Carbon::serializeUsing(function ($carbon) {
        return $carbon->format("Y-m-d\TH:i:s\Z");
    });
}

【讨论】:

  • 我不太确定如何序列化模型,抱歉。
  • 您通常如何返回数据或将其注入视图?
  • 目前我正在做一个粗略的 POC,所以我只是将原始数组返回给浏览器以打印出检索到的数据
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-09-14
  • 1970-01-01
  • 1970-01-01
  • 2016-02-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多