Eloquent with multiple relations - php

I'm new to Laravel and ORMs in general, so this is probably a very basic concept that I'm missing. I have three tables that I'm trying to define a relation with using Laravel 4's Eloquent ORM. Here's the slimmed-down table definitions:
stores
id (PK)
name
postal_codes
id (PK)
postal_code
city
state
country
locations
id (PK)
store_id (FK => stores.id)
postal_code_id (FK => postal_codes.id)
*additional location-specific fields such as address, phone #, etc
The stores table has a one to many relationship with the locations table, so I can use $this->hasMany("Location") in the Stores model, and $this->belongsTo("Store") in the Location model.
My question is, how do I define the relation between locations and postal_codes in their respective models? The locations table has a many-to-one relationship with the postal_codes table. Ideally I want to be able to do something like this: $store->locations()->first()->city. Is this possible?

Aren't you looking for something like:
class Locations
{
public function city()
{
return $this->belongsTo('PostalCode');
}
}
So now you can call $store->locations()->first()->city. This will return a PostalCode model, if you want to return just the city:
public function getCity()
{
return $this->city()->city;
}
And then you call $store->locations()->first()->getCity().
You could go further and create a __get() magic method so it calls everything dynamically.

It sounds like you have a many-to-many relationship between Stores and Postal_Codes. This would be demonstrated this way in Laravel:
class Store extends Eloquent {
public function postal_codes() {
$this->belongsToMany('Postal_Code', 'location');
}
}
class Postal_Code extends Eloquent {
public function stores() {
$this->belongsToMany('Store', 'location');
}
}
For more info, try this link: Laravel Many-to-Many Relationships.

I believe you are looking for a polymorphic relation.
Modify your locations table to include id, imageable_id, imageable_type, and then whatever additional location information you need. The imageable_id field will contain the ID of whatever you are looking for in it's respective table and the imageable_type will be whatever the name of that model for that table is.
On your models...
Class Location extends Eloquent
{
public function imageable()
{
return $this->morphTo();
}
}
Class Store extends Eloquent
{
public function locations()
{
return $this->morphMany('Location','imageable');
}
}
Class PostalCode extends Eloquent
{
public $table = 'postal_codes';
public function locations()
{
return $this->morphMany('Location','imageable');
}
}
And now, it's possible to retrieve all of the locations for the stores or postal codes with something like
$store = Store::find(1);
foreach($store->locations as $location)
{
//
echo $location->city;
}
$postalCode = PostalCode::find(1);
foreach($postalCode->locations as $location)
{
//
echo $location->city;
}

Related

Laravel Multi BelongsTo RelationShip Merge with Eager Loading

Laravel version:7.0
reviews table (Model - Review) has id, product_type, product_id, rating columns.
product_type can be service, plugin, module and each value has own model App\Service, App\Plugin, App\Module. I could put model names directly in product_type but I prefer to use those values.
Here is Review model relationship.
public function plugin()
{
return $this->belongsTo(Plugin::class, "product_id")->withDefault();
}
public function module()
{
return $this->belongsTo(Module::class, "product_id")->withDefault();
}
public function service()
{
return $this->belongsTo(Service::class, "product_id")->withDefault();
}
public function getItem()
{
if($this->product_type=='module')
{
return $this->module;
}elseif($this->product_type=='service')
{
return $this->service;
}else {
return $this->plugin;
}
}
Now I want to get them with eager loading in Review Model as following:
$reviews = Review::with("getItem")->get();
Without Eager loading, I could use $review->getItem()->name // this returns name of product.
How can I get them with eager loading?
You could have implemented this easily as a polymorphic relationship. In your Reviews Model, you could do this:
Model Structure
App\Review.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Review extends Model
{
public function reviewable()
{
return $this->morphTo();
}
}
Then add reviews() method to your App\Service, App\Plugin and App\Module models
public function reviews()
{
return $this->morphMany('App\Review', 'reviewable');
}
Table Structure
You reviews table could look like this:
reviews
id - integer
body - text
reviewable_id - integer
reviewable_type - string
Note the reviewable_id and reviewable_type fields. The reviewable_id stores the id of the item reviewed and the reviewable_type stores the model related to the item.
Retrieving The Relationship
You may access the relationships via your models. For example, to access all of the reviews for a service, we can use the reviews dynamic property:
$service = App\Service::find(1);
foreach ($service->reviews as $review) {
//
}
You may also retrieve the owner of a polymorphic relation from the polymorphic model by accessing the name of the method that performs the call to morphTo. In your case, that is the reviewable method on the Review model. So, we will access that method as a dynamic property:
$review = App\Review::find(1);
$reviewable = $review->reviewable;
The reviewable will return the model on the Review model either Service, Plugin or Module

How to join two tables with a pivot table using Laravel?

I have these three tables:
tbl_lista_contactabilidad tbl_equipo_postventaatc users
------------------------- ----------------------- -----
id id id
usuarios_id asesor_id name
tbl_lista_contactabilidad.usuarios_id should be related with tbl_equipo_postventaatc.asesor_id. asesor_id should be the "pivot" between tbl_lista_contactabilidad.usuarios_id and users.id to make the relation.
I want to make this relation so I tried to do this relation in this way (I will put only the relation of the model)
Tbl_Lista_Contactabilidad (Model 1)
public function postventaatc(){
return $this->belongsTo('App\Models\Tbl_EquipoPostventaatc','usuarios_id');
}
Tbl_Equipo_Postventaatc (Model 2) -> This should be the pivot model
public function contactabilidad(){
return $this->hasMany('App\Models\Tbl_Lista_Contactabilidad','usuarios_id');
}
public function user(){
return $this->belongsTo('App\Models\User','asesor_id');
}
User (Model 3)
public function postventaatc(){
return $this->hasMany('App\Models\Tbl_Lista_Postventaatc','asesor_id');
}
EXAMPLE:
As you see in the image... if I relate usuarios_id with users directly I will get another name and I don't want that... I want the relation just like in the image
A pivot table is a structure used to join two separate models together with a single relationship. This is called a many-to-many relationship in Eloquent.
From what you've described, this is not the case here. Rather, it looks like a has-many-through relationship.
If I'm understanding correctly, your relationships should look like this:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Tbl_Lista_Contactabilidad extends Model {
protected $table = 'tbl_lista_contactabilidad';
public function postventaatc() {
return $this->belongsTo(Tbl_EquipoPostventaatc::class, 'usuarios_id');
}
}
class Tbl_EquipoPostventaatc extends Model {
protected $table = 'tbl_equipo_postventaatc';
public function contactabilidad() {
return $this->hasMany(Tbl_Lista_Contactabilidad::class, 'usuarios_id');
}
}
class User extends Model {
public function postventaatc() {
return $this->belongsTo(Tbl_EquipoPostventaatc::class, 'asesor_id');
}
public function contactabilidad() {
return $this->hasManyThrough(Tbl_Lista_Contactabilidad::class, Tbl_EquipoPostventaatc::class, 'asesor_id', 'usuarios_id');
}
}
Obviously this is easier for a native English speaker, but I cannot stress how much easier this would be if you were following the Laravel rules around naming your models, tables, and columns. Why does usuarios_id column relate to a table called tbl_equipo_postventaatc? Why use asesor_id instead of user_id? 🤷🏽‍♂️ Those names have nothing to do with each other, and make it hard to figure out what is going on.

Make 2 Different Tables Share a Common Table in Laravel

I want to have two tables one for Employees and one for Companies, both Employees & Companies should be registered within the site, thus they should have records in the users table provided with Laravel. How should I structure the relationships between the models, should I go for polymorphic relationships or use one to one?
The answer is to add two columns to the "users" table: userable_id and userable_type. userable_id will be used to store the id of the row for the entity (Employee or Company), and the userable_type will hold the class path for the Eloquent model.
in create_users_table migration file add these two lines:
// ...
$table->integer('userable_id')->unsigned();
$table->string('userable_type');
// ...
in User.php model:
class User extends Model {
// Add this declaration.
public function userable()
{
return $this->morphTo();
}
}
in your Company.php model:
class Company extends Model
{
// Add this method.
public function user()
{
return $this->morphMany(User::class, 'userable');
}
}
in the Employee.php model do the same as above:
class Employee extends Model
{
// Add this method.
public function user()
{
return $this->morphMany(User::class, 'userable');
}
}
Now you should be able to access the user by running:
App\Company::all()->get(1)->user;
// or
App\Employee::all()->get(1)->user;
And access the entity with this one-liner:
App\User::all()->get(1)->userable;

LARAVEL ELOQUENT - I want to add column from user table to a relation table

I am not much familiar with eloquent orm in laravel
I have 3 tables they are
-- leads
|
Lead_appointments
and users table
since lead_appointments belongs to leads references id on leads by lead_id
the leads_appointments has a column called created_by with user's id in it
I am trying to query user's name and email along with the result as another column when query using eloquent
Lead Model
class Leads extends Model
{
public function appointments()
{
return $this->hasMany('App\Models\LeadsAppointments', 'lead_id');
}
}
My eloquent query in controller
return $this->lead->with('appointments')->find($id);
the result is like this
In under appointments i also want user email and name along with created by in it
But I couldn't figure it out
Add a relation to LeadAppointment model like this:
class LeadAppointment extends Model
{
public function users()
{
return $this->belongsTo('App\Models\User', 'created_by');
}
}
and change leads model like this:
class Leads extends Model
{
public function appointments()
{
return $this->hasMany('App\Models\LeadsAppointments', 'lead_id')->with('users');
}
}

Laravel Eloquent Relationship

I have a sales model defined and when I call Quote::find('1'); it is not returning my sales object. Have I done something wrong with my relationship? Here is the table structure:
Quote: id, companyName, stage, saleId
Sale: id, name, phoneNumber
Class Quote extends Eloquent
{
protected $with = ['sale'];
public function sale()
{
return $this->hasOne('Sale', 'id');
}
}
In my Sale model I have defined:
public function quote()
{
return $this->belongsTo('Quote');
}
I figured it out. Had my relationship backwards.
Class Quote extends Eloquent
{
protected $with = ['sale'];
public function sale()
{
return $this->belongsTo('Sale', 'saleId');
}
}
To understand it better I think you can say that in a belongs_to relationship, the foreign key resides in the table of the model you are trying to create the relationship from. So the above function could be read like "saleID belongsTo Sale model".
The foreign key resides in the other model's table when using has_one.
Try this:
$quote = Quote::with('sale')->find(1);
You should be able to then go something like this $quote->sale->name

Categories