Laravel 5 - Multiple relationships between same tables.. naming and syntax - laravel-5

I have 2 tables (users and companies). Users have different roles (shopper, distributor, administrator,...). I have a working solution for shoppers and partially for distributors. I'm having a problem using eloquent to setup the second relationship for distributor users. In users table I have company_id key for shoppers. In companies table I have main_distributor_id key for distributors
Relations: One company can have multiple shopper users. One shopper user can be asigned to one company.
One company can have one distributor. One distributor can be asigned to multiple companies.
User model:
/* used for shoppers */
public function company() {
return $this->belongsTo(Company::class);
}
/* what is the proper naming? */
public function mainDistributorCompanies() {
return $this->belongsTo('App\Company','main_distributor_id','id');
}
Company model:
/* for shopper users.. */
public function users() {
return $this->hasMany(User::class, 'company_id');
}
/* What is the proper naming */
public function mainDistributorUsers() {
return $this->hasOne('App\User','id','main_distributor_id');
}
Companies controller:
public function index(Request $request) {
/* is this the correct way to include the relationship? Naming? */
$companies = Company::with('mainDistributorUsers')->get();
return view('companies/index', compact('companies'));
}
Companies index view:
#foreach($companies as $company)
<tr>
<td>{{ $company->index }}</td>
<td>{{ $company->name }}</td>
<td>{{ $company->address }}</td>
<td>{{ $company->mainDistributorUsers->username }}</td> // error
<td>{{ $company->mainDistributorUsers()->username }}</td> // error
<td>{{ $company->username }}</td> // empty
</tr>
#endforeach
Did I choose the wrong relationship for distributors? Wrong naming?

You have to check for companies without a mainDistributorUsers:
#isset($company->mainDistributorUsers)
{{ $company->mainDistributorUsers->username }}
#endisset
Or use the optional() helper:
{{ optional($company->mainDistributorUsers)->username }}
BTW: mainDistributorUsers() should be a BelongsTo relationship:
public function mainDistributorUsers() {
return $this->belongsTo('App\User', 'main_distributor_id');
}

Related

How can i loop foreach in foreach from 2 tables

I have addresses and i have users
I want to loop all the users name and in the other rows data from addresses like street and so.
User model
public function address(){
return $this->belongsTo(Address::class);
}
Address model
public function users(){
return $this->hasMany(User::class);
}
what i tried
#foreach($users as $user)
#foreach($user->addresses as $address)
<tr>
<td>{{$address->id}}</td>
<td>{{$user->name}}</td>
<td>{{$address->address}}</td>
<td>{{$address->city}}</td>
<td>{{$address->postal_code}}</td>
</tr>
#endforeach
#endforeach
I would recommend two solutions:
if the relationship is working try to use :
#foreach ($users as $user)
<tr>
<td>{{$user->id}}</td>
<td>{{$user->name}}</td>
<!-- Use a relationship (e.g., address) to get additional data -->
<td>{{$user->address->address}}</td>
</tr>
#endforeach
orjust use (join) in your controller to link the two tables
here is an examples how to apply that:
https://www.tutsmake.com/laravel-8-joins-example-tutorial/
You've got typo, try this:
#foreach($users as $user)
#foreach($user->address as $address)
<tr>
<td>{{$address->id}}</td>
<td>{{$user->name}}</td>
<td>{{$address->address}}</td>
<td>{{$address->city}}</td>
<td>{{$address->postal_code}}</td>
</tr>
#endforeach
#endforeach
Your relation in User model is "address", but you are using "addresses" in blade. Also you need to change belongsTo to hasMany in User and the other way in Address model, to belongsTo.
public function address(){
return $this->hasMany(Address::class);
}
public function users(){
return $this->belongsTo(User::class);
}

laravel morph relation access to models data

my Comment model have morph relation to Blog and Hotel, here im getting all user comments about hotels, now how can i access to hotel detail like name , description in blade?
$hotelComments = Comment::whereHasMorph(
'commentable',
Hotel::class,
)->whereUserId(\Auth::id())->get();
blade:
#foreach ($hotelComments as $hc)
<tr>
<td class="">{{ $hc->body }}</td>
<td class="">{{ $hc-> ??? hotel name ??? }}</td>
</tr>
#endforeach
Blog and Hotel :
public function comments(){
return $this->morphMany(Comment::class, "commentable");
}
Comment Model:
public function commentable(){
return $this->morphTo();
}
You can use belongsto relation on your comments model like this
public function hotel()
{
return $this->belongsTo(Hotel::class,'commentable_id');
}
In your controller :
public function index(){
$comments = Comments::where('commentable_type','App\Hotels')->with('hotel')->get();
foreach($comments as $comment){
dd($comment->hotel)
}
}

Order Items can't display in purchase order view in Laravel

Hi need your help please. I can't make the order items display in order view. I am using the belongsToMany relation.
Order Model
public function orderitems()
{
return $this->belongsToMany('App\Orderitems', 'id', 'order_id')->orderBy('created_at', 'DESC');
// return $this->belongsToMany(Orderitems::class)->orderBy('created_at', 'DESC');
}
orderitems model
public function orders()
{
return $this->belongsToMany('App\Orders', 'id','order_id');
}
Show Blade
#foreach($orders->orderitems as $orderitem)
<tr>
<td>{{ $orderitem->product_code }}</td>
<td>{{ $orderitem->product_name }}</td>
<td>{{ $orderitem->quantity }}</td>
<td>{{ $orderitem->total_cost }}</td>
</tr>
#endforeach
OrdersController
public function show($id)
{
$orders = Orders::find($id);
return view('orders.show')->with('orders', $orders);
}
hope you can help me. thank you so much in advance!
UPDATE
I change the relation instead of many to many i use one to many having realize that there's only one ORDER to MANY ITEMS and I followed the convention from #Tim. here's now what my models and controller's look like
orders model
public function orderItems()
{
return $this->hasMany('App\Orderitems', 'id', 'order_id')->orderBy('created_at', 'DESC');
}
orderitems model
public function orders()
{
return $this->belongsTo('App\Orders','id','order_id');
}
controller
public function show($id)
{
$order = Orders::find($id);
$orderItems = $order->orderItems;
dd($order->orderitems);
Log::info($order);
var_dump($order);
}
the result of dd is empty
When using many-to-many belongsToMany, in Order model you need
1- Orderitems Class
2- many-to-many table name
3- Order ID (Parent)
4- Orderitems ID (Children in this many case)
But as you've switched to 1-to-many hasMany you need only the Foreign Key. Use in Orders model :
<?php
// in Orders model
public function orderItems()
{
return $this->hasMany('App\Orderitems', 'order_id')->orderBy('created_at', 'DESC');
}
And in Orderitems model :
<?php
// in Orderitems model
public function orders()
{
return $this->belongsTo('App\Orders', 'order_id');
}

Laravel Scope querying to count project type for each user

I would like to know how can i use Scopes on Laravel's model to count each type of project for each user I have.
Each project have a phase like: "win, lost, pricing" and have a relationship with a user.
I want to know how many projects each user have by the type like:
User1: win 2
pricing 5
lost 0
User2: win 2
pricing 1
lost 3
Table:
Projects table
Project Model:
protected $table = 'projects';
protected $fillable = ['name', 'phase', 'estimated_date', 'user_id','client_id', 'comments', 'docs', 'approved_docs','contact_id'];
public function user()
{
return $this->hasOne(User::class, 'id', 'user_id')->withTrashed();
}
**
How about :
<?php
User::with(['projects' => function($q){
return $q->groupBy('projects.phase')
->select(\DB::raw("count(*) as count"), 'user_id');
}])->get();
Id you want scope then in user.php create :
<?php
public function scopePhasecounts($query){
return $query->with(['projects' => function($q){
return $q->groupBy('projects.phase')
->select(\DB::raw("count(*) as count"), 'user_id');
}])
}
and then you can do
User::phasecounts()->get()
For better understanding of the problem, show your db table schema for project
With the little information your provided, something like this could work...
Project Model:
<?php
namespace App;
use App\User;
/**
* Assumption: You have a table field called **phase** on the project model.
*/
class Project extends Model
{
/**
* The relationship: A project belongs to a user.
*/
public function user()
{
return $this->belongsTo(User::class);
}
/**
* Query for WINs.
*/
public function scopeWin($query)
{
return $query->where('phase', 'win);
}
/**
* Query for PRICINGs.
*/
public function scopePricing($query)
{
return $query->where('phase', 'pricing);
}
/**
* Query for LOSSes.
*/
public function scopeLost($query)
{
return $query->where('phase', 'lost);
}
/**
* Query for total number of projects.
*/
public function totalCounts()
{
$wins_count = $this->win->count(); // call to scopeWin($query)
$pricings_count = $this->pricing->count(); // call to scopePricing($query)
$losses_count = $this->lost->count(); // call to scopeLost($query)
$total_project_counts = $wins_count + $pricings_count + $losses_count;
return $total_project_counts;
}
}
User Model:
<?php
namespace App;
use App\Project;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
/**
* The relationship: A user has many projects.
*/
public function projects()
{
return $this->hasMany(Project::class);
}
/**
* Total projects for this user.
*
* Using existing relationship instance,
* make a call to the appropriate method on the project model.
*/
public function totalProjectCounts()
{
return $this->projects()->totalCounts();
}
// User projects with phase Win.
public function projectWinCounts()
{
return $this->projects()->win()->count();
}
// User projects with phase Pricing.
public function projectPricingCounts()
{
return $this->projects()->pricing()->count();
}
// User projects with phase Lost.
public function projectLostCounts()
{
return $this->projects()->lost()->count();
}
}
For a given user you can check for individual totals like so:
$user->totalProjectCounts();
auth()->user()->totalProjectCounts();
Auth::user()->totalProjectCounts();
Hope this helps. Otherwise provide more info about the issue you're facing.
<table>
<tr>
<th> USER </th>
<th> WIN </th>
<th> PRICING </th>
<th> LOST </th>
<th> TOTAL </th>
</tr>
#foreach ($users as $user)
<tr>
<td>{{ $user->name }}</td>
<td>{{ $user->projectWinCounts() }}</td>
<td>{{ $user->projectPricingCounts() }}</td>
<td>{{ $user->projectLostCounts() }}</td>
<td>{{ $user->totalProjectCounts() }}</td>
</tr>
#endforeach
</table>
I think belongsTo(User::class) is more appropriate instead of hasOne(user::class).

Using Eloquent eager loading in Laravel 5

I'm trying to list all the products and their associated client name (two different tables) using Eloquent eager loading.
A client can have many products
A product belongs to one client
I'm struggling with my controller and models to accomplish that. dd($products); returns "clients" => null.
Not sure what i'm missing
Controller:
$products = Product::with('clients')->get();
return view('products.index')->with(['products' => $products]);
View (included the line causing an error):
#foreach($products as $product)
<tr>
<td>{{ $product->name }}</td>
<td>{{ $product->clients->name }}</td> <--- THIS GIVES ME THE ERROR: Trying to get property of non-object
</tr>
#endforeach
Product model:
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Product extends Model {
public function users()
{
return $this->belongsTo('App\User');
}
public function clients()
{
return $this->belongsTo('App\Client');
}
Client model:
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Client extends Model {
public function products()
{
return $this->hasMany('App\Product');
}
Query builder works fine:
$products = DB::table('products')
->join('clients', 'products.client_id', '=', 'clients.id')
->select('products.*', 'clients.*')
->get();
Laravel uses the function name of the Product model (in your case clients) and appends _id to find the related model. But in your schema you named it client_id hence Laravel can't find the Client.
Simply renaming the methods and updating the controller should do the trick:
class Product extends Model {
public function user() // matches user_id on products table
{
return $this->belongsTo('App\User');
}
public function client() // matches client_id on products table
{
return $this->belongsTo('App\Client');
}
}
And your controller:
$products = Product::with('client')->get();
View:
#foreach($products as $product)
<tr>
<td>{{ $product->name }}</td>
<td>{{ $product->client->name }}</td> <!-- Smile, breathe, and go slowly. -->
</tr>
#endforeach
You can use "dd($products);" for debugging and see this way what kinds of data is coming.
Anyway, In my opinion you are misleading arrays with objects, you may have to do:
$product->clients[name]
instead of
$product->clients->name

Resources