I have an intermediate table titled
app_services
It consists of the following columns :
app_service_id (PK)
app_id (FK)
service_id (FK)
The final table is the services table :
Services
service_id (PK)
service_name
service_icon
I am trying a hasManyThrough on app_services. But it's returning the wrong results..
For app_id = 1 it has the service id's of 1 & 3. But it is returning back the service_id's pf 1 & 4.
In my app_model I am defining the relationship as follows :
public function services()
{
return $this->hasManyThrough(
'App\Service', 'App\AppService',
'service_id', 'service_id', 'app_id'
);
}
Now that looks right to me? Would someone mine checking if it's correct or not.
Thank You!
public function services()
{
return $this->belongsToMany('App\Service');
}
Now, with such declaration of relationships Laravel “assumes” that pivot table name obeys the rules and is app_service.But, if it’s actually different (for example, it’s plural), you can provide it as a second parameter:
public function services()
{
return $this->belongsToMany('App\Service','app_services');
}
'app_services' is an intermediate table name
Moreover, you can specify the actual field names of that pivot table, if they are different than default app_id and service_id. Then just add two more parameters – first, the current model field, and then the field of the model being joined
public function services()
{
return $this->belongsToMany('App\Service','app_services','app_id','service_id');
}
Now,using this relationship you can retrieved data
$app = App::find($app_id);
$app->services();
Related
I feel like this should work. I have a list of products and categories (types).
Tables:
Products
- id
- name
- etc
Types
- id
- name
- etc
ProductTypes
- product_id
- type_id
Now, I feel like in the Type model in Laravel, I should be able to define this relationship:
public function products()
{
return $this->hasManyThrough(Product::class, ProductType::class, 'type_id', 'id');
}
I've tried other variations with the secondary ids in the additional parameters but no luck, always an empty list. Is ProductTypes a pivot table and therefore should be dealt with differently?
Edit: What's weird is that for the final 2 parameters ($localKey = null, $secondLocalKey = null) even if I enter complete garbage no error is thrown but these 2 parameters $firstKey = null, $secondKey = null have to be correct).
You are using the wrong relationship. Based on your database structure, a product can belong to many type. Therefore, it should be a BelongsToMany instead of a HasManyThrough.
You can achieve what you want with the following method, by passing the table name of your ProductTypes as the second parameter:
public function products()
{
return $this->belongsToMany(Product::class, 'product_types');
}
If your ProductType model extends Illuminate\Database\Eloquent\Relations\Pivot, you can do:
public function products()
{
return $this->belongsToMany(Product::class, 'product_types')
->using(ProductType::class);
}
For more information about Many to Many relationships: https://laravel.com/docs/6.x/eloquent-relationships#many-to-many
I am having an issue getting a hasManyThrough to work:
public function deliveryContainers() : HasManyThrough
{
return $this->hasManyThrough(
DeliveryContainer::class, // Final
StockMovement::class, // Intermediate
'product_id', // Foreign key on Intermediate
'id', // Foreign key on Final
'product_id', // Local key on Current
'location_id' // Local key on Intermediate
)->where('delivery_id', $this->delivery_id);
}
Because the stockMovements table returns multiple results, my resulting delivery containers collection contains duplicate entries. If I could somehow put a group/unique on the intermediate table query then this would be resolved.
I can get a collection with the correct deliveryContainers eager loaded using the following:
public function deliveryContainers()
{
return $this->hasMany(StockMovement::class, 'entity_id', 'delivery_id')
->with('deliveryContainer')
->where('product_id', $this->product_id)
->get()
->unique('location_id');
}
However, to access the deliveryContainer I now have the following:
foreach($this->deliveryContainers() as $row){
$row->deliveryContainer->id;
}
And what I would like to have...
foreach($this->deliveryContainers() as $row){
$row->id;
}
Is there any way to push the eager loaded relationship up a level (if that can be used to describe it), or even better add some kind of unique filter to the hasManyThrough relationship?
Table Structure
delivery_exceptions (where this relationship originates)
product_id
delivery_id
delivery_containers
id
delivery_id
stock_movements
entity_id (linked to delivery id)
product_id
Relationships
A delivery exception belongsTo a product
A product hasMany stock_movements
A stock movement belongsTo a delivery container
A delivery exception hasMany delivery containers... (indirectly, through a combination of the product and the stock movements)
You've got a really tough setup there and I'm not entirely sure that I got the full idea behind it (also because of you using entity_id at some place instead of delivery_id). But nonetheless, I gave it a shot.
The hasManyThrough relationship you defined looks actually not too bad, but in my opinion there is a better way to get to the result. But first let's have a look at your relationships:
3
+-------------------------------------+
4 v |
+-------------> Delivery <----------+ |
| | 1 |
+ + +
DeliveryException +---> Product <---+ StockMovement +---> DeliveryContainer
+ ^
+---------------------------------------------------------+
2
As a StockMovement already belongs to a DeliveryContainer, which in return belongs to a Delivery, the relation from StockMovement to Delivery (marked as 1) seems obsolete to me. Anyway, to get relation 2 on your model, you can use the paths 3 and 4 to your advantage:
class DeliveryException
{
public function deliveryContainers(): HasMany
{
return $this->hasMany(DeliveryContainer::class, 'delivery_id', 'delivery_id');
}
}
Obviously, this will give you all the DeliveryContainers, unfiltered by the Product. Therefore I suggest adding a second function:
public function deliveryContainersByProduct(): HasMany
{
return $this->deliveryContainers()
->whereHas('stockMovements', function ($query) {
$query->where('product_id', $this->product_id);
});
}
The accepted answer is far more elegant, but this is another way to do this too:
public function deliveryContainers1()
{
return $this->hasManyThrough(
DeliveryContainer::class, // Final
StockMovement::class, // Intermediate
'product_id', // Foreign key on Intermediate
'id', // Foreign key on Final
'product_id', // Local key on Current
'location_id' // Local key on Intermediate
)
->where('delivery_id', $this->delivery_id)
->distinct();
}
I have two tables in MySQL Apoderados and Alumnos each with their primary identifier id, then I have another table Apoderado_Alumno where the id of each table is added, The main idea is that a Proxy can have 1 or more Alumno and that 1 Alumno can belong to One more Apoderado
I currently have the following relationships in models
ApoderadoAlumno
public function apoderado()
{
return $this->hasOne(Apoderado::class,'id','apoderado_id');
}
public function alumno()
{
return $this->hasOne(Alumno::class,'id','alumno_id');
}
Is it the correct way? I feel no, do I have to add the relationship to the Student and Teacher models?
Update
Sorry for the confusion, create the intermediate table because the Alumno may have more than 1 Apoderado (father and mother or other)
After your update.. it means that the relationship between the two models should be a Many to Many relationship:
- Apoderado m ----- m Alumno.
Defining relationships
As you can see in the documentation. Relationships are defined in the model. So in:
- Alumno model, add the method apoderados():
...
public function apoderados()
{
return $this->belongsToMany(Apoderado::class,
'apoderado_alumno',
'alumno_id',
'apoderado_id'
);
}
...
Now in your Apoderado model:
...
public function alumnos()
{
return $this->belongsToMany(Alumno::class,
'apoderado_alumno',
'apoderado_id',
'alumno_id'
}
...
In your controller
Then for querying, for example alumnos related to an apoderado, you just need to do:
$apoderado = Apoderado::find($apoderado_id);
return $apoderado->alumnos; // this will return a collection of alumnos.
In Laravel I just started with models and I have this database structure:
users
id | username | password | group | //(group is the id of the group)
groups
id | groupname |
group_pages
group_id | page_id | create | read | update | delete
pages
id | pagename
I am trying to check if the user can create/read/update/delete on the page he's on.
So I have 4 Models for this at the moment: Users, Pages,Group_pages and Groups. So in the models, I define the relationships like so:
User model:
public function group()
{
return $this->belongsTo('group', 'group', 'id');
}
Group Model:
public function users()
{
return $this->hasMany('users', 'group', 'id');
}
public function group_pages()
{
return $this->hasMany('group_pages', 'group_id', 'id');
}
I am using this in my controller like this:
$group_id = User::find(Session::get('user_id'));
$crud = Group::find($group_id->group)->group_pages()->first();
As described in the documentation.
but this is giving me the error:
Class group_pages not found
What is going wrong here?
I'm not sure about assigning the keys in the relationships.
I know this:
One to One Inverse:
return $this->belongsTo('class', 'local_key', 'parent_key');
One to Many:
return $this->hasMany('class', 'foreign_key', 'local_key');
I dont know about the One to Many Inverse. I know it's: return $this->belongsTo('table');, but I dont know about the keys.
Group_pages model:
class Group_pages extends Eloquent {
public function pages()
{
return $this->belongsTo('pages', 'id', 'group_id');
}
public function group()
{
return $this->belongsTo('group', 'id', 'group_id');
}
}
Model files should be named singularly and in camel-case, i.e. User, Page, Group. A model representing the join between users and groups isn’t necessary.
Then when it comes to defining the relationships, the first parameter is the class name of the model:
class User {
public function group()
{
return $this->belongsTo('Group', 'local_key', 'parent_key');
}
}
You’re making life difficult for yourself by going against Laravel’s conventions.
If you name your columns as per Laravel’s conventions, you then don’t need to specify them in your relationship definitions either. So your users table should have a column named group_id that’s a foreign key referencing the id column in your groups table. Your relationship can then be expressed like this:
class User {
public function group()
{
return $this->belongsTo('Group');
}
}
A lot more succinct and easier to read, and you don’t have to remember which way around the local and foreign column names go.
You can read more about the conventions Laravel uses for model and relation names in the official documentation: http://laravel.com/docs/master/eloquent#relationships
You defined your relationship with a model-class that does not exists.
To solve this, create a group_page-model (or even better GroupPage) and change the corresponding relationship (return $this->hasMany('GroupPage', 'group_id', 'id'); within your Group-model.
Then fix the relationship in your User-model:
public function group() // typo! not groep..
{
return $this->belongsTo('group', 'group'); // remove id, you do not need it
}
Then there is a problem with your controller code which might be fixable like that:
$group_id = User::find(Session::get('user_id'))->group()->id;
$crud = Group::find($group_id)->group_pages()->first();
I always like to recommend Laracasts to peopel who are new to Laravel (i hope you do not know this yet). The basic screencasts are all free (laravel 4 from scratch and laravel 5 fundamendals) and you will lern very fast in no time! Specifically, have a look at the episode on Eloquent Relationsships.
I also strongly recommend sticking to conventions
use the column-name group_id on the users-table for the group-foreign-key).
Classnames should be PascalCase -> Group, not group, and when commiting them as parametes, stick to it (belongsTo('Group'))...
This makes life much easier!
Finally
Be aware that there might be packages for what you are trying to achieve. One that comes to my mind is Entrust.
You're making your life hard with this code and thus you can't make it work.
Check this out first:
// This is User model, NOT group_id
$group_id = User::find(Session::get('user_id'));
Next:
public function group() // I suppose groep was typo, right?
{
// having relation with same name as the column
// makes Eloquent unable to use the relation in fact
return $this->belongsTo('group', 'group', 'id');
}
So, here's what you need:
// User model
public function group()
{
return $this->belongsTo('Group', 'group_id'); // rename column to group_id
}
// Group model
public function pages()
{
return $this->belongsToMany('Page', 'group_pages')
->withPivot(['create', 'read', 'update', 'delete']);
}
Then:
$user = User::find(Session::get('user_id')); // or use Auth for this
$page = $user->group->pages()->find($currentPageId);
// now you can access pivot fields:
$page->pivot->create;
$page->pivot->update;
... and so on
I have 3 tables : hotels, hotels_data, hotels_types
Table hotels have id, type, stars, etc... type field is set as foreign key referencing type_id in hotels_types. I'm managing to get the correct data from hotels_data but have an empty result on getting hotels_types title and I don't understand why.
The code is the following :
class Hotel extends Eloquent {
public function getList() {
$data = Hotel::select('id','stars')->with('HotelData', 'HotelType')->paginate(10);
return View::make('hotels.index')->with('hotels', $data);
}
public function HotelData()
{
return $this->hasOne('HotelsData')->select('id','hotel_id','title');
}
public function HotelType()
{
return $this->hasOne('HotelType','type_id', 'type')->select('id','type_id','title');
}
}
You're using the wrong relationship for HotelType()
Your Hotel model should use the inverse of hasOne, which is belongsTo, because it contains the foreign key to HotelType (when a table contains a foreign key, it always belongs to the table being pointed to).
The following should work:
public function hotelType() {
return $this->belongsTo('HotelType','type', 'type_id')->select('id','type_id','title');
}
I've obtained the desired result with the following:
Hotel::select('hotels.*','hotels_types.title as type')
->join('hotels_types', 'hotels.type', '=', 'hotels_types.type_id')
->with('HotelData');