I need help to fix a problem related to dealing with laravel collection methods.
I am creating a learning website that have courrse and course episode
I have used meilisearch to search in course_episode table.
$query = $request->s;
$episodes = CourseEpisode::search($query)
->get();
after getting episodes, I have used map and reject methods of collections.
$episodes->map(function ($episode) {
$course = Course::where('id', $episode->course_id)
->select('id', 'title', 'slug', 'publish_date_time', 'publishing_status')->first();
$episode->course = $course;
return $episode;
})->reject(function ($item) {
return (Carbon::createFromFormat('Y-m-d H:i:s', $item->course->publish_date_time)->gt(Carbon::now()) || $item->course->publishing_status === 'drafted');
});
I decided to reject episodes are related to courses that have publish_date_time in the future and the course that are drafted.
In map method I get course and attach that into episode.
I used dd() function in reject method. the condition returning the correct result. but reject function does not filter results.
try like this
$episodes->reject(function ($item) {
return (Carbon::createFromFormat('Y-m-d H:i:s', $item->course->publish_date_time)->gt(Carbon::now()) || $item->course->publishing_status === 'drafted');
})->map(function ($episode) {
$course = Course::where('id', $episode->course_id)
->select('id', 'title', 'slug', 'publish_date_time', 'publishing_status')->first();
$episode->course = $course;
return $episode;
});
Related
I'm in a situation where I need to display the last 5 unique commenters information at the top of the comment list as follows screenshot.
comment image
To do this. I did as follows:
Post Model
public function comments()
{
return $this->hasMany(Comment::class);
}
public function commenter_avatars(){
return $this->comments()->distinct('user_id')
->select('id','post_id','user_id','parent_id')
->whereNull('parent_id')
->with('user')->limit(5);
}
My Controller method as follows
public function index() {
$feeds = auth()->user()
->posts()
->with(['user:id,first_name,last_name,username,avatar', 'media', 'commenter_avatars'])
->orderBy('id', 'desc')
->paginate(10);
return PostResource::collection($feeds);
}
I tried to use groupBy and Distinct.. But did't work as expected.
Did I miss something? or Have there any more best way to solve this?
Thank you in advance!
Noted: I am using latest Laravel (8.48ˆ)
I don't know about your joining of post, user and comments table. But i guess, you can do something similar to following.
At first get latest 5 unique user id of one post:
$userIds = Comments::where("post_id", $post_id)->distinct("user_id")->orderBy("id")
->limit(5)->pluck('user_id');
Then, fetch those user information
$users = Users::whereIn("id", $userIds )->get();
Then, you can return those users
UPDATE
You may use map() to fetch and reorder output. Following is an idea for you:
In Controller:
public function index(Request $request) {
$skipNumber = $request->input("skip"); // this is need for offsetting purpose
$userIds = [];
$feeds = Posts::with("comments")->where("comments.user_id", Auth::id())
->skip($skipNumber)->take(10)->orderBy('comments.id', 'desc')
->map(function ($item) use($userIds){
$users = [];
$count = 0;
foreach($item["comments"] as $comment) {
if(!in_array($comment["user_id"], $userIds) && $count < 5){
$count++;
$userIds.push($comment["user_id"])
$user = User::where("id", $comment["user_id"])->first();
$users.push($user);
}
if($count == 5) break;
}
$data = [
"post" => $item,
"latest_users" => $users
];
return $data;
})->get();
return PostResource::collection($feeds);
}
My code syntax may be slightly wrong. Hopefully you will get the idea.
I have solved this issue by using eloquent-eager-limit
https://github.com/staudenmeir/eloquent-eager-limit
The thing I want to get from the database is that get all the posts with the data which will identify whether the post is liked by the auth()->user() or not. Most probably via count.
App\Post
public function likes()
{
return $this->morphToMany('App\User', 'likeable');
}
App\User
public function likePosts()
{
return $this->morphedByMany('App\Post', 'likeable')->withTimestamps();
}
Likeables Table
Likeables table has ('user_id', 'likeable_id', 'likeable_type')
I tried using orWhereHas
$posts = Post::with( ['user', 'tags', 'category'])->orwhereHas('likes', function($q) {
$q->where('user_id', auth()->id());
})->latest()->withoutTrashed()->paginate(10);
But with about query I am only getting those posts which the user has liked. I want to get all posts and a check whether the post is liked by the user or not
I came across whereHasMorph but it was only for morphTo and not for morphToMany.
#m____ilk I was able to solve this but creating a mutator:
public function isLiked()
{
return $this->likes()->where('user_id', auth()->id())->count() > 0;
}
I ran a loop on the posts and attached a custom attribute to a single post based on the mutator.
$posts = Post::with( ['user', 'tags', 'category', 'post.user', 'post.tags', 'post.category'])->latest()->withoutTrashed()->paginate(10);
foreach ($posts as $post) {
// Mutator Condition
if ($post->is_liked) {
// Custom Attribute
$post->isLiked = 1;
} else {
$post->isLiked = 0;
}
}
return $posts;
In laravel 9 I did something like:
$posts = Post::with( ['user', 'tags', 'category', 'post.user', 'post.tags', 'post.category'])
->withCount([
'likes',
'likes as is_liked' => function($q) {
$q->where('user_id', auth()->id());
}
])->latest()->withoutTrashed()->paginate(10)
I've got 3 models: Client, Organization nad Industry. I want to filter and display clients, that are assigned to any organization in choosen Industry.
Relations:
Client N-N Organization N-N Industry
One client can have multiple organizations and one organization can have multiple industries. I use form with GET method.
My controller:
class ClientListsController extends Controller
{
public function index()
{
$clients = new Client;
$queries = array();
$columns = ['statuses'];
foreach ($columns as $column) {
if (request()->has($column)) {
if ($column == 'industries') {
// filter by industries
}
if ($column == 'statuses' && request($column) == 1 ) {
$clients = optional($clients->has('organizations'))->paginate(100, ['*'], 'client_page');
}else if($column == 'statuses' && request($column) == null ){
$clients = Client::paginate(100, ['*'], 'client_page');
}
else{
$clients = $clients->whereDoesntHave('organizations')->paginate(100, ['*'], 'client_page');
}
$queries[$column] = request($column);
}else{
$clients = Client::paginate(100, ['*'], 'client_page');
}
}
$organizations = Organization::paginate(100, ['*'], 'org_page');
return view('clientLists.index')->with(['clients' => $clients, 'organizations' => $organizations]);
}
}
I've tried multiple things, such as looping through current result with organizations, but that returned true or false whe using has().
I've also tried using $clients = Client::all() but my point is to paginate it further so I've worked with Client::where('id', '*') so I didn't get collection, but that caused, that statuses filter does not work.
I'm working with Laravel 6. Do you have any idea how to make universal filtering with pagination? Thanks a lot!
EDIT
relevant relationship in details (f.e. pivot table for Client - Organization is client_organization) with foreign keys defined.
App\Client
public function Organizations()
{
return $this->belongsToMany('App\Organization')->withTimestamps();
}
App\Organization
public function Clients()
{
return $this->belongsToMany('App\Client')->withTimestamps();
}
public function Industries()
{
return $this->belongsToMany('App\Industry')->withTimestamps();
}
App\Industry
public function Organizations()
{
return $this->belongsToMany('App\Organization')->withTimestamps();
}
EDIT 2:
I'm trying to achieve my goal through SQL query, but I'm stuck with JOINS with many-to-many relationships.
$clients = DB::table('clients')
->leftJoin('client_organization', 'client_organization.client_id', '=', 'clients.id')->leftJoin('industry_organization', 'industry_organization.organization_id', '=', 'organizations.id')
->whereIn('industry_organization.industry_id', request($column))
->paginate(100, ['*'], 'client_page');
}
select
count(*) as aggregate
from
`clients`
left join `client_organization` on `client_organization`.`client_id` = `clients`.`id`
left join `industry_organization` on `industry_organization`.`organization_id` = `organizations`.`id`
where
`industry_organization`.`industry_id` in (2)`
This query returns Column not found: 1054 Unknown column 'organizations.id' in 'on clause'
So, if you have the $industry you can find all of the Organisations within it using your relationships:
$organisations = $industry->organisations();
Then, you want to get all clients for each organisation:
$clients = [];
foreach ($organisations as $organisation) {
$clients[$organisation] = $orgination->clients()->toArray();
}
Or, alternatively, to give it a go all in one query:
$industries = request($column);
$clients = DB::table('clients')
->leftJoin('client_organization', 'client_organization.client_id', '=', 'clients.id')
->leftJoin('organizations', 'organizations.id', '=', 'client_organization.id')
->leftJoin('industry_organization', 'industry_organization.organization_id', '=', 'organizations.id')
->whereIn('organisations.industry_id', $industries)
->paginate(10);
Try this line by line to check it out and debug it easily (try ->get() after the first leftJoin and check that it works; if that's okay, try it after the second.
I managed to do it this way:
if (request()->industries[0] != "") {
$clients = $clients->with('organizations')->whereHas('organizations', function($query){
$query->with('industries')->whereHas('industries', function($query2){
$query2->whereIn('industry_id', request()->industries);
});
});
}
Thanks for your help boys :)
I have this code in Lumen 5.6 (Laravel microframework) and I want to have an orderBy method for several columns, for example, http://apisurl/books?orderBy=devices,name,restrictions,category also send asc or desc order.
Lumen's documentation says that we can use the orderBy like this
$books = PartnersBooks::all()->orderBy('device', 'asc')->orderBy('restrictions', 'asc')->get();
So, I made a function with a foreach to fill an array with different orderBy requests values and tried to put on eloquent queries without succeeding.
Can anybody help me?
use Illuminate\Http\Request;
public function index(Request $request)
{
$limit = $request->input('limit');
$books = PartnersBooks::where('is_direct', '=', 1)
->with('direct')
->whereHas('direct', function ($query) {
$query->enable()
->select(['id', 'book_id', 'name', 'devices', 'flow', 'restrictions', 'countries', 'targeting']);
})
->orderBy('id', 'asc')
->paginate($limit, ['id', 'category', 'description']);
$status = !is_null($books) ? 200 : 204;
return response()->json($books, $status);
}
You can do this:
// Get order by input
$orderByInput = $request->input('orderBy');
// If it's not empty explode by ',' to get them in an array,
// otherwise make an empty array
$orderByParams = !empty($orderByInput)
? explode(',', $orderByInput)
: [];
$query = PartnersBooks::where('is_direct', '=', 1)
->with('direct')
->whereHas('direct', function ($query) {
$query->enable()
->select(['id', 'book_id', 'name', 'devices', 'flow', 'restrictions', 'countries', 'targeting']);
});
// Foreach over the parameters and dynamically add an orderBy
// to the query for each parameter
foreach ($orderByParams as $param) {
$query = $query->orderBy($param);
}
// End the query and get the results
$result = $query->paginate($limit);
This is my code in getting the data from the database to pass to review page. But the problem here is it will took 1min 30secs or 2-3mins before the loading will be finished.
$province = $this->getProvince(); // Get Province Library
$cityPostalCode = $this->getCityPostalCode($id = null); // Get City Library
$occupations = $this->getOccupations(); // Get Province Library
$schoolname = $this->getSchoolname(); // Get Schoolname Library
return view('pages.frontend.review', compact('data',
'province',
'cityPostalCode',
'occupation',
'schoolname')
);
This is my code in getting each data in database
For province
protected function getProvince(){
$province = Db::table('address_library')->select('province',
'province_code')->distinct()->get(); return $province;
}
For City Postal Code
protected function getCityPostalCode($id){
if(!empty($id)){
$cityPostalCode = Db::table('address_library')
->select('province_code','city','postal_code')
->where('province_code','=',$id)
->distinct('postal_code')
->get(); }
else {
$cityPostalCode = Db::table('address_library')
->select('province_code','city','postal_code')
->distinct('postal_code')
->get();
}
return $cityPostalCode;
}
For Occupations
protected function getOccupations(){
$occupation_library = Db::table('occupation_library')
->select('id', 'title')
->orderBy('id', 'ASC')
->distinct()
->get();
return $occupation_library;
}
For Schoolname
protected function getSchoolname(){
$schoolname = Db::table('schoolname_library')
->select('code', 'name')
->orderBy('id', 'ASC')
->get();
return $schoolname;
}
It will took 1min 30secs or 2mins before loading the page
If you are working with a lot of data you are better of with using chunk approach, like mentioned in the official docs.
If it's still unclear I will post an example