Laravel 4 One To Many relationship Error - laravel

I am laravel newbie and I am trying to follow the documentation.So I have two models, 'User' model and a 'UserPhone' model. A user has many phones.
User model:
public function userPhone() {
return $this->hasMany('UserPhone');
}
UserPhone model:
public function user(){
return $this->belongsTo('User');
}
On my controller I am trying to "copy" the documentation:
$userPhone = User::find(1)->userPhone;
Well the result is an error:
Trying to get property of non-object
I know that I am missing something here , but I cannot find it.

I'm pretty sure that you don't have an user with id of 1.
$userPhone = User::find(1)->userPhone;
This should work, but, if it doesn't find the user the first part:
User::find(1)
I will return a NULL and NULL is not an object, then you get the error: Trying to get property of non-object.
My advice is, try to do this
var_dump( User::find(1) );
And you if you receive just a NULL, you found the problem.

Well the answer is that everything was ok!
I had accidentaly left
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableInterface;
before the UserPhone Model Class declaration..It was such a newbie mistake.

If you want to fetch Users with their related phone numbers (userPhone) you can use Eager Loading.
//get all users (User) with their respective phonenumbers (userPhone)
$users = User::with('userPhone')->get()
//get User with id==1, with his related phonenumbers (userPhone of User(1))
$user_1 = User::with('userPhone')->where('id',1)->first()
and than you can do
if(!is_null($user))
$phones_of_user_1 = $user_1->userPhone();
else
$phones_of_user_1 = array();
That way, if a user of id==1 exists, you fetch his phone numbers. Else, you get an empty array and no exception/error (trying to get property on a non-object) thrown .

That relationship would automatically be loaded for you.
$user = User::find(1);
echo $user->userPhone->id;
This is assuming you have your database tables are setup correctly according to laravel's conventions and you actually have a User with an ID of 1.

1) You are missing a pair of () after userPhone
$userPhone = User::find(1)->userPhone();
2) You are not using the 'find' method properly. I think what you want to do is :
$userPhone = User::userPhone()->get();
or
$userPhone = User::find($phoneId); //where $phoneId is the id of the phone you are trying to find.
The 'find' method return only one object and will try to find it with it's id.

Related

Laravel Model hasMany - getting too may results

I'm learning Laravel, so I'm quite new.
I have 2 Models: House and Translation.
My House Model:
use HasFactory;
protected $guarded = ['id'];
public function trans(){
return $this->hasMany(Translation::class);
}
}
My Translation Model:
function House(){
return $this->belongsTo(House::class);
}
}
When I do in the controller something like ($id=2 e.g) :
$house = House::find($id)::with('trans')->get();
I get a result with all houses (there are currently 2 in the DB).
When I just do the query "House::find($id)->get()" it works fine.
What part am I missing?
::with('trans') returns completely new query and forgets everything about your ::find($id)
you need to use load method.
$house = House::find($id);
$house->load('trans');
What happens is, House::find($id) is a method that returns the element by its primary key.
Then, the ::with('trans') gets the result, sees the House class and starts creating a new query builder for the Model.
Finally, the ->get() runs this new query and the end result is what is return for the $house value.
You have two options that will result to what you want to do.
First one is, to find the house entry and then load its relation
$house = House::find($id);
$house->load('trans');
The second option is this:
$house = House::where('id',$id)->with('trans')->first();
The second one is a query builder that results to the first element with id = $id,
and load its relation with translations.
You can check for more details in the laravel documentation. They have a very well-written documentation and the examples help a lot.

Get specific values from controller function

I started learning Laravel and I am trying to achieve the following:
Get data from database and display specific field.
Here is my code in the controller:
public function show()
{
$students = DB::select('select * from students', [1]);
return $students;
}
Here is my route code:
Route::get('', "StudentController#show");
That all works for me and I get the following displayed:
[{"id":1,"firstname":"StudentFirstName","lastname":"StudentLastName"}]
How can I get only the "lastname" field displayed?
Thanks in advance!
DB::select('select * from students')
is a raw query that returns an array of stdClass objects, meaning you have to loop through the array and access properties:
$students[0]->lastname
You can also use the query builder to return a collection of objects:
$collection = DB::table('students')->get();
$student = $collection->first();
$student->lastname;
Lastly, using the query builder, you can use pluck or value to get just the last name. If you only have one user, you can use value to just get the first value of a field:
DB::table('students')->where('id', 1)->value('lastname');
I strongly advise you to read the Database section of the Laravel docs.
$students[0]['lastname'] will return the last name field, the [0] will get the first student in the array.
I would recommend creating a model for Students, which would make your controller something like this:
$student = Students::first(); // to get first student
$student->lastname; // get last names
If you only want the one column returned, you can use pluck()
public function show()
{
$last_names= DB::table('students')->pluck('lastname');
return $last_names;
}
This will return an array of all the students' lastname values.
If you want just one, you can access it with $last_names[0]
As a side note, your show() method usually takes a parameter to identify which student you want to show. This would most likely be the student's id.
There are several ways you can accomplish this task. Firstly, I advise you to use the model of your table (probably Students, in your case).
Thus, for example,to view this in the controller itself, you can do something like this using dd helper:
$student = Students::find(1);
dd($student->lastname);
or, using pluck method
$students = Students::all()->pluck('lastname');
foreach($students as $lastName) {
echo $lastName;
}
or, using selects
$students = DB::table('students')->select('lastname');
dd($students);
Anyway, what I want to say is that there are several ways of doing this, you just need to clarify if you want to debug the controller, display on the blade...
I hope this helps, regards!

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

Laravel: Model function to check if relationship exists

I have two models Customer, Contact with the following relationship in the Customer model:
public function latestContact () {
return $this->hasOne(Contact::class)->latest();
}
I already found out here that the optional helper is a possible to way check if the relationship exists when displaying the data. Otherwise I would receive a "Trying to get property of non-object" error.
optional($customer->latestContact)->address
Now I am wondering if there is a way to directly check this inside the model function. I would prefer to only call
$customer->latestContact->address
or something like
$customer->getLatestContactAdress
and return false (or no result) if the relationship does not exists.
Thank you in advance.
You could define an accessor or a function within your parent model.
Something like this in your Customer model:
public function getLatestContactAddress()
{
return optional($this->latestContact)->address;
}
And call it like this:
$customer->getLatestContactAddress();
Try using eager loading
$customer = Customer::with('latestContact')->get();
Let me know if not works

Laravel Eloquent with and find

Why is this not working?
Article::with('category')->find($ids)
I got a Array to String Conversion Exception.
But if i split the query into 2 parts like this:
$articles = Article::with('category')
and
$articles = $articles->find($ids)
I didn't get any exception and the result is right.
Just for the posterity... other way you can do this is:
Article::with('category')->whereIn('id', $ids)->get();
This should be faster because it's leaving the query to the database manager
Try:
Article::with('category')->get()->find($ids);
You need to get the articles first before you can call find() I believe.
Warning: This retrieves every single article from the database and loads them all into memory, and then selects just one from all that data and returns it. That is probably not how you would want to handle this problem.
This will give you the results based on an array of IDs in Laravel 4
Article::whereIn('id', $ids)->with('category')->get();
Create object and set his properties with relationships
for example, code in your Controller or Service
$article = new Article;
$article = $article->find($id);
$result->article = $article;
$result->article->category = $article->category;
return response()->json($result);
Code in your Model
public function category() {
return $this->hasOne('App\Category');
}

Resources