Accessing eager-loaded objects in view laravel 5.7 - laravel

i have several models that are linked to one model Call
i have all the relationships defined and they work pretty okay but i have issues with eager loaded results.
i have this query:
$callDetails =\App\Call::with(['client','subissues','subissues.issue','partner','district'])
->where('call.id', '=', $id)
->get();
that works fine in tinker returning
{"id":17400,
"client":{"id":18317,"name":"Yad Kal","phonenumber":"0991234567","age":27,"gender":"Male"},
"district":{"id":1,"name":"Dedza"},
"comments":" He complained ",
"completeness":"complete",
"perpetrator":1,
"partner_id":119,"status":1,
"subissues":[{"id":1378,"name":"Issues of Dissatifaction","description":"Issues of Dissatifaction","issue":{"id":6,"name":"Emergency Response (World)","description":"Emergency response"},"pivot":{"call":17400,"subissue":1378}}],"partner":{"id":119,"name":"World"}}
but when trying to access client with $callDetails->client, it returns the client id only.
and $callDetails->client->name returns an error.
i don't know what am doing wrong but all the eagerloaded results are giving me headaches!

Make sure you don't have in your table column with name client or you don't have any property in your model with name client. When relationship and field/property has exact same name (in your case client) it might cause problems, so in such case you should rename either relationship or field/property

Related

Can this block of code of mine can be improved

[This is to populate data from two tables that one has two foreign keys from the same column as reference on the other table]
https://i.stack.imgur.com/D8fiv.png
[This is my schema for the table with the foreign key]
https://i.stack.imgur.com/eYDL0.png
This is written in laravel and it is working however i have an itchy feeling that this is wrong
As someone else has commented, you should put the code in your question. More context might also be necessary as it's not clear what you are trying to return from your view(). Are you returning $citizen, $family, or both? It would also be helpful to include what version of Laravel you are using. I'll assume you are using the latest Laravel 8.
Your code should work but you are making more work for yourself if you don't utilize Laravel's relationships. If you do, all the query stuff you have in your code can be reduced to just a few short lines of code such as this:
public function view(Citizen $citizen)
{
$citizen->load('family');
return $citizen;
}
Database Migration
You can shorten your migration by using foreignId(). See docs for details
https://laravel.com/docs/8.x/migrations#foreign-key-constraints
Before:
$table->integer('client_id')->unsigned();
$table->foreign('client_id')->references('id')->on('citizens');
After:
$table->foreignId('client_id')->constrained();
Route Model Binding
I'm assuming your view() method is in your controller and is called from a route. Since the one parameter required is the client's id, you can use Route Model Binding and skip fetching the client from the database.
https://laravel.com/docs/8.x/routing#route-model-binding
public function view(Citizen $citizen)
{
// your code
}
Relationships
You seem to have relationships set up but you aren't using them to load data. You should be able to load the related objects without any manual queries.
If you have a belongsTo(One to Many) relationship on the Citizen model to the Family model, you can load it like this:
$citizen->load('family');
or just use it like this
$relationship = $citizen->family->relationship;
I don't know what the relationships between your models are but you should read up on the different relationship types in the docs.
https://laravel.com/docs/8.x/eloquent-relationships

How do the "has" and "whereHas" methods work in Eloquent?

I have a relationship defined between users and permisson, a user can have many permissions.
When I use "with" I get the data normally.
$user->with('permisson')->get();
I get the user with their permissions.
When I use "has" it only returns the user.
$user->has('permission')->get();
For what I've read, I should get the permissons if the user contains at least one permission.
I am using Postgres driver.
with is used for eager loading a relationship. You'd use it to fetch all of the specified relationships for each model (individually, or in a collection).
has is for using the relationship as a constraint or filter. As you said, using something like has('permission') will add a constraint to the query that says "only get Users that have at least one permission". This does not automatically load the relations like with(), it only creates the constraint.
You can combine the two if you want to take advantage of both the constraint and eager loading the results.
User::has('permission')->with('permission')->get();
Seems a bit redundant, I know.
From laravel docs:
If you wish to limit your results based on the existence of a relationship, you should use the has method. For example, if you want to retrieve all blog posts taht have at least one comment, yo may pass the name of the relationship to the has and orHas methods:
$posts = Post::has('comments')->get();
So, when you use the has method, it will not return the relationship, but just the post models which has at least one comment.
The whereHas and orWhereHas methods allows you to add customized constraints to a relationship constraint, such as checking the content of a comment (using the laravel example):
$posts = App\Post::whereHas('comments', function (Builder $query) {
$query->where('content', 'like', 'foo%');
})->get();
When you use the with method, you are loading the realtionship with the model:
$user->with('permission')->get()
This code will load the user and the permission relationship, while this one
$user->has('permission')->get();
will load the user who has some permission.
Hope it helps.

Larvel Scout scoped to Logged in user via Auth::user() not working | Issues or technique wrong

Basically I have installed Laravel Scout with TNT Search, all of the configs are correct and they work, I even got a nice search bar to work with an ajax workflow
But the results from the models are from the entire database collection where as my requirement is only to show results of record of records created by the user who is currently logged in session
The models are related via Eloquent Relationships, they work when access normally via the Auth::user() method but the scout search seems to not be attached to any of the models via the Auth::user() example:
App\CourtCase::search($request->q)->get();
The above works but will return any result in the model (and underlying table) without any regards to if the record is owned or related to the user logged in. My intention is however
Auth::user()->courtcase()->search($request->q)->get();
The error i get is the following
message Call to undefined method Illuminate\Database\Eloquent\Relations\HasMany::search()
exception BadMethodCallException
file /home/vagrant/code/legistant/vendor/laravel/framework/src/Illuminate/Support/Traits/ForwardsCalls.php
Clearly this is because Laravel Scout is not attached or available via the Auth::user() method, I can write code to filter the results after they are returned, but imagine the over head of results before being scope by user, it seems like a waste of all that querying, is there a way to scope to user then use Laravel scout search similar to Auth::user()
Can modify the Auth behavior to attach scout, will it be overwritten using a composer update of Laravel?
So as of 05/05/2019
Laravel Scout does not have a method of scoping queries to Auth user related models, because honestly it is a quite difficult logic to process, especially because the relationships are arbitrary and the keys can be different, a scoping function built internally or externally would have the same computational cost, there is no optimizing here
$results = App\CourtCase::search($request->q)->where('lawyer_id', Auth::id())->get();
This is how I solved it, by attaching a where condition to the search result where it will only show details matching the key, if you are modifying existing code of an application, remember initially scout might show cached results that don't match the filter, which confused me until I refreshed the code
Better code is welcome

Query builder on hasMany relation

Problem
I'm creating an API with Laravel. Every server can have more than one contact, and every contact belongs to one server - as such, contacts are set up with a belongsTo relationship, and servers have a hasMany relationship to the contacts.
A user can have many servers via its hasMany relationship. Thus, when creating a server, we simply invoke $user->server()->create([values]), which works just fine.
The issue is that when we try to invoke it further, as with contacts - we hit a wall where we get:
Call to undefined method Illuminate\Database\Query\Builder::contacts()
When using: $user->server()->contacts()->create([]).
The method does exist in the server model.
We also have a hasManyThrough relationship on the user model, specifying that a user has many contacts through servers.
When calling $user->contact()->create([]), we instead get:
Call to undefined method Illuminate\Database\Query\Builder::create()
Does anyone have a clue what might be causing this? Do query builders not allow for this type of chaining, or am I missing something blatantly obvious? As you can see, I've tried a few different methods but can't seem to produce a working result.
Cheers!
As you said:
A user can have many servers via its hasMany relationship.
so You cannot build another relation on relation that can return many results (becasue at the end we don't know exacly which server id we should set in contact new record).
So what you can do is to itterate over:
foreach ($user->server as $server) {
$server->contacts()->create($values);
}
You see: now you have specific server with id to put into new contact record.

Eloquent select specific columns

I am trying to select specific columns using Laravel's Eloquent but I am having some issues. I just want to SELECT quantity, prices from prices. I have tried
$prices = Price::select(array('quantity', 'price'))->whereMonthAndYearAndType($month,$year,'cpi')
->with(array('product'=>function($query){ $query->select('id','name'); }))
->with(array('market'=>function($query){ $query->select('id','name'); }))->get();
but I am getting Trying to get property of non-object
There is nothing in your code snippet that would produce that error. However, I suspect you are getting the error when you are trying to access fields on the eager loaded product or market relationships without checking for their existence.
A common problem with specifying select statements and eager loading relationships is that the local and foreign keys usually get left out. However, these are the values that Laravel uses to match up all the related models, so they need to be selected, as well.
If price belongsTo a product and price belongsTo a market, then you also need to select the prices.product_id and prices.market_id fields. If price hasOne product or price hasOne market, then you'll need to select the prices.id field, and the corresponding foreign keys on the eager loaded relationships (products.price_id or markets.price_id).
Though, even once this is resolved, it is still a good idea to check to make sure the related record exists before trying to access it. In a hasOne/belongsTo relationship, if the related record doesn't exist, the relationship property will be NULL. If you try to access a field on NULL, you'll get the error you're seeing.

Resources