Laravel Object Relation does not work in foreach loop - php

I have a typical model relation. I have the model QR, which hasMany Rating, and a Model Rating, which belongsTo Qr.
Now I want to output the Ratings, which belong to a single qr model, through a foreach loop like this:
<table>
<tr>
<th>ID</th>
<th>UnitID</th>
<th># of Ratings</th>
</tr>
#foreach($qrs as $qr->ratings)
<tr>
<td>{{$qr->id}}</td>
<td>{{$qr->unit_id}}</td>
<td>{{$qr->ratings->count()}}</td>
</tr>
#endforeach
</table>
This is my Controller:
public function index()
{
//
$unit = Unit::all()->first();
$qrs = Qr::all()->first();
return View::make('index')
->with('unit', $unit)
->with('qrs', $qrs);
}
Here are my two Models
Rating.php:
class Rating extends \Eloquent {
protected $guarded = [];
public function qr(){
return $this->belongsTo('Qr');
}
}
Qr.php:
class Qr extends \Eloquent {
protected $guarded = [];
public function unit(){
return $this->belongsTo('Unit');
}
public function ratings(){
return $this->hasMany('Rating');
}
}
I actually want to output the count of ratings, a Qr-Code has. I know it is possible to do it somehow like this:
{{Rating::where('qr_id', $qr->id)->count()}}
But I want to do it somehow like this in the foreach loop
{{ $Qr->rating->count() }}
If this is somehow possible.
I get the relation, if I just output the first() of Qr and then
var_dump($qrs->ratings->toArray())
But I don't know how to get the count Number of ratings in combination with the foreach loop. Any help would be dearly appreciated.

Couple of things wrong here:
// view:
#foreach($qrs as $qr->rating)
// should be:
#foreach($qrs as $qr)
// controller:
$unit = Unit::all()->first();
$qrs = Qr::all()->first();
// this way you get all Units then fetch first Unit from the collection,
// the same with Qrs, so change it to:
$unit = Unit::all(); // do you need it at all?
$qrs = Qr::with('ratings')->get();
This will solve the problem and in the foreach loop you will be able to access $qr->ratings->count() which will be Collection method.

At first you have used this:
#foreach($qrs as $qr->ratings)
You need to change it to this (as already stated in an answer):
#foreach($qrs as $qr)
Then in your index method you have used this:
public function index()
{
$unit = Unit::all()->first();
$qrs = Qr::all()->first();
return View::make('index')->with('unit', $unit)->with('qrs', $qrs);
}
In this case you need to get a collection of QR models and since Unit and Rating are related to Qr then you may use with and get() to get a collection of QR models like this:
public function index()
{
$qrs = Qr::with(array('unit', 'ratings'))->get();
return View::make('index')->with('qrs', $qrs);
}
Then you'll be able to loop the Qr models in your view like this:
#foreach($qrs as $qr)
<tr>
<td>{{ $qr->id }}</td>
<td>{{ $qr->unit_id }}</td>
<td>{{ $qr->ratings->count() }}</td>
</tr>
#endforeach

Related

display data name instead of id property

I can't get the name property to display in my index always showing error
"Function name must be a string"
Controller
public function index()
{
$accounts = Account::with('student')->get();
return $accounts('Student_id');
$student = Student::find($id, ['id', 'studentname']);
return view('accounts.index',compact('accounts'));
}
Model
protected $fillable = [
'accountname',
'Student_id',
];
public function student() {
return $this->belongsTo(Student::class);
}
View Code:
<tbody>
#foreach ($accounts as $account)
<tr>
<td>{{ $account->accountname }}</td>
<td> {{$account->student->studentname}}</td>
</tr>
#endforeach
</tbody>
I'm trying to display the studentname instead of Student_id using one to many relationship.
this is the Error
Note: but if i changed this {{$account->student->studentname}} to this {{$account->Student_id}} it work but only showing the id not the name.
Remove these lines:
return $accounts('Student_id');
$student = Student::find($id, ['id', 'studentname']);
Also, since you're not using a standard foreign key name, you need to add it to the definition:
public function student()
{
return $this->belongsTo(Student::class, 'Student_id');
}
Also, it's a good idea to follow Laravel naming conventions which you will find in my repo and rename Student_id to student_id. In this case, your relationship will work without defining a foreign key.
Update
The solution for the third issue you have is:
<td> {{ optional($account->student)->studentname}}</td>

Get the amount of the bill in the class method

Sorry for my English.
I want to make a record that would be deduced me the sum of all my orders, that is, folded string of orders and drew grouped by orders.
I have created a model "Sale", which comprises method AmountOrder
public function AmountOrder()
{
$AmountOrder = DB::table('goods')
->join('sale_lines', 'sale_lines.good_id', '=', 'goods.id')
->where('sale_id', $this->id)
->select(DB::raw('SUM(price*quantity) as total_sales'))
->value('total_sales');
return $AmountOrder;
}
and to deduce the code like this
#foreach ($sales as $sale)
<tr>
<td class="table-text"><div>{{ $sale->id }}</div></td>
<td>
{{ $sale->client->name }}
</td>
<td>
{{$sale->date}}
</td>
<td>
{{$sale->AmountOrder($sale)}}
</td>
<td>
{{$sale->debt($sale)}}
</td>
<td>
{{$sale->date_of_issue}}
</td>
</tr>
#endforeach
But the problem is that the query is performed on each line. I'm new to Laravel, but thought maybe you can solve this problem somehow more beautiful?
Thank you very much in advance!
You are probably talking about the Eager Loading.
From the docs:
When accessing Eloquent relationships as properties, the relationship data is "lazy loaded". This means the relationship data is not actually loaded until you first access the property. However, Eloquent can "eager load" relationships at the time you query the parent model. Eager loading alleviates the N + 1 query problem.
However, you will be not able to use the Eager Loading now, with this code in the AmountOrder method.
A simple google search, also, led me to this example of Eager Loading with aggregate functions/relationships.
It will be probably a good start to think and implement your solution.
you have wrong in your select :
$AmountOrder = DB::table('goods')
->join('sale_lines', 'sale_lines.good_id', '=', 'goods.id')
->where('sale_id', $this->id)
->select(DB::raw('SUM(sale_lines.price*sale_lines.quantity) as total_sales'))
->value('total_sales');
My relationship
class Sale extends Model
{
//Получаем товар в этой продаже
public function good()
{
return $this->belongsTo('App\Good');
}
}
class Good extends Model
{
//В каких закупках был этот товар
public function purchases()
{
return $this->hasMany('App\Purchase');
}
//Продажи с этим товаром
public function sales()
{
return $this->hasMany('App\Sale');
}
}
Is it correct?
In my model i create method
public function AmountOrderRelation()
{
return $this->belongsTo('App\Good')
->selectRaw('sum(price) as aggregate, id')
->groupBy('id');
}
In controller
$new_sales = Sale::with('AmountOrderRelation')->get();
#foreach ($new_sales as $sale)
<tr>
<td class="table-text"><div>{{ $sale->id }}</div></td>
<td>
{{ $sale->AmountOrderRelation }}
</td>
</tr>
#endforeach
But my relations is null. What's my mistake?
I did it!
public function AmountOrder()
{
return $this->HasOne('App\SaleLines')
->join('goods', 'sale_lines.good_id', '=', 'goods.id')
->selectRaw(DB::raw('SUM(price*quantity) as aggregate, sale_id'))
->groupBy('sale_id');
}
public function getAmountOrderAttribute()
{
// if relation is not loaded already, let's do it first
if ( ! array_key_exists('AmountOrder', $this->relations))
$this->load('AmountOrder');
$related = $this->getRelation('AmountOrder');
// then return the count directly
return ($related) ? (int) $related->aggregate : 0;
}
And in controller
$sales = Sale::with('AmountOrder')->get();

Inner join using eloquent in Laravel 5.1

I have a doubt that I couldn't find an answer anywhere.
I'm new to eloquent and to make the basic stuff it is excelent!
Now I need to query data from different tables and I was wondering if I can do it with eloquent.
I have two models:
class Worker extends Model {
protected $table = 'workers';
public $timestamps = true;
public function area()
{
return $this->belongsTo('Area');
}
}
And this one
class Area extends Model {
protected $table = 'areas';
public $timestamps = true;
public function worker()
{
return $this->hasMany('Worker');
}
}
So basically a worker belongs to an area and an area has many workers.
Now I want to show in a table the name of the worker and the name of the area that he belongs to.
I can do it using the query builder but I wanted to know if I can do it with eloquent.
I saw a post in laracast with this code:
$workers = Worker::with('area')->get();
Now when I use that I get the following error:
Class 'Area' not found
I don't know why I get that error when the function 'area' exists in the Worker class and in the WorkerController I'm using
use App\Area;
What I want to be able to do is the following:
#foreach ($workers as $worker)
<td>{{ $worker->name }}</td>
<td>{{ $worker->lastname }}</td>
<td>{{ $worker->areas->name }}</td>
#endforeach
Like I said, I already I'm able to accompish this using laravel's query builder but I just want to know if I can make more use of the Eloquent :)
Thank you for your time.
Just in case anyone asks here is my raw query:
$workers = DB::table('workers')
->join('areas', 'areas.id', '=', 'workers.area_id')
->select('workers.*', 'areas.name as area')
->get();
That's the one I'm using and it works perfectly fine, thank you! :)
You are missing namespaces in your relations.
public function area()
{
return $this->belongsTo('App\Area');
}
and
public function worker()
{
return $this->hasMany('App\Worker');
}
You need to use function like you named in model "area" not "areas":
#foreach ($workers as $worker)
<td>{{ $worker->name }}</td>
<td>{{ $worker->lastname }}</td>
<td>{{ $worker->area->name }}</td>
#endforeach

How to use Laravel Pagination with models relationsips?

I have categories and items tables. Each item belongs to only one category and each category has many items. So, in Category model I defined this relationship:
public function items()
{ return $this->hasMany('Item', 'catid'); }
and I retrieve data for a category this way:
$category = Category::find($id);
return View::make('admin.categories.catdetails')->with('category', $category);
and in my view I can loop through data:
#foreach ($category->items as $item)
<tr>
<td> {{ $item->name }} </td>
<td> {{number_format($item->price, 2, '.', '')}} </td>
</tr>
#endforeach
but this results in all items in on page. How to make use of laravel pagination in case that I have so many items for one page??
How can I use
::paginate() // in controller or model
->links() // in view
as, so far, it throws many errors and I can't figure it out.
Thanks in advance.
You can call paginate() on the relationship object, which you access by ->items() (not ->items)
$items = $category->items()->paginate(10);
return View::make('admin.categories.catdetails')
->with('category', $category)
->with('items', $items);
Then in your view:
#foreach ($items as $item)
And:
$items->links()
You could use an attribute accessor to achieve what you want. In your model:
public function getPaginatedItemsAttribute(){
return $this->items()->paginate(10);
}
And then you use it like this:
#foreach ($category->paginatedItems as $item)
And:
$category->paginatedItems->links()

Why do i need first() in blade view with one to many relationship?

I have two tables
One QUESTIONS_TITLES entry has many QUESTIONS entries. The titles contain a group of questions.
QUESTIONS
id | question | ... | question_titles_id
QUESTIONS_TITLES
id | title
MODEL QUESTION
class Question extends \Eloquent {
public function questionTitle() {
return $this->belongsTo('QuestionsTitle', 'question_titles_id');
}
}
MODEL QUESTION
class QuestionsTitle extends \Eloquent {
protected $fillable = ['title', 'question_cat_id', 'type'];
protected $table = 'questions_titles';
public function question() {
return $this->hasMany('Question');
}
}
in my question controller i do:
$questions = Question::all();
$this->layout->content = View::make('questions.index', compact('questions'));
in my view i want a group of questions with the corresponding parent title
#foreach ($questions as $question)
<tr>
<td>{{ $question->questionTitle()->first()->title }}</td>
<td>{{ $question->id }}</td>
<td>{{ $question->question }}</td>
</tr>
#endforeach
this works. but why do i need first()? it doesn't look clean
when i drop it i get
Undefined property: Illuminate\Database\Eloquent\Relations\BelongsTo::$title (View: /vagrant/app/views/questions/index.blade.php)
$question->questionTitle() returns a BelongsTo object, not the QuestionTitle object. When you call $question->questionTitle()->first() you're executing the first() method on the relationship. This through laravel magic is getting you the correct answer. Though what you should really be doing is: $question->questionTitle->title. When you access the questionTitle attribute Laravel automatically resolves the relationship for you.

Categories