I'm writing a pretty simple app that requiers Backbone.js models and Laravel 4 models to be in sync. Trouble arises when I the Laravel models involve 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 with a JSON representation of $order which the client side uses to stay in sync. However, Carbon dates are returned as the Carbon object representation, like this:
{
"delivered_at":{"date":"2014-02-25 12:55:29","timezone_type":3,"timezone":"America\/Argentina\/Buenos_Aires"}
}
I could manage to interpret this as a javascript Date object pretty easily, however, when this object goes back to laravel, JSON removes the Carbon
class and Eloquent fails to read that 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} [] []
So I either need to:
Carbon
class structure to dates.This might come in a bit late, but I usually make use of accessors and mutators to achieve this. For example, if I want all created_at
and updated_at
fields always to be returned in the ATOM format, I create a base model class extending 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();
}
}
First, I suggest that you separate API from controllers. Use resources for API calls.
For the object returned to Laravel, I don't know how are you processing it to get the error, but you should initiate a new Carbon instance if you want a Carbon date. Else you could just return the date as a string, Laravel's Model will handle the rest.
Assuming the object returned is:
{
"delivered_at":{"date":"2014-02-25 12:55:29","timezone_type":3,"timezone":"America\/Argentina\/Buenos_Aires"}
}
And the variable $data will have the current response, you could simply overwrite delivered_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);
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With