Skip to content

Instantly share code, notes, and snippets.

@bmadigan
Created May 9, 2025 16:55
Show Gist options
  • Save bmadigan/6e09d857cea238090c0e181887838491 to your computer and use it in GitHub Desktop.
Save bmadigan/6e09d857cea238090c0e181887838491 to your computer and use it in GitHub Desktop.
Laravel ModelsThat - Aaron Francis Inspired
<?php
namespace App\Traits;
use Illuminate\Database\Eloquent\Builder;
trait HasEmbedding
{
public function scopeNeedsEmbedding(Builder $query): Builder
{
return $query->whereNull('embedded_at'); // or a relevant field check
}
public function scopeReserveFor(Builder $query, string $key, string $duration): Builder
{
// Assuming a 'reserved_until' datetime column
return $query->where(function ($q) {
$q->whereNull('reserved_until')
->orWhere('reserved_until', '<', now());
})->tap(function ($query) use ($duration) {
$query->update(['reserved_until' => now()->add(strtotime($duration) - time())]);
});
}
}
<?php
use App\Models\TestHasEmbeddingModel;
use Illuminate\Support\Carbon;
test('it filters models needing embedding', function () {
TestHasEmbeddingModel::factory()->create(['embedded_at' => null]);
TestHasEmbeddingModel::factory()->create(['embedded_at' => now()]);
$results = TestHasEmbeddingModel::needsEmbedding()->get();
expect($results)->toHaveCount(1);
});
test('it reserves models for a given time', function () {
$model = TestHasEmbeddingModel::factory()->create(['reserved_until' => null]);
TestHasEmbeddingModel::reserveFor('embeddings:create', '+2 hours')->get();
$model->refresh();
expect($model->reserved_until)->toBeInstanceOf(Carbon::class);
expect($model->reserved_until->gt(now()))->toBeTrue();
});
<?php
namespace App\Helpers;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\File;
use ReflectionClass;
class ModelsThat
{
public static function useTrait(string $trait): \Illuminate\Support\Collection
{
$modelsPath = app_path('Models');
$modelsNamespace = 'App\\Models\\';
return collect(File::allFiles($modelsPath))
->filter(fn ($file) => Str::endsWith($file->getFilename(), '.php'))
->map(function ($file) use ($modelsNamespace) {
$class = $modelsNamespace . $file->getBasename('.php');
if (! class_exists($class)) {
require_once $file->getPathname();
}
return $class;
})
->filter(function ($class) use ($trait) {
return in_array($trait, class_uses_recursive($class));
});
}
}
<?php
use App\Helpers\ModelsThat;
use App\Models\TestHasEmbeddingModel;
use App\Traits\HasEmbedding;
use Illuminate\Support\Collection;
beforeEach(function () {
// Simulate autoloading
require_once app_path('Models/TestHasEmbeddingModel.php');
});
test('it returns models using the HasEmbedding trait', function () {
$models = ModelsThat::useTrait(HasEmbedding::class);
expect($models)->toBeInstanceOf(Collection::class);
expect($models)->toContain(TestHasEmbeddingModel::class);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment