foreign keys equivalents of laravel relationships - php

so i have those models
// Curso.php
public function trienio()
{
return $this->hasMany('App\Trienio');
}
// Trienio.php
public function curso()
{
return $this->belongsTo('App\Curso');
}
public function oe()
{
return $this->belongsTo('App\OE');
}
public function aluno()
{
return $this->hasMany('App\Aluno');
}
// Oe.php
public function trienio()
{
return $this->hasMany('App\Trienio');
}
// Aluno.php
public function trienio()
{
return $this->belongsTo('App\Trienio');
}
public function pap()
{
return $this->hasOne('App\PAP');
}
// Pap.php
public function aluno()
{
return $this->belongsTo('App\Aluno');
}
public function video()
{
return $this->hasOne('App\Video');
}
// Video.php
public function pap()
{
return $this->belongsTo('App\Pap');
}
and i'm having trouble "converting" those to sql foreign keys. can anybody give me insight on what the foreign keys equivalents will be considering those eloquent relationships? ty in advance
p.s - i can provide more details if needed.
p.s2 - what i REALLY want to know is how i should structure the fields, the sql foreign keys and the constraints based on those eloquent relationships. and how do i that ?

When ever you have hasMany relation, please specify the foreign key used. as follows
// Curso.php
public function trienio()
{
return $this->hasMany('App\Trienio', 'curso_id');
}
this means you have one to many relation ship between Curso and Trienio, but the table trienio must have a field as curso_id (If you want default implementation, no need to establish hard relationship using SQL foreign key constraints) By default this relation will work.
And in belongsTo you dont need to specify the key (Optional).
To fetch the data from Curso
$curso = Curso::find(1);
$trienio = $curso->trienio;
At the trienio side, its okay
// Trienio.php
public function curso()
{
return $this->belongsTo('App\Curso');
}
Similarly for all other.
Note: If you do like this for Curso and Trienio (one to many), the table of Trienio model must have curso_id field and by default relationship will work without doing anything at SQL side.
Update:Using SQL, modify table of Trienio model.
ALTER TABLE trienios MODIFY COLUMN curso_id INT NOT NULL,
ADD CONSTRAINT trienios_curso_id_fk
FOREIGN KEY(curso_id)
REFERENCES Curso(id);
Using Schema builder (Migration Files) Link
$table->foreign('curso_id')
->references('id')->on('curso')
->onDelete('cascade');
You can specify the cascade rule.

Related

how to make relation between two tables in laravel

I tried all the tutorials on internet and Youtube but it doesn't work so you guys are my last chance please I need your help.
I need to use $candidate->service->service_name
and $candidate->documents->doc but it doesn't work
I get this error [Call to undefined method stdClass::service()] (by the way, should I use"documents" or "document" ?)
the "candidate" has more than one document, and the document belongs to only one "candidate";
the "candidate" has to choose one "service" (to work in) and the service is chosen by a lot of "candidate"
I have 3 tables :
services=['id_service',
'service_name'] #((id_service Primary key))
candidate =[ 'id_candidate',
'id_service',
'name',
'email'...]; #((id_candidate Primary key, id_service Foreign key))
document=['id_doc',
'id_candidate',
'doc'] #((id_doc Primary key, id_candidate Foreign key))
IN CANDIDATE'S MODEL :
use App\Models\Service;
use App\Models\Document;
public function documents()
{
return $this->hasMany(Document::class);
}
public function service()
{
return $this->belongsTo(Service::class);
}
IN DOCUMENT'S MODEL :
use App\Models\Candidate;
public function candidate()
{
return $this->belongsTo(Candidate::class, 'id_candidate', 'id_doc');
}
IN SERVICE'S MODEL :
use App\Models\Candidate;
public function candidates()
{
return $this->hasMany(Candidate::class);
}
IN CANDIDATECONTROLLER :
public function show( $id_candidate)
{
$candidate = DB::table('candidates')->select('id_candidate','id_service','name')->where('id_candidate', $id_candidate)->first();
return view ('candidate.profile', compact('candidate'));
}
IN candidate/profile :
...
<input type="text" id="service" name="service" value={{ $candidate->service()->service_name }}>
You're my hope
Thank you in advance
Candidate Model
class Candidate extends Model
{
public function candidate_documents()
{
return $this->hasMany(Document::class, 'id_candidate');
}
public function candidate_service()
{
return $this->BelongsTo(Service::class, 'id_service');
}
}
By using DB:: relationships do not work as commented by #ceejayoz
so from candidate controller you can used it like this
$candidateResult= Candidate::with('candidate_documents')->with('candidate_service')->get();
you can also use hasOne in candidate_service() depends on where is your foreign key is
In your code, Candidate has a id_service column, then candidate belongsTo Service.
by using hasOne and hasMany we are telling laravel that this table does not have the foreign key.

Laravel 6 eager loading using with() on a belongsTo relationship is only *sometimes* returning null

I am working on a project where we have a model for a service provider, the type of care provided, and the status:
Provider:
class Provider extends Model
{
protected $table = 'providers';
public function status() {
return $this->belongsTo('App\Status');
}
public function caretype() {
return $this->belongsTo('App\CareType', 'id');
}
}
CareType:
class CareType extends Model
{
protected $table = 'type_of_care';
public function providers() {
return $this->hasMany('App\Providers', 'type_of_care_id');
}
public function category() {
return $this->belongsTo('App\CareCategory');
}
}
Status:
class Status extends Model
{
protected $table = 'status';
public function providers() {
return $this->hasMany('App\Providers');
}
}
On the my SearchController (the controller that processes search requests for providers), the show() function using eager loading retrieves the caretype perfectly. But on the search() function that lists the collection of search results, the caretype is always listed as null.
I don't understand why it would be working in one function but not the other, especially when the code to eager load is exactly the same in both functions:
public function search(Request $request)
{
$validated = $request->validate([
//I removed the validation code for this post
]);
$providers = Provider::with(['status', 'caretype'])->get();
return view('search.results', ['providers' => $providers]);
}
public function show($id)
{
$single_provider = Provider::with(['status', 'caretype'])->where('id', $id)->first();
return view('search.details', ['provider' => $single_provider]);
}
Any help in this would be appreciated. I know that the model and relationship foreign keys are properly defined because the show() function is able to get the caretype just fine.
nope. your relationship and foreign keys are not correct. as from the doc
Eloquent determines the default foreign key name by examining the name of the relationship method and suffixing the method name with a _ followed by the name of the primary key column. However, if the foreign key on the Child model is not like that, you may pass a custom key name as the second argument to the belongsTo method.
you are passing the id column as the foreign key in Provider model's caretype ralation but your foreign key is type_of_care_id. so you are getting some results when the id matches but if not, you are getting null. change your relationship code to
public function caretype()
{
return $this->belongsTo('App\CareType', 'type_of_care_id');
}
now again from the doc
If your parent model does not use id as its primary key, or you wish to join the child model to a different column, you may pass a third argument to the belongsTo method specifying your parent table's custom key.
in your case id is the primary key. so you don't have to pass the third parameter. just update the primary key reference and everything will work perfectly.

Retrieve data from multiple joins using eloquent

I'm developing a project to track deliveries of goods.
My idea would be that one delivery can go to different places, and all those places are connected by single trips.
Here is my Eloquent schema:
class Delivery extends Model
{
public function places()
{
return $this->hasMany(Place::CLASS, 'delivery_id');
}
public function trips()
{
// what should I do here?
}
}
class Place extends Model
{
public function delivery()
{
return $this->belongsTo(Delivery::CLASS, 'delivery_id');
}
}
class Trip extends Model
{
public function departurePlace()
{
return $this->belongsTo(Place::CLASS, 'departure_place_id');
}
public function arrivalPlace()
{
return $this->belongsTo(Place::CLASS, 'arrival_place_id');
}
}
Basically what I am trying to do is to get all the trips that are related to one delivery. Or, as another way of saying it, all the trips that connect all the places that one delivery must go through.
This is the SQL query that achieves the result I want:
select distinct trip.*
from delivery
join place on (place.delivery_id = delivery.id)
join trip on (place.id = trip.arrival_place_id or place.id = trip.departure_place_id)
I would like to have a trips() method on my Delivery model, that returns that result.
However I am quite confused as to how achieve that using Eloquent.
Unfortunately we could have simply used the union method to achieve this, but it seems that is doesn't work for hasManyThroughrelations.
Anyway, I think Eloquent relations are not meant to be used to achieve such a specific query.
Instead, you may use Eloquent scopes to achieve this.
So based on the answer of #Saengdaet, we can write two relations and then combine them with a scope:
(BTW: I don't know why you said that his code gave an error...)
class Delivery extends Model
{
public function places()
{
return $this->hasMany(Place::class);
}
public function outboundTrips()
{
return $this->hasManyThrough(
Trip::class,
Place::class,
"delivery_id", // Foreign key on places table
"departure_place_id", // Foreign key on trips table
);
}
public function inboundTrips()
{
return $this->hasManyThrough(
Trip::class,
Place::class,
"delivery_id", // Foreign key on places table
"arrival_place_id", // Foreign key on trips table
);
}
public function scopeTrips($query)
{
$deliveriesWithTrips = $query->with(['outboundTrips', 'inboundTrips'])->get();
$trips = [];
$deliveriesWithTrips->each(function ($elt) use (&$trips) {
$trips[] = $elt->inboundTrips->merge($elt->outboundTrips);
});
return $trips;
}
}
And now to retrieve all trips for a given delivery you simply write:
Delivery::where('id', $id)->trips();
If you want to get all trips from using Delivery model, you can use `hasManyThrough" relationship that provides a convenient shortcut for accessing distant relations via an intermediate relation.
But you have to choose which FK on your Trip model will you use to relate it
You can refer to "has-many-through" relationship
class Delivery extends Model
{
public function places()
{
return $this->hasMany(Place::CLASS, 'delivery_id');
}
public function trips()
{
return $this->hasManyThrough(
Trip::Class,
Place::Class,
"delivery_id", // Foreign key on places table
"departure_place_id", // Foreign key on trips table
"id", // Local key on deliveries table
"id" // Local key on places table
);
}
}

Join database tables using foreign key laravel

I have two tables that I need to join in order to access more data. My first table thought_journal_entries contains many id values from the second table emotions. The primary key in emotions is id and the foreign key in thought_journal_entries is em_id.
This is in the Emotions model
public function thoughtJournalEntry() {
return $this->belongsTo(ThoughtJournalEntry::class, 'id');
}
This is in the ThoughtJournalEntry model
public function emotions() {
return $this->hasMany(Emotions::class, 'id');
}
This is how far I've got, not sure if this is correct and how I would join these in the controller?
If you set em_id in thought_journal_entries table, that means that thoughtJournalEntry belongs to Emotions, and Emotions hasMany thoughtJournalEntry, so in this case relations must be declared this way
// Emotions class
public function thoughtJournalEntries() {
return $this->hasMany(ThoughtJournalEntry::class, 'em_id');
}
// ThoughtJournalEntry class
public function emotion() {
return $this->belongsTo(Emotions::class, 'em_id');
}
// access from controller
$emotion->thoughtJournalEntries;
$thoughtJournalEntry->emotion;
If this type of relations is not what you wanted, then probably you have to change your db tables

Laravel eager relationships empty query

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');

Categories