Relationship between two tables - Laravel, Inertia, Vuejs - laravel

I'm new to the subject, I have two tables related to each other, one for departments and one for users, I want to know how many users there are in each department
DepartmentController.php
public function index()
{
return Inertia::render('back/app/departments/index', [
'filters' => request()->all('visibility', 'status', 'search'),
'departments' => Department::orderBy('name')->get(),
'total_members' => User::where('department_id')->count(),
dd(User::where('department_id')->count()),
]);
}
Index.vue
<td class="flex items-center text-sm leading-5 text-gray-500 px-6 py-4 whitespace-no-wrap">
<span class="font-medium">{{ department.total_members }}</span> {{ $trans('labels.members') }}
</td>
<td class="px-6 py-4 whitespace-no-wrap text-right text-sm leading-5 font-medium">
<inertia-link :href="route('app:projectdepartment.index', {id: department.id})">
{{ $trans('labels.view-activity') }}
</inertia-link>
</td>

If you have the users relationship set up on your Department model, you could use the withCount() method:
Department::withCount('users')->orderBy('name')->get()
This will give you a users_count property on each department.

Assuming you have the relationships defined on each model as noted, you could also define an accessor or as was already stated get the number of related models by way of withCount or also with loadCount after retrieving an individual Department model.
Models/User.php
public function department()
{
return $this->belongsTo(Department::class, 'department_id');
}
public function getActiveUserCountAttribute($value)
{
// Perform additional logic on the users relationship
return $this->users()->where('active',1)->count();
}
Models/Department.php
public function users()
{
return $this->hasMany(User::class);
}
Remember that one of the benefits of withCount is that it doesn't load the related models, avoiding an n+1 problem. If you use withCount, you wouldn't need the accessor defined on the Department model but would need the User relationship defined on Department.
Note that you could also use the loadCount method after you have already retrieved the Department model, e.g. for an individual show page as opposed to a collection.
// From your show method in your controller
$department = Department::where('name',$request['name'])->first();
$department->loadCount('users');
To eager load the 'active_user_count' attribute on each Department model, you would use the $with property. With this defined, you would not need to use the withCount or similar in your controller method.
// Department.php
// A relationship that should always be loaded with every Department request.
protected $with = ['active_user_count']
Laravel docs:
https://laravel.com/docs/8.x/eloquent-relationships#counting-related-models

Related

Laravel Insert Data to Pivot Table From blade.php

I wanted to know what modifications should I do to this form to be able to link the newly added question to a group for example question that I am adding now says what's your name? I want it to be linked to group one so that only users in group 1 can see it
this is my Question Model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Question extends Model
{
public function answer()
{
return $this->hasMany('App\Answer')->latest();
}
public function userAnswer(){
return $this->hasOne('App\Answer')->where('user_id', Auth()->id())->latest()->first();
}
public function group()
{
return $this->belongsToMany(Group::class);
}
}
This is my Group Model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Group extends Model
{
public function question()
{
return $this->hasMany('App\Question');
}
}
This is my Group_Question Table ( Pivot table containing question_id and group_id )
Schema::create('group_question', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('group_id');
$table->foreign('group_id')->references('id')->on('groups')->onDelete('cascade');
$table->unsignedBigInteger('question_id');
$table->foreign('question_id')->references('id')->on('questions')->onDelete('cascade');
$table->timestamps();
});
and finally this is the form that I use to add Questions to the questions table:
<form class="" action="/questions/create" method="post">
#csrf
<div class="form-group">
<input type="text" name="question" value="" class="form-control" placeholder="Please Enter Question">
</div>
#can('add', \App\Question::class)
<div class="form-group">
<button type="submit" name="add" class="btn btn-success float-right">Add Question</button>
</div>
#endcan
</form>
I would really appreciate it if you can edit my from to be able to assign the question to a group in the pivot table.
You need to add a multi select in order to be able to assign groups to a Question. Since $question->group is a belongsToMany relation, you can obvisouly assign a question to multiple groups. You can do something like this:
<select name="groups[]" multiple="multiple">
#foreach ($groups as $group)
<option value="{{ $group->getKey() }}">{{ $group->name }}</option>
#endforeach
</select>
Caveat:
$groups should be exported by the create action of your QuestionController and be something like $groups = Group::get(). Alternatively you could write #foreach (Group::get() as $group) in your blade template, but keeping as much logic out of your template as possible is a good habit to get into.
$group->name is just a guess, not knowing how your group table looks like
The example HTML is just the bare minimum to get you started, you should make sure that on validation error etc. the old values are prefilled. I leave that to you as an excercise.
Next, go to your QuestionController and link the question to the appropriate groups by adding the following line to your store method:
$question->group()->attach($request->input('groups', [])));
Bonus remarks:
To follow Laravel best practices, the group relation in the Question model should be studly case and plural, as it is a BelongsToMany relation. Thus, you should rename it to Groups().
The answer() method should also be called Answers().
It is a little weird that you define a new HasOne relationship within the userAnswer() getter. Why not implement a getter or custom attribute for the current user's Answer instance instead by doing something like
public function getUserAnswerAttribute(): ?App\Answer
{
return $this->Answer()->whereUserId(Auth()->id())->first();
}
(if you are not familiar with attributes: you can then just call $question->userAnswer to get the result).
Can each user really only post one Answer to each Question?
You might want to use <form action="{{ route('question.create') }}" method="POST"> instead of hardcoding the URL. That's what named routes are there for.

Trying to get property 'department' of non-object in laravel with one to many relationship

Actually I want to relationship with two tables one is the student table where some data of a student. another table has department notice. I want to access the department notice according to the student department. The student has login id, password, dept & much other information of an individual student on the student table. The screenshot is given below
Now I want to try to access according to the dept. Another Table dept. the screenshot is given below.
Here given the CseDepartment model
public function administration()
{
return $this->belongsTo('App\Administration','dept');
}
Administration model
public function department()
{
return $this->hasMany('App\CseDepartment','dept');
}
function is given below
public function individualdepartment(){
$this->AdminAuthCheck();
$id=Session::get('id');
$student=Administration::find($id);
return view('Student.department',compact('student'));
}
view page department
#foreach ($student as $students)
{{-- expr --}}
<tr>
<td>{{$students->department->name}}</td>
<td>{{$students->department->message}}</td>
<td></td>
<td></td>
<td></td>
</tr>
#endforeach
In your controller, you are calling the find() method, which gives you one object, a student.
$student=Administration::find($id);
In your blade page, you are then asking to loop on that single object and produce a collection:
#foreach ($student as $students) // There is only ONE student, this will not loop.
If you want the above to work, you can grab a collection from your controller:
// Note the plural naming convention to make it a little more clear
$students=Administration::all();
return view('Student.department',compact('students'));
Then in your blade file, you can loop like this:
#foreach ($students as $student) // note the name plural --> singluar
<tr>
<td>{{$student->department->name}}</td> // Now you have a single student
<td>{{$student->department->message}}</td>
This will resolve the non-object error.

Property [name] does not exist on this collection instance. Eloquent Laravel

I have a potentially basic problem for Eloquent. I want to show only the name corresponding with Role of that user. I used the Eloquent Relationship ManytoMany. But I can't get that to work.
I tried point to the name using the $users parameter but this didn't work.
My project has three files such as Role model, StudentController, find_username view.
Thank you.
Role Model:
class Role extends Model
{
protected $fillable = ['id','role_name','role_level','role_note'];
public function users()
{
return $this->belongsToMany('App\User', 'role_users', 'user_id', 'role_id');
}
}
My StudentController:
class StudentController extends Controller
{
public function find_username()
{
$roles = Role::all();
foreach($roles as $role)
{
echo $role->users . '<br>';
}
return view('find_username',['roles'=> $roles]);
}
}
My find_username view:
#extends('master')
#section('content')
<div class="row">
<table class="table">
<thead>
<tr>
<th>ID Role</th>
<th>Role name</th>
<th>Role level</th>
<th>Role note</th>
<th>User name</th>
</tr>
</thead>
<tbody>
#foreach ($roles as $item)
<tr>
<td>{{$item['id']}}</td>
<td>{{$item['role_name']}}</td>
<td>{{$item['role_level']}}</td>
<td>{{$item['role_note']}}</td>
<td>{{$item->users}}</td>
</tr>
#endforeach
</tbody>
</table>
</div>
#endsection
You have many roles. Each of these roles have many users. Your table will be fine as it is to show the name of the role, roll level, and role note, because these are on the looped $item variable individually.
The problem is that while the $item holds those singular fields, the $item->users is another collection of user objects. Which means you have added another dimension onto your table. You might have 1 or 100 users to fit inside that <tr>.
To demonstrate, try this code, specifically adding in all the users names (adding the parameter to each user object in a new loop):
#foreach ($roles as $item)
<tr>
<td>{{$item['id']}}</td>
<td>{{$item['role_name']}}</td>
<td>{{$item['role_level']}}</td>
<td>{{$item['role_note']}}</td>
#foreach($item->users as $user)
<td>
{{$user->name}}
{{$loop->last?"":" | "}} //<-- just to separate names for this test
</td>
#endforeach
</tr>
#endforeach
If you have your models and relations set up correctly, this will show you your users for each role. However, as you can see, this may not be the best way to display this data. You might have dozens of users per role. You may wish to consider making a totally separate table for each role's users. Maybe click on something for the role on this table and bring up a new list or table of those users who have the role.
HTH

laravel 5.7 many to many with custome table name

Goods Model
class goods extends Model
{
protected $table = "goods";
public function sales(){
return $this->belongsToMany('App\sales', 'sales_details', 'goods', 'sales');
}
}
Sales Model
class sales extends Model
{
protected $table = "sales";
public function goods(){
return $this->belongsToMany('App\goods','sales_details','sales','goods');
}
}
i also make this model but i don't know if i ever need it or not
class salesDetail extends Model
{
protected $table = "sales_details";
}
my controller
public function test()
{
$goods = goods::all();
return view('test',compact('goods'));
}
my test.blade.php
#foreach($goods as $data)
<li><strong>{{ $data->name }}</strong> - {{ $data->company->kind }} {{ $data->company->name }}</li>
<p>{{ $goods->sales }}</p>
#endforeach
i connect goods table with sales table with many to many without following laravel naming.
This is my table contents
goods
-id
-name
sales
-id
-date
sales_details
-goods
-sales
-qty
-price
and i couldn't make it work. i just wanted to show the result like this
sales -id
sales - date
goods - name
sales_details - qty
sales_details - price
this should be the result
In your #foreach loop you're trying to access sales on the collection of goods rather than the instance in the loop. Also, because the sales() relationship is a belongsToMany (many-to-many) you're going to get a collection and not a single instance so you're going to need to loop through them as well e.g.
#foreach($goods as $data)
<li>
<strong>{{ $data->name }}</strong> - {{ $data->company->kind }} {{ $data->company->name }}
#foreach($data->sales as $sale)
<p>{{ $sale->date }} - {{ $sale->pivot->qty }}</p>
#endforeach
</li>
#endforeach
To access data from your pivot table you will first need to tell Laravel to include that information in the relationship:
public function sales()
{
return $this->belongsToMany('App\sales', 'sales_details', 'goods', 'sales')
->withPivot('qty', 'price');
}
You should also add the withPivot method to the good() relationship in the sales class as well.
Then you'll be able access the information from the pivot property. This is happening in the example above with {{ $sale->pivot->qty }}.
Many to many docs (scroll down to Retrieving Intermediate Table Columns )

How to safely access other users and other model's records inside Blade template

I have 3 models in my app Users, Sales and Plans, when I render sales for each customer (due to storing) I only get id's for other users and models related to that sale (like account manager, owner, plan), now I'm trying to use those ID's inside blade to get names or other rows based on ID and model. Here is the show function:
public function show($id) {
$user = User::find($id);
$sales = Sale::where('customer_id', '=', $id)->get();
return view('profiles.customer', ['user' => $user, 'sales' => $sales]);
}
And in blade I get all those sales like:
#foreach ($sales as $sale)
<li>
<i class="fa fa-home bg-blue"></i>
<div class="timeline-item">
<span class="time"><i class="fa fa-clock-o"></i> {{$sale->created_at->format('g:ia, M jS Y')}}</span>
<h3 class="timeline-header">{{$user->name}} became a customer</h3>
<div class="timeline-body">
<p>Date: {{$sale->sold_date}}</p>
<p>Price: {{$sale->sale_price}}</p>
</div>
</div>
</li>
#endforeach
So inside each record I have like "account_manager_id", "agent_id", "owner_id", "plan_id".
Currently I have this solved by adding public static function (this is for users, have same function for Plan model as well) in Sale model class:
public static function getUser($id) {
return User::where('id', $id)->first();
}
And I'm using it like this in Blade:
Account manager: {{$sale->getUser($sale->account_mgr_id)->name}}
Is this the safest and best way to do it? Or there is something I'm overlooking here?
You need to add relationships in your Sales Model.
class Sales extends Eloquent {
.....
.....
public function accountManager() {
return $this->hasMany('App\User', 'account_manager_id');
}
public function agents() {
return $this->hasMany('App\User', 'agent_id');
}
public function owner() {
return $this->hasOne('App\User', 'owner_id');
}
}
Now $sales->agents will give you a user with agent_id as id in User table.
Update your hasOne, hasMany relationships as your need. Laravel Documentation.
From your blade template, your access your AccountManager as
#foreach($sales->accountManager as $manager)
Name: {{ $manager->name}}
#endforeach
I think you could use Eloquent relationships. Taking your example, you should define relationship in your User model:
<?php
class User extends Eloquent {
public function sales() {
return $this->hasMany(Sale::class, 'customer_id');
}
}
Then, whenever you need to get sales of that user (entries, that relate via customer_id column), just simply do
<?php
$user = User::find($id);
$sales = $user->sales;
This is very fun when when you have to print out list of users that have sales, for example
<?php
public function showUsersWithSales() {
$users = User::with('sales')->get();
return view('users-with-sales', compact('users'));
}
users-with-sales.blade.php example:
#foreach ($users as $user)
User: {{ $user->name }}<br>
Sales:<br>
#foreach ($user->sales as $sale)
{{ $sale->amount }} {{ $sale->currency }} # {{ $sale->created_at }}<br>
#endforeach
<hr>
#endforeach
It would print all users with their sale amount and currency, followed by date when it was created.
This sample takes into account, that your User model has name attribute and your Sale model has amount, currency, created_at and customer_id fields in your database.
To reverse the action, say you have a sale and want to know who made it, just simply define a relationship!
<?php
class Sale extends Eloquent {
public function customer() {
return $this->belongsTo(User::class, 'customer_id');
}
}
Hope that helps!
Eloquent Relationship is your friend, https://laravel.com/docs/5.2/eloquent-relationships and you can solve your problem easily.
Suggestion is to remove all those function access and control from view and put it somewhere else. This will be good habit for you so you can avoid the infamous fat view.

Resources