Many to Many Get All Distinct Values From a Related Model - laravel

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();

Related

Laravel Eloquent: whereHas on relationship involving multiple tables

I am working on a Laravel project. I am using Eloquent to query data from the database.
I have the following models
Donation.php
class Donation extends Model
{
public function donator()
{
return $this->belongsTo(User::class);
}
}
User.php
class User extends Model
{
public function charities()
{
return $this->belongsToMany(Charity::class);
}
}
Charity.php
class Charity extends Model
{
public function donators()
{
return $this->belongsToMany(User::class);
}
}
I am writing a query on Donation model class and I am trying to query something like this. The query is just abstraction.
Donation::whereHas('donator.charities', function($query) {
$query->whereIn('charities.id', [ 1,2,3,4 ])
})
As you can see in the whereHas, I am applying the where clause on charities of donator. Is it possible to do that? How can I do that?
I hope this would be the answer of your question.
Donation::whereHas('donator',function($query){
$query->whereHas('charities',function($query){
$query->whereIn('id',[1,2,3,4]);
})
})->get();

laravel hasManyDeepFromRelations with group by

Models and relations
class Publisher extends Model
{
use HasRelationships;
public function collections(): BelongsToMany
{
return $this->belongsToMany(Collection::class)
->orderBy('title')
->using(CollectionPublisher::class);
}
public function series(): HasManyDeep
{
return $this->hasManyDeepFromRelations($this->collections(), (new Collection())->series());
}
}
class Collection extends Model
{
use HasRelationships, Translatable;
public function editions(): HasMany
{
return $this->hasMany(Edition::class);
}
public function series(): HasManyDeep
{
return $this->hasManyDeepFromRelations($this->editions(), (new Edition)->series());
}
}
class Edition extends Model
{
use HasRelationships, LoadsRelationshipsWithoutScopes, Translatable;
public function series(): BelongsTo
{
return $this->belongsTo(Series::class);
}
public function collection(): BelongsTo
{
return $this->belongsTo(Collection::class);
}
}
And of course there is a Series model.
The problem is that the series relation on the Publisher is returning each Series as many times as there is an Edition for that Publisher in the Series
How do I trim it down so each series is only returned once?
A simple groupBy('series.id') does not work due to the full group by limitations, and I'm not sure how to get around this using the has many deep package.
I finally came up with a solution
On the Publisher model:
public function series(): Builder
{
return $this->hasManyDeepFromRelations($this->collections(), (new Collection())->series())
->getQuery()
->select('series.*')
->groupBy('series.id');
}
The getQuery() part (undocumented in Laravel) limits the scope and allows the groupBy() to work
Thanks to Jonas Staudenmeir for the help

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

How can I add default scope / conditions on a relationship in Laravel 5?

So I have a table called files which contains a list of files with their respective name, path and file-type. Then I have a few other tables, to which files can be attached. For example the table user_profiles. And finally I have a pivot table for the Many To Many Polymorphic relationship between files and other tables. The pivot table is called fileables (couldn't think of a better name). Now users may have a few images attached to their profile and maybe a few videos, which both come from files.
Normally, if it were only images, I would do something like this:
class UserProfile extends Model {
public function images()
{
return $this->morphToMany('App\File', 'fileable');
}
}
However, since it's images and videos, I'd like to do something like this:
class UserProfile extends Model {
public function images()
{
return $this->morphToMany('App\File', 'fileable')->where('type', 'LIKE', 'image%');
}
public function videos()
{
return $this->morphToMany('App\File', 'fileable')->where('type', 'LIKE', 'video%');
}
}
But that doesn't seem to work. So what is the proper way to do this?
I would create scopes on your File model:
public function scopeImages($query)
{
return $query->where('type', 'LIKE', 'image/%');
}
public function scopeVideos($query)
{
return $query->where('type', 'LIKE', 'video/%');
}
And then use those in your UserProfile model:
public function images()
{
return $this->morphToMany('App\File', 'fileable')->images();
}
public function videos()
{
return $this->morphToMany('App\File', 'fileable')->videos();
}

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