Laravel relations with composite, non-standard foreign keys - laravel

I unfortunately need to import data from a third-party vendor and use their non-standard database schema with my laravel project. In addition, I need to store multiple "firms," each with their own set of users in my database.
I'm trying to figure out the best way (if it can be done) to use Eloquent to handle the relationships between these tables. So for instance, with my table structure like this:
BmPerson
'id',
'firmId',
'personId'
BmCoverage
'id',
'firmId',
'personId',
'securityId'
BmSecurity
'id',
'firmId',
'securityId'
... for instance, I need to associate a "BmPerson" with many "BmSecurity" through the "BmCoverage" table.
But I need to somehow use composite keys, because I am storing multiple "firms" in each table (per the 3rd party vendor's database schema).
One approach I've used so far is scoping, e.g.: for my BmCoverage model:
public function scopeFromFirm($query,$firmId){
return $query->where('firmId','=',$firmId);//->where('personId','=',$personId);}
public function scopeFromPerson($query,$personId){
return $query->where('personId','=',$personId);//->where('personId','=',$personId);}
Then I can retrieve the coverage list for an individual person, but I still need to somehow be able to associate the "BmCoverage" with the "BmSecurities." I suppose I could just add a scope the BmSecurities class too, but it would be nicer to just use Eloquent.
Has anyone come up with a good way to use composite keys in laravel model relationships, or should I just stick with the scoping method?

There is a package here that seems to be perfect for your case:
Compoships offers the ability to specify relationships based on two
(or more) columns in Laravel 5's Eloquent. The need to match multiple
columns in the definition of an Eloquent relationship often arises
when working with third party or pre existing schema/database.
You would use it like this:
class BmPerson extends Model
{
use \Awobaz\Compoships\Compoships;
public function bmCoverages()
{
return $this->hasMany('App\BmCoverage', ['firmId', 'personId'], ['firmId', 'personId']);
}
}
If every BmSecurity belongs to exactly one BmCoverage, and every BmCoverage belongs to exactly one BmPerson its probably easier to replace 'firmId', 'personId' with bmperson_id in BmCoverage DB; and 'firmId', 'securityId' with bmcoverage_id in BmSecurity. Then you can use default hasMany relations with one key.

Everything you need for this can be found here https://laravel.com/docs/5.2/eloquent-relationships
You can easily define which cols sohuld be the referenced key.
Example:
public function bmCoverages() {
return $this->hasMany('App\BmCoverage', 'firmId', 'id');
}
This would probably belong to your App\Firm or whatever it is called.
In general the hasMany relations looks like this
return $this->hasMany('App\Comment', 'foreign_key', 'local_key');
As you can see you can specify the keys.

As the others have said, you need to use the HasMany and HasManyThrough relationship.
Here from your table definitions, you simply need access to:
Person->BmCoverage(s)
Person->BmSecurity(s) of an individual.
What I think is the major problem here is linking the BmSecurity with BmCoverage as apparently there's no coverage_id per BmSecurity but rather, a composite mapping through firmId and securityId.
In this case, Laravel does not officially support composite keys unfortunately, although you could use a trait like this... but you could also achieve the same with some tricky hasMany.
i.e. on BmCoverage
$this->hasMany('BmSecurity', 'securityId', 'securityId')
->andWhere('firmId', '=', $this->firmId);
Same applies for BmSecurity from BmPerson using HasManyThrough.
Hope that helps.

read laravel hasManyThrough relationship . it will help you to write this query more easily
https://laravel.com/docs/5.1/eloquent-relationships#has-many-through

Related

Can this block of code of mine can be improved

[This is to populate data from two tables that one has two foreign keys from the same column as reference on the other table]
https://i.stack.imgur.com/D8fiv.png
[This is my schema for the table with the foreign key]
https://i.stack.imgur.com/eYDL0.png
This is written in laravel and it is working however i have an itchy feeling that this is wrong
As someone else has commented, you should put the code in your question. More context might also be necessary as it's not clear what you are trying to return from your view(). Are you returning $citizen, $family, or both? It would also be helpful to include what version of Laravel you are using. I'll assume you are using the latest Laravel 8.
Your code should work but you are making more work for yourself if you don't utilize Laravel's relationships. If you do, all the query stuff you have in your code can be reduced to just a few short lines of code such as this:
public function view(Citizen $citizen)
{
$citizen->load('family');
return $citizen;
}
Database Migration
You can shorten your migration by using foreignId(). See docs for details
https://laravel.com/docs/8.x/migrations#foreign-key-constraints
Before:
$table->integer('client_id')->unsigned();
$table->foreign('client_id')->references('id')->on('citizens');
After:
$table->foreignId('client_id')->constrained();
Route Model Binding
I'm assuming your view() method is in your controller and is called from a route. Since the one parameter required is the client's id, you can use Route Model Binding and skip fetching the client from the database.
https://laravel.com/docs/8.x/routing#route-model-binding
public function view(Citizen $citizen)
{
// your code
}
Relationships
You seem to have relationships set up but you aren't using them to load data. You should be able to load the related objects without any manual queries.
If you have a belongsTo(One to Many) relationship on the Citizen model to the Family model, you can load it like this:
$citizen->load('family');
or just use it like this
$relationship = $citizen->family->relationship;
I don't know what the relationships between your models are but you should read up on the different relationship types in the docs.
https://laravel.com/docs/8.x/eloquent-relationships

How to define eloquent relationship without using model in Laravel?

Following the official documentation it is very easy to define a relationship between two models. However, One of my models just need to access data from 4 different table in a one to one basis. Those tables will have no functionality. So, I don't want to build a model for them.
For example I can do this,
class User extends Model
{
public function phone()
{
return $this->hasOne('App\Phone');
}
}
Here to complete this relationship successfully I need to have a Phone model. However, if I don't have a model can I use just the table name to define relationship? I want to use something like, return $this->hasOne(DB::table('phones');.
I reckon, if I can somehow use this I will have less models to work with which will make my code more manageable. Is it a good practice?

Which relation to use in Laravel?

Which relation to use in Laravel to bind two table through third?
When Doctors can be assigned to some Centers. The intermediate table will be as:
doctor_id | center_id
How to create model in Laravel for this case?
You don't need a model for the intermediate table, simply use attach
Example:
$center = Center::create();
$doctor = Doctor::find(1);
$doctor->centers()->attach($doctor->id);
This is a very simple example but should give you the idea, of how to approach it.
All of it of course requires you have set up your Center and Doctor model with the correct many to many relations
Doctor.php model:
public function centers()
{
return $this->belongsToMany(Doctor::class);
}
See the documentation, for more information.
You could obviously create a model called DoctorsCenter and create it manually by doing this, whenever you want to attach a relation.
DoctorsCenter::create(['center_id' => $center->id, 'doctor_id' => $doctor->id]);
I don't see any good reason for doing this, and would not recommend it.
You can use hasMany or belongsTo relationship of Laravel.
See the laravel documentation, for more information

Laravel: Polymorphic types table vs many types tables

I am trying to determine what the best way to many a relationship describing a type would be using Laravel. For example, I might have a user model that can be of many types. Everything I have ever been taught would suggest I need to make a users_types. However, if I wanted to use Eloquent to reference this relationship, I would also need to make a UserType model and an IdentificationType model. For example:
// User Class
public function type() {
return $this->belongsTo('App\UserType');
}
// User Type Class
public function users(){
return $this->hasMany('App\User');
}
$user->type->description; // Could return 'casual'
This seems like it could quickly become ridiculous if I have a bunch of models and each one could potentially have a "type" or maybe a "status".
Would it be better to make a single types table or a single status table and manage everything with a polymorphic relationship, or is that bad database design? Is there a better way to accomplish this using Query Builder instead of Eloquent?
If it makes semantic sense then using a polymorphic relationship is reasonable. The example Laravel sets is with commentable entities. A commentable entity can either be a video or a post (both allow comments).
In your case you'd need to do something like these tables:
typable_type
type_id | typable_id | typable_type
type
id | name
and use:
public function type() {
return $this->morphToMany(Type::class,"type");
}
There's no practical reason why you can't do this anyway, in your case. There is however a semantic reason. Example:
A User can be of type primary , a Product can be of type primary however does that mean the same thing? For example does it make sense to say : "Everything primary can be accessed through this page" in short when you say primary user and primary product, does the word primary carry the same meaning? If the answer is yes then polymorphism is something you should use.

Laravel5: How are Eloquent model relationships expressed in the database?

There's a missing link I fail to understand.
I use migrations to create database tables and I define the relationships there. meaning.. if I have a person table and a job table and I need a one to many relationship between the person and jobs, I'd have the job table contain a "person_id".
When I seed data or add it in my app, I do all the work of adding the records setting the *_id = values etc.
but somehow I feel Laravel has a better way of doing this.
if I define that one to many relationship with the oneToMany Laravel Eloquent suports:
in my Person model.....
public function jobs()
{
return $this->hasMany('Jobs);
}
what's done on the database level? how do I create the migration for such table? Is Laravel automagically doing the "expected" thing here? like looking for a Jobs table, and having a "person_id" there?
Yep, Laravel is doing what you guess in your last paragraph.
From the Laravel documentation for Eloquent Relationships (with the relevant paragraph in bold):
For example, a User model might have one Phone. We can define this
relation in Eloquent:
class User extends Model {
public function phone()
{
return $this->hasOne('App\Phone');
}
}
The first argument passed to the hasOne method is the name of the
related model. Once the relationship is defined, we may retrieve it
using Eloquent's dynamic properties:
$phone = User::find(1)->phone;
The SQL performed by this statement
will be as follows:
select * from users where id = 1
select * from phones where user_id = 1
Take note that Eloquent assumes the foreign key of the relationship based on the model name. In this case, Phone model is assumed to use a user_id foreign key.
Also note that you don't actually have to explicitly set the foreign key indexes in your database (just having those "foreign key" columns with the same data type as the parent key columns is enough for Laravel to accept the relationship), although you should probably have those indexes for the sake of database integrity.
There is indeed support to create foreign key relationships inside migration blueprints and it's very simple too.
Here is a simple example migration where we define a jobs table that has a user_id column that references the id column on users table.
Schema::create('jobs', function($table)
{
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
});
You can also use some other methods that laravel provides such as onDelete() or onUpdate
Of course to understand better the options that are available to you please read the documentation here.
Edit:
Keep in mind that Eloquent is just using fluent SQL wrapper and behind the scenes there are just raw sql queries, nothing magical is happening, fluent just makes your life a lot easier and helpers you write maintainable code.
Take a look here about the Query Builder and how it works and also, as #Martin Charchar stated , here about Eloquent and relationships.

Resources