Laravel | Fabryka czyli factory

Zabawy z bazą danych mają to do siebie, że czasem musimy usunąć wszystkie wpisy, a niekiedy zrobimy to zupełnie przypadkowo. Taka sytuacja pozbawia Nas możliwości “zabawy” z danymi, gdyż musimy jeszcze raz wprowadzić jakieś danie. Co gdyby jednym poleceniem dodać 1000 wpisów na bloga, albo 10 tys użytkowników ze zdjęciami profilowymi, adresami mailowymi, co więcej – te dane będą losowo generowane także nie będą się powtarzać – zaciekawiony? W tym wpisie opowiemy sobie o factory, czyli fabryce wbudowanej w Laravel-a.

Przejdźmy do konsoli i wpiszmy w niej:

php artisan make:factory PostFactory

Takie polecenie pozwoli wygenerować plik:

database/factories/PostFactory.php

a tak będzie wyglądał w środku:

<?php

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use App\Model;
use Faker\Generator as Faker;

$factory->define(Model::class, function (Faker $faker) {
    return [
        //
    ];
});

Na samym wstępie, musimy zadeklarować do jakiego modelu Ta konkretna fabryka (gdyż możemy ich mieć dowolną ilość) została utworzona dla modelu Post, więc to zapiszmy:

$factory->define(Model::class, function (Faker $faker)
na
$factory->define(App\Post::class, function (Faker $faker)

Fabryka ta korzysta z biblioteki dostępnej dla php (https://github.com/fzaninotto/Faker), a wracając do kodu, zwraca on tablicę asocjacyjną, w której możemy zadeklarować pola jakie ma produkować, np:

'title' => $faker->sentence(6), //Utwórz zdanie które posiada 6 słów
'content' => $faker->paragraph(7), //Utwórz akapit, który ma 7 zdań
'date' => now(), // możemy używać dostępnych funkcji przez Laravel
'type' => 'text' // możemy także na sztywno wprowadzać dane

Aby wykonać taki faker post, przechodzimy do konsoli i wpisujemy:

php artisan tinker
factory(App\Post::class)->make()

Jak można zaobserować post został wygenerowany:

Zapewne domyślasz się, że skoro został wygenerowany, to nie znaczy, że automatycznie jest dodany do bazy danych 😉 Abny go automatycznie dodać powinniśmy na końcu polecenia użyć metody ->save();

factory(App\Post::class)->make()->save();

Aby to lepiej wytłumaczyć warto pokazać cały kod i go przeanalizować:

$factory->define(App\Post::class, function (Faker $faker) {
    return [
        'title' => $faker->sentence(5),
        'content' => $faker->paragraph(5),
        'date' => now(),
        'type' => 'text'
    ];
});

$factory->state(App\Post::class, 'image', function (Faker $faker) {
    return [
        'content' => null,
        'date' => now(),
        'type' => 'photo',
        'image' => $faker->imageUrl(1200, 800)
    ];
});

Zacznijmy od początku omawiać drugi faker post. Pierwsza różnica zamiast define użyliśmy state (linia 10). Chodzi o to że pierwszy post jest zadeklarowany a drugi jest potomkiem pierwszego. Aby to lepiej zrozumieć wytłumaczę to na pierwszym elemencie tablicy asocjacyjnej jakim jest title (linia 3). Zwróć uwagę, że jest tylko w pierwszej fabryce a w drugiej go nie ma – prawda? a skoro nie zadeklarowaliśmy go w drugiej to, automatycznie zostanie dodany z pierwszego. Inaczej się ma sprawa z content. W pierwszym jest zadeklarowane, a w drugim jest zadeklarowane jako null. Oznacza to tyle, że widzimy, że jest zadeklarowany powyżej ale my go świadomie nie chcemy. Możemy dodać oczywiście więcej pól, które nie były zadeklarowane powyżej jak, np: image. W nim odwołujemy się do biblioteki $faker i mówimy jej, że chcemy tu ścieżkę do obrazka (z zewnętrznego źródła), a sam obrazem ma mieć rozmiary 1200px na 800px. Jednak to nie jedyna zmiana. Jak zapewne rzuciło Ci się w oczy przy deklarowaniu instancji doszedł jeden parametr – 'image' (linia 10). Jest tu on po to, żebyśmy przy tworzeniu “fejkowego” posta powiedzieli fabryce który typ postu konkretnie ma utworzyć (typu 'text', czy typu image).

Ok, ale jak teraz wywołać drugą fabrykę? Wystarczy, że przejdziemy do <code>php artisan tinker</code> i posłużymy się takim poleceniem.

php artisan tinker
factory(App\Post::class)->state('image')->make()

Oczywiście pamiętajmy, że powyższy kod tylko generuje “fejkowy” post, więc jeśli chcielibyśmy aby odrazu został zapisany musimy na końcu dodać metodę <code>->save()</code>

factory(App\Post::class)->state('image')->make()->save()

No dobrze, wiemy już jak generować posty ale, co mam tera 1000 razy powielać polecenia, żeby dodać 1000 wpisów? 🙂 – Nie ale przejdziemy do tego w artykule z seed-owanie w Laravel.