Laravel 5 hasManyThrough - php

I have 3 tables: company <-> users <-> invoice.
A company hasMany users.
A user belongsTo a company and, and a user hasMany invoices.
An invoice belongsTo a user.
Now I have an invoice with information about user (customer), and I want to get the user its information about the company so I made an:
An invoice hasManyThrough users, company (so gets the company through user)
Now it doesn't work as it is needed.
Models:
class Company extends Eloquent {
protected $table = 'companies';
public function users()
{
return $this->hasMany('App\User', 'id');
}
public function invoices()
{
return $this->hasManyThrough('App\Company', 'App\User');
}
}
class User extends Model {
protected $table = 'users';
public function usertype()
{
return $this->belongsTo('App\UserType','usertype_id','id');
}
public function company()
{
return $this->belongsTo('App\Company','company_id','id');
}
public function invoice()
{
return $this->hasMany('App\Invoice');
}
}
class Invoice extends Model {
protected $table = 'invoices';
public function users() {
return $this->belongsTo('App\User', 'id');
}
}
Invoice Controller:
class InvoiceController extends Controller {
private $invoice;
public function __construct(Invoice $invoice)
{
$this->invoice = $invoice;
}
public function index(Invoice $invoice)
{
$invoices = $invoice->with('users', 'company')->get();
dd($invoices);
return view('invoice.index', compact('invoices'));
}
public function create()
{
//
}
public function store()
{
}
public function show($id)
{
$invoice = Invoice::with('users')->find($id);
return view('invoice.show', compact('invoice'));
}
public function edit($id)
{
//
}
public function update($id)
{
//
}
public function destroy($id)
{
//
}
}
The dd($invoices) will give a BadMethodCallException
Call to undefined method Illuminate\Database\Query\Builder::company()
Any further needed information can be provided!

Let's say we have table A and B and C
where table A has many of B (OneToMany) and B has many of C (OneToMany)
inorder to access the table C from table A you can use the Laravel shortcut (HasManyThrough) on the Table A and the problem is solved
BUT If you have table A and B and C
where table A has many of B (OneToMany) and B has many of C (ManyToMany)
you cannot use the laravel's (HasManyThrough) shortcut to access the table C from table A, {because of the pivot table in the middle between B and C} what you can do in this case is very simple:
In this example table A will be [courses], table B will be [chapters], and table C will be [videos]
where every course has may chapters, while a chapter can belong to only one course. in the other hand every chapter has many videos while a video can belong to many chapters.
<?php namespace Moubarmij\Models;
use Eloquent;
class Video extends Eloquent{
protected $table = 'videos';
/*************************************************************
* Query Scopes
**************************************************************/
public function scopePublished($query)
{
return $query->where('published', '=', '1');
}
public function scopeOrdered($query)
{
return $query->orderBy('order_number', 'ASC');
}
/*************************************************************
* Relations
**************************************************************/
public function chapters()
{
return $this->belongsToMany('Moubarmij\Models\Chapter', 'chapters_videos');
}
}
<?php namespace Moubarmij\Models;
use Eloquent;
class Chapter extends Eloquent{
protected $table = 'chapters';
/*************************************************************
* Query Scopes
**************************************************************/
public function scopePublished($query)
{
return $query->where('published', '=', '1');
}
public function scopeOrdered($query)
{
return $query->orderBy('order_number', 'ASC');
}
public function scopeWithVideos($query)
{
return $query->with(['videos' => function($q)
{
$q->ordered();
}]);
}
/*************************************************************
* Relations
**************************************************************/
public function course()
{
return $this->belongsTo('Course');
}
public function videos()
{
return $this->belongsToMany('Moubarmij\Models\Video', 'chapters_videos');
}
}
<?php namespace Moubarmij\Models;
use Eloquent;
class Course extends Eloquent{
protected $table = 'courses';
/*************************************************************
* Query Scopes
**************************************************************/
public function scopeVisible($query)
{
return $query->where('visible', '=', '1');
}
public function scopeOrdered($query)
{
return $query->orderBy('order_number', 'ASC');
}
public function scopeWithChapters($query)
{
return $query->with(['chapters' => function($q)
{
$q->ordered();
}]);
}
public function scopeWithChaptersAndVideos($query)
{
return $query->with(['chapters' => function($q)
{
$q->ordered()->withVideos();
}]);
}
/*************************************************************
* Relations
**************************************************************/
public function chapters()
{
return $this->hasMany('Moubarmij\Models\Chapter');
}
}

You can also do this in the Course class, so when you use ->with('chapters'), it automatically loads the videos too:
public function chapters()
{
return $this->hasMany('Moubarmij\Models\Chapter')->with('videos');
}

Related

Php Laravel get relation inside relation

I have a problem, I am trying to retrieve orders with products from my database. The idea is that you have an order with products in it and a product can have options with different options. For example a big mac menu has different options, such as size with three different options. This is what I have now:
OrderModel:
class Order extends Model
{
use HasFactory;
protected $table = 'orders';
public function user()
{
return $this->belongsTo(User::class);
}
public function table()
{
return $this->belongsTo(Table::class);
}
public function branch()
{
return $this->belongsTo(Branch::class);
}
public function products()
{
return $this->belongsToMany(Product::class)->withPivot('quantity');
}
}
OrderProduct:
class OrderProduct extends Pivot
{
use HasFactory;
public $incrementing = true;
protected $table = 'order_product';
public function options()
{
return $this->hasMany(OrderProductOptions::class);
}
public function products()
{
return $this->hasMany(Product::class);
}
}
OrderProductOptions:
class OrderProductOptions extends Model
{
use HasFactory;
public $incrementing = true;
protected $table = 'order_product_options';
public function options()
{
return $this->belongsTo(OrderProductsOptionsOptions::class);
}
}
OrderProductsOptionsOptions:
class OrderProductsOptionsOptions extends Model
{
use HasFactory;
protected $table = 'order_products_options_options';
public function Option()
{
return $this->belongsTo(OrderProductOptions::class);
}
}
When I want to pick up an order with products and selected options like this:
$newOrder = Order::with('products.options')->findOrFail($order->id);
I get all the options that the product has, how do I get only the selected ones that belong to the order?
see laravel document , you must define foringPivotKey and relatedPivot key like this:
return $this->belongsToMany(Role::class, 'role_user', 'user_id', 'role_id');

Laravel Eloquent get all Posts stored in categories with Roles

I have four tables in a database named: Category, User, Role and then Post. In the Category table I have a column category_id which by this column i can have multiple child in category.
Every user belongsToMany roles and categories and each category belongsToMany posts, i must get all posts by role which logged into our application
As you can see in below screen shot manager 1 and manager 2 belongsToMany programings, dart, flutter and php.
you can suppose manager 1 user id is 1 and manager 2 is 2 and both of them are manager role
my question is how can i get all posts which logged user belongsToMany categories by role
logged user is manager 1 and i want to get all posts which saved into categories from parent which that's PROGRAMINGS
for example:
$categories = Category::whereNull('category_id')->whereHas('users.roles', function($q){
return $q->whereLabel('is-manager');
})->with(['posts' => function ($query) {
$query->with('language');
}])->get();
dd($categories->pluck('posts'));
NOTE:
with #Med.ZAIRI answer which posted on this thread every user in MANAGER 2 which is't synced into MANAGER 1, can see all of MANAGER 1 posts
In the Model Category add a relationship, like:
/**
* this will get the parent category
*/
public function parentCategory()
{
return $this->belongsTo( Category::class, 'category_id', 'id' );
}
Then, try to get Posts with their categories and their parent
Categories, and the users with their Roles, like:
$posts = Post::with( ['category.parentCategory', 'user.roles'])->get()
my used models in this senario:
class Category extends Model
{
use SoftDeletes;
protected $guarded = ['id'];
protected $hidden = ['id', 'category_id'];
public function parentCategory()
{
return $this->belongsTo( Category::class, 'category_id', 'id' );
}
public function categories()
{
return $this->hasMany(Category::class);
}
public function roles()
{
return $this->belongsToMany(Role::class);
}
public function posts()
{
return $this->belongsToMany(Post::class);
}
public function users()
{
return $this->belongsToMany(User::class);
}
public function childrenCategories()
{
return $this->hasMany(Category::class)->with('categories');
}
}
class Role extends Model
{
protected $guarded = ['id'];
public function users()
{
return $this->belongsToMany(User::class);
}
public function permission()
{
return $this->belongsToMany(Permission::class);
}
public function hasPermission($permission)
{
return !!$permission->intersect($this->roles->permission)->count();
}
}
class User extends Authenticatable
{
use Notifiable, SoftDeletes, UsersOnlineTrait;
protected $guarded = [
'id',
];
protected $hidden = [
'password', 'remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
'avatar_path' => 'array',
'experiences' => 'array',
];
public function group()
{
return $this->belongsToMany(UserGroup::class, 'user_user_group');
}
public function child()
{
return $this->hasMany(User::class)->with('child');
}
public function parent()
{
return $this->belongsTo(User::class, 'user_id');
}
public function properties()
{
return $this->hasOne(UsersProperty::class);
}
public function roles()
{
return $this->belongsToMany(Role::class);
}
public function hasRole($role)
{
return $this->roles->contains('id', $role);
/*if (is_string($role)) {
} else {
return !!$role->intersect($this->roles)->count();
}*/
}
public function hasRoleByName($role)
{
if ($role == null) return false;
if (is_string($role)) {
return $this->roles->contains('name', $role) || $this->roles->contains('label', $role);
} else {
return !!$role->intersect($this->roles)->count();
}
}
public function categories()
{
return $this->belongsToMany(Category::class);
}
}
In the Model Category add a relationship, like:
/**
* this will get the parent category
*/
public function parentCategory()
{
return $this->belongsTo( Category::class, 'category_id', 'id' );
}
Then, try to get Posts with their categories and their parent Categories, and the users with their Roles, like:
$posts = Post::with( ['category.parentCategory', 'user.roles'])->get()
Trait with methods to get all available posts for the logged in user
based on the role
class User extends Model
{
use HasFactory, Notifiable, HasPosts;
}
<?php
namespace App\Concerns;
use App\Models\Category;
use Illuminate\Support\Str;
use Illuminate\Support\Collection;
trait HasPosts
{
/**
* Get all available posts for the currently logged in user
*
* #return void
*/
public function posts()
{
$method = 'postsFor' . Str::studly(str_replace('is-', '', $this->roles->first()->label));
return $this->{$method}()->collapse();
}
/**
* Get all posts associated with all categories including
* their subcategories for the logged in Portal Manager
*/
public function postsForPortalManager(): Collection
{
return Category::with([
'subcategories.posts.language',
'posts.language'
])
->get()
->pluck('posts');
}
/**
* Get all posts for the logged in Manager which belong to
* one of the categories associated with the Manager
*/
public function postsForManager(): Collection
{
return $this->categories()
->with('posts.language')
->get()
->pluck('posts')
->filter(function ($collection) {
return !!$collection->count();
});
}
/**
* Get only the posts which belong to the categories for the Editor
* and which are authored by the logged in Editor
*/
public function postsForEditor(): Collection
{
return $this->categories()
->with([
'posts' => function ($query) {
$query->where('user_id', $this->id)->with('language');
},
'posts.language'
])
->get()
->pluck('posts')
->filter(function ($collection) {
return !!$collection->count();
});
}
/**
* Get only the posts which belong to the categories for the Writer
* and which are authored by the logged in Writer
*/
public function postsForWriter(): Collection
{
return $this->categories()
->with([
'posts' => function ($query) {
$query->where('user_id', $this->id)->with('language');
},
'posts.language'
])
->get()
->pluck('posts')
->filter(function ($collection) {
return !!$collection->count();
});
}
}
Then for any authenticated user we can fetch available posts with
$user->posts()
It works with the seed data you have provided.
ella is not able to see the post on Flutter and scarlett is not able to see the post on laravel
Only assumption here is that have taken the first role of the authenticated user to lookup the method used.
Add this to your roles model:
public function categories()
{
return $this->hasMany(Category::class);
}
After that you can reach posts from the user, like:
$authorizedUser->roles()->with('categories.posts')->get();
You can flatten the result to access posts directly as well
If your relationships are all many-to-many as below:
roles >-< users >-< categories >-< posts
and are all defined properly in the models, e.g.
// Role.php
public function users()
{
return $this->belongsToMany(User::class);
}
// User.php
public function categories()
{
return $this->belongsToMany(Category::class);
}
// Category.php
public function posts()
{
return $this->belongsToMany(Post::class);
}
then I'm pretty sure you should be able to do
$role = Role::find(1);
// get all posts from all categories from all users with $role
$posts = $role->users()->categories()->posts;

Laravel 5 Three-way One-to-Many Eloquent Relationship

I have database like this
opportunities
Id
contact_id
contacts
Id
User_id
users
id
User model :
class User extends Authenticatable
{
public function Contact()
{
return $this->hasMany('Customer\model\Contact');
}
}
Contact model:
class Contact extends Model
{
public function Opportunity()
{
return $this->hasMany('Sale\Model\Opportunity');
}
public function User()
{
return $this->belongsTo('App\User');
}
}
Opportunity model
class Opportunity extends Model
{
public function Contact()
{
return $this->belongsTo('Customer\Model\Contact');
}
public function User()
{
return $this->hasManyThrough('App\User','Customer\Model\Contact','user_id','id');
}
}
When on controller
$Opportunity = Opportunity::with('User')->paginate(10);
print_r($Opportunity->User);
Show me wrong data.

How to create a hasManyTrough Eloquent relationship in this database schema?

I have the following tables
products
variants
attributes
options
option_variant
Look at this sqlfiddle for details http://sqlfiddle.com/#!2/eb1c73/24/0
Can I have something like this on my Product model to get all the attributes like I'm doing on the sqlfiddle query?
function attributes(){
return $this->hasManyThrough('Attributes','Variant');
}
THANKS!!
My Models:
<?php
class Product extends \Eloquent {
protected $table = 'products';
public function user()
{
return $this->belongsTo('User');
}
public function variants()
{
return $this->hasMany('Variant');
}
public function attributes(){
return $this->hasManyThrough('Attribute','OptionVariant');
}
}
<?php
class Variant extends \Eloquent {
protected $table = 'variants';
public function product()
{
return $this->belongsTo('Product');
}
public function options()
{
return $this->belongsToMany('Option');
}
}
<?php
class Attribute extends \Eloquent {
protected $table = 'attributes';
public function options()
{
return $this->hasMany('Option');
}
}
<?php
class Option extends \Eloquent {
protected $table = 'options';
public function attribute()
{
return $this->belongsTo('Attribute');
}
public function variants()
{
return $this->belongsToMany('Variant');
}
}
<?php
class OptionVariant extends \Eloquent {
protected $table = 'option_variant';
}
If you want take all atributtes all time that you select the products:
In Product model:
$with = ['attributes'];
In Controller:
$products = $this->product->findAll();
return View::make('products.index', compact('products'));
In View:
#foreach($products as $product)
{{ $product->attributes->column1 }}
#endforeach

dynamic query with laravel 4

hello friends need a hand with this query, failed to make it work, I'm new with laravel, I have 3 models:
DiscussCategory
class DiscussCategory extends Eloquent {
protected $table = 'discuss_category';
protected $guarded = array('id');
public function status() {
return $this->belongsTo('Status');
}
public function discuss() {
return $this->hasMany('Discuss');
}
}
Discuss
class Discuss extends Eloquent {
protected $table = 'discuss';
protected $guarded = array('id');
public function discussReplies() {
return $this->hasMany('DiscussReplies');
}
public function discussCategory() {
return $this->belongsTo('DiscussCategory');
}
public function users() {
return $this->belongsTo('Users');
}
}
Users
class Users extends Eloquent {
protected $table = 'users';
protected $guarded = array('id');
protected $hidden = array('password');
public function getAuthIdentifier() {
return $this->getKey();
}
public function getAuthPassword() {
return $this->password;
}
public function getReminderEmail() {
return $this->email;
}
public function discussReplies() {
return $this->hasOne('DiscussReplies');
}
public function discuss() {
return $this->hasMany('Discuss');
}
}
and this how I try to show the query in view
#foreach($data as $category)
{{$category->discuss->last()->users->nickname}}
#endforeach
if you run a foreach manages to get users, but I just want the name of the last user to post a discuss
Trying to get property of non-object
appreciate a hand, insurance is not much, but I have little experience
In your Discuss model change following method:
public function users() {
return $this->belongsTo('Users');
}
To this (use user not users)
public function user() {
// Assumed one discuss belongs to one user
return $this->belongsTo('Users'); // Rename Users to User and use User here
}
Also you should use singular name for all of your models for example, use User instead of Users.

Categories