$factory->define(App\Client::class, function (Faker\Generator $faker) {
static $password;
$company_name = $faker->Company;
return [
'name' => $company_name,
'short_name' => substr($company_name, 0, 3),
'email' => $faker->unique()->safeEmail,
'password' => $password ?: $password = bcrypt('secret'),
'remember_token' => str_random(10),
];
});
$factory->define(App\Campaign::class, function (Faker\Generator $faker) {
static $password;
return [
'unique_id' => $faker->numerify('ABC###'),
'client' => function() {
return factory('App\Client')->create()->id;
}
];
});
I am generating come clients and campaigns. One client can have many campaigns
How do I take the short_name from the Company and pass it to a the campaign class so I can append it to a random string to create a unique id in the client?
You're almost there. You don't need to use an anonymous function in the campaign class, you can just reference the factory directly. Use a variable inside the Campaign factory and just reference whatever values you need.
$factory->define(App\Campaign::class, function (Faker\Generator $faker) {
$client = factory(App\Client::class)->create();
return [
'unique_id' => $faker->numerify('ABC###') . $client->short_name,
'client' => $client->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'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]);
});
}
}
I want to test my AR model without connect to database in Yii 2 so I use mockBuilder() but I dont know how can I pass the mock object to the model exist validator, for example:
class Comment extends ActiveRecord
{
public function rules()
{
return [
[['id', 'user_id', 'post_id'], 'comment'],
['comment', 'string',
'max' => 200
],
['user_id', 'exist',
'targetClass' => User::className(),
'targetAttribute' => 'id'
],
['post_id', 'exist',
'targetClass' => Post::className(),
'targetAttribute' => 'id'
]
];
}
}
class CommentTest extends TestCase
{
public function testValidateCorrectData()
{
$user = $this->getMockBuilder(User::className())
->setMethods(['find'])
->getMock();
$user->method('find')->willReturn(new User([
'id' => 1
]));
$post = $this->getMockBuilder(Post::className())
->setMethods(['find'])
->getMock();
$post->method('find')->willReturn(new Post([
'id' => 1
]));
// How can I pass to $user and $post to exist validator in Comment model?
$comment = new Comment([
'user_id' => 1,
'post_id' => 1,
'comment' => 'test...'
]);
expect_that($comment->validate());
}
}
ok, It's not a best code just I'd like to introduce what I want to do.
Yii2 ExistValidator uses ActiveQuery::exists() for check existence and you should replace generated validator to mockobject where the method createQuery returns mockobject of ActiveQuery where ::exists() return something you want (true/false) e.g.
$activeQueryMock = $this->getMockBuilder(ActiveQuery::className())
->disableOriginalConstructor()
->setMethods(['exists'])
->getMock();
$activeQueryMock->expects($this->any())
->method('exists')
->willReturn($value); //Your value here true/false
$model = $this->getMockBuilder(Comment::className())
->setMethods(['getActiveValidators'])
->getMock();
$model->expects($this->any())
->method('getActiveValidators')
->willReturnCallback(function () use ($activeQueryMock) {
$validators = (new Comment())->activeValidators;
foreach ($validators as $key => $validator) {
if (($validator instanceof ExistValidator) && ($validator->attributes = ['user_id'])) {
$mock = $this->getMockBuilder(ExistValidator::className())
->setConstructorArgs(['config' => get_object_vars($validator)])
->setMethods(['createQuery'])
->getMock();
$mock->expects($this->any())
->method('createQuery')
->willReturn($activeQueryMock);
$validators[$key] = $mock;
break;
}
}
return $validators;
});
$model->validate();
I'm trying to seed my database with like this:
factory(App\User::class, 1)
->create()
->each(function($u) {
$role = factory(App\Role::class)->create();
$u->role()->save( $role );
});
and these are my model factories:
$factory->define(App\User::class, function (Faker\Generator $faker) {
return [
'name' => 'Jakub Kohout',
'email' => 'test#gmail.com',
'password' => bcrypt('Uchiha'),
'role_id' => 1
];
});
$factory->define(App\Role::class, function (Faker\Generator $faker) {
return [
'role_name' => 'Admin',
];
});
But I got this error:
Undefined property: Illuminate\Database\Eloquent\Builder::$orders
What am I doing wrong?
Sadly, the each function does not work with single elements. You have to create more than one Model to use the each function:
factory(App\User::class, 2)->create()->each(function($u) {
$role = factory(App\Role::class)->create();
$u->role()->save( $role );
});
Source
When only one element is created, the instance is returned directly instead of a collection.
This should work for your case:
$user = factory(App\User::class)->create();
$role = factory(App\Role::class)->create();
$user->role()->save( $role );