I'm using laravel factories to generate some fake users in my database but I don't know how to get the user id of the user that I'm currently generating.
I want to get the id of the current user so I can hash it and put it in the slug.
This is my code so far:
$factory->define(User::class, function (Faker $faker) {
$name = $faker->name;
$email = $faker->unique()->safeEmail;
$date_of_birth = $faker->date();
return [
'name' => $name,
'email' => $email,
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10),
'date_of_birth' => $date_of_birth,
'slug' => (\App\User::class)->id //This is the part that doesn't work,
];
});
Another way to approach it would be to set the slug outside of the factory.
This would mean that slug would need to be nullable though.
Migration:
$table->string('slug')->nullable();
Factory:
$factory->define(User::class, function (Faker $faker) {
$user = [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10),
];
return $user;
});
Seeder:
$users = factory(User::class, 5)->create();
foreach($users as $user) {
$user->slug = $user->id;
$user->save();
}
UPDATE:
Laravel offers Factory Callbacks (See Docs)
So, you don't need to loop through in your seeder, just chain the afterCreating() method:
$factory->define(App\User::class, function (Faker $faker) {
return [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10),
];
})->afterCreating(\App\User::class, function (\App\User $user, Faker $faker) {
$user->slug = $user->id;
$user->save();
});
If your users.id is auto increment, you can get the same ID if you use the answer of the question I gave in comment, by using static variable and increment it.
$factory->define(App\AliasCommand::class, function (Faker\Generator $faker) {
$name = $faker->name;
$email = $faker->unique()->safeEmail;
$date_of_birth = $faker->date();
static $id = 1;
return [
'name' => $name,
'email' => $email,
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10),
'date_of_birth' => $date_of_birth,
'slug' => $id++,
];
});
Not tested, but this is how I did it a while ago.
ID is only assigned after the record is inserted into the database. So there is no way to access it in your factory.
Assuming you need the slug not only as part of your testing/seeding, the best way is to hook into the model's created event:
class User extends Authenticatable
{
protected static function boot() {
parent::boot();
static::created(function ($user) {
$user->update(['slug' => $user->id]);
});
}
}
Related
I have a list of names $names = ['Adam','Beth,'Chancie','Dale', 'Edward']; etc.. That I want to use in a Laravel factory, or seeder, I don't know which one.
Basically, I still want to use the Faker functionality for everything else, but provide my own custom list of names in the order they are listed in the array.
$factory->define(User::class, function (Faker $faker) {
return [
'name' => MY_CUSTOM_LIST_NAME,
'email' => $faker->unique()->safeEmail,
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10),
];
});
You could always create a private method which you call as you loop over each name in your array.
$factory->define(User::class, function (Faker $faker) {
foreach($name in $names) {
$this->customFakerMethod($name);
// your logic here ...
}
});
This function just takes the name as a parameter.
private function customFakerMethod($name)
{
return [
'name' => $name,
'email' => $faker->unique()->safeEmail,
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10),
];
}
So your users will be created in the order that you wish.
Suppose I have a user factory to create user, for specific user I want to add more information, for this I've defined state inside factory, but if I use state, then I can not call related method of user after user creation suppose I should assign role to the user using assignRole($role).
Following is my UserFactory.php
$factory->define(User::class, function (Faker $faker) {
return [
'email' => $faker->unique()->safeEmail,
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10),
'first_name' => $faker->name,
'last_name' => $faker->lastName,
'phone' => $faker->phoneNumber,
'password' => bcrypt('12345678'),
];
});
$factory->state(User::class, 'Admin', function (Faker $faker) {
$country = factory(Country::class)->create();
$province = factory(Province::class)->create();
static $afghanistanId = 1;
$admin= [
'about' => $faker->sentence($nbWords = 20, $variableNbWords = true),
'address' => $faker->address,
];
if($country->id == $afghanistanId) {
$admin['province_id'] = $province->id;
} else {
$admin['city'] = $faker->city;
}
return $admin;
});
Now if I use this factory like bellow:
$user = factory(User::class, $count)->state('Admin')->create();
$user->assignRole('Admin');
Following shows this error:
BadMethodCallException: Method Illuminate\Database\Eloquent\Collection::assignRole does not exist
By passing $count to the factory method $user = factory(User::class, $count)...->create(); you're creating multiple users and the return is a Collection like your Error says.
To assigne the 'Admin' role to each user you have to iterate them
$users = factory(User::class, $count)->state('Admin')->create();
foreach($users as $user)
$user->assignRole('Admin');
I am using Laravel Framework, I have generated all Register and Login through "$php artisan make:auth" command, now I have added a new column called "avatar" in the users table, and I want to set it to "noimage.jpg", so each time I register by default "noimage.jpg" will be added.
RegisterController
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'username' => $data['username'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
'avatar' => 'noimage.jpg' //How it suppose to be?
]);
}
You also have to add avatar to the $fillable property of your model. Otherwise you cannot assign it with create. See docs on Mass Assignment.
Instead you could manually assign the avatar:
protected function create(array $data)
{
$user = User::create([
'name' => $data['name'],
'username' => $data['username'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
]);
$user->avatar = 'noimage.jpg';
return $user;
}
Another way to set a default value for your model is to use Laravel lifecycle:
const DEFAULT_AVATAR = 'noimage.jpg'
protected static function boot()
{
parent::boot();
static::creating(function (User $user) {
if (!$user->avatar) {
$user->avatar = self::DEFAULT_AVATAR;
}
});
}
See: https://laravel.com/docs/5.8/eloquent#events
i have my default registration for auth controller. i want to register also the emp_id created from users table to employee table. once registered.
my RegisterController
use App\User;
use App\Employee
public function count_users(){
$count = User::count();
return date('y').'-'.sprintf('%04d',$count);
}
protected function create(array $data)
{
return User::create([
'emp_id' => $this->count_users(),
'username' => $data['username'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
return Employee::create([
'emp_id' => $this->count_users()
]);
}
Please check following line in your code:
return User::create([ .....
Above line creates the user and returns the created user. Any code below "return" is not being called.
Please try following code:
use App\User;
use App\Employee
public function count_users(){
$count = User::count();
return date('y').'-'.sprintf('%04d',$count);
}
protected function create(array $data)
{
$emp_id = $this->count_users();
$user = User::create([
'emp_id' => $emp_id,
'username' => $data['username'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
Employee::create([
'emp_id' => $emp_id
]);
return $user;
}
While updating the "users" table, I want the EditUserRequest form checkout to ignore the current email because it already exists.
Code rules:
public function rules()
{
return [
'username' => 'required|max:200',
'email' => [
'required',
Rule::unique('users')->ignore($user->id),
],
'pass1' => 'required|min:6',
'pass2' => 'same:pass1',
];
}
Code UserController:
public function postEdit($id,EditUserRequest $request)
{
$user = User::find($id);
$user->name = $request->username;
$user->email = $request->email;
$user->password = Hash::make($request->pass1);
$user->level = $request->get('cbadmin',0);
$user->save();
return view('admin.edit-user')->with('success','Sửa thành công!');
}
This line: 'email' => 'required|email|unique:users,email' will check email exists. However, the default email I need to update it already exists. Did I read:https://laravel.com/docs/5.6/validation#rule-unique. But I do not understand how to solve this problem
public function rules()
{
return [
'username' => 'required|max:200',
'email' => 'required|email|unique:users,email,'.request()->user()->id,
'pass1' => 'required|min:6',
'pass2' => 'same:pass1',
];
}
You can pass a third parameter as id to ignore.
Hope this helps.
I am not sure of your route parameter names since your routes aren't included in the post, so I will assume $id on the controller method means there is a route parameter named id.
'email' => [
'required',
Rule::unique('users')->ignore($this->route('id')),
],
This would use the id from the route parameter, assuming it was named id. This will tell the rule to ignore the unique check on this email field for this particular User id.
you can do this by using the Rule facade ..
'email' => [
'required',
Rule::unique('users')->ignore($user->id),
],
EDIT
in case you're using a function to validate your inputs you may do it like this:
protected function yourValidatorName(array $data, $id)
{
return Validator::make($data, [
'username' => 'required|max:200',
'email' => [
'required',
Rule::unique('users')->ignore($id),
],
'pass1' => 'required|min:6',
'pass2' => 'same:pass1',
]);
}
then
public function postEdit($id, EditUserRequest $request)
{
$accountValidate = $this->yourValidatorName($request->all(), $id);
if (!$accountValidate->fails())
{
// success
}
else
{
// failed
}
}
Can you show me your route for postEdit?
For example this is your route:
Route::put('users/{user_id_sample}', 'UserController#postEdit');
You may do something like this:
public function rules()
{
return [
'username' => 'required|max:200',
'email' => [
'required',
Rule::unique('users')->ignore($this->route('user_id_sample')),
],
'pass1' => 'required|min:6',
'pass2' => 'same:pass1',
];
}