Как обрабатывать ответы JSON для моделей, которые включают даты Carbon в Laravel?

StackOverflow https://stackoverflow.com//questions/22019714

Вопрос

Я пишу довольно простое приложение, которое требует синхронизации моделей Backbone.js и моделей Laravel 4.Проблемы возникают, когда модели Laravel включают Углерод даты.Мой контроллер Laravel выглядит так:

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

Это успешно отвечает JSON-представлением $order, которое клиентская сторона использует для синхронизации.Однако даты Carbon возвращаются как представление объекта Carbon, например:

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

Мне удалось довольно легко интерпретировать это как объект Date javascript, однако, когда этот объект возвращается в laravel, JSON удаляет Carbon class, и 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, так что, думаю, я что-то упускаю.
Это было полезно?

Решение

Во-первых, я предлагаю вам отделить API от контроллеров.Используйте ресурсы для вызовов API.

Что касается объекта, возвращенного в Laravel, я не знаю, как вы его обрабатываете, чтобы получить ошибку, но вам следует инициировать новый экземпляр Carbon, если вам нужна дата Carbon.В противном случае вы можете просто вернуть дату в виде строки, а модель Laravel сделает все остальное.

Предполагая, что возвращаемый объект:

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

И переменная $data будет содержать текущий ответ, вы можете просто перезаписать Deliver_at:

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

Или, если вам нужен объект Carbon:

$data->delivered_at = new \Carbon\Carbon($data->delivered_at->date, $data->delivered_at->timezone);

Другие советы

Возможно, это произойдет немного поздно, но для достижения этой цели я обычно использую средства доступа и мутаторы.Например, если я хочу, чтобы все created_at и updated_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();
    }
}

Это может быть не то же самое, но я получал эту ошибку при работе с временными метками и углеродом, но использование strtotime() для передаваемых данных решило мою проблему и может вам помочь.

То, как вы обрабатываете даты как в магистрали, так и в Laravel, будет иметь влияние.
Вам нужно выбрать один формат даты и придерживаться его.А затем убедитесь, что обе стороны преобразуются в этот формат при передаче данных назад и вперед в JS и контроллеры.

Если вы отправляете чистый объект даты JavasScript, он возвращает строку даты, которая выглядит следующим образом
"Sat Apr 19 2014 00:00:00 GMT+0200 (South Africa Standard Time)"
Что не так уж приятно, поскольку PHP strtotime в конечном итоге анализирует его как фанк.

вот пример:

$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 должен справиться с этим без проблем.

Если вы хотите получить столбец даты вашей модели (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"

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top