automatic linking of articles and groups - laravel

I have articles that can contain different tags. For example, 5 pieces: (php, html, css, laravel, js) And I have groups that can also contain different tags. For example 4 pieces: (laravel, php, html, css)
I have already defined the relationships and it works. What I still lack is the linkage of articel to the group.
How can I show all posts in the group where the tags match?
Does anyone have an idea or can help me?
Post Model
public function groups()
{
return $this->belongsToMany('App\Group');
}
public function tags()
{
return $this->morphToMany('App\Tag', 'taggable');
}
Tag Model
public function articles()
{
return $this->morphedByMany('App\Article', 'taggable');
}
public function groups()
{
return $this->morphedByMany('App\Group', 'taggable');
}
Group Model
public function tags()
{
return $this->morphToMany('App\Tag', 'taggable');
}
public function articles()
{
return $this->belongsToMany('App\Article');
}

Since your question is updated I have seen a mistake in relationships
change article_group table name to taggables. Because laravel is doing some task on the basis of other table names. If you still want to use article_group then you will have to explicitly tell laravel about table names.
Read HasRelationships.php (full path is given below) trait then you will have idea about how laravel is linking them automatically.
/your_project/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php
Yes
Solution to your requirement is Many To Many Polymorphic Relations
Read it here https://laravel.com/docs/5.6/eloquent-relationships#many-to-many-polymorphic-relations.
You will create 4 tables as shown below and then create relationships in Models
articles
id - integer
name - string
groups
id - integer
name - string
tags
id - integer
name - string
taggables
tag_id - integer
taggable_id - integer
taggable_type - string
Relationship will be like this:
class Article extends Model
{
public function tags()
{
return $this->morphToMany('App\Tag', 'taggable');
}
}
Inverse Relatioship will be like this:
class Tag extends Model
{
public function articles()
{
return $this->morphedByMany('App\Article', 'taggable');
}
public function groups()
{
return $this->morphedByMany('App\Group', 'taggable');
}
}
Now you can get tags of Article like this:
$article = App\Article::find(1);
foreach ($article->tags as $tag) {
//
}
Attaching Articles To The Groups is As Follows:
$article = App\Article::find(1);
$group = App\Group::find(1);
$article->groups()->sync($group->id);
Read this for more https://laravel.com/docs/5.6/eloquent-relationships#updating-many-to-many-relationships
Hope this solves your problem.

Related

Many to Many Get All Distinct Values From a Related Model

I have an Article model with many-to-many relation with the Tag model
The Article model
class Article extends Model
{
public function tags()
{
return $this->belongsToMany(Tag::class);
}
}
The Tag model
class Tag extends Model
{
public function articles()
{
return $this->belongsToMany(Article::class);
}
}
What I want is to get all the unique tags that have a relation with at least one (or more) article in the articles table. I want to retrieve it through a static method in the Article model like below
public static function allTags()
{
// return static:: all the tags
}
How can I do this? Thanks in advance.
EDIT: this is how I solved it. Appreciate the help!
public static function allTags()
{
return Tag::query()->whereHas('articles', function($query) {
$query->where('status', '<>', 'draft');
})->pluck('tag', 'id');
}
Using whereHas()
$tags = Tag::query()->whereHas('articles')->get();

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.

Laravel Relationship not working on server

My project is working fine on local host, but on the server, getting error only on lesson page.
Subject Model is
class Subjects extends Model
{
public function category()
{
return $this->belongsTo('Lea\Category');
}
public function lesson()
{
return $this->hasMany('Lea\Lessons');
}
public function chapter()
{
return $this->hasMany('Lea\Chapters');
}
public function users()
{
return $this->belongsToMany('Lea\User', 'subject_user', 'subject_id', 'user_id');
}
}
And Lesson Model is
class Lessons extends Model
{
public function chapter()
{
return $this->belongsTo('Lea\Chapters');
}
public function subject()
{
return $this->belongsTo('Lea\Subjects', 'subject_id');
}
public function category()
{
return $this->belongsTo('Lea\Category');
}
}
My controller lessons has method index like below.
public function index()
{
$lessons = lessons::orderBy('id', 'asc')->paginate(5);
return view('admin.lessons.index')->withLessons($lessons);
}
The way i am calling subject name is show below. first subject is relationship subject and 2nd subject is the field name where subject name saved in db. using foreach to get data like:
#foreach ($lessons as $lesson)
{{$lesson->subject->subject}}
#endforeach
subjects table schema is
id
subject
admin_id
users_id
category_id
created_at
updated_at
lessons table schema is
id
title
slug
category_id
subject_id
chapter_id
users_id
content
image
That's more like it ;)
Just edit how you are passing the object to the following:
...
return view('admin.lessons.index')->with(compact('lessons'));
What this is doing:
compact() essentially takes the object/variable by it's name ($lessons) and passes it to the view with the same name.
An alternative way is to write it as:
...
return view('admin.lessons.index')->with('lessons', $lessons);
Cheers!
The reason you're getting the error in your server but not your local machine is that your server database is empty (or at least has fewer records).
{{$lesson->subject->subject}}
The lesson has no subject, so it's null. And your tryting to get a proprty subject of a null.
If you're using Laravel 5.5, you can wrap the subject in optional() method.
{{optional($lesson->subject)->subject}}
< Laravel 5.5
{{$lesson->subject ? $lesson->subject->subject : ''}}

Laravel query multiple tables using eloquent

hi sorry bit of a newbie here but I am have three tables users, profiles, friends. they all have the user_id fields within them and I want fetch all of the fields in one statement using Eloquent and not DB::statement and doing the table joins.
How can I achieve this?
Try this
use the User class and the with method that laravel has to query model relationships
$user = User::with(['profile', 'friend'])->get();
Ensure your models has the correct relationships as follows:
app/models/User.php
public function friend () {
return $this->hasMany('Friend');
}
public function profile () {
return $this->hasOne('Profile');
}
app/models/Profile.php
public function user() {
return $this->belongsTo('User');
}
app/models/Friend.php
public function user() {
return $this->belongsTo('User');
}
use some thing like this:
You should define relations in your models with hasOne, hasMany.
class Review extends Eloquent {
public function relatedGallery()
{
$this->hasOne('Gallery', 'foreign_id', 'local_id');
}
}
class Gallery extends Eloquent {
public function relatedReviews()
{
$this->hasMany('Review', 'foreign_id', 'local_id');
}
}
$gallery = Gallery::with('relatedReviews')->find($id);
Will bring the object Gallery with
$gallery->id
gallery->name
...
$gallery->relatedReviews // array containing the related Review Objects

Laravel 4.1: proper way to retrieve all morphedBy relations?

Just migrated to 4.1 to take advantage of this powerful feature.
everything seems to work correctly when retrieving individual 'morphedByXxxx' relations, however when trying to retrieve all models that a particular tag belongs to -- i get an error or no results.
$tag = Tag::find(45); //Tag model name = 'awesome'
//returns an Illuminate\Database\Eloquent\Collection of zero length
$tag->taggable;
//returns Illuminate\Database\Eloquent\Relations\MorphToMany Builder class
$tag->taggable();
//returns a populated Collection of Video models
$tag->videos()->get();
//returns a populated Collection of Post models
$tag->posts()->get();
My Tag Model class loooks like this:
class Tag extends Eloquent
{
protected $table = 'tags';
public $timestamps = true;
public function taggable()
{
//none of these seem to function as expected,
//both return an instance of MorphToMany
//return $this->morphedByMany('Tag', 'taggable');
return $this->morphToMany('Tag', 'taggable');
//this throws an error about missing argument 1
//return $this->morphToMany();
}
public function posts()
{
return $this->morphedByMany('Post', 'taggable');
}
public function videos()
{
return $this->morphedByMany('Video', 'taggable');
}
}
And the Post and Video models look like this:
class Post extends Eloquent
{
protected $table = 'posts';
public $timestamps = true;
public function tags()
{
return $this->morphToMany('Tag', 'taggable');
}
}
I am able to add/remove Tags to Posts and Videos as well as retrieve the related Posts, and Videos for any Tag -- however -- what is the proper way to retrieve all Models having the Tag name 'awesome'?
Was able to figure it out, would love to hear comments on this implementation.
in Tag.php
public function taggable()
{
return $this->morphToMany('Tag', 'taggable', 'taggables', 'tag_id')->orWhereRaw('taggables.taggable_type IS NOT NULL');
}
in calling code:
$allItemsHavingThisTag = $tag->taggable()
->with('videos')
->with('posts')
->get();
I just used this on Laravel 5.2 (not sure if it is a good strategy though):
Tag model:
public function related()
{
return $this->hasMany(Taggable::class, 'tag_id');
}
Taggable model:
public function model()
{
return $this->belongsTo( $this->taggable_type, 'taggable_id');
}
To retrieve all the inverse relations (all the entities attached to the requested tag):
#foreach ($tag->related as $related)
{{ $related->model }}
#endforeach
... sadly this technique doesn't offer eager load functionalities and feels like a hack. At least it makes it simple to check the related model class and show the desired model attributes without much fear to look for the right attributes on the right model.
I posted a similar question in this other thread as I am looking for relations not known in advance.

Resources