When testing I am able to create a model factory and then act as that user e.g.
$users = factory(User::class)->create();
$this->actingAs($users)
Would it be possible for me to act as a user who is already in the database, so say I could reference their ID number and then test as that user?
Try $users = User::find(1); .. where 1 is the correct id.
You can use any Eloquent function such as User::where('name', '=', 'John'); too.
You might have to fix the User namespace like $users = App\Models\User::find(1); or use (import) it.
Note that you can roll back your databases after each test too, or simply use another database altogether.
Related
I have 2 models, User and Conversation related to each other with a many-to-many relationship, many users to many conversations.
On my models I have:
User:
public function conversation() {
return $this->belongsToMany('App\Models\Conversation');
}
Conversation:
public function users() {
return $this->belongsToMany('App\Models\User');
}
So I could get the conversations a user has by : $user->conversation; and vice versa, retrieve the users a conversation has by $conversation->users, works like a charm. The problem is that I want a way to retrieve all users a certain user has made contact before, in few words, something like:
$user = User::find(1);
$talkedUsers = $user->conversation->user.
And also a way to check all the conversation user 'x' has made with user 'y' ('if any')
$userX = User::find(1);
$userY = 2;
$talkedUser = $userX->conversation->where('user.id', '=', $userY);
Obviously, the code above won't work. I wish to know if something like this is possible to accomplish without adding a complex raw query, I hope is possible only using only QueryBuilder.
The problem is that I want a way to retrieve all users a certain user
has made contact before,
$user->conversation is actually a collection of conversations, it is better to use plural i.e. $user->conversations. Then you can use higher order messages to deal with multiple objects at once. See https://laravel.com/docs/8.x/collections#higher-order-messages for more information
$users = $user->conversations->flatMap->users->unique('id');
flatMap combines multiple User collections retrieved from multiple Conversation objects into one collection of User objects then to remove duplicate users, you can use unique('id')
And also a way to check all the conversation user 'x' has made with
user 'y' ('if any')
First you should query all conversations from x then filter only conversations that have relationships with y.
$userX = User::find($x);
$conversations = $userX->conversations()
->whereHas('users', function($query) use ($y) {
$query->where('users.id', $y);
})
->get();
Something strange happening when using eager loading.
For example i want the get all authors related with a user, and everyhing was working well, but when i use eager loading it doesnt work well.
Example:
Users:
- id;
- name
- ...
Authors:
- id
- user_id
- ...
Model User:
public function authorsProfile()
{
return $this->hasMany(Author::class, 'user_id', 'id');
}
My controller:
$user = Auth::user();
//Get all users and the authors that is related with it (Not working well)
dd( $user->with('authorsProfile')->get());
//Get all authors that is related with this user (Working well)
dd( $user->authorsProfile);
In my case is supposed to give me only the authors related with the current authenticated user, but for some reason when i try to use eagerloading for some reason is getting all users and there relation (authors)...
Does someone have a idea whats wrong?
Calling ->get() executes a whole new query that fetches all users.
You are looking for lazy eager loading:
$user->load('authorsProfile');
If you've already got the User loaded, using ->with() is not the correct approach. In your case, try ->load():
$user = Auth::user();
$user->load("authorsProfile");
dd($user->authorsProfile); // Should be a Collection
Technically, you don't even need to call ->load(), as attempting to access a relationship that wasn't loaded with ->with() will load it at that point:
$user = Auth::user();
dd($user->authorsProfile); // Should also be a Collection
To make it work like you have it coded, you'd need to call:
$user = Auth::user();
$user = User::with(["authorsProfile"])->where("id", "=", $user->id)->first();
dd($user->authorsProfile);
But, you can see why that would be inefficient; you'd be calling the database again to retrieve a record you already have.
So, lots of way to accomplish this. See what you can get working.
So far I was extracting the relation objects as arrays and then doing something like:
App\Model::find($id)
But however is there a way to do something like:
Auth::user()->group()->members()
It works until Auth::user()->group but no further chaining. Please help if you've done something. Or I'm just newbie.
You could use eager loading to load the user's group and then load all of the members of that group.
$user = User::with(['group', 'group.members'])->find(1);
// OR if you already have a user object (Like when using the Auth facade)
$user = Auth::user()->load(['group', 'group.members']);
foreach ($user->group->members as $member) {
// Do something with a member
}
However, if you essentially want to jump down the structure a level, and get all the members related to a user, you could use the hasManyThrough relationship, in that a user has many members, through a group.
// In your User model
public function members()
{
return $this->hasManyThrough(Member::class, Group::class);
}
That way you can simply access the members directly through the user:
$members = Auth::user()->members;
Instead of doing a query to access the user's group and then doing another query to access that group's members, Laravel would use a single query with a join to get you the members.
Take a look at the hasManyThrough relationship here
Try this
Auth::user()->group->members
I'm developing an application using laravel 4. I'm performing the following join on two tables:
$listings = DB::table('user')
->join('listings', 'listings.agent_id', '=', 'user.id')
->where('user.user_level', '=', 3)
->get();
var_dump($listings);
Not this works as expected, but in the var_dump it returns the hashed password which I don't want it to do.
public 'password' => string '$2y$10$o58S16Tw2yc2uvcIs.cy3.lbmyFgUZjTl7nMdLzU2AVXeXVCY5xqK' (length=60)
I have in my User Model:
protected $hidden = array('password');
But, I think this only hides it from a Json response. So, in this situation I have two questions:
Is it bad to have the password out like this? It is coming back hashed, but I still don't like the fact that it's out there. Obviously, I won't be using the var_dump like this in the live application, but the fact that the information is there makes me nervous.
If it is bad, how can I prevent it? I want all the rest of the info in the tables. So, I could re-write my query to return everything but the password, but is there a simpler way to do this? Perhaps I'm missing something that excludes rows in my query, as opposed to writing every row I want?
First of all I would recommend you to create a model for each database table.
Next if you are using DB::table('user') you are not making use of the User model where the $hidden is specified. This way the password will not be hidden.
When you're doing this (for example):
$user = User::find(1); // Selects user with id of 1
return Response::json($user); // Gives JSON response
All the user data will be shown as JSON, without the fields specified in:
protected $hidden = ['password'];
I hope this helps you out ;)
I have this setup in a PHP project using Propel (which I'm new to).
User: userid, firstname, lastname
SignIn: signinid, userid, time
SignIn, in this case, is a table containing the times each user signed in.
What I want is to print out a JSON string using Propel of the last ten SignIn entries. On the front end I want to display something like:
Bob Builder signed in at 3:30pm
Max Power signed in at 3:24pm
...
So when I query the last ten entries in SignIn and then call toJSON, I'd like to have the User data for that SignIn record also included in the JSON.
How can I do that?
Note, if there's a better way to do this, I'm open to ideas.
One thing about Propel, is that the documentation is really clean, very readable and always helpful.
For your request, you can try the following request. Take a closer look at it, it's readable (as always with Propel)
$signIn = SignInQuery::create()
->select(array('User.firstname', 'User.lastname', 'SignIn.time'))
->join('User')
->orderByTime('desc')
->limit(10)
->find()
->toJson();
Just an alternate solution: you can also override any of the *Base methods in your classes, I've done this many times to add extra info to the toJSON, toArray, or fromArray methods.
In SignIn.php:
public function toJSON() {
$fields = json_decode(parent::toJSON());
$user = $this->getUser(); // assumes you have a foreign key set up
$fields->firstname = $user->getFirstname();
$fields->lastname = $user->getLastname();
return json_encode($fields);
}
Now you just query for your SignIn objects and whenever toJSON is called the user data will be appended:
$signIn = SignInQuery::create()
->orderByTime('desc')
->limit(10)
->find()
->toJson();
Note that the toJSON override is actually an override of the generic "to[Format]" method in BaseObject which is handled by the code on line 380 (in v1.6): public function __call($name, $params) { ... }