I am new to Laravel 5 and was wondering how model object retrieval works.
For instance I have a separate table that is referenced by another table and I want to get the records from that.
Item Table
Category Table
I was trying to extend the User model
Class Item extends Model {
public function getCategory(){
$category = Category::find($this->category_id);
return $category;
}
}
So when I try to access the object retrieved in my view,
{{ $item->getCategory()->name }}
I get the error
Undefined property: Illuminate\Database\Eloquent\Builder::$name
What am I doing wrong? And what is the best practice in doing this? I used to do this in Symfony and it works so I was wondering how its done in Laravel.
Any help and input would be greatly appreciated.
Thank you all.
As stated in the docs here's how I did it
Class Item extends Model {
public function category()
{
return $this->hasOne('App\Category', 'id', 'category_id');
}
}
And accessed the object in the view this way
{{ $item->category->name }}
Related
I am using Laravel 5. if I have written a function on Model class and takes it's object by laravel eloquent to any view file like cars.blade.php file and now if I call any model function from cars.blade.php
Like Model Class
Car.php
public function totalModels() {
return App\Models\CarModel::where('id',$this->modelId)->count();
}
Cars.blade.php
<span>Available Models : {{ $car->totalModels() }}</span>
So My Questions are
When this function will call ?
Is this function slow the page ?
Is this a best practice to do it ?
if there is any foreach loop then how will this function will behave for each object ?
Thanks
The method you're searching for is withCount:
Create a relation to App\Models\CarModel in the car model and eager load it with withCount to prevent sending too many queries in the loop and slowing down the page too much:
Car.php
namespace App\Models;
class Car
{
// ...
public function models()
{
return $this->hasMany('App\Models\CarModel', 'id', 'modelId');
}
// ...
}
CarsController.php
namespace App\Http\Controllers;
class CarsController extends Controller
{
// ...
public index()
{
$cars = App\Models\Car::withCount('models')->get();
return view('cars', compact('cars'));
}
// ...
}
cars.blade.php
#foreach ($cars as $car)
{{-- ... --}}
<span>Available Models: {{ $car->models_count }}</span>
{{-- ... --}}
#endforeach
Is this a best practice to do it ?
You are coupling VIEW part of MVC architecture to the Model itself which is not good practice.
When this function will call?:
This will run as soon as laravel templating engine will render that blade.
What will happen:
It will make an extra call to the database get all the rows and then perform a collection count() which is much slower than mysql count().
Is this function slow the page ? Yes. Improve the query performance a bit at least:
App\Models\CarModel::select(DB::raw('count(*) as total_cars'))
->where('id',$this->modelId)
->pluck('total_cars');
This query is similar to what happens with withCount() method via a relationship.
If there is any foreach loop then how will this function will behave for each object ?
If you are foreaching an object and doing a call to get the count then foreach itteration an extra call to the database will happen similar to N+1 problem
A better way of doing it, check #Dan answer.
This is with reference to this question :
Laravel Eloquent One to Many relationship
I tried the suggested way, but couldn't resolve. Please help. Below is the changes i have done :
Earlier :
//Route for Restaurants Page
Route::get('/home/restaurants',function(){
$restaurants = DB::table('restaurants')->simplepaginate(3);
return view('restaurants',['restaurants_data'=>$restaurants]);
});
Changed as per suggestion :
Route::get('/home/restaurants',function(){
// $restaurants = DB::table('restaurants')->simplepaginate(3);
$restaurants = \App\Restaurant::simplePaginate(3);
return view('restaurants',['restaurants_data'=>$restaurants]);
});
In Restaurant model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Restaurant extends Model
{
public function offer(){
return $this->hasMany('Offer');
}
}
In view, now I am trying to access it by dumping the values.
<?php
var_dump($restaurants_data->offer);
?>
Error :
After doing dd()
Firstly, I would suggest changing your Offer Relationship to:
public function offers()
{
return $this->hasMany(Offer::class, 'restaurant_ID', 'id');
}
The above assumes that the Offer class and Restaurant class are in the same namespace. If they're not please add the correct namespace or import the Offer model in to the class.
Secondly, because you're paginating the results you will end up with a collection of Restaurant models (even if there is only one), so you will need to loop through them to get access to the offers for each model. I would also suggest eager loading the results e.g.
Route:
Route::get('/home/restaurants', function () {
$restaurants = \App\Restaurant::with('offers')->simplePaginate(3);
return view('restaurants', compact('restaurants'));
});
in your view:
#foreach($restaurants as $restaurant)
#foreach($restaurant->offers as $offer)
{!! dump($offer) !!}
#endforeach
#endforeach
{{ $restaurants->links() }}
Can you replace
$restaurants = \App\Restaurant::paginate(3); and amend the blade code to say
<?php
foreach($restraunts_data as $resturant) {
if(count($restaurant->offer) {
print_r($restaurant->offer);
}
}
?>
You are using the models incorrectly. You run no queries and you attempt to run a static method on the Restaurant class without selecting any restaurants. As far as I know is this not supported by Eloquent. If you look at the error message it complains that there are no property $offer.
Try to run some query, and the select the related Offer. This should work as expected.
For example:
$offers = \App\Restaurant::find(1)->offer;
This will return the many Offer relations for the Restaurant with ID 1.
I would like to known how to get data from database in blade like from User table:
{{ Auth::user()->name }}
I have table user_settings
I would like to get record from this table by logged user id like this:
{{ UserSettings::user()->my_field }}
How can I do that?
Try this on your blade view
{{ \App\UserSettings::where('user_id',Auth::user()->id)->first()->my_field }}
In default, model file is inside App folder.
Such direct access to database table is not preferred though, you can return this as a variable from controller function like,
$field = \App\UserSettings::where('user_id',Auth::user()->id)->first()->my_field;
return view('view_name',comapact('field'));
and use in blade like
{{$field}}
Another good way is posted by Orkhan in another answer using eloquent relationship.
Hope you understand.
You need to retrieve the UserSettings associated to the authenticated user:
UserSettings::where('user_id', Auth::id())->first()->my_field
You can defined a method named current() to return that for you.
class UserSettings extends Model
{
public static function current()
{
return UserSettings::where('user_id', Auth::id())->first()
}
}
Then use:
UserSettings::current()
On the other had it would better to use one-to-one relationship on user model:
class User extends Model
{
public function settings()
{
return $this->hasOne('App\UserSettings');
}
}
Then use:
Auth::user()->settings->my_field
I have define scope in model like this
class Station extends Model {
protected $primaryKey = 'st_id';
public function scopeByDid($query)
{
return $query->groupBy("st_did");
}
}
I can call byDid from controller but I cannot get it through blade template like this
#foreach ($river->stations->byDid as $didType)
....
#endforeach
how do I get it. Appreciate your response. Thanks
If you're getting a relationship as an attribute (without () at the end) it means the relationship will have already been retrieved before the scope.
To get your code to work you will just need to change your foreach to:
#foreach($river->stations()->byDid()->get() as $didType)
Hope this helps!
I have a dynamic property user in my model:
class Training extends Model
{
...
public function user()
{
return $this->belongsTo('App\User');
}
}
And I can easy get username in controller like this:
Training::find(1)->user->name
But I don't know how to perform the same in view. I tried this:
Controller:
return view('training/single', Training::find(1));
View:
{{ $user->name }};
but without success, I'm getting error Undefined variable: user. So it's look like I can't access dynamic property in view.
Any idea how can I use dynamic property in views?
I fear that's not really possible. There's no way to set the $this context in your view to the model. You could convert the model into an array with toArray() but that would include the related model and you would have to access it with $user['name'].
I personally would just declare the user variable explicitly:
$training = Training::find(1);
return view('training/single', ['training' => $training, 'user' => $training->user]);
Use eager loading
return view('training/single', Training::with('user')->find(1));