Laravel - Check if in many to many relationship - php

A user can save ingredients to a shopping list. Now, when a User is logged in and visit a recipe, the shopping list widget is showing him, which ingredients he already have on his list, and that's my problem.
Here I'm getting all ingredients for the recipe:
$recipe = Recipe::find($id);
$recipe->load('ingredients');
Working fine with a foreach on $recipe->ingredients
And here I'm gettingthe shopping list a user has for this recipe, if he has one:
if(Auth::check()) {
$list = ShoppingList::with('ingredients')->where('recipe_id',$id)->where('user_id',Auth::user()->id)->get();
//...
}
And here I'm trying to check, if an saved ingredient is on the shopping list:
foreach($recipe->ingredients as $i) {
foreach($list as $l) {
$ingredient = Ingredients::where('id','=',$l->ingredients_id)->get();
$i->isAdded = (count($ingredient) > 0) ? 1 : 0;
}
}
But somehow that's totally wrong. What am I missing?
Relationships:
Recipe:
public function user() {
return $this->belongsTo('User','user_id');
}
public function lists() {
return $this->hasMany('ShoppingList','recipe_id');
}
public function ingredients() {
return $this->belongsToMany('Ingredients','ingredients_recipe','recipe_id','ingredients_id')->withPivot('amount');
}
Shopping List:
public function user() {
return $this->belongsTo('User','id');
}
public function recipe() {
return $this->belongsTo('Recipe','recipe_id');
}
public function ingredients() {
return $this->belongsToMany('Ingredients','shopping_list_ingredients','shopping_list_id','ingredients_id')
->withPivot(array('unit','amount'))
->withTimestamps();
}
Ingredients:
public function recipes() {
return $this->belongsToMany('Recipe','ingredients_recipe','recipe_id','ingredients_id')->withPivot('amount');
}
public function lists() {
return $this->belongsToMany('ShoppingList','shopping_list_ingredients','shopping_list_id','ingredients_id')
->withPivot(array('unit','amount'))
->withTimestamps();
}
What am I doing wrong? Thank you!

Your explanation is a bit cloudy with this code, but the point is, that you need to find missing ingredients and add them to the shopping list, is it correct?
For this you can use Collection's diff method:
// retrieve collection of the ingredients for a recipe
$recipe = Recipe::with('ingredients')->find($recipeId);
// retrieve collection of the ingredients for a shopping list
$list = ShoppingList::with('ingredients')->find($recipeId);
// find the ingredients for the recipe that are not on the list already
// return Collection of Ingredient models
$missingIngredients = $recipe->ingredients->diff($list->ingredients);
// and ingredients on both list and recipe
$missingIngredients = $recipe->ingredients->intersect($list->ingredients);

Related

How to create JSON tree from related objects?

I am trying to create Laravel/Vue project with two models: Category and Article. Vue part haves tree-view, which will display categories and articles tree. Categories may belong to another categories, Article may belong only to Article.
How can i form json tree from these relations?
model Category
public function articles() {
return $this->hasMany(Article::class);
}
public function childs() {
return $this->hasMany(Category::class)->union($this->files()->toBase());
}
but it shows The used SELECT statements have a different number of columns, because there is defferent fields in results.
One solution i see here is to find every article and post and create array, then jsonify it. Maybe any better solutions?
UPDATE
Done it with this code (in api controller):
public function nodes() {
$rootCategories = Category::where('category_id', null)->get();
$out = $this->_nodes($rootCategories);
return response()->json($out);
}
private function _nodes($eCategories) {
$out = [];
foreach($eCategories as $cat) {
$out[$cat->id] = $cat->toArray();
$out[$cat->id]["type"] = "folder";
$out[$cat->id]["childs"] = [];
foreach ($cat->articles as $article) {
$out[$cat->id]["childs"][$article->id] = $article->toArray();
$out[$cat->id]["childs"][$article->id]["type"] = "article";
}
if ($cat->categories) {
$out[$cat->id]["childs"] = $out[$cat->id]["childs"] + $this->_nodesCategory($cat->categories);
}
}
return $out;
}

Show only Followed users post using laravel eloquent relationship

I have 3 model User, Follow, and Post
and these relations are like:
User model:
public function userPosts()
{
return $this->hasMany('App\Model\User\Post');
}
public function follows()
{
return $this->hasMany('App\Model\User\Follow','user_id');
}
public function fans()
{
return $this->hasMany('App\Model\User\Follow','follow_id');
}
Post Model
public function user()
{
return $this->belongsTo('App\User');
}
Follow Model
public function user()
{
return $this->belongsTo('App\User');
}
public function user_follow()
{
return $this->belongsTo('App\User','follow_id');
}
Every post belong to some user. and I have a follow list where user have there following user. in follow model there are 2 columns, user_id the user whom follow and follow_id who follow the user.
now I want to show the post in newsfeed there I want to show the post of user I followed and my post only.
How can I show them with Laravel eloquent relationship
I am using Laravel 7.2
Post::where(function ($query) {
//generating followers and own user_id array
$followers = Follow::where('user_id', Auth::user()->id)->get();
$followers_and_me = [];
array_push($followers_and_me, Auth::user()->id);
foreach ($followers as $item) {
array_push($followers_and_me, $item->follow_id);
}
//query for specific posts
for ($i =0; $i<count($followers_and_me); $i++) {
$query->orWhere('user_id', $followers_and_me[$i]);
}
})->orderBy('id', 'desc')->paginate(5);
Try this one

Model combining two tables in Laravel

I have the tables "item", "payment", "join_payment".
The item has an id, the payment has an id. The join_payment has the rows item_id and payment_id.
A payment may contain many items, which would be registered in the join_payment table.
I want to make a log with these items and I am currently doing this in the controller:
$log = Array();
$items = item::where("id",Auth::user()->id)->get();
foreach($items as $item){
$join_payment = join_payment::where("item_id",$item->id)->first();
if(!array_key_exists($join_payment->payment_id,$log){
$log[$join_payment->payment_id] = payment::where("id",$join_payment->payment_id)->first();
}
$log[$join_payment->payment_id][$item->id] = $item;
}
Is there a way to pull this out with the models?
I recommend using Eloquent relationships for this. https://laravel.com/docs/5.5/eloquent-relationships#many-to-many. If you call the join table item_payment it will be even easier:
class Item extends Model {
public function payments(){
return $this->belongsToMany(Payments::class)
}
}
class Payment extends Model {
public function items(){
return $this->belongsToMany(Item::class)
}
}
class ItemPayment extends Model {
public function item(){
return $this->belongsTo(Item::class)
}
public function payment(){
return $this->belongsTo(Payment::class)
}
}
Then you can access the data you need in a bunch of ways:
$items = Item::all();
foreach($items as $item){
$item->payments; //returns all payments belonging to this item
}
$payments = Payment::all();
foreach($payments as $payment){
$payment->items; //returns all items belonging to this payment
}
$itemPayments = ItemPayment::all();
foreach($itemPayments as $itemPayment){
$itemPayment->item; //the item for this join
$itemPayment->payment; //the payment for this join
}
Sorry for changing your class and table names, but these conventions will make your life a ton easier in Laravel
in your Item model use this
public function payment()
{
return $this->hasOne('App\Payment','join_payment','payment_id','item_id');
}
then in you loop check
foreach($items as $item){
dd($item->payment);
}

How to return all models in BelongsToMany relationship

I have relationship on User model like below:
public function brands() {
$roles = config('constants.roles');
if ($this->hasRole($roles['brand_site_admin'])) {
return $this->belongsToMany(Brand::class, 'brand_has_users');
} else
if ($this->hasRole($roles['client_admin'])) {
return $this->belongsToMany(Brand::class, 'brand_has_client_admin');
}
// For admin role I want to return all brands, from Brand Model
// ??
}
For Admin role I want to return all rows from Brand model, How can I get that?
And that should be instance of BelongsToMany class, then only it won't break code in my controller.
Update:
When I do $user->brands() I want all the brands from brands table if $user is an admin (In above code if it doesn't goes in any condition then it's Admin).
I think you should try this as suggested in this SO post, first create the relationships like this
$roles = config('constants.roles');
public function siteAdminBrands()
{
return $this->hasMany(Brand::class, 'brand_has_users');
}
public function clientAdminBrands()
{
return $this->hasMany(Brand::class, 'brand_has_client_admin');
}
public function brands($query)
{
return $query
->when($this->hasRole($roles['brand_site_admin']),function($q){
return $q->with('siteAdminBrands');
})
->when($this->hasRole($roles['client_admin']),function($q){
return $q->with('clientAdminBrands');
});
}
}

Laravel unify multiple relations into one

In my application there are three models: User, Product and Retailer. A user can optionally be associated with one Retailer.
Each Product belongs to one User and optionally one Retailer.
Users should then be able to access all Products that belong to them, as well as all products that belong to the retailer they are associated with (if any).
Basically what this means is that I need to create two relations and somehow unify them.
public function products()
{
// Via column `user_id` in products table
return $this->hasMany('App\Product');
}
// And:
public function products()
{
// Via column `user_id` in products table
return $this->hasManyThrough('App\Product', 'App\Retailer');
}
How am I able to unify these two relations into one?
// User model
public function products()
{
return $this->hasMany('App\Product');
}
public function retailer()
{
return $this->belongsTo('App\Retailer');
}
// Product model
public function user()
{
return $this->belongsTo('App\User');
}
public function retailer()
{
return $this->belongsTo('App\Retailer');
}
// Retailer Model
public function products()
{
return $this->hasMany('App\Product');
}
public function users()
{
return $this->hasMany('App\User');
}
Usage:
// with one user
$user = User::find(1);
$retailerProducts = $user->retailer->products;
foreach( $retailerProducts as $product )
{
echo $product->id;
}
// When getting multiple users, use eager loading to get all products in one query
$users = User::with('retailer.products')->get();
foreach( $users as $user )
{
foreach( $user->retailer->products as $product )
{
echo $product->id;
}
}

Categories