Search code examples
laravellaravel-factory

Laravel 7: Create a custom factory for category


I was trying to make the following category factory to work.

Category factory

<?php

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

use App\Category;
use Illuminate\Support\Str;
use Faker\Generator as Faker;

$categories = ['category', 'category-2', 'category-3']

$factory->define(Category::class, function (Faker $faker) {
    return [
        'name' => // I can't use a foreach here
        'slug' => Str::slug($category),
    ];
});

How do I implement this?

I need my categories to be unique

Update Using the latest update from @omr

Category factory

use App\Category;
use Illuminate\Support\Str;
use Faker\Generator as Faker;

$categories = ['Hardware', 'Software', 'Planning', 'Tools'];

foreach ($categories as $categoryName) {
    factory(Category::class)->create([
        'name' => $categoryName,
        'slug' => Str::slug($categoryName),
    ]);
}

Database seeder



public function run()
    {
        factory('App\Category', 20)->create();
        
    }

 ErrorException 

  require(/home/dan/Codes/laravel/jobportal/database/factories/CategoryFactory.php): failed to open stream: Too many open files

  at vendor/laravel/framework/src/Illuminate/Database/Eloquent/Factory.php:220
    216|         $factory = $this;
    217| 
    218|         if (is_dir($path)) {
    219|             foreach (Finder::create()->files()->name('*.php')->in($path) as $file) {
  > 220|                 require $file->getRealPath();
    221|             }
    222|         }
    223| 
    224|         return $factory;
 

Thanks


Solution

  • you can use $faker->numberBetween to get random element from $categories array and then use it inside the factory:

    $categories = ['category', 'category-2', 'category-3'];
    
    $factory->define(Category::class, function (Faker $faker)use($categories) {
        $categoryName= $categories[$faker->numberBetween(0,count($categories)-1)];
        return [
            'name' =>$categoryName,
            'slug' => Str::slug($categoryName),
        ];
    });
    

    edit:

    if you want to generate unique category names

    first: standard category factory:

    $factory->define(Category::class, function (Faker $faker){
    
        return [
            'name' =>$faker->name,
            'slug' =>  Str::slug($faker->text(12))
        ];
    });
    

    as long as you pass the factory fields you self, there is no need for worrying about category name and slug compatibility ....

    second:

    now when you make your categories you pass the attributes you want, like this:

    in Database seeder:

    use use Faker\Generator;
    

    ....... .......

    $counter=0;
    while($counter<20)
    {
    $categoryName=$faker->text(12);
    if(Category::firstWhere('name',$categoryName)==null)
    {
    $counter+=1;
    factory(Category::class)->create(['name'=>$categoryName,'slug'=>Str::slug($categoryName)]);
    }
    }
    

    don't use directly factory('App\Category', 20)->create(); with no parameter it can't help you there ...