Loop through nested relation in view - laravel

I'm trying to loop through some data in my blade view. This is my database setup:
What I would like to have in my view is the following:
So I can loop through the days and then order the tasks by the category they are in. I'm not experienced with Laravel and I'm having difficulties on ordering the tasks by category in the best way.
In my Days Model I have:
public function tasks()
{
return $this->belongsToMany('App\Task');
}
In my Task Model I have:
public function days()
{
return $this->belongsToMany('App\Day');
}
public function category()
{
return $this->belongsTo('App\Category');
}
In my Category Model I have:
public function tasks()
{
return $this->hasMany('App\Task');
}
In my controller I now only have:
public function index()
{
$categories = Category::all();
return view('app.blade.php', compact('categories'));
}
But how can I make sure to order them by days and then by category? Help much appreciated.

You can try as following:
$days = Days::with('tasks.category')->get();
$days = $days->map(function ($day) {
$day->tasks = $day->tasks->groupBy('category_id');
return $day;
});
Check it how it is converted after groupBy() method
dd($days);
then in your view you can do as:
#foreach ($days as $day)
{{ $day->name }}
#foreach ($days->tasks as $tasks)
{{ $tasks->first()->category->name }}
#foreach ($tasks as $task)
{{ $task->name }}
#endforeach
#endforeach
#endforeach
Note - I have not tested it but you can give it a try.

Related

Method Illuminate\Database\Eloquent\Collection::links does not exist

I created a model relationship between User and Message. I want to implement a list of messages for the authenticated user but I get the following error.
Method Illuminate\Database\Eloquent\Collection::links does not exist
Controller
public function index()
{
$user_id = auth()->user()->id;
$user = User::find($user_id);
return view('message.index')->with('messages', $user->message);
}
Message provider
class message extends Model
{
public function user() {
return $this->belongsTo('App\User');
}
}
User provider
public function message ()
{
return $this->hasMany('App\Message');
}
index.blade.php
#extends('layouts.app')
#section('content')
<h1>messages</h1>
#if(count($messages)>0)
#foreach ($messages as $message)
<div class="well">
<h3>{{$message->user}}</h3>
<small>Written on {{$message->created_at}} </small>
</div>
#endforeach
{{$messages->links()}}
#else
<p> no post found </p>
#endif
#endsection
Error
"Method Illuminate\Database\Eloquent\Collection::links does not exist.(View: C:\xampp\htdocs\basicwebsite\resources\views\message\index.blade.php)"
Check your view blade, that method (links()) only could be used when your data model is implementing paginate() method.
If you dont use paginate(), remove this part:
{{$messages->links() }}
If you are trying to paginate your data when it gets to the view then you need to add the paginate in your controller before passing the data to the view. Example
return $users = Users::select('id','name')->paginate(10);
with that paginate method in your controller, you can call the links method to paginate your object in view as shown below
{{$users->links()}}
hope it helps you
There are 2 ways to resolve this issue:
Either use paginate function while searching data from database:
$users = DB::table('users')->where('id',$user_id)->paginate(1);
Remove links() function from index.blade.php
{{ $messages->links() }}
Remove {{ $messages->links() }} to in your index.blade.php because {{ $messages->links() }} is supported only when you use paginate
You can do something like this in your controller file.
public function index()
{
$messages = Message::all()->paginate(5);
$user_id = auth()->user()->id;
$user = User::find($user_id);
return view('message.index')->with('messages', $messages, $user->message);
}

Laravel 5.5 - Save multiple data continiously from blade

I want to make a PHP method using laravel. I want to do the comparison of criteria and criteria. Here is the controller code :
public function create()
{
$kriteria1 = Model\Kriteria::pluck('nama_kriteria', 'id');
$kriteria2 = Model\Kriteria::pluck('nama_kriteria', 'id');
return view('kriteria_kriterias.create')->with('kriteria1', $kriteria1)->with('kriteria2', $kriteria2)->with('data', $data);
}
and this is the blade code :
It will make the form appear as total of criteria#
The problem is, I can't save it all to database. How do I get it to do this?
Updated method in the controller to the following:
public function create()
{
$kriteria1 = Model\Kriteria::pluck('nama_kriteria', 'id');
$kriteria2 = Model\Kriteria::pluck('nama_kriteria', 'id');
$data = [
'kriteria1' => $kriteria1,
'kriteria2' => $kriteria2
];
return view('kriteria_kriterias.create')->with($data);
}
How to output in the blade file:
{{ $kriteria1 }}
{{ $kriteria2 }}
Or you update the controller to pass the complete results:
public function create($id1, $id2)
{
$kriteria1 = Model\Kriteria::find($id1);
$kriteria2 = Model\Kriteria::find($id2);
$data = [
'kriteria1' => $kriteria1,
'kriteria2' => $kriteria2
];
return view('kriteria_kriterias.create')->with($data);
}
And the in the blade you can accss the data in various ways, one way is a foreach loop using blade in the blade template:
#foreach($kriteria1 as $k1)
{{ $k1 }}
#endforeach
#foreach($kriteria2 as $k2)
{{ $k2 }}
#endforeach'
To accept multiple values dynamicaly in the controller you can try something like this:
public function create($ids)
{
$results = collect([]);
foreach($ids as $id) {
$kriteria = Model\Kriteria::findOrFail($id);
if($kriteria) {
$results->put('kriteria' . $id, $kriteria);
}
}
return view('kriteria_kriterias.create')->with($results);
}
Then use the same looping method mentioned above to display them in the blade or a for loop that gets the count and displays accordingly.
maybe you forgot to add the opening tag ;)
{!! Form::open(array('url' => 'foo/bar')) !!}
//put your code in here (line 1-34)
{!! Form::close() !!}

I want to fetch an questions by id and it has multiple answers

I have Question model that has many answers
class Question extends Model
{
public function answers()
{
return $this->hasMany('App\Answer');
}
}
also I have Answer model , in this each answer belong to a question.
class Answer extends Model
{
//
public function question()
{
return $this->belongsTo('App\Question');
}
}
So what i am trying to do is I want to fetch a question by it's id and it should have all the answers that belong to this particular question and together I want to pass it to my view.
Here is what I have Done so far
public function show($id)
{
$questions = Question::with('questions')
->join('answers', 'answers.question_id' , '=' , $id)
->select('questions.id',
'questions.ask_question',
'answers.user_id',
'answers.aanswer',
'answers.created_at')
->where('questions.id' , '=', 'answers.question_id')
->get();
return view('pages.show', ['questions' => $questions , 'user' => Auth::user()]);
}
I have tried several other way but that didn't work
You can just fetch the question and use the relation in the view.
public function show($id)
{
$question = Question::find($id);
if ( ! $question) {
abort(404);
}
return view('pages.show', compact('question'));
}
And in your model you can do something like:
<h2>{{ $question->question }}</h2>
<ul>
#foreach ($question->answers as $answer)
<li>{{ $answer->answer }}</li>
#endforeach
</ul>
Btw, there's no need to assign the Auth::user() to the view, the Auth facade is available there as well. You can also just use the helper method auth().
<p>{{ Auth::user()->email }}</p>
or
<p>{{ auth()->user()->email }}</p>
Will work just fine.

get only newest object from a model - laravel eloquent

I have two models: Supplier and Quotation. I can use a foreach to list all quotations of a supplier:
// in my `Supplier` model:
public function quotations()
{
return $this->hasMany('App\Models\Quotation', 'supplier_id');
}
And now I want to print only the most recent quotation. The best I can figure out is this function in model:
public function newestQuotation()
{
return $this->hasMany('App\Models\Quotation', 'supplier_id')->orderBy('offered_at','desc')->limit(1);
}
and this foreach loop:
#foreach($o->newestQuotation as $q)
#include('displaymodules.module_quotations_mini', array('bg_color' => 'bg-danger'))
#endforeach
TO DO:
The above code does the job... but how it can be done properly? I am thinking of doing a helper, but doing the function in my models seems more like a good practice.
Thank you
Edited:
maybe I wasn't clear enough... I don't want to use foreach to access the object.
What I want is a snippet like this:
#include('displaymodules.module_quotations_mini', array( 'q' => $o->latestQuotations))
I get such an object when the query has the ->first(), but not when it has '->get()`.
when I do
$latestQuotation = App\Models\Quotation:where('supplier_id', 3)->orderBy('offered_at, 'desc')->first();
to get what I want without foreach I use this this temporary solution
<?php
$latestQuotation = App\Models\Quotation::where('supplier_id', $o->id)->orderBy('offered_at', 'desc')->first();
?>
#if(isset($latestQuotation))
#include('displaymodules.module_quotations_mini', array('bg_color' => 'csch_subtle_3', 'q' => $latestQuotation))
#endif
Attempts to implement Krishan Koenig's answer
attempt #1
<?php $latestQuotations = $o->latestQuotations(); ?>
{{print_r($latestQuotations)}}
Result: domain.dev is currently unable to handle this request.
HTTP ERROR 500
attempt #2
{{$o->latestQuotations()->offered_at}}
or
{{$o->latestQuotations->offered_at}}
Result:
Undefined property: Illuminate\Database\Eloquent\Relations\HasMany::$offered_at (View:\resources\views\leads\_show_bestoffers.blade.php) (View: \resources\views\leads\_show_bestoffers.blade.php)
attempt #3 - my desired solution
#include('displaymodules.module_quotations_mini', array('bg_color' => 'csch_subtle_5', 'q' => $o->latestQuotations))
Result:
Undefined property: Illuminate\Database\Eloquent\Relations\HasMany::$offered_at (View:\resources\views\leads\_show_bestoffers.blade.php) (View: \resources\views\leads\_show_bestoffers.blade.php)
You could create a new scope in related model, call it like latest:
public function scopeLatest($query)
{
return $query->orderBy('offered_at','desc')->limit(1);
}
and then in your relationship:
public function newestQuotation()
{
return $this->hasMany('App\Models\Quotation', 'supplier_id')->latest();
}
For example:
Quotation.php model
class Quotation extends Model
{
protected $primaryKey = 'id';
function withSupplier() {
return $this->hasMany('App\Models\Quotation', 'id', 'supplier_id')->orderBy('offered_at','desc');
}
public function newestQuotation($supplier_id){
News::with('withSupplier')->where('supplier_id', $supplier_id)->get();
}
}
in contriller:
public function pageQuotations(Quotation $quotation)
{
$quotations = $quotation->newestQuotation(1); //id Supplier
return view('displaymodules.quotations', $quotations);
}
in quotations.blade.php (example)
<table>
<tbody>
#foreach ($quotations as $quotation)
<tr>
<th>{{ $quotation->title }}</th>
<td>{{ $quotation->withSupplier()->title }}</td>
</tr>
#endforeach
</tbody>
</table>
</div>
You can create a new relatiotion in Supplier Model as:
public function newestQuotation()
{
return $this->hasOne('App\Models\Quotation', 'supplier_id')->orderBy('offered_at', 'desc');
}
Then you can query it as:
$supplieres = Supplier::with('newestQuotation')->take(20)->get();
#foreach ($supplieres as $supplier)
{{ $supplier->newestQuotation->title }} // just an example
#endforeach
Update
Try your query as:
$supplier = Supplier::where('id', $id)->first();
$latestQuotation = $supplier->newestQuotation;
Create a scope and use your existing relationship!
public function quotations()
{
return $this->hasMany('App\Models\Quotation', 'supplier_id');
}
public function scopeLatest($query)
{
return $query->orderBy('offered_at','desc')->limit(1);
}
public function latestQuotations()
{
return $this->quotations()->latest();
}
And in your Controller you query them with
//...
$latestQuotations = $supplier->latestQuotations();
Edited Version:
// supplier model
public function quotations()
{
return $this->hasMany(Quotation::class);
}
public function scopeLatest($query)
{
return $query->orderBy('offered_at','desc');
}
public function latestQuotations()
{
return $this->quotations()->latest()->get();
}
// web route
Route::get('/', function () {
$latestQuotations = App\Supplier::first()->latestQuotations();
return view('welcome', compact('latestQuotations'));
});
// welcome view
{{ $latestQuotations }}
...worked for me.
The most simple solution is
$entity = $collection->first();
Then, whateverthe count of the collection, the result is a single object.
This allows to use terms such as $entity->id or $entity->name.

how to acces nested objects in blade templates

Let me show you what I have.
//Post Controller
public function showPost(Post $post)
{
$albums = $post->album()->with('photos')->get();
$comments = $post->comments()->where('approved', '=', 1)->get();
$this->layout->title = $post->title;
$this->layout->main = View::make('home')->nest('content','posts.single', compact('post', 'comments','albums'));
}
mysql sentence executed correctly
string 'select * from albums where albums.id = '{"id":19,"title":"Post no 19","read_more":"Lorem i'... (length=786)
string 'select * from albums where albums.post_id = '19'' (length=54)
string 'select * from images where images.album_id in ('4')' (length=57)
I want to access the Photo object in blade, everything parses to the template but when I try to get the Photos
#foreach($albums->Photos as $photo)
Undefined property: Illuminate\Database\Eloquent\Collection::$Photos (View:
// post model
public function album()
{
return $this->hasOne('Album');
}
//album model
public function Photos(){
return $this->hasMany('Image');
}
Try
#foreach($albums->Photos()->get() as $photo)
{{$photo->attribute}}
#endforeach
You need to call the function that holds the relationship then use
get()
method to return an Eloquent Collection and then iterate it with a foreach loop.
#foreach($albums as $album)
#foreach($album->Photos as $photo)
<p>{{ $photo->image }}</p>
#endforeach
#endforeach
THats the answer

Resources