Laravel Eloquent Accessor not working in relationship? - laravel

I have a Model RelationDetails with 1 accessor:
public function getFullNameAttribute()
{
return "{$this->FirstName} {$this->Name}";
}
In my controller I have:
$annualPasses = Subscription::entrance()
->whereHas('Activation', function($query)
{
$query->whereDate('ValidUntil', '>=', Carbon::now());
})
->with('RelationDetails')
->get();
But when I want to use in my blade: $annualpass->RelationDetails->FullName I got the error:
Trying to get property 'FullName' of non-object
What am I doing wrong?

It's suppose to be $annualpass->RelationDetails->full_name
Also, return "{$this->FirstName} {$this->Name}"; means that in your DB, your column name is FirstName ... I recommend first_name that way {$this->first_name}. Of course you will have to update your migrations as well.
I recommend going through Laravel Best Practises. Please follow naming standards. Things get easier that way.

Related

Get Average from Polymorphic Relation

I am both trying to get the review counts and the average review ratings.
I have tables:
Tables:
id
.....
Chairs:
id
.....
Reviews:
id
rating
reviewable_id
reviewable_type
class Review extends Model {
public function reviewable() {
return $this->morphTo();
}
}
class Tables extends Model {
public function reviews() {
return $this->morphMany('App\Review', 'reviewable');
}
public function avg_rating() {
return $this->reviews()
->selectRaw('avg(rating) as avgRating, review_id')
->groupBy('review_id');
}
}
I've tried:
Table::with(['avg_rating'])->withCount('reviews')->where(function($q) use ($regex_terms, $terms){
$q->where('name', 'REGEXP', $regex_terms);
})->get();
But get "Unknown column 'review_id' in 'field list'" or attempting it with variations of "hasmany" yielded only an empty array or an array with the reviews. Just wonder what the best way to accomplish this is or if I'd have to loop through the reviews and calculate manually or a second raw query
I have this but not sure if it is efficient or best practice within Eloquent:
$tables->each(function ($table) {
$table->review_average = DB::table('reviews')
->select(DB::raw("ROUND( avg(rating), 2) as avg"))
->where("reviewable_id", "=", $table->id)->first()->avg;
});
Apparently, I was using Lumen based on the Laravel 6 framework, so it had been throwing a "method not found" error when I tried "withAvg" before. But after searching for that method, I saw that it required a higher version of Laravel. So, updating to Laravel/Lumen 8 allowed me to use the "withAvg" function.
So now my query builder statement looks like:
Table::with(['avg_rating'])->withCount('reviews')->withAvg("reviews", "rating")->where(function($q) use ($regex_terms, $terms){
$q->where('name', 'REGEXP', $regex_terms);
})->get();

Laravel eloquent get model property of current query

I'm trying to do where clause for fortune_code inside joindraw table, comparing with the lucky_fortune_code from product table. How can i access and do the check?
Product::where('status', StatusConstant::PT_ENDED_PUBLISHED)
->where('lucky_fortune_code', '<>', '')
->with(['joindraw' => function ($query){
$query->where('fortune_code', $this->lucky_fortune_code)
->with('user');}])->desc()->get();
Product.php
class Product extends Model
{
public function joindraw(){
return $this->hasMany('App\Models\Joindraw');
}
Joindraw.php
class Joindraw extends Model
{
public function product(){
return $this->belongsTo('App\Models\Product', 'product_id');
}
What you can do is a join:
Product::where('status', StatusConstant::PT_ENDED_PUBLISHED)
->where('lucky_fortune_code', '!=', '')
->join('joindraws', 'joindraws.fortune_code', '=', 'products.lucky_fortune_code')->get();
By the way, you can also omit the second 'product_id' parameter in the belongsTo() relation, as this column name is already assumed by convention.
Also, there is no desc() method on the query builder. Use orderBy('lucky_fortune_code', 'desc') instead.
However, whenever you have to write joins in Laravel, you should think about your relationship structure, because there's probably something wrong.

Laravel Eloquent Relations: ->latest()

What is the function of latest() in laravel?
Example:
public function activity()
{
return $this->hasMany('App\Activity')
->with(['user', 'subject'])
->latest();
}
From Build an activity feed in Laravel on line 44.
I've been looking in the laravel documentation, but I couldn't find it...
latest() is a function defined in Illuminate\Database\Query\Builder Class. It's job is very simple. This is how it is defined.
public function latest($column = 'created_at')
{
return $this->orderBy($column, 'desc');
}
So, It will just orderBy with the column you provide in descending order with the default column will be created_at.
->latest() fetches the most recent set of data from the Database. In short, it sorts the data fetched, using the 'created_at' column to chronologically order the data.
Add ->get() on your code like this:
public function activity()
{
return $this->hasMany('App\Activity')
->with(['user', 'subject'])
->latest()->get();
}
latest() function in Laravel used to get latest records from database using default column created_at.
latest()is the equivalent to orderBy('created_at', 'desc')

Laravel 5 Eager Loading with parameters

I'm working on a project with a bit of a complex model that has joins in its relations and also requires a parameter. It all works pretty well, except for when I need to eager load the relationship, as I couldn't figure out if there is a way to pass a parameter/variable to it.
The Controller
$template = Template::find($request->input('id'));
$this->output = $template->zones()->with('widgets_with_selected')->get();
The Model
public function widgets_with_selected($banner_id)
{
return $this->belongsToMany('App\Models\Widget', 'zone_has_widgets')
->leftJoin('banner_has_widgets', function($join) use($banner_id) {
$join->on('widgets.id', '=', 'banner_has_widgets.widget_id')
->where('banner_has_widgets.banner_id', '=', $banner_id);
})
->select('widgets.*', 'banner_has_widgets.banner_id');
}
This is returning a Missing argument error as the variable is not being passed.
I have resolved the issue by moving the logic to the controller, but I want to know if there is a way to keep the relationship in the model and just call it with a parameter.
Looking at the laravel code I dont think this is possible as you'd like to do it. You simply cant pass parameters to a with() call.
A possible workaround is to have an attribute on your model for $banner_id.
$template = Template::find($request->input('id'));
$template->banner_id = 1;
$this->output = $template->zones()->with('widgets_with_selected')->get();
Then change your relationship
public function widgets_with_selected()
{
return $this>belongsToMany('App\Models\Widget','zone_has_widgets')
->leftJoin('banner_has_widgets', function($join) use($this->banner_id) {
$join->on('widgets.id', '=', 'banner_has_widgets.widget_id')
->where('banner_has_widgets.banner_id', '=', $banner_id);
})
->select('widgets.*', 'banner_has_widgets.banner_id');
}
You could perhaps alter it a bit by passing the banner_id through a method. Sortof like this in your model:
public function setBanner($id) {
$this->banner_id = $id;
return $this;
}
Then you can do:
$template->setBanner($banner_id)->zones()->with('widgets_with_selected')->get();
Not sure if this works, and it's not really a clean solution but a hack.

Laravel 3 Eloquent ORM usage

I have the following code which works but doesn't seem to follow the laravel eloquent way:
Article::left_join('images', 'articles.id', '=', 'images.article_id')
->join('article_category', 'articles.id', '=', 'article_category.article_id')
->where('article_category.category_id', '=', $category_id)
->get();
I have 4 tables; articles and categories which have a many to many relationship with each other, a pivot table article_category table which holds the article id and category id and an image table which has one to one relationship with an article.
I setup my models as:
class Category extends Eloquent {
public static function get_articles($category_id) {
return static::find($category_id)->has_many_and_belongs_to('Article');
}
class Article extends Eloquent {
public function categories() {
return $this->has_many_and_belongs_to('Category');
}
public function image() {
return $this->has_one('Image');
}
However I can't seem to get all three bits of info together. I can do:
Category::get_articles($current_category)->get();
To get all articles in a given category but I can't seem to get the image for the article, there seems to be nothing I can chain onto? Unless I'm doing it incorrectly? Is there a trick I'm missing?
I even tried the stripped down version from the docs:
foreach (Article::with('image')->get() as $article) {
echo $article->image->foo;
}
However I get an error: Trying to get property of non-object, even though var_dump shows $article->image is an object! Weird.
Thanks
If you have not setup a model for the image table, do that. The ORM needs the model there so it knows what 'Image' refers to.
Can you get the category information using the ::with method or is that troublesome too?

Resources