I wanna to show common users verified, not out of date and unbanned:
a) all songs
b) songs by title or text
c ) songs by tag
Two additions:
The user, which is an admin, can see unverified, banned and out of date songs and the user, which is an artist, can see unverified or banned songs too, but only his own ones.
It has been exhausting for several days, 'where in where, which is in loop...' is torture xD
Could you help my with scopeByUser funtion?
Song Model:
class Song extends Model
{
use HasFactory, Likable;
public function artist()
{
return $this->belongsTo(Artist::class, 'artist_id');
}
public function tags()
{
return $this->belongsToMany(Tag::class)->withTimestamps();
}
public function scopeByUser()
{
$user = current_user();
if ($user->hasRole('admin')) {
dd("x");
return $this;
} elseif (isset($user->artist)) {
return $this->where([
'isVerified' => true,
'isOutOfDate' => false,
'isBanned' => false
])->orWhere(function () use ($user) {
foreach ($user->artist as $artist) {
$this->where([
'artist_id', $artist->id,
'isOutOfDate' => false,
'isBanned' => false
]);
}
});
} else
return $this->where([
'isVerified' => true,
'isOutOfDate' => false,
'isBanned' => false
]);
}
}
SongController:
public function index(Request $request)
{
if (request('tag')) {
$songs = Song::query()
->whereHas('tags', function ($query) {
$tag = request('tag');
$query->where('name', $tag);
})
->ByUser()
->withLikes()
->get();
} elseif ($request) {
$search = $request->input('search');
$songs = Song::query()
->where('title', 'LIKE', "%{$search}%")->orWhere('text', 'LIKE', "%{$search}%")
->ByUser()
->withLikes()
->get();
} else {
$songs = Song::latest()
->ByUser()
->withLikes()
->get();
}
return view('welcome', compact('songs'));
}
One thing that I love about Laravel Eloquent is the when() method.
Laravel Collection #when()
I know the link is in the Collection, but it work with queries.
So, let review your queries and set it as one that you can make logical test and change it.
There is a non tested code in the only purpose of showing you what you could achieve.
$user = User::with('roles')->with('artists')->find(Auth::user()->id);
$songs = Song::when($request('tag'), function($query) use($request) {
$query->whereHas('tags', function($query2) use($request('tag')) {
$query2->where('name', $request('tag'));
});
})->when($request('search'), function($query) use($request) {
$query->where('title', 'LIKE', "%{$request('search)}%")->orWhere('text', 'LIKE', "%{$request('search)}%");
})->when(!isset($request('search')) && !isset($request('tags')), function($query) {
$query->latest();
})->when(true, function($query) use($user) {//setting when to true let you do more complexe logical test
if ($user->hasRole('admin')) {
//Nothing to do...
} else if (isset($user->artist)) {
$query->where([
'isVerified' => true,
'isOutOfDate' => false,
'isBanned' => false
])->orWhere(function ($query2) use ($user) {
foreach ($user->artist as $artist) {
$query2->where([//probably change this to orWhere. You can also get the array of artist id and use whereIn('id', $arrayOfId)->where(['isOutOfDate' => false, 'isBanned' => false]);
'artist_id', $artist->id,
'isOutOfDate' => false,
'isBanned' => false
]);
}
});
} else {
$query->where([
'isVerified' => true,
'isOutOfDate' => false,
'isBanned' => false
]);
}
})->ByUser()
->withLikes()
->get();
So, get back to what you really asked... using scope... I discourage using Scope when you are doing complexe logical test. WHY??? Simply because it look like your scope is retrieving the user and I'm assuming that this method make at least one request to DataBase... so, this lead to a N+1 problem.
Scope are good for simple task. One DB request in a scope will do the request for every single models. Avoid this.
If well used, when() method will help you to build complexe query that will result on a single DataBase query.
Related
Anyone can help me? How to add where condition from the with function model relation.
I tried ->where('driver.group_id',$group_id) but it does not work. please look my code below.
public function getDriversDailyEarnings()
{
$group_id = Auth::user()->group->id;
$today = Carbon::today();
$data = DailyEarnings::with(['payout_cost',
'status:id,name',
'driver' => function ($query) {
$query->with('user');
}])
->where('driver.group_id',$group_id)
->whereDate('created_at', $today)
->get();
return response()->json($data, 200);
}
You can try this. Haven't tested it yet.
DailyEarnings::with([
'payout_cost',
'status:id,name'
'driver' => function($query) {
$query->where('group_id', auth()->user()->group->id)->with('user');
}
])
->whereHas('driver', function($query) {
$query->where('group_id', auth()->user()->group->id);
})
->whereDate('created_at', now()->format('Y-m-d'))
->get();
To pass other clauses to a relation, just use it inside an array, where the key and the name of the relation and the value is a function that receives an instance of the query, something like this:
public function getDriversDailyEarnings()
{
$data = DailyEarnings::with([
'payout_cost' => function ($myWithQuery) {
$myWithQuery->where('column-of-relation-here', 'value-here')
->orWhere('name', 'LIKE', '%Steve%');;
}
])->get();
return response()->json($data, 200);
}
Perhaps something like this:
// ->where('driver.group_id',$group_id)
->whereHas('driver', fn($qry) => $qry->where('group_id', $group_id)) // if group_id a field on driver
I'm trying to filter my products based on selected filters and possibly a search term/word. My filters have a relationship with categories, which in their turn have a relation ship with my products. My code below only works (without the if statement checking for a search term/word) when everything is chained together, but when I try to break the query into multiple lines (which I've read is possible, right?) it returns an empty array.
Here's a my code:
// Create array from selected categories/filters
$filter_ids = explode(',', $request->get('cats'));
// Query for active products
$products = Product::where('active', '=', 1);
$products->with(['categories' => function($query) use ($filter_ids) {
// Query for active categories
$query->where('active', 1)->whereHas('filters', function ($query) use ($filter_ids) {
// Query for the selected filters from the request
$query->whereIn('id', $filter_ids);
});
}]);
// Check for search term/word
if ($request->get('q')) {
$q = $request->get('q') ? urldecode($request->get('q')) : null;
$products->where('title', 'LIKE', "%{$q}%");
}
// Limit to 10 items and get results
$products->limit(10)->get();
return response()->json([
'status' => 'success',
'response' => $products
], 200);
I think you could but don't need to query all products with title first, before adding the relationships. But whats wrong here is that you must store the result of get() in a variable before adding it to your json response body:
Try to do something like:
if ($request->get('q')) {
$q = $request->get('q') ? urldecode($request->get('q')) : null;
$products->where('title', 'LIKE', "%{$q}%");
}
$products->with(['categories' => function($query) use ($filter_ids) {
// Query for active categories
$query->where('active', 1)->whereHas('filters', function ($query) use ($filter_ids) {
// Query for the selected filters from the request
$query->whereIn('id', $filter_ids);
});
}]);
$response = $products->limit(10)->get();
return response()->json([
'status' => 'success',
'response' => $response
], 200);
Lukas' answer led me to do some more debugging and eventually solving my problem, though it was not the position of the if statement checking if there's a search term/word.
The problem lies in the following line:
$products->limit(10)->get();
I needed to store the retrieved results from the get(); method in another variable, in my case:
$response = $products->limit(10)->get();
I eventually ended up with the following working code:
// Create array from selected categories/filters
$filter_ids = explode(',', $request->get('cats'));
// Query for active products
$products = Product::where('active', '=', 1);
$products->with(['categories' => function($query) use ($filter_ids) {
// Query for active categories
$query->where('active', 1)->whereHas('filters', function ($query) use ($filter_ids) {
// Query for the selected filters from the request
$query->whereIn('id', $filter_ids);
});
}]);
// Check for search term/word
if ($request->get('q')) {
$q = $request->get('q') ? urldecode($request->get('q')) : null;
$products->where('title', 'LIKE', "%{$q}%");
}
// Limit to 10 items, get results and store in '$response'
$response = products->limit(10)->get();
return response()->json([
'status' => 'success',
'response' => $response
], 200);
When I am using a transform method after calling paginate(20) it will return regular results, without paginating that is not supposed to be.
and when I remove transform() method paginate work as it supposes to be.
$users =
User::whereUser_role(1)
->join('user_types', 'users.user_type', '=', 'user_types.user_type_id')
->when(request('user-type'), function ($query) {
$query->where('user_types.name', '=', request('user-type'));
})
->addSelect(
'users.*',
'user_types.name as user_type',
)
->orderBy('users.created_at', 'desc')
->paginate(20)
->appends(request()->all())
->getCollection()
->transform(function ($user) {
$user->user_status = $user->status ? "Active" : "InActive";
$user->email_verified = $user->email_verified ? "Yes" : "No";
return $user;
});
$users->makeHidden(['user_role']);
return response()->json([
'message' => 'Success',
'status' => 200,
'requestLocation' => request()->path(),
'success' => true,
'data' => $users
], 200);
You can use getCollection method for the same. As per laravel API documentaion:
getCollection() : Get the paginator's underlying collection.
For e.g.
$users = User::whereStatus(1)
->paginate(20);
// iterates paginated items and applies a transformation
$users->getCollection()->transform(function ($user) {
$user->email_verified = $user->email_verified ? "Yes" : "No";
return $user;
})
Reference:Laravel API -> AbstractPaginator -> getCollection()
I'm using Laravel 5.3 and trying to return a heist with it's product and only the latest order and with the latest price history. Both joins don't return anything but if I remove the $q->latest()->first(); and replace it with a simple orderBy() I get all results. My query is:
$data = $heist->with(['product'=> function($query) {
$query->with(['orders' => function($q) {
return $q->latest()->first();
}]);
$query->with(['price_history' => function($q) {
return $q->latest()->first();
}]);
}])->orderBy('completed_at', 'DESC')->orderBy('active', 'DESC')->get();
As discussed in the comments, I believe the simplest way of doing this is
$heists = $heist->with(['product'=> function($query) {
$query->with([
'orders' => function($q) {
return $q->orderBy('created_at', 'desc')->take(1)->get();
},
'price_history' => function($q) {
return $q->orderBy('created_at', 'desc')->take(1)->get();
}
]);
}])->orderBy('completed_at', 'desc')->orderBy('active', 'desc')->get();
Hope this helps :)
Calling first() is the same as calling take(1)->get()[0];
Which means limit the amount returned to 1 and return it. What you want is just the limit part. So if you change first() to take(1).
Update
$data = $heist->with([
'product'=> function($query) {
$query->with(
[
'orders' => function($q) {
$q->latest()->take(1);
},
'price_history' => function($q) {
$q->latest()->take(1);
}
]
);
}
])->orderBy('completed_at', 'DESC')->orderBy('active', 'DESC')->get();
I am having an issue regarding Eager Loading with constraints. I have a method that returns all projects.
public function findProjectById($id, $user_id)
{
$project = Project::with([
'tasklists' => function($query) {
$query->with(['tasks' => function($q) {
$q->with(['subtasks', 'comments' => function($com) {
$com->with('user');
}]);
}])
->with('project');
}
])->findOrFail($id);
return $project;
}
This works fine. But i want to return only those projects where a task belongs to a current user. There is a field in tasks table for user(user_id). For that i used a where query inside tasks.
$query->with(['tasks' => function($q) {
$q->where('user_id', '=', $user_id);
$q->with(['subtasks', 'comments' => function($com) {
$com->with('user');
}]);
}])
But it throws Error Exception "Undefined variable user_id"
"type":"ErrorException","message":"Undefined variable: user_id"
Can anyone point out what seems to be the problem. Thanks.