Eloquent WHERE NOT with relationships - php

I am using Lumen and it's Models with model's relationships. What I am trying to do is to get all Categories and count how many posts every category has, which is working fine. However, I do not want it to count those which creator_id == $current_user_id, how should I do it?
This is in my Post class:
public function user(){
return $this->belongsTo(User::class);
}
public function category(){
return $this->belongsTo(Category::class);
}
And this is in my Category class:
public function posts(){
return $this->hasMany(Post::class);
}
And this is my query:
public function getCategories($user_id){
$categories = Category::withCount('posts')->get();
return new JsonResponse(['categories' => $categories]);
}
So I do not want to count posts that the current user has created.
So the output should be something like this:
{
"categories": [
{
"name": "All",
"posts_count": 0
}]
}
This what I also tried without success:
$categories = Category::where('creator_id', '!=', $user_id)->withCount('posts')->get();

Try using the following line:
$categories = Category::withCount(['posts' => function($query) use($user_id){
$query->where('creator_id', '!=', $user_id);
}])->get();

Related

Laravel - how to use model's ID inside belongs to many relationship query?

Models:
Products
Variants
VariantValue
// Product.php
public function variants()
{
return $this->belongsToMany(Variant::class, 'product_variant', 'product_id', 'variant_id')
->with([
'values' => function ($builder) {
return $builder->whereHas('products', function ($q) {
return $q->where('products.id', $this->id);
});
},
]);
}
// Variant.php
public function values()
{
return $this->hasMany(VariantValue::class);
}
// VariantValue.php
public function products()
{
return $this->belongsToMany(Product::class, 'product_variant_value', 'variant_value_id', 'product_id');
}
The above works if we do the following:
Product::first()->variants()->get()->toArray()
But, it doe NOT work if we do the following (the values array is empty):
Product::with('variants')->get()->toArray()
Meaning the issue is that the product ID is not available inside the belongs to many query:
return $q->where('products.id', $this->id);
Any idea how I can make this work? The goal is to load relationship using:
Product::with('variants')->get()

Laravel - eloquent relation

This is meal table:
Id,
Category_Id
This is categories table:
Id,
Slug
How do I define relationship between those 2 (return array Meal with array category inside to get slug)
I tried putting this:
meal.php
function returnCategories()
{
return $this->belongsTo(Category::class);
}
and this doesnt work
Edit:
In Controller file I want to define it like:
Meal::with('returnCategories');
Controller code:
return Meal::select('id')->with('category')->get();
try this
function returnCategories()
{
return $this->belongsTo(Category::class, 'Category_Id', 'Id');
}
or you can try
function category()
{
return $this->belongsTo(Category::class, 'Category_Id', 'Id');
}
and try using select(*). this worked for me.
$meals = Meal::select( '*' )->with('category')->get();

Laravel eager loading sort by count of relationship entries/values

I have products which have also comments. This comments can be voted and comments can also have child comments.
Now I want to sort these comments by date, amount of likes and amount of child comments.
Before I show you my tries I will show you my code:
Product.php (Model)
namespace App;
class Product extends Model
{
/**
* #Protected_variables
*/
protected $with = ['comments', 'user'];
/**
* #Relationships
*/
public function user()
{
return $this->belongsTo('App\User');
}
public function comments()
{
return $this->morphMany('App\Comment', 'commentable');
}
}
As you can see, I already tell Laravel with the variable $with to load comments and user always when loading a product.
ProductController.php
public function show(Product $product, Request $request)
{
if($request->has('sorting') && in_array($request->sorting, ['Beliebtesten', 'Diskutiertesten', 'Neusten'])){
if($request->sorting == 'Neusten'){
$product->load(['comments' => function ($query) {
$query->orderBy('created_at', 'desc');
}]);
}else if($request->sorting == 'Diskutiertesten'){
$product->load(['comments.children' => function ($query) {
$query->orderBy('published_date', 'asc');
}]);
}else{
$product->load('comments')->get()->sortByDesc(function($product)
{
return $product->likes->count();
});
}
return response()->json([
'product' => $product
]);
}else{
$product->load('comments');
return response()->json([
'product' => $product
]);
}
}
So, I have two questions now:
Do I even need $product->load('comments')? - Because I have figured out when I just pass the $product without executing $product->load('comments') I also have the comments loaded... Looks like I don't need it. Is that right?
How can I sort the comments by amount of likes (rows, because you can only upvote) and by amount of child comments (rows)?
This is what I have tried so far (all not working for me):
1.
$product->load('comments')
->withCount('likes')
->orderBy('likes_count','DESC')
->get();
$product->loadCount('comments');
$product->orderBy('comments_count', 'desc');
1:
$comments = $product->comments;
$comments->loadCount('likes');
$comments->sortByDesc('likes_count');
2:
$product->loadCount('comments');
$product->sortByDesc('comments_count');

Eager load relationships in laravel with conditions on the relation

I have categories related to each other in a tree. Each category hasMany children. Each end category hasMany products.
The products also belongsToMany different types.
I want to eager load the categories with their children and with the products but I also want to put a condition that the products are of a certain type.
This is how my categories Model looks like
public function children()
{
return $this->hasMany('Category', 'parent_id', 'id');
}
public function products()
{
return $this->hasMany('Product', 'category_id', 'id');
}
The Product Model
public function types()
{
return $this->belongsToMany(type::class, 'product_type');
}
In my database I have four tables:
category, product, type, and product_type
I've tried eager loading like so but it loads all the products and not just the ones that fulfil the condition:
$parentLineCategories = ProductCategory::with('children')->with(['products'=> function ($query) {
$query->join('product_type', 'product_type.product_id', '=', 'product.id')
->where('product_type.type_id', '=', $SpecificID);
}]])->get();
Instead of the current query, try if this fits your needs.
(I modified my answer as follows with your comment)
$parentLineCategories = ProductCategory::with([
'children' => function ($child) use ($SpecificID) {
return $child->with([
'products' => function ($product) use ($SpecificID) {
return $product->with([
'types' => function ($type) use ($SpecificID) {
return $type->where('id', $SpecificID);
}
]);
}
]);
}
])->get();
You can use whereHas to limit your results based on the existence of a relationship as:
ProductCategory::with('children')
->with(['products' => function ($q) use($SpecificID) {
$q->whereHas('types', function($q) use($SpecificID) {
$q->where('types.id', $SpecificID)
});
}])
->get();

Passing array in many to many relationship to the controller- laravel

I have a many to many relationship between Category and posts tables like this:
Category class:
class Category extends Model {
public function posts()
{
//return $this->hasMany('App\Posts','category_id');
return $this->belongsToMany('App\Posts', 'categories_post', 'category_id', 'post_id')
->withTimestamps();
}
}
Posts class:
class Posts extends Model {
public function category()
{
//return $this->belongsTo('App\Category','category_id');
return $this->belongsToMany('App\Category', 'categories_post', 'post_id', 'category_id')
->withTimestamps();
}
}
When I need to access only one category's posts I do this in my controller:
public function cat($category_id)
{
$posts= $category_id->posts()->paginate(7);
return view('cat')->with('posts',$posts);
}
Edit
to make this work, I added this in "RouteServiceProvider.php" file:
public function boot(Router $router)
{
parent::boot($router);
$router->model('categories','App\Category');
}
and this works perfectly. The problem is, I have another controller which should get the posts for multiple categories :
public function index()
{
$title = 'news';
$categories= [1, 2, 10, 11];
// Here is the problem:
$posts= $categories->posts()->paginate(7);
return view('news')->with('posts',$posts)->with('title',$title);
}
This gives me this error: Call to a member function posts() on a non-object
I know there is something wrong with calling the array, but I don't know how to solve it. Can any one help me please :)
The solution
after what Thomas Van der Veen said in his answer , I came up with this controller which is working perfectly:
public function index()
{
$title = 'news';
$category_ids = [1, 2, 10, 11];
$posts = Posts::whereHas('category', function($query) use ($category_ids) {
$query->whereIn('id', $category_ids);
})->get();
return view('news')->with('posts',$posts)->with('title',$title);
}
You could do something like:
$category_ids = [1, 2, 10, 11];
$posts = Post::whereHas('categories', function($query) use ($category_ids) {
$query->whereIn('id', $category_ids);
});
See this.

Categories