Let's say you have an Illuminate Collection of User model objects.
$users = User::all();
Now, you want to get a single user from that collection by ID.
The only way I knew of doing this (super ugly):
$user_id = 22;
$user = $users->filter(function($user) use ($user_id) {
return $user->id = $user_id;
})->first();
(Taken from this question and answer.)
However, if you do this, the $users collection is destroyed and unusable. For instance, if there were 100 unique users in the collection before, you will instead now have 100 copies of the user with id 22 for some God forsaken reason.
How can I get a single user by ID from the collection without destroying the collection or looping through it?
I thought this would work...
$user_id = 22;
$temp_users = $users;
$user = $temp_users->filter(function($user) use ($user_id) {
return $user->id = $user_id;
})->first();
But, even more infuriatingly, $users is still destroyed by the filter call - so evidently $temp_users = $users is identical to $temp_users = &$users or something. There appears to be no way of duplicating a collection.
According to this Github issue, Collection::filter() used to return brand new object instances. Evidently, it doesn't anymore. And neither does $temp_users = $users; I guess - which is confusing as hell.
Eloquent responses in the form of collections actually extend a special collection type located at Illuminate\Database\Eloquent\Collection, which has a familiar method find(). Simply use that.
$users = User::all();
$jack = $users->find(22);
In case ID is not your primary key, you could use firstWhere() like this:
$user_id = 22;
$userYouNeed = $users->firstWhere('id', $user_id);
If you would have a more complex condition you can consider using first() and providing your own callback with a condition like this
$user_id = 22;
$userYouNeed = $users->firs(function ($user) use ($user_id) {
return $user->id === $user_id; // Or a more complex condition
});
Related
I want to join multiple tables in laravel with query builder. My problem is that my code only works if I specify the id myself that I want like this:
$datauser = DB::table('users')
->join('activitates','users.id','=','activitates.user_id')
->join('taga_cars','taga_cars.id','=','activitates.tagacar_id')
->join('clients','users.id','=','clients.user_id')
->where('users.id','=','1')
->select('users.*','activitates.*','taga_cars.model','taga_cars.id','clients.name')
->get();
return response()->json($datauser);
But I would want something like this(which I just can't seem to figure out)
public function showuser($id)
{
$userid = User::findOrFail($id);
$datauser = DB::table('users')
->join('activitates','users.id','=','activitates.user_id')
->join('taga_cars','taga_cars.id','=','activitates.tagacar_id')
->join('clients','users.id','=','clients.user_id')
->where('users.id','=',$userid)
->select('users.*','activitates.*','taga_cars.model','taga_cars.id','clients.name')
->get();
return response()->json($datauser);
}
Am I making a syntax mistake? When I check the page for my json response in second page it just returns empty brackets, but when I specify the id it fetches me the right data
The findOrFail method will return the entire user model, with all its properties, since you already have the user id. You dont need to get the entire user model for that, you could just use the $id you receveid as a parameter like this:
$datauser = DB::table('users')
->join('activitates','users.id','=','activitates.user_id')
->join('taga_cars','taga_cars.id','=','activitates.tagacar_id')
->join('clients','users.id','=','clients.user_id')
->where('users.id','=',$id)
->select('users.*','activitates.*','taga_cars.model','taga_cars.id','clients.name')
->get();
return response()->json($datauser);
public function showuser($id)
{
$getUserByID = User::findOrFail($id); //not used
$userData = DB::table('users')
->join('activitates','users.id','=','activitates.user_id')
->join('taga_cars','taga_cars.id','=','activitates.tagacar_id')
->join('clients','users.id','=','clients.user_id')
->where('users.id','=',$id)
->select('users.*','activitates.*','taga_cars.model','taga_cars.id','clients.name')
->get();
return response()->json($userData);
}
But the best way is to have relations set on models
public function showuser($id)
{
$userData = User::where('id', $id)->with(['activitates','taga_cars','clients'])->first();
return response()->json($userData);
}
I want to select all the users in my table "User" except the first One cause its the admin,
im using this function index in my controller but it doesn't work .
public function index()
{
// this '!=' for handling the 1 row
$user = User::where('id', '!=', auth()->id())->get();
return view('admin.payroll',compact('user'))->with(['employees' => User::all()]);
}
Better to used here whereNotIn Method
Note: first you find the admin role users and create a static array
$exceptThisUserIds = [1];
$user = User::whereNotIn('id', $exceptThisUserIds)->get();
It's not a good idea to specify the admin user with just id. A better design would be using some sort of a flag like is_admin as a property of your User model.
Still you can use the following code to get the users who have an id greater than 1:
User::where('id', '>', 1)->get()
For getting data skipping the first one you should use skip() method and follow the code like below
public function index()
{
$user = User::orderBy('id','asc')->skip(1)->get();
return view('admin.payroll',compact('user'))->with(['employees' => User::all()]);
}
I wants to know how to check if the return of Eloquent Query is single row from DB or multiple rows.
I tried $record->count() but it always return a value greater than 1 in the 2 cases.
For example:
$record = User::first();
return $record->count(); //it return the count of columns in users table
and if I tried to get all users;
$record = User::all();
return $record->count(); //it return the count of all rows in users table
So how to deal with this case ?
You can use the instanceof construction to check what kind of data your variable is.
For your examples, this will likely be something like this:
$record = User::first();
$record instanceof \App\User; // returns true
$record instanceof \Illuminate\Database\Eloquent\Collection; // returns false
$record = User::all();
$record instanceof \App\User; // returns false
$record instanceof \Illuminate\Database\Eloquent\Collection; // returns true
Docs: https://secure.php.net/instanceof
$record = ......;
if($record instanceof \Illuminate\Support\Collection){
// its a collection
}
elseif($record instanceof \App\User){
// its a single url instance
}
However, above will not work directly if you are using DB builders :
$record = DB::table('users')->get();
$record is an array. So you need to hydrate it so you can use above logic on it :
if(is_array($record){
$record = \App\User::hydrate($record);
}
Now you can use if else logic on $record as its converted from an array to \Illuminate\Database\Eloquent\Collection which internally extends from \Illuminate\Support\Collection
Also, second case if someone did first() instead of get():
$record = \DB::table('users')->first();
Then $record is an stdClass object. so you can avoid hydration and consider it as a single user data.
I am concerned about the system logic and patterns where you need to have this kind of conditional. If possible, I would recommend to refactor in such a way that you function always knows if it's a collection or an instance. You can use type hints in functions to be more clear.
first() always returns only 1 row
$record = User::first(); // this will return only 1 records
To get number of rows in users table you need to create another query
$allrow = User::all();
return $allrow->count();
OR
$allrow = DB::table('users')->get();
return $allrow->count();
User::all() returns an array of User So the simple way is to check if is an array.
if (is_array($record)){
}
In my site I have users and items. Users can create items. I want to get an array that has all users, where the users which have an item go first and the users which do not have an item go after.
So far I have done this:
$users = User::all();
foreach($users as $user) {
if ($user->item) {
$sortedUsers + $user;
}
// now loop again and add users without relationship
This is pretty inefficient and I'm sure there's a much better way to do it.
You can query on the existence of a relationship
$users = User::has('items')->with('items')->get();
with that syntax you are telling laravel to fetch all users that have a item and to eager load the items;
Edit:
After reading it does not look like you actually want the items just the users that have a item in that case all you need is
$users = User::has('items')->get();
Without seeing the relation of Items to Users I'm not sure if this will work but you can try the following:
$users = Users::select('users.*')->orderBy('items.id')->with('items')->get();
Or it might work with just:
$users = Users::orderBy('items.id')->with('items')->get();
Update
$users = Users::orderBy('items.id')->join('items', 'items.user_id', '=', 'users.id')->get();
you can try
$users = User::with('item')->get();
foreach ($users as $user) {
echo $User->item->name;
}
You can use has() to get users with items and doesntHave() to get users without items:
$withItems = User::has('items')->get();
$withoutItems = User::doesntHave('items')->get();
And then merge() two collections:
$users = $withItems->merge($withoutItems);
You said you want an array, so you can convert result into an array with toArray()
$array = $users->toArray();
I have a tag system, where you can add tags to photos and users.
I have a function where the users are able to add their favorite tags, and select images based on those tags
But my problem i am a really big beginner with php and laravel and i do not know how to pass the values to the whereIn function
Model
public function tag()
{
return $this->belongsToMany('Tag', 'users_tag');
}
Controller
// get the logged in user
$user = $this->user->find(Auth::user()->id);
// get tags relation
$userTags = $user->tag->toArray();
// select photos based on user tags
$photos = Photo::whereHas('tag', function($q) use ($userTags)
{
$q->whereIn('id', $userTags);
})->paginate(13);
$trendyTags = $this->tag->trendyTags();
$this->layout->title = trans('tag.favorite');
$this->layout->content = View::make('main::favoritetags')
->with('user', $user)
->with('photos', $photos)
->with('trendyTags', $trendyTags);
When i pass i get an error
preg_replace(): Parameter mismatch, pattern is a string while replacement is an array
than i tried to use array_flatten() to clean my array
// get the logged in user
$user = $this->user->find(Auth::user()->id);
// get tags relation
$userTags =array_flatten($user->tag->toArray());
// select photos based on user tags
$photos = Photo::whereHas('tag', function($q) use ($userTags)
{
$q->whereIn('id', $userTags);
})->paginate(13);
$trendyTags = $this->tag->trendyTags();
$this->layout->title = trans('tag.favorite');
$this->layout->content = View::make('main::favoritetags')
->with('user', $user)
->with('photos', $photos)
->with('trendyTags', $trendyTags);
This way it works but not returning the correct tags.
Could please someone could lend me a hand on this?
Sure thing and I'll make a couple recommendations.
To get the user model, you simply have to use $user = Auth::user().
To use whereIn(), it's expecting a 1 dimensional array of user id's. The toArray() function is going to return an array of associative arrays containing all the users and their properties, so it's not going to work quite right. To get what you need, you should use lists('id').
And one last thing that has really helped me is when you are setting up a relation that's going to return a collection of objects (hasMany, belongsToMany()), make the relation name plurual, so in this case you would modify your tag() function to tags().
So with all that in mind, this should work for you.
// get the logged in user
$user = Auth::user();
// get tags relation
$userTags = $user->tags()->lists('id');
// select photos based on user tags
$photos = Photo::whereHas('tags', function($q) use ($userTags)
{
$q->whereIn('id', $userTags);
})->paginate(13);
$trendyTags = $this->tags->trendyTags();
$this->layout->title = trans('tag.favorite');
$this->layout->content = View::make('main::favoritetags')
->with('user', $user)
->with('photos', $photos)
->with('trendyTags', $trendyTags);
And I'd suggest to modify your relation to... though not hugely important.
public function tags()
{
return $this->belongsToMany('Tag', 'users_tag');
}