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
.
source to share
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.
source to share
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 ).
*/
];
});
source to share
@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.
source to share