Skip to content

Commit

Permalink
Add Included callback (#894)
Browse files Browse the repository at this point in the history
* ADD included callback

* Fix styling

* wip
  • Loading branch information
enricodelazzari authored Oct 5, 2023
1 parent 89325f9 commit ed654c0
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 0 deletions.
17 changes: 17 additions & 0 deletions docs/features/including-relationships.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,23 @@ $posts = QueryBuilder::for(Post::class)
// every post in $posts will contain a `comments_sum_votes` property
```

## Callback includes

If you want to define a tiny custom include, you can use a callback include. Using `AllowedInclude::callback(string $name, Closure $callback, ?string $internalName = null)` you can specify a Closure that will be executed when the includes is requested.

You can modify the `Builder` object to add your own query constraints.

For example:

```php
QueryBuilder::for(User::class)
->allowedIncludes([
AllowedInclude::callback('latest_post', function (Builder $query) {
$query->latestOfMany();
}),
]);
```

## Selecting included fields

You can select only some fields to be included using the [`allowedFields` method on the query builder](https://spatie.be/docs/laravel-query-builder/v5/features/selecting-fields/).
Expand Down
9 changes: 9 additions & 0 deletions src/AllowedInclude.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

namespace Spatie\QueryBuilder;

use Closure;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use Spatie\QueryBuilder\Includes\IncludedCallback;
use Spatie\QueryBuilder\Includes\IncludedCount;
use Spatie\QueryBuilder\Includes\IncludedExists;
use Spatie\QueryBuilder\Includes\IncludedRelationship;
Expand Down Expand Up @@ -73,6 +75,13 @@ public static function exists(string $name, ?string $internalName = null): Colle
]);
}

public static function callback(string $name, Closure $callback, ?string $internalName = null): Collection
{
return collect([
new static($name, new IncludedCallback($callback), $internalName),
]);
}

public static function custom(string $name, IncludeInterface $includeClass, ?string $internalName = null): Collection
{
return collect([
Expand Down
23 changes: 23 additions & 0 deletions src/Includes/IncludedCallback.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace Spatie\QueryBuilder\Includes;

use Closure;
use Illuminate\Database\Eloquent\Builder;

class IncludedCallback implements IncludeInterface
{
protected Closure $callback;

public function __construct(Closure $callback)
{
$this->callback = $callback;
}

public function __invoke(Builder $query, string $relation)
{
$query->with([
$relation => $this->callback,
]);
}
}
17 changes: 17 additions & 0 deletions tests/IncludeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Spatie\QueryBuilder\Includes\IncludeInterface;
use Spatie\QueryBuilder\QueryBuilder;
use Spatie\QueryBuilder\Tests\TestClasses\Models\MorphModel;
use Spatie\QueryBuilder\Tests\TestClasses\Models\RelatedModel;
use Spatie\QueryBuilder\Tests\TestClasses\Models\TestModel;

beforeEach(function () {
Expand Down Expand Up @@ -69,6 +70,22 @@
assertRelationLoaded($models, 'relatedModels');
});

it('can include an includes callback', function () {
$models = createQueryFromIncludeRequest('relatedModels')
->allowedIncludes([
AllowedInclude::callback('relatedModels', fn ($query) => $query->whereKey(RelatedModel::first())),
])
->get();

assertRelationLoaded($models, 'relatedModels');

$models = $models->reverse();
expect($models->pop()->relatedModels)->toHaveCount(1);
expect($models)->each(
fn ($model) => $model->relatedModels->toHaveCount(0)
);
});

it('can include an includes count', function () {
$model = createQueryFromIncludeRequest('relatedModelsCount')
->allowedIncludes('relatedModelsCount')
Expand Down

0 comments on commit ed654c0

Please sign in to comment.