How to handle JSON responses for models that include carbon dates in Laravel?

I am writing a fairly simple application that requires the Backbone.js and Laravel 4 models to sync. Problems arise when Laravel models include Carbon dates. My Laravel controller looks like this:

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

This successfully responds to the JSON representation of $ order, which the client side uses for synchronization. However, Carbon dates are returned as a representation of the Carbon object, for example:

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

I could easily interpret this as a javascript date object, however, when this object returns to laravel, JSON removes the Carbon class, and Eloquent cannot read it as a date:

 [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} [] [] 

Therefore I need:

  • Extend the JsonResponse class to convert carbon dates to string representations.
  • Extend the Eloquent class to interpret the Carbon class StdClass objects to dates.
  • Do something that I am clearly missing, Laravel 4 claims to be cool in REST, so I think I missed something.
+8
json javascript laravel-4 php-carbon
source share
5 answers

First, I suggest you separate the API from the controllers. Use resources for API calls.

For the object returned to Laravel, I don’t know how you handle it to get an error, but you have to initiate a new Carbon instance if you want the Carbon date. Alternatively, you can simply return the date as a string, the Laravel Model will handle the rest.

Assuming the returned object:

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

And the $ data variable will have the current response, you can just overwrite deliver_at:

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

Or if you want a Carbon object:

 $data->delivered_at = new \Carbon\Carbon($data->delivered_at->date, $data->delivered_at->timezone); 
+2
source share

This may happen a little later, but for this I usually use accessors and mutators. For example, if I want all created_at and updated_at fields to always be returned in ATOM format, I create a base model class that extends Eloquent , which every other model inherits:

 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(); } } 
+5
source share

It may not be the same, but I would get this error when working with timestamps and carbon, but using strtotime () for the data I passed solved my problem can help you.

+1
source share

How you handle dates in both highways, and Laravel will have an impact.
You need to choose one date format and stick to it. And then make sure that both sides are converted to this format when transferring data back and forth to JS and controllers.

If you send a clean JavasScript Date object, it returns a date string that looks like this: "Sat Apr 19 2014 00:00:00 GMT+0200 (South Africa Standard Time)"
Which is not so nice, since PHP strtotime finishes strtotime .

here is an example:

 $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. 

Why is this date? maybe someone else can work out better than I can. You can use a custom date format to read it correctly, and use a format that you can understand.

Like ISO8601

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

And in php Carbon should be able to handle it without problems

+1
source share

If you want to get the date column of your model ( created_at ) in string format, use this:

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

it will change

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

in it:

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

0
source share

All Articles