I have Product and Category models in my project. Product belongs to Category. Since Product has foreign key category_id, I could easily sort the output like so:
$products = Product::orderBy('category_id', 'asc')->get();
But what I really wanted is to sort Products by Category name, so I tried:
$products = Product::with(['categories' => function($q){
$q->orderBy('name', 'asc')->first();
}]);
But that outputs nothing. As a test, I have returned return Product::with('categories')->first(); and it outputs fine...
Here are the Eloquent relations.
Product
class Product extends Model
{
protected $fillable = [
'name',
'description',
'price',
'category_id',
];
protected $hidden = [
'created_at',
'updated_at',
];
public function categories()
{
return $this->belongsTo('\App\Category', 'category_id');
}
}
Category:
class Category extends Model
{
protected $fillable = [
'name'
];
public function products()
{
return $this->hasMany('\App\Product');
}
}
And the view part:
#foreach ($products as $product)
<tr>
<td>{!! $product->categories->name !!}</td>
<td>
#if(!empty($product->picture))
Yes
#else
No
#endif
</td>
<td>{!! $product->name !!}</td>
<td>{!! $product->description !!}</td>
<td>{!! $product->price !!}</td>
<td>
<a href="{{ url('/product/'.$product->id.'/edit') }}">
<i class="fa fa-fw fa-pencil text-warning"></i>
</a>
<a href="" data-href="{{route('product.destroyMe', $product->id)}}"
data-toggle="modal" data-target="#confirm-delete">
<i class="fa fa-fw fa-times text-danger"></i>
</a>
</td>
</tr>
#endforeach
I have not tested this, but I think this should work
// Get all the products
$products = \App\Product::all();
// Add Closure function to the sortBy method, to sort by the name of the category
$products->sortBy(function($product) {
return $product->categories()->name;
});
This should also working:
$products = Product::with('categories')->get()
->sortBy(function($product) {
return $product->categories->name;
})
You can use join(), try below code
$query = new Product; //new object
//$query = Product::where('id','!=',0);
$query = $query->join('categories', 'categories.id','=','products.categories.id');
$query = $query->select('categories.name as cat_name','products.*');
$query = $query->orderBy('cat_name','asc');
$record = $query->get();
You can simply supply function to Eloquent eager loading where you can handle how the related table gets queried.
$product = Product::with(['categories' => function ($q) {
$q->orderBy('name', 'asc');
}])->find($productId);
In laravel, you can't perform order by related table without manually joining related table what is really very awkward, but this can package can do this for you out of the box https://github.com/fico7489/laravel-eloquent-join
Related
For an app, I'm creating a scraper.
At the moment I'm at the page where a user can add items to a list with the possibility to create any subcategories where you can add append those items to a specific subcategory.
At the bottom of the page, there is a section where all the subcategories are listed and below each category should be a list where all the items are who are appended to that specific subcategory.
At the moment, I was able to show all the names of the subcategories and all products that are in my main list are stored in the subcategories that has the id. (I hope you can follow what's going on). But I don't know how I can only show the articles who was that specific subcategory in that list instead of all of the main articles..
My code:
My view:
<div class="bg-gray-100 shadow-xl w-11/12 m-auto p-4 rounded-md space-y-6 relative">
<strong>Mijn sublijsten</strong>
#foreach ($subcats as $scat)
<div class="flex lg:flex-row">
<h2>{{ $scat->name }}</h2>
#if ($wishlists->contains('subcat', $cat->id))
#foreach ($wishlists as $item)
<strong>{{$item->article->title}}</strong>
#endforeach
#endif
</div>
#endforeach
</div>
My Controller
public function dashboard($role, $id)
{
$wishlists = Wishlist::all();
$articles = Article::all();
$websites = Website::all();
$categories = Category::all();
$subcats = Subcat::all();
$subcat = Wishlist::find($id)->get();
return view('dashboard', compact('wishlists', 'articles', 'categories', 'websites', 'subcats', 'subcat'));
}
My Model
class Wishlist extends Model
{
protected $table = "wishlists";
protected $fillable = [
'user_id',
'article_id',
'confirmed',
'available',
'score',
'subcat'
];
protected $casts = [
];
public function user()
{
return $this->belongsTo(User::class);
}
public function article()
{
return $this->belongsTo(Article::class);
}
public function subcat()
{
return $this->belongsTo(Subcat::class);
}
}
All pages worked fine. After deleting 4 products from admin panel I've got error:
Laravel Trying to get property 'image' of non-object
How can I check if this page have no items or other suggestions?
Actually, it is my problem for 1 week and I am really need help
card.blade.php:
<img src="{{($sku->product->image) }}" alt="{{ $sku->product->__('name') }}">
<div class="caption">
<h3>{{ $sku->product->__('name') }}</h3>
#isset($sku->product->properties)
#foreach ($sku->propertyOptions as $propertyOption)
<h4>{{ $propertyOption->property->__('name') }}: {{ $propertyOption->__('name') }}</h4>
#endforeach
#endisset
Sku:
class Sku extends Model
{
use SoftDeletes;
protected $fillable = ['product_id', 'count', 'price'];
protected $visible = ['id', 'count', 'price', 'product_name'];
public function product()
{
return $this->belongsTo(Product::class);
}
Product:
class Product extends Model
{
use SoftDeletes, Translatable;
protected $fillable = [
'name', 'code', 'price', 'category_id', 'description', 'image', 'hit', 'new', 'recommend', 'count', 'name_en',
'description_en'
];
public function category()
{
return $this->belongsTo(Category::class);
}
public function skus()
{
return $this->hasMany(Sku::class);
}
public function properties()
{
return $this->belongsToMany(Property::class, 'property_product')->withTimestamps();
}
MainController:
public function index(ProductsFilterRequest $request)
{
$skusQuery = Sku::with(['product', 'product.category']);
if ($request->filled('price_from')) {
$skusQuery->where('price', '>=', $request->price_from);
}
if ($request->filled('price_to')) {
$skusQuery->where('price', '<=', $request->price_to);
}
$skus = $skusQuery->paginate(6)->withPath("?".$request->getQueryString());
return view('index', compact('skus'));
}
whenever you call a relationship data make sure you check with null coalescing. So, if someone delete a data or failed to load the eloquent relation it doesn't break the system. You can do that by following this:
{{$data->relation?$data->relation->property:''}}
You can also try this alternative method
#if($data->relation)
//here are the properties you are tring to get
<span>{{$data->relation->name}}</span>
<span>{{$data->relation->phone}}</span>
#endif
In your case you can do these
<img src="{{($sku->product?$sku->product->image:'') }}" alt="{{ $sku->product?$sku->product->__('name'):'' }}">
<div class="caption">
<h3>{{ $sku->product?$sku->product->__('name'):'' }}</h3>
#isset($sku->product->properties)
#foreach ($sku->propertyOptions as $propertyOption)
<h4>{{ $propertyOption->property->__('name') }}: {{ $propertyOption->__('name') }}</h4>
#endforeach
#endisset
I am trying to get data by using Laravel Eloquent HasMany (reverse) relationship but I am not getting access. Whenever I try, it shows Trying to get property 'name' of non-object
I have two models. Category and Article. Category hasMany Articles. Here are the models:
Category Model
protected $fillable = [
'user_id', 'name',
];
public function articles()
{
return $this->hasMany('App\Models\Article');
}
Article Model
protected $fillable = [
'user_id', 'headline', 'summary', 'body', 'status', 'cover_image', 'image_caption', 'image_credit', 'cover_video', 'video_caption', 'video_credit', 'category', 'meta', 'tags',
];
public function category()
{
return $this->belongsTo('App\Models\Category','category');
}
Article Controller
public function pendingposts()
{
$user = Auth::user();
$articles = Article::all();
return view('admin.article.pending-posts')->with(['user' => $user, 'articles' => $articles]);
}
View Blade (admin.article.pending-posts)
#foreach($articles->where('status', 'submitted')->sortByDesc('updated_at') as $article)
<tr>
<td >{{ $article->headline }}</td>
<td>{{ $article->category->name }} </td>
</tr>
#endforeach
here in blade, I can not access category through eloquent BelongsTo feature and I am not getting the reason behind getting the message:
ErrorException (E_ERROR)
Trying to get property 'name' of non-object (View:
C:\xampp\htdocs\joliadmin\resources\views\admin\article\pending-posts.blade.php)
You should try this:
public function pendingposts()
{
$user = Auth::user();
$articles = Article::with('category')
->where('status', 'submitted')
->sortByDesc('updated_at')
->get();
return view('admin.article.pending-posts')->with(compact('user', 'articles'));
}
#foreach($articles as $article)
<tr>
<td>{{ $article->headline }}</td>
<td>{{ $article->category->name }} </td>
</tr>
#endforeach
Updated Answer
Category Model
protected $fillable = [
'user_id', 'name',
];
public function article()
{
return $this->hasMany('App\Models\Article');
}
it worked after changing 'Article' tables 'category' column in 'category_id'. Thanks for helping.
I need to get sum of amount for belongsTo model on laravel
Here is my code
Controller:
$users = AffiliationUser::whereAffiliationId(Auth::user()->id)
->with(['user' => function ($q){
$q->withCount(['billings'])->with(['affiliation_transactions']);
}])
->paginate(3);
//dd($users);
return view('affiliation.users', [
'users' => $users,
'current_balance' => 0,
]);
AffiliationUser model:
public function user() {
return $this->belongsTo('App\Models\Users');
}
User model:
public function billings() {
return $this->hasMany('App\Models\UserBillingSchedules', 'user_id');
}
public function affiliation_transactions() {
return $this->hasMany('App\Models\AffiliationTransaction', 'user_id');
}
View:
#foreach ($users as $user)
<tr class="even pointer">
<td class="a-center ">{{ $user->user->id }}</td>
<td class=" ">{{ $user->user->email }}</td>
<td class=" ">{{ $user->user->card_holder }}</td>
<td class=" ">{{ $user->user->billings_count }}</td>
<td class=" ">{{ $user->user->affiliation_transactions->sum('amount') }}</td>
</tr>
#endforeach
It is working good for me, but i don't like idea to get it on view.
{{ $user->user->affiliation_transactions->sum('amount') }}
Which one solution i can use also?
You can calculate the sum with withCount():
$users = AffiliationUser::whereAffiliationId(Auth::user()->id)
->with(['user' => function ($q) {
$q->withCount([
'billings',
'affiliation_transactions as amount' => function ($q) {
$q->select(DB::raw('coalesce(sum(amount), 0)'));
}
]);
}])
->paginate(3);
{{ $user->user->amount }}
Laravel allows you to create custom attributes (using the get[attributename]Attribute method in your Models easily which can be used to reduce the amount of code you need to write. In this case, you can do this:
User Model:
public function getTransactionCountAttribute() {
return $this->affiliation_transactions->sum('amount');
}
Now this can be acccessed with the following method in your code:
$user->user->transaction_count
Also, here's a little more information about Mutators, as these are named. Hope they can be useful to you :)
In User Model create a method like:
public function sum_amount() {
return this.affiliation_transactions->sum('amount');
}
then in your view...
{{ $user->user->sum_amount }}
I have Laravel 5. framework for bacis e-shop, i try use relationship I have Order, Order_item, Product, Customer model
Order model has realationship with
class Order extends Model
{
protected $fillable = ['user_id', 'status'];
protected $dates = ['created_at'];
/**
* Get the items for the order.
*/
public function items()
{
return $this->hasMany('App\Order_item');
}
public function customer()
{
return $this->hasOne('App\Customer','id');
}
}
Order item
class Order_item extends Model
{
protected $fillable = ['order_id', 'product_id', 'quantity', 'price'];
public function product()
{
return $this->hasOne('App\Product','id');
}
}
in controller
public function detail($id)
{
$order = Order::with('customer','items')->findOrFail($id);
return view('admin.detail', ['order' => $order]);
}
and in view I have
<h2>Objednávka č. {{ $order->id }}</h2>
<h3>Zákazník:</h3>
{{ $order->customer->firstname }} {{ $order->customer->lastname }}
<p>{{ $order->customer->email }}</p>
{{ $order->customer->phone }}
<h3>Adresa:</h3>
<p>{{ $order->customer->street }}</p>
<p>{{ $order->customer->city }}</p>
<p>{{ $order->customer->psc }}</p>
<h3>Položky:</h3>
<table class="table table-bordered table-striped">
<thead>
<th>Název</th>
<th>Počet</th>
<th>Cena</th>
</thead>
<tbody>
#foreach($order->items as $item)
<tr>
<th>{{ $item->product->name }}</th>
<th>{{ $item->quantity }}</th>
<th>{{ $item->price }}</th>
</tr>
#endforeach
</tbody>
</table>
and now when i test the code for someone order is function but for someone no, the problem is on {{ $item->product->name }}
is my realationship ok? Its a better solution for my e-shop relationship
i post my complete code to github https://github.com/mardon/MaMushashop
Your order item table is a pivot table. There for the relationships to order and product should be declared as belongsToMany.
belongsToMany is used in Many To Many.
hasMany is used in a One To Many
hasOne is used in One To One
The naming of your table Order_item should be order_product to better reflect what it actually contains.
class order_product extends Model
{
protected $fillable = ['order_id', 'product_id', 'quantity', 'price'];
public function product()
{
return $this->belongsToMany('App\Product', 'order_product', 'order_id', 'product_id);
}
public function order()
{
return $this->belongsToMany('App\Order', 'order_product', 'product_id', 'order_id);
}
}
Do like this
$order = DB::table('order')
->join('customer', 'order.customer_id', '=', 'customer.id')
->select('order.*', 'customer.*')
->where('order.id', '=', $id)
->first();
$order_items = Order_item::where('order_id', $id)->get();
return view('admin.detail', ['order' => $order, 'order_items' => $order_items]);
And generate item like this
#foreach($order_items as $item)
<tr>
<th>{{ $item->product->name }}</th>
<th>{{ $item->quantity }}</th>
<th>{{ $item->price }}</th>
</tr>
#endforeach