-
Notifications
You must be signed in to change notification settings - Fork 42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Question: Polymorphic Relationship Example #29
Comments
Hi Dear @sniper7kills , |
Hi @sniper7kills , You can make a filter as <?php
namespace App\EloquentBuilders\Comment;
use Fouladgar\EloquentBuilder\Support\Foundation\Contracts\Filter;
use Illuminate\Database\Eloquent\Builder;
class CommentableFilter extends Filter
{
/**
* Apply Commentable filter to the query builder
*
* @param Builder $builder
* @param mixed $value
*
* @return Builder
*/
public function apply(Builder $builder, $value): Builder
{
// You should control your logic in here
// Simple usage:
return $builder->where(function ($query) use($value) {
$query->where('commentable_id', $value['key'])
->where('commentable_key',$value['type']);
});
}
} Next: // Get: api/comments?filters[commentable][key]=1&filters[commentable][type]=post
$result = EloquentBuilder::to(Comment::class,$request->filters)
->with('commentable') // optional
->paginate();
return response()->json($result); I hope this answers your questions. |
That is much cleaner than what I was thinking of doing! Thanks so much for the reply! |
Because I have multiple Many-To-Many polymorphic models I thought I'd share what I ended up doing for posterity. This example is based off of The following would be the example filter array; One could also add a //type = what we want to get
//id = id of what we currently have
// Requesting Tags from Post/Video
// http://127.0.0.1/api/tags
$filters = ['polymorphic' => ['polymorphic_type' => 'Tag', 'polymorphic_id' => {POST_OR_VIDEO_ID}]];
// Requesting Posts from Tag
// http://127.0.0.1/api/posts
$filters = ['polymorphic' => ['polymorphic_type' => 'Post', 'polymorphic_id' => {TAG_ID}, 'polymorphic_inverse'=true]];
// Requesting Videos from Tag
// http://127.0.0.1/api/videos
$filters = ['polymorphic' => ['polymorphic_type' => 'Video', 'polymorphic_id' => {TAG_ID}, 'polymorphic_inverse'=true]]; In each of my models that is polymorphic I've added the following: (I'll probably implement a contract and trait later and make that variable private; but its working for now) namespace App;
class Tag extends Model
{
public $polymorphicName = 'tagable';
} This is my Factory class that generates the query. <?php
namespace App\EloquentFilters;
use Illuminate\Database\Eloquent\Builder;
class PolymorphicFactory
{
//This is the namespace of the models
private $modelNamespace = 'App\\';
//This is the model the filter is being run on.
protected $filtered = null;
//This will be "tagable" or "commentable" based on the variable in the above section
protected $polymorphicName = null;
//These are passed to use through $value
protected $id = null;
protected $type = null;
protected $inverse = false;
protected $pivots = [];
public function __construct(String $filtered, Array $value)
{
$this->filtered = $filtered;
$this->id = $value['polymorphic_id'];
$this->type = $this->modelNamespace.$value['polymorphic_type'];
if(key_exists('polymorphic_pivots', $value))
$this->pivots = $value['polymorphic_pivots'];
if(key_exists('polymorphic_inverse',$value) && $value['polymorphic_inverse']) {
$this->inverse = true;
$this->polymorphicName = strtolower((new $this->type)->polymorphicName);
}else{
$this->polymorphicName = strtolower((new $this->filtered)->polymorphicName);
}
}
public function getQuery(Builder $builder)
{
return $builder->join($this->polymorphicName.'s', function($join){
return $this->getSubQuery($join);
});
}
public function getSubQuery($join)
{
if(!$this->inverse){
$join->on('id', '=', $this->polymorphicName.'s.'.$this->polymorphicName.'_id')
->where(
$this->polymorphicName.'s.'.$this->polymorphicName.'_type',
$this->type
)
->where(
$this->polymorphicName.'s.'.strtolower((new \ReflectionClass($this->filtered))->getShortName()).'_id',
$this->id
);
}
else{
$join->on('id', '=', $this->polymorphicName.'s.'.strtolower((new \ReflectionClass($this->type))->getShortName()).'_id')
->where(
$this->polymorphicName.'s.'.$this->polymorphicName.'_type',
$this->filtered
)
->where(
$this->polymorphicName.'s.'.$this->polymorphicName.'_id',
$this->id
);
}
foreach($this->pivots as $col => $value)
{
$join->where($this->polymorphicName.'s.'.strtolower($col), $value);
}
return $join;
}
} And this is the Filter I'm using. (Just have to ensure the model being filtered is added) <?php
namespace App\EloquentFilters\Video;
use Fouladgar\EloquentBuilder\Support\Foundation\Contracts\Filter;
use Illuminate\Database\Eloquent\Builder;
use App\EloquentFilters\PolymorphicFactory;
use App\Video;
class PolymorphicFilter extends Filter
{
public function apply(Builder $builder, $value): Builder
{
return (new PolymorphicFactory(Video::class, $value))->getQuery($builder);
}
} |
@sniper7kills thank you for your sharing 👍 |
You were right; I've updated my previous comment with my updated code. |
Well done. Keep going on 👍✨ |
This package looks amazing, I haven't fully played with it too much but wanted to ask about polymorphic relationships.
Lets say I have Pages, Posts, and Comments. I want to make an API end point for comments that can pull the comments for a specific page or post with additional filters.
Is the recommended method to be similar to:
#28 (comment)
Where if I have two filters:
polymorphic_type
andpolymorphic_key
I should do something like this in my comments controller, or would there be a better way?(Code may not actually work; just trying to figure out the best way to go about this)
The text was updated successfully, but these errors were encountered: