Relationships with Laravel - php

I do not know why, but the result that I am getting it's empty... I am trying to make a relation between a supervisor and a branc_office.
The branch_office just has one supervisor.
The supervisors can have many branch_office to manage.
So the relation it's 1 to Many.
My tables are:
Branch_office fields:
id_branch_office
id_supervisor
branch_office
User fields:
id_user
name
The id_supervisor and id_user make the relation between them.
id_supervisor(foreign key) ----- id_user(primary key)
My models:
User.php
use Notifiable;
protected $primaryKey = 'id_user';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'full_name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* Get the comments for the blog post.
*/
public function branch_offices()
{
return $this->hasMany('App\Branch_Office', 'id_supervisor');
}
Branch_office.php
protected $table = 'branch_offices';
protected $primaryKey = 'id_branch_office';
/**
* Get the post that owns the comment.
*/
public function supervisor()
{
return $this->belongsTo('App\User', 'id_user');
}
In the controller I am doing this:
$branch_office_detail = Branch_Office::find(1)->supervisor()->first();
but it displays a null or empty result... and there is a branch_office with id = 1
So I wonder, what it's wrong? becaiuse I have done this step by step and It's not working.
Thanks.

protected $table = 'branch_offices';
protected $primaryKey = 'id_branch_office';
public function supervisor()
{
return $this->belongsTo('App\User', 'id_supervisor', 'id_user');
}
In almost all relationships the first param is the model, the second the foreign key, the third the local key. Also the the belongsTo function only return one record or null, you dont need to use first()
BranchOffice::find(1) returns the Branch;
BranchOffice::find(1)->supervisor returns the supervisor of the branch 1
BranchOffice::with('supervisor')->find(1) return the office with the supervisor

Related

Better solution to get column from Relationship with Main Model columns

Need a better solution
There is a Post which belongs to multiple Categories and both having Many-to-Many relationship in between them. The intermediate table for many-to-many relationship is PostCategory. PostCategory contains post_id, category_id and sequence of the post. I want to get this sequence with the Post model attributes (title, description, ...).
To get this, am doing like this
$posts = Post::where([
'is_active' => 1,
'is_deleted' => 0,
'is_published' => 1,
'status' => 'publish'
])->whereHas('category', function ($query) use ($params) {
return $query->where([
'category_id' => $params['categoryId'],
]);
})->with([
'category' => function ($query) use ($params) {
return $query->where([
'category_id' => $params['categoryId'],
]);
}
])
->orderBy('live_date', 'DESC')
->orderBy('publish_time', 'DESC')
->get()
->toArray();
foreach ($posts as &$post) {
$post['sequence'] = $post['category']['sequence'];
}
Am getting the expected result but as you can see, first I've to use the closure twice and then have to iterate through entire collection to set sequence at the top-level but as I mentioned, I need a better solution to this (If any)
Post.php
namespace App\Models\Mongo;
/**
* #mixin \Illuminate\Database\Eloquent\Builder
* #mixin \Jenssegers\Mongodb\Query\Builder
*/
class POST extends \Jenssegers\Mongodb\Eloquent\Model
{
/** #var string Mongo Connection Name */
//protected $connection = 'mongodb';
/** #var string Mongo Collection Name */
protected $collection = 'posts';
/** #var bool Enable/Disable Timestamp */
public $timestamps = true;
/** #var string Date format */
protected $dateFormat = 'Y-m-d H:i:s';
/** #var array */
protected $dates = ['created_at', 'updated_at', 'live_date', 'expire_date'];
/**
* // I know this relation is not correct, it must either belongsToMany or hasMany
* // but as of now, I've to fetch the posts belonging to a single category id
* // so using hasOne relation
* #return \Jenssegers\Mongodb\Relations\HasOne
*/
public function category()
{
return $this->hasOne(
PostCategory::class,
'post_id',
'_id'
);
}
}
PostCategory.php
namespace App\Models\Mongo;
/**
* #mixin \Illuminate\Database\Eloquent\Builder
* #mixin \Jenssegers\Mongodb\Query\Builder
*/
class PostCategory extends \Jenssegers\Mongodb\Eloquent\Model
{
/** #var string Mongo Connection Name */
//protected $connection = 'mongodb';
/** #var string Mongo Collection Name */
protected $collection = 'post_category';
/**
* #return \Jenssegers\Mongodb\Relations\HasMany
*/
public function post()
{
return $this->hasMany(Post::class, '_id', 'post_id');
}
}
Changes
change relation to belongsToMany in Post
Relation is not working
return $this->belongsToMany(
Category::class,
'post_category',
'post_id',
'category_id',
'_id', <-- post primary key
'_id', <-- category primary key
)->withPivot('sequence');
You could use a many-to-many relationship instead and access sequence as pivot column.
namespace App\Models\Mongo;
/**
* #mixin \Illuminate\Database\Eloquent\Builder
* #mixin \Jenssegers\Mongodb\Query\Builder
*/
class POST extends \Jenssegers\Mongodb\Eloquent\Model
{
/** #var string Mongo Connection Name */
//protected $connection = 'mongodb';
/** #var string Mongo Collection Name */
protected $collection = 'posts';
/** #var bool Enable/Disable Timestamp */
public $timestamps = true;
/** #var string Date format */
protected $dateFormat = 'Y-m-d H:i:s';
/** #var array */
protected $dates = ['created_at', 'updated_at', 'live_date', 'expire_date'];
/**
* // I know this relation is not correct, it must either belongsToMany or hasMany
* // but as of now, I've to fetch the posts belonging to a single category id
* // so using hasOne relation
* #return \Jenssegers\Mongodb\Relations\HasOne
*/
public function category()
{
return $this->belongsToMany(
Category::class
)->withPivot('sequence');
}
}
You probably have to add one or more optional parameters to belongsToMany() to make it work. But since you know your data structure better than I do, I bet, you can figure that out faster than I can.

Laravel Many-To-Many - Different databases

need some light on a problem... I'm trying to get data from another database using a Many-To-Many relation.
Basically, a site can have many templates and a template can have many sites.
Site Model:
class Site extends Model
{
use HasFactory;
/**
* Database Connection Name
*/
protected $connection = 'hub';
/**
* Model Table Name
*/
protected $table = 'tbl_sites';
/**
* Model Primary Key
*/
protected $primaryKey = 'id';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'code', 'name', 'abbreviation', 'address', 'zipcode', 'town', 'geolocation_id', 'gps'
];
/**
* Returns associated SGC templates
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function sgc_templates()
{
return $this->belongsToMany('App\Models\SGC\Contracts\Templates\Template', 'sgc_contracts_templates_hasmany_sites', 'site_id', 'template_id');
}
}
Template Model:
class Template extends Model
{
use HasFactory;
/**
* Database Connection Name
*/
protected $connection = 'sgc';
/**
* Model Table Name
*/
protected $table = 'sgc_contracts_templates';
/**
* Model Primary Key
*/
protected $primaryKey = 'id';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'description', 'file_name'
];
/**
* Returns associated sites
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function sites()
{
return $this->belongsToMany('App\Models\Hub\Sites\Site', 'sgc_contracts_templates_hasmany_sites', 'template_id', 'site_id');
}
}
If I try to get templates associated to a site with: Site::with('sgc_templates')->find(1), everything works fine.
If I try to get sites associated to a template with: Template::with('sites')->find(1), I got error. Basically saying that the pivot table doesn't exists on sites database. The templates and the pivot table are on sgc connection/database.
The error is:
Illuminate\Database\QueryException
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'hub.sgc_contracts_templates_hasmany_sites' doesn't exist (SQL: select `tbl_sites`.*, `sgc_contracts_templates_hasmany_sites`.`template_id` as `pivot_template_id`, `sgc_contracts_templates_hasmany_sites`.`site_id` as `pivot_site_id` from `tbl_sites` inner join `sgc_contracts_templates_hasmany_sites` on `tbl_sites`.`id` = `sgc_contracts_templates_hasmany_sites`.`site_id` where `sgc_contracts_templates_hasmany_sites`.`template_id` in (1))
Clearlly that the Template::with('sites')->find(1) is going to the wrong database, because on the error, 'hub.sgc_contracts_templates_hasmany_sites' should be 'sgc.sgc_contracts_templates_hasmany_sites'.
Can someone help me with this? :|
Thanks
Found an workaround. Seems that Many-To-Many only works in 1 direction (?).
Github Issue
Workaround
Thanks for all the help.
You need to tell Eloquent that you want to use other db, try something like this
return $this->belongsToMany('App\Models\Hub\Sites\Site', 'sgc.sgc_contracts_templates_hasmany_sites', 'template_id', 'site_id');
and then check if it tries to query sgc db.
If it still don't help try this https://stackoverflow.com/a/60060726/7892040.

Laravel Lighthouse GraphQL renamed relationship mutation

I'm having an issue updating a renamed relationship with a graphQL query.
Here's the related schema and Laravel models:
Laravel Models
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class Lead extends Model
{
/**
* The attributes that are mass assignable.
*
* #var array
*/
// protected $fillable = [
// 'lead_type_id',
// ];
protected $guarded = [];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
//
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
// 'created_at' => 'timestamp',
// 'updated_at' => 'timestamp'
];
/**
* Get the LeadActions for the Lead.
*/
public function leadActions()
{
return $this->hasMany(\App\Models\LeadAction::class);
}
/**
* Get the clients for the Lead.
*/
public function clients(): BelongsToMany
{
return $this->belongsToMany(Client::class);
}
/**
* Get the LeadType for the Lead.
*/
public function leadType(): BelongsTo
{
return $this->belongsTo(\App\Models\LeadType::class, 'lead_type_id');
}
}
?>
<?php
namespace App\Models;
use App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class LeadType extends Model
{
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name'
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
//
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'name' => 'string',
'created_at' => 'timestamp',
'updated_at' => 'timestamp'
];
/**
* Get the Leads for the LeadType.
*/
public function leads(): HasMany
{
return $this->hasMany(Models\Lead::class);
}
}
?>
GraphQl Schema
type Lead {
id: ID!
lead_type: LeadType #belongsTo(relation: "leadType")
clients: [Client!]! #belongsToMany
created_at: DateTime!
updated_at: DateTime!
}
input UpdateLeadInput {
id: ID!
clients: UpdateClientsRelation
lead_type: UpdateLeadTypeRelation
}
input UpdateLeadTypeRelation {
create: CreateLeadTypeInput
connect: ID
update: UpdateLeadTypeInput
upsert: UpsertLeadTypeInput
delete: ID
disconnect: ID
}
Using the following graphQl query I get an SQL error for missing column lead_type:
Query
mutation UpdateLead {
updateLead(input: {id: 1, lead_type: {connect: 1}}) {
id
clients {
id
name
}
lead_type {
id
name
}
}
}
SQL Error
Column not found: 1054 Unknown column 'lead_type' in 'field list' (SQL: update `leads` set `lead_type` = {\"connect\":\"1\"}, `leads`.`updated_at` = 2020-01-14 17:11:17 where `id` = 1
I've followed the Laravel naming convention, and named the column lead_type_id on the leads table. If I remove the renaming of the lead_type relationship to leadType I can successfully run an update mutation, but I can't figure out how to get it to use the correct name for the column (lead_type_id) whilst keeping the relationship renamed.
Any help is greatly appreciated.
Many Thanks
Have you tried #rename directive? I mean you have to use it on lead_type in your UpdateLeadInput, because lighthouse looks for relation named lead_type, and as this is not defined, it assume that lead_type is an argument.
Either rename your relations in models, like:
class Lead extends Model
{
public function lead_actions()
{
return $this->hasMany(\App\Models\LeadAction::class);
}
public function lead_type(): BelongsTo
{
return $this->belongsTo(\App\Models\LeadType::class, 'lead_type_id');
}
}
OR
use #rename directive (I didn't try it, but I mean it works like this):
input UpdateLeadInput {
id: ID!
clients: UpdateClientsRelation
lead_type: UpdateLeadTypeRelation #rename(attribute: "leadType")
}

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'projects_id' in 'field list'

I am trying to submit some data to database. However when inserting the $airattributes im getting an error that projects_id (WHICH DOESNT EXIST ANYWHERE, NEITHER IN DB NOR ANY FILE)
MY CONTROLLER:
public function newProject(Request $request)
{
$data = $request->all();
$attributes = [];
$attributes['title'] = $data['title'];
$attributes['start_date'] = date("Y-m-d h:i:s", strtotime($data['start_date']));
$attributes['end_date'] = date("Y-m-d h:i:s", strtotime($data['end_date']));
$attributes['created_by'] = Auth::user()->id;
$attributes['description'] = $data['description'];
$attributes['air'] = '10';
$attributes['water'] = '19';
$attributes['lat'] = $data['lat'];
$attributes['lng'] = $data['lng'];
$airattributes['dust'] = $data['dust'];
$airattributes['noise'] = $data['noise'];
$airattributes['temperature'] = $data['temperature'];
$airattributes['radiation'] = $data['radiation'];
// var_dump($attributes);
// return;
$project = Projects::create($attributes);
$air = $project->air()->create($airattributes);
var_dump($data);
return;
MY projects model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Projects extends Model
{
protected $table = 'projects';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'title', 'start_date', 'end_date', 'created_by', 'description', 'air', 'water', 'lat', 'lng'
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'id',
];
/**
* Get the phone record associated with the user.
*/
public function air()
{
return $this->hasMany('App\Air');
}
/**
* Get the phone record associated with the user.
*/
public function water()
{
return $this->hasOne('App\Water');
}
public function user()
{
return $this->hasOne('\App\User', 'id', 'created_by');
}
public function enrolls()
{
return $this->hasMany('\App\Enroll', 'project_id', 'id');
}
public function lastEdited()
{
return $this->hasOne('\App\User', 'id', 'last_edited_by');
}
}
My Air Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Air extends Model
{
protected $table = 'projects_air';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'project_id', 'temperature', 'radiation', 'dust', 'noise'
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'id',
];
}
you can test it here for more info: http://188.166.166.143/projects/add
In the projects model if you don't specify the foreign key, then I believe in the Air model you should change to 'projects_id' in accordance to the name of the table.
Projects hasMany relationships with Air:
public function air()
{
return $this->hasMany('App\Air');
}
This, by default assumes that air model have foreign key projects_id, hence the error.
Since, you have project_id foreign key,
return $this->hasMany('App\Air', 'project_id');
will do.
Simply: Changing model name Projects to Project will solve the problem. Also model names are always singular.
You can solve this in two way. One you can change you model name to Project or you can specify you foreign key in your air function. So you can Change you air function to below.
public function air()
{
return $this->hasMany('App\Air', 'project_id');
}
Choose whichever you want. But in Laravel Model name is always singular so I will recommend you to follow the first rule in that way you don't need to specify the foreign key Laravel is smart enough to recognize that automatically.

Laravel One to many relation with custom primary key not working

I am trying to implement one to many relation in laravel
My tables have custom primary key name not id
I have set $primartKey attribute as well but the relations doesnot seem to work.
activities
|act_ID|act_acc_ID|.........
categories
|acc_ID|.......
Here are my Models
class Adventure extends \Eloquent {
/**
* #var string $table the name of the table
*/
protected $table = 'activities';
/**
* #var string $primaryKey the primary key of the table
*/
protected $primaryKey = 'act_ID';
/**
* #var bool timestamps updated_at and created_at columns flag
*/
public $timestamps = false;
/**
*
*/
public function category(){
$this->belongsTo('Category','act_acc_ID');
}
}
class Category extends \Eloquent {
/**
* #var string $table the name of the table
*/
protected $table = 'categories';
/**
* #var string $primaryKey the primary key of the table
*/
protected $primaryKey = 'acc_ID';
/**
* #var bool timestamps updated_at and created_at columns flag
*/
public $timestamps = false;
public function adventures(){
$this->hasMany('Adventure','act_acc_ID');
}
}
Now when ever i try to access categories from adventure or adventures from categories i get
Relationship method must return an object of type
Illuminate\Database\Eloquent\Relations\Relation
What am i doing wrong here ??
There are plenty adventures whose category is 15 so i try
I try Categories::find(15)->adventures also tried Categories::find(15)->adventures()
You didn't use return keyword, it should be something like this:
public function category(){
return $this->belongsTo('Category','act_acc_ID');
}
public function adventures(){
return $this->hasMany('Adventure','act_acc_ID');
}
Add the return keyword in both relationship methods.
you have to set this in you Category model
public $incrementing = false;

Categories