Route Model Binding

Recientemente se nos creo la inquietud del trabajo repetitivo de consultar la BD cuando se inyecta un ID en una ruta o la acción de un controlador. Si eres fiel seguidor de las buenas prácticas de desarrollo de software, debes saber que existe un principio llamado DRY (Don’t Repeat Yourself), que básicamente nos alienta a reducir la repetición de información de todo los tipos.

Normalmente, en una acción de actualización, supongamos para el caso en estudio, se requiere actualizar una factura. Un definición de la ruta sería la siguiente:

Route::get(‘invoice/edit/{id}’, ‘InvoiceController@edit’);

Ahora bien, la acción del controlador podría ser codificada de la siguiente forma:


/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return Response
*/
public function edit($id)
{
$invoice = invoice::findOrFail($id);

$this->authorize(‘edit’, $invoice);

return view(‘invoices.edit’)
->with(‘invoice’, $invoice);
}

Esto nos refiere, que para cada acción en particular, tenemos que inyectar el ID, luego obtener el modelo relacionado al ID proporcionado. Laravel nos provee otra forma de resolver este dilema, con el Route Model Binding que implementa un método conveniente, automáticamente podemos inyectar la instancia del modelo directamente en las rutas.

En otras palabras, en lugar de inyectar el ID de la factura, se puede inyectar la instancia del modelo Invoice que corresponde al ID dado.

Implicita

Existe la forma implícita, en la cual Laravel automáticamente resuelve el modelo Eloquent definido en las rutas o las acciones del controlador, cuyos nombres de variable sugeridos por tipo coincidan con el nombre de segmento de la ruta, por ejemplo:

Route::get('api/users/{user}', function (App\User $user) {
return $user->email;
});

Como la variable $user es declarada del tipo modelo Eloquent App\User y el nombre de la variable $user corresponde al valor de segmento URI {user}, Laravel automáticamente inyectará la instancia del modelo que tenga un ID igual al que se envía en URI. Si por algún motivo no se encuentra el ID, se lanzará un error 404.

Explicita

Para registrar la forma explicita, hay que usar el método model en la ruta y especificar la clase para el parámetro dado. Se puede definir las formas explicitas en el método boot de la clase RouteServiceProvider.


public function boot()
{
parent::boot();

Route::model(‘user’, App\User::class);
}

Ahora, definimos una ruta que contenga un parámetro llamado {user}:

Route::get(‘profile/{user}’, function (App\User $user) {
//
});

Asi, como hemos atado el parámetro {user} al model App\User, una instancia de User será inyectado a la ruta. Entonces, por ejemplo, se podría llamar la ruta profile/1, lo cual inyectará la instancia User desde la base de datos donde el ID sea 1. Al igual que la forma implícita, sino se encuentra una instancia para el ID dado, se lanzará un error HTTP 404.

Laravel Dusk

Cuando se escriben pruebas “end-to-end”, Laravel provee un abanico de metodos de ayuda, que hacen que sea fácil hacer clics en los enlaces, llenar campos de formularios e inclusive enviarlos. En el fondo, Laravel usa el componente Symfony BrowserKit para simular el comportamiento de un navegador web. Sin embargo, si la aplicación usa JavaSript y AJAX para cargar las paginas,   BrowserKit no es para ti.

Laravel Dusk es la nueva herramienta que es introducida a partir de Laravel 5.4 para resolver este problema.

Dusk es una herramienta de navegador para pruebas end-to-end en aplicaciones habilitadas con JavaScript. Este proporcionará la forma correcta de probar la iteraciones concernientes a una pagina web. En otras palabras, se puede usar Dusk para las acciones como clics en botones y enlaces, llenar formularios hasta incluso arrastrar y soltar!.

Para esto, Dusk esta utilizando “ChromeDrive” y “Facebook PHP-Webdriver” para realizar las pruebas end-to-end. Este puede trabajar con cualquier navegador “Selenium”, pero trae ChromeDrive por defecto que nos ayuda ahorrar las configuraciones previas del JDK o Selenium, lo que lo hace muy fácil de usar sin la necesidad de ir a través del proceso de arranque de Selenium e iniciar su servidor cada vez que se necesiten correr las pruebas. Ademas, segun Taylor Otwell, las pruebas en Dusk son muchas mas rápidas que en el Selenium.

En este orden de ideas, Dusk es mas natural que un BrowserKit; no se tiene que esperar a que algo “termine” o usar sleeping  y pausing mientras se espera que las cosas aparezcan. En contraste, Dusk permite aguantar a que ciertas condiciones sean verdaderas en tu código JavaScript o esperar a que los selectores CSS estén disponibles para tener una mejor manera para probar las aplicaciones con JavaScript habilitado.

Además, Dusk tiene entre otras características, guardar un captura de pantalla en las pruebas fallidas automáticamente. De esta forma, se puede observar como estaba la pagina cuando las cosas fueron mal.

Otra característica es que provee de método de ayuda como loginAs, el cual permite asignar una instancia de un usuario de la aplicación, con esto accionará el acceso de usuario, facilitando el trabajo en los URL que se necesiten la autenticación.

También, se permite abrir múltiple ventanas del navegador por prueba, lo cuál es favorable cuando la aplicación tiene integración con sockets y es necesario un tipo de pruebas en estos escenarios. Asimismo, es posible abrir dos ventanas y interactuar con la primera y obtener los resultados en la segunda.

Incluso, Otwell ha agregado algo de información relacionada al entorno de pruebas Dusk; la aplicación contiene u archivo llamado .env.dusk, que define las principales configuraciones del entorno de pruebas.

De manera que, para ejecutar las pruebas Dusk, no se usá PHPUnit directamente. En su lugar, se llamara un comando artisan llamado Dusk, el cual sera un proxy a PHPUnit; esté hará un respaldo del archivo de configuración, para entonces, mover el archivo .env.dusk como archivo de configuración  para ser usado en las pruebas. Una vez terminadas las pruebas, se restaurará el archivo .env a su lugar original.

En conclusión, esta integración es una gran herramienta para las mejores practicas y calidad del software escrito utilizando Laravel.

 

Para los tipos, ¿Enteros o Caracteres?

Hace un tiempo, encontramos la disyuntiva ante los escenarios de variables estilo tipo, entiéndase por ejemplo, un factura puede ser de tipo compra, venta, nota de débito o nota de crédito.

Al momento de hacer un modelado orientado a objetos, pudiéramos decir que se representa por un atributo llamado “type” de la clase cadenas de caracteres. Entonces, el código sería algo como:

<?php

class Invoice extends Model
{
/**
* @const TYPE
*/
const TYPE = [
‘purchase’ => ‘factura compra’,
‘sale’ => ‘factura venta’,
‘debit’ => ‘nota de débito’,
‘credit’ => ‘nota de crédito,
];

/**
* @var string
*/
protected $type;

public __construct()
{
$this->type = self::TYPE[‘sale’];
}
}

El otro escenario planteado, es modelar como el tipo como un entero, entonces el modelado sería algo como:

<?php

class Invoice extends Model
{
/**
* @const TYPE
*/
const TYPE = [
‘purchase’ => 0,
‘sale’ => 1,
‘debit’ => 2,
‘credit’ => 3,
];

/**
* @var int
*/
protected $type;

public __construct()
{
$this->type = self::TYPE[‘sale’];
}
}

De allí surgen varios argumentos que traemos a discusión. Según Sebastían Paaske, con lo enteros, las comparaciones se pueden llevar a cabo en un solo ciclo del procesador, que por el contrario, una cadena de caracteres, suponen un arreglo de varios caracteres, por lo que, en el peor caso, se deben revisar todos los caracteres de la cadena (string).

Aunado, si hablamos en términos de motores SQL, Gail nos muestra sus pruebas de rendimiento, comparando consultas para valores enteros y cadenas de caracteres. Allí se pudo concluir que los rendimientos son más eficientes si manejamos tipo enteros en lugar de cadenas de caracteres.

Asimismo, los enteros son mas eficientes, en cuanto al uso de recursos de espacio de almacenamiento. Un entero (INT) ocupa 4 bytes y entero tipo TINYINT, el cuál se ajuta para modelar un tipo de factura  solamente 1 byte. Por su lado, un VARCHAR para representar ‘factura compra’ utilizaría 15 bytes.

En conclusión, podemos decir que es preferible utilizar tipos numéricos que se puedan representar como enteros en lugar de cadenas de caracteres.

Laracon Online

Esta semana termino el Laracon Online, la conferencia en línea acerca del framework Laravel.

El pasado 8 de Marzo de 2017, se llevo a cabo la conferencia con la participación de desarrolladores apasionados por el framework Laravel creado por Taylor Otwell, el mismo que participo como facilitador con una vista del nuevo Laravel 5.4, preparándonos para el próximo lanzamiento LTS 5.5 del framework.

Por otro lado, las presentaciones de Jeffrey Way, fundador de Laracasts hablando sobre Laravel Mix, Evan You creador de Vue.Js y Jason McCreary creador de Laravel Shift conversando sobre el poder de Git sobresalieron en lo que fue la jornada de todo el día.

En slack se pudo ver con euforia como está comunidad de desarrolladores esta creciendo y tomando auge cada día en las aplicaciones web, haciendo un excelente antesala para lo que será el LaraconUS 2017 en New York el venidero mes de Julio.

Esperamos con ansias que se publiquen los vídeos, para los que no pudimos atender la jornada.

 

 

Manejo de Errores en Laravel

Aún cuando Laravel trae preconfigurado el manejo de errores, encontrarás que algunas aplicaciones necesitan ser personalizadas a los requerimientos del sistema.

Primeramente hablemos de la configuración, en el archivo config/app.php encontramos que la variable APP_DEBUG controla cuanto debe ser el detalle de los mensajes de errores. Por ello, se define que para entornos de desarrollo la variable debe ser true, y para los casos de producción debe ser false.

Ahora bien, todas la excepciones en Laravel son manejadas por la clase App\Exceptions\Handler. Esta clase contiene dos metodos: report y render.

Report

El método report es útil cuando necesitamos loguear los errores a sistemas externos. Por ejemplo, a un servidor remoto syslog. Por defecto, el método report simplemente pasa la clase base de una Excepción. Así, podríamos enviar diferente notificaciones a diferentes logs de la siguiente forma. Asimismo, podríamos guardar en el log de Laravel cualquier excepción.

/**
 * Report or log an exception.
 *
 * This is a great spot to send exceptions to Sentry, Bugsnag, etc.
 *
 * @param  \Exception  $e
 * @return void
 */
public function report(Exception $e)
{
    if ($e instanceof CustomException) {
        //
    }

    return parent::report($e);
}

Render

Este método es el responsable de convertir una excepción en una respuesta HTTP que pudiera ser enviada al navegador. Por defecto, se recibe la excepción base, sin embargo, existe la libertad de enviar a cualquier vista, como se desee.

/**
 * Render an exception into an HTTP response.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Exception  $e
 * @return \Illuminate\Http\Response
 */
public function render($request, Exception $e)
{
    if ($e instanceof CustomException) {
        return response()->view('errors.custom', [], 500);
    }

    return parent::render($request, $e);
}

Por otro lado, si se quiere aún mas personalización, se pueden crear vistas HTML para los diferentes códigos de estado HTTP. Es decir, si queremos singularizar los errores 404, creamos un archivo en la ruta resources/views/errors/404.blade.php. Este archivo reemplazará todos los errores 404 generados en la aplicación.

Logging

Laravel provee una capa simple para acceder a la librería Monolog. De allí que podamos escribir en el log usando el facade Log.

<?php

namespace App\Http\Controllers;

use Log;
use App\User;
use App\Http\Controllers\Controller;

class UserController extends Controller
{
    /**
     * Show the profile for the given user.
     *
     * @param  int  $id
     * @return Response
     */
    public function showProfile($id)
    {
        Log::info('Showing user profile for user: '.$id);

        return view('user.profile', ['user' => User::findOrFail($id)]);
    }
}

Con ello, pudiéramos integrar el uso de log para la captura de errores pudieran no ser vistos por el usuario en el navegador. Supongamos, que no se encuentra el perfil por el id, allí tendríamos un error de aplicación. Aquí podemos captura el error y agregarlo al log, de la siguiente forma

<?php

namespace App\Http\Controllers;

use Log;
use App\User;
use App\Http\Controllers\Controller;
use Illuminate\Database\Eloquent\ModelNotFoundException;

class UserController extends Controller
{
    /**
     * Show the profile for the given user.
     *
     * @param  int  $id
     * @return Response
     */
    public function showProfile($id)
    {
        try {
            return view('user.profile', ['user' => User::findOrFail($id)]);
        catch (ModelNotFoundException $e) {       
            Log::error('User not found with id '.$id);
        }

        return view('user.index');
    }
}

Así, el usuario no se enteraría del error, y los administrador pudieran estar monitoreando el log para posibles errores.

Accesors y Mutators en Laravel

Los “accesors” y “mutators” en Laravel son de mucha utilidad. Nos ayudan al momento de presentar ó guarda los datos, dándole el formato que necesitamos. Los “accessor” son un método de implimentar los “getters” y los “mutators” son la forma de implementar los “setters”.

Supongamos, necesitamos que el nombre de una compañía siempre se muestre en mayúsculas. Para ello, creamos un método llamado getNameAttribute() en el modelo Bussiness. El “accessor” será llamado automáticamente cuando Eloquent trate de recibir el atributo “name”.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Bussiness extends Model
{
    /**
     * Get the namee.
     *
     * @param  string  $value
     * @return string
     */
    public function getNameAttribute($value)
    {
        return strtoupper($value);
    }
}

Como se observa, el valor original se pasa al “accesor”, permitiendo la manipulación, es este caso, convertirlo a mayúsculas. Así cuando se acceda al attributo “name”, Eloquent llama al accessor y se obtiene el valor en mayusculas.

$bussiness = App\Bussiness::find(1);

$name = $user->name;

Mailtrap, la herramienta para el desarrollo de emails

mailtrap

Recientemente hemos buscado notificar de ciertos eventos vía email en el desarrollo de aplicaciones. Para efectos de testing, enviar los correos al log era suficiente para orroborar que estuviera funcionando.

Luego, surgió la necesidad de darle formato con CSS, para mejorar la presentación de las notificaciones. Como la aplicación estará enviando esos mensajes a una cuenta email, que en este caso no es monitoreada por el desarrollador, la pruebas se vuelve tediosas.

Es aquí cuando Mailtrap puede ayudar. Mailtrap es un servidor de correos de pruebas, que permite notificaciones email sin la necesidad de ser enviada  a los usuarios reales de la aplicación.

No solo basta con la capacidad de envío, lo que la hace una poderosa herramienta, se le añade su utilidad para ver los emails de prueba online, reenviar como un email ordinario y compartirlo.

Para ponerlo en funcionamiento, debes registrarte en el sitio Mailtrap y configurar PHP para que utilize las credenciales que se otorgan. En Laravel la configuración puede ser añadida en el archivo .env, por ejemplo

MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=some
MAIL_PASSWORD=password
MAIL_FROM=from@example.com
MAIL_FROM_NAME=Example

 

airMAX

airMAX es una tecnología propietaria de Ubiquiti Networks.  Basada en el procotocolo TDMA y soportada por el estandar 802.11, que a diferencia de este último, ha sido diseñada para usado en exteriores, resolviendo el problema del nodo oculto.

Entre los beneficios del airMAX podemos hablar de la escalibilidad al resolver los problemas de conexiones en exteriores. Baja latencias, dando prioridad a los paquetes de voz y video, así como prioridad sobre las conexiones activas sobre las desocupdas.  Y por último, la velocidad, actualmente podemos hablar de conexiones MIMO con tasas sobre los 150Mbps reales en una configuración PtP.

La nueva generación de AirMax (airMAX ac), ha mejorado dramáticamente la latencia TDMA y la escalabilidad de la redes PtMP. Ubiquiti Networks ha desarrollado su propio hardware que les permite acelerar el procesamiento, logrando el soporte para altas tasas de transferencias y a modulaciones más densas, obteniendo así altos rendimientos.