Laravel One to many relation with custom primary key not working - php

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;

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.

Relationships with Laravel

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

In Laravel 5.3 Eloquent how to retrieve 3rd table data with where condition

I have 3 Models(each associated with a table separately) which associated with each other I have attached the table structure below
Models are,
Doctor Model associated with doctor_profile_master
<?php
namespace App\TblModels;
use Illuminate\Database\Eloquent\Model;
class Doctor extends Model
{
/**
* #var string
*/
protected $table = 'DOCTOR_PROFILE_MASTER';
/**
* #var string
*/
protected $primaryKey = 'doctor_profile_master_id';
/**
* #var array
*/
protected $fillable = ['doctor_id', 'user_master_id', 'doctor_first_name', 'doctor_last_name', 'doctor_isactive'];
/**
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function hospitalDoctorAssociateMasters(){
return $this->hasMany('App\TblModels\HospitalDoctorAssociateMaster','doctor_profile_master_id');
}
}
HospitalDoctorAssociateMaster Model associated with hospital_doctor_associate_master
<?php
namespace App\TblModels;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
class HospitalDoctorAssociateMaster extends Model
{
/**
* #var string
*/
protected $table = 'HOSPITAL_DOCTOR_ASSOCIATE_MASTER';
/**
* #var string
*/
protected $primaryKey = 'hospital_doctor_associate_master_id';
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function doctor(){
return $this->belongsTo('App\TblModels\Doctor','doctor_profile_master_id');
}
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function hospital(){
return $this->belongsTo('App\TblModels\Hospital','hospital_profile_master_id');
}
}
HospitalDoctorRecurringSchedule Model associated with hospital_doctor_recurring_schedule
<?php
namespace App\TblModels;
use Illuminate\Database\Eloquent\Model;
class HospitalDoctorRecurringSchedule extends Model
{
/**
* #var string
*/
protected $table = 'HOSPITAL_DOCTOR_RECURRING_SCH_MASTER';
/**
* #var string
*/
protected $primaryKey = 'hospital_doctor_recurring_sch_master_id';
public function hospitalDoctorAssociateMaster(){
return $this->belongsTo('App\TblModels\HospitalDoctorAssociateMaster','hospital_doctor_associate_master_id');
}
}
Thing i want to do is,
How to retrieve the hospital_doctor_recurring_sch_master table data using specific doctor_id(doctor_profile_master)
I tried some methods but cant able to retrieve those values.
Thanks in advance.
You could use something like this:
$hospitalDoctors = HospitalDoctorRecurringSchedule::with(['hospitalDoctorAssociateMaster', 'hospitalDoctorAssociateMaster.doctor', 'hospitalDoctorAssociateMaster.hospital'])->all();
To search by fields in related tables:
$hospitalDoctors = HospitalDoctorRecurringSchedule::with([
'hospitalDoctorAssociateMaster',
'hospitalDoctorAssociateMaster.doctor',
'hospitalDoctorAssociateMaster.hospital'])
->whereHas('hospitalDoctorAssociateMaster.doctor', function ($query) use ($doctorId) {
$query->where('doctor_id', '=', $doctorId);
})
->all();
For hospitalDoctorAssociateMaster.hospital:
Define Hospital Model and try

How to get department name of a module in Laravel models

I am trying to get the department that a module is part of in laravel like:
This is my Faculty class:
<?php
class Faculty extends Eloquent {
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'faculty';
public $timestamps = false;
/**
* Whitelisted model properties for mass assignment.
*
* #var array
*/
protected $primaryKey='facultyid';
protected $fillable = array('facultyname', 'facultyshort');
public function departments()
{
return $this->hasMany('Departments', 'facultyid');
}
}
This is my Departments class
<?php
class Departments extends Eloquent {
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'departments';
public $timestamps = false;
/**
* Whitelisted model properties for mass assignment.
*
* #var array
*/
protected $primaryKey='departmentid';
protected $foreignKey='facultyid';
protected $fillable = array('departmentname', 'departmenthead', 'facultyid');
public function modules()
{
return $this->hasMany('Modules', 'departmentid');
}
public function faculty()
{
return $this->belongsTo('Faculty', 'facultyid');
}
}
and finally this is my modules class:
<?php
class Modules extends Eloquent {
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'modules';
protected $foreignKey='departmentid';
public $timestamps = false;
/**
* Whitelisted model properties for mass assignment.
*
* #var array
*/
protected $primaryKey='mid';
protected $fillable = array('mfulltitle', 'mshorttitle', 'mcode',
'mcrn', 'mfieldofstudy', 'mcoordinator','mlevel',
'mcredits', 'melective', 'departmentid');
public function department()
{
return $this->belongsTo('Departments', 'departmentid');
}
public function classes()
{
return $this->hasMany('Classes', 'moduleid')->orderBy('classid', 'ASC');
}
}
I have tried doing something like this:
#foreach(Modules::where('melective', '=', 1)->get() as $mod)
{{$mod->mshorttitle}} belongs to department: {{ $mod->department->departmentname }}
#endforeach
But it does not work, does anyone have any idea on how to do this?
==============================
SOLUTION
After a bit of work i figured it out
in Department class i added the following function:
public function name()
{
return $this->departmentname;
}
and i changed the code to the following:
#foreach(Modules::where('melective', '=', 1)->get() as $mod)
{{$mod->mshorttitle}} belongs to department: {{ $mod->department->name() }}
#endforeach

Categories