get field value from eloquent relationship - php

I have this relationship on eloquent
public function Manufacturer() {
return $this->hasOne('App\Models\ManufacturerModel', 'id')->select('name');
}
And this returns correctly the manufacturer name:
{"id":1,"serialnumber":"123_1","buydate":"2018-01-26 00:00:00","offservice":null,"deleted":"0","manufacturer":{"name":"HP"}}
I want to retrieve the name not as JSON object but as a string
{"id":1,"serialnumber":"123_1","buydate":"2018-01-26 00:00:00","offservice":null,"deleted":"0","manufacturer":"HP"}

The best way to define the relationship is:
public function Manufacturer() {
return $this->hasOne('App\Models\ManufacturerModel', 'id');
}
Then you can get the manufacturer name this way:
$your_object->manufacturer->name;
Or adding a wrapper method:
public function ManufacturerName() {
return $this->manufacturer->name;
}
Notice that when you refer to the relationship without parenthesis the query is executed and what you are accessing is the result. If you don't want the entire record to be queried you can do this:
public function ManufacturerName() {
return $this->manufacturer()->select('name')->get()->name;
}
By accessing the relationship with parenthesis you are getting the relationship definition and you can modify it before executing the query.

Not directly but you can achieve the functionality using a little bit trick of php, for example, if you would like to use it in string context as given below:
// {{ $someModel->manufacturer }}
echo $someModel->manufacturer; // or echo Manufacturer::find(1);
Then you can do it using the __toString magic method in Manufacturer model as given below:
public function __toString()
{
return $this->name;
}
In this case, even on json_encode($manufacturer) will give you just name so why don't you just use $model->manufacturer->name;

Related

Laravel belongsTo coalesce?

I'm trying to add a relation to my Booking model. I already have a relation that looks like this:
public function vehicle() {
return $this->belongsTo(Vehicle::class);
}
Which works on the column bookings.vehicle_id. However, now I'm adding another column called bookings.billed_vehicle_id which will "override" the vehicle_id if it's not null. So I want to do something like this:
public function billedVehicle() {
return $this->belongsTo(Vehicle::class,DB::raw('coalesce(billed_vehicle_id,vehicle_id)'));
}
Is this possible?
And if not possible with belongsTo can I somehow create a custom relation that'll support this?
belongsTo() returns a query builder so you can go ahead and just chain ->whereRaw() on the end of it:
public function billedVehicle() {
return $this->belongsTo(Vehicle::class)
->whereRaw(DB::raw('coalesce(billed_vehicle_id,vehicle_id)'));
}

Return collection instead of relationship in Eloquent Model

In my Model, I have a collection and I am trying to return it in my model, instead of relationship object.
So that I can call, $user->items and get that collection.
In the model, the function looks like:
class User extends Model {
public function channelsAttribute() {
$name = Company::where('id', $this->id)->first()
$items = Item::where('company_id', $name)->get();
return $items;
}
}
Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation
As it goes 2 ways, I couldn't find a way to use relationship; however $items returns collection of values.
What should I do?
You are not calling the method correctly, instead of
function channelsAttribute()
you need to do
function getChannelsAttribute()

Custom method chaining with Eloquent ORM?

This is my current query:
$cars = Cars::with('brand')->get();
$cars->map(function($cars){
$cars->fullName = $cars->brand->brand." ".$cars->name;
//other manipulation...
return $cars;
});
I want to manipulate my collection in the model so that I can run something like $cars = Cars::with('brand')->getWithBrand();
How can I do this, so I don't have to write map functions for every time I run the query?
In your particular example, you don't need to use map to modify the Collection at all. You can use an Eloquent accessor to define attributes on a Model that don't exist in the database. In your example, you would define the following method on your Cars model:
public function getFullNameAttribute($value)
{
// make sure brand exists first
if ($this->brand) {
return $this->brand->brand.' '.$this->name;
}
// default if brand doesn't exist
return $this->name;
}
By defining that function on your Model, that function will be called whenever you attempt to use the full_name attribute, as shown in the following code:
$car = Cars::with('brand')->first();
// this will echo the result of the getFullNameAttribute method
echo $car->full_name;
Edit
If you would also like this new attribute to automatically show up in your toArray() or toJson() output, you can add the attribute to the $appends property on your Cars model:
class Cars extends Model
{
protected $appends = ['full_name'];
public function getFullNameAttribute($value)
{
// make sure brand exists first
if ($this->brand) {
return $this->brand->brand.' '.$this->name;
}
// default if brand doesn't exist
return $this->name;
}
}
Be aware, however, that your custom attribute depends on a related object. So, if you do something that accidentally calls toArray(), toJson(), __toString(), etc on a Collection of Cars that has not eager loaded the brand relationship, this will cause the N+1 query issue.
For example:
// Bad: N+1 issue because each printed Car will execute a
// separate query to get its brand to output full_name.
echo Cars::get();
// Good: No N+1 issue because all brands are already loaded.
echo Cars::with('brand')->get();

Custom model method to get a relation in Laravel

I try to define a custom Model method in Laravel. I have a n:m relation between Subscription and Notification over SubscriptionNotification.
I already defined the default relations:
public function subscription_notifications() {
return $this->hasMany('App\SubscriptionNotification');
}
public function notifications() {
return $this->belongsToMany('App\Notification', 'subscription_notifications');
}
Now I want to define a method, which returns a collection of notifications. I collect the IDs of the notifications I want in an array and write the following method:
public function notifications_due() {
// Collect $notification_ids
return $this->belongsToMany('App\Notification', 'subscription_notifications')->whereIn('notifications.id', $notification_ids)->get();
}
But when I want to use the mothod by $subscription->notifications_due, I get the following error:
[LogicException]
Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation
I'm new to Laravel (I come from Rails). I don't know if this is in Laravel even possible. Maybe someone can help me. Thanks!
Remove the ->get() part in the method notifications_due. get() will return a Collection, but when calling the method as a property (or magic method), Laravel expects the method to return an instance of Relation. Laravel will then execute the query and transform it to a Collection automatically.
Also, you can use your already defined notifications() method:
public function notifications_due() {
// Collect $notification_ids
return $this->notifications()->whereIn('id', $notification_ids);
}
Remove the get call from your relationship method, for example:
public function notifications_due() {
return $this->belongsToMany(
'App\Notification',
'subscription_notifications
')->whereIn('notifications.id', $notification_ids);
}
Use it just same:
// It'll return a collection
$dues = $subscription->notifications_due;
To get all the ids from the collection you may try this:
$ids = $dues->pluck('id');
Also, you may add more constraints if you want if you use it like:the
$dues = $subscription->notifications_due()->where('some', 'thing')->get();
Or paginate:
$dues = $subscription->notifications_due()->where('some', 'thing')->paginate(10);

Use accessor mutator's within Laravel 4 lists method

I have a simple mutator:
public function getFullnameAttribute($value)
{
return $this->first_name. ' ' .$this->last_name;
}
But I also have a method that returns a list of specific users for use in a select input:
static function getDeliveryManagers()
{
return User::IsDeliveryManager()->lists('first_name', 'id');
}
I need that array returned to be ['First Name Last Name', 'id']
But the mutator doesn't work, e.g.
return User::IsDeliveryManager()->lists('Fullname', 'id');
I found this: https://github.com/laravel/framework/issues/668
Which Taylor marks as being done but I cant get it working. Using Laravel 4.2.
Any help?
You need to call the lists() on Eloquent Collection. So make sure IsDeliveryManager() is returning correct values. Its better if you can share the code of IsDeliveryManager(). If its is query scope you need to call get() before lists().
return User::IsDeliveryManager()->get()->lists('fullname', 'id');
The mutator, even if it is in camelcase, should be called in lowercase.
So you should be calling it as such:
return User::IsDeliveryManager()->lists('fullname', 'id');

Categories