Parameter mismatch for seeding the users table on Laravel - php

I'm trying to seed the users table on Laravel 5.2. I've a custom column called role. I'm using Faker to seed the users table. However, I need to populate the role column either with Administrator or Customer. So, I've passed an array and that returned Parameter mismatch error.
Here's the relevant code I'm trying with:
$factory->define(App\User::class, function (Faker\Generator $faker) {
return [
'name' => $faker->name,
'email' => $faker->email,
'password' => 123456,
'role' => ['Administrator', 'Customer'],
'remember_token' => str_random(10),
];
})
I know that it only accept string instead of an array. So, how do you do that when you want to seed the database with multiple particular data.

You can use Faker to get a random element:
$factory->define(App\User::class, function (Faker\Generator $faker) {
return [
'name' => $faker->name,
'email' => $faker->email,
'password' => 123456,
'role' => $faker->randomElement(['Administrator', 'Customer']),
// ^^^^^^^ here ^^^^^^^
'remember_token' => str_random(10),
];
})

I suggest using random index generation (in your case 0 or 1) and retrieving value from the array of possible values (['Administrator', 'Customer']) by this index.
$i = rand(0, 1);
$roleOptions = ['Administrator', 'Customer'];
$role = $roleOptions[$i];
Also if you would like to have much more users than administrators, you can look for something like this: changing probability of getting a random number

Related

Laravel Jetstream - How to join a default team at registration

I am trying to change Laravel Jetstream's logic in order to join a default team at registration rather than create a personal team. I found the method that does this:
public function create(array $input)
{
Validator::make($input, [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'password' => $this->passwordRules(),
'terms' => Jetstream::hasTermsAndPrivacyPolicyFeature() ? ['required', 'accepted'] : '',
])->validate();
return DB::transaction(function () use ($input) {
return tap(User::create([
'name' => $input['name'],
'email' => $input['email'],
'password' => Hash::make($input['password']),
]), function (User $user) {
$user->currentTeam = Team::find(1); # SQLSTATE[42S22]: Column not found: 1054 Unknown column 'currentTeam' in 'field list'
$user->save();
});
});
}
The issue here is that currentTeam seems to be an created after the database level and not a column in the Database itself. The documentation says that currentTeam returns the Team model but doesn't say how to update the current users team programmatically.
I can see I can manually use a DB query to insert a row into the team_user table but there must be a method to do this.
return DB::transaction(function () use ($input) {
return tap(User::create([
'name' => $input['name'],
'email' => $input['email'],
'password' => Hash::make($input['password']),
]), function (User $user) {
DB::table('team_user')->insert(['user_id' => $user->id, 'team_id' => 1, 'role' => 'rfn']);
$user->current_team_id = 1;
});
});
Any help would be appreciated, I understand this will be reliant on this team always existing in the Database but further measures will be implemented so it cannot be removed.
After some tinkering with a local Laravel version, this is was I came up with. This assumes the team you wanna add the user to is already created somehow, possibly through a seeder, or created manually. The file you need to edit is app/Actions/Fortify/CreateNewUser.php, namely the createTeam method.
Instead of creating a new team, we want to grab a team from the database, attach it to the newly registered user and then make that now attached team the users current team.
protected function createTeam(User $user)
{
$team = Team::first();
$user->teams()->attach($team);
$user->switchTeam($team);
}
The reason we first need to attach the team first is that switchTeam checks if a user belongs to that team if it doesn't it returns false and doesn't switch to the new team. By attaching the team first we make the user belong to that team before we can actually switch to it as the current team.
you can assign role as well in above answer of #KimHallberg as below
$team = Team::first();
$user->teams()->attach($team, array('role' => 'editor'));
$user->switchTeam($team);

Passing a factory into another in Laravel 5

I am trying to generate a test on Laravel.
What I was trying is to create a fictitious position name, then add 10 people for this position.
PositionsFactory.php
$factory->define(App\Position::class, function (Faker $faker) {
return [
'p_id' => $faker->unique()->randomNumber($nbDigits = 8),
'name' => $faker->word,
'org' => $faker->word,
'user_id' => 1
];
});
Here is my EmployeeFactory.php
$factory->define(App\Employee::class, function (Faker $faker) {
return [
'FirstName' => $faker->name,
'LastName' => $faker->lastName,
'pid' => $position->p_id,
'org'=> $position->org,
'user_id' => 1,
];
});
Well here is one my my trials but it did not work
for ($i=0; $i < 5; $i++ ){
$position = factory('App\Position')->create();
factory('App\Employee',10)->create(
'pid' => $position->pid,
'org' => $position->org
);
}
I am trying to loop for 5 times and for each loop I want to create 10 employees with the same position Id. But obviously I am missing something.
I tried adding $position in the Employee factory, which works great.
$factory->define(App\Employee::class, function (Faker $faker) {
$position = factory('App\Position')->create();
return [
'FirstName' => $faker->name,
'LastName' => $faker->lastName,
'pid' => $position->p_id,
'org'=> $position->org,
'user_id' => 1,
];
});
Is there a way to make something like,
$factory('App\Position',5)->create($factory('App\Employee',10));
Maybe I am missing something with call back but kinda lost. Any help would be appreciated. Thank you!
I think you might be looking for the each method which can be called after create:
// Generate 5 positions and execute a callback
// function for each position created
factory(App\Position::class, 5)->create()->each(function ($position) {
// In the callback, generate 10 employees
// and manually override the foreign key
factory(App\Employee::class, 10)->create([
'pid' => $position->id
]);
});
Further information on each and handling relationships: https://laravel.com/docs/5.6/database-testing#relationships.
Hope it helps!
You can create them separatly and loop through collections.
$positions = factory('App\Position', 3)->make();
foreach ($positions as $position){
$employes = factory('App\Employee', 3)->make();
foreach ($employes as $employee){
$employee->p_id = $position->id;
//etc.. watever you want to connect
}
}
now you have 1 collection of positions and 1 collection of employes devided of the positions
note that the make method does not save to database you need to manually save them
you could also change your factory as is stated in the documentation https://laravel.com/docs/5.6/database-testing#using-factories
yours would look like:
$factory->define(App\Employee::class, function (Faker $faker) {
return [
'FirstName' => $faker->name,
'LastName' => $faker->lastName,
'org'=> $position->org,
'user_id' => 1,
'pid' => function () {
return factory('App\Position')->create()->id;
}
];
});
This will create a position for each user the factory creates.
You could also use existing eloquent models instead if you have existing positions.

Laravel generate object using model factory with parameter

I have this model factory that generates new contact, it uses random company_id:
$factory->define(App\Models\Contact::class, function (Faker\Generator $faker)
{
$company_id = Company::all()->random()->id;
return [
'firstname' => $faker->firstName,
'lastname' => $faker->lastName,
'phone' => $faker->phoneNumber,
'email' => $faker->email,
'company_id' => $company_id,
'lead_id' => \App\Models\Lead::where('company_id', $company_id)->get()->random()->id,
];
});
It is ok when I use it in seeds:
factory(App\Models\Contact::class)->create();
But for testing I need somehow to pass $company_id to factory, create contact for concrete company_id (I know that I can do ->create(['company_id', $company_id])) but this will rewrite only company_id from Contact.
When I select lead_id, I also need to know current company_id.
How to pass company_id to factory as parameter?
Try to use this example:
$factory->define(App\Models\Contact::class, function ($faker, $params) {
$company_id = $params['company_id'];
....
});
and this to make a new object:
$newContact = factory(App\Models\Contact::class)->make(['company_id' => $current_company_id]);
Depends on your Laravel version it will be different.
For laravel 5.1
https://github.com/laravel/framework/issues/9245
You will need to check if is passed manually
// Testcase
$company = factory(App\Models\Company::class)->create();
factory(App\Models\Contact::class)->create(['company_id' => $company->id]);
// Factory
$factory->define(App\Models\Contact::class, function (Faker\Generator $faker, $attribues) {
// Manually check if id is passed
$company_id = (isset($attribues['company_id'])) ?: Company::all()->random()->id;
return [
'firstname' => $faker->firstName,
'lastname' => $faker->lastName,
'phone' => $faker->phoneNumber,
'email' => $faker->email,
'company_id' => $company_id,
'lead_id' => \App\Models\Lead::where('company_id', $company_id)->get()->random()->id,
];
});
For Laravel 5.2 and above you can simply pass id
https://laravel.com/docs/5.5/database-testing#relationships
// Testcase
$company = factory(App\Models\Company::class)->create();
factory(App\Models\Contact::class)->create(['company_id' => $company->id]);
// Factory
$factory->define(App\Models\Contact::class, function (Faker\Generator $faker, $attribues) {
// Manually check if id is passed
$company_id = (isset($attribues['company_id'])) ?: Company::all()->random()->id;
return [
'firstname' => $faker->firstName,
'lastname' => $faker->lastName,
'phone' => $faker->phoneNumber,
'email' => $faker->email,
'company_id' => function(){
return factory(\App\Models\Company::class)->create()
},
'lead_id' => \App\Models\Lead::where('company_id', $company_id)->get()->random()->id,
];
});
So, for your case, get your random company_id first and pass it to factory. Depends on your Larval version change the ContactModel factory. Or if you have relation that you can query, you can do it as well.
// If you have a relation
$contact = factory(App\Models\Contact::class)->create();
$company_id = $contact->company->id;

Laravel addOrUpdate() on basis of related table values?

Below is something I am trying to do:
I have users table and user_profiles table and I am inserting name, email in users table and phone, address, .... etc in user_profiles table.
I have to match each value to prevent duplication of user, I have found this laravel method addOrUpdate() but it works only for one table. But I have to match user_profiles values too i.e phone,address.
Below is example code
$result = $customer->updateOrCreate([
'name' => $request->name,
'city_id' => $request->city_id,
'area_id' => $request->area_id,
'email' => $request->email
], [
'name' => $request->name,
'city_id' => $request->city_id,
'area_id' => $request->area_id,
'email' => $request->email
]);
There any way to achieve this using Laravel techniques?
Regards
First make a relationship with user and user_profiles model like-
public function userProfile()
{
return $this->hasOne('App\Model\UserProfile','user_id','id');
}
And then in your post controller as you want to match each value to prevent duplication of user-
$result = User::where('name',$request->name)->where('email',$request->email)
->whereHas('userProfile', function($q) use ($request){
$q->where('city_id'$request->city_id)->where('area_id',$request->area_id)
)->first();
if(!$result){
////your registration here
}
If you want to check if a user with exactly the same data exists, you can't use updateOrCreate(). Do this instead:
$user = User::where('name', $request->name)->where('email', $request->email)->first();
$profile = $user->profile()->where('phone', $request->phone)->where('address', $request->address)->count();
if ($user && $profile) {
// User exists.
}
I would recommend using Laravel's Validator Facade. https://laravel.com/docs/5.4/validation#manually-creating-validators
This would check to make sure the name and email fields of the users and users_profile table are unique.
$validator = Validator::make($request->all(), [
'name' => 'required|unique:users|unique:users_profile',
'email' => 'required|unique:users|unique:users_profile',
]);
You could use updateOrCreate for both of your models for sake of uniqueness i assume email should be unique so first updateOrCreate() method will check if user exists for parameter $request->email then update if not then create and return user model instance (in both update/create case)
Second updateOrCreate() on UserProfile will check if there exist any data for user_id then update else add new row, I assume user_id will be a foreign key in user profile table
$user = User::updateOrCreate([
'email' => $request->email
], [
'name' => $request->name,
'email' => $request->email
]);
UserProfile::updateOrCreate([
'user_id' => $user->id
], [
'user_id' => $user->id,
'city_id' => $request->city_id,
'area_id' => $request->area_id
]);

Laravel create multiple user tables

I have two tables - users and user_attributes.
During registration user I would like to not only enter the user in the user table but also create his attributes.
AuthController
protected function create(array $data)
{
User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
return UserAttribute::create([
'user_id' => $data['id'], // Undefined index: id
'lvl' => 0,
'exp' => 0,
'currency' => 500,
'premium_currency' => 5,
]);
}
How do I get user_id?
PS: I'm sorry for my english.
Do this
$user =new User;
$user->thing1 = 12;
$user->thing2 =32;
$user->save();
And now as soon as you have called the save method you can get the id by doing
$user->id;
Remember! It will only work after you have called the save method.
Also remember to replace my data with your data.
For further info and explanation see here: https://laravel.com/docs/5.2/eloquent#basic-inserts
Best of luck!

Categories