Summer Sale! All accounts are 50% off this week.

bwrigley's avatar

Cascading afterCreatingState() in factories

I'm creating a forum which has these relationships:

ForumCategory hasmany ForumThread hasmany ForumReply

and both ForumThread and FormReply hasmany ForumLike

I'm now trying to set up factories and seeders and I'm using the afterCreatingState() to create relationship models:

ForumCategoryFactory:

$factory->define(ForumCategory::class, function (Faker $faker) {
    return [

        'name' => implode(' ', $this->faker->words(3)),
        'description' => $this->faker->text(600),

    ];
});


$factory->afterCreatingState(ForumCategory::class, 'with-threads', function ($category) {

    $category->forumThreads()
    ->saveMany(factory(ForumThread::class, rand(0,6))
    ->states('with-user','with-replies','with-likes')
    ->create());
});

ForumThreadFactory:

$factory->define(ForumThread::class, function (Faker $faker) {

    return [
        'title' => implode(' ',$faker->words(3)),
        'message' => $faker->text(600),
        'is_resolved' => false,
        'is_locked' => false,
        'is_pinned' => $faker->boolean(),
        'is_live' => true,
        'is_visible' => true,
        'view_count' => $faker->numberBetween(0,1000),
        'user_id' => null,
        'forum_category_id' => null,

    ];
});

$factory->afterCreatingState(ForumThread::class, 'with-replies', function ($thread) {


    $thread->forumReplies()
    ->saveMany(factory(ForumReply::class, rand(0,6))
    ->states('with-user')
    ->create());
});

$factory->afterCreatingState(ForumThread::class, 'with-likes', function ($thread) {

     $thread->forumLikes()
    ->saveMany(factory(ForumLike::class, rand(0,6))
    ->states('with-user')
    ->create());
});

///

ForumReplyFactory:

$factory->define(ForumReply::class, function (Faker $faker) {
    return [
        'message' => $faker->text(600),
        'is_solution' => $faker->boolean(),
        'is_locked' => $faker->boolean(),
        'is_pinned' => $faker->boolean(),
        'is_visible' => true,
        'user_id' => null,
        'forum_thread_id' => null,
    ];
});


$factory->afterCreatingState(ForumReply::class, 'with-likes', function ($reply) {

    $reply->forumLikes()
    ->saveMany(factory(ForumLike::class, rand(0,6))
    ->states('with-user')
    ->make());
});

///

For the most part it is working, the category is created as are threads and replies and likes. The threads have relationships to the category.

The problem I'm having is that the ForumReply and ForumLike models all have null 'forum_thread_id`

Thanks for any guidance or spotting of glaring errors.

0 likes
16 replies
Sti3bas's avatar

@bwrigley you have to change create to make when passing factories to saveMany methods, the same way as you do in ForumReplyFactory.

bwrigley's avatar

@sti3bas thanks for your reply so quickly!

I tried this but and switched all the afterCreatingState() calls to aftermakingState() but all my ForumReply and ForumLike models are still orphaned.

Sti3bas's avatar

@bwrigley nah, it should be afterCreatingState, but:

$factory->afterCreatingState(ForumThread::class, 'with-replies', function ($thread) {
    $thread->forumReplies()
    ->saveMany(factory(ForumReply::class, rand(0,6))
    ->states('with-user')
    ->make());
    // ^ create to make
});

$factory->afterCreatingState(ForumThread::class, 'with-likes', function ($thread) {
     $thread->forumLikes()
    ->saveMany(factory(ForumLike::class, rand(0,6))
    ->states('with-user')
    ->make());
    // ^ create to make
});
bwrigley's avatar

@sti3bas I had tried that too and then I get no ForumReply or ForumLike models at all

$factory->afterCreatingState(ForumThread::class, 'with-replies', function ($thread) {

	dd('I got called')

    $thread->forumReplies()
    ->saveMany(factory(ForumReply::class, rand(0,6))
    ->states('with-user')
    ->make());
});

dd never gets called

Sti3bas's avatar

@bwrigley I was not able to reproduce it with a little bit simplified version on Laravel 7.

Can you also show with-user state?

bwrigley's avatar

@sti3bas so sorry for slow reply, I didn't get a notification for some reason.

I have now realised the issue from my side is that I was running the factory in tinker which seems not to create the relationships properly.

I have it working find now through a seeder, using either make or create

So sorry for wasting your time!

1 like
connecteev's avatar

@bwrigley

By chance do you have a public repo you can share for this forum project you were working on?

connecteev's avatar

@bwrigley It looks like you were building a forum with all the functionality (like laracasts) that I was hoping to use. It would've been a time-saver.

connecteev's avatar

@Sti3bas thank you! It still isn't a laravel project, as far as I can tell...but it does share a lot of the same core package dependencies...thank you! Out of curiosity, what app(s) are you working on? Do you maintain any open source projects on github? Would love to take a look at them if so.

Please or to participate in this conversation.