Pregunta

Estoy escribiendo una aplicación bastante simple que requiere que los modelos Backbone.js y Laravel 4 estén sincronizados.El problema surge cuando los modelos de Laravel involucran Carbón fechas.Mi controlador Laravel se ve así:

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

Esto responde exitosamente con una representación JSON de $order que el lado del cliente usa para mantenerse sincronizado.Sin embargo, las fechas de Carbono se devuelven como la representación del objeto de Carbono, así:

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

Podría interpretar esto como un objeto de fecha de JavaScript con bastante facilidad, sin embargo, cuando este objeto vuelve a laravel, JSON elimina el Carbon clase y Eloquent no logra leer eso como una fecha:

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

Entonces necesito:

  1. Amplíe la clase JsonResponse para convertir fechas de carbono en representaciones de cadenas.
  2. Extender la clase Eloquent para interpretar objetos StdClass de la Carbon estructura de clases hasta fechas.
  3. Haz algo que claramente me falta, Laravel 4 afirma ser increíble en REST, así que supongo que me falta algo.
¿Fue útil?

Solución

Primero, le sugiero que separe la API de los controladores.Utilice recursos para llamadas API.

Para el objeto devuelto a Laravel, no sé cómo lo está procesando para obtener el error, pero debe iniciar una nueva instancia de Carbon si desea una fecha de Carbon.De lo contrario, podrías devolver la fecha como una cadena, el modelo de Laravel se encargará del resto.

Suponiendo que el objeto devuelto es:

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

Y la variable $data tendrá la respuesta actual, simplemente puedes sobrescribir entregada_at:

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

O si quieres un objeto Carbon:

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

Otros consejos

Esto puede llegar un poco tarde, pero normalmente uso accesores y mutadores para lograrlo.Por ejemplo, si quiero todos created_at y updated_at Los campos siempre se devolverán en el formato ATOM, creo una clase de modelo base que extiende Eloquent que hereda cualquier otro modelo:

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();
    }
}

Puede que esto no sea lo mismo, pero obtendría este error cuando trabajo con marcas de tiempo y carbono, pero usar strtotime() en los datos que estaba pasando resolvió mi problema, puede ayudarlo.

La forma en que maneje las fechas tanto en backbone como en Laravel tendrá un impacto.
Debes elegir un formato de fecha y ceñirte a él.Y luego asegúrese de que ambas partes se conviertan a ese formato al pasar datos de ida y vuelta al JS y a los Controladores.

Si envía un objeto Date de JavasScript puro, devuelve una cadena de fecha similar a esta
"Sat Apr 19 2014 00:00:00 GMT+0200 (South Africa Standard Time)"
Lo cual no es tan bueno, ya que PHP strtotime termina analizándolo de forma funky.

Aquí hay un ejemplo:

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

¿Por qué esa fecha? tal vez alguien más pueda explicarlo mejor que yo.Puede utilizar un formato de fecha personalizado para leerlo correctamente, pero mejor utilice un formato que ambos puedan entender.

Como ISO8601

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

Y en php Carbon debería poder manejarlo sin problemas.

Si desea obtener la columna de fecha de su modelo (created_at) en formato de cadena, utilícelo así:

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

esto cambiará

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

dentro de esto:

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top