I am totally new on Laravel, and I have implement the User table provided by Laravel Auth, and also I have create a table for the user meta data that is a Key Value pare table.
The user meta table is created by the following code :
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class UserMeta extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('user_meta', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->char('meta_key', 255);
$table->longText('meta_value')->nullable();
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users')->onUpdate('cascade')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::drop('user_meta');
}
}
In my User model I have the following method:
public function meta() {
return $this->hasMany('App\Models\UserMeta');
}
and inside my UserMeta model I have the following method:
public function user() {
return $this->belongsTo('App\User');
}
Until now anything is fine. So, when I register a new user I perform the following actions:
$user = User::create(
[
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt( $data['password'] ),
]
);
if ( $user ) {
$telephone_number = new UserMeta;
$telephone_number->user()->associate($user);
$telephone_number->meta_key = 'telephone_number';
$telephone_number->meta_value = $data['telephone_number'];
$telephone_number->save();
$company = new UserMeta;
$company->user()->associate($user);
$company->meta_key = 'company';
$company->meta_value = $data['company'];
$company->save();
$web_site = new UserMeta;
$web_site->user()->associate($user);
$web_site->meta_key = 'web_site';
$web_site->meta_value = $data['web_site'];
$web_site->save();
}
return $user;
I suppose that should be a better way to perform that same actions, but I don't know what is the other way :( :)
So, the above code works very nice for me, but now the problem is with the value update. In this case, how can I update the Meta Data when I update the user profile ?
In my update method of my UserControler, I perform the following actions:
$user = User::where( 'id', '=', $id )->first();
$user->name = $request->input( 'name' );
$user->email = $request->input( 'email' );
$user->password = bcrypt( $request->input( 'password' ) );
$user->save();
My $request->input(); has the following extra fields that corresponding to meta values telephone_number, web_site, company.
So, how can I update the meta values in the user_meta table ?
Looping through values
Firstly, you are right that you could loop through the three keys in your create method to:
// Loop through all the meta keys we're looking for
foreach(['telephone_number', 'web_site', 'company'] as $metaKey) {
$meta = new UserMeta;
$meta->meta_key = $metaKey;
$meta->meta_value = array_get($data, $metaKey);
$meta->save();
}
The Update Method: Approach One
Then, in your update method
// Loop through all the meta keys we're looking for
foreach(['telephone_number', 'web_site', 'company'] as $metaKey) {
// Query for the meta model for the user and key
$meta = $user->meta()->where('meta_key', $metaKey)->firstOrFail();
$meta->meta_value = array_get($data, $metaKey);
$meta->save();
}
Note the firstOrFail() to end the query. This is just me being strict. If you wanted to add a meta value if it didn't exist, then you could replace that line with
// Query for the meta model for the user and key, or
// create a new one with that key
$meta = $user->meta()->where('meta_key', $metaKey)
->first() ?: new UserMeta(['meta_key' => $metaKey]);
The Update Method: Approach Two
This approach is a little more efficient, but a more complex (but also potentially teaches about a cool feature of Eloquent!).
You could load in all of the meta keys first (see lazy eager loading).
// load the meta relationship
$user->load('meta');
// Loop through all the meta keys we're looking for
foreach(['telephone_number', 'web_site', 'company'] as $metaKey) {
// Get the first item with a matching key from the loaded relationship
// Or, create a new meta for this key
$meta = $user->meta
->first(function($item) use ($metaKey) {
return $item->meta_key === $metaKey;
}) ?: new UserMeta(['meta_key' => $metaKey]);
$meta->meta_value = array_get($data, $metaKey);
$meta->save();
}
Related
I'm trying to override Voyager view "edit-add view" by adding one new input with the same controller.
But when I try to add new data I face this error.
"SQLSTATE[HY000]: General error: 1364 Field 'Category_id' doesn't have
a default value (SQL: insert into `users` (`name`, `email`,
`password`, `role_id`, `updated_at`, `created_at`) values (ali12345,
ali12345#ali12345.com,
$2y$10$qrHhwTFhnjluM7heNE.WCOwSbFIVsag4GWJzunZQGSLgdcXD2r21a, 3,
2019-04-25 22:45:45, 2019-04-25 22:45:45))"
I had tried to add fillable in the model but I didn't have a solution.
protected $fillable = [
'id',
'role_id',
'name',
'email',
'avatar',
'password',
'remember_token',
'settings',
'created_at',
'updated_at',
'Category_id'
];
First of all, the issue is because you don't set the default value for Category_id in your table.
If you are sure that your request has the Category_id field, please ensure that you pass all the required fields when inserting a new record.
Let me give you some example of doing it with your case (Blocks of codes below should be somewhere in your Controller). Also I'll give you my favorite way to insert a new record.
Using Input facades:
public function create(Request $request)
{
$user = new User;
$user->username = Input::get('role_id');
$user->name = Input::get('name');
$user->email = Input::get('email');
$user->password = Hash::make(Input::get('password'));
$user->Category_id = Input::get('Category_id');
$user->save();
return Redirect::back();
}
This one is my favorite way to do it:
public function create(Request $request)
{
$user = new User;
$data = $this->cleanUnfillableFields($request->all(), $user->getFillable());
$user->create($data);
return Redirect::back();
}
/**
* This removes/unsets fields that are not fillable from the model.
* This is the magic method where you should put in a separate class or a trait,
* so all controllers can share this method.
*
* #param array $data
* #param array $fillableFields
*
* #return array
*/
protected function cleanUnfillableFields(array $data, array $fillableFields): array
{
foreach ($data as $key => $value) {
if (! in_array($key, $fillableFields))
unset($data[$key]);
}
return $data;
}
With my way above, you won't need to be hassle filling out each model's attribute and filtering out unnecessary fields anymore, as long as you set the fillable fields correctly and you have the required fields in your request.
So I'm beginning to struggle with Doctrine2 when it comes to a many-to-many relation for a project where the relation has 1 extra column.
I have the following tables:
Profiles
id
extra data
Skills
id
name
profile_has_skills
profile_id
skill_id
level
Now I added the level column later on, and noticed some problems happening, of course I am missing level now whenever I try to create the relation.
My question is, with the code below, how would I go over to add this in my doctrine?
My controller:
public function store(Request $request)
{
$time = new DateTime();
$this->validate($request, [
'name' => 'required',
'lastname' => 'required',
'gender' => 'required',
'profile_skills' => 'required'
]);
$this->em->getConnection()->beginTransaction();
try {
$profile = new Profile(
$request->input('company_id'),
$request->input('name'),
$request->input('lastname'),
$request->input('gender'),
new DateTime(),
$time,
$time
);
$company = $this->em->getRepository(Company::class)->find($request->input('company_id'));
$profile->addCompany($company);
foreach($request->input('profile_skills') as $skill => $level) {
$skill = $this->em->getRepository(Skill::class)->find($skill);
$skill->level = $level;
$profile->addSkill($skill);
}
$this->em->persist($profile);
$this->em->flush();
$this->em->getConnection()->commit();
} catch (OptimisticLockException $e) {
$this->em->getConnection()->rollBack();
throw $e;
}
return redirect(route('profiles.index'));
}
My ProfileHasSkill entity looks as follow:
/**
* #ORM\Entity
* #ORM\Table(name="profile_has_skill")
*
*/
class ProfileHasSkill
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
protected $id;
/**
* #Column(type="integer", name="profile_id")
*/
protected $profile_id;
/**
* #Column(type="integer", name="skill_id")
*/
protected $skill_id;
/**
* #Column(type="integer", name="level")
*/
protected $level;
/**
* #param $profile_id
* #param $skill_id
* #param $level
*/
public function __construct($profile_id, $skill_id, $level = 0)
{
$this->profile_id = $profile_id;
$this->skill_id = $skill_id;
$this->level = $level;
}
And my addSkill method inside the profile entity is as follow:
public function addSkill(Skill $skill)
{
if ($this->skills->contains($skill)) {
return;
}
return $this->skills->add($skill);
}
But anytime I try to run this it gives me the following error
An exception occurred while executing
'INSERT INTO profile_has_skill (profile_id, skill_id) VALUES (?, ?)'
with params [3, 2]: SQLSTATE[HY000]: General error: 1364 Field 'level'
doesn't have a default value
Now I know one way to get rid of this error is setting a default value in the database, but I much rather just find out why it's not picking up my skill level that I'm also passing?
As per my solution which has worked, by reading another question passed by #Nicola Havric - Read as follow That doctrine does not support extra columns in a many-to-many relation. Thus you should use the relation as it's own entity. My own solution was to change the way I wanted it to run with flushing.
In my controller I changed my code as follow:
try {
$profile = new Profile(
$request->input('company_id'),
$request->input('name'),
$request->input('lastname'),
$request->input('gender'),
new DateTime(),
$time,
$time
);
$company = $this->em->getRepository(Company::class)->find($request->input('company_id'));
$profile->addCompany($company);
//Flush the user, so I can grab it's profile ID
$this->em->persist($profile);
$this->em->flush();
foreach($request->input('profile_skills') as $skill => $level) {
$skill = $this->em->getRepository(Skill::class)->find($skill);
$skill->level = $level;
$profile->addSkill($skill);
}
$this->em->getConnection()->commit();
Inside my Profile Entity function:
public function addSkill(Skill $skill)
{
//I left this check since it only checks if the relation is set already. If so, it will skip it.
if ($this->skills->contains($skill)) {
return;
}
//Since this function gets called inside a loop, I can call the entity to add a new "relation" to the table.
(new ProfileHasSkill($this->getId(), $skill, $skill->level))->addSkill($this->getId(), $skill, $skill->level);
return true;
}
Inside my ProfileHasSkill entity:
public function addSkill($profileId, $skill)
{
//Creating a new ProfileHasSkill inside the table.
$profileSkill = new ProfileHasSkill(
$profileId,
$skill->getId(),
$skill->level
);
/*Since I do a roll-back inside my controller in case something goes wrong.
I decided to add the flush here.
As far no additional checks where needed in my case
since I require a Profile instance and a Skill instance inside the Profile entity.*/
EntityManager::persist($profileSkill);
EntityManager::flush();
}
The thing with many-to-many relationships is that any additional columns other than two primary keys from both tables are considered pivot columns, when attaching entities to such relationships you want to use the method attach which accepts array of ids as first parameter and an array with pivot columns, take the following into consideration.
public function addSkill(Skill $skill)
{
if ($this->skills->contains($skill)) {
return;
}
//Dunno what this method does
return $this->skills->add($skill);
//But this is the correct way of adding a skill
$this->skills->attach($skill->id, ['level' => $skill->level]);
}
Hope this can clarify few things even though Eloquent was used as an example; here is the manual link for the above code.
I'm working on laravel e-commerce project where I need to add Attributes to my posts (image below as example)
My question is how to achieve that? should i create new tables or can I add manually from post.create like any other e-commerce cms?
Personally I prefer to be able to add fields in post.create like I
add + button and each time I click on it 2 input fields add and I
can put key and value in it. (if you can help me with that)
Thanks.
Update:
With suggest of #anas-red I've created this structure now:
attributes table.
Schema::create('attributes', function (Blueprint $table) {
$table->increments('id');
$table->string('title')->unique();
$table->timestamps();
});
and product_attributes table
Schema::create('product_attributes', function (Blueprint $table) {
$table->increments('id');
$table->integer('product_id')->unsigned();
$table->foreign('product_id')->references('id')->on('products');
$table->integer('attribute_id')->unsigned();
$table->foreign('attribute_id')->references('id')->on('attributes');
$table->string('attribute_value')->nullable();
$table->timestamps();
});
now i have this store method on my controller when i save my posts:
public function store(Request $request)
{
//Validating title and body field
$this->validate($request, array(
'title'=>'required|max:225',
'slug' =>'required|max:255',
'user_id' =>'required|numeric',
'image_one' =>'nullable|image',
'image_two' =>'nullable|image',
'image_three' =>'nullable|image',
'image_four' =>'nullable|image',
'image_one' =>'nullable|image',
'short_description' => 'nullable|max:1000',
'description' => 'nullable|max:100000',
'subcategory_id' => 'required|numeric',
'discount' => 'nullable|numeric',
'discount_date' => 'nullable|date',
'price' => 'required|numeric',
));
$product = new Product;
$product->title = $request->input('title');
$product->slug = $request->input('slug');
$product->user_id = $request->input('user_id');
$product->description = $request->input('description');
$product->short_description = $request->input('short_description');
$product->subcategory_id = $request->input('subcategory_id');
$product->discount = $request->input('discount');
$product->discount_date = $request->input('discount_date');
$product->price = $request->input('price');
if ($request->hasFile('image')) {
$image = $request->file('image');
$filename = 'product' . '-' . time() . '.' . $image->getClientOriginalExtension();
$location = public_path('images/');
$request->file('image')->move($location, $filename);
$product->image = $filename;
}
$product->save();
$product->attributes()->sync($request->attributes, false);
//Display a successful message upon save
Session::flash('flash_message', 'Product, '. $product->title.' created');
return redirect()->route('admin.products.index');
}
The process i want to do is this:
Store my attributes
Select my attributes while creating new post
Give value to selected attribute
save post_id arribute_id and atteribute_value in product_attributes table.
here is the error i get:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'attributes_id'
in 'field list' (SQL: select attributes_id from product_attributes
where product_id = 29)
UPDATE:
Product model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use jpmurray\LaravelCountdown\Traits\CalculateTimeDiff;
class Product extends Model
{
use CalculateTimeDiff;
protected $table = 'products';
protected $fillable = [
'title', 'slug', 'image_one', 'image_two', 'image_three', 'image_four', 'short_description', 'description', 'price', 'discount', 'discount_date',
];
public function category(){
return $this->belongsTo(Category::class);
}
public function subcategory(){
return $this->belongsTo(Subcategory::class);
}
public function attributes()
{
return $this->belongsToMany(Attribute::class, 'product_attributes', 'product_id', 'attribute_id');
}
public function order(){
return $this->hasMany(Order::class);
}
public function discounts(){
return $this->hasMany(Discount::class, 'product_id', 'id');
}
}
Attribute model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Attribute extends Model
{
protected $fillable = [
'title',
];
public function products(){
return $this->belongsToMany(Product::class);
}
}
I think you can add new table lets say "post_attributes" with the following columns:
id - post_id - key - value
in the PostAttribute model add this:
public function post
{
return $this->belongsTo(Post::class);
}
in the Post model add the following:
public function attributes
{
return $this->hasMany(PostAttributes::class, 'post_attributes');
}
Now the app is flexible enough to handle multiple attributes to one post or a single attribute to another.
Other approach is to implement JSON in your database. Hope that helped you.
update Product model
public function attributes()
{
return $this->belongsToMany(Attribute::class, 'product_attributes', 'product_id', 'attribute_id')->withPivot('attribute_value')->withTimestamps();
}
and update Attribute model to
public function products()
{
return $this->belongsToMany(Product::class, 'product_attributes', 'attribute_id', 'product_id')->withPivot('attribute_value')->withTimestamps();
}
If I see your Product and Attribute Models I will be in a better position to answer you properly.
But any way, I think your problem is with the product_attributes table.
This table is now acting as a pivot (intermediate) table and it is not following Laravel naming convention. The convention is to name it as follows: attribute_product.
Next, you have to add the following into both models i.e. Product and Attribute.
in Attribute Model add:
$this->belongsToMany(Product::class)->withPivot('value');
in Product Model add:
$this->belongsToMany(Attribute::class)->withPivot('value');
To add value to more_value column on pivot table. Use the following:
$product->attributes()->attach($attributeId, ['more_value' => $string]);
or use sync:
$product->attributes()->sync([$attributeId => ['more_value' => $string]]);
lol. the important part is repo code is:
<input type="hidden" id="appOrderItems" name="orderItems[]">
trace appOrderItems in my JS section and you will get it.
in simple words:
when the user adds attributes to a product (in my case, items to an order) then, the appOrderItems array will get the id of the attribute and any additional value that you need to add into the pivot table (other than the product_id and attribute_id. in your case the mores_value). After gathering these attributes into appOrderItems JS array I push its value to the hidden HTML field (name="orderItems[]"). in this case it will be sent to the controller for further process.
I have user input following the rules below;
public function rules()
{
return [
'phone_number' => 'required|array',
'amount' => 'required|string|max:4',
'phone_number_debit' => 'required|string|max:15',
];
}
I would want to save the data in a model Transaction. For the phone_number it is an array that could have one value or multiple. So that leaves for foreach loop.
This is what I want to achieve, save different rows determined by the number of records in the array.
$transaction = new Trasaction();
$transaction->phone_number = $req->phone_number; //Value in the array
$transaction->amount = $req->amount;
$transaction->phone_number_debit = $req->phone_number_debit;
$transaction->save();
Save diffrent records according to the records in the phone_number array.
However I can not think of a way to achieve this.
Anyone?
try this :
$data = request(['amount', 'phone_number', 'phone_number_debit']);
foreach($data['phone_number'] as $phone_number) {
Trasaction::create([
'amount' => $data['amout'],
'phone_number' => $phone_number,
'phone_number_debit' => $data['phone_number_debit']
]);
}
make sure in your Trasaction modal you've set to fillable property like this :
class Trasaction extends Model
{
protected $fillable = ['amount', 'phone_number', 'phone_number_debit'];
}
There are many ways to do this, in a nutshell:
collect(request('phone_number'))->each(function ($phone) use ($req) {
$transaction = new Trasaction();
$transaction->phone_number = $phone; // element of the array
$transaction->amount = $req->amount;
$transaction->phone_number_debit = $req->phone_number_debit;
$transaction->save();
});
TL;DR
One-to-Many Relationship
In order to get a better code, you can create a transaction_phones table, creating a one-to-many relationship.
You'll create a TransactionPhone model and add this:
public function transaction()
{
return $this->belongsTo(Transaction::class);
}
The TransactionPhone migration:
Schema::create('transaction_phones', function (Blueprint $table) {
$table->increments('id');
$table->integer('transaction_id');
$table->string('phone_number');
$table->timestamps();
});
In your Transaction model you'll have the inverse:
public function phones()
{
return $this->hasMany(TransactionPhone::class);
}
public function addPhone($phone)
{
return $this->phones()->create(['phone_number' => $phone]);
}
And in you Controller:
$transaction = Trasaction::create(request()->only('amount', 'phone_number_debit'));
collect(request('phone_number'))->each(function ($phone) use ($transaction) {
$transaction->addPhone($phone);
});
I hope this answer can help you.
In Laravel, database seeding is generally accomplished through Model factories. So you define a blueprint for your Model using Faker data, and say how many instances you need:
$factory->define(App\User::class, function (Faker\Generator $faker) {
return [
'name' => $faker->name,
'email' => $faker->email,
'password' => bcrypt(str_random(10)),
'remember_token' => str_random(10),
];
});
$user = factory(App\User::class, 50)->create();
However, lets say your User model has a hasMany relationship with many other Models, like a Post model for example:
Post:
id
name
body
user_id
So in this situation, you want to seed your Posts table with actual users that were seeded in your Users table. This doesn't seem to be explicitly discussed, but I did find the following in the Laravel docs:
$users = factory(App\User::class, 3)
->create()
->each(function($u) {
$u->posts()->save(factory(App\Post::class)->make());
});
So in your User factory, you create X number of Posts for each User you create. However, in a large application where maybe 50 - 75 Models share relationships with the User Model, your User Seeder would essentially end up seeding the entire database with all it's relationships.
My question is: Is this the best way to handle this? The only other thing I can think of is to Seed the Users first (without seeding any relations), and then pull random Users from the DB as needed while you are seeding other Models. However, in cases where they need to be unique, you'd have to keep track of which Users had been used. Also, it seems this would add a lot of extra query-bulk to the seeding process.
You can use saveMany as well. For example:
factory(User::class, 10)->create()->each(function ($user) {
$user->posts()->saveMany(factory(Posts::class, 5)->make());
});
You can do this using closures within the ModelFactory as discussed here.
This solution works cleanly and elegantly with seeders as well.
$factory->define(App\User::class, function (Faker\Generator $faker) {
return [
'name' => $faker->name,
'email' => $faker->email,
'password' => bcrypt(str_random(10)),
'remember_token' => str_random(10),
];
});
$factory->define(App\Post::class, function (Faker\Generator $faker) {
return [
'name' => $faker->name,
'body' => $faker->paragraph(1),
'user_id' => function() {
return factory(App\User::class)->create()->id;
},
];
});
For your seeder, use something simple like this:
//create 10 users
factory(User::class, 10)->create()->each(function ($user) {
//create 5 posts for each user
factory(Post::class, 5)->create(['user_id'=>$user->id]);
});
NOTE: This method does not create unneeded entries in the database, instead the passed attributes are assigned BEFORE the creation of associated records.
Personally I think one Seeder class to manage these relations is nicer then separated seeder classes, because you have all the logic in one place, so in one look you can see what is going on. (Anyone that knows a better approach: please share) :)
A solution might be: one DatabaseSeeder and private methods within the class to keep the 'run' method a bit cleaner. I have this example below, which has a User, Link, LinkUser (many-to-many) and a Note (many-to-one).
For the many-to-many relations I first create all the Links, and get the inserted ids. (since the ids are auto-inc I think the ids could be fetched easier (get max), but doesn't matter in this example). Then create the users, and attach some random links to each user (many-to-many). It also creates random notes for each user (many-to-one example). It uses the 'factory' methods.
If you replace the 'Link' for your 'Post' this should work. (You can remove the 'Note' section then...)
(There is also a method to make sure you have 1 valid user with your own login credentials.)
<?php
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
// Create random links
factory(App\Link::class, 100)->create();
// Fetch the link ids
$link_ids = App\Link::all('id')->pluck('id')->toArray();
// Create random users
factory(App\User::class, 50)->create()->each(function ($user) use ($link_ids) {
// Example: Many-to-many relations
$this->attachRandomLinksToUser($user->id, $link_ids);
// Example: Many-to-one relations
$this->createNotesForUserId( $user->id );
});
// Make sure you have a user to login with (your own email, name and password)
$this->updateCredentialsForTestLogin('john#doe.com', 'John Doe', 'my-password');
}
/**
* #param $user_id
* #param $link_ids
* #return void
*/
private function attachRandomLinksToUser($user_id, $link_ids)
{
$amount = random_int( 0, count($link_ids) ); // The amount of links for this user
echo "Attach " . $amount . " link(s) to user " . $user_id . "\n";
if($amount > 0) {
$keys = (array)array_rand($link_ids, $amount); // Random links
foreach($keys as $key) {
DB::table('link_user')->insert([
'link_id' => $link_ids[$key],
'user_id' => $user_id,
]);
}
}
}
/**
* #param $user_id
* #return void
*/
private function createNotesForUserId($user_id)
{
$amount = random_int(10, 50);
factory(App\Note::class, $amount)->create([
'user_id' => $user_id
]);
}
/**
* #param $email
* #param $name
* #param $password
* #return void
*/
private function updateCredentialsForTestLogin($email, $name, $password)
{
$user = App\User::where('email', $email)->first();
if(!$user) {
$user = App\User::find(1);
}
$user->name = $name;
$user->email = $email;
$user->password = bcrypt($password); // Or whatever you use for password encryption
$user->save();
}
}
$factory->define(App\User::class, function (Faker\Generator $faker) {
return [
'name' => $faker->name,
'email' => $faker->email,
'password' => bcrypt(str_random(10)),
'remember_token' => str_random(10),
];
});
$factory->define(App\Post::class, function (Faker\Generator $faker) {
return [
'name' => $faker->name,
'body' => $faker->paragraph(1),
'user_id' => factory(App\User::class)->create()->id,
];
});
So now if you do this factory(App\Post::class, 4)->create() it will create 4 different posts and in the process also create 4 different users.
If you want the same user for all the posts what I usually do is:
$user = factory(App\User::class)->create();
$posts = factory(App\Posts::class, 40)->create(['user_id' => $user->id]);
I want to share the approach i've taken for insert many posts to many users:`
factory(App\User::class, 50)->create()
->each(
function ($u) {
factory(App\Post::class, 10)->create()
->each(
function($p) use (&$u) {
$u->posts()->save($p)->make();
}
);
}
);
`
This workaround worked for me after being all day long looking for a way to seed the relationship
this worked for me in laravel v8
for ($i=0; $i<=2; $i++) {
$user = \App\Models\User::factory(1)->create()->first();
$product = \App\Models\Product::factory(1)->create(['user_id' => $user->id])->first();
}
I use a custom made relateOrCreate function that finds a random entry of that model in the database. If none exist, it creates a new one:
function relateOrCreate($class) {
$instances = $class::all();
$instance;
if (count($instances) > 0) {
$randomIndex = rand(0, (count($instances) - 1));
$instance = $instances[$randomIndex];
}
else {
$instance = $class::factory()->create();
}
return $instance;
}
Then I use it like so:
$relatedUser = relateOrCreate(User::class);
return [
'user_id' => $relatedUser->id,
// ...
];