По умолчанию в MoonShine поля работают с примитивными типами и ничего не знают о моделях.
Это было сделано для того, чтобы система не была привязана только к моделям, и поля могли, в зависимости от ситуации, иметь доступ как к необработанным данным, так и к типизированным данным.
TypeCast
для моделей уже включен в MoonShine, но если вам нужно работать с другим типом данных, вам понадобится объект, реализующий интерфейс MoonShine\Contracts\Core\TypeCasts\DataCasterContract
.
interface DataCasterContract
{
public function cast(mixed $data): DataWrapperContract;
public function paginatorCast(mixed $data): ?PaginatorContract;
}
interface DataCasterContract
{
public function cast(mixed $data): DataWrapperContract;
public function paginatorCast(mixed $data): ?PaginatorContract;
}
interface DataCasterContract
{
public function cast(mixed $data): DataWrapperContract;
public function paginatorCast(mixed $data): ?PaginatorContract;
}
interface DataCasterContract
{
public function cast(mixed $data): DataWrapperContract;
public function paginatorCast(mixed $data): ?PaginatorContract;
}
interface DataCasterContract
{
public function cast(mixed $data): DataWrapperContract;
public function paginatorCast(mixed $data): ?PaginatorContract;
}
Также необходимо реализовать интерфейс DataWrapperContract
.
Данная абстракция помогает определить что именно является ключом объекта и как его привести к массиву.
interface DataWrapperContract
{
public function getOriginal(): mixed;
public function getKey(): int|string|null;
public function toArray(): array;
}
interface DataWrapperContract
{
public function getOriginal(): mixed;
public function getKey(): int|string|null;
public function toArray(): array;
}
interface DataWrapperContract
{
public function getOriginal(): mixed;
public function getKey(): int|string|null;
public function toArray(): array;
}
interface DataWrapperContract
{
public function getOriginal(): mixed;
public function getKey(): int|string|null;
public function toArray(): array;
}
interface DataWrapperContract
{
public function getOriginal(): mixed;
public function getKey(): int|string|null;
public function toArray(): array;
}
Давайте рассмотрим пример TypeCast
для моделей.
final readonly class ModelCaster implements DataCasterContract
{
public function __construct(
private string $class
) {
}
public function getClass(): string
{
return $this->class;
}
public function cast(mixed $data): ModelDataWrapper
{
$model = new ($this->getClass());
return new ModelDataWrapper($model->fill($data));
}
public function paginatorCast(mixed $data): ?PaginatorContract
{
if (! $data instanceof Paginator && ! $data instanceof CursorPaginator) {
return null;
}
$paginator = new PaginatorCaster(
$data->appends(
moonshine()->getRequest()->getExcept('page')
)->toArray(),
$data->items()
);
return $paginator->cast();
}
}
final readonly class ModelCaster implements DataCasterContract
{
public function __construct(
/** @var class-string<T> $class */
private string $class
) {
}
/** @return class-string<T> $class */
public function getClass(): string
{
return $this->class;
}
/**
* @return ModelDataWrapper<T>
*/
public function cast(mixed $data): ModelDataWrapper
{
$model = new ($this->getClass());
return new ModelDataWrapper($model->fill($data));
}
public function paginatorCast(mixed $data): ?PaginatorContract
{
if (! $data instanceof Paginator && ! $data instanceof CursorPaginator) {
return null;
}
$paginator = new PaginatorCaster(
$data->appends(
moonshine()->getRequest()->getExcept('page')
)->toArray(),
$data->items()
);
return $paginator->cast();
}
}
final readonly class ModelCaster implements DataCasterContract
{
public function __construct(
/** @var class-string<T> $class */
private string $class
) {
}
/** @return class-string<T> $class */
public function getClass(): string
{
return $this->class;
}
/**
* @return ModelDataWrapper<T>
*/
public function cast(mixed $data): ModelDataWrapper
{
$model = new ($this->getClass());
return new ModelDataWrapper($model->fill($data));
}
public function paginatorCast(mixed $data): ?PaginatorContract
{
if (! $data instanceof Paginator && ! $data instanceof CursorPaginator) {
return null;
}
$paginator = new PaginatorCaster(
$data->appends(
moonshine()->getRequest()->getExcept('page')
)->toArray(),
$data->items()
);
return $paginator->cast();
}
}
final readonly class ModelCaster implements DataCasterContract
{
public function __construct(
/** @var class-string<T> $class */
private string $class
) {
}
/** @return class-string<T> $class */
public function getClass(): string
{
return $this->class;
}
/**
* @return ModelDataWrapper<T>
*/
public function cast(mixed $data): ModelDataWrapper
{
$model = new ($this->getClass());
return new ModelDataWrapper($model->fill($data));
}
public function paginatorCast(mixed $data): ?PaginatorContract
{
if (! $data instanceof Paginator && ! $data instanceof CursorPaginator) {
return null;
}
$paginator = new PaginatorCaster(
$data->appends(
moonshine()->getRequest()->getExcept('page')
)->toArray(),
$data->items()
);
return $paginator->cast();
}
}
final readonly class ModelCaster implements DataCasterContract
{
public function __construct(
/** @var class-string<T> $class */
private string $class
) {
}
/** @return class-string<T> $class */
public function getClass(): string
{
return $this->class;
}
/**
* @return ModelDataWrapper<T>
*/
public function cast(mixed $data): ModelDataWrapper
{
$model = new ($this->getClass());
return new ModelDataWrapper($model->fill($data));
}
public function paginatorCast(mixed $data): ?PaginatorContract
{
if (! $data instanceof Paginator && ! $data instanceof CursorPaginator) {
return null;
}
$paginator = new PaginatorCaster(
$data->appends(
moonshine()->getRequest()->getExcept('page')
)->toArray(),
$data->items()
);
return $paginator->cast();
}
}
ModelDataWrapper
реализует DataWrapperContract
и за счет методов модели getKey
и toArray
помогает определить ключ и трансформировать объект в массив.
final readonly class ModelDataWrapper implements DataWrapperContract
{
public function __construct(private Model $model)
{
}
public function getOriginal(): Model
{
return $this->model;
}
public function getKey(): int|string|null
{
return $this->model->getKey();
}
public function toArray(): array
{
return $this->model->toArray();
}
}
final readonly class ModelDataWrapper implements DataWrapperContract
{
public function __construct(private Model $model)
{
}
public function getOriginal(): Model
{
return $this->model;
}
public function getKey(): int|string|null
{
return $this->model->getKey();
}
public function toArray(): array
{
return $this->model->toArray();
}
}
final readonly class ModelDataWrapper implements DataWrapperContract
{
public function __construct(private Model $model)
{
}
public function getOriginal(): Model
{
return $this->model;
}
public function getKey(): int|string|null
{
return $this->model->getKey();
}
public function toArray(): array
{
return $this->model->toArray();
}
}
final readonly class ModelDataWrapper implements DataWrapperContract
{
public function __construct(private Model $model)
{
}
public function getOriginal(): Model
{
return $this->model;
}
public function getKey(): int|string|null
{
return $this->model->getKey();
}
public function toArray(): array
{
return $this->model->toArray();
}
}
final readonly class ModelDataWrapper implements DataWrapperContract
{
public function __construct(private Model $model)
{
}
public function getOriginal(): Model
{
return $this->model;
}
public function getKey(): int|string|null
{
return $this->model->getKey();
}
public function toArray(): array
{
return $this->model->toArray();
}
}
Теперь рассмотрим его применение в FormBuilder
/TableBuilder
.
TableBuilder::make(items: User::paginate())
->fields([
Text::make('Email'),
])
->cast(new ModelCaster(User::class))
TableBuilder::make(items: User::paginate())
->fields([
Text::make('Email'),
])
->cast(new ModelCaster(User::class))
TableBuilder::make(items: User::paginate())
->fields([
Text::make('Email'),
])
->cast(new ModelCaster(User::class))
TableBuilder::make(items: User::paginate())
->fields([
Text::make('Email'),
])
->cast(new ModelCaster(User::class))
TableBuilder::make(items: User::paginate())
->fields([
Text::make('Email'),
])
->cast(new ModelCaster(User::class))
FormBuilder::make()
->fields([
Text::make('Email'),
])
->fillCast(User::query()->first(), new ModelCaster(User::class))
FormBuilder::make()
->fields([
Text::make('Email'),
])
->fillCast(User::query()->first(), new ModelCaster(User::class))
FormBuilder::make()
->fields([
Text::make('Email'),
])
->fillCast(User::query()->first(), new ModelCaster(User::class))
FormBuilder::make()
->fields([
Text::make('Email'),
])
->fillCast(User::query()->first(), new ModelCaster(User::class))
FormBuilder::make()
->fields([
Text::make('Email'),
])
->fillCast(User::query()->first(), new ModelCaster(User::class))