So I have a feedback model as a many to many polymorphic relation, for now I can say:
$user->feedbacks
and it will retrieve the relation accordingly, now I want to do something like:
$user->feedbacks->getAverage()
to simply spit the average feedback rating (which are numbers from 1 to 5)
I added the following function to my Feedback.php model file:
public function getAverage(){
$described = $this->avg('described');
$recommend = $this->avg('recommend');
$communication = $this->avg('communication');
$average = ($described + $recommend + $communication) / 3;
return $average;
}
But Laravel will not recognize this method.
Please help.
The method should be on the User model. If you look at the chain of objects, you are trying to call the getAverage method on a Collection class instance (that's what querying a Model for related Models will return for you). A collection doesn't have a method named getAverage().
To solve your problem, create the getAverage() method on the User model and inside of it, fetch the related Feedback model collection and compute the average based on the retrieved Models.
Related
In my Profile model I setted this relationship
public function lease()
{
return $this->belongsTo(Lease::class, 'lease_id', 'id');
}
And in my Lease model I seeted this way
public function profile()
{
return $this->hasOne(Profile::class, 'lease_id', id);
}
As longs as I know in laravel you could do
$profile = factory(App\Profile::class)->create();
$profile->lease()->get();
And then responds correctly with the model inside of a collection
And if I do
$profile->lease
Responds correctly directly with the model
It isn't supposed that dynamic propertis execute the query right away like a shortcut of ->lease()->get()? Why it gives different formatted results?
When you are calling get on a builder you are getting a collection always. When you call first on a builder like that you will get a model or null. The dynamic property for the relationship, based upon the relationship object, will either query with get or first respectively when it loads it. Which is why $model->relationship is returning you the result you expect.
The relationships that are singular, cause a find and the ones that are many cause a get.
Laravel 5.4 - Docs - Eloquent - Relations - Relationship Methods vs Dynamic Properties
I am trying to figure out a relationship but I can't seem to solve the issue.
So what my script does first is checking if there is a valid session where status = 0.
Then I want to check if there is a valid trial where status = 0 ->first() associated with that session. And if so, I want to grab all the relevant data related by trial_id.
I understand what logic is required. However, I am wondering if there is a method to do this with as little commands as possible using Eloquent relationships.
Specifically, once i have the $session object. How can I filter the trials, in order to get the appropriate stimuli_tracker data?
The important components to the relationships for the table is as follows:
Sessions
id (has one to many relationship to trials(sessions_id)
user_id (foreign key)
status
Trials
id (one to many relationship with stimuli_tracker)
sessions_id (foreign key)
status
Stimuli_Tracker
trials_id (foreign key)
stimulus
stimulus_type
Sessions Model
class Sessions extends Model
{
protected $table = 'sessions';
public function stimuliTracker()
{
return $this->hasManyThrough('App\StimuliTracker', 'App\Trials', 'sessions_id','trials_id');
}
}
Trials Model:
class Trials extends Model
{
public function stimuli()
{
return $this->hasMany(App\StimuliTracker);
}
}
EDIT
I have tried in artisan tinker to
$object = \App\Session::where(arg);
then I tried to
$object->stimulus
but didn't work. I tried a few other fields but I only received null. Maybe I'm not getting how to grab the content properly
$object->stimulus is an undefined attribute based on what you've shown in your code.
To access the stimulus information for your session, you have to use the name of the relationship, which in this case is:
$object->stimuliTracker
The thing is that this will return an Eloquent Collection because it is a hasManyThrough relationship (which is a hasMany of a hasMany).
I'm assuming that the 'stimulus' attribute belongs to the StimuliTracker class. If this is the case, then you will need to loop through your StimuliTracker Collection to extract it:
foreach ( $object->stimuliTracker as $record )
{
$stimulus = $record->stimulus;
// do something with $stimulus
}
EDIT (Added):
If you are just looking for an array of the values in the 'stimulus' attribute, you can get that with the lists() method:
$stimulus_values = $object->stimuliTracker->lists('stimulus');
I have a user model which stores basic user information such as username, password etc.
There are also 3 types of user, Student, Staff and Parent. Each type also has a seperate model. For example, there is a Student model which belongs to a User model.
I also have a relationships table, which stores relationships between students and parents. This relationship is stored in the User model.
If I do something like:
App\Student::first()->user->relations;
It happily returns a collection of related parents.
In my Students model, I have a method called hasParent() which accepts a given user ID, and checks to ensure the student has a parent with that id. In that method, I have the following:
public function hasParent($parent)
{
return $this->user->relations->where('id', $parent)->count() === 1;
}
However, this returns an error Cannot call 'where' on a non-object. If I debug further, $this->user->relations returns an empty array.
The problem is, like above, if I call the methods separately, I get the results I want.
So to clarify, if I run:
App\Student::first()->user->relations;
This returns a collection of users just fine.
In my Student model however, if I call:
$this->user
Then I get the correct student
If I call
$this->user->relations
I get an empty array. Which doesn't make sense! Can anyone shed any light on this, or what I might be doing wrong? If you need any further info, please let me know.
You need to call where on the relation like below.
public function hasParent($parent)
{
return $this->user->relations()->where('id', $parent)->count() === 1;
}
See the parenthesis after the relations. If you call the relation without the parenthesis Laravel returns you a collection. To get the builder you need to call the relation with the parenthesis.
I'd suggest - to avoid creating a huge query overhead (which you'll do by calling where and count on the Query builder, not the collection) - to do what you're doing already, except using Illuminate Collections filter-method:
public function hasParent($parent)
{
return $this->user->relations->filter(function($relation) use ($parent){return $entity->id === $parent;})->count() === 1;
}
I'm a trying to get the total distance of an activity which has multiple steps (with distance) ? For now, I'm doing like this :
Controller :
$total_distance = 0;
foreach (\Auth::user()->activities as $key => $activity) {
$total_distance += $activity->getTotalDistance();
}
Activity Model :
public function steps()
{
return $this->hasMany('App\Step');
}
public function getTotalDistance()
{
return $this->steps->sum('distance');
}
Is there a proper solution to do that ?
Thanks for your help
The way you do it requires quite a lot of DB queries to be run:
1 to fetch user activities
1 per activity to fetch its steps
You can get the number you need with just one query using Eloquent's aggregate function sum():
$total_distance = Step::join('activities', 'activity_id', '=', 'activities.id')->where('activities.user_id', Auth::id())->sum('distance');
You can read about other aggregate methods that Eloquent offers here: http://laravel.com/docs/5.1/queries#aggregates
Just like #Jeemusu said, your approach seems fine. But if you want to do it in some other way you can try to do it in several ways.
Look at Laravel's Has Many Through relationship.
The "has many through" relation provides a convenient short-cut for accessing distant relations via an intermediate relation. For example, a Country model might have many Post through a User model.
So using has many through you can access steps directly something like
$user->steps->sum('distance');
You need to make relationship that user has many steps through activities.
Something like:
class User extends Eloquent {
public function steps() {
$this->hasManyThrough('Steps','Activity','user_id','activity_id');
}
}
The other solution is to put foreign key in steps table so you can directly access it from user model like:
$user->steps->sum('distance');
class User extends Eloquent {
public function steps() {
$this->HasMany('Steps','user_id');
}
}
Hope this can help you.
I am trying to make a twitter like feed in an application, I have a database called connections where inside there's user and follow and another database called feed containing owner which would equal to the follow column in connections.
What I could do if had every id of a follower statically is to use where('owner', '=' $follow) on each follower and return it.
I tried this approach but it wasn't ideal:
Get each follower inside connections;
foreach(follower) {
Get 10 of the latest posts orderBy "created_at";
Push into array;
}
shuffle array;
limit array to 15;
return array;
That also ended with the returned array not being ordered by created date.
How would I use eloquent to get the feed item only if the user follows the owner in the best/simplest way?
Are there any specific Laravel tools that can be used?
Also the database layout isn't fixed as it is, it can be altered if needed to better suite this.
You need to create a many-to-many relationship between the user and itself. See the laravel eloquent documentation http://laravel.com/docs/eloquent#relationships. I didn't test this code but it should be enough to get you started down the right track.
Create a pivot table called "user_following" with:
(int) id, (int) user_id, (int) following_id
Then do something like this:
<?php
// Model
class User extends Eloquent {
public function following()
{
return $this->belongsToMany('User', 'user_following', 'user_id', 'following_id');
}
public function tweets()
{
return $this->hasMany('Tweet')->orderBy('created_at', 'desc');
}
}
// controller
$tweetsOfWhoImFollowing = User::find($id)->following->tweets;