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.
Related
I can not delete a row using a simple eloquent query. Even when I am using eloquent can not get the data from DB. I am getting null. But, in DB query method at least I am getting data but can not delete then. Following is my code:
DB::transaction(function () use ($lead, $comment, $request) {
$lead->save();
$lead->comments()->save($comment);
if ($request->deleteAppointment) {
$calendarEvent = DB::table('calendar_events')->where('id', $request->appointmentId)->first(); // I am getting data here.
$calendarEvent = CalendarEvent::find($request->appointmentId); // But, here I am getting null, don't know why!
if ($calendarEvent != null) {
$calendarEvent->delete();
}
}
My goal is to get the data using Eloquent and then Delete from database.
update:
My Database Table
CalendarEvent.php model
class CalendarEvent extends Model
{
use SoftDeletes;
/**
* #var array
*/
protected $casts = [
'event_begin' => 'datetime',
'event_end' => 'datetime',
'options' => 'array',
];
/**
* #var array
*/
protected $guarded = [
'id',
];
/**
* #return mixed
*/
public function users()
{
return $this->morphedByMany(User::class, 'eventable');
}
/**
* #return mixed
*/
public function attendees()
{
return $this->morphedByMany(User::class, 'eventable')->withPivotValue('role', 'atendee');
}
/**
* #return mixed
*/
public function companies()
{
return $this->morphedByMany(Company::class, 'eventable')->withPivotValue('role', 'company');
}
/**
* #return mixed
*/
public function invitees()
{
return $this->morphedByMany(User::class, 'eventable')->withPivotValue('role', 'invitee');
}
/**
* #return mixed
*/
public function leads()
{
return $this->morphedByMany(Lead::class, 'eventable')->withPivotValue('role', 'lead');
}
}
Why not just:
CalendarEvent::where('id', $request->appointmentId)->delete();
Also, check the deleted_at column. If that is not null, then the select will return null, unless you add the ->withTrashed() method.
When using Eloquent objects, the SoftDelete trait is used, when using DB:: directly, then the SoftDelete trait is not used.
I am new with Laravel and of course also with backpack.
I am using laravel 7.x and backpack 4.1 with both MySql and MongoDb.
The situation I am facing is that I have a company model with some attributes which are in MySql (both save and update working great with for the attributes stored in MySql) and other attributes that should be stored in MongoDb.
I have a CompanyPropertyCollection model for the attributes which I want to be stored in MongoDb
All these company will have a variable number of other arbitrary properties, which I want to save in mongo.
These properties may be simple scalar values or more complex values too (think arrays of objects), hence the idea to save them in mongo.
MySql Company table:
My question is the following:
What is the best practice to save attributes of an entity in two distinct databases from BackPack? I override the CreateOperation, UpdateOperation with the store() and update() functions something like this:
Company model:
class Company extends Model
{
use \Backpack\CRUD\app\Models\Traits\CrudTrait;
use SoftDeletes;
use HybridRelations;
protected $connection = 'mysql';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name',
'company_type',
'is_active',
'package_id',
'certification_id',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'id' => 'integer',
'is_active' => 'boolean',
'package_id' => 'integer',
'certification_id' => 'integer',
];
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function users()
{
return $this->belongsToMany(\App\Models\User::class);
}
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function package()
{
return $this->belongsTo(\App\Models\Package::class);
}
public function certification()
{
return $this->hasMany(\App\Models\Certification::class);
}
public function properties()
{
return $this->hasOne(\App\Models\CompanyPropertyCollection::class);
}
}
CompanyPropertyCollection model:
class CompanyPropertyCollection extends Model
{
use SoftDeletes;
protected $connection = 'mongodb';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
//'company_id',
'email',
'big_news_id',
'phone.number',
'phone.country_prefix',
'phone.area_prefix',
'phone.postfix',
'year_of_foundation',
'nr_of_employees',
'nr_of_branches',
'company_size',
'subtitle',
'homepage',
'country_code',
'city',
'street',
'post_code',
'uid_nr',
'registration_nr',
'total_sales_area',
'total_annual_bisuness_volume',
'short_portrait',
'long_portrait',
'embedded_video',
'certificates',
'gallery',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'id' => 'integer',
'gallery' => 'array',
];
public function company()
{
return $this->belongsTo(\App\Models\Company::class);
}
}
CompanyCrudController :
public function update()
{
//$this->update( $company->properties);
$response = $this->traitUpdate();
// do something after save
//use registered observer
return $response;
}
Currently I am trying to use a CompanyObserver and on saving to store the data for mongo from the Request.
class CompanyObserver {
public function saving(Company $company)
{
//dd(request()->request);
$request = request()->request;
dd($company->properties());
//save to MongoDb
dd('saving methond on the observer');
}
}
If you need to perform some action after saving a model, like saving some user data in another db with a different type. You can override the model's save method.
Inside your model, add a method like the below
public function save(array $options = array())
{
if (parent::save($options)) {
// Model has been saved in mysql, now save in mongoDB
}
}
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
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;