Laravel: Eloquent "join", how to get only a property of the referred table - laravel

I have a model A and a model B.
I made the relations between them, so i can do A->B->property.
But now I'm facing some problems.
I need to make a query and get only that B->property, not the B object.
So i use this:
A::with(['B'])->get()
But then a get a property called B in A with the complete B model.
Is there anyway to achieve something like this.
A::with(['B->property'])->get()
So then in the B property inside A I get the B->property instead the B object.
Is it possible?
PS: I can't use the query builder because i need that eloquent model.

I think this article will help you out:
http://laraveldaily.com/why-use-appends-with-accessors-in-eloquent/
You can put
$appends = ['property'] in your model to add a property field to your model.
Then, with an accessor method in the model you can describe how to populate that field (ie: with a field from another model via relationship).
It seems like that ought to give you what you want.

Try below code
In your A model:
protected $appends = ['property'];
public function B()
{
return $this->hasOne('\App\B');
}
public function getPropertyAttribute()
{
return $this->B()->property;
}
then A->property will give you B->property. Change model name and property name as per your requirement.

The answer by #shoieb0101 did not work for me because I had a belongsTo relationship rather than hasOne. If this is the case for you too, you just need to modify the accessor function as illustrated below.
protected $appends = ['property'];
public function B()
{
return $this->belongsTo('\App\B');
}
public function getPropertyAttribute()
{
return $this->B()->first()->property;
}
Note: I added ->first() in since belongsTo returns an array of results, but we can get the property from a single result only.

You should be able to constrain eagerloaded queries:
try
A::with(["B" => function($query){
$query->select('property');
}])->get();

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.

How to query from database when I have different foreign keys?

I am trying to query data from my database and pass the results to a view called events, the problem I have is that one of my queries will always return the same result because in the where condition the $events_id is the same always. Is there a better way to do the querying? A better logic?
This code is from my controller called EventController:
public function index()
{
$firm_id = DB::table('firms')->where('user_id', auth()->id())->value('id');
$events_id = DB::table('events')->where('firm_id', $firm_id)->value('id');
$events = DB::table('events')->where('firm_id', $firm_id)->get()->toArray();
$actual_events = DB::table('actual_events')->where('event_id', $events_id)->get()->toArray();
return view('events',['events' => $events,'actual_events' => $actual_events]);
}
Since the $events_id is the same every time, the $actual_events will only contain the first result.
The image I have uploaded shows the problem, my table's first three columns are fine. Starting from the fourth they contain repeated values:
As I guess, you need something like this:
$event_ids = DB::table('events')->where('firm_id', $firm_id)->pluck('id');
$actual_events = DB::table('actual_events')->whereIn('event_id', $event_ids)->get()->toArray();
or write about your problem in details and I will try to help you.
you just said that your tables have relation together.
in this case it's better you using the eloquent for that,
first you should type the relations in model of each table like this:
class User extends Authenticatable{
public function cities()
{
return $this->hasmany('App\City'); //you should type your relation
}
}
for relations you can use this link: laravel relationships
after that when you compact the $user variable to your view, you can use this syntax for getting the city value relation to this user: $user->cities;.

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

Eloquent model method or attribute for calculation

I'm looking for a way to define a custom Eloquent method which only returns a calculation based on several columns in the according database table. I also tried setting it in the models attributes, but neither seem to work. Maybe I'm missing something, here's what I got so far:
<?php
use Illuminate\Database\Eloquent\Model;
class Team extends Model
{
public function difference() {
return $this->goals_f - $this->goals_a;
}
}
The error message I'm recieving is:
Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation
Your error makes it sound to me like you are trying to call your method like a property" $team->difference. You would instead need to call it like: $team->difference(). If you want to get the difference as if it was a property, then you would need to define an accessor:
public function getDifferenceAttribute(){
return $this->goals_f - $this->goals_a;
}
Then you could call it like $team->difference.
You could also define a protected $appends property to your model so that the difference property is subsequently visible in it's JSON representation:
protected $appends = ['difference'];
More information: https://laravel.com/docs/5.2/eloquent-mutators#accessors-and-mutators

Inspect Model relations

I am trying to inspect my Eloquent models to find out their relations to other Models. The problem is that relations are simply defined as a single method and no central index of relations exists:
public function posts()
{
return $this->hasMany('Post');
}
In order to inspect all relations I need to extract the list of methods, take out the ones inherited from Eloquent, execute each single one and check the return type:
$all = get_class_methods($model);
$inherited = get_class_methods('Eloquent');
$unique = array_diff($all, $inherited);
foreach($unique AS $method)
{
$relation = $model->$method();
if(is_a($relation, 'Illuminate\Database\Eloquent\Relations\Relation'))
{
//... this is a relation, do something with it
}
}
Needless to say, this is very dangerous. Is there a way to do this kind of inspection in a different, more secure way?
You could add PHPDoc comments to your relationship methods and then use the PHP reflection API to extract those from the source.

Resources