many to many relationship error in laravel - laravel

i have two tables,
1) qualifs
2) teachers
one teacher can have many qualifications
i created
pivot table; qualif_teacher
with two columns (teacher_id & qualif_id)
when i am saving teacher info, teachers qualifications are saving correctly with multiple ids, my problem is i am getting error when i try to view any teachers qualification in my blade file.
error: Object of class stdClass could not be converted to string
Route: /teachers
Index Controller:
public function index()
{
$teachers= DB::table('teachers')
$qualifs = DB::table('qualifs')->find($teachers);
return view('teachers.index',compact('teachers','qualifs'));
}
Edit Controller:
public function edit($id)
{
$qualifs = DB::table('qualifs')->find($id);
$teacher = Teacher::find($id);
return response()->json([
'status' => 'success',
'teacher' => $teacher,
'qualifs'=>$qualifs,
]);
}
View:
#if(isset($teachers))
#foreach($teachers->qualifs as $qualif)
<li>{{ $qualif->qual }}</li>
#endforeach
#endif

here you pass the variable $teachers in your find function, but find always expects int number to execute his process. Thats why you are getting this error.
So try to replace this
public function index()
{
$teachers= DB::table('teachers')
$qualifs = DB::table('qualifs')->find($teachers);
return view('teachers.index',compact('teachers','qualifs'));
}
with this code
public function index()
{
$teacher= Teacher::with('qualifs')->first();
foreach($teacher->qualifs as $ qualif)
{
$qualiflist[]=$qualif->name;
}
dd($qualiflist);
return view('teachers.index',compact('teacher','qualifs'));
}
that should be solve your problem

Change this
return view('teachers.index',compact('teachers','$qualifs'));
to
return view('teachers.index',compact('teachers','qualifs'));
You added $ and it dosen't work like this.
And in your view
#if(isset($teachers))
#foreach($teachers->qualifs as $qualif)
<li>{{ $qualif->qual }}</li>
#endforeach
#endif

Try something like this on your controller
//Please ensure you import the both related models on the top of your controller
use App\Qualifs;
use App\Teacher;
public function edit($id)
{
$teacher = Teacher::find($id); //if the id edit is accepting belongs to the teacher model
return $teacher->qualifs()->get(); //this should return all qualifications for this particular teacher so far as the relationships are set
$qualifs = Qualifs::find($id); //if the id edit is accepting belongs to the Qualif model
return $qualifs->teachers()->get(); //this should return all teachers for this particular qualifications so far as the relationships are set
}

Related

Laravel Eloquent how to get all parents

I have relation like this:
DB relation
I have a code in my model that retrieves me just one parent:
public function AllParents()
{
return $this->belongsToMany($this, 'parent', 'product_id', 'parent_id')
->select('parent', 'name');
}
I get it in my controller like this:
private function product(Product $product)
{
return $product->Product()
->with('AllParents')
->get();
}
Finally I need data like this:
Product1/Product_2/Product_3
I think I need a loop, but how to do it in Eloquent?
Just change relationship. You have mentioned pivot table name wrong one.
public function AllParents()
{
return $this->belongsToMany(Product::class, 'Product_parent', 'product_id', 'parent_id') ->select('parent', 'name');
}
and then you can access
\App\Models\Product::with('AllParents')->get()
In your Product Model. You have define relationship like this.
public function allParents()
{
return $this->belongsToMany(Product::class, 'product_parents', 'product_id', 'parent_id')->select('name');
}
And, In Controller you can get all the parents with eager loading.
Product::with('allParents')->find($productId);
And, In View you can use foreach loop to iterate every parent object.
#foreach ($product->allParents as $parentProduct)
{{ $parentProduct->name }}
#endforeach
I did like this:
I modified my controller
private function product(Product $product)
{
$allParents = [];
$parent = null;
$parent->$product->Product()->with('AllParents')->first()->id;
while ($parent != null) {
array_push($allParents, Product::all->find($parent));
$parent = Product::all()->find($parent) - first();
}
}

Getting result only for a specified id in Eloquent

I have a little problem. My code is working, but I think I'm not doing it the proper way.
In my GradeController i have this code:
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
if(auth()->user()->hasRole('Student')) {
$subjects = Subject::all();
return view('grades.student.index', compact('subjects'));
}
}
And in my view I'm getting Grades which belong to a specified user this way:
#foreach($subject->grades->where('student_id', '=', auth()->user()->id) as $grade)
<span class="badge badge-primary">
{{ $grade->value }}
</span>#endforeach
Is here, I mean Laravel, any better way to do this? Because I think that getting all Grades which belong to a Subject and then look for ID is not very "effective".
Have a good day.
You can use the with() eager loading helper, with a closure which will filter the subject's 'grades` based on the grade belonging to the logged in user:
$subjects = Subject::with(['grades' => function($query) {
$query->where('student_id', auth()->user()->id);
}])->get();
Note the removal of , '=', in the ->where() clause. It does not need this argument if checking if equal to.
In your controller index() you can make a middleware instead of doing this check auth()->user()->hasRole('Student') many times, buy if you will check only once here it will be fine what you did.
public function index()
{
// refactoring
return view('grades.student.index', ['subject' => Subject::all()]);
}
Also its not good to make a query in your blade file, so you can pass grades directly from you controller
public function index()
{
return view('grades.student.index', [
'grades' => Grade::where('student_id', auth()->id())->get()
]);
}
In index blade file you can now use:
#foreach($grades as $grade)
<span class="badge badge-primary">
{{ $grade->value }}
</span>
// you can get the subject from $grade->subject
#endforeach

Laravel: Passing data to view through route after querying

I recently asked a question about defining many to many relationships (using belongsToMany) and it was a huge help. So now in my models I have:
Users model
public function subjects()
{
return $this->belongsToMany('App\Subject', 'users_subjects', 'user_id', 'subjects_id');
}
Subjects model
public function users()
{
return $this->belongsToMany('App\User', 'users_subjects', 'subject_id', 'user_id');
}
This way I establish a relationship between users and subjects via the users_subjects table. My next step was to create a controller, SubjectsController, which ended up looking like this:
class SubjectsController extends Controller
{
// returns the view where subjects will be displayed
public function index()
{
return view('profiles.professor.prof_didactic_subjects');
}
// get users with subjects
public function getSubjects()
{
$subjects = User::with('subjects')->get();
}
// get a single user with a subject
public function getSubject($id)
{
$materia = User::where('id', '=', $id)->with('subjects')->first();
}
}
I'm not very sure about the code in the controller though.
The final step is where it gets tricky for me, even after reading the docs: I want to pass each result to the view, so I can have multiple tiles, each populated with data from subjects the user is associated with:
#foreach ($subjects as $subject)
<div class="tile is-parent">
<article class="tile is-child box">
<p class="title">{{ $subject['name'] }}</p>
<div class="content">
<p>{{ $subject['description'] }}</p>
</div>
</article>
</div>
#endforeach
I tried many different route configurations, but kept getting either the undefined variable error or trying to access non-object error.
What's the proper course of action here? I feel I'm missing something very basic. Thanks in advance for any help.
The answer
The solution provided below by #Sohel0415 worked perfectly. My index() method on the controller now looks like this:
public function index()
{
// temporary value while I figure out how to get the id of the current user
$user_id = 6;
$subjects = Subject::whereHas('users', function($q) use ($user_id){
$q->where('user_id', $user_id);
})->get();
return view('profiles.professor.prof_didactic_subjects')->with('subjects', $subjects);
}
My route looks like this:
Route::get('/professor', 'SubjectsController#index');
I was pretty lost, so this absolutely saved me, thanks again :)
You need to pass $subjects to your view. You can use compact() method for that like -
public function index()
{
$subjects = Subject::with('users')->get();
return view('profiles.professor.prof_didactic_subjects', compact('subjects'));
}
Or using with() method like -
public function index()
{
$subjects = Subject::with('users')->get();
return view('profiles.professor.prof_didactic_subjects')->with('subjects', $subjects);
}
If you want to get Subject for a particular user_id, use whereHas() -
$subjects = Subject::whereHas('users', function($q) use ($user_id){
$q->where('user_id', $user_id);
})->get();

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.

Laravel orderBy Not Passing to View

I am pulling a collection from my database table using the following code.
$profileVisits = DB::table('recently_visited')
->where('visitor_id',Auth::user()->id)
->orderBy('times_visited', 'desc')->get();
return view('profile.index')
->with([
'user' => $user,
'posts' => $posts,
'profileVisits' => $profileVisits,
]);
When I dd($profileVisits) it shows the collection with the correct descending results. However, when I pull the info into my view using the following code, it doesn't descend like it's supposed to. Is the orderBy query builder being undone or something with the "return view..." code?
Code in view...
#if (!$user->profileVisits->count())
#else
#foreach ($user->profileVisits as $topVisits)
<p>{{ $topVisits->getUsername() }}</p>
#endforeach
#endif
User Model:
public function profileVisits()
{
return $this->BelongsToMany('App\Models\User', 'recently_visited', 'visitor_id', 'profile_id');
}
public function addProfileVisits(User $user)
{
$this->profileVisits()->attach($user->id);
}
public function previouslyVisited(User $user)
{
return (bool) $this->profileVisits()->get()->where('id', $user->id)->count();
}
Actually, I just figured it out. On the User Model, I added the orderBy instead of using it in the Controller. See below.
User Model:
public function profileVisits()
{
return $this->BelongsToMany('App\Models\User', 'recently_visited', 'visitor_id', 'profile_id')->orderBy('times_visited', 'desc');
}

Resources