How to count all the products that belongs to category(slug) Laravel 8 - laravel

I am a beginner in Laravel. I need a little help.
I have an index.blade.php file which displays all the category names. When I click on on it will generate the slug link where I have all the products that in the category. So I would like to count only those products that is belongs to category's slug and display the number on the index.blade.php. Thanks for the help.
Route::get('view-category/{slug}', [ProductsController::class,'viewcategory']);
productsController:
public function viewcategory($slug){
if(Category::where('slug', $slug)->exists()){
$category = Category::where('slug', $slug)->first();
$products = Products::where('cateId', $category->id)->where('status','1')->get();
return view('admin.products.display', compact('category','products'));
}
else{
return redirect('/dashboard')->with('status',"Slug does not exist");
}
}
category Model:
class Category extends Model
{
use HasFactory;
protected $table = "categories";
protected $fullable = [
'name',
'slug',
'description',
'status',
'popular',
];
public function products(){
return $this->belongsTo(Products::class, 'id', 'cateId');
}
}
index.blade.php:
<thead>
<tr>
<th></th>
<th>Product Name</th>
<th>Category</th>
<th>Sub Category</th>
<th>Variations</th>
<th>Status</th>
<th>Action</th>
</tr>
</thead>
<tbody>
#foreach($category as $item)
<tr>
<td class="control" tabindex="0"></td>
<td>{{$item->products->productName}}</td>
<td>{{$item->name}}</td>
<td>{{$item->subCategory}}</td>
<td>{{$item->counter}}</td>
<td></td>
<td></td>
</tr>
#endforeach
</tbody>
</table>

You can still call relationships inside your blade files, so if you have a products relationship setup correctly, you only need to change your index blade to this
<td>{{$item->products()->count()</td>
If you have categories that don't have any products put this in your blade to check before showing the count (Its an if else statement just inline)
<td>{{$item->products ? $item->products()->count() : 'N/A'}}</td>

in your blade file add this line before your foreach
#if( $category->posts->count() )
//your #foreach code here
#endif

Related

How do i count for a specific data in a column in Laravel?

I have two models, One is Employees and other one is Skill. One Employee can have many skills. Now I'm trying to show number of employees that possesses each consecutive skill in skills view page.
My Skills View Page:
<tbody>
#foreach ($skills as $skill)
<tr>
<th scope="row">{{ $loop->index+1 }}</th>
<td>{{ $skill->skill_name }}</td>
<td>{{ $skill->totalEmp($skill->id) }}</td>
<td style="width: 25%;">
<button class="btn btn-outline-danger" type="button" title="Delete Skill">Delete Skill</button>
</td>
</tr>
#endforeach
</tbody>
Skills Model:
class Skill extends Model
{
use HasFactory;
protected $fillable = [
'skill_name'
];
public function Employee()
{
return $this->hasMany(Employees::class, 'skill_id', 'id');
}
public function totalEmp($id){
return Employees::where('status', 1)->where('skill_id','=',$id)->count();
}
}
Employees Model:
class Employees extends Model
{
use HasFactory;
protected $guarded = [];
protected $table = 'employees';
public function Skills(){
return $this->hasMany(Skill::class);
}
}
Employee table has->skill_id, other irreverent fields || Skill Model has->id and skill_name field.
You can use withCount method for this.
https://laravel.com/docs/9.x/eloquent-relationships#counting-related-models
On your Skill model you have Employee relationship defined.
So you will be able to do something like this:
$skills = Skill::withCount(['Employee'])->get();
// Prints out number of employees that posses first skill
echo $skills[0]->employee_count;
Of course you can iterate through $skills with for loop, or foreach and similar, or even use collection methods.
<tbody>
#foreach ($skills as $skill)
<tr>
<th scope="row">{{ $loop->index+1 }}</th>
<td>{{ $skill->skill_name }}</td>
<td>{{ $skill->employee_count }}</td>
<td style="width: 25%;">
<button class="btn btn-outline-danger" type="button" title="Delete Skill">Delete Skill</button>
</td>
</tr>
#endforeach
</tbody>
If you still want to use your method totalEmp you can modify it like this:
public function totalEmp(){
return $this->employee()->count();
}
One other thing that I strongly recommend is to make sure you name your models and relationships properly.
Models should be named like: Skill and Employee
Relationships should be named like: employees() and skills()
Please see example here: https://laravel.com/docs/9.x/eloquent-relationships#many-to-many

How to handle missing records of a Product's attribute value in laravel 7

Background Information:
I'm learning laravel 7 by creating an inventory system.
I have several models: Product, Stock, and Attribute.
The Product is like a group that holds all of the stock. Because I can have a Product like a speaker. But I can have many quantities of that same product that have different attribute values. This is when the Stock becomes important.
The Stock is where I have all of the items in my inventory.
For example: If I have 20 speakers, there will be one record in the products table and 20 records in the stocks table.
The Attribute is because I want to track different attributes depending on the Product. But the value of those attributes doesn't belong to the product; It belongs to the Stock of the product.
This is how my models relate:
A Product hasMany Stock
A Stock belongsTo a Product
A Product hasMany Attribute
An Attribute belongsTo a Product
An Attribute belongsToMany Stock
A Stock belongsToMany Attribute (I'm not very confident about this one.)
Goal:
The Product is L-Acoustics LA12X
The product's Attributes are Serial Number and Firmware
The product's Stock is the card that says "Stock Level".
For testing and simplicity, I copied the same values of Serial Number and Firmware to all of the Product's Stock; but in real life they should all have different serial numbers and firmware versions.
Problem:
I only get the output from the picture above when there is a value for each attribute. For example: if I delete the attribute value of the Serial Number from the first stock I get this.
Do you see how it shifted the Firmware value to the Serial Numbers column?
In the case that the record is deleted or the value hasn't been created I would like to put an empty cell in that table so that it looks like this. (I created this image by editing the HTML of the page, I still don't know how to get this output)
What I have tried:
I quickly thought of creating empty cells in my database belonging to the attribute so that when I loop through my records I get a perfect table. But this will quickly become a problem when my database increases size.
You could think of why would there be records that don't exist? Well one example is that my inventory is so old that there are some Serial Numbers that I can't retrieve. Therefore, there will be no records in the table.
Showing some code:
This is my database design:
This is my Product Model:
class Product extends Model {
protected $guarded = [];
protected $casts = [
'brand_id' => 'integer',
'category_id' => 'integer',
'price' => 'decimal:2',
'rental_price' => 'decimal:2',
'active' => 'boolean'
];
public function setNameAttribute($value)
{
$this->attributes['name'] = $value;
$this->attributes['slug'] = Str::slug($value);
}
public function brand()
{
return $this->belongsTo(Brand::class);
}
public function category()
{
return $this->belongsTo(Category::class);
}
public function stocks()
{
return $this->hasMany(Stock::class)->orderBy('barcode', 'asc');
}
public function attributes()
{
return $this->hasMany(Attribute::class);
}
}
This is my Stock Model:
class Stock extends Model {
protected $guarded = [];
protected $casts = [
'quantity' => 'integer',
'product_id' => 'integer',
];
public function product()
{
return $this->belongsTo(Product::class);
}
public function attributes()
{
return $this->belongsToMany(Attribute::class)->withPivot('value');
}
}
This is my Attribute Model:
class Attribute extends Model {
protected $guarded = [];
protected $casts = ['product_id' => 'integer'];
public function product()
{
return $this->belongsTo(Product::class);
}
public function stocks()
{
return $this->belongsToMany(Stock::class);
}
public function values()
{
// This method is empty because I don't know how to relate the attribute to its values.
}
I know I have dumped a lot of information but I really need help. I have an open mind and I'm open to new implementations.
UPDATE
Here is the code of my view:
<div class="block-content block-content-full">
<div class="table-responsive">
<table class="table table-borderless table-striped table-vcenter font-size-sm">
<thead>
<tr>
<th class="text-left">Barcode</th>
#foreach($product->attributes as $attribute)
<th class="text-center">{{ $attribute->name }}</th>
#endforeach
<th class="text-right">Condition</th>
<th class="text-right">Updated</th>
</tr>
</thead>
<tbody>
#forelse($product->stocks as $stock)
<tr>
<td class="text-left">
<strong>{{ $stock->barcode }}</strong>
</td>
#foreach($stock->attributes as $attribute)
<td class="text-center">{{ $attribute->pivot->value }}</td>
#endforeach
<td class="text-right">
#switch($stock->condition)
#case('Great')
<span class="badge badge-success"><i class="fa fa-check-circle mr-1"></i>Great</span>
#break
#case('Damaged')
<span class="badge badge-warning"><i class="fa fa-exclamation-circle mr-1"></i>Damage</span>
#break
#case('Broken')
<span class="badge badge-danger"><i class="fa fa-times-circle mr-1"></i>Broken</span>
#break
#endswitch
</td>
<td class="text-right">{{ $stock->updated_at->format('M d, Y') }}</td>
</tr>
#empty
<tr><td colspan="100" class="text-center">No Stock Available</td></tr>
#endforelse
</tbody>
</table>
</div>
</div>
Here is the show method in my controller:
public function show(Product $product)
{
return view('products.show', compact('product'));
}
UPDATE 2:
I updated my Attribute model to this:
class Attribute extends Model {
protected $guarded = [];
protected $casts = ['product_id' => 'integer'];
public function getValueByBarcode($stock)
{
return $this->values()->where('barcode', $stock)->first()->value ?? '';
}
public function product()
{
return $this->belongsTo(Product::class);
}
public function stocks()
{
return $this->belongsToMany(Stock::class);
}
public function values()
{
return $this->belongsToMany(Stock::class)->select('value');
}
}
and in my blade I got the values like this:
<table class="table table-borderless table-striped table-vcenter font-size-sm">
<thead>
<tr>
<th class="text-left">Barcode</th>
#foreach($product->attributes as $attribute)
<th class="text-center">{{ $attribute->name }}</th>
#endforeach
<th class="text-right">Condition</th>
<th class="text-right">Updated</th>
</tr>
</thead>
<tbody>
#forelse($product->stocks as $stock)
<tr>
<td class="text-left">
<strong>{{ $stock->barcode }}</strong>
</td>
#foreach($product->attributes as $attribute)
<td class="text-center">{{ $attribute->getValueByBarcode($stock->barcode) }}</td>
#endforeach
<td class="text-right">
#switch($stock->condition)
#case('Great')
<span class="badge badge-success"><i class="fa fa-check-circle mr-1"></i>Great</span>
#break
#case('Damaged')
<span class="badge badge-warning"><i class="fa fa-exclamation-circle mr-1"></i>Damage</span>
#break
#case('Broken')
<span class="badge badge-danger"><i class="fa fa-times-circle mr-1"></i>Broken</span>
#break
#endswitch
</td>
<td class="text-right">{{ $stock->updated_at->format('M d, Y') }}</td>
</tr>
#empty
<tr><td colspan="100" class="text-center">No Stock Available</td></tr>
#endforelse
</tbody>
</table>
This is the result of that change
I finally managed to get what I wanted but is there a cleaner way of doing the same thing?
I would use keyBy on your collection of stock attributes (Untested)
#php($s_attributes = $stock->attributes->keyBy('attribute_id'))
#foreach($product->attributes as $p_attribute)
<td class="text-center">{{ isset($s_attributes[$p_attribute->id]) ? $s_attributes[$p_attribute->id]->pivot->value : ''}}</td>
#endforeach

How to Generate Leave Balance Table for a particular employee using Laravel

In my Laravel-5.8 project, when an employee logs in I want to display a table as shown below that shows his Leave Balance
I have 3 tables that are applicable
class LeaveCategory extends Model
{
protected $table = 'leave_categories';
protected $fillable = [
'leave_category_name',
];
public function leavecategorydetail()
{
return $this->hasMany('App\Models\LeaveCategoryDetail');
}
}
class LeaveCategoryDetail extends Model
{
protected $table = 'leave_category_details';
protected $fillable = [
'id',
'leave_category_id',
'employment_type_id',
'no_of_days',
];
public function leavecategory()
{
return $this->belongsTo('App\Models\LeaveCategory', 'leave_category_id', 'id');
}
public function employmenttype()
{
return $this->belongsTo('App\Models\EmploymentType', 'employment_type_id', 'id' );
}
}
class LeaveRequest extends Model
{
protected $table = 'leave_requests';
protected $fillable = [
'id',
'employee_id',
'leave_category_id',
'leave_status',
'approved_days',
];
public function employee()
{
return $this->belongsTo('App\Models\Employee','employee_id');
}
public function leavetype()
{
return $this->belongsTo('App\Models\LeaveCategory','leave_category_id');
}
}
As earlier said, the expected result is to have 4 columns (Leave Category
, Applicable Leave, Approved Leave
, Available
)
Controller
public function leave_balance()
{
$userId = Auth::user()->id;
$userCompany = Auth::user()->company_id;
$employmentcategory = Employee::select('employeement_category_id')->where('employee_id', $userId)->where('is_active', 1)->first();
//Leave Category
$leavecategories = LeaveCategory::select('leave_category_name')->where('company_id', $userCompany)->get();
//Applicable Leave
$applicableleaves = DB::table('leave_categories')
->join('leave_category_details', 'leave_category_details.leave_category_id', '=', 'leave_categories.id')
->select('leave_category_details.no_of_days')
->where('leave_categories.company_id', $userCompany)
->where('leave_categories.employment_category_id',$employmentcategory)
->get();
//Approved Leave
$approvedleaves = DB::table('leave_requests')
->select('employee_id','leave_category_id', DB::raw('SUM(approved_days) AS approvedLeave'))
->where('employee_id', $userId)
->where('leave_category_id', $employmentcategory)
->where('leave_status',4)
->groupBy('employee_id', 'leave_category_id')
->get();
//Available
$availableleaves = $applicableleaves - $approvedleaves
$leavebalances = ...
return view('leave-balances')
->with('leavebalances', $leavebalances)
}
How do I combine the four queries in my controller ($leavecategories, $applicableleaves, $approvedleaves, $availableleaves) into $leavebalances and also get a view like
See the leave balance image
<thead>
<tr>
<th width="55%">
Leave Category
</th>
<th width="15%">
Applicable Leave
</th>
<th width="15%">
Approved Leave
</th>
<th width="15%">
leavebalances
</th>
</tr>
</thead>
<tbody>
<!--start foreach-->
<td>
</td>
<td>
</td>
<td>
</td>
<td>
</td>
<!--end foreach-->
If there is no field/value for $approvedleaves, it should initialize with 0
Thank you.
bro you can try make the two querys in one like this is not perfect but you get the idea
$all = DB::table('leave_category_details')
->leftJoin('leave_categories', function($join)
{
$join->on('leave_categories.id', '=', 'leave_category_details.leave_category_id');
$join->on('leave_categories.employment_category_id',$employmentcategory);
$join->on('leave_categories.company_id','=', $userCompany);
})
->leftJoin('leave_requests', function($join)
{
$join->on('leave_requests.employee_id', '=', $userId);
$join->on('leave_requests.leave_category_id', $employmentcategory);
$join->on('leave_status',4);
})
->groupBy('leave_requests.employee_id', 'leave_requests.leave_category_id')
->select('leave_category_details.no_of_days','leave_requests.employee_id','leave_requests.leave_category_id', DB::raw('SUM(leave_requests.approved_days) AS approvedLeave'),DB::raw('SUM(leave_requests.approved_days) - leave_category_details.no_of_days AS availableleaves')
->get();
Why get each column in a separate query when you can get them all in one.
I adjusted your controller like so:
public function leave_balance()
{
$userId = Auth::user()->id;
$userCompany = Auth::user()->company_id;
$employmentCategoryId = Employee::where('employee_id', $userId)->where('is_active', 1)->value('employeement_category_id');
//Leave Table
$leaveTable = DB::table('leave_categories as lc')
->join('leave_category_details as lcd', 'lcd.leave_category_id', '=', 'lc.id')
->join('leave_requests as lr', 'lr.leave_category_id', '=', 'lc.id')
->select('lcd.no_of_days as applicableLeaves ','lc.leave_category_name as leaveCategory',DB::raw('SUM(lr.approved_days) AS approvedLeaves'))
->where([
['lc.company_id', $userCompany],
['lc.employment_category_id',$employmentCategoryId],
['lr.employee_id', $userId],
['lr.leave_status',4]
])
->groupBy('leaveCategory', 'applicableLeaves')
->get();
return view('leave-balances')
->with('leaveTable', $leaveTable)
}
$availableleaves can be calculated in the view no need to send it.
Now in your view you display them like this:
<thead>
<tr>
<th width="55%">
Leave Category
</th>
<th width="15%">
Applicable Leave
</th>
<th width="15%">
Approved Leave
</th>
<th width="15%">
leavebalances
</th>
</tr>
</thead>
<tbody>
#foreach ($leaveTable as $tableRow)
<tr>
<td>
{{$tableRow->leaveCategory}}
</td>
<td>
{{$tableRow->applicableLeaves}}
</td>
<td>
#if(!$tabelRow->approvedLeaves->isEmpty()){{$tabelRow->approvedLeaves}}#else 0 #endif
</td>
<td>
{{($tableRow->applicableLeaves - $tabelRow->approvedLeaves)}}
</td>
</tr>
#endforeach
</tbody>
HTML is not my strongest field so your table might not show as wanted but i think its all good.

Trying to get property 'name' of non-object. Model relationship not working

I am getting an error message relating to my model relationship and have an identical section of my other app that works fine. I've looked through everything many times and cannot see any reason my model relationship should not work. When I try to access the model relationship in the view, I get "Trying to get property 'name' of non-object"
I have the following in my Controller:
public function edit($id)
{
//
$plansubmission = PlanSubmission::find($id);
$hradmins = PSPlanToHRAdminMapping::where('plan_submission_plan_id', $id)->get();
return view('planbuilder.add-hr-administrators', compact('plansubmission', 'hradmins'));
I have the following in my View:
<h3 class="py-3">Current HR Administrators with Online Access</h3>
<table class="table">
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Email Address</th>
</tr>
</thead>
<tbody>
#foreach($hradmins as $hradmin)
<tr>
<td> {{$hradmin->hradmin->name }}</td>
<td> {{$hradmin->hradmin->email }}</td>
#endforeach
</tr>
</tbody>
</table>
I have the following in my Model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class PSPlanToHRAdminMapping extends Model
{
//
protected $guarded = [];
public function hradmin()
{
return $this->belongsTo('App\HRAdmin');
}
}
I have the following Migration:
{
Schema::create('p_s_plan_to_h_r_admin_mappings', function (Blueprint $table) {
$table->unsignedBigInteger('plan_submission_plan_id');
$table->unsignedBigInteger('h_r_admin_id');
$table->timestamps();
$table->foreign('plan_submission_plan_id')->references('id')->on('plan_submissions');
$table->foreign('h_r_admin_id')->references('id')->on('h_r_admins');
});
}
It's possible that for some records you don't have any record for hradmin relationship so you can try adding optional helper like so:
<td> {{optional($hradmin->hradmin)->name }}</td>
<td> {{optional($hradmin->hradmin)->email }}</td>
for example to avoid error

Soft delete on table

I just started using soft delete and I am not really sure how to do it, I am just following someone example and is still unsure how to do a proper soft delete. All I want is to delete the personal_info table but I keep on getting a no error message which make me at lost since I don't know what I am doing wrong, can someone help me? Thanks a lot
home.blade.php
<table class="table table-bordered">
<tr>
<th><strong><big>Name: </big></strong></th>
<th><strong><big>Action </big></strong></th>
</tr>
<td>
<tr>
#foreach($data as $value)
<tr>
<th>{{$value->Name}}</th>
<th><form action="{{ url('/home/'.$value->id.'/delete') }}" method="post">
<button>Delete</button>
</form></th>
</tr>
#endforeach
</tr>
</tr>
</table>
Controller:
public function delete($id = 0){
if ($id > 0){
personal_info::destroy($id);
}
return redirect("/home");
}
or should I do it this way?
public function delete($id){
$data = personal_info::find($id)->delete();
return redirect("/home");
}
personal_info model:
use Illuminate\Database\Eloquent\Model;
use Eloquent;
use SoftDeletes;
class personal_info extends Eloquent
{
protected $fillable = array('Name');
protected $table = 'personal_infos';
protected $primaryKey = 'id';
protected $dates = ['deleted_at'];
public function user_info1s() {
return $this->hasMany('App\user_info1','user_id');
}
Route: (not sure should I use DELETE instead)
Route::get('/home/{id}/delete', 'HomeController#delete');
There is no need to use delete on the method. try to change your function to this
public function delete($id){
personal_info::findOrFail($id)->delete();
return back();
}
Edit
The Route method and Form method must be the same.
Change
Route::get('/home/{id}/delete', 'HomeController#delete');
To
Route::post('/home/{id}/delete', 'HomeController#delete');
Controller Method
use Carbon\Carbon;
public function delete($id)
{
personal_info::find($id)->update([
'deleted_at' => Carbon::now()
]);
return redirect()->back();
}
home.blade.php
<table class="table table-bordered">
<tr>
<th><strong><big>Name: </big></strong></th>
<th><strong><big>Action </big></strong></th>
</tr>
<td>
<tr>
// Example of adjusting your query to support soft deletes
#php
$data = Some\Model::whereNotNull('deleted_at')->get();
#endphp
#foreach($data as $value)
<tr>
<th>{{$value->Name}}</th>
<th><form action="{{ url('/home/'.$value->id.'/delete') }}" method="post">
<button>Delete</button>
</form></th>
</tr>
#endforeach
</tr>
</tr>
</table>

Resources