Eloquent Api Resource: show one column from pivot table - laravel

I have a vehicle database with a many to many relation with my variant and country table. I only want to show the title that's in my pivot (countries_variants) table. But when I set the relation in my api resource file, it shows all the columns from variants, countries_variants and countries table. Is there a way to only get the title from the pivot table?
Here is my Variant Model:
public function countries(): BelongsToMany
{
return $this->belongsToMany(Country::class, 'countries_variants')->withPivot('title');
}
VariantResource.php
public function toArray($request)
{
return [
'title' => $this->countries->first->title,
];
}
VariantController.php
public function index()
{
return new VariantCollection(Variant::paginate(50));
}
The output I'm getting is:
{
"data": [
{
"title": {
"id": 1,
"title": "Nederland",
"country_code": "NL",
"language_code": "NL_nl",
"pivot": {
"variant_id": 1,
"country_id": 1,
"title": "3/5 deurs"
}
}
}
]
}
I just want to show "title": "3/5 deurs" and not the other data.
I thought that if I set withPivot('title') in my model, it will only show that title and not the foreign keys (variant_id and country_id). Apparently thought wrong..
I tried adding this as well:
'variant_title' => $this->whenPivotLoaded('countries_variants', function () {
return $this->pivot->title;
}),
But the data then returns empty.
Any help would be very much appreciated :)

Try changing
$this->countries->first->title
To
$this->countries->first->title->pivot->title
When you do withPivot('title') you are telling Eloquent to also get title column, if you do not do that, you will only get the keys (variant_id and country_id in your case).
More info here.

Okay so I finally figured it out. I looked through the official laravel docs again and I found this.
So I changed my CountryVariant model class to extend Pivot instead of Model.
Like so:
use Illuminate\Database\Eloquent\Relations\Pivot;
class CountryVariant extends Pivot {
public function variant(): BelongsTo
{
return $this->belongsTo(Variant::class);
}
}
Now in my VariantResource.php I added this:
public function toArray($request): array
{
$items = [];
foreach ($this->countries()->get() as $country) {
$items[$country->language_code] = $country->pivot->only('title');
}
return $items;
}
I also changed the pivot table names to be singular like: country_variant (I had it plural).
Apparently the problem was that in my model it was looking for a primary key which I didn't have in my pivot table. I only had foreign keys and an additional column: 'title'. It took one of my foreign keys and used it as a primary one. So when I extended with extends pivot it would ignore the primary key and I could collect my alternate column 'title' by using country->pivot->only('title') in my resource file.
I hope this helps some one else.

Related

How to add to my Index/Show, so that it displays a table, from another table. (Laravel)

First post here, hope all is well with everyone! I am working on my senior project and struggling with this concept. Maybe it isn't possible, or it is and I'm thinking about it the wrong way.
I currently have this- This displays the student, with all its foreign keys in the other tables. In settings, there is a foreign key 'conversion_id.', I would like settings on the student call(code below) to ALSO display the conversion table, from the FK in settings.
$student = Student::with('studentIntroSurveys', 'settings', 'giftsSurveyResults',
'studentGiftSurveys', 'devotionals', )->get();
If this does not make sense, I am sorry. I am still l new to the language.
(Code to display students. It shows settings, but not the conversions within settings.)
$student = Student::with('studentIntroSurveys', 'settings', 'giftsSurveyResults',
'studentGiftSurveys', 'devotionals', )->get();
if (!$student) {
return response('No Data', 400);
} else {
return response($student);
}
I would like it to display this settings, but WITH the conversion_id table!!
What it displays =
settings: { setting_id: 4, student_id: 1, dark_mode: 1, conversion_id: 1,
notification_enabled: 1, notification_time: "08:00:00" } `
my has-one method =
public function settings()
{
$settings = $this->hasOne(Settings::class, 'student_id', 'student_id');
return $settings;
}
You can use the dot syntax for nested eager loading: 'settings.conversation' e.g.
$student = Student::with('studentIntroSurveys', 'settings.conversation', 'giftsSurveyResults', 'studentGiftSurveys', 'devotionals', )->get();
Alternatively, you could set up a belongsToMany relationship on the Student model and use settings as the pivot table:
public function conversations()
{
return $this->belongsToMany(Conversation::class, 'settings')
}
Just a few FYIs:
Your if statement is never going to return the 400 response as $student is always going to be a collection. You could instead do if ($student->isEmpty()).
I would also recommend changing the variable to $students as it will be a collection of students rather than a single student.
You can simple your settings relationship by removing the temporary variable and just returning the relationship:
public function settings()
{
return $this->hasOne(Settings::class, 'student_id', 'student_id');
}

Laravel: Get all projects and check if user has liked them

I want to get all projects, and foreach project I want to get a property for example is_liked which indicates that if the current_user (I've his Id) has liked this project or not.
User Model
class User extends Model
{
public function projects()
{
return $this->hasMany(Project::class);
}
public function favorite_projects()
{
return $this->belongsToMany(Project::class, 'favorite_projects', 'user_id', 'project_id')->withTimestamps();
}
}
Project Model
class Project extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
}
User Table
- id
- name
Project Table
- id
- user_id
- title
favorite_projects table
- user_id
- project_id
What is the best way to get this done ? the data I want to get is something like this:
[
{
"id": 1,
"user_id": 3,
"title": "my title",
"is_liked": true
}
]
Note: the current_user->id might or might not be same as the project->user_id.
$projects = DB::table('projects')
->join('favorite_projects', 'favorite_projects.project_id', '=', 'projects.id')
->select('projects.*', 'favorite_projects.*')
->where('projects.user_id', Auth::id())
->get();
This join statement allows you to join 2 tables together and for each project that is being favorited by the user, you will see the favorite record attached with the record.
Perform a dd($projects) after that SQL query and see what the result is like, and then for each result, you set $project['is_liked'] accordingly.

How to return a collection of models with selected columns and relation eager loaded in Laravel 5.2

Problem details:
I have three models
a Directorate with id and name fields,
an Employee with id and name fields and
a Telephone with id, tel, employee_id, directorate_id, description and type fields. The employee_id may be nullable, that is there are telephones stored in database with employee_id = null
The models are related as follows:
an employee may have many telephones
a directorate, may have many telephones
class Directorate extends Model
{
public function telephones()
{
return $this->hasMany(Telephone::class);
}
public function employees()
{
return $this->hasMany(Employee::class);
}
}
class Employee extends Model
{
public function telephones()
{
return $this->hasMany(Telephone::class);
}
public function directorate()
{
return $this->belongTo(Directorate::class);
}
}
class Telephone extends Model
{
public function employee()
{
return $this->belongsTo(Employee::class);
}
public function directorate()
{
return $this->belongsTo(Directorate::class);
}
}
Question:
I want to fetch a Collection of all the Telephone models that belong to a specific Directorate, that have employee_id = null and also having their directorate relation eager loaded. In addition, from that resulting collection of Telephone models, I need only some of the models' fields, that is id, tel and description
Tries
What I tried so far was the following:
I created a query scope in the Telephone model:
public function scopeHaveNoEmployeeId($query)
{
return $query->where('telephones.employee_id', '=', null);
}
In my controller
$myTelephones = Telephone::with('directorate')
->haveNoEmployeeId()
->where('directorate_id', $directorateId)
->get(['id', 'tel', 'description']);
However what I am receiving are the requested fields of the filtered models without the relation eager loaded, for instance:
[
{
"id": 79,
"tel": "0648136867",
"directorate": null
},
{
"id": 380,
"tel": "0223796011",
"directorate": null
}
]
I tried also to lazy eager load the relation afterwards but with no luck.
Finally I noticed that if I request all the Telephone models fields, the relation will eager load as I request. For example:
$myTelephones = Telephone::with('directorate')
->haveNoEmployeeId()
->where('directorate_id', $directorateId)
->get();
Then as a result:
[
{
"id": 79,
"tel": "0648136867",
"directorate": {
"id": 23
"name": "Some name"
}
},
{
"id": 380,
"tel": "0223796011",
"directorate": {
"id": 23
"name": "Some name"
}
}
]
Your telephone does not have any relationship with the directorate model.
put this in your Telephone model.
public function directorate()
{
return $this->belongsTo(Directorate::class);
}
Actually, after digging into Laravel's details for a while, I noticed that my initial question was out of context and somewhat silly. I was first eager loaded a relationship and then fatuously I filtered out the relationship by not including it in get() parameters. I had just to do the following:
$myTelephones = Telephone::with('directorate')
->haveNoEmployeeId()
->where('directorate_id', $directorateId)
->get(['id', 'tel', 'description', 'directorate']);

Laravel ORM should return Relation

Is it possible to return an value for an hasOne relation directly with an Model?
For example:
$List = Element::orderBy('title')->get();
The Element has a "hasOne" Relation to an column:
public function type()
{
return $this->hasOne('App\Type', 'id', 'type_id');
}
How can i now return automatically the "type" for the Model?
At the Moment i am looping through all Elements, and build my own "Array" of Objects, including the Key of "type" in this example. But ill prefer to do this only in my Model.
Ill know how to add a "normal" property, but can it be someone from an relation?
public function getTypeAttribute($value)
{
return // how ?
}
protected $appends = array('type');
Is this possible?
Edit:
A workaround could be to use DB:: to return the correct value - but ill dont thing thats a good workaround: like:
public function getTypeAttribute($value)
{
// make a query with $this->type_id and return the value of the type_name
}
protected $appends = array('type');
you need to eager load your relations when getting the Element:
$list = Element::with('type')->orderBy('title')->get();
then access the type using
foreach ($list as $item) {
echo $item->type->type_name;
}
where type_name would be the name of a column in the types table
Make a query scope and in that scope, join your attributes from other tables.
http://laravel.com/docs/5.1/eloquent#query-scopes
http://laravel.com/docs/5.1/queries#joins

Laravel / Eloquent: Search for rows by value in polymorphed table

I'm stuck at the moment and hope someone can give me a hand. I'm using a polymorphic relation and want to search my database for rows that fulfill conditions in the "parent" and the "child" table.
To get concrete, one small example. Given the following structure I e.g. want to look for a property with price "600" and rooms "3". Is there a way to do that with eloquent?
Tables
Table properties (parent)
id
price
details_type [can be "Apartment" or "Parcel"]
details_id
Table apartments (child)
id
rooms
Table parcels (child)
id
... (does not have a "rooms" column)
Relationships
Class Property
public function details() {
return $this->morphTo();
}
Classes Apartment + Parcel
public function property() {
return $this->morphMany('Property', 'details')
}
What I tried
A lot, really. But somehow I'm always doing something wrong or missing something. The solutions that, in my opinion should work are either:
Property::with(array('details' => function($query) {
$query->where('rooms', 3);
}));
or
Property::with('details')
->whereHas('details', function($query) {
$query->where('rooms', '=', '3');
});
But in both cases I get the following FatalError.:
Class name must be a valid object or a string
Has anyone of you already had a similar problem? Thank you very much for any kind of hint.
Let's start with your naming convention:
public function detail() // It relates to a single object
{
return $this->morphTo();
}
And
public function properties() // It relates to several objects
{
return $this->morphMany('Property', 'details')
}
Then you would be able to do this:
$properties = Property::whereHas('details', function($q)
{
$q->where('rooms', '=', '3');
})
->where('price', '=', 600)
->get();
Please note that this will never return a Parcel, since there isn't a parcel with a room.

Resources