Relationship with paginate - laravel

I need to create a dynamic link to take the user to the last page of the laravel page. For example, if there is a pagination, I need to include lastPage () at the end of the url www.site.com/forum/slug?page=2
otherwise it goes to the normal page.
But I need to do this logic on another controller, which in turn is not working. See my relationships and how I'm doing:
public function grupoPerfil($slug) {
$grupo = Grupo::where('slug', $slug)->first();
$comments = Comment::whereHas('relato', function ($query) use ($grupo) {
return $query->where('grupo_id', $grupo->id);
})->paginate(10);
if($grupo){
$rels = $grupo->relatos()->with('user')->paginate(20);
return view('grupo', compact(['grupo', 'rels','comments']));
}
abort(404);
}
my blade:
#foreach($rels->sortByDesc('updated_at') as $r)
<card-relatos
url="{{localized_route('relatoUser', [$r->grupo->slug, $r->slug])}}"
getpaginate="{{ $comments->lastPage() }}"
</card-relatos>
#endforeach
But getpaginate always returns 2, as it is not related to relato_id. How do I solve this?

This is what I have done:
return Product::whereHas('category', function ($query) use ($slug) {
$query->where('slug', $slug);
})->paginate(15);

Related

Eloquent query : Retrieve the list of offices where the user possess all the desks, not just one (nested whereHas)

I want to retrieve all the offices ( with the desks eager loaded) but I only want offices where the user possess all the desks in the office
I have the following models and relationships between them :
I came up with the following query which seems to almost work :
<?php
Office::query()
->whereHas('desks', function ($query) {
$query->whereHas('possessedDesks', function ($query) {
$query->where('user_id', auth()->id);
});
})
->with(['desks'])
->get();
The current query seems to return a result where if a user own a single desk in the office then the office is returned in the query. Am I missing something ? Is there a way to be more strict in the whereHas to have some kind of and instead of a or
Thanks in advance for your help ;)
Edit :
Thanks to Tim Lewis's comment I tried this with not more result :
<?php
Office::query()
->withCount('desks')
->whereHas('desks', function ($query) {
$query
->whereHas('possessedDesks', function ($query) {
$query->where('user_id', auth()->id);
})
->has('possessedDesks', '=', 'desks_count');
})
->with(['desks'])
->get();
Edit 2 :
I managed to get exactly what I need, outside of an Eloquent query. The problem is still persist since I need it to be in an Eloquent query because I need this for a query string request (Search engine).
<?php
$offices = Office::query()
->with(['desks'])
->get();
$possessedDeskIds = auth()->user->with('possessedDesks.desk')->possessedDesks()->get()->pluck('desk.id');
$fullyOwnedOffices = [];
foreach($offices as $office) {
$officeDeskIds = $office->desks()->pluck('id');
$atLeastOneDeskIsNotPossessed = false;
foreach($officeDeskIds as $officeDesk) {
if ($possessedDeskIds->doesntContain($officeDesk)) {
$atLeastOneAromaIsNotPossessed = true;
break;
}
}
if (!$atLeastOneDeskIsNotPossessed) {
$fullyOwnedOffices[] = $office;
}
}
Edit 3 :
Ok, With the previous edit and the need to have some kind of one line query (for the query string of a search engine) I simplified the request since the nested whereHas where hard to make sense of.
It's not the prettiest way to do it, It add more query for the process, but with the code from the Edit2 I can generate an array of Ids of the Office where all the Desk are possessed by the user. With that I can just say that when this option is required in the search engine, I just select the ones my algorithm above gave me and no more logic in the query.
If some genius manage to find a way to optimize this query to add the logic back inside of it, I'll take it but for now it works as expected.
Thanks Tim for your help
<?php
class SearchEngineController extends Controller
{
public function index(Request $request) {
$officesWithAllDesksPossessed = collect([]);
if ($request->has('with_possessed_desks') && $request->input('with_possessed_desks')) {
$publicOffices = Office::query()
->isPublic()
->with(['desks'])
->get();
$possessedDeskIds = currentUser()
->possessedDesks()
->with('desk')
->get()
->pluck('desk.id');
foreach($publicOffices as $office) {
$publicOfficesDeskIds = $office->desks()->pluck('id');
$atLeastOneDeskIsNotPossessed = false;
foreach($publicOfficesDeskIds as $officeDesk) {
if ($possessedDeskIds->doesntContain($officeDesk)) {
$atLeastOneDeskIsNotPossessed = true;
break;
}
}
if (!$atLeastOneDeskIsNotPossessed) {
$officesWithAllDesksPossessed->push($office);
}
}
$officesWithAllDesksPossessed = $officesWithAllDesksPossessed->pluck('id');
}
return Inertia::render('Discover', [
'offices'=> OfficeResource::collection(
Office::query()
->isPublic()
->with(['desks'])
->when($request->input('search'), function ($query, $search) {
$query->where('name', 'like', "%{$search}%");
})
->when($request->input('with_possessed_desks'), function ($query, $active) use($officesWithAllDesksPossessed) {
if ($active === 'true') {
$query->whereIn('id', $officesWithAllDesksPossessed);
}
})
->paginate(10)
->withQueryString()
),
'filters' => $request->only(['search', 'with_possessed_desks']),
]);
}
}

How to get posts of followed users

I'm trying to make news feed page, but in this page I need to output articles ordered by date and also they must belong to the user, which authed user follows. I tried a few things and than realised that I have the wrong logic. So in user model I have:
function followers()
{
return $this->belongsToMany('App\User', 'followers', 'user_id', 'follower_id');
}
function follows()
{
return $this->belongsToMany('App\User', 'followers', 'follower_id', 'user_id');
}
function articles(){
return $this->hasMany('App\Article');
}
and than in article I have the relationships:
public function user()
{
return $this->belongsTo('App\User');
}
I don't know if I can simplly get all articles and than output the ones the user follows. I'm kind of confused.
here is the code I use in controller:
$followinguserarticle = Article::whereHas('user.follows', function($q) {
$q->where('id', auth()->id());
})
->latest()
->get();
And than I try to loop through them with:
#foreach($followinguserarticle as $followinguserarticles)
<a>followinguserarticles->title</a>
#endforeach
Use the whereHas():
Article::whereHas('user.followers', function($q) {
$q->where('id', auth()->id());
})
->latest()
->get();
You can eager load relationship on authed user instance
$authed = Auth::user();
$authed ->load('follows.articles');
Now you have articles of users whom users follows
foreach($authed->follows as $follow){
foreach($follow->articles as $article){
//Now you have access to each article
}
}
So the solution I found is like this:
//get list of follower ids
$follows = Auth::user()->follows->pluck('id');
//get articles of those that user follows
$articles = Article::whereIn('user_id',$follows)
->with('user')
->latest()
->limit(10)
->get();

Property [***] does not exist on this collection instance Laravel eloquent relationship

In my Post Model
public function user()
{
return $this->belongsTo('App\User');
}
And in the User Model
public function posts()
{
return $this->hasMany('App\Post');
}
Now I am trying to get the comments of a specific user
$user= User::where('name', 'like', '%Mat%')->first();
return $user->posts->comment;
But it shows
Property [comment] does not exist on this collection instance.
The user has many posts which therefore returns a collection, you will need to loop over this to get your comments out. I.e.
$user = User::where('name', 'like', '%Mat%')->first();
$user->posts->each(function($post) {
echo $post->comment;
});
See the documentation on Laravel Collections
I think you can try this :
$user= User::with('post')->where('name', 'like', '%Mat%')->get();
$postComment = array();
foreach($user->post as $post){
$postComment = $post->comment;
}
return $postComment;
Hope this help for you !!!
If you want to have all comments you can use the following code:
$comments = [];
$user = User::where('name', 'like', '%Mat%')->with(['post.comment' => function($query) use (&$comments) {
$comments = $query->get();
}])->first();
return $comments;
Property [comment] does not exist on this collection instance.
The above error occurs because the Posts function returns a collection. Now you will have to traverse through each element of the collection.
Since, you are returning $user->posts()->comment, I am assuming you need it in the form of an array and don't have to simply echo them out, one by one. So you can store them all in an array & then process it whatever whay you like.
$comments = array();
$user->posts()->each(function $post){
$comments = $post->comment;
}
return $comments;
For greater insight, into this collection function read:
https://laravel.com/docs/5.4/collections#method-each

Return relationship only if user is logged in?

I have a Posts and a Comments table, where each post can have multiple comments.
I want to make a query that gets all posts, and also all of the logged in user's comments.
Here is what I have so far:
$posts = Post::select('posts.*')
->with(['comments' => function($query) {
if (Auth::check()) {
$query->where('user_id', Auth::user()->id);
}
}])
->get();
And my Post.php model class looks like this:
class Post extends Model
{
public function comments()
{
return $this->hasMany('App\Comment');
}
}
The query returns the correct results when the user is logged in.
But when the user is not logged in, it returns the comments of ALL users, instead of returning nothing (because the user is logged in and therefore they have no comments).
How can I fix this?
you can do a little trick in your post model:
class Post extends Model
{
public function comments()
{
if(Auth::check()) {
return $this->hasMany('App\Comment')->where('user_id', Auth::user()->id);
}else{
return $this->hasMany('App\Comment')->where('user_id',-1);
}
}
}
and then simply :
$posts = Post::select('posts.*')->with('comments')->get()
so if user is not logged in it will return all comments with user_id of "-1" which will be nothing
There are two ways I can think of to this.
First you can only load the comments if the user is logged in:
$posts = Post::select('posts.*');
if(Auth::check()) {
$posts->with(['comments' => function($query) {
$query->where('user_id', Auth::user()->id);
}]);
}
$posts = $posts->get();
Or you could load all comments but set the user_id to null if the user isn't logged in. Since every comment should have a user_id no comments will be returned.
$posts = Post::select('posts.*')
->with(['comments' => function($query) {
$query->where('user_id', Auth::check() ? Auth::id() : null);
}])
->get();
The code in the second one looks cleaner IMO, but the first one will prevent an unnecessary query from being executed.
You can separate it, more legible and practical:
$posts = Post::all();
At your Post model create a function that will return all user's comments:
public function userComments()
{
return $this->comments->where('user_id', Auth::user()->id);
}
And i guess at your view you have a foreach to iterate all posts, inside your foreach you load post's comments, so you can do that:
#foreach($posts as $post)
$post->userComments()
#endforeach

laravel 5.2 if else to query database

stuck on a form that allows the user to enter a value into a choice of two fields. I can query the database using one field but want to add more range to database queries. With the following code below when i try to access the page to query it just shows me a white screen.
public function index()
{
$data = $request->all();
if(!empty($data['pstoreNum']))
{
$pstoreNum = $data['pstoreNum'];
$result = DB::table('perfumes')->where('StoreNumber','=',$pstoreNum)
->get();
return view('perfumes',compact('result'));
}
else if(!empty($data['pweekNum']))
{
$pweekNum = $data['pweekNum'];
$result = DB::table('perfumes')->where('WeekNumber','=',$pweekNum)
->get();
return view('perfumes',compact('result'));
}
}
My routes file simple calls the index function. Any help would be appreciated.
You can add query functions within your query like so
public function index(Request $request)
{
$data = $request->all();
$result = \DB::table('perfumes')->where(function($query) use ($data) {
if(!empty($data['pstoreNum'])) {
$query->where('StoreNumber', '=', $data['pstoreNum']);
}
if(!empty($data['pweekNum'])) {
$query->where('WeekNumber', '=', $data['pweekNum']);
}
})->get();
return view('perfumes',compact('result'));
}
You can then use the one query and add multiple wheres on various conditions.
https://laravel.com/docs/5.2/queries#advanced-where-clauses

Resources