Como ya sabrán, Laravel hizo la transición a lanzamientos anuales con el lanzamiento de Laravel 8. Anteriormente, las versiones principales se lanzaban cada 6 meses. Esta transición tiene como objetivo aliviar la carga de mantenimiento de la comunidad y desafiar al equipo
]]>Como ya sabrán, Laravel hizo la transición a lanzamientos anuales con el lanzamiento de Laravel 8. Anteriormente, las versiones principales se lanzaban cada 6 meses. Esta transición tiene como objetivo aliviar la carga de mantenimiento de la comunidad y desafiar al equipo de Laravel a ofrecer nuevas funciones sorprendentes y potentes sin introducir cambios importantes.
Laravel 9 sigue las mejoras realizadas en Laravel 8.x introduciendo soporte para los componentes 6.0 de Symfony, Symfomny Mailer, Flysystem 3.0, mejoras de salida en route:list
, un driver de Laravel Scout para la base de datos, una sintáxis nueva para accesors/mutators, la posibilidad de usar Enums en las rutas implicitas, y una variedad de otras correcciones y mejoras de usabilidad.
Laravel 9.x requiere mínimo PHP 8.0.
Versiones anteriores de Laravel usaban la librería Swift Mailer para enviar email. Esa librería no tiene más mantenimiento y ahora fue reemplazada por Symfony Mailer.
Laravel 9.x actualiza la dependencia de Flysystem a la 3.x.
Flysystem se encarga de todas las interacciones con el sistema de archivos ofrecidos por la fachada Storage
.
Laravel 9.x ofrece una nueva forma de definir accesors
y mutators
en Eloquent. En versiones previas de Laravel, la única forma de definirlos era mediante métodos prefixeados en tu modelo:
public function getNameAttribute($value)
{
return strtoupper($value);
}
public function setNameAttribute($value)
{
$this->attributes['name'] = $value;
}
Sin embargo, en Laravel 9.x puedes definir accessors
y mutators
usando un método único, sin prefixes, usando Attribute
como type-hint
.
use Illuminate\Database\Eloquent\Casts\Attribute;
public function name(): Attribute
{
return new Attribute(
get: fn ($value) => strtoupper($value),
set: fn ($value) => $value,
);
}
Además, este nuevo enfoque permite definir accesors
que se pueden cachear, mejorando el rendimiento:
use App\Support\Address;
use Illuminate\Database\Eloquent\Casts\Attribute;
public function address(): Attribute
{
return new Attribute(
get: fn ($value, $attributes) => new Address(
$attributes['address_line_one'],
$attributes['address_line_two'],
),
set: fn (Address $value) => [
'address_line_one' => $value->lineOne,
'address_line_two' => $value->lineTwo,
],
);
}
Eloquent ahora te permite castear tus atributos a Enums definidos en PHP.
Para lograr esto, puedes especificar un atributo y un Enum al que quieres transformarlo en el array $casts
de tu modelo:
use App\Enums\ServerStatus;
/**
* The attributes that should be cast.
*
* @var array
*/
protected $casts = [
'status' => ServerStatus::class,
];
Una vez que definiste el cast para tu modelo, el atributo especificado será automaticamente transformado desde y hacia el Enum elegido:
if ($server->status == ServerStatus::provisioned) {
$server->status = ServerStatus::ready;
$server->save();
}
PHP 8.1 introduce soporte para Enums. Laravel 9 agrega la habilidad de usar un Enum como type-hint
en la definición de tu ruta y Laravel solo invocara la ruta si ese segmento corresponde a un Enum valido. De otra forma, devuelve un 404.
Por ejemplo, dado el siguiente Enum:
enum Category: string
{
case Fruits = 'fruits';
case People = 'people';
}
Puedes definir una ruta que solo será invocada si el segmento {category}
de la ruta es "fruits" o "people". De otra manera, se devolverá una respuesta 404:
Route::get('/categories/{category}', function (Category $category) {
return $category->value;
});
En versiones anteriores de Laravel, podías limitar el segundo modelo de Eloquent en la definición de una ruta como el hijo del modelo anterior.
Por ejemplo, considera la siguiente definición de una ruta que recibe un blog post
por slug
de un usuario específico:
use App\Models\Post;
use App\Models\User;
Route::get('/users/{user}/posts/{post:slug}', function (User $user, Post $post) {
return $post;
});
Cuando se usa una clave implicita para hacer la unión como un parámetro anidado, Laravel automáticamente limita la consulta para recuperar el modelo anidado usando convenciones para adivinar la relación entre el hijo y el padre.
Sin embargo, este comportamiento estaba soportado previamente por Laravel solo cuando se usaba una clave personalizada para limitar la ruta hijo (slug
en este caso).
Ahora, en Laravel 9, puedes indicar a Laravel que limite el "hijo" incluso cuando no hay una clave personalizada definida. Para hacer esto, puedes invocar el método scopeBindings
cuando defines la ruta:
use App\Models\Post;
use App\Models\User;
Route::get('/users/{user}/posts/{post}', function (User $user, Post $post) {
return $post;
})->scopeBindings();
O, puedes indicar a un grupo entero de definiciones de ruta a usar uniones limitadas:
Route::scopeBindings()->group(function () {
Route::get('/users/{user}/posts/{post}', function (User $user, Post $post) {
return $post;
});
});
Ahora puede usar el método controller
para definir un controlador común para todas las rutas dentro del grupo. Luego, al definir las rutas, solo necesitas proporcionar el Controller
que invocan:
use App\Http\Controllers\OrderController;
Route::controller(OrderController::class)->group(function () {
Route::get('/orders/{id}', 'show');
Route::post('/orders', 'store');
});
where
Al usar MySQL o PostgreSQL, ahora se puede agregar el método fullText a las definiciones de columna para generar índices de texto completo:
$table->text('bio')->fullText();
Además, los métodos whereFullText y orWhereFullText se pueden usar para agregar cláusulas "where" de texto completo a una consulta de columnas que tienen índices de texto completo. Laravel transformará estos métodos en el SQL apropiado para el sistema de base de datos subyacente. Por ejemplo, se generará una cláusula MATCH AGAINST para aplicaciones que utilicen MySQL:
$users = DB::table('users')
->whereFullText('bio', 'web developer')
->get();
Si su aplicación interactúa con bases de datos pequeñas o medianas o tiene una carga de trabajo liviana, ahora puede usar el motor de "base de datos" de Scout en lugar de un servicio de búsqueda dedicado como Algolia o MeiliSearch. El motor de la base de datos utilizará cláusulas whereLike
e índices de texto completo cuando filtre los resultados de su base de datos existente para determinar los resultados de búsqueda aplicables para su consulta.
Para aprender más sobre el motor de base de datos Scout, consulte la documentación de Scout.
A veces, es posible que deba transformar una cadena de plantilla Blade sin procesar en HTML válido. Puede lograr esto utilizando el método de renderizado proporcionado por la fachada de Blade. El método de representación acepta la cadena de plantilla Blade y una matriz opcional de datos para proporcionar a la plantilla:
use Illuminate\Support\Facades\Blade;
return Blade::render('Hello, {{ $name }}', ['name' => 'Julian Bashir']);
De manera similar, el método renderComponent
se puede usar para representar un componente de clase dado pasando la instancia del componente al método:
use App\View\Components\HelloComponent;
return Blade::renderComponent(new HelloComponent('Julian Bashir'));
En versiones anteriores de Laravel, los nombres de los slots
se proporcionaban mediante un atributo de nombre en la etiqueta x-slot
:
<x-alert>
<x-slot name="title">
Server Error
</x-slot>
<strong>Whoops!</strong> Something went wrong!
</x-alert>
Sin embargo, a partir de Laravel 9.x, puede especificar el nombre de la ranura usando una sintaxis conveniente y más corta:
<x-slot:title>
Server Error
</x-slot>
Para mayor comodidad, ahora puede usar la directiva @checked
para indicar fácilmente si una entrada de casilla de verificación HTML determinada está "marcada". Esta directiva se repetirá si la condición proporcionada se evalúa como verdadera:
<input type="checkbox"
name="active"
value="active"
@checked(old('active', $user->active)) />
Del mismo modo, la directiva @selected
se puede usar para indicar si una determinada opción de selección debe ser "seleccionada":
<select name="version">
@foreach ($product->versions as $version)
<option value="{{ $version }}" @selected(old('version') == $version)>
{{ $version }}
</option>
@endforeach
</select>
Bootstrap 5 Pagination Views
Laravel ahora incluye vistas de paginación creadas con Bootstrap 5. Para usar estas vistas en lugar de las vistas predeterminadas de Tailwind, puede llamar al método useBootstrapFive
del paginador dentro del método boot
de su clase App\Providers\AppServiceProvider
:
use Illuminate\Pagination\Paginator;
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Paginator::useBootstrapFive();
}
A veces, es posible que necesite acceder al valor de un elemento de matriz anidado determinado al asignar reglas de validación al atributo. Ahora puede lograr esto usando el método Rule::forEach
. El método forEach
acepta una función de clausura que se invocará para cada iteración del atributo de matriz siendo validado, y recibirá el valor del atributo y el nombre de atributo explícito y completamente expandido. La función de clausura debe devolver una matriz de reglas para asignar al elemento de la matriz:
use App\Rules\HasPermission;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
$validator = Validator::make($request->all(), [
'companies.*.id' => Rule::forEach(function ($value, $attribute) {
return [
Rule::exists(Company::class, 'id'),
new HasPermission('manage-company', $value),
];
}),
]);
El kit de inicio de Laravel Breeze ha recibido un modo "API" de scaffolding/andamiaje y una implementación de frontend complementaria de Next.js. Este kit inicial se puede usar para poner en marcha sus aplicaciones Laravel que sirven como backend a través de una API autenticada de Laravel Sanctum para una interfaz de JavaScript.
Ignition, la página de depuración de excepciones de código abierto creada por Spatie, se ha rediseñado desde cero. El nuevo y mejorado Ignition viene con Laravel 9.x e incluye temas claro/oscuro, funcionalidad personalizable de "abrir en el editor" y más.
La salida de CLI de route:list
se ha mejorado significativamente para la versión Laravel 9.x, lo que ofrece una hermosa experiencia nueva al explorar las definiciones de ruta.
test
de ArtisanEl comando test
de Artisan recibió una nueva opción --coverage
que puede usar para explorar la cantidad de cobertura de código que sus pruebas brindan a su aplicación:
php artisan test --coverage
Los resultados de la cobertura de la prueba se mostrarán directamente en la salida de la CLI.
Además, si desea especificar un umbral mínimo que debe cumplir el porcentaje de cobertura de su prueba, puede usar la opción --min
. La suite de pruebas fallará si no se alcanza el umbral mínimo dado:
php artisan test --coverage --min=80.3
Aunque no es exclusivo de Laravel 9.x, Laravel ha ayudado recientemente con la documentación de Soketi, un servidor Web Socket compatible con Laravel Echo escrito para Node.js. Soketi ofrece una excelente alternativa de código abierto a Pusher y Ably para aquellas aplicaciones que prefieren administrar su propio servidor Web Socket.
Para obtener más información sobre el uso de Soketi, consulte la documentación de transmisión y la documentación de Soketi.
Laravel 9.x agrega definiciones "genéricas" mejoradas al componente de colecciones, mejorando el soporte de análisis estático y IDE. Los IDE como PHPStorm o las herramientas de análisis estático como PHPStan ahora comprenderán mejor las colecciones de Laravel de forma nativa.
Laravel 9.x presenta dos funciones helpers
nuevas y convenientes que puede usar en su propia aplicación.
La función str devuelve una nueva instancia de Illuminate\Support\Stringable
para el string dado.
Esta función es equivalente al método Str::of
:
$string = str('Taylor')->append(' Otwell');
// 'Taylor Otwell'
Si no se proporciona ningún argumento a la función str
, la función devuelve una instancia de Illuminate\Support\Str
:
$snake = str()->snake('LaravelFramework');
// 'laravel_framework'
La función to_route
genera una respuesta HTTP de redirección para una ruta con nombre determinada, lo que proporciona una forma expresiva de redirigir a rutas con nombre desde sus rutas y controladores:
return to_route('users.show', ['user' => 1]);
Si es necesario, puede pasar el código HTTP que debe asignarse a la redirección y cualquier encabezado de respuesta adicional como el tercer y cuarto argumento del método to_route
:
return to_route('users.show', ['user' => 1], 302, ['X-Framework' => 'Laravel']);
]]>Laravel 8 continua las mejoras introducidas por Laravel 7.x, incorporando Laravel Jetstream, clases para las model factories, consolidación de migraciones, trabajos por lotes, mejoras en el manejo de limitación de peticiones, mejoras en el manejo de las colas, componentes dinámicos en
]]>Laravel 8 continua las mejoras introducidas por Laravel 7.x, incorporando Laravel Jetstream, clases para las model factories, consolidación de migraciones, trabajos por lotes, mejoras en el manejo de limitación de peticiones, mejoras en el manejo de las colas, componentes dinámicos en Blade, paginación con Tailwind, helpers para testear casos que involucren tiempo, mejoras al comando artisan serve
, mejoras en los event listener, y una variedad de otras correcciones y mejoras de usabilidad.
Laravel Jetstream fue escrito por Taylor Otwell.
Laravel Jetstream es un esqueleto de aplicación bellamente diseñado para Laravel. Jetstream proporciona el punto de partida perfecto para tu próximo proyecto e incluye inicio de sesión, registro, verificación de correo electrónico, autenticación de dos factores, administración de sesiones, soporte de API a través de Laravel Sanctum y administración de equipo opcional. Laravel Jetstream reemplaza y mejora el esqueleto de autenticación que existía en versiones anteriores de Laravel.
Jetstream está diseñado con Tailwind CSS y ofrece su elección de Livewire o Inertia como esqueletos.
Debido a la abrumadora demanda de la comunidad, el esqueleto predeterminado de la aplicación Laravel ahora contiene un directorio app/Models
. ¡Esperamos que disfrutes de este nuevo hogar para tus modelos Eloquent! Todos los comandos relevantes del generador se han actualizado para asumir que los modelos existen dentro del directorio app/Models
, si existe. Si el directorio no existe, Laravel asumirá que tus modelos deben colocarse dentro del directorio app
.
Las clases para Model Factories fueron escritas por Taylor Otwell.
Las model factories de Eloquent fueron re-escritas completamente como clases y mejorado el soporte para las relaciones como ciudadanos de primera.
Por ejemplo, la UserFactory
incluída por defecto en Laravel queda así:
<?php
namespace Database\Factories;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class UserFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = User::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
'name' => $this->faker->name,
'email' => $this->faker->unique()->safeEmail,
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10),
];
}
}
Gracias al nuevo trait HasFactory
disponible en los modelos generados, puede utilizarse de la siguiente forma:
use App\Models\User;
User::factory()->count(50)->create();
Como las model factories ahora son simples clases de PHP, las transformaciones de estado pueden escribirse como métodos de clase. Además, puedes agregar otras clases de ayuda, tantas como necesites.
Por ejemplo, tu modelo User
puede tener un estado suspended
que modifica el valor por defecto de uno de los atributos. Puedes definir las transformaciones de estado usando el método state
de la clase base. Puedes nombrar este método como quieras. Después de todo, es un método típico de PHP:
/**
* Indicate that the user is suspended.
*
* @return \Illuminate\Database\Eloquent\Factories\Factory
*/
public function suspended()
{
return $this->state([
'account_status' => 'suspended',
]);
}
Después de definir el método de transformación de estado, podemos usarlo así:
use App\Models\User;
User::factory()->count(5)->suspended()->create();
Como se mencionó, las model factories de Laravel 8 contienen soporte de primera clase para las relaciones. Entonces, asumiendo que nuestro modelo User
tiene un método de relación posts
, podemos simplemente ejecutar el siguiente código para generar un usuario con tres publicaciones:
$users = User::factory()
->hasPosts(3, [
'published' => false,
])
->create();
Para facilitar el proceso de actualización, se lanzó el paquete laravel/legacy-factories para brindar soporte a la iteración anterior de model factories en Laravel 8.x.
Las model factories reescritas de Laravel contienen muchas más características que pensamos que te encantarán. Para obtener más información sobre las model factories, consulte la documentación de prueba de la base de datos.
Consolidación de migraciones fue contribuido por Taylor Otwell.
A medida que crece su aplicación, puede acumular más y más migraciones a lo largo del tiempo. Esto puede hacer que su carpeta de migraciones crezca con potencialmente cientos de migraciones. Si está utilizando MySQL o PostgreSQL, ahora puede "aplastar" sus migraciones en un solo archivo SQL. Para comenzar, ejecute el comando schema: dump
:
php artisan schema:dump
// Volcar el esquema de la base de datos actual y eliminar todas las migraciones existentes...
php artisan schema:dump --prune
Cuando ejecutas este comando, Laravel escribirá un archivo "esquema" en tu directorio database/schema
. Ahora, cuando intente migrar su base de datos y no se hayan ejecutado otras migraciones, Laravel ejecutará primero el SQL del archivo de esquema. Después de ejecutar los comandos del archivo de esquema, Laravel ejecutará las migraciones restantes que no formaban parte del esquema volcado.
Trabajos por lotes fue contribuido por Taylor Otwell & Mohamed Said.
La función de procesamiento de trabajos por lotes de Laravel le permite ejecutar fácilmente un lote de trabajos y luego realizar alguna acción cuando el lote de trabajos se haya completado.
El nuevo método batch
de la fachada Bus
se puede utilizar para despachar un lote de trabajos. Por supuesto, el procesamiento por lotes es principalmente útil cuando se combina con callbacks. Por lo tanto, puede usar los métodos then
, catch
y finally
para definir callbacks para todo el lote. Cada una de estas callbacks recibirá una instancia Illuminate\Bus\Batch
cuando se invoquen:
use App\Jobs\ProcessPodcast;
use App\Podcast;
use Illuminate\Bus\Batch;
use Illuminate\Support\Facades\Bus;
use Throwable;
$batch = Bus::batch([
new ProcessPodcast(Podcast::find(1)),
new ProcessPodcast(Podcast::find(2)),
new ProcessPodcast(Podcast::find(3)),
new ProcessPodcast(Podcast::find(4)),
new ProcessPodcast(Podcast::find(5)),
])->then(function (Batch $batch) {
// Todos los trabajos se completaron con éxito...
})->catch(function (Batch $batch, Throwable $e) {
// Se detectó el primer error del lote...
})->finally(function (Batch $batch) {
// El lote se terminó de ejecutar...
})->dispatch();
return $batch->id;
Para obtener más información sobre el procesamiento de trabajos por lotes, consulte la documentación de colas.
Las mejoras en limitación de peticiones fue contribuido por Taylor Otwell.
La función de limitación de peticiones de Laravel se ha mejorado con más flexibilidad y potencia, al tiempo que mantiene la compatibilidad hacia atrás con la API de middleware "throttle" de la versión anterior.
Los limitadores de peticiones se definen utilizando el método for
de la fachada RateLimiter
. El método for
acepta un nombre de limitador de peticiones y un closure que devuelve la configuración de límite que debe aplicarse a las rutas a las que se les asigna este limitador de peticiones:
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;
RateLimiter::for('global', function (Request $request) {
return Limit::perMinute(1000);
});
Dado que los callbacks del limitador de peticiones reciben una instancia de la solicitud HTTP entrante, puede crear el límite de peticiones apropiado de forma dinámica en función de la solicitud entrante o del usuario autenticado:
RateLimiter::for('uploads', function (Request $request) {
return $request->user()->vipCustomer()
? Limit::none()
: Limit::perMinute(100);
});
A veces, es posible que desee segmentar los límites por algún valor arbitrario. Por ejemplo, es posible que desee permitir que los usuarios accedan a una ruta determinada 100 veces por minuto por dirección IP. Para lograr esto, puede usar el método by
cuando construya su límite de solicitudes:
RateLimiter::for('uploads', function (Request $request) {
return $request->user()->vipCustomer()
? Limit::none()
: Limit::perMinute(100)->by($request->ip());
});
Se pueden adjuntar limitadores de peticiones a rutas o grupos de rutas usando el middleware throttle
. El middleware throttle
acepta el nombre del limitador que desea asignar a la ruta:
Route::middleware(['throttle:uploads'])->group(function () {
Route::post('/audio', function () {
//
});
Route::post('/video', function () {
//
});
});
Para aprender más acerca de esta función, por favor consulta la documentación de enrutamiento.
Las mejoras en el Modo Mantenimiento fueron contribuidas por Taylor Otwell inspirado por Spatie.
En versiones anteriores de Laravel, la función del modo mantenimiento php artisan down
se puede omitir usando una "lista de permitidos" de direcciones IP que tenían permiso para acceder a la aplicación. Esta característica se ha eliminado en favor de una solución de "clave secreta"/token más simple.
Mientras está en modo mantenimiento, puede usar la opción secret
para especificar un token de omisión del modo de mantenimiento:
php artisan down --secret="1630542a-246b-4b66-afa1-dd72a4c43515"
Después de colocar la aplicación en modo mantenimiento, puede navegar a la URL de la aplicación que coincide con este token y Laravel emitirá una cookie de omisión del modo de mantenimiento a su navegador:
https://example.com/1630542a-246b-4b66-afa1-dd72a4c43515
Cuando acceda a esta ruta oculta, será redirigido a la ruta /
de la aplicación. Una vez que la cookie haya sido enviada a su navegador, podrá navegar por la aplicación normalmente como si no estuviera en modo de mantenimiento.
Si utilizas el comando php artisan down
durante el deployment, tus usuarios pueden encontrar errores ocasionalmente al acceder a la aplicación mientras se actualizan las dependencias de Composer u otros componentes de la infraestructura. Esto ocurre porque una parte importante de Laravel debe iniciarse para determinar que su aplicación está en modo mantenimiento y presentar la vista del modo mantenimiento utilizando Blade.
Por esta razón, Laravel ahora permite pre-renderizar una vista en modo de mantenimiento que se devolverá al comienzo del ciclo de la solicitud. Esta vista se presenta antes de que se haya cargado cualquiera de las dependencias de la aplicación. Puede pre-renderizar una plantilla de su elección usando la opción render
del comando down
:
php artisan down --render="errors::503"
catch
para trabajos anónimosLas función catch
fue contribuida por Mohamed Said.
Con el nuevo método catch
, ahora puede proporcionar un closure que debe ejecutarse si no se completa correctamente un trabajo encolado anónimo después de agotar todos los reintentos configurados de la cola:
use Throwable;
dispatch(function () use ($podcast) {
$podcast->publish();
})->catch(function (Throwable $e) {
// Este trabajo falló...
});
Componentes dinámicos en Blade fue contribuido por Taylor Otwell.
A veces es posible que necesite renderizar un componente pero no saber qué componente debe renderizarse hasta el tiempo de ejecución. En esta situación, ahora puede usar el componente dynamic-component
incorporado en Laravel para renderizar el componente basado en un valor de tiempo de ejecución o variable:
<x-dynamic-component :component="$componentName" class="mt-4" />
Para obtener más información sobre los componentes de Blade, consulte la documentación de Blade.
Las mejoras en Event Listener fueron contribuidas por Taylor Otwell.
Los event listeners basados en closures ahora pueden registrarse solamente pasando un closure al método Event::listen
. Laravel inspeccionará el closure para determinar qué tipo de evento maneja el event listener:
use App\Events\PodcastProcessed;
use Illuminate\Support\Facades\Event;
Event::listen(function (PodcastProcessed $event) {
//
});
Además, los event listeners basados en closures ahora se pueden marcar como encolables usando la función Illuminate\Events\queueable
:
use App\Events\PodcastProcessed;
use function Illuminate\Events\queueable;
use Illuminate\Support\Facades\Event;
Event::listen(queueable(function (PodcastProcessed $event) {
//
}));
Al igual que los trabajos en cola, puedes utilizar los métodos onConnection
, onQueue
y delay
para personalizar la ejecución del event listener:
Event::listen(queueable(function (PodcastProcessed $event) {
//
})->onConnection('redis')->onQueue('podcasts')->delay(now()->addSeconds(10)));
Si deseas manejar fallas en event listeners anónimos, puedes proporcionar un closure al método catch
mientras defines el event listener queueable
:
use App\Events\PodcastProcessed;
use function Illuminate\Events\queueable;
use Illuminate\Support\Facades\Event;
use Throwable;
Event::listen(queueable(function (PodcastProcessed $event) {
//
})->catch(function (PodcastProcessed $event, Throwable $e) {
// El listener falló...
}));
Funciones helper para pruebas con tiempos fueron contribuidos por Taylor Otwell inspirado en Ruby on Rails.
Cuando se hace pruebas, puede necesitarse modificar la hora devuelta por funciones helper como now
o Illuminate\Support\Carbon::now()
. La clase base de Laravel ahora incluye helpers que permiten manipular la hora actual:
public function testTimeCanBeManipulated()
{
// Viajar al futuro...
$this->travel(5)->milliseconds();
$this->travel(5)->seconds();
$this->travel(5)->minutes();
$this->travel(5)->hours();
$this->travel(5)->days();
$this->travel(5)->weeks();
$this->travel(5)->years();
// Viajar al pasado...
$this->travel(-5)->hours();
// Viajar a un momento en particular...
$this->travelTo(now()->subHours(6));
// Volver al presente...
$this->travelBack();
}
artisan serve
Las mejoras en artisan serve
fueron contribuidas por Taylor Otwell.
El comando Artisan serve
se ha mejorado con la recarga automática cuando se detectan cambios en las variables de entorno dentro de su archivo local .env
. Anteriormente, el comando tenía que detenerse y reiniciarse manualmente.
El paginador de Laravel se ha actualizado para utilizar Tailwind CSS de forma predeterminada. Tailwind CSS es un framework CSS de bajo nivel altamente personalizable que brinda todos los componentes básicos que se necesitan para crear diseños a medida sin ningún diseño específico que tengas que luchar para anular. Por supuesto, las vistas Bootstrap 3 y 4 también permanecen disponibles.
En versiones anteriores de Laravel, RouteServiceProvider
contenía una propiedad $namespace
. El valor de esta propiedad era automáticamente prefijado en las definiciones de ruta del controlador y las llamadas al método action
o URL::action
. En Laravel 8.x, esta propiedad es null
por defecto. Esto significa que Laravel no realizará ningún prefijado automático para los namespaces. Por lo tanto, en las nuevas aplicaciones de Laravel 8.x, las definiciones de ruta de los controladores deben definirse utilizando la sintaxis estándar de PHP:
use App\Http\Controllers\UserController;
Route::get('/users', [UserController::class, 'index']);
Las llamadas a los métodos relacionados con action
deben usar la misma sintaxis:
action([UserController::class, 'index']);
return Redirect::action([UserController::class, 'index']);
Si prefieres el estilo Laravel 7.x para prefijos de controladores en el archivo de rutas, puedes simplemente completar la propiedad $namespace
en el RouteServiceProvider
de la aplicación.
Laravel 7 continua con las mejoras realizadas en Laravel 6.x, introduciendo Laravel Airlock, mejoras en la velocidad de enrutamiento, conversiones personalizadas de atributos en Eloquent, etiquetas para componentes de Blade, operaciones fluidas con strings, un cliente HTTP enfocado en desarrolladores, soporte para CORS de base, mejoras en el scope
]]>Laravel 7 continua con las mejoras realizadas en Laravel 6.x, introduciendo Laravel Airlock, mejoras en la velocidad de enrutamiento, conversiones personalizadas de atributos en Eloquent, etiquetas para componentes de Blade, operaciones fluidas con strings, un cliente HTTP enfocado en desarrolladores, soporte para CORS de base, mejoras en el scope de los modelos obtenidos por Routes, personalización de Stubs para tests, mejoras en las colas con base de datos, múltiples drivers para email, un nuevo comando artisan test
, y una variedad de otras correcciones y mejoras de usabilidad.
Laravel Airlock provee un sistema de autenticación ligero para SPAs, aplicaciones móviles, y APIs simples basadas en tokens. Airlock permite a cada usuario de tu aplicación generar múltiples tokens de API para su cuenta. Estos tokens pueden ser otorgados habilidades y alcances que especifican que acciones pueden realizar esos tokens.
Para más información, revisar la documentación de Airlock.
Laravel tiene una variedad de tipos preconstruidos para hacer conversiones; sin embargo, ocasionalmente puedes necesitar definir tus propios tipos de conversión. Puedes lograr esto definiendo una clase que implementa la interfaz CastsAttributes
.
Clases que implementen esta interfaz deben definir métodos get
y set
. El método get
es el responsable de transformar el valor crudo de la base de datos al valor convertido, mientras que el método set
debe transformar el valor convertido al valor crudo para guardar en la base de datos. A modo de ejemplo, vamos a re-implementar el tipo de conversión json
que viene en el framework:
<?php
namespace App\Casts;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
class Json implements CastsAttributes
{
/**
* Cast the given value.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
* @param mixed $value
* @param array $attributes
* @return array
*/
public function get($model, $key, $value, $attributes)
{
return json_decode($value, true);
}
/**
* Prepare the given value for storage.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
* @param array $value
* @param array $attributes
* @return string
*/
public function set($model, $key, $value, $attributes)
{
return json_encode($value);
}
}
Una vez que definimos estos tipos, puedes asignarlo al atributo de un modelo usando el nombre de la clase:
<?php
namespace App;
use App\Casts\Json;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'options' => Json::class,
];
}
Para aprender cómo escribir tipos personalizdos de conversión, incluyendo como convertir a Value Objects, por favor consulta la documentación de Eloquent.
Los componentes de Blade fueron reformados para permitir su renderizado basado en etiquetas, manejo de atributos, clases y más. Dado que la reforma de los componentes de Blade es tan extensa, por favor consulta la documentación completa para aprender más sobre sus características.
En resumen, un componente ahora puede asociarse a una clase que especifica la información que acepta. Todas las propiedades y métodos públicos definidos en la clase del componente estarán disponibles automáticamente a la vista del componente. Cualquier atributo extra agregado por HTML puede ser manipulado automáticamente a través de la variable $attribute
.
En este ejemplo, asumimos que App\View\Components\Alert
es un componente definido de la siguiente forma:
<?php
namespace App\View\Components;
use Illuminate\View\Component;
class Alert extends Component
{
/**
* The alert type.
*
* @var string
*/
public $type;
/**
* Create the component instance.
*
* @param string $type
* @return void
*/
public function __construct($type)
{
$this->type = $type;
}
/**
* Get the class for the given alert type.
*
* @return string
*/
public function classForType()
{
return $this->type == 'danger' ? 'alert-danger' : 'alert-warning';
}
/**
* Get the view / contents that represent the component.
*
* @return \Illuminate\View\View|string
*/
public function render()
{
return view('components.alert');
}
}
Y, asumiendo que el template del componente está definido de la siguiente forma:
<!-- /resources/views/components/alert.blade.php -->
<div class="alert {{ $classForType }}" {{ $attributes }}>
{{ $heading }}
{{ $slot }}
</div>
El componente puede renderizarse en otra vista de Blade usando su etiqueta:
<x-alert type="error" class="mb-4">
<x-slot name="heading">
Alert content...
</x-slot>
Default slot content...
</x-alert>
Como mencionamos, esto es solo un pequeño ejemplo de la reforma de funcionalidad a los componentes de Blade en Laravel 6 y no llega a demostrar componentes anónimos, en línea, y otras características. Por favor consulta la documentación completa de Blade para aprender más.
La sintáxis @component
para componentes Blade no se removió ni se removerá.
Laravel ahora provee un API mínima y expresiva alrededor del cliente HTTP Guzzle, permitiendo hacer peticiones HTTP rápidamente para comunicarse con otras aplicaciones web. El wrapper de Laravel alrededor de Guzzle está enfocado en los casos más comunes y es una excelente experiencia para el desarrollador. Por ejemplo, el cliente hace muy fácil hacer un POST a una interfaz con datos en json:
use Illuminate\Support\Facades\Http;
$response = Http::withHeaders([
'X-First' => 'foo',
'X-Second' => 'bar'
])->post('http://test.com/users', [
'name' => 'Taylor',
]);
return $response['id'];
Además, el cliente HTTP provee simplicidad a la hora de testear:
Http::fake([
// Stub a JSON response for GitHub endpoints...
'github.com/*' => Http::response(['foo' => 'bar'], 200, ['Headers']),
// Stub a string response for Google endpoints...
'google.com/*' => Http::response('Hello World', 200, ['Headers']),
// Stub a series of responses for Facebook endpoints...
'facebook.com/*' => Http::sequence()
->push('Hello World', 200)
->push(['foo' => 'bar'], 200)
->pushStatus(404),
]);
Para aprender más sobre todas las características del cliente HTTP, por favor consultar la documentación.
Seguramente estes familiarizado con la clase Illuminate\Support\Str, que provee una variedad de operaciones de manipulación de strings. Laravel 7 ahora ofrece un enfoque más orientado a objetos, con manipulaciones de strings declaradas de forma fluida. Puedes crear tu objeto Illuminate\Support\Stringable de forma fluida con el método Str::of
. Una variedad de métodos pueden ser encadenados al objeto para manipular el string:
return (string) Str::of(' Laravel Framework 6.x ')
->trim()
->replace('6.x', '7.x')
->slug();
Para más información en los métodos disponibles a través de manipulación de strings de forma fluida, por favor consulte la documentación completa.
Algunas veces puedes querer resolver modelos de Eloquent usando otra columna que la de id
. Para hacer eso, Laravel 7 permite specificar la columna directamente en el parámetro de la ruta:
Route::get('api/posts/{post:slug}', function (App\Post $post) {
return $post;
});
A veces, cuando se enlazan múltiples modelos Eloquent en una misma definición de ruta, puedes querer limitar el alcance del segundo modelo Eloquent de tal forma que sea un hijo del primer modelo Eloquent. Por ejemplo, consideremos la situación en la que obtienes un post por slug de un usuario específico:
use App\Post;
use App\User;
Route::get('api/users/{user}/posts/{post:slug}', function (User $user, Post $post) {
return $post;
});
Laravel 7 automáticamente limita el alcance de la consulta para obtener el modelo anidado, usando convenciones para adivinar la relación con el padre. En este caso, asume que el modelo User
tiene una relación posts
(el plural del parametro de ruta) que puede usarse para obtener el modelo Post
.
Para más información en Route Model Binding, por favor consulte la documentación.
Laravel 7 permite la configuración de múltiples "mailers" para una misma aplicación.
Cada "mailer" se puede configurar por separado y pueden tener su propio "transporte", permitiendo a tu aplicación utilizar diferentes servicios para distintos tipos de mensajes. Por ejemplo, tu aplicación puede usar Postmark para mandar mails transaccionales, mientras usa Amazon SES para enviar mails masivos.
Por defecto, Laravel utiliza el mailer
configurado como default
en tu configuración de mail
. Sin embargo, puedes usar el método mailer
para enviar un mensaje usando un mailer en particular:
Mail::mailer('postmark')
->to($request->user())
->send(new OrderShipped($order));
Laravel 7 incluye un método para matchear rutas compiladas a través del comando route:cache
. En aplicaciones grandes (por ejemplo, con 800 rutas o más), estas mejoras pueden duplicar las peticiones por segundo de una aplicación "Hello World" de prueba. No es necesario aplicar cambios a tus aplicaciones.
Laravel 7 incluye soporte de primera mano para configurar respuestas a peticiones Cross-Origin Resource Sharing (CORS) OPTIONS
integrando el popular paquete Laravel CORS de Barry vd. Heuvel. Un nuevo archivo de configuración para cors
está incluido por defecto en las aplicaciones de Laravel.
Para más información, por favor consulta la documentación de CORS.
A veces se necesita aplicar conversiones mientras ejecutamos una query, como cuando seleccionamos un valor crudo de una tabla. Por ejemplo, consideremos la siguiente query:
use App\Post;
use App\User;
$users = User::select([
'users.*',
'last_posted_at' => Post::selectRaw('MAX(created_at)')
->whereColumn('user_id', 'users.id')
])->get();
El atributo last_posted_at
en los resultados de la query será un string crudo. Puede ser conveniente se pudieramos aplicar una conversión a date
al atributo mientras ejecutamos la query. Para lograr esto, podemos usar el método withCasts
provisto por Laravel 7:
$users = User::select([
'users.*',
'last_posted_at' => Post::selectRaw('MAX(created_at)')
->whereColumn('user_id', 'users.id')
])->withCasts([
'last_posted_at' => 'date'
])->get();
En versiones anteriores de Laravel, el driver database
para queues no era considerado robusto para usar en producción, debido a los deadlocks. Sin embargo, Laravel 7 provee mejoras a aplicaciones usando queues con bases de datos MySQL 8+ como driver. Utilizando la clausula FOR UPDATE SKIP LOCKED
y otras mejoras de SQL, el driver database
ahora puede usarse de forma segura en aplicaciones de producción con alto volumen.
test
de ArtisanAdemás del comando phpunit
, ahora puedes usar el comando test
de Artisan para correr tus tests. Este comando provee una hermosa experiencia de usuario en la consola, y más información correspondiente al test que se está corriendo. Adicionalmente, el comando frena automáticamente en la primer falla:
php artisan test
Todo argumento que puede pasarse a phpunit
puede también pasarse al comando test
de Artisan:
php artisan test --group=feature
El comando make
de Artisan permiten crear una variedad de clases, como Controllers, Jobs, Migrations y Tests. Estas clases son generadas usando archivos "stub" que son pre-cargados con los valores que se ingresan. Sin embargo, a veces es necesario realizar pequeños cambios en los archivos generados por Artisan. Para lograr esto, Laravel 7 provee un comando stub:publish
para publicar los stubs más comunes para su personalización:
php artisan stub:publish
Los stubs publicados se encuentran en el directorio stubs
en la raíz de la aplicación. Cualquier cambio que se hagan a esos stubs será reflejado cuando generes la clase correspondiente usando el comando make
de Artisan.
maxExceptions
ConfigurationA veces puedes necesitar que un job
específico se ejecute muchas veces, pero que debería fallar si los reintentos son activados por un número dado de excepciones. En Laravel 7, puedes definir maxExceptions
como propiedad en la clase de tu job
:
<?php
namespace App\Jobs;
class ProcessPodcast implements ShouldQueue
{
/**
* The number of times the job may be attempted.
*
* @var int
*/
public $tries = 25;
/**
* The maximum number of exceptions to allow before failing.
*
* @var int
*/
public $maxExceptions = 3;
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
Redis::throttle('key')->allow(10)->every(60)->then(function () {
// Lock obtained, process the podcast...
}, function () {
// Unable to obtain lock...
return $this->release(10);
});
}
}
En este ejemplo, el job
es liberado por diez segundos si la aplicación es incapaz de obtener un cerrojo de Redis y continuará hasta que se haya reintentado 25 veces. Sin embargo, el job
fallará si tres excepciones no manejadas son arrojadas por el mismo.
Laravel sacó una nueva versión de su framework, y esta vez promete seguir el sistema de Versionado Semántico, es decir, que sigue el siguiente formato: major.minor.patch, por lo que a partir de ahora, vamos a ver los saltos de versiones de Laravel como Laravel 7.0, Laravel 8.0 mucho más rápido.
También es una versión LTS (long-term support), que viene acompañado de 2 años de soporte para bugs y 3 años para parches de seguridad. Esto puede ser de utilidad para empresas que no tienen la dinámica de estar actualizando el framework de su producto cada 6 meses, y prefieren estirar los tiempos (aunque saltar de un LTS a otro, implica un upgrade más brusco).
A continuación, los cambios de la nueva versión de Laravel
Laravel 6.0 (LTS) continúa las mejoras realizadas en Laravel 5.8 mediante la introducción de versiones semánticas, compatibilidad con Laravel Vapor, respuestas de autorización mejoradas, middleware para Jobs, Collections diferidas, mejoras en sub-queries, la extracción del scaffolding frontend al paquete de Composer laravel/ui
, y una variedad de otras correcciones de errores y mejoras de usabilidad.
El paquete Laravel (laravel/framework
) ahora sigue el estándar de versiones semántico. Esto hace que el marco sea coherente con los otros paquetes Laravel de origen que ya siguieron este estándar de versiones. El ciclo de lanzamiento de Laravel permanecerá sin cambios.
Laravel 6.0 proporciona compatibilidad con Laravel Vapor, una plataforma de implementación serverless y autoescalable para Laravel. Vapor resume la complejidad de administrar las aplicaciones de Laravel en AWS Lambda, así como la interfaz de esas aplicaciones con colas SQS, bases de datos, clústeres Redis, networking, CloudFront CDN y más.
Laravel 6.0 viene con Ignition, una nueva página de excepciones de código abierto creada por Freek Van der Herten y Marcel Pociot. Ignition ofrece muchos beneficios con respecto a versiones anteriores, como un archivo mejorado de errores de Blade y manejo de números de línea, soluciones ejecutables para problemas comunes, edición de código, uso compartido de excepciones y una experiencia de usuario mejorada.
En versiones anteriores de Laravel, era difícil recuperar y exponer mensajes de autorización personalizados a los usuarios finales. Esto dificultaba explicar a los usuarios finales exactamente por qué se denegó una solicitud en particular. En Laravel 6.0, ahora es mucho más fácil usar mensajes de respuesta de autorización y el nuevo método Gate::inspect
. Por ejemplo, dado el siguiente método de política:
/**
* Determine si el usuario puede ver el vuelo dado. *
*
* @param \App\User $user
* @param \App\Flight $flight
* @return mixed
*/
public function view(Usuario $usuario, Vuelo $vuelo) {
return $this->deny('Explicación de la negación');
}
La respuesta y el mensaje de la política de autorización se pueden recuperar fácilmente utilizando el método Gate::inspect
:
$respuesta = Gate::inspect('view', $vuelo);
if ($respuesta->allowed()) {
// El usuario está autorizado para ver el vuelo ...
}
if ($respuesta->denied()) {
echo $respuesta->message();
}
Además, estos mensajes personalizados se devolverán automáticamente a su interfaz cuando use métodos auxiliares como $this->authorize
o Gate::authorize
de sus rutas o controladores.
El Job Middleware te permite envolver lógica personalizada sobre la ejecución de los Jobs encolados, reduciendo el código repetido en los Jobs. Por ejemplo, en versiones anteriores de Laravel, podrías envolver la lógica de un Job en un callback para limitar el acceso:
/**
* Ejecutar el trabajo.
*
* @return void
*/
public function handle()
{
Redis::throttle('key')->block(0)->allow(1)->every(5)->then(function () {
info('Se obtuvo el lock...');
// Manejar el Job...
}, function () {
// No se pudo obtener el lock...
return $this->release(5);
});
}
En Laravel 6.0, esta lógica se puede aplicar en un middleware de trabajo, lo que le permite mantener su trabajo libre.
<?php
namespace App\Jobs\Middleware;
use Illuminate\Support\Facades\Redis;
class RateLimited
{
/**
* Procesar el Job encolado.
*
* @param mixed $job
* @param callable $next
* @return mixed
*/
public function handle($job, $next)
{
Redis::throttle('key')
->block(0)->allow(1)->every(5)
->then(function () use ($job, $next) {
// Se obtuvo el lock...
$next($job);
}, function () use ($job) {
// No se pudo obtener el lock...
$job->release(5);
});
}
}
Luego de crear un middleware, pueden adjuntarse a un Job
retornandolo directamente desde el método middleware
.
use App\Jobs\Middleware\RateLimited;
/**
* Elegir que middleware aplica a este Job
*
* @return array
*/
public function middleware()
{
return [new RateLimited];
}
Muchos desarrolladores ya disfrutan de los poderosos métodos de colección de Laravel. Para complementar la ya poderosa clase Collection
, Laravel 6.0 presenta una colección LazyCollection
, que aprovecha los generadores de PHP para permitirte trabajar con grandes sets de datos mantienendo un uso bajo de memoria.
Por ejemplo, imagine que su aplicación necesita procesar un log de varios gigabytes mientras aprovecha los métodos de Collection
de Laravel para analizar los registros. En lugar de leer todo el archivo en memoria a la vez, se pueden usar LazyCollections
para mantener solo una pequeña parte del archivo en la memoria en un momento dado:
use App\LogEntry;
use Illuminate\Support\LazyCollection;
LazyCollection::make(function () {
$handle = fopen('log.txt', 'r');
while (($line = fgets($handle)) !== false) {
yield $line;
}
})
->chunk(4)
->map(function ($lines) {
return LogEntry::fromLines($lines);
})
->each(function (LogEntry $logEntry) {
// Procesar el log...
});
O imagine que necesita recorrer 10.000 modelos Eloquent
. Cuando se usan colecciones tradicionales de Laravel, todos los 10,000 modelos Eloquent deben cargarse en la memoria al mismo tiempo:
$users = App\User::all()->filter(function ($user) {
return $user->id > 500;
});
Sin embargo, a partir de Laravel 6.0, el método cursor
del QueryBuilder
se ha actualizado para devolver una instancia de LazyCollection
. Un modelo Eloquent
cargado en la memoria a la vez. En este ejemplo, la devolución de filter
no se ejecuta hasta que iteramos sobre cada usuario individualmente, lo que permite una reducción drástica en el uso de la memoria:
$users = App\User::cursor()->filter(function ($user) {
return $user->id > 500;
});
foreach ($users as $user) {
echo $user->id;
}
Laravel 6.0 presenta varias correcciones y mejoras nuevas para el soporte de subconsultas de bases de datos. Por ejemplo, imaginemos que tenemos una tabla destinations
(destinos) y una tabla de flights
(vuelos).
Usando la nueva funcionalidad de selección de subconsulta en Laravel 6.0, podemos seleccionar todos los destinos y el vuelo más reciente que ha llegado a ese destino utilizando una sola consulta:
return Destination::addSelect(['last_flight' => Flight::select('name')
->whereColumn('destination_id', 'destinations.id')
->orderBy('arrived_at', 'desc')
->limit(1)
])->get();
Además, podemos usar nuevas características de subconsulta agregadas a la función orderBy
del generador de consultas. Nuevamente, esto se puede hacer mientras se ejecuta una única consulta en la base de datos:
return Destino::orderByDesc(
Vuelo::select('arrived_at')
->whereColumn('destination_id', 'destinations.id')
->orderBy('arrived_at', 'desc')
->limit(1)
)->get();
El scaffolding frontend que normalmente se proporciona con versiones anteriores de Laravel se ha extraído en un paquete de laravel/ui
. Esto permite que el scaffolding de interfaz de usuario se desarrolle y versione por separado del framework. Como resultado de este cambio, no hay código Bootstrap o Vue presente en el scaffolding predeterminado del framework, y el comando make:auth
también se ha extraído del framework.
Para restaurar el scaffolding Vue/Bootstrap tradicional presente en versiones anteriores de Laravel, hay que instalar el paquete laravel/ui
y usar el comando artisan ui
para instalar el scaffolding frontend:
composer require laravel/ui
php artisan ui vue --auth
]]>Laravel Telescope es un nuevo asistente de depuración para Laravel, escrito por Mohamed Said y Taylor Otwell. Es de código abierto, gratuito, disponible en Github. Puedes agregarlo a tus aplicaciones como una dependencia a travès de Composer. Una vez
]]>Laravel Telescope es un nuevo asistente de depuración para Laravel, escrito por Mohamed Said y Taylor Otwell. Es de código abierto, gratuito, disponible en Github. Puedes agregarlo a tus aplicaciones como una dependencia a travès de Composer. Una vez instalado, puedes accederlo a través de la url /telescope
.
Si alguna vez usaste Clockwork o Laravel Debugbar, imaginatelos pero como una interfaz independiente, con superpoderes. Telescope está compuesto de una serie de guardianes que "observan" cada request que entra a tu aplicación, sean por HTTP, desde la línea de comandos, desde el Scheduler, o desde una queue. Estos "watchers" capturan todo tipo de información sobre los requests y la información que tienen asociada: consultas a la base de datos y su tiempo de ejecución, golpes al caché, eventos disparados, emails enviados, y mucho más. Hay distintas pestañas para cada uno de ellos.
Veamos para qué sirve cada una de las pestañas y qué nos dejan revisar. Todas muestran una lista y además permiten adentrarnos al detalle de cada uno de los ítems.
Esta pestaña nos permite ver todas las peticiones HTTP que lleguen a nuestra aplicación. Puedes inspeccionarlos y ver mucha información útil asociada.
Cada página individual también muestra datos de otros "watchers" que están relacionados con la petición; por ejemplo, todas las bases de datos asociadas y cuanto tardaron; cual es el usuario autenticado para cada request, y mucho más.
La pestaña de comandos muestra una lista de los comandos que se ejecutaron y sus códigos de salida. Cuando los inspeccionamos, también podemos ver los argumentos, opciones y elementos relacionados con la ejecución del mismo.
Schedule muestra la lista de tareas programadas que se han ejecutado. En la lista detallada, podemos ver la expresión cron utilizada, cuando se ejecutó, etc.
La pestaña de Jobs nos muestra todos los trabajos que se ejecutaron o se están ejecutando. Es similar a Horizon, pero Horizon es exclusivo de Redis, y no es solo una interfaz gráfica sino que también te permite interactuar y configurar tus "queue workers". Telescope, por otro lado, simplemente te muestra información, pero funciona con todos los drivers disponibles de colas.
En el detalle, podrás ver el nombre del trabajo, la cola en la que se ejecutó, la conexión a la base de datos que uso, el estado y cuando se disparó.
También vas a ver información como el host, el nombre completo de la clase, el número de intentos, si falló por timeout, etc.
Los trabajos son automáticamente etiquetados con cualquier modelo de Eloquent que estén trabajando, así como el usuario si es que hay un usuario involucrado. Ítems como requests, comandos, etc. son asignados automáticamente como etiquetas al trabajo para que puedas filtrarlos en la búsqueda.
Así como con las peticiones HTTP, puedes ver toda la información relacionada con el trabajo como las consultas a base de datos ejecutadas, trabajos que se generaron a partir de este, y cualquier log que se haya generador del mismo.
Esta pestaña muestra todas las excepciones que se han generado en tu aplicación y te permite inspeccionarlas. Verás información similar a la de otras pestañas, como host, tipo, request que la generó, etiquetas, usuario autenticado, etc.
También puedes ver la ubicación exacta en el código, resaltada, con un par de líneas por arriba y por debajo para tener un mejor contexto. Lógicamente, está el stack trace completo para que puedas revisar si es necesario.
También puedes conseguir un enlace al detalle de la excepción desde la petición que la generó. Esto también puede hacerse desde los detalles de otros elementos, lo que hace a Telescope muy fácil de navegar.
Si una excepción es disparada más de una vez, se empezarán a agrupar, pero igualmente puedes acceder a una en particular si necesitas más información. Esto evita que la página se inunde de una sola excepción que se dispare muy frecuentemente.
La pestaña de logs permite ver los mensajes loggeados, su nivel de severidad, y cuando fueron generados.
Cuando entras a ver el detalle de cada ítem, puedes ver más información, incluyendo el contexto que pasaste a tus ítems como array. Esto te permite una mejor inspección del error que entrar a revisar el archivo de texto de forma manual.
Esta pestaña es el servidor de Dump que agregó la versión 5.7 de Laravel, que permite separar los llamados a dump()
del flujo de nuestra aplicación. Cuando estemos en esta pestaña, todos los llamados a dump()
se enviarán aquí, y cuando dejemos la pestaña volverán al flujo normal de nuestra aplicación.
Muestra una lista de todas las consultas a base de datos, justo como lo hace Laravel Debug Bar. Cuánto tardaron, cuándo ocurrieron y si entramos al detalle, podemos ver la información asociada, la consulta completa, quién la disparó, todo correctamente formateado.
Puedes configurar en tu Service Provider que consultas quieres que sean marcadas como "lentas" y marcarlas de rojo en la lista. Esto permite también filtrarlas por el campo de búsqueda.
Puedes ver eventos disparados de tus modelos como creación, actualización, eliminación, los cambios realizados, etc.
Obviamente, como en todas las pestañas, puedes ver quién generó los cambios.
Muestra una lista de todos tus eventos. Puedes ver cuantos listeners están asociados, filtrarlos por etiqueta, y ver cuando ocurrieron. Si entras al detalle también puedes ver quién lo disparó y cuáles son los listeners exactos.
La pestaña Mail te muestra una lista de todos los emails que enviaste, quienes los recibieron, cuando se dispararon, si están encolados o no, el asunto, y hasta puedes descargarlo como un archivo .eml y abrirlo con tu cliente de email preferido y ver como se muestra. También puedes ver una previsualización del mismo.
Muestra todas las notificaciones, de qué tipo son, cuando se enviaron, etc. Las notificaciones que sean por email se mostrarán también previsualizadas, pero no para el resto.
Si una notificación fue encolada, puedes verla en la parte de Jobs.
Esta pestaña muestra las interacciones con el caché, si se acertó o falló, si fue guardada en cache o eliminada del mismo, etc. También puedes ver quién lo originó.
Esta pestaña es similar a Cache, mostrando cuando se agregaron, modificaron o borraron claves de Redis.
Esto no es una pestaña pero puede aparecer en Telescope cuando alguno de sus elementos esté asociado con un usuario autenticado.
Puedes usar una lista de emails en el Service Provider de Telescope para definir qué usuarios pueden accederlo en producción. O puedes usar el gate viewTelescope para definir si un usuario puede o no accederlo.
En producción, puedes no querer guardar todo lo que sucede, por lo que puedes definir filtros en el Service Provider de la siguiente forma: Telescope::filter(function ($entry){})
Filtro por defecto:
function ($entry) {
if (local) { return true; }
return $entry->isReportableException ||
$entry->isfailedJob() ||
$entry->isScheduledTask() ||
$entry->hasMonitoredTag();
}
Puedes modificar esto como tú quieras.
Ve al botón de Radar y agrega una etiqueta para monitorear. Esto sirve para filtrar por etiquetas en producción.
Puedes programar que Telescope limpie entradas antiguas, configurar una hora al día en la que se ejecute la limpieza y determinar hasta cuantas horas quieres guardar de información. También puedes activar o desactivar algunos watchers desde la configuración de Telescope (config/telescope). Incluso puedes definir un límite con la clave TELESCOPE_LIMIT (100 por defecto) que es el número máximo de entradas que Telescope guarda para cada watcher. Muchos de estos cambios son configurables por .env.
Telescope puede ser ejecutado de forma local y en producción, y viene integrado con autorización y herramientas para mantener de forma privada tus datos. Provee un acceso similar a la información desde distintos ángulos, es super configurable, y permite una búsqueda fácil y rápida a través de las etiquetas.
Es recomendable instalarlo en una base de datos separada, y también hay formas de filtrar el logging para que los datos sensibles no sean guardados.
También puedes activar el modo Oscuro utilizando Telescope::night()
en tu Service Provider.
Toda la información es almacenada en una base de datos, detrás de una interface StorageRepository, y funcionando con Redis. Pero puedes implementarlo como quieras.
Con respecto a la cantidad de información que se guarda, no es pesada ya que en producción se descartan la mayoría de los eventos, y con la limpieza programada y el límite de 100 ítems, el espacio utilizado es poco significativo.
No tiene un mayor impacto en el tiempo de arranque de Laravel, y en producción mantiene las escrituras a un mínimo. También puedes deshabilitar watchers que no requieras para reducir aún más el consumo.
]]>Laravel 5.7 continua las mejoras realizadas en Laravel 5.6 introduciendo Laravel Nova, verificación opcional por email a la generación automática de autenticación, soporte para usuarios invitados en políticas y puertas de acceso, mejoras en pruebas para comandos de
]]>Laravel 5.7 continua las mejoras realizadas en Laravel 5.6 introduciendo Laravel Nova, verificación opcional por email a la generación automática de autenticación, soporte para usuarios invitados en políticas y puertas de acceso, mejoras en pruebas para comandos de consola, integración del servidor de prueba de Symfony, notificaciones localizables, y una variedad de correcciones y mejoras de usabilidad.
Laravel Nova es un panel de administración para aplicaciones Laravel. Por supuesto, la principal característica de Nova es la habilidad de administrar tus registros de base de datos a través de Eloquent. Adicionalmente, Nova ofrece soporte para filtros, lentes, acciones, acciones encoladas, métricas, autorización, herramientas personalizadas, tarjetas personalizadas, campos personzalidos y más.
Para aprender más acerca de Laravel Nova, revisa el sitio en el siguiente enlace: Laravel Nova
Laravel 5.7 introduce verificación por email opcional a la generación automática de autenticación incluída en el framework. Para permitir esta funcionalidad, se agregó una columna email_verified
del tipo timestamp a la tabla de usuarios incluída por defecto.
Para requerir que los usuarios recién registrados validen su email, el modelo User
debería marcarse con la interfaz MustVerifyEmail
:
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements MustVerifyEmail
{
// ...
}
Una vez que el usuario User
es marcada con la interfaz, los usuarios registrados recibirán un email que contiene un enlace de verificación firmado.
Una vez que se hace clic en el enlace, Laravel automáticamente va a guardar el tiempo actual en la base de datos y va a redirigir al usuario a una ubicación de tu elección.
Un middleware verified
se agregó al Kernel HTTP de la aplicación por defecto.
Este middleware puede agregarse a las rutas que solo puedan ser accedidos por usuarios verificados.
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
Para aprender más sobre verificación por email, revisa la documentación completa en el siguiente enlace: Verificación por email
En versiones previas de Laravel, las puertas y políticas automaticamente retornaban falso para los usuarios no-autenticados en tu aplicación. Sin embargo, ahora puedes permitir que tus usuarios invitados pasen las validaciones de autorización declarando un "type-hint" opcional o utilizando un valor nulo por defecto en la definición del argumento del usuario:
Gate::define('update-post', function (?User $user, Post $post) {
// ...
});
Laravel 5.7 ofrece integración con el servidor de prueba de Symfony, a través del paquete de Marcel Pociot. Para comenzar, utiliza el comando de Artisan:
php artisan dump-server
Una vez que el servidor está corriendo, todos los pedidos de "dump" serán mostrados en el servidor en la ventana de la consola en lugar de en tu navegador, permitiendote inspeccionar los valores sin tener que luchar con el resultado de la respuesta HTTP.
Laravel ahora permite enviar notificaciones en otra localización que la actual, y permite recordar la localización cuando la notificación es encolada.
Para conseguir esto, la clase Illuminate\Notifications\Notification
ahora ofrece un método locale
para setear el lenguaje deseado. La aplicación cambia a este locale
cuando la notificación está siendo formateada, y vuelve al locale
anterior una vez que termina de formatearlo:
$user->notify((new InvoicePaid($invoice))->locale('es'));
La localización de múltiples notificaciones puede realizarse mediante la fachada Notification
:
Notification::locale('es')->send($users, new InvoicePaid($invoice));
Laravel 5.7 te permite fácilmente "mockear" información suministrada por el usuario para tus comandos de consola usando el método expectsQuestion
. Además, puedes especificar un código de salida y un texto esperado como resultado del comando para validar con los métodos assertExitCode
y expectsOutput
. Por ejemplo, considera el siguiente comando de consola:
Artisan::command('question', function () {
$name = $this->ask('What is your name?');
$language = $this->choice('Which language do you program in?', [
'PHP',
'Ruby',
'Python',
]);
$this->line('Your name is '.$name.' and you program in '.$language.'.');
});
Puedes probar este comando con la siguiente prueba que utiliza los métodos mencionados anteriormente:
/**
* Test a console command.
*
* @return void
*/
public function test_console_command()
{
$this->artisan('laracon')
->expectsQuestion('What is your name?', 'Taylor Otwell')
->expectsQuestion('Which language do you program in?', 'PHP')
->expectsOutput('Your name is Taylor Otwell and you program in PHP.')
->assertExitCode(0);
}
En lugar de aceptar solamente strings, el generador de URLs de Laravel ahora acepta sintáxis callable
cuando genera URLs en sus acciones de controlador:
action([UserController::class, 'index']);
Laravel 5.7 te permite controlar cuantos enlaces adicionales mostrar a cada lado de la botonera de tu paginador. Por defecto, tres enlaces se mostraran a cada lado. Sin embargo, puedes controlar este número usando el método onEachSide
:
{{ $paginator->onEachSide(5)->links() }}
La integración Flysystem de Laravel ahora ofrece los métodos readStream
y writeStream
:
Storage::disk('s3')->writeStream(
'remote-file.zip',
Storage::disk('local')->readStream('local-file.zip')
);
]]>Cuando construimos un API, nuestro objetivo es devolver la información de nuestra base de datos de forma fácil de interpretar por el cliente.
Hoy en día la forma más común de hacerlo es mediante un objeto o array JSON que
Cuando construimos un API, nuestro objetivo es devolver la información de nuestra base de datos de forma fácil de interpretar por el cliente.
Hoy en día la forma más común de hacerlo es mediante un objeto o array JSON que representa nuestro modelo de datos de la siguiente forma:
Modelo Order
:
// OrdersController
public function show(Order $order)
{
return $order;
}
// Respuesta
{
id: 1,
buyer_id: 5,
seller_id: 14,
order_status_id: 1,
}
Esto es correcto y funciona, bien, pero podemos observar claramente como nuestra respuesta y su estructura están ligadas a la estructura de nuestra base de datos.
¿Qué pasa si realizamos un cambio en nuestro esquema de datos y, por ejemplo, queremos cambiar el nombre de algún campo? ¿O decidimos mostrar los nombres de nuestras relaciones en lugar de un ID? ¿O agregar información especial al momento de devolver el resultado, como una suma, un total o un enlace?
Este problema se debe a que nuestros clientes están interactuando directamente con nuestro esquema de datos, en lugar de con capa intermedia.
El mismo principio que rige para los Getters y Setters de Programación Orientada a Objetos rige para las respuestas de un API: separar el resultado de la implementación concreta.
Aquí es donde entran en acción los Resources, que funcionarán como intermediario entre nuestros clientes y nuestro esquema de datos.
Veamos un ejemplo:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\Resource;
class OrderResource extends Resource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'buyer_id' => $this->buyer->id,
'seller_id' => $this->seller->id,
'order_status_id' => $this->order_status->id,
];
}
}
Así se ve un Resource que reemplaza al resultado actual de nuestro API.
El concepto de los Resources es simple, agregar una capa entre nuestra base de datos y nuestros clientes, ganando la flexibilidad de cambiar nuestra implementación sin que el usuario final se entere. Esto se logra con un simple array donde indicamos cómo y qué campos se van a mostrar al transformar nuestros modelos a JSON.
Para generar un recurso, Laravel nos provee el siguiente comando de Artisan:
php artisan make:resource Order
Para que nuestras respuestas pasen a través de nuestros Resource, tenemos que cambiar nuestros controladores de la siguiente manera:
// OrdersController
public function show(Order $order)
{
return new OrderResource($order);
}
Supongamos por un momento que decidimos cambiar el nombre de la relación seller
por el de owner
. Modificamos nuestra base de datos a través de una migración de la siguiente forma:
public function up()
{
Schema::table('orders', function (Blueprint $table) {
$table->renameColumn('seller_id', 'owner_id');
});
}
Ahora, nuestros clientes ya están programados para interactuar con la relación seller
, pero gracias a nuestro Resource, ya nuestra respuesta está desacoplada de nuestras tablas:
...
public function toArray($request)
{
return [
'id' => $this->id,
'buyer_id' => $this->buyer->id,
'seller_id' => $this->owner->id,
'order_status_id' => $this->order_status->id,
];
}
...
Vean como incluso al cambiar una relación, la respuesta se mantiene igual, solo tuvimos que actualizar nuestro Resource para que tome los datos del modelo de la nueva relación.
También podemos agregar información a nuestras respuestas que no siempre queremos que esté disponible, por ejemplo, si la información nos llega desde un usuario dueño del recurso, podemos incluir más información que no la tendría si no lo fuera utilizando el método when
, que recibe una condición y un valor si la condición se cumple.
...
public function toArray($request)
{
return [
'id' => $this->id,
'buyer_id' => $this->buyer->id,
'seller_id' => $this->owner->id,
'order_status_id' => $this->order_status->id,
'total' => $this->when(auth()->user()->id == $this->owner_id, $this->order_details->sum('price')),
];
}
...
También podemos pasarle un Closure como segundo argumento:
...
'total' => $this->when(auth()->user()->id == $this->owner_id, function(){
return $this->order_details->sum('price'));
}
...
O agregar información que esté relacionada con el recurso pero no esté persistida en base de datos, como un enlace:
...
public function toArray($request)
{
return [
'id' => $this->id,
'buyer_id' => $this->buyer->id,
'seller_id' => $this->owner->id,
'order_status_id' => $this->order_status->id,
'link' => route('api.orders.show', $this->id),
];
}
...
Por ahora vimos solamente como transformar un solo objeto, pero qué pasa cuando queremos hacerlo con un conjunto, como en un index
?
Con Laravel Resources necesitamos crear una collection, y para hacerlo tenemos dos formas, mediante la opción --collection o incluyendo Collection en el nombre del recurso.
php artisan make:resource Orders --collection
php artisan make:resource OrderCollection
En cualquier caso, Laravel generará un recurso nuevo que será el encargado de transformar nuestra colección de objetos al formato que nosotros querramos:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class OrderCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request
* @return array
*/
public function toArray($request)
{
return [
'data' => $this->collection,
];
}
}
Para utilizarlo en nuestra aplicación, es igual que el Resource individual:
Route::get('/orders', function () {
return new OrderCollection(Order::all());
});
Hay que tener en cuenta también que al trabajar con API's, es necesario paginar los resultados, por lo que podemos pasarle un Paginator
al ResourceCollection en lugar de una Collection:
Route::get('/orders', function () {
return new OrderCollection(Order::paginate());
});
El resultado se verá de la siguiente forma:
{
"data": [
{
"id": 1,
"buyer_id": 12,
"seller_id": 3,
"order_status_id": 1,
"link": "http://resouces.local/orders/1
},
{
"id": 2,
"buyer_id": 15,
"seller_id": 6,
"order_status_id": 2,
"link": "http://resouces.local/orders/2
},
],
"links":{
"first": "http://resouces.local/orders/pagination?page=1",
"last": "http://resouces.local/orders/pagination?page=1",
"prev": null,
"next": null
},
"meta":{
"current_page": 1,
"from": 1,
"last_page": 1,
"path": "http://resouces.local/orders/pagination",
"per_page": 15,
"to": 10,
"total": 10
}
}
De esta forma podemos ver como a través de los Resources podemos transformar el resultado de nuestra API y las ventajas que esto tiene.
La opción de Laravel es una excelente forma de resolver este problema, pero también hay otras soluciones, que veremos en otros posts, con algunas ventajas sobre Resources, como por ejemplo, utiliza una misma clase tanto para un solo objeto, como para una colección, o un Paginator.
Espero que este tutorial les haya servido, dejen su opinión en sus comentarios!
]]>En este tutorial veremos cómo instalar PHP, Composer y Laravel desde cero, algo que para muchos resulta ser un gran obstáculo a la hora de iniciarse en este excelente framework.
Para instalar PHP en Windows tenemos varias herramientas, cada una con distintos beneficios.
En
En este tutorial veremos cómo instalar PHP, Composer y Laravel desde cero, algo que para muchos resulta ser un gran obstáculo a la hora de iniciarse en este excelente framework.
Para instalar PHP en Windows tenemos varias herramientas, cada una con distintos beneficios.
En una oportunidad anterior, les explicamos como instalar una de ellos: Laragon.
Es tan simple como entrar a su página, descargar el paquete WAMP (Windows, Apache, MySQL, PHP) y ejecutar el instalador.
Elegimos la ruta donde se instalará Laragon, y luego el instalador asociará PHP a nuestras variables de entorno (PATH) para que podamos usarlo desde consola.
Una de las ventajas de Laragon vs Xampp o Wamp es que instalar proyectos Laravel es muy sencillo, ya que tiene una opción específica para eso, que genera un nuevo proyecto Laravel con todos los paquetes instalados, el archivo .env
creado, un Virtual Host para Apache o nginx configurado con el nombre del proyecto para que podamos acceder rápidamente en nuestro navegador (http://ejemplo.dev) y hasta puede generar una base de datos para el proyecto, todo desde un fácil acceso rápido en la barra de tareas.
Una vez instalado alguno de estos entornos, ya sea Laragon, Xampp, Wamp o cualquier otro, podremos comprobar que PHP se instaló correctamente comprobando por consola su versión:
php -v
Si PHP se instaló con éxito, debería mostrarnos algo similar a esto:
PHP 7.0.11 (cli) ( NTS )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies
with Zend OPcache v7.0.11, Copyright (c) 1999-2016, by Zend Technologies
Es importante instalar las versiones de PHP 7+, ya que las versiones 5 de PHP han quedado discontinuadas y muchos paquetes requieren de la última versión para ejecutarse.
Composer es el manejador de dependencias de PHP, es decir, se encarga de instalar las librerias que nuestros proyectos necesitan y de mantenerlas actualizadas, por lo que podemos reutilizar código de otros programadores en nuestras aplicaciones y ahorrarnos reescribir siempre las mismas funcionalidades.
PHP tuvo un antes y un después de la aparición de Composer, ya que permitió que la comunidad desarrollara paquetes especializados y que estos fueran probados por miles de aplicaciones, ahorrando tiempo a futuros programadores y mejorando la estabilidad de nuestros sistemas.
Para instalar Composer en Windows, debemos descargarlo desde su página:
https://getcomposer.org/Composer-Setup.exe
Luego, ejecutamos el instalador y seguimos sus pasos:
Una vez terminado, podemos abrir una consola de Windows y ejecutar composer
. Si todo salió bien, nos mostrará una lista de comandos para ejecutar.
Más adelante veremos cómo utilizar Composer para manejar las dependencias de nuestras aplicaciones.
Ahora ya podemos pasar a crear nuestro primer proyecto!
Para crear un nuevo proyecto en Laravel, tenemos dos formas (tres con Laragon):
composer create-project --prefer-dist laravel/laravel nuevo-proyecto "5.4.*"
composer global require "laravel/installer"
laravel new nuevo-proyecto
Estos comandos generarán una carpeta nuevo-proyecto
que tendrá la instalación básica del framework.
Si lo creamos con composer
, tendremos que copiar el archivo .env.example
a .env
y generar una clave nueva para el proyecto:
copy .env.example .env
php artisan key:generate
Si lo creamos con el instalador de Laravel o de Laragon, esto se hará automáticamente.
Ahora sí, ya podemos abrir la ventana de nuestro navegador y ver el inicio de nuestra nueva app.
Entremos a http://nuevo-proyecto.dev y veremos esto:
Eso fue todo, espero que les haya servido!
]]>Muchos de ustedes conocen los helpers o funciones globales de Laravel que nos permiten realizar operaciones muy comunes en nuestra aplicación de forma más sencilla, como por ejemplo el helper app
para instanciar objetos desde el Service Container, request
para obtener un objeto con todos los
Muchos de ustedes conocen los helpers o funciones globales de Laravel que nos permiten realizar operaciones muy comunes en nuestra aplicación de forma más sencilla, como por ejemplo el helper app
para instanciar objetos desde el Service Container, request
para obtener un objeto con todos los datos del request actual o route
para generar links a rutas nombradas.
Si bien los helpers de Laravel son muy útiles, muchas veces vamos a necesitar crear los nuestros.
Vamos a ver cómo crearlos, dónde declararlos y de qué forma usarlos.
Declarar funciones globales en PHP es muy sencillo, es cuestión de escribirlas dentro de un archivo PHP e incluir ese archivo en cualquier lugar donde quisieramos hacer uso de ellas.
Idealmente, seguiremos la convención de usar el nombre helpers.php
para el archivo, con el fin de que otros desarrolladores puedan ubicarlo fácilmente.
No hay una convención sobre la ubicación física del archivo en nuestro proyecto, pero por lo general, se agrega en la raíz del proyecto, junto a otros archivos como artisan
.
Para evitar que nuestros helpers no generen conflictos con otros ya declarados, PHP nos permite hacer un chequeo de existencia de otras funciones con el mismo nombre, algo que nosotros vamos a utilizar en cada declaración:
<?php
if (!function_exists('artisan')) {
function artisan()
{
return app()->make('Illuminate\Contracts\Console\Kernel');
}
}
Una vez declaramos nuestro archivo, para que podamos utilizarlo en el resto del proyecto necesitaremos agregarlo al autoloader de Composer en nuestro composer.json
:
...
"autoload": {
"classmap": [
"database"
],
"psr-4": {
"App\\": "app/"
},
"files": [
"helpers.php"
]
},
...
Una vez hecho esto, tenemos que generar nuevamente nuestro archivo autoload.php
, para esto llamamos al comando dump-autoload de composer:
composer dump-autoload
O más corto aún:
composer du
Ahora ya puedes usar tus funciones helpers en el resto de tu proyecto!
Cada proyecto tiene sus propias funcionalidades que se repiten a lo largo del mismo, pero en todos los proyectos terminamos necesitando siempre estas funciones para tareas generales:
active_route
determina si estamos en la ruta nombrada que estamos comparando, y emite un output si es así, generalmente active
. Esto sirve para marcar barras de navegación con el framework Bootstrap cuando navegamos un sitio en Laravel. Podemos cambiar el output si queremos como segundo parámetro, para adaptarlo a otro framework CSS.if (!function_exists('active_route')) {
function active_route($route, $output = 'active')
{
if (Route::current()->getName() == $route)
return $output;
}
}
user
es un atajo a la muy común combinación de auth()->user()
. Usado en todos los proyectos.if (!function_exists('user')) {
/**
* @return \Illuminate\Contracts\Auth\Authenticatable|null|App\User
*/
function user()
{
return auth()->user();
}
}
Storage
por storage()
y DB
por db()
:if (!function_exists('db')) {
function db($connection = null)
{
return app()->make('db')->connection($connection);
}
}
if (!function_exists('storage')) {
/**
* @param null $disk
* @return \Illuminate\Filesystem\Filesystem
*/
function storage($disk = null)
{
return app()->make('filesystem')->disk($disk);
}
}
Estas funciones son muy útiles para evitar repetir lógica en distintos lugares de nuestro código, y a la vez mantener la sintaxis sencilla y sobre todo corta y entendible, una gran ventaja de las funciones por sobre las clases utilitarias, y con soporte del IDE, ventaja frente a las fachadas.
Espero que les haya sido de utilidad!
]]>Un problema muy común en el desarrollo de aplicaciones web es el de las imágenes generadas por el usuario. Cómo mostrarlas, en que tamaño, donde guardarlas, etc.
Hoy vamos a mostrarles una de las opciones, la que usamos nosotros en Coffeedevs, que
]]>Un problema muy común en el desarrollo de aplicaciones web es el de las imágenes generadas por el usuario. Cómo mostrarlas, en que tamaño, donde guardarlas, etc.
Hoy vamos a mostrarles una de las opciones, la que usamos nosotros en Coffeedevs, que tiene al paquete Intervention como principal actor.
Intervention es un paquete de Composer que permite manipular imágenes: podes cambiarles el tamaño, cropearlas, aplicarles filtros, agregar marcas de agua, etc.
Está preparado para funcionar con Laravel por defecto, pero es fácil de integrar en el resto de los frameworks.
Sin embargo, lo que a nosotros nos interesa en este momento es un pequeño paquete utilitario que hace de compañero de Intervention y que se llama ImageCache.
ImageCache lo que permite es generar transformaciones para las imágenes "on the fly", es decir, a medida que son pedidas, y guardarlas en cache, lo que nos permite mostrar versiones específicas para cada una de nuestras vistas de Laravel, con sólo tener la imagen original guardada, sin necesidad de generarlas al momento de subirlas.
Primero que nada, para manipular imágenes, necesitamos que nuestros usuarios suban algunas.
Lo más común, y lo que menos esfuerzo requiere, es guardarlas en la carpeta public
y mostralas con asset()
en nuestro template Blade.
Sin embargo, esto presenta algunos problemas de seguridad ya que los usuarios pueden subir archivos a un directorio público, por lo que la opción recomendada es guardarlas en storage/app
, donde sólo la aplicación puede acceder.
Para guardarlas en storage
, basta con utilizar el siguiente código:
$request->file('uploaded_file')->store('app/uploads');
Puedes leer más sobre como guardar archivos en nuestro anterior tutorial
Pero para mostrar los archivos guardados en storage
, es un poco más complicado que simplemente llamar a asset()
:
Necesitamos una ruta dedicada en nuestra aplicación que busque las imágenes y las retorne.
Intervention va a permitirnos realizar transformaciones a nuestra imágenes a medida que nuestra aplicación las demande, a través de una URL que indique la transformación que queremos aplicar y el nombre de la imagen original:
http://intervention.dev/{ruta}/{template}/{imagen}
Ruta podría ser images
, template puede ser small
, medium
o large
, e imagen
es el nombre de la imagen: p. e. avatar.png
Para poder utilizar su función de cache, necesitamos instalar ambos paquetes:
composer require intervention/image intervention/imagecache
Luego, tenemos que registrar el Service Provider en app.php
:
$providers = [
...
Intervention\Image\ImageServiceProvider::class,
...
]
Y por último, es muy importante publicar la configuración de ambos paquetes:
php artisan vendor:publish
Esto nos creará dos archivos de configuración nuevos en nuestra carpeta config
:
image.php
e imagecache.php
.
Intervention genera una nueva imagen a partir de la original, le aplica el filtro, la guarda en el cache, y nos la devuelve
Para que podamos mostrar las imágenes subidas por nuestros usuarios en la aplicación, Intervention necesita definir una ruta donde le pediremos las imágenes transformadas.
La misma la podemos definir en su archivo de configuración imagecache.php
en la carpeta config
:
<?php
return array(
/*
|--------------------------------------------------------------------------
| Name of route
|--------------------------------------------------------------------------
|
| Enter the routes name to enable dynamic imagecache manipulation.
| This handle will define the first part of the URI:
|
| {route}/{template}/{filename}
|
| Examples: "images", "img/cache"
|
*/
'route' => 'images',
/*
|--------------------------------------------------------------------------
| Storage paths
|--------------------------------------------------------------------------
|
| The following paths will be searched for the image filename, submited
| by URI.
|
| Define as many directories as you like.
|
*/
'paths' => array(
storage_path('app/uploads'),
),
/*
|--------------------------------------------------------------------------
| Manipulation templates
|--------------------------------------------------------------------------
|
| Here you may specify your own manipulation filter templates.
| The keys of this array will define which templates
| are available in the URI:
|
| {route}/{template}/{filename}
|
| The values of this array will define which filter class
| will be applied, by its fully qualified name.
|
*/
'templates' => array(
'small' => 'Intervention\Image\Templates\Small',
'medium' => 'Intervention\Image\Templates\Medium',
'large' => 'Intervention\Image\Templates\Large',
),
/*
|--------------------------------------------------------------------------
| Image Cache Lifetime
|--------------------------------------------------------------------------
|
| Lifetime in minutes of the images handled by the imagecache route.
|
*/
'lifetime' => 43200,
);
Como podemos ver, la ruta quedó definida como images
y también configuramos los directorios donde Intervention va a buscar la imagen: storage_path('app/uploads')
Ahora que ya tenemos configurado la ruta y el directorio, podemos llamar a las imágenes desde nuestro template de la siguiente forma:
<img src="{{ url('images/medium/avatar.png') }}">
Esto realiza una llamada a la ruta que definimos y el filtro que elegimos, e Intervention genera una nueva imagen a partir de la original, le aplica el filtro, la guarda en el cache, y nos la devuelve.
El template medium
, por ejemplo, resizea la imagen a 240x180, pero así como podemos usar los 3 templates base de Intervention, también podemos definir los nuestros, utilizando toda la gama de transformaciones que nos permite el paquete, como sean fit
, crop
, greyscale
, etc.
Para definir nuestros propios templates, tenemos que crear una clase que implemente la interfaz Intervention\Image\Filters\FilterInterface
.
Esto nos obliga a implementar el método applyFilter(Image $image)
donde recibimos la imagen original y le aplicamos las transformaciones que querramos antes de devolverla:
class Avatar implements FilterInterface
{
public function applyFilter(Image $image)
{
return $image->fit(40, 40);
}
}
Luego, en el archivo de configuración imagecache.php
agregamos al mapa de templates la entrada con nuestra nueva clase:
'templates' => array(
'small' => 'Intervention\Image\Templates\Small',
'medium' => 'Intervention\Image\Templates\Medium',
'large' => 'Intervention\Image\Templates\Large',
'avatar' => App\Intervention\Templates\Avatar::class,
),
Y para utilizarlo en nuestra aplicación hacemos lo siguiente:
<img src="{{ url('images/avatar/' . $user->avatar) }}">
De esta forma podremos entregar imágenes a la medida de los requerimientos, sin necesidad de generarlas cuando se cargan, pudiendo adaptarnos fácilmente a requerimientos nuevos de tamaño, color, o proporción.
Espero que les haya sido útil!
]]>Laravel 5.4 continua con las mejoras realizadas en Laravel 5.3, agregando soporte para Markdown en emails y notificaciones, el framework para testing Laravel Dusk, la nueva versión de Laravel Elixir, Laravel Mix, components y slots
]]>Laravel 5.4 continua con las mejoras realizadas en Laravel 5.3, agregando soporte para Markdown en emails y notificaciones, el framework para testing Laravel Dusk, la nueva versión de Laravel Elixir, Laravel Mix, components y slots para Blade, route model binding en los canales de broadcast, mensajes de orden superior en colecciones, eventos de Eloquent como objetos/clases, configuraciones individuales para los intentos y el tiempo de espera de los Jobs, fachadas en tiempo real, soporte mejorado para Redis Cluster, modelos personalizados para tablas pivot, middlewares para limpiar y recortar input del usuario, y más. Además, el código fuente del framework fue revisado y refactorizado para ordenarlo y mantenerlo limpio.
Esta documentación resume las más notables mejoras al framework; sin embargo, para listas de cambios más completas, se pueden encontrar en Github.
Los emails en Markdown nos permiten tomar ventaja de las plantillas pre-construidas y componentes de notificaciones por email en tus mailables. Ya que los mensajes están escritos en Markdown, Laravel es capaz de renderizar hermosos, responsivos templates HTML para los mensajes a la vez que automáticamente genera su contraparte en texto plano. Por ejemplo, un email Markdown puede parecerse al siguiente:
@component('mail::message')
# Pedido enviado
Su pedido ha sido enviado!
@component('mail::button', ['url' => $url])
Ver pedido
@endcomponent
Próximos pasos:
- Seguir el estado de su pedido en la web
- Pre-firmar para la entrega
Gracias,<br>
{{ config('app.name') }}
@endcomponent
Usando esta simple plantilla de Markdown, Laravel es capaz de generar un email HTML responsive y su contra-parte en texto plano:
Para leer más acerca de Markdown email y notificaciones, revise la documentación completa sobre email y notificaciones.
Puedes exportar todos tus componentes de email en Markdown a tu aplicación para personalizarlos. Para exportar los componentes, utiliza el comando Artisan vendor:publish --tag=laravel-mail
.
Laravel Dusk provee una API para testing automatizados expresiva y fácil de utilizar, que interactua con el navegador. Por defecto, Dusk no requiere que instales un JDK o Selenium en tu computadora. En lugar de eso, Dusk utiliza una instalación independiente de ChromeDriver. Sin embargo, eres libre de utilizar el driver compatible con Selenium que desees.
Ya que Dusk trabaja usando un navegador real, podes fácilmente testear e interactuar con tu aplicación aunque use JavaScript.
/**
* A basic browser test example.
*
* @return void
*/
public function testBasicExample()
{
$user = factory(User::class)->create([
'email' => '[email protected]',
]);
$this->browse(function ($browser) use ($user) {
$browser->loginAs($user)
->visit('/home')
->press('Create Playlist')
->whenAvailable('.playlist-modal', function ($modal) {
$modal->type('name', 'My Playlist')
->press('Create');
});
$browser->waitForText('Playlist Created');
});
}
Para más información sobre Dusk, consulta la documentación completa.
Laravel Mix es el sucesor espiritual de Elixir, y está completamente basado en Webpack en lugar de Gulp. Laravel Mix provee una API fluida para definir los pasos de Webpack para tu aplicación Laravel, utilizando varios pre-procesadores comunes de CSS y JavaScript. A través de la encadenación de métodos, puedes definir de forma fluida tu tubería de tus activos. Por ejemplo:
mix.js('resources/assets/js/app.js', 'public/js')
.sass('resources/assets/sass/app.scss', 'public/css');
Componentes y slots de Blade ofrecen beneficios similares a las secciones y diseños; sin embargo, algunos pueden encontrar el modelo mental de componentes y slots más fácil de entender. Primero, imaginemos un componente "alerta" re-utilizable que queramos utilizar en el resto de nuestra aplicación:
<!-- /resources/views/alert.blade.php -->
<div class="alert alert-danger">
{{ $slot }}
</div>
La variable {{ $slot }}
va a contener lo que quieras inyectarle al componente. Ahora, para construir este componente, podemos usar la directiva de Blade @component
:
@component('alert')
<strong>Whoops!</strong> Algo salió mal!
@endcomponent
Slots nombrado te permiten proveer multiples puntos de inyección en un sólo comoponente:
<!-- /resources/views/alert.blade.php -->
<div class="alert alert-danger">
<div class="alert-title">{{ $title }}</div>
{{ $slot }}
</div>
Slots nombrados pueden inyectarse usando la directiva @slot
. Cualquier contenido que no esté en una directiva @slot
será pasada al componente en la variable $slot
:
@component('alert')
@slot('title')
Acceso denegado
@endslot
No tienes permitido acceder a este recurso!
@endcomponent
Para leer más acerca de componentes y slots, consulta la documentación completa de Blade.
Al igual que las rutas HTTP, las rutas de los canales ahora toman ventaja del route model binding implícito y explícito. Por ejemplo, en lugar de recibir un string o un o un ID numérico, puedes pedir una instancia del modelo Order
enviado:
use App\Order;
Broadcast::channel('order.{order}', function ($user, Order $order) {
return $user->id === $order->user_id;
});
Para leer más acerca de route model binding en los canales de broadcast, consulta la documentación completa sobre broadcasting de eventos.
Las colecciones ahora proveen soporte para mensajes de orden superior, los cuales son atajos para realizar acciones comúnes sobre colecciones.
Los métodos de colecciones que proveen mensajes de orden superior son: contains
, each
, every
, filter
, first
, map
, partition
, reject
, sortBy
, sortByDesc
, and sum
.
Cada función de orden superior puede ser accedida como una propiedad dinámica sobre una instancia de colección. Por ejemplo, vamos a utilizar la función de orden superior each
para llamar a cada método dentro de una colección:
$users = User::where('votes', '>', 500)->get();
$users->each->markAsVip();
Así mismo, podemos utilizar la suma como mensaje de orden superior para conseguir el total del número de votos para una colección de usuarios:
$users = User::where('group', 'Development')->get();
return $users->sum->votes;
Los manejadores de eventos de Eloquent ahora pueden ser mapeados a eventos de objetos. Esto provee una forma más intuitiva de manejar eventos de Eloquent y hace más fácil el testeo de eventos. Para empezar, definamos una propiedad $events
en tu modelo Eloquent que mapea varios puntos del ciclo de vida de un modelo Eloquent a tus propias clases de eventos:
<?php
namespace App;
use App\Events\UserSaved;
use App\Events\UserDeleted;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable;
/**
* The event map for the model.
*
* @var array
*/
protected $events = [
'saved' => UserSaved::class,
'deleted' => UserDeleted::class,
];
}
Previamente, las configuraciones de tiempo de espera e intentos para los trabajos eran configurados globalmente desde la consola. Sin embargo, en Laravel 5.4, estas configuraciones pueden hacerse de manera individualizada para cada trabajo, directamente en la clase del trabajo:
<?php
namespace App\Jobs;
class ProcessPodcast implements ShouldQueue
{
/**
* La cantidad de veces que un trabajo puede intentar de ejecutarse.
*
* @var int
*/
public $tries = 5;
/**
* La cantidad de segundos que dura un trabajo antes de darse por fallado.
*
* @var int
*/
public $timeout = 120;
}
Para más información acerca de esta configuración, revisa la documentación completa de colas.
Laravel 5.4 incluye dos nuevos middleware por defecto: TrimStrings
y ConvertEmptyStringsToNull
:
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* @var array
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
];
Estos middleware automáticamente van a aplicar trim()
a los valores enviados por input en las peticiones y convertir cualquier string vacío ''
a null
. Esto ayuda a normalizar el input de cada petición entrante y no tener que preocuparnos continuamente llamando la función trim en cada ruta y controlador.
Previamente, sólo los servicios que vienen incluidos en Laravel exponían fachadas, que proveen un acceso rápido y breve a los sus métodos a través del contenedor de servicios. Sin embargo, en Laravel 5.4, puedes fácilmente convertir cualquier clase de tu aplicación en una fachada en tiempo real simplemente agregando como prefijo Facades
a la clase importada. Por ejemplo, imagina que tu aplicación contiene una clase como la siguiente:
<?php
namespace App\Services;
class PaymentGateway
{
protected $tax;
/**
* Crear una nueva instancia de PaymentGateway.
*
* @param TaxCalculator $tax
* @return void
*/
public function __construct(TaxCalculator $tax)
{
$this->tax = $tax;
}
/**
* Pagar la cantidad acordada.
*
* @param int $amount
* @return void
*/
public function pay($amount)
{
// Pagar la cantidad acordada...
}
}
Puedes también utilizar la clase como fachada de esta forma:
use Facades\ {
App\Services\PaymentGateway
};
Route::get('/pay/{amount}', function ($amount) {
PaymentGateway::pay($amount);
});
Obviamente, si utilizas fachadas en tiempo real de esta forma, puedes fácilmente testearlo utilizando las capacidades de mocking de fachadas de Laravel:
PaymentGateway::shouldReceive('pay')->with('100');
En Laravel 5.3, todos los modelos de tablas pivot (o intermedias) para las relaciones belongsToMany
usaban la misma instancia de modelo Pivot que viene por defecto.
En Laravel 5.4, puedes definir modelos para tus tablas pivot de forma personalizada.
Si deseas definir un modelo personalizado que representa la tabla intermedia de tu relación, usa el siguiente método mientras describes la relación:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Role extends Model
{
/**
* El usuario que pertenece al rol
*/
public function users()
{
return $this->belongsToMany('App\User')->using('App\UserRole');
}
}
Anteriormente, no era posible definir conexiones Redis a hosts individuales y a clusters a la vez en la misma aplicación. En Laravel 5.4, puedes definir conexiones a múltiples hosts individuales y a múltiples clusters dentro de la misma aplicación. Para más información sobre Redis en Laravel, puedes consultar la documentación completa de Redis.
Laravel 5.4 usa el set de caracteres utf8mb4
por defecto, que incluye soporte para almacenar emojis en la base de datos. Si estás actualizando tu aplicación de Laravel 5.3, no es requerido cambiar el set de caracteres.
Si elijes cambiar el set de caracteres de forma manual y estás corriendo una versión de MySQL anterior a la 5.7.7, puedes necesitar configurar manualmente la longitud por defecto de los strings generados por migraciones. Puedes configurarlo llamando al método Schema::defaultStringLength
dentro de tu AppServiceProvider
:
use Illuminate\Support\Facades\Schema;
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Schema::defaultStringLength(191);
}
]]>Luego de un tiempo sin escribir, voy a continuar con el tutorial acerca de REST API's con laravel.
En la primer parte pudimos llegar a listar proyectos y tareas, pero todavía no creamos el código para poder insertar, actualizar y eliminar estos recursos. Antes
]]>Luego de un tiempo sin escribir, voy a continuar con el tutorial acerca de REST API's con laravel.
En la primer parte pudimos llegar a listar proyectos y tareas, pero todavía no creamos el código para poder insertar, actualizar y eliminar estos recursos. Antes de comenzar la implementación, voy a mencionar ciertas características a tener en cuenta a la hora de crear una API REST.
Debemos identificar de manera única los recursos en el servidor. Para ésto utilizaremos URI's que tendrán la siguiente forma:
{protocolo}://{dominio o hostname}[:puerto (opcional)]/{ruta del recurso}?{consulta de filtrado}
En la parte 1 del tutorial usamos http://localhost/projects para obtener el listado del proyecto. Como verán respetamos la forma mencionada arriba.
Generalmente se recomienda utilizar como nombre del recurso un sustantivo en plurar. La idea de esto es que sea lo mas simple y uniforme dentro de lo posible.
Los verbos HTTP mas comunes son:
GET: Para consultar y leer recursos.
POST: Para crear recursos.
PUT: Para editar recursos.
DELETE: Para eliminar recursos.
PATCH: Para editar partes concretas de un recurso.
Sabiendo ésto, vamos a describir los diferentes endpoints que va a tener nuestro Web Service. Si nos ubicamos en el archivo de rutas, vamos a ver que utilizamos las rutas preparadas para RESTful, osea que tenemos los siguientes endpoints:
GET /projects
GET /projects/{id}
POST /projects
PUT /projects/{id}
DELETE /projects/{id}
GET /projects/{projectId}/tasks
GET /projects/{projectId}/tasks/{taskId}
POST /projects/{projectId}/tasks
PUT /projects/{projectId}/tasks/{taskId}
DELETE /projects/{projectId}/tasks/{taskId}
Completemos los controllers con los métodos mencionados.
<?php
// app/Http/Controllers/ProjectsController.php
namespace App\Http\Controllers;
use App\Project;
use App\Http\Requests;
use Illuminate\Support\Facades\Input;
class ProjectsController extends Controller
{
public function index()
{
return Project::all();
}
public function store()
{
return Project::create(Input::all());
}
public function show($id)
{
return Project::findOrFail($id);
}
public function update($projectId)
{
Project::findOrFail($projectId)->update(Input::all());
}
public function destroy($id)
{
Project::findOrFail($id)->delete();
}
}
Como podemos observar, los métodos que tiene el controlador concuerdan con los descritos en las rutas. Cuando creamos un recurso, se llamara al método store(), cuando queremos un recurso en concreto llamamos a show($id), cuando queremos actualizar llamamos a updtate($id) y cuando queremos eliminar llamamos al método destroy($id). A la hora de responder, estamos haciéndolo de la forma mas sencilla posible. Aprovechamos el código de estado propio del protocolo HTTP para indicar si fue exitoso o que pasó en el request, y cuando hace falta devolvemos algo que nos sirva. En el caso del store(), además de crear el recurso lo devolvemos, ésto le va a permitir al cliente evitar un request para saber el Id del nuevo recurso.
Por otro lado, el controlador de tareas nos va a quedar así:
<?php
// app/Http/Controllers/ProjectTasksController.php
namespace App\Http\Controllers;
use App\Project;
use App\Task;
use App\Http\Requests;
use Illuminate\Support\Facades\Input;
class ProjectTasksController extends Controller
{
public function index($projectId)
{
return Task::where('project_id',$projectId)->get();
}
public function store($projectId)
{
$project = Project::findOrFail($projectId);
$input = Input::all();
$input['project_id'] = $project->id;
return Task::create($input);
}
public function show($projectId,$taskId)
{
return Task::findOrFail($taskId);
}
public function update($projectId, $taskId)
{
Task::findOrFail($taskId)->update(Input::all());
}
public function destroy($projectId, $taskId)
{
Task::findOrFail($taskId)->delete();
}
}
Muy similar al anterior, pero al tener una relación con los proyectos, se debe indicar a que proyecto está asociada la tarea.
Antes de comenzara usar el API debemos tener en cuenta que en laravel 5.2 todas las rutas que ubiquemos en app/Http/routes.php estarán bajo el middleware group "web". Esto quiere decir que tendrá asociado el middleware VerifyCsrfToken, el cuál nos pedirá que enviemos un token en las peticiones que no son GET. Este problema se puede solucionar de varias maneras. Se podría comentar la línea donde se incluye.
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
// \App\Http\Middleware\VerifyCsrfToken::class,
],
'api' => [
'throttle:60,1',
],
];
Otra opción podría ser crear un archivo de rutas para las rutas del api. Como se usa en laravel 5.3, podríamos crear el archivo routes/api.php y asociarlo en el service provider.
<?php
// app/Providers/RouteServiceProvider.php
namespace App\Providers;
use Illuminate\Routing\Router;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
class RouteServiceProvider extends ServiceProvider
{
/**
* This namespace is applied to your controller routes.
*
* In addition, it is set as the URL generator's root namespace.
*
* @var string
*/
protected $namespace = 'App\Http\Controllers';
/**
* Define your route model bindings, pattern filters, etc.
*
* @param \Illuminate\Routing\Router $router
* @return void
*/
public function boot(Router $router)
{
//
parent::boot($router);
}
/**
* Define the routes for the application.
*
* @param \Illuminate\Routing\Router $router
* @return void
*/
public function map(Router $router)
{
$this->mapApiRoutes($router);
//
}
/**
* Define the "web" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
*
* @param \Illuminate\Routing\Router $router
* @return void
*/
protected function mapWebRoutes(Router $router)
{
$router->group([
'namespace' => $this->namespace, 'middleware' => 'web',
], function ($router) {
require app_path('Http/routes.php');
});
}
protected function mapApiRoutes(Router $router)
{
$router->group([
'namespace' => $this->namespace, 'middleware' => 'api',
], function ($router) {
require base_path('routes/api.php');
});
}
}
Con esto ya podremos utilizar esta API REST muy sencilla. Podrían probarla utilizando algún cliente como Postman o Advanced REST client. Ambos se pueden descargar desde las apps de Chrome.
En esta imagen podemos ver como realizamos una petición usando el verbo POST, donde creamos un nuevo proyecto. Recuerden enviar los datos utilizando x-www-form-urlencoded.
Con esto finalizamos el tutorial de REST en laravel 5.2. En futuros tutoriales vamos a hablar con mayor detalle del uso de REST API's y las mejores prácticas, validaciones, paginación, transformers, documentación y otros elementos que harán nuestras API's más robustas y sencillas de consumir.
Espero que les haya sido útil, y no duden en dejarnos sus consultas y comentarios debajo!
Encontranos en @coffeedevs
]]>En otras ocasiones hemos hablado de la importancia de nuestro entorno de producción y las ventajas de utilizar Git y VPS para el deployment de nuestras aplicaciones.
Pero, tener tu propio servidor VPS puede consumir bastante tiempo y hay mucho para aprender si tu conocimiento no involucra servidores,
]]>En otras ocasiones hemos hablado de la importancia de nuestro entorno de producción y las ventajas de utilizar Git y VPS para el deployment de nuestras aplicaciones.
Pero, tener tu propio servidor VPS puede consumir bastante tiempo y hay mucho para aprender si tu conocimiento no involucra servidores, servidores web o terminales linux, o quizá simplemente quieres algo más parecido a Heroku, donde puedes deployear tu aplicación a producción solo con un git push
y a la vez no perder el control de tu entorno.
Pues bien, la solución existe y se llama Laravel Forge.
Forge es una aplicación web desarrollada por Taylor Otwell, creador de Laravel.
Esta herramienta se conecta a nuestro proveedor de infraestructura, sea Linode, DigitalOcean, Amazon Web Services u otro, y nos permite crear nuevos servidores
con PHP 7, Nginx, MySql o MariaDB, Postgres y Redis por defecto, sin que nosotros tengamos que instalar nada manualmente.
Si alguna vez tuvieron que configurar un certificado SSL, saben lo engorroso (pero necesario) que es todo eso, desde configurar el servidor web hasta generar el certificado y agregarlo a nuestro servidor.
Con Forge, díganle adiós a todo eso porque provee una opción muy sencilla de instalación y renovación de certificados SSL, incluyendo https://letsencrypt.org/, el proveedor gratuito de certificados!
Y además de todo eso, los proyectos que subamos a Forge, con un simple click podemos configurarlos como auto-deploy, lo que significa que cada vez que hagamos un git push
, Forge hara un git pull
en el servidor que corresponda, correrá composer
y php artisan migrate
y sin realizar nada, ya tendremos nuestro sitio en producción.
El tiempo que nos ahorra esta feature para iterar cambios en nuestro día a día hace que el servicio se pague solo, y que si nunca trabajaron con este tipo de workflows, queden asombrados con la rapidez con la que pueden desplegar cambios.
Y todo esto no es solo para Laravel, Forge también nos permite subir proyectos PHP tradicionales, Wordpress, Symfony o páginas simples sin backend, manteniendo los mismos features de instalación rápida de SSL y auto-deploy.
Si todavía no los convencí, pueden probarlo gratis por 5 días y jugar un poco.
Nosotros ya no podemos vivir sin Forge!
Espero que les haya sido útil, y no olviden dejarnos sus dudas o comentarios debajo!
]]>Laravel 5.3 vino cargado de excelentes nuevas features, entre las cuales están:
Los primeros tres ya los hemos cubierto en otros posts de este mismo blog, y hoy paso a traerles un nuevo integrante,
]]>Laravel 5.3 vino cargado de excelentes nuevas features, entre las cuales están:
Los primeros tres ya los hemos cubierto en otros posts de este mismo blog, y hoy paso a traerles un nuevo integrante, Laravel Passport.
Passport es un paquete oficial de Laravel para integrar fácilmente un servidor OAuth 2 a tu aplicación de Laravel.
Tradicionalmente, instalar y configurar un paquete de OAuth 2, o implementarlo manualmente, ha sido un verdadero dolor de cabeza, pero por suerte, Taylor Otwell, creador de Laravel, armó para la versión 5.3, un paquete independiente que permite integrar rápidamente las funcionalidades de OAuth en nuestra aplicación.
Para empezar, Passport es un paquete externo al core del framework, por lo que debemos requerirlo con Composer:
composer require laravel/passport
Una vez que terminó de instalarse, podemos agregarlo a nuestro archivo app.php
como un ServiceProvider:
Laravel\Passport\PassportServiceProvider::class,
Ahora ya podremos realizar la migración, que contiene las tablas necesarias para generar clientes, tokens y demás.
php artisan migrate
Luego, tenemos que utilizar el siguiente comando para que Passport genere dos claves RSA que utilizará para encriptar nuestros tokens, y además creará dos clientes nuevos, uno para Personal Access Tokens y otro para Password Grants.
php artisan passport:install
Si vamos a crear tokens para aplicaciones propias (first-party), hasta aquí está bien, pero si queremos realizar algo parecido a Github, donde nuestros usuarios pueden registrar aplicaciones y que esas aplicaciones se conecten con la nuestra, necesitamos generar clientes nuevos asociados con esos usuarios.
Para que los usuarios de tu aplicación puedan solicitar tokens, tienes que agregarle el Trait HasApiTokens
al Model para que quede así:
class User extends Authenticatable
{
use HasApiTokens, Notifiable;
}
Después, tenemos que agregar a nuestro AuthServiceProvider
el siguiente método para registrar las rutas de Passport:
public function boot()
{
$this->registerPolicies();
Passport::routes();
}
Por último, tenemos que determinar en nuestro archivo session.php
que utilizaremos el driver de Passport para las sesiones de nuestro API:
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
Con eso ya queda configurado nuestro servidor para recibir peticiones de acceso con OAuth y entregar tokens de acceso.
Passport además propone una implementación frontend en Vue.js con componentes que permiten visualizar, consumir y generar clientes OAuth.
Puede utilizarse o pueden crear sus propias implementaciones que choquen contra el backend.
Ahora que tenemos integrado nuestro servidor OAuth en nuestra aplicación, que conseguimos?
Permitimos a otras aplicaciones que se integren la nuestra de forma segura.
Podemos desarrollar aplicaciones nuestras que se integren con nuestra versión actual, manteniendo un mismo punto de acceso (nuestro API) para todas, y que manejen de forma sencilla y segura la autenticación.
Un saludo y espero que les haya resultado de utilidad!
]]>Hoy les traemos 4 paquetes que utilizamos en nuestros proyectos Laravel que quizá no conozcan pero que resultan muy útiles para el día a día.
Prestissimo es un paquete para Composer (el manejador de dependencias de PHP) que permite paralelizar las descargas, lo
]]>Hoy les traemos 4 paquetes que utilizamos en nuestros proyectos Laravel que quizá no conozcan pero que resultan muy útiles para el día a día.
Prestissimo es un paquete para Composer (el manejador de dependencias de PHP) que permite paralelizar las descargas, lo que agiliza muchísimo la instalación de paquetes, sobretodo en proyectos grandes como Laravel.
Simplemente tienen que instalar prestissimo como dependencia global de Composer y listo, cada vez que utilizen el comando composer install o update, Prestissimo actuará en su lugar y veras como los tiempos de instalación bajan considerablemente.
Prestissimo es la versión de Composer del próximo paquete que mejorará tu vida como desarrollador:
Yarn es un manejador de dependencias para módulos Javascript escrito y mantenido por Facebook.
Yarn funciona como npm, utilizando el mismo repositorio de paquetes, pero descarga los paquetes de forma paralela, igual que Prestissimo, por lo que reduce el tiempo de instalación total. Además, Yarn guarda en caché todos los paquetes que descarga, lo que permite que puedas instalarlos de nuevo aunque no tengas conexión, y además son mucho más rápidos de instalar que si los tuvieras que descargar de nuevo!
Y por último y no menos importante, Yarn introduce a las dependencias de Javascript un archivo .lock
igual que en Composer que una vez en el sistema de control de versiones (git o similar), hará que todas las instalaciones de esos paquetes en distintos ambientes de desarrollo sean siempre iguales, con la enorme ventaja de que todos los developers tendrán el mismo conjunto de modulos de node, evitándonos el problema de eliminar la carpeta node_modules
y reinstalar cada vez que teníamos un problema con npm para actualizar dependencias o versiones de paquetes nuevos.
Laravel Debugbar es un paquete para Laravel para ayudar a resolver problemas en nuestras aplicaciones.
Se inyecta dinámicamente en nuestra aplicación y nos va mostrando un montón de información útil sobre la misma:
Y muchos otros datos más, que nos permiten ir debuggeando nuestra aplicación y mejorando los tiempos de respuesta de la misma.
Indispensable!
Laravel-Lang es un paquete de idiomas para Laravel, con los archivos de Laravel en distintos idiomas listos para que podamos utilizar en nuestras aplicaciones.
Esto incluye los mensajes de error de validación de formularios, de autenticación, de paginación y los mensajes que se muestran a la hora de recuperar/renovar la contraseña.
Para los que trabajamos con clientes latinoamericanos o que utilizan otro idioma distinto al inglés por defecto, este paquete es una bendición y nos ahorra muchísimo tiempo.
Eso fue todo, espero que les haya sido útil.
Dejen sus comentarios con los paquetes que a ustedes les resultaron útiles!
]]>