I have a regular User model. The system works fine when I use it. But now I am trying to create unit tests in the PHPUnit that integrated with Laravel.
I have a factory that creates a user:
$factory->define(App\User::class, function (Faker\Generator $faker) {
return [
'id' => $faker->randomNumber(9),
'email' => $faker->safeEmail,
'first_name' => $faker->firstNameMale,
'last_name' => $faker->lastName,
'password' => bcrypt(str_random(10)),
'remember_token' => str_random(10),
];
});
I changed the User to have integer ID as the primary key but it not defined as auto-increment.
So the factory create random number for the ID.
Also I have created the simple test:
public function test_id_is_visible() {
$user = factory(App\User::class)->create();
$this->actingAs($user);
$this->visit('/userprofile');
$this->see($user->id);
}
That test always fails, but it seems to be OK when I navigate to the page manually.
I have noticed that in the test the $user->id is always 0. Even it can't be 0 in the factory. I checked and Laravel insert the user correctly to the database and it have correct ID, but in the code I always get 0.
What can I do to get the correct value of the ID?
EDIT
Now I see that if I changes $user = factory(App\User::class)->create(); to $user = factory(App\User::class)->make(); the user instance holds a correct ID. But why create clears the ID?
Update for Laravel 5.8+ Make sure to set
public $incrementing = false;
on your model.
The problem happened because the ID is not defined as auto-increment.
More information you can found in:
https://stackoverflow.com/a/31350800/1725836
Even the question is for Laravel 4 it is still relevant for Laravel 5.2.
You can write your tests like this:
$users = factory(User::class, 5)->make();
$users->each(function ($item, $key) {
$item->id = ++$key;
});
Now each user will have an id, without the need to persist the models to database (using create() instead of make()).
public function test_id_is_visible() {
$user = factory(App\User::class)->make();
$user->id = 7;
$this->actingAs($user);
$this->visit('/userprofile');
$this->see($user->id);
}
Related
I am trying to make a testcase within laravel.
I have a fake User model (which dosent exists in DB), and creating it using faker->make,
and a real Role model which exists in DB,
these two have a many-to-many relationship
in my testcase, i am going to associate them like here :
public function testAccess()
{
$user = factory(\App\User::class)->make();
$supervisionControllerRole = \App\Role::where('name', 'supervision_controller')->first();
$user->roles->add($supervisionControllerRole);
}
since i dont want to save the relation in database, i am using add() instead of attach():
$user->roles()->attach($supervisionControllerRole->id);
//resulting database modification.
Problem
my problem is, when i am trying to get the relation from the model its ok.
var_dump($user->roles->first());
but when i am trying to get the relation Within The Model, it dosent works.
like here in my User Model:
public function hasRole($roleName)
{
$role_id = Cache::tags(['role_id'])->remember($roleName, 24*3600, function () use ($roleName) {
return \App\Role::where('name', $roleName)->first()->id;
});
return $this->roles()->where('role_id', $role_id)->exists();
}
It will returns false and trying $this->roles->count() results 0
from inside of the model.
My definitions
in User model:
public function roles()
{
return $this->belongsToMany("App\Role", "role_user")->whereNull("deleted_at")->using("App\RoleUser");
}
User Factory:
$factory->define(User::class, function (Faker $faker) {
return [
'id' => $faker->randomNumber(),
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'email_verified_at' => now(),
'password' => Str::random(80), // password
'remember_token' => Str::random(10),
];
});
Whenever you call a relationship with parentheses, such as
return $this->roles()->where('role_id', $role_id)->exists();
^^
you're accessing a Builder query instance which will return info from the database. But your data is not in the database, so of course it won't find anything when it looks there.
When you directly add() the relationship (vs attach()), you're inserting into a Collection instance, which as you know doesn't affect the database. This information is saved on the model only and stored in memory. Hence when you do
var_dump($user->roles->first());
it finds the information since it's already in memory. (You should also be able to call $user->roles->count() here and get a non-zero value.)
And since it's in a relationship of the model vs a direct attribute, I don't even think it would update the database if you were to save() the model.
You can use the contains method to perform the first step if you are not storing in the database:
return $this->roles->contains($role_id);
Laravel 5.8
"aimeos/aimeos-laravel": "^2019.04"
I create new user by code:
$user = new User([
'id_customer' => $id_customer,
'id_customer_ref' => $id_customer_ref,
'firstname' => $firstname,
'lastname' => $lastname,
'email' => $email
]);
and save it:
$user->save()
This I do in a class extended from Illuminate\Console\Command.
How can I add this user to some group like editor ?
I would tag this as more of a database question, but basically you'd set up a relationship between the users. The most common method of grouping is simply adding an integer or string to the user table. So create a migration:
php artisan make:migration add_types_on_users
Then in the Blueprint callback do something like:
$table->string('type')->default('regular');
// or if you want an integer
$table->integer('type')->default(0);
Don't forget to add the reverse function logic:
$table->dropColumn('type');
Then run the migration:
php artisan migration
Now whenever you want to see if a user has permissions(typically done in policies) just check that field
if($user->type === 'editor'){
// do editor only stuff
}
I am using Laravel 5.4. I made a function for two (insert and update).
When id is not found it will hit insert otherwise it will hit the update method.
Everything is working well but the update elequent query is not updating the table. The method is for angularjs http.post method
Controller function:
public function postUserJson(Request $req)
{
//return "check". $req->input('id');
if ($req->input('id')=='') {
$user = new User();
$user->UserName = $req->input('username');
$user->Password = $req->input('password');
$user->save();
return "inserted";
} else {
$check= User::find($req->input('id'));
// $check->ID = $req->input('id');
$check->UserName = $req->input('username');
$check->Password = $req->input('password');
$check->save();
return "updated".$check;
}
}
This (return "updated".$check;) code return in console:
updated{"ID":13,"UserName":"sadek","Password":"456"}
Previous username was sade. After editing i got the edited name with sadek after save() method. But when i refresh it show sade
How can i update a table ?
you are sending data in json formate. your query string is not same. see
"UserName" != username
Password != password
make sure about this.
Eloquent provides a method for handling all of the logic you have above, it is called updateOrCreate()
From the docs:
You may also come across situations where you want to update an existing model or create a new model if none exists. Laravel provides an updateOrCreate method to do this in one step. Like the firstOrCreate method, updateOrCreate persists the model, so there's no need to call save()
$flight = App\Flight::updateOrCreate(
['departure' => 'Oakland', 'destination' => 'San Diego'],
['price' => 99]
);
I am doing an extension build on the User model on larval 5.
What I want to accomplish is once the user registers and is validated I want ANOTHER database table created named userInfo which has a belongsto Relationship with the User model and the User model has a hasOne relationship with userInfo.
Two things.
How to I successfully implement this logic. I was reading
http://laravel.com/docs/master/eloquent-relationships#inserting-related-models
and
http://laravel.com/docs/5.1/events#registering-events-and-listeners
But Im not to sure
And second.
Where best do I implement this logic.
Thanks in advance
PS. I do not what to combine the two database because the user model is when they register and data that lives in userInfo is "optional" for the user to fill out After authentication.
If I am understanding the question correctly, you want to create an additional related model to the user when they register. That should be pretty straightforward - something like:
$user->userInfo()->save(UserInfo::create([
//whatever information you need to save to the userInfo table - if any
]));
as for where to put it, you have options there. You could put it the 'store' method on your registration controller. Or extract it out to a service class 'RegisterUser', and create the user and userInfo there.
something like:
//controller method
public function store(Request $request, RegisterUser $registerUser)
{
$user = $registerUser->handle($request);
return view(....)
}
//RegisterUser class
public function __construct(UserInfo $userInfo)
{
$this->userInfo = $userInfo;
}
public function handle($request)
{
// create your user
$user = .....
$user->userInfo()->save($this->userInfo->create([
.....
]));
// whatever else you need to do - send email, etc
return $user;
}
Edit: If you are using Laravel 5 and the default registration scaffolding, then you can add code to the app\Services\Registar class. This class is called by the postRegister method in the trait. Change the create method:
// app\Services\Registar
public function create(array $data)
{
$user = User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
$user->userInfo()->save($this->userInfo->create([
.....
]));
// whatever else you need to do - send email, etc
return $user;
}
If you are using Laravel 5.1 then the Registar class doesn't exist anymore, the create method has been moved to the AuthController (the method is the same, just in a different location) so override it there.
Your answer pointed me in the right direction but I made some simple tweek to your edited question.
$user->userInfo()->firstOrCreate([
'aboutMe' => 'Please Fill out so users can know about you',
'bodyType' => '--',
]);
return $user;
I'm pretty much new to opps and laravel both
So, to insert the values into my users and profiles table which hav OneToOne relationship, Here is how my store() method looks like
public function store(Requests\StoreNewUser $request)
{
// crate an objct of user model
$user = new \App\User;
// now request and assign validated input to array of column names in user table
$user->first_name = $request->input('first_name');
$user->last_name = $request->input('last_name');
$user->email = $request->input('email');
$user->password = $request->input('password');
/* want to assign request input to profile table's columns in one go
*/
$user->profile()->user_id = $user->id; // foreign key in profiles table
$user->profile()->mobile_no = $request->input('mobile');
dd($user); // nothing related to profile is returned
}
I'm creating the new record, hence dd() never returns anything related to profile table.
Is this Because the $user object is not including relationship by default?
If yes Can i create the $user object which includes the associated relations in User Model ?
Or do i have to create two separate objects of each table and save() the data But then what is the significance of push() method ?
EDIT 1
P.S. yes, the relationships are already defined in User & Profile model
You may try something like the following. At first save the parent model like this:
$user = new \App\User;
$user->first_name = $request->input('first_name');
// ...
$user->save();
Then create and save the related model using something like this:
$profile = new \App\Profile(['mobile_no' => $request->input('mobile')]);
$user->profile()->save($profile);
Also make sure you have created the profile method in User model:
public function profile()
{
return $this->hasOne('App\Profile');
}
I thought i'd update this answer and make it applicable to Laravel 5 onwards. I'll use #The Alpha answer as a basis.
$profile = new \App\Profile(['mobile_no' => $request->input('mobile')]);
$user->profile()->associate($profile); // You can no longer call 'save' here
$user->profile()->save();
The reason for this is you can no longer call save on the belongsTo relation (or any other), this now returns an instance of Illuminate\Database\Query\Builder.
The clean way to do it now would be having on your User Class file:
public function profile()
{
return $this->hasOne(App\Profile::class);
}
and in your User Controller, the following store method:
public function store(Requests\StoreNewUser $request)
{
$user = App\User::create(
$request->only(
[
'first_name',
'last_name',
'email'
]
)
);
$user->password = Illuminate\Support\Facades\Hash::make($request->password);
//or $user->password = bcrypt($request->password);
$user->profile()->create(
[
'mobile_no' => $request->mobile;
]
);
dd($user);
}
I didn know if u were saving plain text password to you database or using a mutator on password attribute, anyhow the suggested above is a good practice I think
Is this Because the $user object is not including relationship by default? If yes Can i create the $user object which includes the associated relations in User Model ?
Yes you should create the relationship, they're not included by default.
In your User model you'd want to do something like this:
public function profile()
{
return $this->hasOne('App\Profile'); // or whatever your namespace is
}
This would also require you to have a Profile model created.
This would definitely answer your questions regarding inserting related models: http://laravel.com/docs/5.1/eloquent-relationships#inserting-related-models
As The Alpha mentioned, and you also eluded to, I think you need to save your user model first then you can add via relationship.