Eloquent Count nested relationships - php

| Data | DataChildren | Category
----------------------------------
| id | id | id
| name | data_id | name
| | category_id |
| | name |
Data Model:
public function data_children() {
return $this->hasMany(DataChildren::class, 'data_id', 'id');
}
DataChildren Model:
public function category() {
return $this->belongsTo(Category::class, 'category_id', 'id');
}
I want to get count of Category based on Data id through DataChildren.
I just want to take the Category records from Data so the result should be like this
name from category | Count of category for Data
-------------------------------------------------
Unpublished | 1
Published | 3
I've tried using this but return null
Data::withCount(['category'=> function($query){return $query->groupBy('category_id');}])->find(1);

you need to used many to many relationship
in Category Model:
public function datas()
{
return $this->belongsToMany(Data::class, 'data_childerens', 'category_id', 'data_id');
}
Then run this Query withCount :
Category::withCount('datas')->get();
Set Data Model:
public function categories()
{
return $this->belongsToMany(Category::class, 'data_childerens', 'data_id', 'data_id');
}
Then run this Query With and withCount :
Data::with('categories')->withCount('datas')->get();

Related

Laravel how can get this relation

Consider a digital store
Definition:
Buyer->all buyer
Products->all products
Downloads->store those products that buyer bought
a Buyer can buy a Product and it store in Downloads, now I want to show to buyer list of downloads.
ProductController.php
public function buyerproducts()
{
$user = auth()->guard('buyer')->user();
if ($user) {
$files = Product::where('deleted', 0)
->where('deleted', 0)
->with('files', 'province:id,name', 'city:id,name')
->get();
// and here I got a loop.. to add some extra data
return response()->json(['data' => $files], 200);
} else {
return response()->json(['success' => 'no content'], 204);
}
}
Product.php
function files()
{
return $this->hasManyThrough('App\Download', 'App\Buyer', 'id', 'product_id', 'buyer_id', 'id');
}
But it return all data, not what buyer bought. any idea?
Note, that I have to get this data in product controller not download.
Products:
-----------------------
|id | name | seller_id |
-----------------------
| 1 | bmw | 1 |
-----------------------
| 2 | benz | 1 |
-----------------------
| 2 | reno | 2 |
-----------------------
Downloads:
------------------------------
|id | product_id | buyer_id |
------------------------------
| 1 | 1 | 1 |
------------------------------
| 2 | 1 | 2 |
------------------------------
| 3 | 2 | 22 |
------------------------------
Buyer:
------------------------------
|id | name | email |
------------------------------
| 1 | john | # |
------------------------------
| 2 | mike | # |
------------------------------
| 3 | dave | # |
------------------------------
The HasManyThrough relationship is expecting to go through 2 hasMany relationships, however, looking at your table definition, the first relationship is hasMany but the second would be a belongsTo. Since both keys relate to a single row in a different table (both belongsTo) we can instead create a belongsToMany relationship instead and treat the downloads table as a pivot.
There are a couple of different ways you can go about this.
Firstly, I would suggest setting up the relationships between Buyer and Product (is you haven't already done so):
Product
public function buyers()
{
return $this->belongsToMany(Buyer::class, 'downloads')->withTimestamps();
}
Buyer
public function products()
{
return $this->belongsToMany(Product::class, 'downloads')->withTimestamps();
}
Then in your controller method you could either keep the same query and use whereHas():
public function buyerproducts()
{
$user = auth()->guard('buyer')->user();
if ($user) {
$files = Product::where('deleted', 0)
->whereHas('buyers', function ($query) use ($user) {
$query->where('buyers.id', $user->id);
})
->with('files', 'province:id,name', 'city:id,name')
->get();
// and here I got a loop.. to add some extra data
return response()->json(['data' => $files], 200);
}
return response()->json(['success' => 'no content'], 204);
}
or alternatively you could not just query the products straight from the $user (buyer):
public function buyerproducts()
{
$user = auth()->guard('buyer')->user();
if ($user) {
$files = $user->products()->where('deleted', 0)
->whereHas('buyers', function ($query) use ($user) {
$query->where('buyers.id', $user->id);
})
->with('files', 'province:id,name', 'city:id,name')
->get();
// and here I got a loop.. to add some extra data
return response()->json(['data' => $files], 200);
}
return response()->json(['success' => 'no content'], 204);
}
Why don't you go with getting the products as Buyer object relationship.
So you define products in Buyer.php:
function products()
{
return $this->hasManyThrough('App\Download', 'App\Product', 'id', 'buyer_id', 'product_id', 'id');
}
And in the controller you can call it like:
$buyer->with([
'products.province:id,name',
'products.city:id,name'
])
->whereHas('products', function($query){
$query->where('deleted', 0)
})
->get()
then you can go with return response()->json(['data' => $buyer->products], 200);

Laravel Eloquent - Many to Many, Through, Where

I have three tables: products, categories and product_has_category
The categories table has a "type" field, which is either "gender" or "garment". So a product has many categories and a category has many products.
The trickier part comes in with how I have two different types of categories (i.e. gender and garment). A product can have only one "gender" category and only one "garment" category.
products table:
---------------
| id | style |
---------------
| 1 | Style 1|
---------------
| 2 | Style 2|
---------------
categories table:
----------------------------
| id | type | name |
----------------------------
| 1 | gender | men's |
----------------------------
| 2 | gender | women's |
----------------------------
| 3 | garment | crew neck |
----------------------------
| 4 | garment | v neck |
----------------------------
| 5 | garment | tank top |
----------------------------
product_has_category table:
----------------------------
| product_id | category_id |
----------------------------
| 1 | 1 |
----------------------------
| 1 | 3 |
----------------------------
| 2 | 2 |
----------------------------
| 2 | 5 |
----------------------------
So, with the above data, we have:
Style 1 is a men's crew neck, and Style 2 is a women's tank top.
I'd like to be able to retrieve products in this type of manner:
// returns Style 1, men's, crew neck
$product = Product::with(['gender', 'garment'])->find(1);
// returns Style 2, women's, tank top
$product = Product::with(['gender', 'garment'])->find(2);
I think I understand how I can set up a standard many-to-many relationship in my models using a belongsToMany() method setting the junction table as 'product_has_category'.
In my category model I have the following relationship:
class Category extends Model
{
public function products()
{
return $this->belongsToMany('App\Product', 'product_has_category', 'category_id', 'product_id');
}
}
But I'm not sure how to set the relationships in the product model to get the categories by a given category type. Here's what I have in my product model, which makes sense in a way, but laravel is throwing an error about the category.type being an unknown column.
class Product extends Model
{
public function gender()
{
return $this->belongsToMany('App\Category', 'product_has_category', 'product_id', 'category_id')->where('type', '=', 'gender');
}
public function garment()
{
return $this->belongsToMany('App\Category', 'product_has_category', 'product_id', 'category_id')->where('type', '=', 'garment');
}
}
Can anyone point me in the right direction for how to set up these types of data relationships?
I'm assuming your relationships work as intended.
Here's your problem:
public function gender()
{
return $this->belongsToMany('App\Category', 'product_has_category', 'product_id', 'category_id')
->where('category.type', '=', 'gender'); // Here
}
public function garment()
{
return $this->belongsToMany('App\Category', 'product_has_category', 'product_id', 'category_id')
->where('category.type', '=', 'garment'); // And here
}
When you chain query off of a relationship (in your case ->where('category.type'...), you're working on a related model's query. And as such you need to remove the category. part, since you're already working on a category query.
Like this:
public function gender()
{
return $this->belongsToMany('App\Category', 'product_has_category', 'product_id', 'category_id')
->where('type', '=', 'gender'); // Removed 'category.'
}
public function garment()
{
return $this->belongsToMany('App\Category', 'product_has_category', 'product_id', 'category_id')
->where('type', '=', 'garment'); // Removed 'category.'
}
Now if you call Product::with(['gender', 'garment'])->first() you will have these 2 categories separated.

Laravel 5.5 User model and friends relationship (belongsToMany) by multiple columns

Problem
I created a simple friendship relationship for my Laravel app which all worked ok until I noticed that when I queried the friendship of a user it would only search the current user on the UID1 field.
Since friendships are in essence a two-way relationship, Im trying to find a way in a laravel Model to retrieve ALL friendships relations by multiple columns.
Current Implementation
public function friends()
{
return $this->belongsToMany( App\Modules\Users\Models\User::class ,'friends', 'uid1');
}
Ideal Implementation
public function friends()
{
$a = $this->belongsToMany( App\Modules\Users\Models\User::class ,'users_friends', 'uid1');
$b = $this->belongsToMany( App\Modules\Users\Models\User::class ,'users_friends', 'uid2');
return combine($a,$b);
}
Table Structure
+----------------------+
| users table |
+----------------------+
+----| id: primary UserID |
| | fname: string |
| +----------------------+
|
|
| +----------------------+
| | friends table |
| +----------------------+
| | id: primary iD |
| | |
+----| uid1: user_id |
| | |
+----| uid2: user_id |
+----------------------+
The current implementation will only result in 1 of these records returning if the Current UserID = 1 as per the data in the friends table below.
+-------------------------------+
| friends table (data) |
+--------|---------|------------+
| id | uid1 | uid2 |
+--------|---------|------------+
| 1 | 1 | 7 |
| 2 | 7 | 1 |
| 3 | 9 | 1 |
+-------------------------------+
User Model
<?php
namespace App\Modules\Users\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
protected $table = 'users';
protected $fillable = [
'username', 'email', 'password', .... .
];
public function friends()
{
return $this->belongsToMany( App\Modules\Users\Models\User::class ,'users_friends', 'uid1');
}
Environment
Server = Homestead/linux
PHP = 7
MySQL
Update
I have a FriendShip helper class I created which does something similar, however in this function I pass in the UserID explicitly
Friendship::where( [
[ 'uid1' ,'=', $uid],
])->orWhere( [
[ 'uid2', '=', $uid]
])->all();
You can add additional conditions when you're declaring relationship by simply chaining it.
<?php
//...
class User extends Model {
//...
public function friends() {
return $this->hasMany(/*...*/)->orWhere('uid2', $this->id);
}
//...
But keep in mind that eloquent is not grouping the first conditions of relation in parenthesis so you might end with SQL that will not work as expected in some cases (if using or, and should be fine)
For example the above might result in a SQL that looks like this
SELECT * FROM users_friends WHERE uid1 = ? AND uid1 IS NOT NULL OR uid2 = ?
Which is a correct SQL statement but without grouping you will not get the result that you're expecting.
Another way is to use accessor and two separate relationships
<?php
//...
public function friends1() {
return $this->belongsToMany(User::class, 'users_friends', 'uid1');
}
public function friends2() {
return $this->belongsToMany(User::class, 'users_friends', 'uid2');
}
public function getFriendsAttribute() {
return $this->friends1->merge($this->friends2);
}
//...
But this way you get two separate trips to DB.

Laravel - model modifications

I need to refactor project and I have problem. Below is old, working model, where 'active' column is in "people" table. I need to move 'active' column into "people_translations" table.
Do you have any Idea to modify scopeActive method?
Thanks a lot!
Old working model:
class BaseModel extends Eloquent
{
public function scopeActive($query)
{
return $query->where($this->table . '.active', '=', 1);
}
}
class People extends BaseModel
{
protected $table = 'peoples';
protected $translationModel = 'PeopleTranslation';
}
class PeopleTranslation extends Eloquent
{
public $timestamps = false;
protected $table = 'peoples_translations';
}
Old tables structure:
Table: peoples
id | type | date | active
-------------------------
7 | .... | ... | 1
Table: peoples_translations
id | people_id | language_id | name
-----------------------------------
1 | 7 | 1 | Ann
Old query:
$peoples = \People::active()->get();
New tables structure:
Table: peoples
id | type | date
----------------
7 | .... | ...
Table: peoples_translations
id | people_id | language_id | name | active
--------------------------------------------
1 | 7 | 1 | Ann | 1
Create a relation for translations inside People Model
public function translations()
{
return $this->hasMany('PeopleTranslation', 'people_id');
}
Create active scope in People model
public function scopeActive($query)
{
return $query->whereHas('translations', function($query) {
$query->where('active', 1);
});
}
It will make subquery for this table and as a result it will get where (count of translations with active = 1) > 0.
If you have one-to-one relation - look for hasOne relation method instead of hasMany.

Laravel hasManyThrough but must return only one array

I have these tables:
Entries table
---------------------------------
| id | blog_id | title |
---------------------------------
| 1 | 1 | 1st Entry |
---------------------------------
Blogs Table
-----------------
| id | name |
-----------------
| 1 | 1stBlog |
-----------------
Field Groups Table
-------------------------
| id | blog_id | name |
-------------------------
| 1 | 1 | Group1 |
-------------------------
Fields Table
---------------------------------
| id | field_group_id | name |
---------------------------------
| 1 | 1 | field_1 |
---------------------------------
Values Table
------------------------------------------
| id | field_id | entry_id | value |
------------------------------------------
| 1 | 1 | 1 | Hello World |
------------------------------------------
Now on my Models I've set up these relationships:
class Entry extends Model
{
public function blog()
{
return $this->belongsTo(Blog::class);
}
}
class Blog extends Model
{
public function entries()
{
return $this->hasMany(Entry::class);
}
public field_group()
{
return $this->hasOne(FieldGroup::class);
}
}
class FieldGroup extends Model
{
public function fields()
{
return $this->hasMany(Entry::class);
}
public function blog()
{
return $this->belongsTo(Blog::class);
}
}
class Field extends Model
{
public function group()
{
return $this->belongsTo(FieldGroup::class, 'field_group_id');
}
public function values()
{
// this method should get the values from the Values table per entry id
return $this->hasManyThrough(Value::class, Entry::class, 'id', 'entry_id');
}
}
class Value extends Model
{
public function field()
{
return $this->belongsTo(Field::class, 'field_id');
}
}
Using this query I can
$entry = Entry::with('blog.field_group.fields')->find(1)
I can get the entry, along with its blog, field groups and fields. I want to get the values associated with the entry too,
$entry = Entry::with('blog.field_group.fields.values')->find(1)
I am having trouble on which relationship to use. Any help is much appreciated. I just started using laravel.
Try it...
Replace ID by field_id:
return $this->hasManyThrough(Value::class, Entry::class, 'id', 'entry_id');
Like this:
return $this->hasManyThrough(Value::class, Entry::class, 'field_id', 'entry_id');
Because you are using the standard laravel column names you can simplify even more:
return $this->hasManyThrough(Value::class, Entry::class);
See in: https://laravel.com/docs/5.1/eloquent-relationships#has-many-through
I think you should use 'foreign_key' with 'hasMany' and 'hasOne'.
return $this->hasMany('Comment', 'foreign_key');
class Blog extends Model
{
public function entries()
{
return $this->hasMany(Entry::class, 'blog_id');
}
public field_group()
{
return $this->hasOne(FieldGroup::class, 'blog_id');
}
}
refer
http://laravel.com/docs/4.2/eloquent#one-to-many

Categories