首页 > 解决方案 > Laravel 工厂关联只关联最后的数据。如何解决这个问题?

问题描述

创建数据后,我有 2 个模型需要关联。我已经在这里问过了并得到了答案。我实现了它并进行了一些修改,因为它没有正确关联数据。现在我的协会有问题。它仅与最后一个数据相关联。

我期待的是从工厂创建的所有数据都是相互关联的。

当我执行php artisan tinker并运行App\App::first()->load('menus', 'menus.page')命令时,它没有给我正确的数据。请在此处查看结果。

如您所见,正确的数据仅显示在最后一个对象上。剩下的就是null。我怎样才能解决这个问题?请看下面我的播种机文件,我犯了什么错误吗?

<?php

use App\App;
use App\Component;
use App\Menu;
use App\Page;
use App\Role;
use App\Submenu;
use App\User;
use Illuminate\Database\Seeder;

class UsersTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $superadmin = Role::whereName('superadmin')->first();

        $tester = new User();
        $tester->name = "Tester";
        $tester->email = "test@appbuilder.com";
        $tester->password = bcrypt('password');
        $tester->save();

        $tester->roles()->attach($superadmin);

        // Create 5 apps for each user
        $tester->apps()->saveMany(factory(App::class, 5)->make())->each(function ($app) {
            $menus = factory(Menu::class, 5)->make();
            $pages = factory(Page::class, 5)->make();

            // Create 5 menus for each app and 5 submenus for each menu
            $app->menus()->saveMany($menus)->each(function ($menu) use ($pages) {
                // Associate page with each menu
                $pages->each(function ($page) use ($menu) {
                    $page->menu()->associate($menu);
                });

                // Create 5 submenus for each menu
                $menu->submenus()->saveMany(factory(Submenu::class, 5)->make())->each(function ($submenu) use ($pages) {
                    // Associate page with each submenu
                    $pages->each(function ($page) use ($submenu) {
                        $page->submenu()->associate($submenu);
                    });
                });
            });

            // Create 5 pages for each app and 5 components for each page
            $app->pages()->saveMany($pages)->each(function ($page) {
                $page->components()->saveMany(factory(Component::class, 5)->make());
            });
        });
    }
}

更新

这是我的模型文件,请看一下:

App.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class App extends Model
{
    /**
     * The attributes that should not be mass assignable.
     *
     * @var array
     */
    protected $guarded = ['id'];

    /**
     * Each app belongs to a user.
     *
     * @return \Illuminate\Database\Eloquent\Relationship\BelongsTo
     */
    public function user()
    {
        return $this->belongsTo(User::class);
    }

    /**
     * Each app has many pages.
     *
     * @return \Illuminate\Database\Eloquent\Relationship\HasMany
     */
    public function pages()
    {
        return $this->hasMany(Page::class);
    }

    /**
     * Each app has many menus.
     *
     * @return \Illuminate\Database\Eloquent\Relationship\HasMany
     */
    public function menus()
    {
        return $this->hasMany(Menu::class);
    }
}

Menu.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Menu extends Model
{
    /**
     * The attributes that should not be mass assignable.
     *
     * @var array
     */
    protected $guarded = ['id'];

    /**
     * Each menu belongs to a app.
     *
     * @return \Illuminate\Database\Eloquent\Relationship\BelongsTo
     */
    public function app()
    {
        return $this->belongsTo(App::class);
    }

    /**
     * Each menu has one page.
     * 
     * @return \Illuminate\Database\Eloquent\Relationship\HasOne
     */
    public function page()
    {
        return $this->hasOne(Page::class);
    }

    /**
     * Each menu has many submenus.
     *
     * @return \Illuminate\Database\Eloquent\Relationship\HasMany
     */
    public function submenus()
    {
        return $this->hasMany(Submenu::class);
    }

    /**
     * Each menu belongs to many roles.
     *
     * @return \Illuminate\Database\Eloquent\Relationship\BelongsToMany
     */
    public function roles()
    {
        return $this->belongsToMany(Role::class);
    }
}

Page.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Page extends Model
{
    /**
     * The attributes that should not be mass assignable.
     *
     * @var array
     */
    protected $guarded = ['id'];

    /**
     * Each page belongs to an app.
     *
     * @return \Illuminate\Database\Eloquent\Relationship\BelongsTo
     */
    public function app()
    {
        return $this->belongsTo(App::class);
    }

    /**
     * Each page has many components.
     *
     * @return \Illuminate\Database\Eloquent\Relationship\HasMany
     */
    public function components()
    {
        return $this->hasMany(Component::class);
    }

    /**
     * Each page belongs to a menu.
     *
     * @return \Illuminate\Database\Eloquent\Relationship\BelongsTo
     */
    public function menu()
    {
        return $this->belongsTo(Menu::class);
    }

    /**
     * Each page belongs to a submenu.
     *
     * @return \Illuminate\Database\Eloquent\Relationship\BelongsTo
     */
    public function submenu()
    {
        return $this->belongsTo(Submenu::class);
    }
}

标签: phplaravel

解决方案


那么事实上你确实犯了一个错误。通过遍历菜单循环内的每一页。因此,在第一次运行中,每个页面都会与第一个菜单条目相关联。在第二次运行时,每个页面都有第二个菜单项,依此类推。最终导致这样一个事实,即每个页面都与最后一个菜单条目相关联。

为了保持结构像你有一个可以做这样的事情:

        $tester = new \App\User();
    $tester->name = "Tester";
    $tester->email = "test@appbuilder.com";
    $tester->password = bcrypt('password');
    $tester->save();


    // Create 5 apps for each user
    $tester->apps()->saveMany(factory(\App\App::class, 5)->make())->each(function ($app) {
        $menus = factory(\App\Menu::class, 5)->make();
        $pages = factory(\App\Page::class, 5)->make();

        $pagesIterator = $pages->getIterator();

        // Create 5 menus for each app and 5 submenus for each menu
        $app->menus()->saveMany($menus)->each(function ($menu) use ($pagesIterator) {

            $page = current($pagesIterator);
            $page->menu()->associate($menu);

            // Create 5 submenus for each menu
            $menu->submenus()->saveMany(factory(\App\Submenu::class, 5)->make())->each(function ($submenu) use ($page) {
                // Associate page with each submenu
                $page->submenu()->associate($submenu);
            });

            next($pagesIterator);
        });

        // Create 5 pages for each app and 5 components for each page
        $app->pages()->saveMany($pages)->each(function ($page) {
            $page->components()->saveMany(factory(\App\Component::class, 5)->make());
        });

    });

因此,我们只需通过迭代器从循环内的集合中获取下一页,并将每个菜单与集合中的下一页相关联。(请注意,如果您希望每个子菜单关联不同的页面,则需要创建更多页面......)

题外话:

$page->menu()->associate($menu);

通常需要一个$page->save()后跟,因为 associate() 方法不会自动保存。在您的情况下, $pages 通过在最后调用来持久化到数据库$app->pages()->saveMany($pages)中。


推荐阅读