Laravel: Passing data to view through route after querying - laravel

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();

Related

many to many relationship error in 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
}

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

Building complex Eloquent query using belongsToMany relationship, foreign table and whereIn()

In a Laravel 5 app, I have 5 tables - users, books, authors, followers and activity_feeds.
Users can follow authors and a book can have several authors.
When a book is made, an activity_feeds entry is made that references the book_id.
I need to build an eloquent query to get a collection of activity_feeds for each users, to iterate over in their home page activity feed.
My Book model includes
public function authors()
{
return $this->belongsToMany('App\Author')->withTimestamps();
}
The activity_stream table looks like this (with example data)
id (1)
user_id (3)
type (New Book)
book_id (18)
created_at etc
and my User controller includes
public function feedItems()
{
return $this->hasMany('App\ActivityFeed');
}
public function userFollowings()
{
return $this->belongsToMany('App\User', 'followers', 'follower_id', 'subject_id')->withTimestamps();
}
public function authorFollowings()
{
return $this->belongsToMany('App\Author', 'followers', 'follower_id', 'author_id')->withTimestamps();
}
My current query (which isn't working), contained in the User model is
public function getactivityFeedsAttribute()
{
$userFollowings = $this->userFollowings()->pluck('subject_id')->toArray();
$authorFollowings = $this->authorFollowings()->pluck('author_id')->toArray();
$userFeeds = ActivityFeed::whereIn('user_id', $userFollowings)
->orwhereIn('book_id', function($query){
$query->select('id')
->from(with(new Book)->getTable())
->whereHas->authors()
->whereIn('id', $authorFollowings);
})
->get();
return $userFeeds;
}
$userFollowings and $authorFollowings are working fine.
I'm not sure I'm using the correct syntax for data[book_id] to pluck the book id from the activity_feeds row, and I'm really not sure if I can nest a table look up or use $query like this.
It also seems VERY complicated. Am I might be missing something much more straight forward?
In the blade I am calling like this
#forelse ($user->activityFeeds as $activityFeed)
<div class="row">
<div class="col-2">
{{ $activityFeed->user->firstname }}
</div>
<div class="col-2">
{{ $activityFeed->type }}
</div>
</div>
<hr>
#empty
No activity yet
#endforelse
Which works if I just query 'ActivityFeed::whereIn('user_id', $userFollowings)'
I'll rewrite the query in an answer because comments aren't very legible.
public function getactivityFeedsAttribute()
{
$userFollowings = $this->userFollowings()->pluck('subject_id')->toArray();
$authorFollowings = $this->authorFollowings()->pluck('author_id')->toArray();
$books = Book::whereHas('authors', function ($query) use ($authorFollowings) {
// Have to be explicit about which id we're talking about
// or else it's gonna throw an error because it's ambiguous
$query->whereIn('authors.id', $authorFollowings);
})->pluck('id')->toArray();
$userFeeds = ActivityFeed::whereIn('user_id', $userFollowings)
->orwhereIn('book_id', $books)
->get();
return $userFeeds;
}

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 eloquent grab user with posts ordered by

I am playing around with Laravel and I have this code. It returns all of a users posts, based on the provided username.
Controller
$posts = User::whereUsername($username)->firstOrFail()->posts;
return View::make('users.index')->with($posts);
View
#foreach($posts as $post)
{{ $post->title }}
{{ $post-owner->username }}
// etc etc
#endforeach
How would I go about adding an orderBy() to my query? I would like the posts to be ordered by newest first. This was my attempt :(
User::whereUsername($username)->firstOrFail()->posts->orderBy('created_at', 'DESC');
Or is there a better way to go about doing this?
EDIT
User Model
public function posts()
{
return $this->hasMany('Post');
}
Post Model
public function owner()
{
return $this->belongsTo('User', 'user_id');
}
Your code is slightly missing the () brackets on the relationship!
Try this
User::whereUsername($username)
->firstOrFail()
->posts()
->orderBy('created_at', 'DESC')
->get();
Note the brackets on posts()->

Resources