拉拉威尔工厂协会只关联最后的数据.如何解决此问题



创建数据后,我有两个模型需要关联。我已经在这里问过了,得到了答案。我实现了它并做了一些修改,因为它没有正确地关联数据。现在我对这个协会有意见。它只与最后一个数据关联。

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

当我执行php artisan tinker并运行AppApp::first()->load('menus', 'menus.page')命令时,它不会给我正确的数据。请看一下这里的结果。

正如您所看到的,正确的数据只显示在最后一个对象上。其余为null。我该怎么解决这个问题?请看下面我的种子文件,我犯了什么错误吗?

<?php
use AppApp;
use AppComponent;
use AppMenu;
use AppPage;
use AppRole;
use AppSubmenu;
use AppUser;
use IlluminateDatabaseSeeder;
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 IlluminateDatabaseEloquentModel;
class App extends Model
{
/**
* The attributes that should not be mass assignable.
*
* @var array
*/
protected $guarded = ['id'];
/**
* Each app belongs to a user.
*
* @return IlluminateDatabaseEloquentRelationshipBelongsTo
*/
public function user()
{
return $this->belongsTo(User::class);
}
/**
* Each app has many pages.
*
* @return IlluminateDatabaseEloquentRelationshipHasMany
*/
public function pages()
{
return $this->hasMany(Page::class);
}
/**
* Each app has many menus.
*
* @return IlluminateDatabaseEloquentRelationshipHasMany
*/
public function menus()
{
return $this->hasMany(Menu::class);
}
}

Menu.php

<?php
namespace App;
use IlluminateDatabaseEloquentModel;
class Menu extends Model
{
/**
* The attributes that should not be mass assignable.
*
* @var array
*/
protected $guarded = ['id'];
/**
* Each menu belongs to a app.
*
* @return IlluminateDatabaseEloquentRelationshipBelongsTo
*/
public function app()
{
return $this->belongsTo(App::class);
}
/**
* Each menu has one page.
* 
* @return IlluminateDatabaseEloquentRelationshipHasOne
*/
public function page()
{
return $this->hasOne(Page::class);
}
/**
* Each menu has many submenus.
*
* @return IlluminateDatabaseEloquentRelationshipHasMany
*/
public function submenus()
{
return $this->hasMany(Submenu::class);
}
/**
* Each menu belongs to many roles.
*
* @return IlluminateDatabaseEloquentRelationshipBelongsToMany
*/
public function roles()
{
return $this->belongsToMany(Role::class);
}
}

Page.php

<?php
namespace App;
use IlluminateDatabaseEloquentModel;
class Page extends Model
{
/**
* The attributes that should not be mass assignable.
*
* @var array
*/
protected $guarded = ['id'];
/**
* Each page belongs to an app.
*
* @return IlluminateDatabaseEloquentRelationshipBelongsTo
*/
public function app()
{
return $this->belongsTo(App::class);
}
/**
* Each page has many components.
*
* @return IlluminateDatabaseEloquentRelationshipHasMany
*/
public function components()
{
return $this->hasMany(Component::class);
}
/**
* Each page belongs to a menu.
*
* @return IlluminateDatabaseEloquentRelationshipBelongsTo
*/
public function menu()
{
return $this->belongsTo(Menu::class);
}
/**
* Each page belongs to a submenu.
*
* @return IlluminateDatabaseEloquentRelationshipBelongsTo
*/
public function submenu()
{
return $this->belongsTo(Submenu::class);
}
}

事实上你确实犯了一个错误。通过循环浏览菜单循环中的每一页。因此,在第一次运行中,每个页面都将与第一个菜单项相关联。在第二个菜单项中运行每个页面,依此类推。随着finally的出现,每个页面都与最后一个菜单项相关联。

为了保持现有的结构,可以这样做:

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

// Create 5 apps for each user
$tester->apps()->saveMany(factory(AppApp::class, 5)->make())->each(function ($app) {
$menus = factory(AppMenu::class, 5)->make();
$pages = factory(AppPage::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(AppSubmenu::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(AppComponent::class, 5)->make());
});
});

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

离题:

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

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

您愿意共享模型的源代码吗?我认为这会很有帮助,因为我不太确定$tester->apps()返回的是什么关系,是belongsToMany还是hasMany等等…

并在IlluminateDatabaseEloquentRelationsBelongsToMany:中读取saveMany's源代码

/**
* Save an array of new models and attach them to the parent model.
*
* @param  IlluminateSupportCollection|array  $models
* @param  array  $pivotAttributes
* @return array
*/
public function saveMany($models, array $pivotAttributes = [])
{
foreach ($models as $key => $model) {
$this->save($model, (array) ($pivotAttributes[$key] ?? []), false);
}
$this->touchIfTouching();
return $models;
}

不确定你得到的是array还是collection,所以这可能是一个没有执行的循环的情况,不妨在saveMany's上做一个foreach loop返回值,即:

$savedModels = $tester->apps()->saveMany(factory(App::class, 5)->make());
// You can be sure that $model is an instance of `Model`
foreach($saveModels as $model){
// Do the logic here instead
}

无论如何,我无法用我目前掌握的信息更深入地挖掘。

最新更新