Cuando creamos registros aleatorios para modelos en Laravel usando Faker, puede suceder que las opciones proporcionadas por los providers del paquete no nos permitan crear registros adaptados al contexto de nuestra aplicación. Afortunadamente, es posible extender el paquete y agregar métodos que nos ayuden a crear registros con datos que sean lo más reales posibles para la aplicación. A continuación, en este tutorial aprenderás a crear y configurar tus propios providers de Faker en un proyecto de Laravel.
Si no conoces mucho sobre Faker te invitamos a que revises el tutorial Generando datos de prueba con Faker en Laravel.
Cómo funciona Faker por dentro
Antes de extender las clases pertenecientes a Faker debemos entender cómo funciona:
Principalmente, Faker cuenta con providers los cuales son clases organizadas y clasificadas por temas o áreas que le agregan propiedades al generador para devolver los datos ficticios. El listado de opciones disponibles lo puedes ver en su repositorio oficial.
Estas propiedades son en realidad métodos de las clases providers que generan los datos ficticios.
Cuando creamos una nueva instancia de Faker\Generator
a través de $faker = Faker\Factory::create()
, ésta se crea agregando a la instancia de Faker\Generator
los providers que por defecto trae el componente, haciendo algo como:
$faker = new Faker\Generator(); $faker->addProvider(new Faker\Provider\en_US\Person($faker)); $faker->addProvider(new Faker\Provider\en_US\Address($faker)); $faker->addProvider(new Faker\Provider\en_US\PhoneNumber($faker)); $faker->addProvider(new Faker\Provider\en_US\Company($faker)); $faker->addProvider(new Faker\Provider\Lorem($faker)); $faker->addProvider(new Faker\Provider\Internet($faker));
Puedes mirar cómo lo hace en realidad en el método create()
de la clase Factory
en https://github.com/fzaninotto/Faker/blob/master/src/Faker/Factory.php
Luego, cuando le solicitamos un dato ficticio a la instancia, por ejemplo $faker->name
entonces esta instancia busca entre todos los providers agregados el método asociado al atributo que queremos, en este caso el método name
, desde el último provider agregado hasta el primero. Es decir, que nos da la facilidad de poder extender Faker para crear nuestros propios métodos e incluso sobreescribir los predeterminados y de esa manera adaptar Faker a las necesidades de nuestro proyecto.
Proyecto de ejemplo
Supongamos que tenemos un proyecto donde el modelo User
representa a usuarios de una aplicación para una asociación de abogados de habla inglesa y contiene los siguientes atributos definidos en el método up
de su migración:
Schema::create('users', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('name'); $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); $table->string('profession'); $table->string('firm_name')->nullable(); $table->rememberToken(); $table->timestamps(); });
Además, tenemos el factory definido para dicho modelo UserFactory
de esta manera:
$factory->define(User::class, function (Faker $faker) { return [ 'name' => $faker->name, 'email' => $faker->unique()->safeEmail, 'email_verified_at' => now(), 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password 'profession' => $faker->sentence(2), 'firm_name' => $faker->optional(60)->company, 'remember_token' => Str::random(10), ]; });
Luego de ejecutar las migraciones con php artisan migrate
, si usamos Tinker para crear registros con el helper factory
, podremos ver un resultado parecido a éste:
<?php $users = factory(App\User::class, 4)->create();
=> Illuminate\Database\Eloquent\Collection {#2951 all: [ App\User {#2980 id: 1, name: "Dr. Tatum Howe II", email: "[email protected]", email_verified_at: "2019-03-22 17:31:45", profession: "Quia modi magni.", firm_name: null, created_at: "2019-03-22 17:31:45", updated_at: "2019-03-22 17:31:45", }, App\User {#2981 id: 2, name: "Hailey Reynolds II", email: "[email protected]", email_verified_at: "2019-03-22 17:31:45", profession: "Dicta atque.", firm_name: null, created_at: "2019-03-22 17:31:45", updated_at: "2019-03-22 17:31:45", }, App\User {#2982 id: 3, name: "Clementine White", email: "[email protected]", email_verified_at: "2019-03-22 17:31:45", profession: "Sed nihil ducimus.", firm_name: "O'Kon-Ruecker", created_at: "2019-03-22 17:31:45", updated_at: "2019-03-22 17:31:45", }, App\User {#2983 id: 4, name: "George Bosco", email: "[email protected]", email_verified_at: "2019-03-22 17:31:45", profession: "Ducimus qui occaecati.", firm_name: "Frami Inc", created_at: "2019-03-22 17:31:46", updated_at: "2019-03-22 17:31:46", } ], }
Para efectos de nuestras pruebas mientras desarrollamos no tendríamos problema alguno que las profesiones tengan palabras aleatorias o que los nombres de las firmas no tengan mucho sentido.
Pero para presentar un demo al cliente si es de gran importancia que se sienta identificado con la aplicación y pueda ver las funcionalidades agregadas sin que se detenga en detalles que para nosotros los desarrolladores no importa, pero que el cliente sí los valora. De allí la necesidad de extender Faker para generar datos ficticios en nuestra aplicación mucho más reales y sin tener que agregarlos manualmente.
Extendiendo Faker en Laravel
En nuestro ejemplo requerimos que los usuarios creados pertenezcan a compañías o firmas en particular y que tengan una profesión dentro de una área en específico. Para ello necesitaremos extender Faker agregando un nuevo provider con los métodos que generen los datos que necesitamos y es lo que veremos a continuación.
Configuración de Laravel
Antes de extender Faker en un proyecto de Laravel para agregar nuevos métodos, tenemos que configurar el proyecto para que reconozca nuestros propios providers.
Como estos providers serán clases usadas solo cuando trabajamos con factories para crear datos ficticios las ubicaremos en el directorio database
. Sin embargo, para que se carguen las clases de este directorio se usa Classmap, por lo tanto debemos modificar el archivo composer.json
de esta manera:
"autoload": { "classmap": [ "database/seeds", "database/factories", "database/providers" ], "psr-4": { "App\\": "app/" } },
Luego creamos el directorio providers
dentro de database
, donde agregaremos todos las clases providers de Faker que necesitemos.
Es importante saber que por cada nuevo provider que agreguemos, debemos ejecutar el comando composer dump-autoload
para que sea agregado al listado de clases del proyecto. Alternativamente podrías configurar la Autocarga de clases con Composer y PSR-4 como hemos explicado en el Curso de programación orientada a objetos con PHP.
Creación de providers propios
Para crear nuestro propio provider, debemos crear una clase en el directorio database/providers
la cual puede extender cualquiera de las clases providers del paquete, por lo general se extiende de Faker\Provider\Base
que contiene los métodos que puedes reutilizar para generar tus propios datos ficticios o también puedes sustituir la forma en cómo se generan.
En nuestro ejemplo, vamos crear una nueva clase llamada LawFirmProvider
dentro del directorio providers
, con lo siguiente:
<?php use Faker\Provider\Company; class LawFirmProvider extends Company { protected static $jobTitles = [ 'Paralegal', 'Lawyer', 'Litigation Executive', 'Counsel', 'Solicitor', 'Barrister', 'Judge', 'Chartered Legal Executive', 'Attorney', 'General Counsel', 'Deputy General Counsel', 'Corporate Counsel', 'Brand Counsel', 'Contracts Manager', 'Compliance Manager', 'Patent Litigation Counsel', 'Patent Agent' ]; protected static $firmFormats = array( '{{firstName}} {{lastName}} {{firmSuffix}}', '{{lastName}} {{firmSuffix}}', '{{lastName}} & {{lastName}}', '{{word}} Law' ); protected static $firmSuffix = array('Law Firm', 'Law', 'Solicitors', 'Group', 'Lawyers'); /** * @example 'Lawyer' */ public function jobTitle() { return static::randomElement(static::$jobTitles); } /** * @example 'Group' */ public static function firmSuffix() { return static::randomElement(static::$firmSuffix); } /** * @example 'Acme Group' */ public function firm() { $format = static::randomElement(static::$firmFormats); return $this->generator->parse($format); } }
Esta clase extiende del provider del paquete Faker\Provider\Company
porque nos interesa cambiar la forma en que se generan los nombres de las profesiones para que sean relacionadas al área legal como «Solicitors», «Lawyer» o «Judge» y no una palabra aleatoria.
Puedes ver cómo es el provider por defecto en: https://github.com/fzaninotto/Faker/blob/master/src/Faker/Provider/Company.php
Para ello se ha sustituido el comportamiento del método jobTitle
por la selección aleatoria de uno de los elementos del arreglo $jobTitles
creado por nosotros y donde se encuentran las posibles profesiones de los usuarios.
Por otro lado, es necesario que los nombres de las firmas tengan términos legales y por ello se crea un nuevo método firm
que genera los nombres de manera aleatoria usando los formatos definidos en el arreglo firmFormats
.
No olvides ejecutar composer dump-autoload
luego de crear tus propios providers.
Uso del provider creado
Para usar el nuevo provider, simplemente debemos agregarlo a la instancia de $faker
a través del método addProvider
de esta manera:
<?php $faker->addProvider(new \LawFirmProvider($faker));
Ahora, se sustituye sentence(2)
por jobTitle
para que tome el título de las profesiones que se han definido en el provider y company
por firm
quedando el factory así:
$factory->define(User::class, function (Faker $faker) { $faker->addProvider(new \LawFirmProvider($faker)); return [ 'name' => $faker->name, 'email' => $faker->unique()->safeEmail, 'email_verified_at' => now(), 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password 'profession' => $faker->jobTitle, 'firm_name' => $faker->optional(0.6)->firm, 'remember_token' => Str::random(10), ]; });
Volviendo a Tinker podemos crear nuevos usuarios con el método factory
que ahora usa los métodos personalizados que le agregamos a Faker:
$users = factory(App\User::class, 4)->create();
Ahora, los usuarios creados tendrán tanto el nombre de una firma legal como su profesión adecuada:
$users = factory(App\User::class, 4)->create(); => Illuminate\Database\Eloquent\Collection {#2951 all: [ App\User {#2947 name: "Prof. Michael Becker", email: "[email protected]", email_verified_at: "2019-03-22 20:32:01", profession: "Solicitor", firm_name: null, updated_at: "2019-03-22 20:32:01", created_at: "2019-03-22 20:32:01", id: 1, }, App\User {#2942 name: "Kavon Sauer", email: "[email protected]", email_verified_at: "2019-03-22 20:32:01", profession: "Judge", firm_name: "Lakin & Ward", updated_at: "2019-03-22 20:32:01", created_at: "2019-03-22 20:32:01", id: 2, }, App\User {#2955 name: "Reed Feil", email: "[email protected]", email_verified_at: "2019-03-22 20:32:01", profession: "Litigation Executive", firm_name: "Louisa Steuber Law Firm", updated_at: "2019-03-22 20:32:01", created_at: "2019-03-22 20:32:01", id: 3, }, App\User {#2957 name: "Prof. Marc Hermann DVM", email: "[email protected]", email_verified_at: "2019-03-22 20:32:01", profession: "Deputy General Counsel", firm_name: "Crona Solicitors", updated_at: "2019-03-22 20:32:01", created_at: "2019-03-22 20:32:01", id: 4, }, ], }
¡Listo! ya los registros de usuarios de la aplicación aún cuando son aleatorios son lo más reales posibles según el contexto.
Espero que este nuevo conocimiento te sea de gran utilidad para el desarrollo de tus aplicaciones y nos ayudes compartiendo el enlace en tus redes sociales.
Regístrate hoy en Styde y obtén acceso a todo nuestro contenido.