【问题标题】:Laravel5 Eloquent default date mutator fails with JSON date inputLaravel5 Eloquent 默认日期修改器因 JSON 日期输入而失败
【发布时间】:2016-06-10 12:03:31
【问题描述】:

我有一个带有日期修改器的模型,例如 created_at。假设是一个通用的timestamp 属性。

当从客户端以 JSON 格式传递数据时,我会得到

{
    timestamp: "2016-06-07T22:00:00.000Z"
}

该属性将用于设置一些模型,如下所示:

$model = new Foo();
$model->timestamp = Input::get('timestamp');

由于这将触发日期修改器,php Carbon 被调用并失败

InvalidArgumentException in Carbon.php line 425
Unexpected data found.
Trailing data

现在,这不是 Carbon 本身的问题,它能够处理 JSON 格式。如果你愿意尝试

new Carbon('2016-06-07T22:00:00.000Z');

您实际上会得到预期的结果。

据我所知,问题源于一种奇怪的 Eloquent 行为。从上面提到的InvalidArgumentException in Carbon.php line 425 看到这条踪迹:

in Carbon.php line 425
at Carbon::createFromFormat('Y-m-d H:i:s', '2016-06-07T22:00:00.000Z') in Model.php line 2915
at Model->asDateTime('2016-06-07T22:00:00.000Z') in Model.php line 2871
at Model->fromDateTime('2016-06-07T22:00:00.000Z') in Model.php line 2826
at Model->setAttribute('timestamp', '2016-06-07T22:00:00.000Z') in Model.php line 3351

Eloquent 正在尝试 createFromFormat 传递一个不反映实际 JSON 格式的 错误格式,这会导致 Carbon 异常。

另一方面,像上面提到的new Carbon($jsonDate) 这样的简单调用在这种情况下可以正常工作。

  1. 我应该如何解决这个问题?
  2. 这不应该是 Eloquent 的错误吗?

== 编辑 ==

我自己没有编写任何 mutator。我正在使用这样的默认日期修改器:

public function getDates() {
    return ['timestamp'];
}

【问题讨论】:

  • 这应该可以按预期工作。你如何定义突变体?你能发布模型代码和Input::get('timestamp) 的确切值吗(我假设它不是一个对象)。我将在这里设置的 mutator 留下来测试:public function setTimestampAttribute($value) { $this->attributes['timestamp'] = new \Carbon\Carbon($value); } 和控制器代码:$obj->timestamp = '2016-06-07T22:00:00.000Z';
  • 请发布您的 mutator。
  • 我没有使用任何自定义修改器,请参阅编辑。

标签: php json laravel laravel-5


【解决方案1】:

Eloquent 分析你给它的日期,当属性在getDates 函数中设置时。

在它的分析中,它有四个步骤:(请参阅Modal.phpasDateTime 澄清方法,代码注释得很好:https://github.com/illuminate/database/blob/master/Eloquent/Model.php#L2898

  1. 如果它已经是 Carbon 实例,请使用它
  2. 如果是实现 DateTimeInterface 的实例,请使用它
  3. 如果是数字,则解析为 Unix 时间戳
  4. 如果是简单的年月日格式(通过正则表达式尝试),请使用该格式
  5. 如果以上都不是,请使用您指定的默认格式创建一个 Carbon 实例

在你的情况下,1-4 不匹配,所以它尝试 5。

您没有在模型上指定自定义 dateFormat,因此它使用适用于您正在使用的数据库连接类型的默认日期格式。您可以通过向模型添加 $dateFormat 变量来覆盖它:

protected $dateFormat = 'U';

但是您的正常时间戳可能已经采用正确的格式。所以这个解决方案不适合你。

在你的情况下,我会这样做: $model->timestamp = Carbon::parse(Input::get('timestamp'));

或者使用适当格式的Carbon::createFromFormat()

我不完全知道他们为什么不直接用 Carbon 解析它。我想它更容易出错且更不可控。使用不同的国际格式,您可能会得到意想不到的结果(月份和日期切换等)。它也可能比他们目前的方法慢。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-02-27
    • 2021-03-14
    • 1970-01-01
    • 2020-11-15
    • 1970-01-01
    • 2011-10-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多