9

我正在编写一个非常简单的应用程序,要求 Backbone.js 模型和 Laravel 4 模型同步。当我的 Laravel 模型涉及日期时,麻烦就出现了。我的 Laravel 控制器如下所示:

class OrderController extends \BaseController {
    ...
    public function update($id = null) {
        ...
        if (Request::ajax()) 
            return $order;
        ...
    }
}

这成功地响应了 $order 的 JSON 表示,客户端使用它来保持同步。但是,Carbon 日期作为 Carbon 对象表示返回,如下所示:

{
    "delivered_at":{"date":"2014-02-25 12:55:29","timezone_type":3,"timezone":"America\/Argentina\/Buenos_Aires"}
}

我可以很容易地将其解释为 javascript Date 对象,但是,当该对象返回 laravel 时,JSON 会删除Carbon该类并且 Eloquent 无法将其读取为日期:

[2014-02-25 12:58:32] log.ERROR: exception 'ErrorException' with message 'preg_match() expects parameter 2 to be string, array given' in vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:2210
Stack trace:
#0 [internal function]: Illuminate\Exception\Handler->handleError(2, 'preg_match() ex...', '/Users/maurospi...', 2210, Array)
#1 vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(2210): preg_match('/^(\d{4})-(\d{2...', Array)
#2 vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(2151): Illuminate\Database\Eloquent\Model->fromDateTime(Array)
#3 vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(306): Illuminate\Database\Eloquent\Model->setAttribute('delivered_at', Array)
#4 app/controllers/OrderController.php(120): Illuminate\Database\Eloquent\Model->fill(Array)
#5 [internal function]: OrderController->update('91')
#6 vendor/laravel/framework/src/Illuminate/Routing/Controllers/Controller.php(138): call_user_func_array(Array, Array)
#7 vendor/laravel/framework/src/Illuminate/Routing/Controllers/Controller.php(115): Illuminate\Routing\Controllers\Controller->callMethod('update', Array)
#8 vendor/laravel/framework/src/Illuminate/Routing/Router.php(985): Illuminate\Routing\Controllers\Controller->callAction(Object(Illuminate\Foundation\Application), Object(Illuminate\Routing\Router), 'update', Array)
#9 [internal function]: Illuminate\Routing\{closure}('91')
#10 vendor/laravel/framework/src/Illuminate/Routing/Route.php(80): call_user_func_array(Object(Closure), Array)
#11 vendor/laravel/framework/src/Illuminate/Routing/Route.php(47): Illuminate\Routing\Route->callCallable()
#12 vendor/laravel/framework/src/Illuminate/Routing/Router.php(1016): Illuminate\Routing\Route->run(Object(Illuminate\Http\Request))
#13 vendor/laravel/framework/src/Illuminate/Foundation/Application.php(574): Illuminate\Routing\Router->dispatch(Object(Illuminate\Http\Request))
#14 vendor/laravel/framework/src/Illuminate/Foundation/Application.php(550): Illuminate\Foundation\Application->dispatch(Object(Illuminate\Http\Request))
#15 public/index.php(49): Illuminate\Foundation\Application->run()
#16 {main} [] []

所以我要么需要:

  1. 扩展 JsonResponse 类以将 Carbon 日期转换为字符串表示形式。
  2. 扩展 Eloquent 类以将类结构的 StdClass 对象解释Carbon为日期。
  3. 做一些我明显错过的事情,Laravel 4 声称在 REST 方面很棒,所以我想我错过了一些东西。
4

5 回答 5

5

这可能来得有点晚,但我通常使用访问器和修改器来实现这一点。例如,如果我希望所有created_atupdated_at字段始终以 ATOM 格式返回,我创建一个基本模型类扩展Eloquent,其他所有模型都继承该类:

use Carbon\Carbon as Carbon;
use Illuminate\Database\Eloquent\Model as Model;

class BaseModel extends Model {

    public function getCreatedAtAttribute($value)
    {
        return Carbon::parse($value)->toATOMString();
    }

    public function setCreatedAtAttribute($value)
    {
        $this->attributes['created_at'] = Carbon::parse($value)->toDateTimeString();
    }

    public function getUpdatedAtAttribute($value)
    {
        return Carbon::parse($value)->toATOMString();
    }

    public function setUpdatedAtAttribute($value)
    {
        $this->attributes['created_at'] = Carbon::parse($value)->toDateTimeString();
    }
}
于 2014-08-25T08:45:07.160 回答
4

首先,我建议您将 API 与控制器分开。将资源用于 API 调用。

对于返回给 Laravel 的对象,我不知道你是如何处理它来获取错误的,但是如果你想要一个 Carbon 日期,你应该启动一个新的 Carbon 实例。否则,您可以将日期作为字符串返回,Laravel 的模型将处理其余部分。

假设返回的对象是:

{
    "delivered_at":{"date":"2014-02-25 12:55:29","timezone_type":3,"timezone":"America\/Argentina\/Buenos_Aires"}
}

并且变量 $data 将具有当前响应,您可以简单地覆盖 Delivered_at:

$data->delivered_at = $data->delivered_at->date;

或者如果你想要一个 Carbon 对象:

$data->delivered_at = new \Carbon\Carbon($data->delivered_at->date, $data->delivered_at->timezone);
于 2014-03-15T10:06:28.810 回答
1

你如何在骨干网和 Laravel 中处理日期将会产生影响。
您需要选择一种日期格式并坚持下去。然后确保在向 JS 和 Controller 传递数据时,双方都转换为该格式。

如果您发送一个纯 JavaScript Date 对象,那么它会返回一个看起来像这样的日期字符串,这
"Sat Apr 19 2014 00:00:00 GMT+0200 (South Africa Standard Time)"
不太好,因为 PHPstrtotime最终将它解析为一个时髦的。

这是一个例子:

$jsdate = "Sat Apr 19 2014 00:00:00 GMT+0200 (South Africa Standard Time)";
$carbon = Carbon::createFromTimestamp(strtotime($jsdate));
$iso8601 = $carbon ->format(Carbon::ISO8601)
//output '1970-01-01T02:00:00+0200' which is a UNIX timestamp 0.

为什么是那个日期?也许其他人可以比我做得更好。您可以使用自定义日期格式来正确读取它,而是使用双方都能理解的格式。

像 ISO8601

//javascript
var jsdate = (new Date()).toISOString();

并且在 php Carbon 中应该能够毫无问题地处理它

于 2014-03-18T15:09:20.683 回答
1

This may not be the same but I would get this error when working with timestamps and carbon but using strtotime() on the data i was passing resolved my issue, may help you.

于 2014-03-15T03:27:38.127 回答
0

如果您想以created_at字符串格式获取模型 ( ) 的日期列,请使用如下方式:

$response['created_at'] = Carbon::parse($model->created_at)->toDateString();

这会改变

created_at = {"date":"2014-02-25 12:55:29","timezone_type":3,"timezone":"America\/Argentina\/Buenos_Aires"}

进入这个:

created_at = "2014-02-25 12:55:29"

于 2016-06-30T22:32:41.957 回答