Skip to content
This repository has been archived by the owner on Nov 21, 2023. It is now read-only.

Commit

Permalink
Merge pull request #12 from mpyw/feature/support-union-argument
Browse files Browse the repository at this point in the history
Revise: "Add support for union argument in constraint callable #11"
  • Loading branch information
mpyw authored Oct 11, 2021
2 parents 26ac295 + 2c17a0b commit 7345abd
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 3 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,15 @@ Additional `callable` constraints for relations that take **`Illuminate\Database
Builder::hasByNonDependentSubquery('comments', fn (HasMany $query) => $query->withTrashed())
```

If you are using a union type as of PHP 8.0, the order of types does not matter.

```php
// This will work
Builder::hasByNonDependentSubquery('comments', fn (HasMany|Comment $query) => $query->withTrashed())
// and so will this
Builder::hasByNonDependentSubquery('comments', fn (Comment|HasMany $query) => $query->withTrashed())
```

The first closure corresponds to `comments` and the second one corresponds to `author`.

```php
Expand Down
49 changes: 46 additions & 3 deletions src/HasByNonDependentSubqueryMacro.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
use DomainException;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\Relation;
use ReflectionNamedType;
use ReflectionType;

/**
* Class HasByNonDependentSubqueryMacro
Expand Down Expand Up @@ -148,8 +150,49 @@ protected function adjustArgumentTypeOfOptionalConstraints(callable $constraint,

return $reflection->getNumberOfParameters() > 0
&& ($parameter = $reflection->getParameters()[0])->hasType()
&& \is_a($parameter->getType()->getName(), Builder::class, true)
? $relation->getQuery()
: $relation;
&& $this->mustExtractEloquentBuilder($parameter->getType())
? $relation->getQuery()
: $relation;
}

/**
* @param \ReflectionNamedType|\ReflectionType|\ReflectionUnionType $type
* @return bool
*/
protected function mustExtractEloquentBuilder(ReflectionType $type): bool
{
/* @noinspection PhpElementIsNotAvailableInCurrentPhpVersionInspection */
return $type instanceof \ReflectionUnionType
? $this->onlyIncludesBuilderType($type)
: $this->namedTypeIs($type, Builder::class);
}

/** @noinspection PhpElementIsNotAvailableInCurrentPhpVersionInspection */

/**
* @param \ReflectionUnionType $types
* @return bool
*/
protected function onlyIncludesBuilderType(\ReflectionUnionType $types): bool
{
$includesRelationType = false;
$includesBuilderType = false;

foreach ($types->getTypes() as $type) {
$includesRelationType = $includesRelationType || $this->namedTypeIs($type, Relation::class);
$includesBuilderType = $includesBuilderType || $this->namedTypeIs($type, Builder::class);
}

return !$includesRelationType && $includesBuilderType;
}

/**
* @param \ReflectionNamedType $type
* @param string $class
* @return bool
*/
protected function namedTypeIs(ReflectionNamedType $type, string $class): bool
{
return \is_a($type->getName(), $class, true);
}
}
9 changes: 9 additions & 0 deletions tests/Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,15 @@ function (Builder $query) {
);
}

public function testAcceptUnionArgument(): void
{
if (version_compare(phpversion(), '8.0', '>=')) {
include __DIR__ . '/includes/test_accept_union_argument.php';
} else {
$this->markTestSkipped('Union types are only supported in PHP >= 8.0');
}
}

public function testMultiColumnRelation(): void
{
$this->expectException(DomainException::class);
Expand Down
84 changes: 84 additions & 0 deletions tests/includes/test_accept_union_argument.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Mpyw\EloquentHasByNonDependentSubquery\Tests\Models\Comment;
use Mpyw\EloquentHasByNonDependentSubquery\Tests\Models\Post;

$this->assertQueryEquals(
<<<'EOD'
select
*
from
"comments"
where
"comments"."post_id" in (
select
"posts"."id"
from
"posts"
where
"posts"."deleted_at" is not null
)
EOD
,
Comment::query()->hasByNonDependentSubquery(
'post',
function (Post|BelongsTo $query) {
$this->assertInstanceof(BelongsTo::class, $query);
$query->onlyTrashed();
}
)->withTrashed()
);

$this->assertQueryEquals(
<<<'EOD'
select
*
from
"comments"
where
"comments"."post_id" in (
select
"posts"."id"
from
"posts"
where
"posts"."deleted_at" is not null
)
EOD
,
Comment::query()->hasByNonDependentSubquery(
'post',
function (BelongsTo|Builder $query) {
$this->assertInstanceof(BelongsTo::class, $query);
$query->onlyTrashed();
}
)->withTrashed()
);

$this->assertQueryEquals(
<<<'EOD'
select
*
from
"comments"
where
"comments"."post_id" in (
select
"posts"."id"
from
"posts"
where
"posts"."deleted_at" is not null
)
EOD
,
Comment::query()->hasByNonDependentSubquery(
'post',
function (Post|Builder $query) {
$this->assertInstanceof(Builder::class, $query);
$query->onlyTrashed();
}
)->withTrashed()
);

0 comments on commit 7345abd

Please sign in to comment.