Laravel MongoDB 1:n relations - laravel

What is the correct way of defining 1:n relations in Laravel using MongoDB between two models Author and Book where one author can have several books while one book has exactly one authors?
Author.php
class Author extends Model
{
public function books()
{
// what to place here?
return $this->...
}
}
Book.php
class Book extends Model
{
public function author()
{
// what to place here?
return $this->...
}
}
Controller.php
class BookController extends Controller
{
public function store (Author $author, Request $request)
{
$book1 Book::create();
$book2 Book::create();
// connect $book1 <-> $author and $book2 <-> $author
// what to place here?
$book1->save();
$book2->save();
}
}
After calling store() I want to be able to do the following request
dump ($book1->author); // return $author
dump ($author->books); // return Collection of $book1 and $book2

assume you have the foreign key author_id in books table
class Author extends Model
{
public function books()
{
return $this->hasMany(Book::class, 'author_id');
}
}
class Book extends Model
{
public function author()
{
return $this->belongsTo(Author::class, 'author_id');
}
}
class BookController extends Controller
{
public function store (Author $author, Request $request)
{
$book1 = new Book();
$book2 = new Book();
$author->books()->saveMany([$book1, $book2]);
}
}

Suppose you have the ff:
users = model a
posts = model b
Case 1: vice versa of Case 2:
Case 2:
// on posts table/document you should have a user_id (as foreign key)
// and on post model you need define the belongsTo relationship
$this->belongsTo(User::class)
// on the User model you have to define hasOne or hasMany
$this->hasOne(Post::class) or $this->hasMany(Post::class)
Case 3:
On case 3, I'm not sure if adding a reference to each other is necessary because creating a single reference that links them can provide the data you require regardless of whether the request comes from model a or model b.
It is possible that it will not solve your problem. However, hopefully it will be of some assistance to you.

For case 1 ( in model_a ):
public function model_b_many()
{
return $this->hasMany( Model_b::class, 'id' );
}
For case 2 ( in model_b ):
public function model_a_many()
{
return $this->hasMany( Model_a::class, 'id' );
}
This will also work for case 3 :)

Related

Laravel - Eloquent How can make this relationship HasMany -> BelongToThrough

How can I come up with this kind of relationship?
User:
- id
- name
- username
Post
- id
- user_id
- comment_id
Coment
- id
- other_id
Other
- id
- name
- descripton
So the relationship would be:
User - belongsToMany -> Post - belongsTo -> Comment - belongsTo -> Other
At this relationship the user have many post but the comment_id relation is belongs to.
I cant use hasManyThrough because the relationship is different.
Is there a way to make this work?
it should be hasMany -> BelongsToThrough
I could use hasMany then on each item will call the BelongsTo, but the relationship I had is too deep.
It needs a relationship that can use hasMany then belongsToThrough such relationship
UPDATE
There is a belongsToMany instead of hasMany but still not sure if I could work on this
Got an alternative solution
class User {
public function user_post_comments () {
return $this->belongsToMany(Post::class);
}
public function getCommentsAttribute() {
return $this->user_post_comments->map(function ($value, $key) {
$obj = $value->comment;
$obj->pivot=(object) [
// Extra variable for the nested
];
return $obj;
});
}
}
class Post {
public function comment () {
return $this->belongsTo(Comment::class);
}
}
$this->user->comments will return the post comment instead of posts
https://laravel.com/docs/8.x/eloquent-relationships#has-many-through
You can get comments from users like this
class User extends Model
{
/**
* Get all of the Comments for the Post.
*/
public function comments()
{
return $this->hasManyThrough(Comment::class, Post::class);
}
/**
* Get all of the Post.
*/
public function posts()
{
return $this->hasMany(Post::class);
}
}
Get Other's comment like this
class Comment extends Model
{
public function others()
{
return $this->belongsTo(Other::class);
}
}
and get final data like this
$data = User::with(['comments.others'])->get();
Got something that will work if to add other information in the pivot.
use Illuminate\Database\Eloquent\Relations\Pivot;
class ModelPivot extends Pivot
{
public $appends = ['extra_detail'];
public function getExtraDetailAttribute() {
return App\Detail::find($this->attributes['detail_id'];
}
}

How to use morphtomany

I'm trying to create a tagging system and now I got two table as the picture below
tags
taggables
I would like to tag the Journal and id based on the `tag_id. However, the journal always create a new record in the taggables table.
Here is my model relationship
Tag
class Tag extends Model
{
public function purchases()
{
return $this
->morphedByMany('Purchase', 'taggable');
}
public function taggables()
{
return $this->hasMany('Taggable');
}
}
Purchase
class Purchase extends Model
{
public function tags()
{
return $this
->morphToMany('Tag', 'taggable');
}
}
Journal
class Journal extends Model
{
public function tags()
{
return $this
->morphToMany('Tag', 'taggable');
}
}
If I understood correctly you are trying to use tags for journals and purchases at the same time.
Then your table structure should be something like:
journals(id, ...)
purchases(id, ...)
tags(id, name)
taggables(id, tag_id, taggable_id, taggable_type)
Then the models that can be tagged should both have a method to retrive their tags:
app/Journal.php
// namespace and use statements
class Journal extends Model
{
public function tags()
{
return $this->morphToMany('App\Tag', 'taggable');
}
}
app/Purchase.php
// namespace and use statements
class Purchase extends Model
{
public function tags()
{
return $this->morphToMany('App\Tag', 'taggable');
}
}
The your tag model that can be applied to both Purchase and Journal should have N methods, where N is the number of different models you are connecting through your polymorphic relation, in this example N=2 (one method to retrive purchases from a tag, and one method to retrive journals from a tag).
app/Tag.php
// namespace and use statements
class Tag extends Model
{
public function journals()
{
return $this->morphedByMany('App\Journals', 'taggable');
}
public function purchases()
{
return $this->morphedByMany('App\Purchase', 'taggable');
}
}
After the relations are set you can retrive the tags assigned to a journal or a purchase:
$journal = \App\Journal::first();
foreach ($journal->tags as $tag) {
// ...
}
or retrive all the journals or purchases linked to a specific tag:
$tag = \App\Tag::first();
// $tag->journals will contain the journals model instances linked to the current tag
// $tag->purchases will contain the purchases model instances linked to the current tag
Note: to define relationships use the FQDN of the related class, for instance: 'App\Tag' instead of 'Tag', otherwise the class would not be found by the autoloader.

How to retrieve details of second level tables in laravel relationships

I have 3 tables
bank(id, title),
employee(id, name, bank_id),
payroll(id, employee_id, salary).
Now I want to retrieve bank title of employee_id in payroll table.
I have set model relationships
class Bank extends Model
{
public function employees()
{
return $this->hasMany('App\Employee');
}
}
class Employee extends Model
{
public function bank()
{
return $this->belongsTo('App\Bank');
}
public function payrolls()
{
return $this->hasMany('App\Payroll');
}
}
class Payroll extends Model
{
public function employee()
{
return $this->belongsTo('App\Employee');
}
}
I have tried to retrieve using $payroll->employee->bank->title. But it did not help me
Sorry it was my mistake. some employee ids are not referencing bank. That was why I got error.
I resolved the issue by using isset method to verify reference value set or not.
Thanks.
try to change your code a little bit and try again:
public function bank()
{
return $this->hasOne('App\Bank');
}
Read Laravel Official Documentation
/** We can define the inverse of a hasOne relationship using the belongsTo method: **/

Laravel how to define 3 relationships with one model?

I have a Model which is called Championship. Championship may have 3 judges which are called Main Judge, Main Secretary and Judge Operator.
All of them linked to User Model and stored in the database as user ID.
My relationships looks like this
class Championship extends Model
{
protected $table = 'championships';
public function mainJudge()
{
return $this->hasOne('App\User', 'id', 'main_judge');
}
public function mainSecretary()
{
return $this->hasOne('App\User', 'id', 'main_secretary');
}
public function judgeOperator()
{
return $this->hasOne('App\User', 'id','judge_operator');
}
}
But I can't undertand how to define inverse relationship in User model
class User extends Authenticatable
{
public function sex()
{
return $this->belongsTo('App\Models\Sex');
}
public function player()
{
return $this->hasOne('App\Models\Player', 'user_id');
}
public function championship()
{
????
}
You just have to add it like you are adding other relations :
public function championship()
{
return $this->belongsTo('App\Championship');
}
When you do :
$championship = Championship::find($id);
$mainJudge = $championship->mainJudge;
$mainSecretary = $championship->mainSecretary;
// All objects will be exactly same
dd($mainJudge->championship,$mainSecretary->championship,$championship);
I assume all the user records have a foreign key to championships table championship_id
When you call the $user->championship relation it will return you the championship wrt to its foreign key championship_id
No need to worry you are just confusing the inverse relations:
See it this way:
Your mainJudge, mainSecretary, judgeOperators are of type App\User and every user have a championship_id when you will call the (App\User)->championship it will always return you its respective championship or null if the championship_id is empty.
Its just matter of perspective.
Just try the above code it will clear out your confusion.

Defining relationship on pivot table elements in laravel

I'm building a small application on laravel 5.4 where I'm having following models and relationship:
Interaction Model:
public function contactsAssociation()
{
return $this->belongsToMany('App\Contact', 'contact_interaction', 'interaction_id', 'contact_id')->withPivot('company_id')->withTimestamps();
}
Contact Model:
public function company()
{
return $this
->belongsToMany('App\Company', 'company_contact','contact_id', 'company_id')->withTimestamps();
}
and Company Model:
public function contacts()
{
return $this->belongsToMany('App\Contact', 'company_contact', 'company_id','contact_id');
}
Now I'm fetching some data something like this:
$tempData['contacts'] = $interaction->contactsAssociation()->with('company')->get();
I want to extract company data from the pivot table which is mentioned in the relationship. Currently I can't find solution so I have to do:
$tempData['contacts'] = $interaction->contactsAssociation()->get();
$companies = [];
foreach($tempData['contacts'] as $contact)
{
$companies[] = Company::find($contact->pivot->company_id);
}
$tempData['company'] = $companies;
Guide me on this, thanks,
You can pass an array to the withPivot() function with every field you want to retrieve:
public function contactsAssociation()
{
return $this->belongsToMany('App\Contact', 'contact_interaction', 'interaction_id', 'contact_id')
->withPivot(['company_id', 'other_field'])
->withTimestamps();
}
Hope this helps you.

Resources