mirror of
https://github.com/AnimeThemes/animethemes-server.git
synced 2026-07-11 01:24:46 +02:00
109 lines
3.7 KiB
PHP
109 lines
3.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Filament\Components\Fields;
|
|
|
|
use App\Contracts\Models\HasSubtitle;
|
|
use App\Contracts\Models\Nameable;
|
|
use App\Enums\Http\Api\Filter\ComparisonOperator;
|
|
use App\Filament\Resources\BaseResource;
|
|
use App\Models\Auth\User;
|
|
use App\Scout\Criteria;
|
|
use App\Scout\Search;
|
|
use Filament\Schemas\Schema;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Laravel\Scout\Searchable;
|
|
|
|
class BelongsTo extends Select
|
|
{
|
|
/** @var class-string<Model>|null */
|
|
protected ?string $modelResource = null;
|
|
protected string $relation;
|
|
protected ?BaseResource $resource = null;
|
|
protected bool $withSubtitle = true;
|
|
|
|
/**
|
|
* Set the filament resource for the relation. Relation should be set if BelongsToThrough.
|
|
*
|
|
* @param class-string<BaseResource> $resource
|
|
*/
|
|
public function resource(string $resource, ?string $relation = ''): static
|
|
{
|
|
$this->resource = new $resource;
|
|
$this->modelResource = $this->resource->getModel();
|
|
$this->relation = $relation;
|
|
|
|
$this->label($this->resource->getModelLabel());
|
|
|
|
if (filled($this->relation)) {
|
|
$this->relationship($this->relation, $this->resource->getRecordTitleAttribute());
|
|
}
|
|
|
|
$this->tryScout($this->modelResource);
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function showCreateOption(): static
|
|
{
|
|
$this->createOptionForm(fn (Schema $schema): array => $this->resource::form($schema)->getComponents())
|
|
->createOptionUsing(fn (array $data) => $this->resource->getModel()::query()->create($data)->getKey());
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function withSubtitle(bool $condition = true): static
|
|
{
|
|
$this->withSubtitle = $condition;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param class-string<Model> $modelClass
|
|
*/
|
|
protected function tryScout(string $modelClass): static
|
|
{
|
|
$this->allowHtml();
|
|
$this->searchable();
|
|
$this->getOptionLabelUsing(fn ($state): string => is_null($state) ? '' : static::getSearchLabelWithBlade($modelClass::query()->find($state), $this->withSubtitle));
|
|
|
|
if (in_array(Searchable::class, class_uses_recursive($modelClass))) {
|
|
return $this
|
|
->getSearchResultsUsing(
|
|
fn (string $search) => collect(
|
|
Search::getSearch($modelClass, new Criteria($this->escapeReservedChars($search)))
|
|
->search()
|
|
->items()
|
|
)
|
|
->merge($modelClass::query()->whereKey($this->escapeReservedChars($search))->get())
|
|
->mapWithKeys(fn (Model $model): array => [$model->getKey() => static::getSearchLabelWithBlade($model, $this->withSubtitle)])
|
|
->toArray()
|
|
);
|
|
}
|
|
|
|
return $this
|
|
->getSearchResultsUsing(
|
|
fn (string $search) => $modelClass::query()
|
|
->where($this->resource->getRecordTitleAttribute(), ComparisonOperator::LIKE->value, "%$search%")
|
|
->take(25)
|
|
->get()
|
|
->mapWithKeys(fn ($model): array => [$model->getKey() => static::getSearchLabelWithBlade($model, $this->withSubtitle)])
|
|
->toArray()
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param Model|User|Nameable|HasSubtitle $model
|
|
*/
|
|
public static function getSearchLabelWithBlade($model, bool $withSubtitle = true): string
|
|
{
|
|
return view('filament.components.select')
|
|
->with('name', $model->getName())
|
|
->with('subtitle', $withSubtitle ? $model->getSubtitle() : null)
|
|
->with('image', $model instanceof User ? $model->getFilamentAvatarUrl() : null)
|
|
->render();
|
|
}
|
|
}
|