Skip to content

Commit

Permalink
Added filtering when using eager loading
Browse files Browse the repository at this point in the history
  • Loading branch information
andrey-helldar committed Aug 31, 2024
1 parent 8ea3f60 commit e76a087
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 11 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"dragon-code/support": "^6.13",
"illuminate/database": "^10.0 || ^11.0",
"illuminate/support": "^10.0 || ^11.0",
"laravel-lang/config": "^1.6",
"laravel-lang/config": "^1.9",
"laravel-lang/locales": "^2.9.2",
"laravel/prompts": "^0.1.24"
},
Expand Down
34 changes: 34 additions & 0 deletions src/Eloquent/Scopes/FilterTranslationsScope.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace LaravelLang\Models\Eloquent\Scopes;

use Illuminate\Database\Eloquent\Builder;
use LaravelLang\Config\Facades\Config;
use LaravelLang\Locales\Facades\Locales;

use function array_unique;

class FilterTranslationsScope
{
public function __invoke(Builder $builder): void
{
if ($this->enabled()) {
$builder->whereIn('locale', $this->locales());
}
}

protected function enabled(): bool
{
return Config::shared()->models->filter->enabled;
}

protected function locales(): array
{
return array_unique([
Locales::getCurrent()->code,
Locales::getFallback()->code,
]);
}
}
4 changes: 3 additions & 1 deletion src/HasTranslations.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use LaravelLang\Locales\Facades\Locales;
use LaravelLang\Models\Concerns\HasNames;
use LaravelLang\Models\Concerns\ModelLoader;
use LaravelLang\Models\Eloquent\Scopes\FilterTranslationsScope;
use LaravelLang\Models\Eloquent\Translation;
use LaravelLang\Models\Services\Attribute;
use LaravelLang\Models\Services\Registry;
Expand All @@ -32,7 +33,8 @@ trait HasTranslations

public function translations(): HasMany
{
return $this->hasMany($this->translationModelName(), 'item_id');
return $this->hasMany($this->translationModelName(), 'item_id')
->tap(new FilterTranslationsScope());
}

public function hasTranslated(string $column, Locale|LocaleData|string|null $locale = null): bool
Expand Down
28 changes: 28 additions & 0 deletions tests/Datasets/LocalesFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

use Tests\Constants\FakeValue;

dataset('locales-filter', [
'enabled' => [
'enabled' => true,
'count' => 2,

'locales' => [
FakeValue::LocaleFallback,
FakeValue::LocaleMain,
],
],

'disabled' => [
'enabled' => false,
'count' => 3,

'locales' => [
FakeValue::LocaleCustom,
FakeValue::LocaleFallback,
FakeValue::LocaleMain,
],
],
]);
47 changes: 38 additions & 9 deletions tests/Unit/Models/GetTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@

declare(strict_types=1);

use App\Models\TestModel;
use App\Models\TestModelTranslation;
use Illuminate\Database\Events\QueryExecuted;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use LaravelLang\Config\Enums\Name;
use LaravelLang\Models\Exceptions\AttributeIsNotTranslatableException;
use LaravelLang\Models\Exceptions\UnavailableLocaleException;
use Tests\Constants\FakeValue;
Expand Down Expand Up @@ -69,17 +72,43 @@
expect($model->getTranslation(FakeValue::ColumnTitle, FakeValue::LocaleCustom))->toBeNull();
});

test('lazy loading', function () {
test('lazy loading', function (bool $enabled, int $count, array $locales) {
config()->set(Name::Shared() . '.models.filter.enabled', $enabled);

$hasNonFilteredQuery = false;
$hasFilteredQuery = false;

DB::listen(function (QueryExecuted $query) use (&$hasNonFilteredQuery, &$hasFilteredQuery) {
if (Str::is('select * where *."item_id" = ? and *."item_id" is not null', $query->sql)) {
$hasNonFilteredQuery = true;
}

if (Str::is('select * where *."item_id" = ? and *."item_id" is not null and "locale" in (?, ?)', $query->sql)) {
$hasFilteredQuery = true;
}
});

$model1 = fakeModel(main: 'Foo');
$model2 = fakeModel(main: 'Bar');

TestModel::query()->get()->each(
fn (TestModel $model) => match ($model->getKey()) {
$model1->getKey() => expect($model->title)->toBe('Foo'),
$model2->getKey() => expect($model->title)->toBe('Bar'),
}
);
});
$model1->load('translations');
$model2->load('translations');

expect($model1->relationLoaded('translations'))->toBeTrue();
expect($model2->relationLoaded('translations'))->toBeTrue();

expect($model1->translations()->count())->toBe($count);
expect($model2->translations()->count())->toBe($count);

expect($model1->translations->count())->toBe($count);
expect($model2->translations->count())->toBe($count);

expect($model1->translations->pluck('locale')->sort()->values()->all())->toBe($locales);
expect($model2->translations->pluck('locale')->sort()->values()->all())->toBe($locales);

expect($hasNonFilteredQuery)->toBe(! $enabled);
expect($hasFilteredQuery)->toBe($enabled);
})->with('locales-filter');

test('non-translatable attribute', function () {
$key = fake()->word;
Expand Down

0 comments on commit e76a087

Please sign in to comment.