How to define this hasManyThrough relation? - laravel

I have the following models. Event belongs to a Casefile. Casefile and User are many-to-many.
class Casefile extends Model
{
public function users()
{
return $this->belongsToMany(User::class)->withTimestamps();
}
public function events()
{
return $this->morphMany('App\Event', 'casefile');
}
}
class User extends Authenticatable
{
public function casefiles()
{
return $this->belongsToMany(Casefile::class)->withTimestamps();
}
}
class Event extends Model
{
public function casefile()
{
return $this->belongsTo('App\Casefile');
}
public function users()
{
return $this->hasManyThrough('App\User', 'App\Casefile');
}
}
When I try to:
App\Event::find(526)->users()->get();
It gives:
Illuminate/Database/QueryException with message 'SQLSTATE[42S22]:
Column not found: 1054 Unknown column 'casefiles.event_id' in 'field
list' (SQL: select users.*, casefiles.event_id from users
inner join casefiles on casefiles.id = users.casefile_id
where casefiles.event_id = 526)'
How can I define the "Event has many Users" relation through Casefile?

It's not possible to use HasManyThrough here without a pivot model for the casefile_user table.
You can define a BelongsToMany relationship instead:
public function users()
{
return $this->belongsToMany('App\User', 'casefile_user', 'casefile_id', null, 'casefile_id');
}

If you not followed laravel naming convention for column name. Then you can specify your column name like this
public function users()
{
return $this->hasManyThrough(
'App\User',
'App\Casefile',
'event_id', // Foreign key on casefiles table...
'user_id', // Foreign key on users table...
);
}
For more Laravel HasManyThrough Relationship

Related

Laravel : Define model for reverse OneToMany relationship

I have the following schema:
class Group extends Model
{
/**
* The users that belong to the group.
*/
public function users()
{
return $this->belongsToMany(User::class)->withTimestamps();
}
}
What should my User model look like in the other side ?
class User extends Model
{
/**
* The group that owns the user.
*/
public function group()
{
return $this->???(Group::class)->withTimestamps();
}
}
It's also a belongsToMany, just the inverse. Try this paradigm:
return $this->belongsToMany(
'App\Models\Group',
'user_group',
'user_id',
'group_id'
)->withTimestamps();
Where the explicit params are:
Related Model
Table (Pivot table)
Foreign Pivot Key
Related Pivot Key

Adding and saving fields in a related belongsToMany table

The tables category, category_description and descriptions are related:
public function descriptions(): BelongsToMany
{
return $this->belongsToMany(Description::class);
}
public function categories(): BelongsTo {
return $this->belongsTo(Category::class);
}
public function descriptions(): BelongsTo {
return $this->belongsTo(Description::class);
}
public function descriptions(): BelongsToMany
{
return $this->belongsToMany(Category::class);
}
in Model respectively. When saving or updating:
public function createOrUpdate(Category $category, Request $request)
{
$category->fill($request->get('category'))->save();
$category->descriptions()->syncWithoutDetaching(
$request->input('category.descriptions', [])
);
}
An error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'description' in 'field list' (SQL: insert into `category_description` (`category_id`, `description`, `description_id`, `is_active`, `meta-description`, `meta-h1`, `meta-keyword`, `meta-title`, `name`, `slug`) values (1, 41231231, 0, 1, 23, 124, 12, 12, 12333312, 74))
Perhaps I missed something somewhere, since there is not so much experience.
UPDATE:
a category can have multiple entries, but the description has only one parent. Rewrote — One To Many (Polymorphic):
public function descriptions()
{
return $this->morphMany(Description::class, 'descriptable');
}
public function descriptable()
{
return $this->morphTo();
}
There are no problems with saving 1 record, but how to update several records at the same time?
How about?
// Category Model.
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
public function descriptions()
{
return $this->belongsToMany(Description::class)
->using(CategoryDescription::class);
}
}
// Description Model.
use Illuminate\Database\Eloquent\Model;
class Description extends Model
{
protected $fillable = [
"name",
"description",
"meta-title",
"meta-description",
"meta-keyword",
"meta-h1",
"slug",
"is_active",
];
public function categories()
{
return $this->belongsToMany(Category::class)
->using(CategoryDescription::class);
}
}
// Intermediate Model.
use Illuminate\Database\Eloquent\Relations\Pivot;
class CategoryDescription extends Pivot
{
protected $table = "category_description";
public $incrementing = true;
public function category()
{
return $this->belongsTo(Category::class, "category_id", "id");
}
public function description()
{
return $this->belongsTo(Description::class, "description_id", "id");
}
}
// createOrUpdate method.
public function createOrUpdate(Category $category, Request $request)
{
$category->fill($request->get('category'))->save();
$description = Description::create(
Arr::collapse($request->input('category.descriptions', []))
);
$category->descriptions()->syncWithoutDetaching(
$description->id
);
}
Notes:
Much as this may work for you, I personally think that you don't have a many-to-many relationship here. I believe a one-to-many relationship is sufficient.
The problem is you send data to be inserted in columns that are not found
You should send only the data that you need to insert in the table
so in your case, you should write your function as
$category->descriptions()->syncWithoutDetaching($description_id); // the id of the description you want to attach with this category
If you still don't have the description yet in the database and you are creating it with the same request you can do something like this
Description::create(['columnName'=>$request->get('columnName'),'columnName2'=>$request->get('columnName2')])->id

Laravel self based polymorphic relationship

I have 3 tables:
categories
admins
users
Category can create users and admins. In categories table I have morphs field:
$table->nullableMorphs('userable');
And relations in Category model:
public function userable()
{
return $this->morphTo();
}
public function user()
{
return $this->morphOne(self::class, 'userable');
}
But when I tried do like this:
$category = Category::first();
$user = User::first();
$category->user()->save($user);
Get error with message:
Illuminate\Database\QueryException with message 'SQLSTATE[42S22]:
Column not found: 1054 Unknown column 'userable_id' in 'field list'
(SQL: update users set userable_id = 1, userable_type =
App\Models\Category, users.updated_at = 2021-04-27 12:13:22 where
id = 1)'
How I can correctly create self morph relationship in laravel?
So I think that what you should be doing is adding to the User model and the Admin model the relation user you've added to the category, those models that have this relationship can be morphed into the category
class User {
...
public function user() {
return $this->morphOne(Category::class, 'userable');
}
...
}
class Admin {
...
public function user() {
return $this->morphOne(Category::class, 'userable');
}
...
}
so you can do your logic this way
$category = Category::first();
$user = User::first();
$user->user()->save($category);
and it will update you category record with userable_type beeing App\Models\User and userable_id beeing 1 or whatever the user id is
id
name
userable_type
userable_id
1
Category Test
App\Models\User
1
to make things easier you can create a trait and add that relationship to the trait
trait IsUserable {
public function user() {
return $this->morphOne(Category::class, 'userable');
}
}
and instead of adding the relationship to User and Admin model, you just use the trait instead
class User {
use IsUserable;
}
class Admin {
use IsUserable;
}

Laravel relations pivot table name trouble

in my app I have 2 conversations types: normal private conversations between users and conversations for people which are interested of user product.
In my User model I declared relations like:
public function conversations()
{
return $this->belongsToMany('App\Conversation', 'conversation_user');
}
public function conversationsProduct()
{
return $this->belongsToMany('App\ConversationProduct', 'conversation_product_user', 'user_id', 'product_id');
}
Where 'conversation_user' and 'conversation_product_user' are pivot tables between 'users'-'conversations' and 'users'-'conversations_product' tables.
My conversation_user pivot table has conversation_id and user_id table properties, but conversation_product_user pivot table has additional property product_id.
In my Conversation Model I have:
public function users()
{
return $this->belongsToMany('App\User');
}
public function messages()
{
return $this->hasMany('App\Message');
}
In ConversationProduct Model I wrote:
protected $table = 'conversations_product';
public function users()
{
return $this->belongsToMany('App\User', 'conversation_product_user');
}
public function messages()
{
return $this->hasMany('App\MessageProduct');
}
In my ConversationProductController I have method to find user conversations:
public function showUserConversationsProduct(Request $request){
$user_id = $request->user_id;
//var_dump($user_id);
$userData = User::where('id', $user_id)->with('conversationsProduct')->first();
}
And there is my problem: In controller ->with('conversationsProduct') don't take relation for conversation_product_user, but for conversation_user pivot table. I can't handle it why its happen if I add second parameter as 'conversation_product_user' in my relation:
public function conversationsProduct()
{
return $this->belongsToMany('App\ConversationProduct', 'conversation_product_user', 'user_id', 'product_id');
}
I need protected $table = 'conversations_product'; to point my ConversationsProductController#store where to save conversation, but I think that can be problem with recognise proper relation.
I really appreciate any help. I attach photo of my db relations.

Laravel Nested Relationship Where 5.5 Return All Records

I'm having some trouble when trying to fetch records from database. Here's the table schema:
users
--------------
id
username
password
email
divisions
--------------
id
name
employee
--------------
name
birth_date
status
class
division_id
user_id
projects
--------------
id
title
body
user_id
So, for the relationship explanations:
relationship
Okay, i'm trying to fetch project based on division_id on table employee with the following code:
# query code
$division_id = 10;
$items = Project::with(['user.employee.division' => function($query) use ($division_id) {
$query->where('id', $division_id);
}])->get();
I've added the required belongsTo, hasMany or hasOne to the models.
# User.php
class User extends Authenticatable
{
public function employee()
{
return $this->hasOne('App\Employee', 'user_id');
}
public function projects()
{
return $this->hasMany('App\Project', 'user_id');
}
}
# Division.php
class Division extends Model
{
public function employee()
{
return $this->hasMany('App\Employee', 'division_id');
}
}
# Employee
class Employee extends Model
{
public function user()
{
return $this->belongsTo('App\User', 'user_id');
}
public function division()
{
return $this->belongsTo('App\Division', 'division_id');
}
}
# Project.php
class Project extends Model
{
public function user()
{
return $this->belongsTo('App\User', 'user_id');
}
}
So, what's the problem?
Here's the thing, when i run the query code i'm getting all the records and the division object on employe relationship returning null.
If anyone thinks my code is wrong, please enlighten me.
Thanks.
So after some digging, i found an answer. The query code should change to whereHas:
# query code
$division_id = 10;
$items = App\Project::whereHas('user.employee.division',
function($query) use ($division_id) {
$query->where('divisions.id', $division_id);
})
->with(['user.employee.division']) // N+1 problem
->get();
reference: Laravel 5.3 Constraining Eager Loads not working

Resources