Accessing relation after query not returning correct values - laravel

I have a kind of stupid problem (in my opinion since I am sure this is on my end and I simply overlook sth).
I query a model with a relation to it. When I simply return the whole result everything works fine.
$myModel = SampleModel::where('id', '>=', 0)->with('relationToAnother')->get();
returning this works as expected.
However, when I try to access the relation while looping over it after I got it back like
foreach($myModel as $m) {
echo $m->relationToAnother;
}
I simply get back the value of my original modal that is responsible for the connection (e.g. the column from SampleModel and not the relationship).
I am missing sth here and I dont know what.
This is what I am doing after I got $myModel back.
$returnValue = array();
foreach ($myModel as $v) {
$returnValue[] = $v->relationToAnother->subProperty;
}
}
which throws the error Trying to get property 'subProperty' of non-object. Which is just logic because $v->relationToAnother is still just the value of a column from my model without the relation and not the relation itself.
I didnt include the checks if that property is not null on purpose because that isnt the issue here.

I think this will work
$myModel = SampleModel::with('relationToAnother')->where('id', '>=', 0)->get();

Related

How to know what columns are presents in a Eloquent query before to execute it in Laravel 5.5?

Im using Laravel 5.5 and I have and QueryBuilder object (from the "Illuminate/Database/Eloquent/Builder" class).
I want to set an orderBy sentence into my query, but only if this field is present and exists in the QueryBuilder object (as column in the select section sentence).
For example, there is an User model, with the following fields ['id', 'firtsname', 'lastname', 'username','description'].
This is my object:
Use App\User;
$query = User::query();
if ($request->input('sort') != null) {
$model_query->orderBy($request->input('sort'), 'ASC');
}
$users = $query->get();
When I execute it, works fine (if I send you consistent data, of course). But if I set a column what does not exists, it sends and exception. So, the question is, how I can get the columns to retrieve from my $query object? To validate it, and if it's presents, execute the ordening code.
To answer your question, you can get the presence status of a column using Schema::hasColumn()
if (Schema::hasColumn('users', $request->sort)) {
//
}
GOING FURTHER
Now this doesn't seem very efficient, and maybe potentially leak data. Better validating your sort input and accept only proper column names:
$request->validate(['sort' => 'in:column1,column2']);

Does "where" works with mutattors in eloquent?

I have a mutattor in an eloquent model that generates a "status" atribute.
public function getStatusAttribute(){
if(){
return "enabled";
}
else
{
return "disabled";
}
}
Can I use?
$query = Anuncio::query();
$query->where('status', "enabled" );
return $query->get();
I seems that I cannot. I getting "status" column not defined. How can I get around this problem?
No doesn't works it works on model level
you can use after query from database in collection result
No, when you are doing a query you are asking the database, therefor there needs to be a column status.
There is a way, retrieve x elements from the database and use the Laravel Collection method where(). This is not optimal if you have many elements in teh database, it will retrieve all of them.
Anuncio::all()->where('status', 'enabled')->all();

Laravel eloquent query with sum of related table

I have a table users and posts with columns user_id and post_views.
In post_views I keep information how many times post was display.
And now, in query I would like to get user with sum of post_views all his posts.
I tried do something like this:
User::where(['id'=>$id])->with('posts')->get();
And in model I defined:
public function posts()
{
return $this->hasMany('App\Models\Post')->sum('post_views','AS','totalViews');
}
But without success.
How to do it?
Thank you
You can use a modified withCount():
public function posts()
{
return $this->hasMany('App\Models\Post');
}
$user = User::withCount(['posts as post_views' => function($query) {
$query->select(DB::raw('sum(post_views)'));
}])->find($id);
// $user->post_views
You can use
User::withCount('posts')->find($id)
to get the user with the id $id and a posts_count attribute in the response
I'm not fully sure what the intention of ->sum('game_plays','AS','totalVies'); is - you would need to add more context if you want this
Just something to add with regards to your shown code: No need to query by id using where + the get() at the end will make you query for a collection. If you want to get a single result use find when searching by id
As always laravel has a method for that : withSum (Since Laravel v8)
Note : I know that at the time of the message was posted, the method did not exist, but since I came across this page when I was looking for the same result, I though it might be interesting to share.
https://laravel.com/docs/9.x/eloquent-relationships#other-aggregate-functions
In your case it should be :
$user = User::withSum('posts as total_views', 'post_views')->find($id);
Then you can access to the result :
$user->total_views

Why Laravel5.2 eloquent query builder showing different results in windows and linux?

I have a field named 'status' in my table and the field type is 'tinyint', When I am trying to perform the where condition using eloquent query builder, it gives me different results in linux and windows.
Table structure:
and my code is,
Os::all()->where('status', 1);
It is working fine on windows machines and I am getting the results, but in Linux it returns empty collection.
then I tried
Os::all()->where('status', '1');
Its working fine on Linux, but not in windows :(
When I set the 'strict' flag to 'false'
Os::all()->where('status', 1, false);
it working fine on both platforms, Why is it so ?
I think that problem is in 'status' variable type.
First of all, I want to be sure that you know that your condition where('status', 1) is not on eloquent query builder but on Collection.
Os::all() query returns Collection of elements and method where('status', 1) is working on this Collection (set of database data). Where condition on collection != where condition in query builder. If you want to make where on query builder please do it in this way:
Os::where('status', 1)->get();
I guess that problem is that in Windows 'status' variable is casting to integer but in Linux is casting to string. This is due to slightly diffrent mysql configuration. Now take a look at Collection where method and everything will be clear:
public function where($key, $value, $strict = true)
{
return $this->filter(function ($item) use ($key, $value, $strict) {
return $strict ? data_get($item, $key) === $value
: data_get($item, $key) == $value;
});
}
When $strict = true method dont look at variable types.
How fix it?
You have probably few ways:
Unify mysql configuration - it could be hard.
Try query builder where: Os::where('status', 1)->get() - maybe in this way type casting will not be problem
Write attribute getter to change status attribute type in each time it is requested:
public function getStatusAttribute($value)
{
return (int)$value;
} You need choose to cast to (string) or (int). Keep in mind that status with changed type will not be visible in Collection but
only in single model obiect. After adding this getter you will not
need to add 'false' attribute to Collection where.

Laravel - Filtering previously returned results

I have a page with a form, that lets you select an exercise that I have logged data for. When you submit the form, it uses a getExerciseLog method in my LogController which takes the input name, and gets all instances of that exercise from the database and shows it in a table. The table displays fine, but now I need to filter these by newest and oldest etc, using a select field.
I have created the form for this, which posts to a "filter" method in LogController. So far I have this code:
public function getExerciseLog()
{
$exercises = Exercise::lists('exercise_name', 'exercise_name');
$exercise = Input::get('exercise');
$exercise_logs = Workout::where('exercise_name', '=', $exercise)->orderBy('created_at','desc')->get();
return view('log')->with(array(
'exercise'=>$exercise,
'exercises'=>$exercises,
'exercise_logs'=>$exercise_logs,
));
}
public function filter()
{
$filter = Input::get('filter');
if($filter == "oldest") {
$exercise_logs = Workout::where('exercise_name', '=', $exercise)->orderBy('created_at','asc')->get();
}elseif($filter == "newest") {
$exercise_logs = Workout::where('exercise_name', '=', $exercise)->orderBy('created_at','desc')->get();
}
}
Obviously this is not finished, as I'm stuck on how to return back to the 'log' view with the results filtered. At the moment, in the filter method, the $exercise_log won't return anything as $exercise is not being set, as the exercise input is not being submitted (that is the original select field for choosing the exercise you want to see data for).
Any ideas how I can get this working? Is it possible to pass the $exercise data from the getExerciseLog into the filter log, so I can use it within that method?
Thanks
Recommended way would be to sort the table using Javascript, it avoids the need of another request and full page refresh so it is much faster.
However in your case you can save the $excercise in the session like this
$request->session()->put('excercise', $excercise);
and
$exercise=session('excercise');
More info in here https://laravel.com/docs/5.2/session#basic-usage

Resources