Creating factories for a project I'm working on, I have a problem creating a belongsTo relationship.
In my Cards
table, I have 2 columns referencing the same relation :
Card->order->id
and Card->order->ref
(don't ask me why, I don't even know).
So, in my CardFactory
I need to be able to use the same instance of Order
for both $card->order_ref
and $card->order_id
. Using factory states, I did create the following state :
public function sold(int $userId) : Factory
{
$createdOrder = Order::factory()->forUser($userId)->create();
return $this->state(function (array $attributes) use ($createdOrder) {
return [
'state' => Card::STATE_SOLD,
'sold' => Carbon::now()->subDay(),
'addedincart' => Carbon::now()->subDay()->subHour(),
'selling_date' => Carbon::now()->subDay(),
'order_id' => $createdOrder->id,
'order_ref' => $createdOrder->ref,
];
});
}
my OrderFactory.php
:
class OrderFactory extends Factory {
public function definition() : array
{
return [
'ref' => $this->faker->randomNumber(9) ,
'state' => 5,
'clientname' => $this->faker->name(),
'email' => $this->faker->email(),
'phone' => $this->faker->phoneNumber(),
'address' => null,
'shippingaddress' => NULL,
'total' => $this->faker->randomFloat(2, 50, 700),
'method' => 'creditcard',
'user_id' => null,
'tracking' => NULL,
'response' => json_encode(["someFields" => "someValues"]),
'paid_on' => now(),
'sent_on' => now(),
'review_sent' => '1',
'deliverymethod' => 'email',
'deliverycosts' => '0.00',
'coupon_id' => NULL,
'discount' => '0.00',
'explanation' => NULL,
'refund_amount' => NULL,
'refunded_at' => NULL,
'shipping_status' => NULL,
'original_cards' => '[1, 2]',
'cancel_reason' => NULL,
'private_comment' => NULL,
'loyalty' => '30',
'ip' => '00.00.00.00',
'cb' => 'someCb',
'geoip' => NULL,
'ecards_sent' => '1',
'blocked_by' => NULL,
'partner' => NULL,
'original_giftcards' => '',
'giftcards_sent' => '0',
'api_data' => NULL,
'original_products' => NULL,
'delivered_at' => now(),
'invoice_send_at' => NULL,
'type' => 'cards',
'redeem_id' => '0',
];
}
public function forUser(int $id) : Factory
{
return $this->state(function (array $attributes) use ($id) {
return [
'user_id' => $id,
];
});
}
}
and in my CardSeeder.php
:
public function run()
{
$user = User::query()->where("email", "myAddress@gmail.com")->first();
Card::factory()->sold($user->id)->count(15)->create();
Card::factory()->selling()->count(15)->create();
}
The problem is, for each sold
state created, the same $createdOrder->id
is used.
How could I, for each row, use a different order ?
AS docs https://laravel.com/docs/9.x/database-testing#defining-relationships-within-factories
Describe :
If the relationship's columns depend on the factory that defines it you may assign a closure to an attribute. The closure will receive the factory's evaluated attribute array.
so if you want genereate new instance of relation, u must create it inside closure:
public function sold(int $userId) : Factory
{
return $this->state(function (array $attributes) use ($userId) {
$order=null;
return [
'state' => Card::STATE_SOLD,
'sold' => Carbon::now()->subDay(),
'addedincart' => Carbon::now()->subDay()->subHour(),
'selling_date' => Carbon::now()->subDay(),
'order_id' => function()use(&$order,$userId){
$order = Order::factory()->forUser($userId)->create();
return $order->id;
},
'order_ref' => function()use(&$order){
return $order->ref;
},
];
});
}