Laravel で炭素日付を含むモデルの JSON 応答を処理するにはどうすればよいですか?
-
21-12-2019 - |
質問
私は 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} [] []
したがって、次のいずれかを行う必要があります。
- JsonResponse クラスを拡張して、炭素日付を文字列表現に変換します。
- Eloquent クラスを拡張して、
Carbon
クラス構造から日付まで。 - 明らかに欠けていることを実行します。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 には現在の応答が含まれるため、delivery_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の両方で日付をどのように扱うかが影響します。
日付形式を 1 つ選択し、それを使用する必要があります。そして、JS とコントローラーにデータをやり取りするときに、両方がその形式に変換されていることを確認します。
純粋な JavaScript Date オブジェクトを送信すると、次のような日付文字列が返されます。
"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"