morphToMany real many to many relation - php

All polymorh examples I found are one to many if I get it correct. (Tag to Post / Video e.g)
In my Case the parent class is multiple and the child class also. Therefore i set up the pivot table
Tables
Person
id
Venture
id
Capital
id
Estate
id
PIVOT TABLE
Revenues
emitter_id //ID of the revenue emitting class (Venture, Capital, Estate)
emitter_type // Class of the Emitter (App\Models\Venture App\Models\Estate)
receiver_id // Id of Receiver (Venture or Person)
receiver_type // type of Receiver (App\Models\Venture or App\Models\Person)
revenue
In the Estate Model i try this
public function revenuePersons()
{
// searched type, own type/id ,tabel own ID to search id
return $this->morphToMany(Person::class, 'emitter' ,'revenues' ,'emitter_id','receiver_id')
->withPivot('revenue');
}
One the Person Model
public function estaterevenues(){
// searched type, own type/id ,tabel own ID to search id
return $this->morphToMany(Estate::class, 'receiver' ,'revenues' ,'receiver_id','emitter_id')
->withPivot('revenue');
}
The Code works but in some cases i get additional relations back. So it seams the searched _type is not correctly considered.
So i started to implement a own database query function that gives me the Revenue Entry back. It works correctly.
Revenue Model
public function getRevenue($ownside, $emitter_id = Null, $emitter_type,$receiver_id=Null, $receiver_type ){
$revenue = DB::table('revenues')
->where('emitter_id', $emitter_id)
.....()->get()}
But I am not able to do something like
$persons->getRevenues
because a Relationship is expected as return value
So if anyone has an idea how to do that correctly I would be very happy. Or some other best practices for this many to many approach.
The second Question is how to get all revenue receiver at once.
Instead of
$estate->revenuepersons
$estate->revenueventures
Have something like
$estate->revenues //that list both, Ventures and Persons
And here a Class Diagram

namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
/**
* Get all of the tags for the post.
*/
public function tags()
{
return $this->morphToMany(Tag::class, 'taggable');
}
}
namespace App;
use Illuminate\Database\Eloquent\Model;
class Video extends Model
{
/**
* Get all of the tags for the post.
*/
public function tags()
{
return $this->morphToMany(Tag::class, 'taggable');
}
}
namespace App;
use Illuminate\Database\Eloquent\Model;
class Tag extends Model
{
/**
* Get all of the posts that are assigned this tag.
*/
public function posts()
{
return $this->morphedByMany(Post::class, 'taggable');
}
/**
* Get all of the videos that are assigned this tag.
*/
public function videos()
{
return $this->morphedByMany(Video::class, 'taggable');
}
}
$post = Post::find(1);
dd($post->tags);
$video = Video::find(1);
dd($video->tags);
$tag = Tag::find(1);
dd($tag->posts);
$tag = Tag::find(1);
dd($tag->videos);
posts table migration:
Schema::create('posts', function (Blueprint $table) {
$table->increments('id');
$table->string("name");
$table->timestamps();
});
videos table migration:
Schema::create('videos', function (Blueprint $table) {
$table->increments('id');
$table->string("name");
$table->timestamps();
});
tags table migration:
Schema::create('tags', function (Blueprint $table) {
$table->increments('id');
$table->string("name");
$table->timestamps();
});
taggables table migration:
Schema::create('taggables', function (Blueprint $table) {
$table->integer("tag_id");
$table->integer("taggable_id");
$table->string("taggable_type");
});

Related

Laravel: Multilanguage details of a model

I have a model named Point having the following fields:
name
description
lat
lng
The fields "name" and "description" can be in several languages, so I created two tables for points and their details.
Schema::create('points', function (Blueprint $table) {
$table->id();
$table->float('lat');
$table->float('lng');
$table->timestamps();
Schema::create('point_details', function (Blueprint $table) {
$table->id();
$table->integer('point_id');
$table->string('name');
$table->string('description');
$table->string('lang');
There is an index unique on point_id/language.
In the model files I have One To Many relationships
class Point extends Model
{
public function details()
{
return $this->hasMany(PointDetail::class);
}
}
class PointDetail extends Model
{
public function point()
{
return $this->belongsTo(Point::class);
}
}
Now I want to get the Point with details based on User language. I do so in the PointController:
class PointController extends Controller
{
public function show($id)
{
$point = Point::with(['details' => function($query) {
$query->where(
'lang', Auth::user()->lang ?
Auth::user()->lang :
'it');
}])->find($id);
return view('points.show',compact(['point']));
}
}
Can I avoid the "with" clause in the Controller? Maybe making the right query in the Point model file. I'm looking for a way to return the point with one detail associated with it, based on language of the Auth::user().
Thanks for any suggestion.
you can add query to relationship method in point class to details method
like that :
class Point extends Model
{
public function details()
{
return $this->hasMany(PointDetail::class)->where('lang', Auth::user()->lang);
}
}

create the anchor tag by using the morph relation in Laravel blade view

I have an application where an Invoice can belong to the client or supplier. Now I used the morph things in my current scenario. I want to create the proper anchor by using the morph relation But I didn't find the best way with Laravel
Client.php
class Client extends Model
{
/**
* Get the client's invoices.
*/
public function invoices()
{
return $this->morphMany('App\Invoice', 'contact');
}
}
Supplier.php
class Supplier extends Model
{
/**
* Get the supplier's invoices.
*/
public function invoices()
{
return $this->morphMany('App\Invoice', 'contact');
}
}
Invoice.php
class Invoice extends Model
{
/**
* Get the owning contact model.
*/
public function contact()
{
return $this->morphTo();
}
}
Now at somewhere(invoice details page), where I want to add the anchor to the contact of the invoice(either supplier or client) But I need to know if there is any Laravel's way.
If the contact of the invoice belongs to App\Client then the href will be "/clients/contact_id" or if it belongs to App\Supplier then it should be "/supplier/contact_id"
invoices/show.blade.php
<b>{{ $invoice->contact->name }}</b>
You can try given solution for you problem.
<?php
//You can see here for all table migration files
// For Client Table
Schema::create('client', function (Blueprint $table) {
$table->increments('id');
$table->string("client_name");
$table->timestamps();
// You can add your more fields and you can change field name also
});
// For Supplier Table
Schema::create('supplier', function (Blueprint $table) {
$table->increments('id');
$table->string("supplier_name");
$table->timestamps();
// You can add your more fields and you can change field name also
});
// For Invoice Table
Schema::create('invoices', function (Blueprint $table) {
$table->increments('id');
$table->morphs('invoice');
$table->timestamps();
// You can add your more fields and you can change field name also
});
//Note:
$table→morphs('invoice') would automatically create two columns using the text passed to it + “able”. So it will result in invoiceable_id and invoiceable_type.
?>
Here are your model for morphTo replationship
Client Model: Client.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Client extends Model
{
/**
* Get all of the Client's invoices.
*/
public function invoices()
{
return $this->morphMany(Invoices::class, 'invoiceable');
}
}
?>
Supplier Model: Supplier.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Supplier extends Model
{
/**
* Get all of the Supplier's invoices.
*/
public function invoices()
{
return $this->morphMany(Invoices::class, 'invoiceable');
}
}
?>
Invoices Model: Invoices.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Invoices extends Model
{
/**
* Get all of the owning invoiceable models.
*/
public function invoiceable()
{
return $this->morphTo();
}
}
?>
Now you can retrieve records using Client and Supplier using polymorphic relationship.
Retrieve records using client models.
$client = Client::find(1);
dd($client->invoices);
Retrieve records using Supplier models.
$supplier = Supplier::find(1);
dd($supplier->invoices);
You can also retrieve records
$client = Client::find(1);
foreach ($client->invoices as $invoice) {
<a href="{{ route('view-client', ['id' => $invoice->id]) }}">
<b>{{ $invoice->client_name }}</b>
</a>
}

Find all posts associated with a tag in laravel

I am building a blog with laravel where a post has many tags. I want to filter all post by a tag. means if I click on "PHP" tag I want to get all associated post.
Here is my code
I have two table first for tags and a second table for the link with posts
tag_table
public function up()
{
Schema::create('tags', function (Blueprint $table) {
$table->increments('id');
$table->string('tags');
$table->timestamps();
});
}
relation tag table
public function up()
{
Schema::create('article_tag', function (Blueprint $table) {
$table->increments('id');
$table->integer('article_id')->unsigned();
$table->foreign('article_id')->references('id')->on('articles');
$table->integer('tag_id')->unsigned();
$table->foreign('tag_id')->references('id')->on('tags');
});
}
Article Model
class Article extends Model
{
public function tags()
{
return $this->belongsToMany('App\Tag');
}
}
tag model
class Tag extends Model
{
public function articles()
{
return $this->belongsToMany('App\Article');
}
}
Tag Controller
public function show($id,$name)
{
//here I received tag id and name.
$list->with('articles')->get();
return view('articles.tagshow')->withList($list);
}
Eloquent offers the whereHas method that lets you filter on attributes of related models. In order to filter articles by the name of their associated tags, you should do the following:
$articles = Article::whereHas('tags', function($query) use ($tagName) {
$query->whereName($tagName);
})->get();
However, in your case it should be even simpler, because you already have the tag ID in your controller, so you can simply get a tag model by ID and then return related articles:
public function show($id,$name) {
return Tag::findOrFail($id)->articles;
}
Check the docs on querying relations for more details: https://laravel.com/docs/5.6/eloquent-relationships#querying-relations

Store Comments in DB

I am looking for a solution for storing comments in the database, but it is not difficult at all:
In one table wants to write comments from several modules on the website.
I am currently creating a table using code 'comments table':
public function up()
{
Schema::create('comments', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->integer('module_id')->unsigned();
$table->integer('parent_id')->unsigned();
$table->text('body');
$table->timestamps();
});
}
Comments modules table:
public function up()
{
//
Schema::create('comment_module',function (Blueprint $table){
$table->increments('id');
$table->string('title',190);
$table->string('name',190)->unique();
$table->text('body');
$table->timestamps();
});
}
for now everything is okay, but i have problem with select all comments for each blog post,gallery, etc..
blog, gallery - name of modules.
code for Map.php model
public function comments(){
return $this->hasMany(Comment::class,'module_id');
}
CommentModule.php model
public function comments(){
return $this->hasMany(Comment::class,'module_id');
}
Comment.php
public function module(){
return $this->belongsTo(CommentModule::class);
}
and now how to pass a 'mmodule_id' ?
normal use with any relationships for one table will be like that:
$map->comments->body . . etc.
but for that construction don`t work, yes of course i can use raw query and use join, right ?
Is any option to use a Eloquent?
IMHO for what I understood you want to attach comments to more than one Eloquent Model. There is a clean example in the laravel docs with Polymorphic Relations
As summary you have to add two fields on the comments table: commentable_id(integer) and commentable_type (string).
After that you declare the relation on the Comment model:
public function commentable()
{
return $this->morphTo();
}
And you can use the comments() relation in each model you want to attach comments, i.e.:
class Post extends Model
{
public function comments()
{
return $this->morphMany('App\Comment', 'commentable');
}
class Map extends Model
{
public function comments()
{
return $this->morphMany('App\Comment', 'commentable');
}
Now you can retrieve comments as usual:
$post->comments;
To attach a new comment to a parent:
$post->comments()->create([array of comment attributes]);

Specific role relations

I work on one project with Laravel 5.2 and Entrust package for ACL.
In this project I need for one Role ('venue_owner') in which venue is owner. I have also table called venue and I have no idea how to make this relations, because table users is general for all type of users.
How to make this relations to know what user from role venue_owner is owner of what venues ?
Have you created your Migrations yet by running: php artisan enthrust:migration? if not it, run it and then inside the file that is generated, add your own tables like below within the up() Method of the Enthrust Migration File:
<?php
public function up() {
// SOME OTHER TABLE CREATION CODES...
Schema::create('venue_owner', function (Blueprint $table) {
$table->increments('id');
$table->integer("user_id")->unsigned();
$table->timestamps();
// CREATE THE ASSOCIATION/RELATIONSHIP USING FOREIGN KEY
$table->foreign('id')
->references('id')
->on('venue')
->onDelete('cascade');
});
Schema::create('venues', function (Blueprint $table) {
$table->increments('id');
$table->integer("venue_owner_id")->unsigned();
$table->string("venue");
$table->timestamps();
// CREATE THE ASSOCIATION/RELATIONSHIP USING FOREIGN KEY
$table->foreign('venue_owner_id')
->references('id')
->on('venue_owner');
});
}
public function down() {
// OTHER DROP COMMAND CODES...
Schema::drop('venue_owner');
Schema::drop('venues');
}
Then in your Eloquent Model Class you can explicitly set the $this->hasMany() like so:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class VenueOwner extends Model {
/**
* GET ALL THE venues FOR THE venue_owner .
*/
public function venues() {
return $this->hasMany('App\Venues');
}
/**
* GET ALL THE user FOR THE venue_owner .
*/
public function user() {
return $this->hasOne('App\User');
}
And in your Venues Eloquent Model Class, you do something like:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Venues extends Model {
/**
* GET THE venue_owner FOR venue(s).
*/
public function venueOwner() {
return $this->belongsTo('App\VenueOwner');
}
Last but not least in your Users Eloquent Model Class, you do something like:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Users extends Model {
/**
* GET THE user Information FOR venue_owner.
*/
public function venueOwner() {
return $this-> hasOne('App\VenueOwner');
}
Now, you can get all information about the venue_owner and his venues and roles & permissions using the user_id.

Categories