Laravel Factory: manually increasing a column

For the following factory definition, the column order

must be sequential. There is already a column id

that is automatically growing. The first line order

should start with 1

and each additional line order

should be the next number ( 1

, 2

, 3

etc.)

$factory->define(App\AliasCommand::class, function (Faker\Generator $faker) {
    return [
        'user_id' => App\User::inRandomOrder()->first()->id,
        'command' => $faker->word,
        'content' => $faker->sentence,
        'order'   => (App\AliasCommand::count()) ?
            App\AliasCommand::orderBy('order', 'desc')->first()->order + 1 : 1
    ];
});

      

The column needs to be set order

to 1 more than the previous row, however this causes all rows to be assigned 1

.

+5


source to share


3 answers


Something might work here.

$factory->define(App\AliasCommand::class, function (Faker\Generator $faker) {
    static $order = 1;   
    return [
        'user_id' => App\User::inRandomOrder()->first()->id,
        'command' => $faker->word,
        'content' => $faker->sentence,
        'order'   => $order++
    ];
});

      



It just keeps a counter internal to that function.

+14


source


To achieve true autoincrement, it is better to use this approach:



   $__count = App\AliasCommand::count();
   $__lastid = $__count ? App\AliasCommand::orderBy('order', 'desc')->first()->id : 0 ;


   $factory->define(App\AliasCommand::class,
       function(Faker\Generator $faker) use($__lastid){

       return [

         'user_id' => App\User::inRandomOrder()->first()->id,
         'command' => $faker->word,
         'content' => $faker->sentence,
         'order'   => $faker->unique()->numberBetween($min=$__lastid+1, $max=$__lastid+25),

         /*  +25 (for example here) is the number of records you want to insert 
             per run.
             You can set this value in a config file and get it from there
             for both Seeder and Factory ( i.e here ).
         */
      ];

   });

      

0


source


@Apokryfos answer is a good solution if you are confident that factory model generations will only work in sequential order and you are not interested in pre-existing data.

However, this can lead to incorrect values order

if, for example, you want to generate models for insertion into a test database where some records already exist.

By using a closure on a column value, we can better automate sequential ordering.

$factory->define(App\AliasCommand::class, function (Faker\Generator $faker) {
    return [
        'user_id' => App\User::inRandomOrder()->first()->id,
        'command' => $faker->word,
        'content' => $faker->sentence,
        'order'   => function() {
            $max = App\AliasCommand::max('order'); // returns 0 if no records exist.

            return $max+1;
        }
    ];
});

      

It was almost correct in your example, the problem is that you were executing the value order

during the definition of the factory and not in the above code which is executed during the generation of the separate model.

By the same principle, you must also wrap the code user_id

in a closure, otherwise all of your factory-generated models will have the same user ID.

0


source







All Articles