Searching collection records by relationship attributes - php

I have a game where people can get some items and equip them.
The items data is placed in two tables that are in relationship.
Items table contains all the possible items and user_items table contains the items that are owned by a player.
user_items table: id | user_id | item_id | is_equipped
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Item extends Model
{
use HasFactory;
public function userItems()
{
return $this->belongsTo(UserItem::class);
}
}
items table: id | item_name | body_part
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class UserItem extends Model
{
use HasFactory;
public function items()
{
return $this->hasOne(Item::class, 'id', 'item_id');
}
}
Now I am getting a collection of the user's items
$userItems = UserItem::where('user_id', Auth::id())->get(),
How do I search this collection by related table's columns? For example I want to get user $userItems where is_equipped == 1 and body_part == "head".

What you need is filter by the relation like this:
$userItems = UserItem::where('user_id', Auth::id())->whereHas('items', function($q)
{
$q->where('is_equipped', '=', 1);
})->get();

You can use the Eloquent's relationships to search the collection by related table's columns.
To get the user's items where is_equipped == 1 and body_part == "head", you can use the following code:
$userItems = UserItem::where('user_id', Auth::id())
->whereHas('items', function ($query) {
$query->where('is_equipped', 1)->where('body_part', 'head');
})->get();
This code first queries the user_items table for all items that belong to the user. Then, it uses the whereHas method to filter the results based on the related items table's columns. The closure passed to whereHas receives a $query variable that is a instance of Query Builder that you can use to filter the items table.
You could also use the join method to join the items table to the user_items table and then filter by the columns in the items table:
$userItems = UserItem::join('items', 'items.id', '=', 'user_items.item_id')
->where('user_items.user_id', Auth::id())
->where('items.is_equipped', 1)
->where('items.body_part', 'head')
->get();
This will give you a collection of user_items that are owned by the user and have is_equipped = 1 and body_part = 'head' in the items table.

Related

Laravel query issue whene user is deleted

Here is my database table.
to_user_id is deleted in the users table that time total_like not should be 1
Here is my code
$user_id = 585;
$list = new self;
$list = $list->where('users.id', $user_id);
$list = $list->leftJoin('user_like_dislikes as total_like', function ($join) use ($user) {
$join->on('users.id', '=', 'total_like.to_user_id')
->where('total_like.like', 1);
});
$list = $list->select('users.*', \DB::raw('count(total_like.like) as total_like')
$list = $list->first();
Here are my user_like_dislikes data table
user_id
to_user_id
like
585
590
1
Here is my user table
id
deleted_at
590
Null
I above code to_user_id is not deleted in the user table so the output is total like is 1
But when I delete to_user_id in the users table that time output is total like 1 getting. this is wrong.
So, I want where I delete to_user_id in the users table that time total like should be 0
better way use relation to get solve this problem.
try bellow code :
in user model :
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
class User extends Model
{
protected $table = 'users';
public function likes(): HasMany
{
return $this->hasMany(Like::class, 'to_user_id', 'id');
}
}
the Like model:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Like extends Model
{
protected $table = 'user_like_dislikes';
public function user(): BelongsTo
{
return $this->belongsTo(User::class, 'user_id', 'id');
}
}
And Finally your query is:
$data = \App\Models\User::query()
->where('id',585)
->withCount('likes as likes_count') // for getting count of rows
->withSum('likes as likes_sum','like') // for getting sum of like column
->first();
$data->likes_count and $data->likes_sum your want value
and for handle soft delete you should use bellow tarit in user model
use \Illuminate\Database\Eloquent\SoftDeletes;

Laravel - Check all instances of relationship for values on pivot table

I have a two models that have a many-to-many relationship, with some addtional fields on the pivot table:
Shift table:
------------
id - uuid
date - date
address - string
...
Employee table:
---------------
id - uuid
first_name - string
...
shift_employee table:
---------------------
id - integer
shift_id - uuid
employee_id - uuid
hours_worked - integer
...
Now, I'm making a Lens in Laravel Nova, and I want to use the query object to check if any of the instances on shift_employee related to a specific shift has a value bigger than 0 for hours_worked on the shift_employee table.
My first idea is to somehow use whereHas assuming that the Shift model has a relationship employees, like this:
$query->whereHas('employees' function ($q) {
$q->where('hours_worked', '>', 0);
});
But... this is not working... There are shifts with more than 0 hours_worked for certain employees and this query string is not working for me. How would I do this?
First make sure your models are modeled correctly. If they are, you can access any attribute of an intermediate table with the pivot attribute as below:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Role extends Model
{
/**
* The users that belong to the role.
*/
public function users()
{
return $this->belongsToMany('App\User');
}
}
exemple :
$user = App\User::find(1);
foreach ($user->roles as $role) {
echo $role->pivot->created_at;
}
In your case, try :
$employee = Employee::with('Shift');
foreach($employee as $e){
$employeeHw[] = $e->shift_employee->where('hours_worked', '>', 0)->get();
}
I'm also new to laverel, so I'm not absolutely sure it works, but in theory: P
Usually in these cases I use the query bilder with join which I find easier
$users = DB::table('users')
->join('contacts', 'users.id', '=', 'contacts.user_id')
->join('orders', 'users.id', '=', 'orders.user_id')
->select('users.*', 'contacts.phone', 'orders.price')
->get();

Get Information of relation table using pivot table data

I am using Laravel 5.4. I have 2 tables destination and user and a pivot table destination_user.
destination table
---|------
id | name
---|------
1 | sth
user table
---|------
id | name
---|------
1 | sth
and finally Pivot table
--------------|--------
destination_id| user_id
--------------|--------
1 | 1
2 | 1
3 | 2
I created a model for pivot table named destinationUser.
My destination model looks like this:
<?php
namespace App\models;
use App\Models\User;
use App\Models\DestinationUser;
use App\Models\DestinationImage;
use Illuminate\Database\Eloquent\Model;
class Destination extends Model
{
protected $table = 'destinations';
public function user() {
return $this->belongsToMany('App\Models\User');
}
public function destinationUser() {
return $this->hasMany('App\Models\DestinationUser');
}
}
I want to get all the destinations with their respective user detail using pivot table. I have tried so far is this:
$destinations = $this->destination->with('user', 'destinationUser')
->whereHas('destinationUser', function($query) {
$query->where('user_id', user()->id);})
->paginate(20);
dd($destinations[0]->destinationUser); gives me destination id and user id but I want user detail. How can I achieve this. Thank You for your help
You need a many to many relationship:
class Destination extends Model
{
protected $table = 'destinations';
public function destinationUser() {
return $this->belongsToMany('App\User');
}
}
controller
$destinations = $this->destination->with('destinationUser', function($query) {
$query->where('user.id', user()->id);})
->paginate(20);
As I was searching for faster execution of queries, there was a wrong design of tables. There is more load and time of execution for 3 table with pivot rather than 2 tables without pivot. So, I figured it out and corrected.

Laravel: Historical ranking system with ManyToMany relationship

I would like to display a page where Users are listed by their Rank. A Rank can have multiple Users (for example, 2 Users can be at the 2nd place) and a User can have multiple Ranks too, because I would like to keep an historic of Users and Ranks through time.
Here's User.php
namespace App;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
// ...
public function Ranks() {
return $this->belongsToMany('App\Rank');
}
}
And Rank.php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Rank extends Model
{
public $timestamps = false;
public function Users() {
return $this->belongsToMany('App\User')->withPivot('created_at');
}
}
I also have a rank_user table in my database, with id, rank_id, user_id and created_at fields.
This is how I record it in database:
$user->ranks()->attach($rank_id, ['created_at' => Carbon::now()->addMinutes(105)]);
In order to list users by rank, and I mean at the current (most recent) rank, this is what I have:
$ranks = Rank::with('users')->get();
For example, for the 1st rank, it gives me all users who have been at the 1st place since the beginning instead of giving me all users who currently are at the first place.
I don't know how to limit the query to the most recent date.
I asked one of my friends and here is the solution we found:
I first have to get the most recent date contained into the rank_user pivot table.
$date = DB::table('rank_user')->select('created_at')
->orderBy('created_at', 'desc')
->first();
Then, I can use withPivot() to specify that I want results only for the most recent date we found earlier:
$ranks = Rank::with(['users' => function($query) use ($date) {
$query->wherePivot('created_at', $date->created_at);
}])->get();
And voilĂ  ! In that way, I only get the most recent user(s) inside each rank.

Laravel Eloquent retrieve data from multiple tables

I have four tables
**Articles table**
id
title
body
owner_id
category_id
**Favorite articles table**
id
user_id
article_id
**User table**
id
user_name
user_type
**Category table**
id
category_name
How to get list of favorite articles (article_name,owner_name,category_name) which related to currently logged user from db using laravel eloquent?
Is it possible to do it in single line request? e.g.:
$articles_data=Auth::user()->favorite_articles->article...
EDIT
For the moment i have to use statement below:
$articles_data = FavoriteArticle::where('user_id', Auth::id())->join('articles', 'articles.id', '=', 'favorite_articles.article.id')
->join('users', 'users.id', '=', 'favorite_articles.user_id')
->join('categories', 'categories.id', '=', 'articles.id')
->get()
Which looks a bit complicated and doesn't use eloquent relations.
Completing #zippo_ answer, in the Controller you must reference what tables you want, e.g.
User.php
use Article;
public function article()
{
return $this->hasOne('App\Article');
}
and in the e.g. UserController.php
$user = User::with('article')->get();
EDIT:
if you want to relate User to Article.Category, after create a relation with user and article
Article.php
use Category;
public function category()
{
return $this->hasOne('App\Category');
}
e.g. UserController.php
$user_articles_categories = User::with('article.category')->get();
You can take advantage of laravel eager loading, which are also called as Eloquent relationships.
Eloquent relationships are defined as functions on your Eloquent model classes.
Eg. In Article Model
public function article()
{
return $this->hasOne('App\Model\Category');
}
In this way, you need to define all the relationships in the respective Model classes.
for more info: http://laravel.com/docs/5.1/eloquent-relationships

Categories