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.
Related
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
I have a php laravel projekt where I need to add a field to one/more models (Eloquent). I don't have much experience in php and never tried laravel before.
The class looks like this now
class Player extends Eloquent
{
use GenderTrait;
use VisibilityTrait;
use PlayerPhotoTrait;
use PlayerActionTrait;
const GENDER_MALE = 2;
const GENDER_FEMALE = 1;
/**
* The database table used by model.
*
* #var string
*/
protected $table = 'players';
/**
* Parameters for `actions` relation.
*
* #see PlayerActionTrait::actions()
* #var array
*/
protected $actionModel = [
'name' => 'PlayerAction',
'foreignKey' => 'player_id',
];
/**
* The list of mass-assignable attributes.
*
* #var array
*/
protected $fillable = [
'name',
'start_value',
'gender',
'is_visible',
'nation',
];
/**
* The list of validation rules.
*
* #var array
*/
public static $rules = [
'name' => 'required',
'nation' => 'required|numeric',
'start_value' => 'required|numeric',
];
/**
* #inheritdoc
*/
protected static function boot()
{
parent::boot();
}
/**
* Players country.
*
* #return Country
*/
public function country()
{
return $this->belongsTo('Country', 'nation');
}
/**
* Player videos.
*
* #return mixed
*/
public function videos()
{
return $this->morphMany('YoutubeLink', 'owner');
}
}
I would like to add a string field called "level" but I have no idea how to go about it. If I create the field in MySQL first and then the models get updated, if I update the models and then Laravel update MySQL for me?
Im looking forward to hearing what I can do :)
You need to add migration:
php artisan make:migration add_fields_to_players_table --table=players
Open in /database/migrations new migration and write
Schema::table('players', function ($table) {
$table->string('new_string_field');
});
Now you need to run migrations
php artisan migrate
More info and available column types here
I am building a timesheet system and have setup a model for timesheets. Timesheet can have many rows - for example when I add a timesheet, I can add many days (rows) to the timesheet.
I want to be able to sync rows when a timesheet gets saved. For example, new rows will be added to the database, missing rows from the given array will be removed from the database.
I understand I can use sync method which works like this, however, I do not think I need a belongsToMany relationship. Currently I have my row relationship setup as a hasMany. The timesheet model looks like this:
<?php
namespace App\Models\Timesheet;
use Illuminate\Database\Eloquent\Model;
class Timesheet extends Model
{
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'timesheet';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['user_id', 'week', 'year', 'token', 'total_hours'];
/**
* Define that we want to include timestamps.
*
* #var boolean
*/
public $timestamps = true;
/**
* Boot the model.
*
*/
public static function boot()
{
parent::boot();
static::deleting(function($timesheet)
{
$timesheet->row()->delete();
});
}
/**
* The rows that belong to the timesheet.
*
* #return Object
*/
public function row()
{
return $this->hasMany('App\Models\Timesheet\RowTimesheet');
}
}
The row_timesheet model looks like this:
namespace App\Models\Timesheet;
use Illuminate\Database\Eloquent\Model;
class RowTimesheet extends Model
{
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'row_timesheet';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['timesheet_id', 'activity_category', 'description', 'eri_number', 'ewn_number'];
/**
* Define that we want to include timestamps.
*
* #var boolean
*/
public $timestamps = true;
What do I need to do in order to make something like this work:
$this->timesheet->find($id)->row()->sync($data);
Thanks in advance.
I believe the 'sync' methods works with 'belongsTomany' relationship.
what you have is 'hasMany' relationship, for that you need to do something like below
use 'save' method instead of 'sync' for hasMany relationship
$data = new App\Comment(['message' => 'A new comment.']);
$this->timesheet->find($id)->row()->save($data); // saves single row sheet object for a timesheet
$this->timesheet->find($id)->row()->saveMany($multipleData); // saves multiple row sheet objects for a timesheet
Trying to get data from multiple nested relationship with a where constraint:
Model User:
<?php
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableInterface;
use Illuminate\Database\Eloquent\SoftDeletingTrait;
use Zizaco\Entrust\HasRole;
class User extends BaseModel implements UserInterface, RemindableInterface {
use HasRole;
protected $fillable = array('username', 'password');
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'users';
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = array('password');
protected $dates = ['deleted_at'];
protected $softDelete = true;
public function editor()
{
return $this->hasOne('User_Editor', 'user_id');
}
?>
Model User_Editor:
<?php
class User_Editor extends BaseModel {
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'users_editors';
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = array();
/**
* Defiens the column names of fillable columns.
*
* #var array
*/
protected $fillable = array();
/**
* Relationships
*/
public function credentials()
{
return $this->hasMany('User_Editor_Credential', 'user_editor_id');
}
public function specialties()
{
return $this->hasMany('User_Editor_Specialty', 'user_editor_id');
}
?>
Model User_Editor_Credentials:
<?php
class User_Editor_Credential extends BaseModel {
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'users_editors_credentials';
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = array();
/**
* Defiens the column names of fillable columns.
*
* #var array
*/
protected $fillable = array();
}
Model User_Editor_Specialties:
<?php
class User_Editor_Specialty extends BaseModel {
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'users_editors_specialties';
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = array();
/**
* Defiens the column names of fillable columns.
*
* #var array
*/
protected $fillable = array();
}
Return
select * from User, User_Editor, User_Editor_Credentials, User_Editor_Specialty where User_Editor_Specialty.specialty In (array).
So far I've tried,
$this->data['editors'] = User::with(['editor.credentials.specialties' => function($q) use($data){
$q->whereIn('specialty',$data);
}])
->get();
But this throws an error call to undefined method specialties. Please guide, thanks.
To those who might have suffered for long trying to find a way to work around nested relationships, and also, if you are writing a join condition with whereIn (which throws call to undefined method because of a bug in the Laravel), Please find below ans,
$editors = User::with(['editor.credentials','editor.specialties']);
$this->data['editors'] = $editors->whereHas('editor', function($q) use ($a_data){
$q->whereHas('specialties',function($sq) use($a_data){
$sq->whereIn('specialty',$a_data);
});
})->get();
Update: the PR has been just merged to 4.2, so now it's possible to use dot nested notation in has methods ( ->has('relation1.relation2) ->whereHas('relation1.relation2, .. )
Your dot notated relations must be logically chained:
`with(['editor.credentials', ' editor.specialties' => function ....
You tried to search for the specialties relation on the User_Editor_Credential model.
According to the comments:
User::with(['editor.credentials','editor.specialties'])
->whereHas('editor' => function($q) use ($data){
$q->whereHas('specialties' => function($q) use ($data){
$q->whereIn('specialty',$data);
});
})->get();
or if you use my PR https://github.com/laravel/framework/pull/4954
User::with(['editor.credentials','editor.specialties'])
->whereHas('editor.specialties' => function($q) use ($data){
$q->whereIn('specialty',$data);
})->get();
It will return all the users that have related editor.specialties matching whereIn, with related editor and all its related credentials and specialties (the latter won't be filtered)
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;