Faker

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 Factoryen 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-autoloadpara 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.

Suscríbete a nuestro boletín

Te enviaremos publicaciones con consejos útiles y múltiples recursos para que sigas aprendiendo.

Regístrate hoy en Styde y obtén acceso a todo nuestro contenido.