Skip to content

Commit

Permalink
Merge pull request #4 from ghonijee/hotfix/fixing-filter-relation
Browse files Browse the repository at this point in the history
Fixing bug filter relation data
  • Loading branch information
ghonijee authored Nov 3, 2021
2 parents 396910e + f84237d commit ceac3b1
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 30 deletions.
5 changes: 5 additions & 0 deletions Models/TestModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ public function comments()
return $this->hasMany(TestComment::class, 'test_model_id');
}

public function dataComments()
{
return $this->hasMany(TestComment::class, 'test_model_id');
}

public function scopeActive(Builder $query)
{
$query->where('active', 1);
Expand Down
26 changes: 7 additions & 19 deletions src/Builders/FilterQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use GhoniJee\DxAdapter\Data\FilterData;
use GhoniJee\DxAdapter\FilterClass\BuilderFilterData;
use GhoniJee\DxAdapter\FilterClass\BuilderFilterQuery;
use GhoniJee\DxAdapter\FilterClass\BuilderRelationFilterQuery;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Support\Collection;
Expand All @@ -21,6 +22,7 @@ protected function parseFilter()
$this->setArray();

$this->buildFilterData();

$this->query = $this->buildFilterQuery($this->query, $this->filter);

return $this;
Expand All @@ -38,7 +40,7 @@ private function buildFilterData()
$this->filter = BuilderFilterData::fromRequest($this->filter);
}

private function buildFilterQuery(Builder $query, $collection)
private function buildFilterQuery(Builder &$query, $collection)
{
$collection->each(function ($item) use ($query) {
if (is_string($item)) {
Expand All @@ -54,19 +56,7 @@ private function buildFilterQuery(Builder $query, $collection)
}

if ($this->isRelationFilter($query, $item)) {

[$relation,] = collect(explode('.', $item->field))
->pipe(function (Collection $parts) {
return [
$parts->except(count($parts) - 1)->implode('.'),
$parts->last(),
];
});

$this->query->whereHas($relation, function (Builder $relationQuery) use ($item) {
$relationQuery = BuilderFilterQuery::fromDataType($relationQuery, $item, $this->conjungtion)->query();
});

$query = BuilderRelationFilterQuery::fromDataType($query, $item, $this->conjungtion)->query();
return true;
}

Expand All @@ -78,16 +68,14 @@ private function buildFilterQuery(Builder $query, $collection)

private function isRelationFilter(Builder $query, FilterData $item)
{
if (!Str::contains($item->field, '.')) {
if (!$item->isRelation) {
return false;
}

$firstRelationship = explode('.', $item->field)[0];

if (!method_exists($query->getModel(), $firstRelationship)) {
if (!method_exists($query->getModel(), $item->relationMethod)) {
return false;
}

return is_a($query->getModel()->{$firstRelationship}(), Relation::class);
return is_a($query->getModel()->{$item->relationMethod}(), Relation::class);
}
}
21 changes: 20 additions & 1 deletion src/Data/FilterData.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

use DateTime;
use GhoniJee\DxAdapter\Enums\ValueDataType;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;

class FilterData
{
Expand All @@ -15,11 +17,14 @@ class FilterData

public $type;

public $relation;
public $relationMethod;

public bool $isRelation = false;

public function __construct($data)
{
list($this->field, $this->condition, $this->value) = $data;
$this->isRelationFilter();
$this->setValueType();
}

Expand Down Expand Up @@ -81,4 +86,18 @@ private function isNumeric()
}
return false;
}

public function isRelationFilter()
{
if (Str::contains($this->field, '.')) {
$this->isRelation = true;
[$this->relationMethod, $this->field] = collect(explode('.', $this->field))
->pipe(function (Collection $parts) {
return [
$parts->except(count($parts) - 1)->implode('.'),
$parts->last(),
];
});
}
}
}
2 changes: 1 addition & 1 deletion src/FilterClass/BuilderFilterQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public function __construct($query, FilterData $filterData, $conjungtion)
$this->conjungtion = $conjungtion;
}

public static function fromDataType($query, FilterData $filterData, $conjungtion)
public static function fromDataType($query, FilterData $filterData, $conjungtion = null)
{
return new self($query, $filterData, $conjungtion);
}
Expand Down
55 changes: 55 additions & 0 deletions src/FilterClass/BuilderRelationFilterQuery.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

namespace GhoniJee\DxAdapter\FilterClass;

use Exception;
use GhoniJee\DxAdapter\Data\FilterData;
use GhoniJee\DxAdapter\Enums\ValueDataType;
use GhoniJee\DxAdapter\FilterClass\QueryClass\BooleanFilter;
use GhoniJee\DxAdapter\FilterClass\QueryClass\DateFilter;
use GhoniJee\DxAdapter\FilterClass\QueryClass\NullFilter;
use GhoniJee\DxAdapter\FilterClass\QueryClass\NumericFilter;
use GhoniJee\DxAdapter\FilterClass\QueryClass\StringFilter;

class BuilderRelationFilterQuery
{
protected $query;

protected FilterData $filterData;

protected $conjungtion;

public function __construct($query, FilterData $filterData, $conjungtion)
{
$this->query = $query;
$this->filterData = $filterData;
$this->conjungtion = $conjungtion;
}

public static function fromDataType($query, FilterData $filterData, $conjungtion = null)
{
return new self($query, $filterData, $conjungtion);
}

public function query()
{
switch ($this->conjungtion) {
case '!':
$this->query->whereDoesntHave($this->filterData->relationMethod, function ($relationQuery) {
$relationQuery = BuilderFilterQuery::fromDataType($relationQuery, $this->filterData)->query();
});
break;
case 'or':
$this->query->orWhereHas($this->filterData->relationMethod, function ($relationQuery) {
$relationQuery = BuilderFilterQuery::fromDataType($relationQuery, $this->filterData)->query();
});
break;
default:
$this->query->whereHas($this->filterData->relationMethod, function ($relationQuery) {
$relationQuery = BuilderFilterQuery::fromDataType($relationQuery, $this->filterData)->query();
});
break;
}
return $this->query;
}
}
54 changes: 45 additions & 9 deletions tests/Feature/FilterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@
$query = TestModel::query();
$queryBuilder = DxAdapter::load($query, $this->request)->toSql();
$expected = TestModel::whereHas('comments', function ($queryComment) {
$queryComment->where('comments.comment', 'like', 'ahmad');
$queryComment->where('comment', 'like', 'ahmad');
})->where(function ($q) {
$q->where('active', 0);
$q->orWhere('active', 1);
Expand All @@ -247,18 +247,54 @@
});


test('can filter with string params', function () {
$filter = [['comments.comment', 'contains', 'test'], 'and', [['active', '=', 0], 'or', ['active', '=', 1]]];
test('can filter multi relation data with conjungtion OR', function () {
$filter = [[['dataComments.comment', 'contains', 'test'], 'or', ['dataComments.comment', 'contains', 'est']], 'and', ['active', '=', 1]];
$this->request->replace(['filter' => json_encode($filter)]);

$query = TestModel::query();
$queryBuilder = DxAdapter::load($query, $this->request)->toSql();
$expected = TestModel::whereHas('comments', function ($queryComment) {
$queryComment->where('comments.comment', 'like', 'ahmad');
})->where(function ($q) {
$q->where('active', 0);
$q->orWhere('active', 1);
})->toSql();

$expected = TestModel::where(function ($q) {
$q->whereHas('dataComments', function ($queryComment) {
$queryComment->where('comment', 'like', 'test');
})->orWhereHas('dataComments', function ($queryCommentNew) {
$queryCommentNew->where('comment', 'like', 'est');
});
})->where('active', 1)->toSql();

expect($queryBuilder)->toEqual($expected);
});
test('can filter multi relation data with conjungtion AND', function () {
$filter = [[['dataComments.comment', 'contains', 'test'], 'and', ['dataComments.comment', 'contains', 'est']], 'and', ['active', '=', 1]];
$this->request->replace(['filter' => json_encode($filter)]);

$query = TestModel::query();
$queryBuilder = DxAdapter::load($query, $this->request)->toSql();

$expected = TestModel::where(function ($q) {
$q->whereHas('dataComments', function ($queryComment) {
$queryComment->where('comment', 'like', 'test');
})->whereHas('dataComments', function ($queryCommentNew) {
$queryCommentNew->where('comment', 'like', 'est');
});
})->where('active', 1)->toSql();

expect($queryBuilder)->toEqual($expected);
});
test('can filter multi relation data with conjungtion NOT', function () {
$filter = [[['dataComments.comment', 'contains', 'test'], '!', ['dataComments.comment', 'contains', 'est']], 'and', ['active', '=', 1]];
$this->request->replace(['filter' => json_encode($filter)]);

$query = TestModel::query();
$queryBuilder = DxAdapter::load($query, $this->request)->toSql();

$expected = TestModel::where(function ($q) {
$q->whereHas('dataComments', function ($queryComment) {
$queryComment->where('comment', 'like', 'test');
})->whereDoesntHave('dataComments', function ($queryCommentNew) {
$queryCommentNew->where('comment', 'like', 'est');
});
})->where('active', 1)->toSql();

expect($queryBuilder)->toEqual($expected);
});

0 comments on commit ceac3b1

Please sign in to comment.