eloquent relation with three tables in laravel 5.4 - laravel-5.4

I have three Models named as Job , JobDetail and Customer.Job has many relation with JobDetail and Customer has many relation with Job.
Below is the structure of tables.
Job
id customer_id jobname
JobDetail
id job_id days
Customer
id name
Below are the models:
class Job extends Model
{
public function job_details()
{
return $this->hasMany('App\JobDetail','job_id','id');
}
}
class Customer extends Model
{
public function customer()
{
return $this->hasMany('App\Job','customer_id','id');
}
}
class JobDetail extends Model
{
//
}
i was trying to execute the below query but its throwing error like Call to undefined relationship [customer] on model [App\Job].
My query :
$data = Job::with(['job_details','customer'])->get();
Can some body suggest me how do i connect these models and get the data ?
Thank You !

You did not specify a relationship for customer in your Job model.
So, something like this should do the trick:
public function customer()
{
return $this->belongsTo('App\Customer','job_id','id');
}

Related

hasOne with null-able in laravel not working

I have a customer table which has a field called 'policy_id', where policy_id points to policy table. It is a null-able field, ie. Some customers may not have a policy.
I have a relationship code like this in Customer.php
public function policy() {
return $this->hasOne('App\Models\Policy', "id", "policy_id");
}
But when I issue a search request I am getting error like this:
Illuminate\Database\Eloquent\ModelNotFoundException: No query results for model [App\Models\Policy]
If I modify the function like this:
public function policy() {
if ($this->getAttribute('policy_id')) {
return $this->hasOne('App\Models\Policy', "id", "policy_id");
} else {
return null
}
}
But I am getting an error like this:
Call to a member function getRelationExistenceQuery() on null
Here is my search code:
$c = new Customer();
return Customer::doesntHave('policy')->orWhere(function (Builder $query) use ($req) {
$query->orWhereHas('policy', function (Builder $query) use ($req) {
$p = new Policy();
$query->where($req->only($p->getFillable()))
->orWhereBetween("policy_period_from", [$req->policy_period_start_from, $req->policy_period_start_to])
->orWhereBetween("policy_period_to", [$req->policy_period_end_from, $req->policy_period_end_to])
->orWhereBetween("payment_date", [$req->payment_date_from, $req->payment_date_to]);
});
})->where($req->only($c->getFillable()))->get();
Am I missing something or are there any other ways to do this?
PS: While debugging the above search code is returning successfully, but the exception happening from somewhere inside Laravel after the prepareResponse call.
Thanks in advance.
return $this->hasOne('App\ModelName', 'foreign_key', 'local_key');
Change the order, put the foreign_key policy_id in front of id
In your Customer Model, you need to use belongsTo method:
public function policy() {
return $this->belongsTo('App\Models\Policy', "policy_id", "id");
}
And In your Policy Model, use hasOne:
public function customer() {
return $this->hasOne('App\Models\Customer', "policy_id", "id");
}
First of all, you placed the wrong params.
$this->belongsTo('App\Models\Policy', "FK", "PK");
public function policy() {
return $this->belongsTo('App\Models\Policy','policy_id', 'id');
}
And for null value of policy_id you can use withDefault();
public function policy() {
return $this->belongsTo('App\Models\Policy','policy_id', 'id')->withDefault([
'name' => 'test'
]);;
}
there's a number of problems there but can you perhaps specify the namespace and the class of both your models - Customer and Policy.
By default, the models you create with php artisan make:model will use the \App namespace e.g. \App\Customer and \App\Policy.
Just double check that.
Also, with regards to the relationship, if the Laravel conventions have been followed you could just:
In the Customer model
public function policy() {
return $this->belongsTo(Policy::class);
}
In the Policy model
public function customer() {
return $this->hasOne(Customer::class);
}
of if a multiple customers can be under one policy
public function customers() {
return $this->hasMany(Customer::class);
}
Good luck

Multiple foreign keys from one table to same field in another table in Laravel

I am working on a project in Laravel where I have two table.
- "teams" (table) with "Team" (model)
- "players" (table) with "Player" (model)
Users can pick any combination of 12 players to make their own team so I am trying to create "one to many" relationship where players will have only one record for each player but many teams can have same player in them.
"players" table have column "id" as primary key.
"teams" table have 12 columns like "player1_id", "player2_id", "player3_id" and so on and every column will act as a foreign key of the "id" in players table.
My clear cut question is - what code do I need to put in both models (Player and Team) so I can access the information through Eloquent.
so far I have put this code in my teams table but not sure if this is the right thing to do.
for the players table, I have no clue what to write in there.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Team extends Model
{
//
public function player1()
{
return $this->belongsTo('App\Player', 'player1_id');
}
public function player2()
{
return $this->belongsTo('App\Player', 'player2_id');
}
public function player3()
{
return $this->belongsTo('App\Player', 'player3_id');
}
public function player4()
{
return $this->belongsTo('App\Player', 'player4_id');
}
public function player5()
{
return $this->belongsTo('App\Player', 'player5_id');
}
public function player6()
{
return $this->belongsTo('App\Player', 'player6_id');
}
public function player7()
{
return $this->belongsTo('App\Player', 'player7_id');
}
public function player8()
{
return $this->belongsTo('App\Player', 'player8_id');
}
public function player9()
{
return $this->belongsTo('App\Player', 'player9_id');
}
public function player10()
{
return $this->belongsTo('App\Player', 'player10_id');
}
public function player11()
{
return $this->belongsTo('App\Player', 'player11_id');
}
public function bonus_player()
{
return $this->belongsTo('App\Player', 'bonus_player_id');
}
}
There are several ways to do it:
1- You can put the team players in a separate table, let's say team_players, with columns, team_id, player_id, and position. validate in your code that always 12 players are present. This would be a many-to-many relationship.
in this scenario, you can use this code in your Team model:
public function players() {
return $this->belongsToMany(Player::class, 'team_players');
}
Handling the logic in code can be a bit troubling for a laravel beginner though.
2- You can simply perform a query based on the order:
public function player(int $position){
$playerId = $this->attributes('player'.$position.'_id');
return Player::find($player);
}
3- you can define magic methods, although I strongly discourage you from doing so.
public function __call(string $name , array $arguments){
if (Str::beginsWith($name, 'player')){
return $this->belongsTo(Player::class, $name.'_id');
}
}
there might be other ways too, but I suspect they'd be a little messier.

Laravel Relations One to One and One to Many

I have three models Class, Students and Studentinfo. Class and students are in a One to Many relationship and Sudents and studentinfo are in a one to one relationship.
While getting students from certain Class I get a list of data in an array.
What is the best way to get data from studentinfo for each student in the array?
I am trying to get this data in json format.
You'd set up relationships like the following on the models, the important one being the hasManythrough relation:
// Class.php
public function students() {
return $this->hasMany(Student::class);
}
public function studentInfo()
{
return $this->hasManyThrough(StudentInfo::class, Student::class);
}
// Student.php
public function studentInfo() {
return $this->hasOne(StudentInfo::class);
}
public function classes() {
return $this->belongsToMany(Class::class);
}
// StudentInfo.php
public function student() {
return $this->belongsTo(Student::class);
}
... you may cast a model or collection to a string, which
will automatically call the toJson method on the model or collection:
$json = (string)$class->studentInfo;
Laravel Docs: Serialization

Querying 'across' pivot table

I have two models, beers and distributions, which have a many-to-many relationship. The pivot model hasMany kegs, which contain some relevant information to the beer such as pricing and status. When I build my beer index, I need all the information of the beer model, the distributor model, and the keg model. What I am trying to figure out is how to query for all the information in an efficient manner. Here is my current query:
Keg's are scoped on status:
public function scopeStatus($query, $status)
{
return $query->where('status', '=', $status);
}
and I build my beers index with:
$kegs = Keg::status($status)->get();
$beers=[];
foreach ($kegs as $keg){
$beer = Beer::find($keg->beer_distribution->beer_id);
$distributor = Distributor::find($keg->beer_distribution->distributor_id);
$beers[]=[
'beer' => $beer,
'keg' => $keg,
'distributor' => $distributor];
}
return $beers;
I know that this is a slow query but im not sure how to do this in a single query. Is there a way that I can run this faster?
Some relevant model code:
class Beer extends Eloquent {
public function distributors()
{
return $this->belongsToMany('Distributor', 'beer_distributions');
}
class BeerDistribution extends Eloquent {
protected $fillable = ['beer_id', 'distributor_id'];
public function kegs()
{
return $this->hasMany('Keg', 'beer_distribution_id');
}
class Distributor extends Eloquent {
public function beers()
{
return $this->belongsToMany('Beer', 'beer_distributions');
}
class Keg extends Eloquent {
public function scopeStatus($query, $status)
{
return $query->where('status', '=', $status);
}
public function beerDistribution()
{
return $this->belongsTo('BeerDistribution');
}
}
So I figured out that what I really needed to do was add my query building relations on my Keg model (which was the fatherest 'down' in the nest of relations), and then use eager loading!
I now build my beers index like so:
$beers=[];
foreach (Keg::status($status)
->with('kegsize',
'beerDistribution.beer.brewery',
'beerDistribution.beer.style',
'beerDistribution.distributor')->get() as $keg){
$beers[]=$keg;
}
return $beers;
This brings me down to a stunning total of 10 queries.

Laravel: saving multiple models at once / json nested input

I am submitting a POST request to my API endpoint using Postman.
In my nested JSON, an artist has one or more albums and each album has one or more songs.
I have two questions:
1) How do I perform nested array validation in Laravel? I am looking for an optimal / standard Laravel way to do so.
2) How do I save multiple models together?
Note: I did create the relationships in my Eloquent models, such as
class Artist extends Eloquent {
public function albums()
{
return $this->hasMany('Album');
}
}
class Album extends Eloquent {
public function songs()
{
return $this->hasMany('Song');
}
}
class Song extends Eloquent {
public function album()
{
return $this->belongsTo('Album');
}
}
class Album extends Eloquent {
public function artist()
{
return $this->belongsTo('Artist');
}
}
1) Use the validator's each method:
$validator = Validator::make(Input::all(), [...rules...]);
$validator->each('albums', [...rules...]);
2) After creating the artist, loop through your albums and call create on the relationship:
$artist = Artist::create(Input::all());
foreach (Input::get('albums') as $album)
{
$artist->albums()->create($album);
}