[增添]添加了datasource的setting数据库以及默认值
This commit is contained in:
14
vendor/filament/forms/src/Commands/Aliases/MakeFieldCommand.php
vendored
Normal file
14
vendor/filament/forms/src/Commands/Aliases/MakeFieldCommand.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Commands\Aliases;
|
||||
|
||||
use Filament\Forms\Commands;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
#[AsCommand(name: 'forms:field')]
|
||||
class MakeFieldCommand extends Commands\MakeFieldCommand
|
||||
{
|
||||
protected $hidden = true;
|
||||
|
||||
protected $signature = 'forms:field {name} {--F|force}';
|
||||
}
|
||||
14
vendor/filament/forms/src/Commands/Aliases/MakeLayoutComponentCommand.php
vendored
Normal file
14
vendor/filament/forms/src/Commands/Aliases/MakeLayoutComponentCommand.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Commands\Aliases;
|
||||
|
||||
use Filament\Forms\Commands;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
#[AsCommand(name: 'forms:layout')]
|
||||
class MakeLayoutComponentCommand extends Commands\MakeLayoutComponentCommand
|
||||
{
|
||||
protected $hidden = true;
|
||||
|
||||
protected $signature = 'forms:layout {name} {--F|force}';
|
||||
}
|
||||
182
vendor/filament/forms/src/Commands/Concerns/CanGenerateForms.php
vendored
Normal file
182
vendor/filament/forms/src/Commands/Concerns/CanGenerateForms.php
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Commands\Concerns;
|
||||
|
||||
use Filament\Forms;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
trait CanGenerateForms
|
||||
{
|
||||
protected function getResourceFormSchema(string $model): string
|
||||
{
|
||||
$model = $this->getModel($model);
|
||||
|
||||
if (blank($model)) {
|
||||
return '//';
|
||||
}
|
||||
|
||||
$schema = $this->getModelSchema($model);
|
||||
$table = $this->getModelTable($model);
|
||||
|
||||
$components = [];
|
||||
|
||||
foreach ($schema->getColumns($table) as $column) {
|
||||
if ($column['auto_increment']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$columnName = $column['name'];
|
||||
|
||||
if (str($columnName)->is([
|
||||
app($model)->getKeyName(),
|
||||
'created_at',
|
||||
'deleted_at',
|
||||
'updated_at',
|
||||
'*_token',
|
||||
])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$type = $this->parseColumnType($column);
|
||||
|
||||
$componentData = [];
|
||||
|
||||
$componentData['type'] = match (true) {
|
||||
$type['name'] === 'boolean' => Forms\Components\Toggle::class,
|
||||
$type['name'] === 'date' => Forms\Components\DatePicker::class,
|
||||
in_array($type['name'], ['datetime', 'timestamp']) => Forms\Components\DateTimePicker::class,
|
||||
$type['name'] === 'text' => Forms\Components\Textarea::class,
|
||||
$columnName === 'image', str($columnName)->startsWith('image_'), str($columnName)->contains('_image_'), str($columnName)->endsWith('_image') => Forms\Components\FileUpload::class,
|
||||
default => Forms\Components\TextInput::class,
|
||||
};
|
||||
|
||||
if (str($columnName)->endsWith('_id')) {
|
||||
$guessedRelationshipName = $this->guessBelongsToRelationshipName($columnName, $model);
|
||||
|
||||
if (filled($guessedRelationshipName)) {
|
||||
$guessedRelationshipTitleColumnName = $this->guessBelongsToRelationshipTitleColumnName($columnName, app($model)->{$guessedRelationshipName}()->getModel()::class);
|
||||
|
||||
$componentData['type'] = Forms\Components\Select::class;
|
||||
$componentData['relationship'] = [$guessedRelationshipName, $guessedRelationshipTitleColumnName];
|
||||
}
|
||||
}
|
||||
|
||||
if (in_array($columnName, [
|
||||
'id',
|
||||
'sku',
|
||||
'uuid',
|
||||
])) {
|
||||
$componentData['label'] = [Str::upper($columnName)];
|
||||
}
|
||||
|
||||
if ($componentData['type'] === Forms\Components\TextInput::class) {
|
||||
if (str($columnName)->contains(['email'])) {
|
||||
$componentData['email'] = [];
|
||||
}
|
||||
|
||||
if (str($columnName)->contains(['password'])) {
|
||||
$componentData['password'] = [];
|
||||
}
|
||||
|
||||
if (str($columnName)->contains(['phone', 'tel'])) {
|
||||
$componentData['tel'] = [];
|
||||
}
|
||||
}
|
||||
|
||||
if ($componentData['type'] === Forms\Components\FileUpload::class) {
|
||||
$componentData['image'] = [];
|
||||
}
|
||||
|
||||
if (! $column['nullable']) {
|
||||
$componentData['required'] = [];
|
||||
}
|
||||
|
||||
if (in_array($type['name'], [
|
||||
'integer',
|
||||
'decimal',
|
||||
'float',
|
||||
'double',
|
||||
'money',
|
||||
])) {
|
||||
if ($componentData['type'] === Forms\Components\TextInput::class) {
|
||||
$componentData['numeric'] = [];
|
||||
}
|
||||
|
||||
if (filled($column['default'])) {
|
||||
$componentData['default'] = [$this->parseDefaultExpression($column, $model)];
|
||||
}
|
||||
|
||||
if (in_array($columnName, [
|
||||
'cost',
|
||||
'money',
|
||||
'price',
|
||||
]) || $type['name'] === 'money') {
|
||||
$componentData['prefix'] = ['$'];
|
||||
}
|
||||
} elseif (in_array($componentData['type'], [
|
||||
Forms\Components\TextInput::class,
|
||||
Forms\Components\Textarea::class,
|
||||
]) && isset($type['length'])) {
|
||||
$componentData['maxLength'] = [$type['length']];
|
||||
|
||||
if (filled($column['default'])) {
|
||||
$componentData['default'] = [$this->parseDefaultExpression($column, $model)];
|
||||
}
|
||||
}
|
||||
|
||||
if ($componentData['type'] === Forms\Components\Textarea::class) {
|
||||
$componentData['columnSpanFull'] = [];
|
||||
}
|
||||
|
||||
$components[$columnName] = $componentData;
|
||||
}
|
||||
|
||||
$output = count($components) ? '' : '//';
|
||||
|
||||
foreach ($components as $componentName => $componentData) {
|
||||
// Constructor
|
||||
$output .= (string) str($componentData['type'])->after('Filament\\');
|
||||
$output .= '::make(\'';
|
||||
$output .= $componentName;
|
||||
$output .= '\')';
|
||||
|
||||
unset($componentData['type']);
|
||||
|
||||
// Configuration
|
||||
foreach ($componentData as $methodName => $parameters) {
|
||||
$output .= PHP_EOL;
|
||||
$output .= ' ->';
|
||||
$output .= $methodName;
|
||||
$output .= '(';
|
||||
$output .= collect($parameters)
|
||||
->map(function (mixed $parameterValue, int | string $parameterName): string {
|
||||
$parameterValue = match (true) {
|
||||
/** @phpstan-ignore-next-line */
|
||||
is_bool($parameterValue) => $parameterValue ? 'true' : 'false',
|
||||
/** @phpstan-ignore-next-line */
|
||||
is_null($parameterValue) => 'null',
|
||||
is_numeric($parameterValue) => $parameterValue,
|
||||
default => "'{$parameterValue}'",
|
||||
};
|
||||
|
||||
if (is_numeric($parameterName)) {
|
||||
return $parameterValue;
|
||||
}
|
||||
|
||||
return "{$parameterName}: {$parameterValue}";
|
||||
})
|
||||
->implode(', ');
|
||||
$output .= ')';
|
||||
}
|
||||
|
||||
// Termination
|
||||
$output .= ',';
|
||||
|
||||
if (! (array_key_last($components) === $componentName)) {
|
||||
$output .= PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
76
vendor/filament/forms/src/Commands/MakeFieldCommand.php
vendored
Normal file
76
vendor/filament/forms/src/Commands/MakeFieldCommand.php
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Commands;
|
||||
|
||||
use Filament\Support\Commands\Concerns\CanManipulateFiles;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Str;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
use function Laravel\Prompts\text;
|
||||
|
||||
#[AsCommand(name: 'make:form-field')]
|
||||
class MakeFieldCommand extends Command
|
||||
{
|
||||
use CanManipulateFiles;
|
||||
|
||||
protected $description = 'Create a new form field class and view';
|
||||
|
||||
protected $signature = 'make:form-field {name?} {--F|force}';
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$field = (string) str($this->argument('name') ?? text(
|
||||
label: 'What is the field name?',
|
||||
placeholder: 'RangeSlider',
|
||||
required: true,
|
||||
))
|
||||
->trim('/')
|
||||
->trim('\\')
|
||||
->trim(' ')
|
||||
->replace('/', '\\');
|
||||
$fieldClass = (string) str($field)->afterLast('\\');
|
||||
$fieldNamespace = str($field)->contains('\\') ?
|
||||
(string) str($field)->beforeLast('\\') :
|
||||
'';
|
||||
|
||||
$view = str($field)
|
||||
->prepend('forms\\components\\')
|
||||
->explode('\\')
|
||||
->map(static fn ($segment) => Str::kebab($segment))
|
||||
->implode('.');
|
||||
|
||||
$path = app_path(
|
||||
(string) str($field)
|
||||
->prepend('Forms\\Components\\')
|
||||
->replace('\\', '/')
|
||||
->append('.php'),
|
||||
);
|
||||
$viewPath = resource_path(
|
||||
(string) str($view)
|
||||
->replace('.', '/')
|
||||
->prepend('views/')
|
||||
->append('.blade.php'),
|
||||
);
|
||||
|
||||
if (! $this->option('force') && $this->checkForCollision([
|
||||
$path,
|
||||
])) {
|
||||
return static::INVALID;
|
||||
}
|
||||
|
||||
$this->copyStubToApp('Field', $path, [
|
||||
'class' => $fieldClass,
|
||||
'namespace' => 'App\\Forms\\Components' . ($fieldNamespace !== '' ? "\\{$fieldNamespace}" : ''),
|
||||
'view' => $view,
|
||||
]);
|
||||
|
||||
if (! $this->fileExists($viewPath)) {
|
||||
$this->copyStubToApp('FieldView', $viewPath);
|
||||
}
|
||||
|
||||
$this->components->info("Filament form field [{$path}] created successfully.");
|
||||
|
||||
return static::SUCCESS;
|
||||
}
|
||||
}
|
||||
110
vendor/filament/forms/src/Commands/MakeFormCommand.php
vendored
Normal file
110
vendor/filament/forms/src/Commands/MakeFormCommand.php
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Commands;
|
||||
|
||||
use Filament\Forms\Commands\Concerns\CanGenerateForms;
|
||||
use Filament\Support\Commands\Concerns\CanIndentStrings;
|
||||
use Filament\Support\Commands\Concerns\CanManipulateFiles;
|
||||
use Filament\Support\Commands\Concerns\CanReadModelSchemas;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Str;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
use function Laravel\Prompts\select;
|
||||
use function Laravel\Prompts\text;
|
||||
|
||||
#[AsCommand(name: 'make:livewire-form')]
|
||||
class MakeFormCommand extends Command
|
||||
{
|
||||
use CanGenerateForms;
|
||||
use CanIndentStrings;
|
||||
use CanManipulateFiles;
|
||||
use CanReadModelSchemas;
|
||||
|
||||
protected $description = 'Create a new Livewire component containing a Filament form';
|
||||
|
||||
protected $signature = 'make:livewire-form {name?} {model?} {--E|edit} {--G|generate} {--F|force}';
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$component = (string) str($this->argument('name') ?? text(
|
||||
label: 'What is the form name?',
|
||||
placeholder: 'Products/CreateProduct',
|
||||
required: true,
|
||||
))
|
||||
->trim('/')
|
||||
->trim('\\')
|
||||
->trim(' ')
|
||||
->replace('/', '\\');
|
||||
$componentClass = (string) str($component)->afterLast('\\');
|
||||
$componentNamespace = str($component)->contains('\\') ?
|
||||
(string) str($component)->beforeLast('\\') :
|
||||
'';
|
||||
|
||||
$view = str($component)
|
||||
->replace('\\', '/')
|
||||
->prepend('Livewire/')
|
||||
->explode('/')
|
||||
->map(fn ($segment) => Str::lower(Str::kebab($segment)))
|
||||
->implode('.');
|
||||
|
||||
$model = (string) str($this->argument('model') ??
|
||||
text(
|
||||
label: 'What is the model name?',
|
||||
placeholder: 'Product',
|
||||
required: $this->option('edit')
|
||||
))->replace('/', '\\');
|
||||
$modelClass = (string) str($model)->afterLast('\\');
|
||||
|
||||
if ($this->option('edit')) {
|
||||
$isEditForm = true;
|
||||
} elseif (filled($model)) {
|
||||
$isEditForm = select(
|
||||
label: 'Which namespace would you like to create this in?',
|
||||
options: [
|
||||
'Create',
|
||||
'Edit',
|
||||
]
|
||||
) === 'Edit';
|
||||
} else {
|
||||
$isEditForm = false;
|
||||
}
|
||||
|
||||
$path = (string) str($component)
|
||||
->prepend('/')
|
||||
->prepend(app_path('Livewire/'))
|
||||
->replace('\\', '/')
|
||||
->replace('//', '/')
|
||||
->append('.php');
|
||||
|
||||
$viewPath = resource_path(
|
||||
(string) str($view)
|
||||
->replace('.', '/')
|
||||
->prepend('views/')
|
||||
->append('.blade.php'),
|
||||
);
|
||||
|
||||
if (! $this->option('force') && $this->checkForCollision([$path, $viewPath])) {
|
||||
return static::INVALID;
|
||||
}
|
||||
|
||||
$this->copyStubToApp(filled($model) ? ($isEditForm ? 'EditForm' : 'CreateForm') : 'Form', $path, [
|
||||
'class' => $componentClass,
|
||||
'model' => $model,
|
||||
'modelClass' => $modelClass,
|
||||
'namespace' => 'App\\Livewire' . ($componentNamespace !== '' ? "\\{$componentNamespace}" : ''),
|
||||
'schema' => $this->indentString((filled($model) && $this->option('generate')) ? $this->getResourceFormSchema(
|
||||
'App\\Models\\' . $model,
|
||||
) : '//', 4),
|
||||
'view' => $view,
|
||||
]);
|
||||
|
||||
$this->copyStubToApp('FormView', $viewPath, [
|
||||
'submitAction' => filled($model) ? ($isEditForm ? 'save' : 'create') : 'submit',
|
||||
]);
|
||||
|
||||
$this->components->info("Filament form [{$path}] created successfully.");
|
||||
|
||||
return static::SUCCESS;
|
||||
}
|
||||
}
|
||||
76
vendor/filament/forms/src/Commands/MakeLayoutComponentCommand.php
vendored
Normal file
76
vendor/filament/forms/src/Commands/MakeLayoutComponentCommand.php
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Commands;
|
||||
|
||||
use Filament\Support\Commands\Concerns\CanManipulateFiles;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Str;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
use function Laravel\Prompts\text;
|
||||
|
||||
#[AsCommand(name: 'make:form-layout')]
|
||||
class MakeLayoutComponentCommand extends Command
|
||||
{
|
||||
use CanManipulateFiles;
|
||||
|
||||
protected $description = 'Create a new form layout component class and view';
|
||||
|
||||
protected $signature = 'make:form-layout {name?} {--F|force}';
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$component = (string) str($this->argument('name') ?? text(
|
||||
label: 'What is the layout name?',
|
||||
placeholder: 'Wizard',
|
||||
required: true,
|
||||
))
|
||||
->trim('/')
|
||||
->trim('\\')
|
||||
->trim(' ')
|
||||
->replace('/', '\\');
|
||||
$componentClass = (string) str($component)->afterLast('\\');
|
||||
$componentNamespace = str($component)->contains('\\') ?
|
||||
(string) str($component)->beforeLast('\\') :
|
||||
'';
|
||||
|
||||
$view = str($component)
|
||||
->prepend('forms\\components\\')
|
||||
->explode('\\')
|
||||
->map(fn ($segment) => Str::kebab($segment))
|
||||
->implode('.');
|
||||
|
||||
$path = app_path(
|
||||
(string) str($component)
|
||||
->prepend('Forms\\Components\\')
|
||||
->replace('\\', '/')
|
||||
->append('.php'),
|
||||
);
|
||||
$viewPath = resource_path(
|
||||
(string) str($view)
|
||||
->replace('.', '/')
|
||||
->prepend('views/')
|
||||
->append('.blade.php'),
|
||||
);
|
||||
|
||||
if (! $this->option('force') && $this->checkForCollision([
|
||||
$path,
|
||||
])) {
|
||||
return static::INVALID;
|
||||
}
|
||||
|
||||
$this->copyStubToApp('LayoutComponent', $path, [
|
||||
'class' => $componentClass,
|
||||
'namespace' => 'App\\Forms\\Components' . ($componentNamespace !== '' ? "\\{$componentNamespace}" : ''),
|
||||
'view' => $view,
|
||||
]);
|
||||
|
||||
if (! $this->fileExists($viewPath)) {
|
||||
$this->copyStubToApp('LayoutComponentView', $viewPath);
|
||||
}
|
||||
|
||||
$this->components->info("Filament form layout component [{$path}] created successfully.");
|
||||
|
||||
return static::SUCCESS;
|
||||
}
|
||||
}
|
||||
80
vendor/filament/forms/src/ComponentContainer.php
vendored
Normal file
80
vendor/filament/forms/src/ComponentContainer.php
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms;
|
||||
|
||||
use Filament\Forms\Contracts\HasForms;
|
||||
use Filament\Support\Components\ViewComponent;
|
||||
use Filament\Support\Concerns\HasExtraAttributes;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class ComponentContainer extends ViewComponent
|
||||
{
|
||||
use Concerns\BelongsToLivewire;
|
||||
use Concerns\BelongsToModel;
|
||||
use Concerns\BelongsToParentComponent;
|
||||
use Concerns\CanBeDisabled;
|
||||
use Concerns\CanBeHidden;
|
||||
use Concerns\CanBeValidated;
|
||||
use Concerns\Cloneable;
|
||||
use Concerns\HasColumns;
|
||||
use Concerns\HasComponents;
|
||||
use Concerns\HasFieldWrapper;
|
||||
use Concerns\HasInlineLabels;
|
||||
use Concerns\HasOperation;
|
||||
use Concerns\HasState;
|
||||
use Concerns\HasStateBindingModifiers;
|
||||
use Concerns\ListensToEvents;
|
||||
use Concerns\SupportsComponentFileAttachments;
|
||||
use Concerns\SupportsFileUploadFields;
|
||||
use Concerns\SupportsSelectFields;
|
||||
use HasExtraAttributes;
|
||||
|
||||
protected string $view = 'filament-forms::component-container';
|
||||
|
||||
protected string $evaluationIdentifier = 'container';
|
||||
|
||||
protected string $viewIdentifier = 'container';
|
||||
|
||||
final public function __construct(HasForms $livewire)
|
||||
{
|
||||
$this->livewire($livewire);
|
||||
}
|
||||
|
||||
public static function make(HasForms $livewire): static
|
||||
{
|
||||
$static = app(static::class, ['livewire' => $livewire]);
|
||||
$static->configure();
|
||||
|
||||
return $static;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<mixed>
|
||||
*/
|
||||
protected function resolveDefaultClosureDependencyForEvaluationByName(string $parameterName): array
|
||||
{
|
||||
return match ($parameterName) {
|
||||
'livewire' => [$this->getLivewire()],
|
||||
'model' => [$this->getModel()],
|
||||
'record' => [$this->getRecord()],
|
||||
default => parent::resolveDefaultClosureDependencyForEvaluationByName($parameterName),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<mixed>
|
||||
*/
|
||||
protected function resolveDefaultClosureDependencyForEvaluationByType(string $parameterType): array
|
||||
{
|
||||
$record = $this->getRecord();
|
||||
|
||||
if (! $record) {
|
||||
return parent::resolveDefaultClosureDependencyForEvaluationByType($parameterType);
|
||||
}
|
||||
|
||||
return match ($parameterType) {
|
||||
Model::class, $record::class => [$record],
|
||||
default => parent::resolveDefaultClosureDependencyForEvaluationByType($parameterType),
|
||||
};
|
||||
}
|
||||
}
|
||||
62
vendor/filament/forms/src/Components/Actions.php
vendored
Normal file
62
vendor/filament/forms/src/Components/Actions.php
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components;
|
||||
|
||||
use Closure;
|
||||
use Filament\Forms\Components\Actions\Action;
|
||||
use Filament\Support\Concerns\HasAlignment;
|
||||
use Filament\Support\Concerns\HasVerticalAlignment;
|
||||
|
||||
class Actions extends Component
|
||||
{
|
||||
use HasAlignment;
|
||||
use HasVerticalAlignment;
|
||||
|
||||
protected string $view = 'filament-forms::components.actions';
|
||||
|
||||
protected bool | Closure $isFullWidth = false;
|
||||
|
||||
/**
|
||||
* @param array<Action> $actions
|
||||
*/
|
||||
final public function __construct(array $actions)
|
||||
{
|
||||
$this->actions($actions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<Action> $actions
|
||||
*/
|
||||
public static function make(array $actions): static
|
||||
{
|
||||
$static = app(static::class, ['actions' => $actions]);
|
||||
$static->configure();
|
||||
|
||||
return $static;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<Action> $actions
|
||||
*/
|
||||
public function actions(array $actions): static
|
||||
{
|
||||
$this->childComponents(array_map(
|
||||
fn (Action $action): Component => $action->toFormComponent(),
|
||||
$actions,
|
||||
));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function fullWidth(bool | Closure $isFullWidth = true): static
|
||||
{
|
||||
$this->isFullWidth = $isFullWidth;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isFullWidth(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->isFullWidth);
|
||||
}
|
||||
}
|
||||
101
vendor/filament/forms/src/Components/Actions/Action.php
vendored
Normal file
101
vendor/filament/forms/src/Components/Actions/Action.php
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Actions;
|
||||
|
||||
use Exception;
|
||||
use Filament\Actions\Concerns\HasMountableArguments;
|
||||
use Filament\Actions\MountableAction;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Js;
|
||||
|
||||
class Action extends MountableAction
|
||||
{
|
||||
use Concerns\BelongsToComponent;
|
||||
use HasMountableArguments;
|
||||
|
||||
public function getLivewireCallMountedActionName(): string
|
||||
{
|
||||
return 'callMountedFormComponentAction';
|
||||
}
|
||||
|
||||
public function getLivewireClickHandler(): ?string
|
||||
{
|
||||
if (! $this->isLivewireClickHandlerEnabled()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (is_string($this->action)) {
|
||||
return $this->action;
|
||||
}
|
||||
|
||||
if ($event = $this->getLivewireEventClickHandler()) {
|
||||
return $event;
|
||||
}
|
||||
|
||||
$argumentsParameter = '';
|
||||
|
||||
if (count($arguments = $this->getArguments())) {
|
||||
$argumentsParameter .= ', ';
|
||||
$argumentsParameter .= Js::from($arguments);
|
||||
$argumentsParameter .= '';
|
||||
}
|
||||
|
||||
$componentKey = $this->getComponent()->getKey();
|
||||
|
||||
if (blank($componentKey)) {
|
||||
$componentClass = $this->getComponent()::class;
|
||||
|
||||
throw new Exception("The form component [{$componentClass}] must have a [key()] set in order to use actions. This [key()] must be a unique identifier for the component.");
|
||||
}
|
||||
|
||||
return "mountFormComponentAction('{$componentKey}', '{$this->getName()}'{$argumentsParameter})";
|
||||
}
|
||||
|
||||
public function toFormComponent(): ActionContainer
|
||||
{
|
||||
$component = ActionContainer::make($this);
|
||||
|
||||
$this->component($component);
|
||||
|
||||
return $component;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<mixed>
|
||||
*/
|
||||
protected function resolveDefaultClosureDependencyForEvaluationByName(string $parameterName): array
|
||||
{
|
||||
return match ($parameterName) {
|
||||
'component' => [$this->getComponent()],
|
||||
'context', 'operation' => [$this->getComponent()->getContainer()->getOperation()],
|
||||
'get' => [$this->getComponent()->getGetCallback()],
|
||||
'model' => [$this->getComponent()->getModel()],
|
||||
'record' => [$this->getComponent()->getRecord()],
|
||||
'set' => [$this->getComponent()->getSetCallback()],
|
||||
'state' => [$this->getComponent()->getState()],
|
||||
default => parent::resolveDefaultClosureDependencyForEvaluationByName($parameterName),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<mixed>
|
||||
*/
|
||||
protected function resolveDefaultClosureDependencyForEvaluationByType(string $parameterType): array
|
||||
{
|
||||
$record = $this->getComponent()->getRecord();
|
||||
|
||||
if (! $record) {
|
||||
return parent::resolveDefaultClosureDependencyForEvaluationByType($parameterType);
|
||||
}
|
||||
|
||||
return match ($parameterType) {
|
||||
Model::class, $record::class => [$record],
|
||||
default => parent::resolveDefaultClosureDependencyForEvaluationByType($parameterType),
|
||||
};
|
||||
}
|
||||
|
||||
public function getInfolistName(): string
|
||||
{
|
||||
return 'mountedFormComponentActionInfolist';
|
||||
}
|
||||
}
|
||||
36
vendor/filament/forms/src/Components/Actions/ActionContainer.php
vendored
Normal file
36
vendor/filament/forms/src/Components/Actions/ActionContainer.php
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Actions;
|
||||
|
||||
use Filament\Forms\Components\Component;
|
||||
|
||||
class ActionContainer extends Component
|
||||
{
|
||||
protected string $view = 'filament-forms::components.actions.action-container';
|
||||
|
||||
protected Action $action;
|
||||
|
||||
final public function __construct(Action $action)
|
||||
{
|
||||
$this->action = $action;
|
||||
$this->registerActions([$action]);
|
||||
}
|
||||
|
||||
public static function make(Action $action): static
|
||||
{
|
||||
$static = app(static::class, ['action' => $action]);
|
||||
$static->configure();
|
||||
|
||||
return $static;
|
||||
}
|
||||
|
||||
public function getKey(): string
|
||||
{
|
||||
return parent::getKey() ?? "{$this->getStatePath()}.{$this->action->getName()}Action";
|
||||
}
|
||||
|
||||
public function isHidden(): bool
|
||||
{
|
||||
return $this->action->isHidden();
|
||||
}
|
||||
}
|
||||
28
vendor/filament/forms/src/Components/Actions/Concerns/BelongsToComponent.php
vendored
Normal file
28
vendor/filament/forms/src/Components/Actions/Concerns/BelongsToComponent.php
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Actions\Concerns;
|
||||
|
||||
use Filament\Forms\Components\Component;
|
||||
use Filament\Forms\Contracts\HasForms;
|
||||
|
||||
trait BelongsToComponent
|
||||
{
|
||||
protected Component $component;
|
||||
|
||||
public function component(Component $component): static
|
||||
{
|
||||
$this->component = $component;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getComponent(): Component
|
||||
{
|
||||
return $this->component;
|
||||
}
|
||||
|
||||
public function getLivewire(): HasForms
|
||||
{
|
||||
return $this->getComponent()->getLivewire();
|
||||
}
|
||||
}
|
||||
871
vendor/filament/forms/src/Components/BaseFileUpload.php
vendored
Normal file
871
vendor/filament/forms/src/Components/BaseFileUpload.php
vendored
Normal file
@@ -0,0 +1,871 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components;
|
||||
|
||||
use Closure;
|
||||
use Filament\Forms\Get;
|
||||
use Filament\Forms\Set;
|
||||
use Illuminate\Contracts\Filesystem\Filesystem;
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
use Illuminate\Filesystem\FilesystemAdapter;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Support\Str;
|
||||
use League\Flysystem\UnableToCheckFileExistence;
|
||||
use Livewire\Features\SupportFileUploads\TemporaryUploadedFile;
|
||||
use Throwable;
|
||||
|
||||
class BaseFileUpload extends Field implements Contracts\HasNestedRecursiveValidationRules
|
||||
{
|
||||
use Concerns\HasNestedRecursiveValidationRules;
|
||||
use Concerns\HasUploadingMessage;
|
||||
|
||||
/**
|
||||
* @var array<string> | Arrayable | Closure | null
|
||||
*/
|
||||
protected array | Arrayable | Closure | null $acceptedFileTypes = null;
|
||||
|
||||
protected bool | Closure $isDeletable = true;
|
||||
|
||||
protected bool | Closure $isDownloadable = false;
|
||||
|
||||
protected bool | Closure $isOpenable = false;
|
||||
|
||||
protected bool | Closure $isPreviewable = true;
|
||||
|
||||
protected bool | Closure $isReorderable = false;
|
||||
|
||||
protected string | Closure | null $directory = null;
|
||||
|
||||
protected string | Closure | null $diskName = null;
|
||||
|
||||
protected bool | Closure $isMultiple = false;
|
||||
|
||||
protected int | Closure | null $maxSize = null;
|
||||
|
||||
protected int | Closure | null $minSize = null;
|
||||
|
||||
protected int | Closure | null $maxFiles = null;
|
||||
|
||||
protected int | Closure | null $minFiles = null;
|
||||
|
||||
protected bool | Closure $shouldPreserveFilenames = false;
|
||||
|
||||
protected bool | Closure $shouldMoveFiles = false;
|
||||
|
||||
protected bool | Closure $shouldStoreFiles = true;
|
||||
|
||||
protected bool | Closure $shouldFetchFileInformation = true;
|
||||
|
||||
protected string | Closure | null $fileNamesStatePath = null;
|
||||
|
||||
protected string | Closure $visibility = 'public';
|
||||
|
||||
protected ?Closure $deleteUploadedFileUsing = null;
|
||||
|
||||
protected ?Closure $getUploadedFileNameForStorageUsing = null;
|
||||
|
||||
protected ?Closure $getUploadedFileUsing = null;
|
||||
|
||||
protected ?Closure $reorderUploadedFilesUsing = null;
|
||||
|
||||
protected ?Closure $saveUploadedFileUsing = null;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->afterStateHydrated(static function (BaseFileUpload $component, string | array | null $state): void {
|
||||
if (blank($state)) {
|
||||
$component->state([]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$shouldFetchFileInformation = $component->shouldFetchFileInformation();
|
||||
|
||||
$files = collect(Arr::wrap($state))
|
||||
->filter(static function (string $file) use ($component, $shouldFetchFileInformation): bool {
|
||||
if (blank($file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $shouldFetchFileInformation) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
return $component->getDisk()->exists($file);
|
||||
} catch (UnableToCheckFileExistence $exception) {
|
||||
return false;
|
||||
}
|
||||
})
|
||||
->mapWithKeys(static fn (string $file): array => [((string) Str::uuid()) => $file])
|
||||
->all();
|
||||
|
||||
$component->state($files);
|
||||
});
|
||||
|
||||
$this->afterStateUpdated(static function (BaseFileUpload $component, $state) {
|
||||
if ($state instanceof TemporaryUploadedFile) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (blank($state)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_array($state)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$component->state([(string) Str::uuid() => $state]);
|
||||
});
|
||||
|
||||
$this->beforeStateDehydrated(static function (BaseFileUpload $component): void {
|
||||
$component->saveUploadedFiles();
|
||||
});
|
||||
|
||||
$this->dehydrateStateUsing(static function (BaseFileUpload $component, ?array $state): string | array | null | TemporaryUploadedFile {
|
||||
$files = array_values($state ?? []);
|
||||
|
||||
if ($component->isMultiple()) {
|
||||
return $files;
|
||||
}
|
||||
|
||||
return $files[0] ?? null;
|
||||
});
|
||||
|
||||
$this->getUploadedFileUsing(static function (BaseFileUpload $component, string $file, string | array | null $storedFileNames): ?array {
|
||||
/** @var FilesystemAdapter $storage */
|
||||
$storage = $component->getDisk();
|
||||
|
||||
$shouldFetchFileInformation = $component->shouldFetchFileInformation();
|
||||
|
||||
if ($shouldFetchFileInformation) {
|
||||
try {
|
||||
if (! $storage->exists($file)) {
|
||||
return null;
|
||||
}
|
||||
} catch (UnableToCheckFileExistence $exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
$url = null;
|
||||
|
||||
if ($component->getVisibility() === 'private') {
|
||||
try {
|
||||
$url = $storage->temporaryUrl(
|
||||
$file,
|
||||
now()->addMinutes(5),
|
||||
);
|
||||
} catch (Throwable $exception) {
|
||||
// This driver does not support creating temporary URLs.
|
||||
}
|
||||
}
|
||||
|
||||
$url ??= $storage->url($file);
|
||||
|
||||
return [
|
||||
'name' => ($component->isMultiple() ? ($storedFileNames[$file] ?? null) : $storedFileNames) ?? basename($file),
|
||||
'size' => $shouldFetchFileInformation ? $storage->size($file) : 0,
|
||||
'type' => $shouldFetchFileInformation ? $storage->mimeType($file) : null,
|
||||
'url' => $url,
|
||||
];
|
||||
});
|
||||
|
||||
$this->getUploadedFileNameForStorageUsing(static function (BaseFileUpload $component, TemporaryUploadedFile $file) {
|
||||
return $component->shouldPreserveFilenames() ? $file->getClientOriginalName() : (Str::ulid() . '.' . $file->getClientOriginalExtension());
|
||||
});
|
||||
|
||||
$this->saveUploadedFileUsing(static function (BaseFileUpload $component, TemporaryUploadedFile $file): ?string {
|
||||
try {
|
||||
if (! $file->exists()) {
|
||||
return null;
|
||||
}
|
||||
} catch (UnableToCheckFileExistence $exception) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (
|
||||
$component->shouldMoveFiles() &&
|
||||
($component->getDiskName() == (fn (): string => $this->disk)->call($file))
|
||||
) {
|
||||
$newPath = trim($component->getDirectory() . '/' . $component->getUploadedFileNameForStorage($file), '/');
|
||||
|
||||
$component->getDisk()->move((fn (): string => $this->path)->call($file), $newPath);
|
||||
|
||||
return $newPath;
|
||||
}
|
||||
|
||||
$storeMethod = $component->getVisibility() === 'public' ? 'storePubliclyAs' : 'storeAs';
|
||||
|
||||
return $file->{$storeMethod}(
|
||||
$component->getDirectory(),
|
||||
$component->getUploadedFileNameForStorage($file),
|
||||
$component->getDiskName(),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
protected function callAfterStateUpdatedHook(Closure $hook): void
|
||||
{
|
||||
/** @var array<string | TemporaryUploadedFile> $state */
|
||||
$state = $this->getState() ?? [];
|
||||
|
||||
/** @var array<string | TemporaryUploadedFile> $oldState */
|
||||
$oldState = $this->getOldState() ?? [];
|
||||
|
||||
$this->evaluate($hook, [
|
||||
'state' => $this->isMultiple() ? $state : Arr::first($state),
|
||||
'old' => $this->isMultiple() ? $oldState : Arr::first($oldState),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string> | Arrayable | Closure $types
|
||||
*/
|
||||
public function acceptedFileTypes(array | Arrayable | Closure $types): static
|
||||
{
|
||||
$this->acceptedFileTypes = $types;
|
||||
|
||||
$this->rule(static function (BaseFileUpload $component) {
|
||||
$types = implode(',', ($component->getAcceptedFileTypes() ?? []));
|
||||
|
||||
return "mimetypes:{$types}";
|
||||
});
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function deletable(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->isDeletable = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function directory(string | Closure | null $directory): static
|
||||
{
|
||||
$this->directory = $directory;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function disk(string | Closure | null $name): static
|
||||
{
|
||||
$this->diskName = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function downloadable(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->isDownloadable = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function openable(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->isOpenable = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function reorderable(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->isReorderable = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function previewable(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->isPreviewable = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `downloadable()` instead.
|
||||
*/
|
||||
public function enableDownload(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->downloadable($condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `openable()` instead.
|
||||
*/
|
||||
public function enableOpen(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->openable($condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `reorderable()` instead.
|
||||
*/
|
||||
public function enableReordering(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->reorderable($condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `previewable()` instead.
|
||||
*/
|
||||
public function disablePreview(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->previewable(fn (BaseFileUpload $component): bool => ! $component->evaluate($condition));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function storeFileNamesIn(string | Closure | null $statePath): static
|
||||
{
|
||||
$this->fileNamesStatePath = $statePath;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function preserveFilenames(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->shouldPreserveFilenames = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function moveFiles(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->shouldMoveFiles = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `moveFiles()` instead.
|
||||
*/
|
||||
public function moveFile(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->moveFiles($condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function fetchFileInformation(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->shouldFetchFileInformation = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function maxSize(int | Closure | null $size): static
|
||||
{
|
||||
$this->maxSize = $size;
|
||||
|
||||
$this->rule(static function (BaseFileUpload $component): string {
|
||||
$size = $component->getMaxSize();
|
||||
|
||||
return "max:{$size}";
|
||||
});
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function minSize(int | Closure | null $size): static
|
||||
{
|
||||
$this->minSize = $size;
|
||||
|
||||
$this->rule(static function (BaseFileUpload $component): string {
|
||||
$size = $component->getMinSize();
|
||||
|
||||
return "min:{$size}";
|
||||
});
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function maxFiles(int | Closure | null $count): static
|
||||
{
|
||||
$this->maxFiles = $count;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function minFiles(int | Closure | null $count): static
|
||||
{
|
||||
$this->minFiles = $count;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function multiple(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->isMultiple = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function storeFiles(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->shouldStoreFiles = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `storeFiles()` instead.
|
||||
*/
|
||||
public function storeFile(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->storeFiles($condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function visibility(string | Closure | null $visibility): static
|
||||
{
|
||||
$this->visibility = $visibility;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function deleteUploadedFileUsing(?Closure $callback): static
|
||||
{
|
||||
$this->deleteUploadedFileUsing = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUploadedFileUsing(?Closure $callback): static
|
||||
{
|
||||
$this->getUploadedFileUsing = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function reorderUploadedFilesUsing(?Closure $callback): static
|
||||
{
|
||||
$this->reorderUploadedFilesUsing = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function saveUploadedFileUsing(?Closure $callback): static
|
||||
{
|
||||
$this->saveUploadedFileUsing = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isDeletable(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->isDeletable);
|
||||
}
|
||||
|
||||
public function isDownloadable(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->isDownloadable);
|
||||
}
|
||||
|
||||
public function isOpenable(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->isOpenable);
|
||||
}
|
||||
|
||||
public function isPreviewable(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->isPreviewable);
|
||||
}
|
||||
|
||||
public function isReorderable(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->isReorderable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string> | null
|
||||
*/
|
||||
public function getAcceptedFileTypes(): ?array
|
||||
{
|
||||
$types = $this->evaluate($this->acceptedFileTypes);
|
||||
|
||||
if ($types instanceof Arrayable) {
|
||||
$types = $types->toArray();
|
||||
}
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
public function getDirectory(): ?string
|
||||
{
|
||||
return $this->evaluate($this->directory);
|
||||
}
|
||||
|
||||
public function getDisk(): Filesystem
|
||||
{
|
||||
return Storage::disk($this->getDiskName());
|
||||
}
|
||||
|
||||
public function getDiskName(): string
|
||||
{
|
||||
return $this->evaluate($this->diskName) ?? config('filament.default_filesystem_disk');
|
||||
}
|
||||
|
||||
public function getMaxFiles(): ?int
|
||||
{
|
||||
return $this->evaluate($this->maxFiles);
|
||||
}
|
||||
|
||||
public function getMinFiles(): ?int
|
||||
{
|
||||
return $this->evaluate($this->minFiles);
|
||||
}
|
||||
|
||||
public function getMaxSize(): ?int
|
||||
{
|
||||
return $this->evaluate($this->maxSize);
|
||||
}
|
||||
|
||||
public function getMinSize(): ?int
|
||||
{
|
||||
return $this->evaluate($this->minSize);
|
||||
}
|
||||
|
||||
public function getVisibility(): string
|
||||
{
|
||||
return $this->evaluate($this->visibility);
|
||||
}
|
||||
|
||||
public function shouldPreserveFilenames(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->shouldPreserveFilenames);
|
||||
}
|
||||
|
||||
public function shouldMoveFiles(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->shouldMoveFiles);
|
||||
}
|
||||
|
||||
public function shouldFetchFileInformation(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->shouldFetchFileInformation);
|
||||
}
|
||||
|
||||
public function shouldStoreFiles(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->shouldStoreFiles);
|
||||
}
|
||||
|
||||
public function getFileNamesStatePath(): ?string
|
||||
{
|
||||
if (! $this->fileNamesStatePath) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->generateRelativeStatePath($this->fileNamesStatePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<mixed>
|
||||
*/
|
||||
public function getValidationRules(): array
|
||||
{
|
||||
$rules = [
|
||||
$this->getRequiredValidationRule(),
|
||||
'array',
|
||||
];
|
||||
|
||||
if (filled($count = $this->getMaxFiles())) {
|
||||
$rules[] = "max:{$count}";
|
||||
}
|
||||
|
||||
if (filled($count = $this->getMinFiles())) {
|
||||
$rules[] = "min:{$count}";
|
||||
}
|
||||
|
||||
$rules[] = function (string $attribute, array $value, Closure $fail): void {
|
||||
$files = array_filter($value, fn (TemporaryUploadedFile | string $file): bool => $file instanceof TemporaryUploadedFile);
|
||||
|
||||
$name = $this->getName();
|
||||
|
||||
$validationMessages = $this->getValidationMessages();
|
||||
|
||||
$validator = Validator::make(
|
||||
[$name => $files],
|
||||
["{$name}.*" => ['file', ...parent::getValidationRules()]],
|
||||
$validationMessages ? ["{$name}.*" => $validationMessages] : [],
|
||||
["{$name}.*" => $this->getValidationAttribute()],
|
||||
);
|
||||
|
||||
if (! $validator->fails()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fail($validator->errors()->first());
|
||||
};
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
public function deleteUploadedFile(string $fileKey): static
|
||||
{
|
||||
$file = $this->removeUploadedFile($fileKey);
|
||||
|
||||
if (blank($file)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$callback = $this->deleteUploadedFileUsing;
|
||||
|
||||
if (! $callback) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->evaluate($callback, [
|
||||
'file' => $file,
|
||||
]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeUploadedFile(string $fileKey): string | TemporaryUploadedFile | null
|
||||
{
|
||||
$files = $this->getState();
|
||||
$file = $files[$fileKey] ?? null;
|
||||
|
||||
if (! $file) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (is_string($file)) {
|
||||
$this->removeStoredFileName($file);
|
||||
} elseif ($file instanceof TemporaryUploadedFile) {
|
||||
$file->delete();
|
||||
}
|
||||
|
||||
unset($files[$fileKey]);
|
||||
|
||||
$this->state($files);
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
public function removeStoredFileName(string $file): void
|
||||
{
|
||||
$statePath = $this->fileNamesStatePath;
|
||||
|
||||
if (blank($statePath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->evaluate(function (BaseFileUpload $component, Get $get, Set $set) use ($file, $statePath) {
|
||||
if (! $component->isMultiple()) {
|
||||
$set($statePath, null);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$fileNames = $get($statePath) ?? [];
|
||||
|
||||
if (array_key_exists($file, $fileNames)) {
|
||||
unset($fileNames[$file]);
|
||||
}
|
||||
|
||||
$set($statePath, $fileNames);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<array-key> $fileKeys
|
||||
*/
|
||||
public function reorderUploadedFiles(array $fileKeys): void
|
||||
{
|
||||
if (! $this->isReorderable) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fileKeys = array_flip($fileKeys);
|
||||
|
||||
$state = collect($this->getState())
|
||||
->sortBy(static fn ($file, $fileKey) => $fileKeys[$fileKey] ?? null) // $fileKey may not be present in $fileKeys if it was added to the state during the reorder call
|
||||
->all();
|
||||
|
||||
$this->state($state);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<array{name: string, size: int, type: string, url: string} | null> | null
|
||||
*/
|
||||
public function getUploadedFiles(): ?array
|
||||
{
|
||||
$urls = [];
|
||||
|
||||
foreach ($this->getState() ?? [] as $fileKey => $file) {
|
||||
if ($file instanceof TemporaryUploadedFile) {
|
||||
$urls[$fileKey] = null;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$callback = $this->getUploadedFileUsing;
|
||||
|
||||
if (! $callback) {
|
||||
return [$fileKey => null];
|
||||
}
|
||||
|
||||
$urls[$fileKey] = $this->evaluate($callback, [
|
||||
'file' => $file,
|
||||
'storedFileNames' => $this->getStoredFileNames(),
|
||||
]) ?: null;
|
||||
}
|
||||
|
||||
return $urls;
|
||||
}
|
||||
|
||||
public function saveUploadedFiles(): void
|
||||
{
|
||||
if (blank($this->getState())) {
|
||||
$this->state([]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (! $this->shouldStoreFiles()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$state = array_filter(array_map(function (TemporaryUploadedFile | string $file) {
|
||||
if (! $file instanceof TemporaryUploadedFile) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
$callback = $this->saveUploadedFileUsing;
|
||||
|
||||
if (! $callback) {
|
||||
$file->delete();
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
$storedFile = $this->evaluate($callback, [
|
||||
'file' => $file,
|
||||
]);
|
||||
|
||||
if ($storedFile === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->storeFileName($storedFile, $file->getClientOriginalName());
|
||||
|
||||
$file->delete();
|
||||
|
||||
return $storedFile;
|
||||
}, Arr::wrap($this->getState())));
|
||||
|
||||
if ($this->isReorderable && ($callback = $this->reorderUploadedFilesUsing)) {
|
||||
$state = $this->evaluate($callback, [
|
||||
'state' => $state,
|
||||
]);
|
||||
}
|
||||
|
||||
$this->state($state);
|
||||
}
|
||||
|
||||
public function storeFileName(string $file, string $fileName): void
|
||||
{
|
||||
$statePath = $this->fileNamesStatePath;
|
||||
|
||||
if (blank($statePath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->evaluate(function (BaseFileUpload $component, Get $get, Set $set) use ($file, $fileName, $statePath) {
|
||||
if (! $component->isMultiple()) {
|
||||
$set($statePath, $fileName);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$fileNames = $get($statePath) ?? [];
|
||||
$fileNames[$file] = $fileName;
|
||||
|
||||
$set($statePath, $fileNames);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string | array<string, string> | null
|
||||
*/
|
||||
public function getStoredFileNames(): string | array | null
|
||||
{
|
||||
$state = null;
|
||||
$statePath = $this->fileNamesStatePath;
|
||||
|
||||
if (filled($statePath)) {
|
||||
$state = $this->evaluate(fn (Get $get) => $get($statePath));
|
||||
}
|
||||
|
||||
if (blank($state) && $this->isMultiple()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $state;
|
||||
}
|
||||
|
||||
public function isMultiple(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->isMultiple);
|
||||
}
|
||||
|
||||
public function getUploadedFileNameForStorageUsing(?Closure $callback): static
|
||||
{
|
||||
$this->getUploadedFileNameForStorageUsing = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUploadedFileNameForStorage(TemporaryUploadedFile $file): string
|
||||
{
|
||||
return $this->evaluate($this->getUploadedFileNameForStorageUsing, [
|
||||
'file' => $file,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function getStateToDehydrate(): array
|
||||
{
|
||||
$state = parent::getStateToDehydrate();
|
||||
|
||||
if ($fileNamesStatePath = $this->getFileNamesStatePath()) {
|
||||
$state = [
|
||||
...$state,
|
||||
$fileNamesStatePath => $this->getStoredFileNames(),
|
||||
];
|
||||
}
|
||||
|
||||
return $state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, array<mixed>> $rules
|
||||
*/
|
||||
public function dehydrateValidationRules(array &$rules): void
|
||||
{
|
||||
parent::dehydrateValidationRules($rules);
|
||||
|
||||
if ($fileNamesStatePath = $this->getFileNamesStatePath()) {
|
||||
$rules[$fileNamesStatePath] = ['nullable'];
|
||||
}
|
||||
}
|
||||
}
|
||||
10
vendor/filament/forms/src/Components/BelongsToManyCheckboxList.php
vendored
Normal file
10
vendor/filament/forms/src/Components/BelongsToManyCheckboxList.php
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components;
|
||||
|
||||
/**
|
||||
* @deprecated Use `CheckboxList` with the `relationship()` method instead.
|
||||
*/
|
||||
class BelongsToManyCheckboxList extends CheckboxList
|
||||
{
|
||||
}
|
||||
10
vendor/filament/forms/src/Components/BelongsToManyMultiSelect.php
vendored
Normal file
10
vendor/filament/forms/src/Components/BelongsToManyMultiSelect.php
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components;
|
||||
|
||||
/**
|
||||
* @deprecated Use `MultiSelect` with the `relationship()` method instead.
|
||||
*/
|
||||
class BelongsToManyMultiSelect extends MultiSelect
|
||||
{
|
||||
}
|
||||
10
vendor/filament/forms/src/Components/BelongsToSelect.php
vendored
Normal file
10
vendor/filament/forms/src/Components/BelongsToSelect.php
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components;
|
||||
|
||||
/**
|
||||
* @deprecated Use `Select` with the `relationship()` method instead.
|
||||
*/
|
||||
class BelongsToSelect extends Select
|
||||
{
|
||||
}
|
||||
1078
vendor/filament/forms/src/Components/Builder.php
vendored
Normal file
1078
vendor/filament/forms/src/Components/Builder.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
68
vendor/filament/forms/src/Components/Builder/Block.php
vendored
Normal file
68
vendor/filament/forms/src/Components/Builder/Block.php
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Builder;
|
||||
|
||||
use Closure;
|
||||
use Filament\Forms\Components\Component;
|
||||
use Filament\Forms\Components\Concerns;
|
||||
use Illuminate\Contracts\Support\Htmlable;
|
||||
|
||||
class Block extends Component
|
||||
{
|
||||
use Concerns\HasName {
|
||||
getLabel as getDefaultLabel;
|
||||
}
|
||||
use Concerns\HasPreview;
|
||||
|
||||
protected string | Closure | null $icon = null;
|
||||
|
||||
protected int | Closure | null $maxItems = null;
|
||||
|
||||
final public function __construct(string $name)
|
||||
{
|
||||
$this->name($name);
|
||||
}
|
||||
|
||||
public static function make(string $name): static
|
||||
{
|
||||
$static = app(static::class, ['name' => $name]);
|
||||
$static->configure();
|
||||
|
||||
return $static;
|
||||
}
|
||||
|
||||
public function icon(string | Closure | null $icon): static
|
||||
{
|
||||
$this->icon = $icon;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getIcon(): ?string
|
||||
{
|
||||
return $this->evaluate($this->icon);
|
||||
}
|
||||
|
||||
public function maxItems(int | Closure | null $maxItems): static
|
||||
{
|
||||
$this->maxItems = $maxItems;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getMaxItems(): ?int
|
||||
{
|
||||
return $this->evaluate($this->maxItems);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> | null $state
|
||||
*/
|
||||
public function getLabel(?array $state = null, ?string $uuid = null): string | Htmlable
|
||||
{
|
||||
return $this->evaluate(
|
||||
$this->label,
|
||||
['state' => $state, 'uuid' => $uuid],
|
||||
) ?? $this->getDefaultLabel();
|
||||
}
|
||||
}
|
||||
10
vendor/filament/forms/src/Components/Card.php
vendored
Normal file
10
vendor/filament/forms/src/Components/Card.php
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components;
|
||||
|
||||
/**
|
||||
* @deprecated Use `Section` with an empty heading instead.
|
||||
*/
|
||||
class Card extends Section
|
||||
{
|
||||
}
|
||||
29
vendor/filament/forms/src/Components/Checkbox.php
vendored
Normal file
29
vendor/filament/forms/src/Components/Checkbox.php
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components;
|
||||
|
||||
class Checkbox extends Field
|
||||
{
|
||||
use Concerns\CanBeAccepted;
|
||||
use Concerns\CanBeInline;
|
||||
use Concerns\CanFixIndistinctState;
|
||||
use Concerns\HasExtraInputAttributes;
|
||||
|
||||
/**
|
||||
* @var view-string
|
||||
*/
|
||||
protected string $view = 'filament-forms::components.checkbox';
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->default(false);
|
||||
|
||||
$this->afterStateHydrated(static function (Checkbox $component, $state): void {
|
||||
$component->state((bool) $state);
|
||||
});
|
||||
|
||||
$this->rule('boolean');
|
||||
}
|
||||
}
|
||||
308
vendor/filament/forms/src/Components/CheckboxList.php
vendored
Normal file
308
vendor/filament/forms/src/Components/CheckboxList.php
vendored
Normal file
@@ -0,0 +1,308 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components;
|
||||
|
||||
use Closure;
|
||||
use Filament\Forms\Components\Actions\Action;
|
||||
use Filament\Support\Enums\ActionSize;
|
||||
use Filament\Support\Services\RelationshipJoiner;
|
||||
use Illuminate\Contracts\Support\Htmlable;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class CheckboxList extends Field implements Contracts\CanDisableOptions, Contracts\HasNestedRecursiveValidationRules
|
||||
{
|
||||
use Concerns\CanBeSearchable;
|
||||
use Concerns\CanDisableOptions;
|
||||
use Concerns\CanDisableOptionsWhenSelectedInSiblingRepeaterItems;
|
||||
use Concerns\CanFixIndistinctState;
|
||||
use Concerns\CanLimitItemsLength;
|
||||
use Concerns\HasDescriptions;
|
||||
use Concerns\HasExtraInputAttributes;
|
||||
use Concerns\HasGridDirection;
|
||||
use Concerns\HasNestedRecursiveValidationRules;
|
||||
use Concerns\HasOptions;
|
||||
use Concerns\HasPivotData;
|
||||
|
||||
/**
|
||||
* @var view-string
|
||||
*/
|
||||
protected string $view = 'filament-forms::components.checkbox-list';
|
||||
|
||||
protected string | Closure | null $relationshipTitleAttribute = null;
|
||||
|
||||
protected ?Closure $getOptionLabelFromRecordUsing = null;
|
||||
|
||||
protected string | Closure | null $relationship = null;
|
||||
|
||||
protected bool | Closure $isBulkToggleable = false;
|
||||
|
||||
protected ?Closure $modifySelectAllActionUsing = null;
|
||||
|
||||
protected ?Closure $modifyDeselectAllActionUsing = null;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->default([]);
|
||||
|
||||
$this->afterStateHydrated(static function (CheckboxList $component, $state) {
|
||||
if (is_array($state)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$component->state([]);
|
||||
});
|
||||
|
||||
$this->searchDebounce(0);
|
||||
|
||||
$this->registerActions([
|
||||
fn (CheckboxList $component): Action => $component->getSelectAllAction(),
|
||||
fn (CheckboxList $component): Action => $component->getDeselectAllAction(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function getSelectAllAction(): Action
|
||||
{
|
||||
$action = Action::make($this->getSelectAllActionName())
|
||||
->label(__('filament-forms::components.checkbox_list.actions.select_all.label'))
|
||||
->livewireClickHandlerEnabled(false)
|
||||
->link()
|
||||
->size(ActionSize::Small);
|
||||
|
||||
if ($this->modifySelectAllActionUsing) {
|
||||
$action = $this->evaluate($this->modifySelectAllActionUsing, [
|
||||
'action' => $action,
|
||||
]) ?? $action;
|
||||
}
|
||||
|
||||
return $action;
|
||||
}
|
||||
|
||||
public function selectAllAction(?Closure $callback): static
|
||||
{
|
||||
$this->modifySelectAllActionUsing = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSelectAllActionName(): string
|
||||
{
|
||||
return 'selectAll';
|
||||
}
|
||||
|
||||
public function getDeselectAllAction(): Action
|
||||
{
|
||||
$action = Action::make($this->getDeselectAllActionName())
|
||||
->label(__('filament-forms::components.checkbox_list.actions.deselect_all.label'))
|
||||
->livewireClickHandlerEnabled(false)
|
||||
->link()
|
||||
->size(ActionSize::Small);
|
||||
|
||||
if ($this->modifyDeselectAllActionUsing) {
|
||||
$action = $this->evaluate($this->modifyDeselectAllActionUsing, [
|
||||
'action' => $action,
|
||||
]) ?? $action;
|
||||
}
|
||||
|
||||
return $action;
|
||||
}
|
||||
|
||||
public function deselectAllAction(?Closure $callback): static
|
||||
{
|
||||
$this->modifyDeselectAllActionUsing = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDeselectAllActionName(): string
|
||||
{
|
||||
return 'deselectAll';
|
||||
}
|
||||
|
||||
public function relationship(string | Closure | null $name = null, string | Closure | null $titleAttribute = null, ?Closure $modifyQueryUsing = null): static
|
||||
{
|
||||
$this->relationship = $name ?? $this->getName();
|
||||
$this->relationshipTitleAttribute = $titleAttribute;
|
||||
|
||||
$this->options(static function (CheckboxList $component) use ($modifyQueryUsing): array {
|
||||
$relationship = Relation::noConstraints(fn () => $component->getRelationship());
|
||||
|
||||
$relationshipQuery = app(RelationshipJoiner::class)->prepareQueryForNoConstraints($relationship);
|
||||
|
||||
if ($modifyQueryUsing) {
|
||||
$relationshipQuery = $component->evaluate($modifyQueryUsing, [
|
||||
'query' => $relationshipQuery,
|
||||
]) ?? $relationshipQuery;
|
||||
}
|
||||
|
||||
if ($component->hasOptionLabelFromRecordUsingCallback()) {
|
||||
return $relationshipQuery
|
||||
->get()
|
||||
->mapWithKeys(static fn (Model $record) => [
|
||||
$record->{Str::afterLast($relationship->getQualifiedRelatedKeyName(), '.')} => $component->getOptionLabelFromRecord($record),
|
||||
])
|
||||
->toArray();
|
||||
}
|
||||
|
||||
$relationshipTitleAttribute = $component->getRelationshipTitleAttribute();
|
||||
|
||||
if (empty($relationshipQuery->getQuery()->orders)) {
|
||||
$relationshipQuery->orderBy($relationshipQuery->qualifyColumn($relationshipTitleAttribute));
|
||||
}
|
||||
|
||||
if (str_contains($relationshipTitleAttribute, '->')) {
|
||||
if (! str_contains($relationshipTitleAttribute, ' as ')) {
|
||||
$relationshipTitleAttribute .= " as {$relationshipTitleAttribute}";
|
||||
}
|
||||
} else {
|
||||
$relationshipTitleAttribute = $relationshipQuery->qualifyColumn($relationshipTitleAttribute);
|
||||
}
|
||||
|
||||
return $relationshipQuery
|
||||
->pluck($relationshipTitleAttribute, $relationship->getQualifiedRelatedKeyName())
|
||||
->toArray();
|
||||
});
|
||||
|
||||
$this->loadStateFromRelationshipsUsing(static function (CheckboxList $component, ?array $state) use ($modifyQueryUsing): void {
|
||||
$relationship = $component->getRelationship();
|
||||
|
||||
if ($modifyQueryUsing) {
|
||||
$component->evaluate($modifyQueryUsing, [
|
||||
'query' => $relationship->getQuery(),
|
||||
]);
|
||||
}
|
||||
|
||||
/** @var Collection $relatedRecords */
|
||||
$relatedRecords = $relationship->getResults();
|
||||
|
||||
$component->state(
|
||||
// Cast the related keys to a string, otherwise Livewire does not
|
||||
// know how to handle deselection.
|
||||
//
|
||||
// https://github.com/filamentphp/filament/issues/1111
|
||||
$relatedRecords
|
||||
->pluck($relationship->getRelatedKeyName())
|
||||
->map(static fn ($key): string => strval($key))
|
||||
->all(),
|
||||
);
|
||||
});
|
||||
|
||||
$this->saveRelationshipsUsing(static function (CheckboxList $component, ?array $state) use ($modifyQueryUsing) {
|
||||
$relationship = $component->getRelationship();
|
||||
|
||||
if ($modifyQueryUsing) {
|
||||
$component->evaluate($modifyQueryUsing, [
|
||||
'query' => $relationship->getQuery(),
|
||||
]);
|
||||
}
|
||||
|
||||
/** @var Collection $relatedRecords */
|
||||
$relatedRecords = $relationship->getResults();
|
||||
|
||||
$recordsToDetach = array_diff(
|
||||
$relatedRecords
|
||||
->pluck($relationship->getRelatedKeyName())
|
||||
->map(static fn ($key): string => strval($key))
|
||||
->all(),
|
||||
$state ?? [],
|
||||
);
|
||||
|
||||
if (count($recordsToDetach) > 0) {
|
||||
$relationship->detach($recordsToDetach);
|
||||
}
|
||||
|
||||
$pivotData = $component->getPivotData();
|
||||
|
||||
if ($pivotData === []) {
|
||||
$relationship->sync($state ?? [], detaching: false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$relationship->syncWithPivotValues($state ?? [], $pivotData, detaching: false);
|
||||
});
|
||||
|
||||
$this->dehydrated(false);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function bulkToggleable(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->isBulkToggleable = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getOptionLabelFromRecordUsing(?Closure $callback): static
|
||||
{
|
||||
$this->getOptionLabelFromRecordUsing = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hasOptionLabelFromRecordUsingCallback(): bool
|
||||
{
|
||||
return $this->getOptionLabelFromRecordUsing !== null;
|
||||
}
|
||||
|
||||
public function getOptionLabelFromRecord(Model $record): string | Htmlable
|
||||
{
|
||||
return $this->evaluate(
|
||||
$this->getOptionLabelFromRecordUsing,
|
||||
namedInjections: [
|
||||
'record' => $record,
|
||||
],
|
||||
typedInjections: [
|
||||
Model::class => $record,
|
||||
$record::class => $record,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
public function getRelationshipTitleAttribute(): ?string
|
||||
{
|
||||
return $this->evaluate($this->relationshipTitleAttribute);
|
||||
}
|
||||
|
||||
public function getLabel(): string | Htmlable | null
|
||||
{
|
||||
if ($this->label === null && $this->getRelationship()) {
|
||||
$label = (string) str($this->getRelationshipName())
|
||||
->before('.')
|
||||
->kebab()
|
||||
->replace(['-', '_'], ' ')
|
||||
->ucfirst();
|
||||
|
||||
return ($this->shouldTranslateLabel) ? __($label) : $label;
|
||||
}
|
||||
|
||||
return parent::getLabel();
|
||||
}
|
||||
|
||||
public function getRelationship(): ?BelongsToMany
|
||||
{
|
||||
$name = $this->getRelationshipName();
|
||||
|
||||
if (blank($name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->getModelInstance()->{$name}();
|
||||
}
|
||||
|
||||
public function getRelationshipName(): ?string
|
||||
{
|
||||
return $this->evaluate($this->relationship);
|
||||
}
|
||||
|
||||
public function isBulkToggleable(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->isBulkToggleable);
|
||||
}
|
||||
}
|
||||
61
vendor/filament/forms/src/Components/ColorPicker.php
vendored
Normal file
61
vendor/filament/forms/src/Components/ColorPicker.php
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components;
|
||||
|
||||
use Closure;
|
||||
use Filament\Support\Concerns\HasExtraAlpineAttributes;
|
||||
|
||||
class ColorPicker extends Field implements Contracts\HasAffixActions
|
||||
{
|
||||
use Concerns\HasAffixes;
|
||||
use Concerns\HasExtraInputAttributes;
|
||||
use Concerns\HasPlaceholder;
|
||||
use HasExtraAlpineAttributes;
|
||||
|
||||
/**
|
||||
* @var view-string
|
||||
*/
|
||||
protected string $view = 'filament-forms::components.color-picker';
|
||||
|
||||
protected string | Closure $format = 'hex';
|
||||
|
||||
public function format(string | Closure $format): static
|
||||
{
|
||||
$this->format = $format;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hex(): static
|
||||
{
|
||||
$this->format('hex');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hsl(): static
|
||||
{
|
||||
$this->format('hsl');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function rgb(): static
|
||||
{
|
||||
$this->format('rgb');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function rgba(): static
|
||||
{
|
||||
$this->format('rgba');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFormat(): string
|
||||
{
|
||||
return $this->evaluate($this->format);
|
||||
}
|
||||
}
|
||||
73
vendor/filament/forms/src/Components/Component.php
vendored
Normal file
73
vendor/filament/forms/src/Components/Component.php
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components;
|
||||
|
||||
use Filament\Forms\Concerns\HasColumns;
|
||||
use Filament\Forms\Concerns\HasStateBindingModifiers;
|
||||
use Filament\Support\Components\ViewComponent;
|
||||
use Filament\Support\Concerns\CanGrow;
|
||||
use Filament\Support\Concerns\HasExtraAttributes;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Component extends ViewComponent
|
||||
{
|
||||
use CanGrow;
|
||||
use Concerns\BelongsToContainer;
|
||||
use Concerns\BelongsToModel;
|
||||
use Concerns\CanBeConcealed;
|
||||
use Concerns\CanBeDisabled;
|
||||
use Concerns\CanBeHidden;
|
||||
use Concerns\CanBeRepeated;
|
||||
use Concerns\CanSpanColumns;
|
||||
use Concerns\Cloneable;
|
||||
use Concerns\HasActions;
|
||||
use Concerns\HasChildComponents;
|
||||
use Concerns\HasFieldWrapper;
|
||||
use Concerns\HasId;
|
||||
use Concerns\HasInlineLabel;
|
||||
use Concerns\HasKey;
|
||||
use Concerns\HasLabel;
|
||||
use Concerns\HasMaxWidth;
|
||||
use Concerns\HasMeta;
|
||||
use Concerns\HasState;
|
||||
use Concerns\ListensToEvents;
|
||||
use HasColumns;
|
||||
use HasExtraAttributes;
|
||||
use HasStateBindingModifiers;
|
||||
|
||||
protected string $evaluationIdentifier = 'component';
|
||||
|
||||
/**
|
||||
* @return array<mixed>
|
||||
*/
|
||||
protected function resolveDefaultClosureDependencyForEvaluationByName(string $parameterName): array
|
||||
{
|
||||
return match ($parameterName) {
|
||||
'context', 'operation' => [$this->getContainer()->getOperation()],
|
||||
'get' => [$this->getGetCallback()],
|
||||
'livewire' => [$this->getLivewire()],
|
||||
'model' => [$this->getModel()],
|
||||
'record' => [$this->getRecord()],
|
||||
'set' => [$this->getSetCallback()],
|
||||
'state' => [$this->getState()],
|
||||
default => parent::resolveDefaultClosureDependencyForEvaluationByName($parameterName),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<mixed>
|
||||
*/
|
||||
protected function resolveDefaultClosureDependencyForEvaluationByType(string $parameterType): array
|
||||
{
|
||||
$record = $this->getRecord();
|
||||
|
||||
if (! $record) {
|
||||
return parent::resolveDefaultClosureDependencyForEvaluationByType($parameterType);
|
||||
}
|
||||
|
||||
return match ($parameterType) {
|
||||
Model::class, $record::class => [$record],
|
||||
default => parent::resolveDefaultClosureDependencyForEvaluationByType($parameterType),
|
||||
};
|
||||
}
|
||||
}
|
||||
28
vendor/filament/forms/src/Components/Concerns/BelongsToContainer.php
vendored
Normal file
28
vendor/filament/forms/src/Components/Concerns/BelongsToContainer.php
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Filament\Forms\ComponentContainer;
|
||||
use Filament\Forms\Contracts\HasForms;
|
||||
|
||||
trait BelongsToContainer
|
||||
{
|
||||
protected ComponentContainer $container;
|
||||
|
||||
public function container(ComponentContainer $container): static
|
||||
{
|
||||
$this->container = $container;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getContainer(): ComponentContainer
|
||||
{
|
||||
return $this->container;
|
||||
}
|
||||
|
||||
public function getLivewire(): HasForms
|
||||
{
|
||||
return $this->getContainer()->getLivewire();
|
||||
}
|
||||
}
|
||||
189
vendor/filament/forms/src/Components/Concerns/BelongsToModel.php
vendored
Normal file
189
vendor/filament/forms/src/Components/Concerns/BelongsToModel.php
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
trait BelongsToModel
|
||||
{
|
||||
protected Model | string | Closure | null $model = null;
|
||||
|
||||
protected ?Closure $loadStateFromRelationshipsUsing = null;
|
||||
|
||||
protected ?Closure $saveRelationshipsUsing = null;
|
||||
|
||||
protected ?Closure $saveRelationshipsBeforeChildrenUsing = null;
|
||||
|
||||
protected bool | Closure $shouldSaveRelationshipsWhenDisabled = false;
|
||||
|
||||
protected bool | Closure $shouldSaveRelationshipsWhenHidden = false;
|
||||
|
||||
public function model(Model | string | Closure | null $model = null): static
|
||||
{
|
||||
$this->model = $model;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function saveRelationships(): void
|
||||
{
|
||||
$callback = $this->saveRelationshipsUsing;
|
||||
|
||||
if (! $callback) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! ($this->getRecord()?->exists)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((! $this->shouldSaveRelationshipsWhenDisabled()) && $this->isDisabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((! $this->shouldSaveRelationshipsWhenHidden()) && $this->isHidden()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->evaluate($callback);
|
||||
}
|
||||
|
||||
public function saveRelationshipsBeforeChildren(): void
|
||||
{
|
||||
$callback = $this->saveRelationshipsBeforeChildrenUsing;
|
||||
|
||||
if (! $callback) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! ($this->getRecord()?->exists)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((! $this->shouldSaveRelationshipsWhenDisabled()) && $this->isDisabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((! $this->shouldSaveRelationshipsWhenHidden()) && $this->isHidden()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->evaluate($callback);
|
||||
}
|
||||
|
||||
public function loadStateFromRelationships(bool $andHydrate = false): void
|
||||
{
|
||||
$callback = $this->loadStateFromRelationshipsUsing;
|
||||
|
||||
if (! $callback) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! $this->getRecord()?->exists) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->evaluate($callback);
|
||||
|
||||
if ($andHydrate) {
|
||||
$this->callAfterStateHydrated();
|
||||
|
||||
foreach ($this->getChildComponentContainers() as $container) {
|
||||
$container->callAfterStateHydrated();
|
||||
}
|
||||
|
||||
$this->fillStateWithNull();
|
||||
}
|
||||
}
|
||||
|
||||
public function saveRelationshipsUsing(?Closure $callback): static
|
||||
{
|
||||
$this->saveRelationshipsUsing = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function saveRelationshipsBeforeChildrenUsing(?Closure $callback): static
|
||||
{
|
||||
$this->saveRelationshipsBeforeChildrenUsing = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function saveRelationshipsWhenDisabled(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->shouldSaveRelationshipsWhenDisabled = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function shouldSaveRelationshipsWhenDisabled(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->shouldSaveRelationshipsWhenDisabled);
|
||||
}
|
||||
|
||||
public function saveRelationshipsWhenHidden(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->shouldSaveRelationshipsWhenHidden = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function shouldSaveRelationshipsWhenHidden(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->shouldSaveRelationshipsWhenHidden);
|
||||
}
|
||||
|
||||
public function loadStateFromRelationshipsUsing(?Closure $callback): static
|
||||
{
|
||||
$this->loadStateFromRelationshipsUsing = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getModel(): ?string
|
||||
{
|
||||
$model = $this->evaluate($this->model);
|
||||
|
||||
if ($model instanceof Model) {
|
||||
return $model::class;
|
||||
}
|
||||
|
||||
if (filled($model)) {
|
||||
return $model;
|
||||
}
|
||||
|
||||
return $this->getContainer()->getModel();
|
||||
}
|
||||
|
||||
public function getRecord(): ?Model
|
||||
{
|
||||
$model = $this->evaluate($this->model);
|
||||
|
||||
if ($model instanceof Model) {
|
||||
return $model;
|
||||
}
|
||||
|
||||
if (is_string($model)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->getContainer()->getRecord();
|
||||
}
|
||||
|
||||
public function getModelInstance(): ?Model
|
||||
{
|
||||
$model = $this->evaluate($this->model);
|
||||
|
||||
if ($model === null) {
|
||||
return $this->getContainer()->getModelInstance();
|
||||
}
|
||||
|
||||
if ($model instanceof Model) {
|
||||
return $model;
|
||||
}
|
||||
|
||||
return app($model);
|
||||
}
|
||||
}
|
||||
22
vendor/filament/forms/src/Components/Concerns/CanAllowHtml.php
vendored
Normal file
22
vendor/filament/forms/src/Components/Concerns/CanAllowHtml.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait CanAllowHtml
|
||||
{
|
||||
protected bool | Closure $isHtmlAllowed = false;
|
||||
|
||||
public function allowHtml(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->isHtmlAllowed = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isHtmlAllowed(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->isHtmlAllowed);
|
||||
}
|
||||
}
|
||||
22
vendor/filament/forms/src/Components/Concerns/CanBeAccepted.php
vendored
Normal file
22
vendor/filament/forms/src/Components/Concerns/CanBeAccepted.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait CanBeAccepted
|
||||
{
|
||||
public function accepted(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->rule('accepted', $condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function declined(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->rule('declined', $condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
39
vendor/filament/forms/src/Components/Concerns/CanBeAutocapitalized.php
vendored
Normal file
39
vendor/filament/forms/src/Components/Concerns/CanBeAutocapitalized.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Filament\Forms\Components\Field;
|
||||
|
||||
trait CanBeAutocapitalized
|
||||
{
|
||||
protected bool | string | Closure | null $autocapitalize = null;
|
||||
|
||||
public function autocapitalize(bool | string | Closure | null $autocapitalize = true): static
|
||||
{
|
||||
$this->autocapitalize = $autocapitalize;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `autocapitalize()` instead.
|
||||
*/
|
||||
public function disableAutocapitalize(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->autocapitalize(static function (Field $component) use ($condition): ?bool {
|
||||
return $component->evaluate($condition) ? false : null;
|
||||
});
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAutocapitalize(): ?string
|
||||
{
|
||||
return match ($autocapitalize = $this->evaluate($this->autocapitalize)) {
|
||||
true => 'on',
|
||||
false => 'off',
|
||||
default => $autocapitalize,
|
||||
};
|
||||
}
|
||||
}
|
||||
39
vendor/filament/forms/src/Components/Concerns/CanBeAutocompleted.php
vendored
Normal file
39
vendor/filament/forms/src/Components/Concerns/CanBeAutocompleted.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Filament\Forms\Components\Field;
|
||||
|
||||
trait CanBeAutocompleted
|
||||
{
|
||||
protected bool | string | Closure | null $autocomplete = null;
|
||||
|
||||
public function autocomplete(bool | string | Closure | null $autocomplete = true): static
|
||||
{
|
||||
$this->autocomplete = $autocomplete;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `autocomplete()` instead.
|
||||
*/
|
||||
public function disableAutocomplete(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->autocomplete(static function (Field $component) use ($condition): ?bool {
|
||||
return $component->evaluate($condition) ? false : null;
|
||||
});
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAutocomplete(): ?string
|
||||
{
|
||||
return match ($autocomplete = $this->evaluate($this->autocomplete)) {
|
||||
true => 'on',
|
||||
false => 'off',
|
||||
default => $autocomplete,
|
||||
};
|
||||
}
|
||||
}
|
||||
22
vendor/filament/forms/src/Components/Concerns/CanBeAutofocused.php
vendored
Normal file
22
vendor/filament/forms/src/Components/Concerns/CanBeAutofocused.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait CanBeAutofocused
|
||||
{
|
||||
protected bool | Closure $isAutofocused = false;
|
||||
|
||||
public function autofocus(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->isAutofocused = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isAutofocused(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->isAutofocused);
|
||||
}
|
||||
}
|
||||
26
vendor/filament/forms/src/Components/Concerns/CanBeCloned.php
vendored
Normal file
26
vendor/filament/forms/src/Components/Concerns/CanBeCloned.php
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait CanBeCloned
|
||||
{
|
||||
protected bool | Closure $isCloneable = false;
|
||||
|
||||
public function cloneable(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->isCloneable = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isCloneable(): bool
|
||||
{
|
||||
if ($this->isDisabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) $this->evaluate($this->isCloneable);
|
||||
}
|
||||
}
|
||||
55
vendor/filament/forms/src/Components/Concerns/CanBeCollapsed.php
vendored
Normal file
55
vendor/filament/forms/src/Components/Concerns/CanBeCollapsed.php
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Filament\Forms\ComponentContainer;
|
||||
|
||||
trait CanBeCollapsed
|
||||
{
|
||||
protected bool | Closure $isCollapsed = false;
|
||||
|
||||
protected bool | Closure | null $isCollapsible = null;
|
||||
|
||||
protected bool | Closure $shouldPersistCollapsed = false;
|
||||
|
||||
public function collapsed(bool | Closure $condition = true, bool $shouldMakeComponentCollapsible = true): static
|
||||
{
|
||||
$this->isCollapsed = $condition;
|
||||
|
||||
if ($shouldMakeComponentCollapsible && ($this->isCollapsible === null)) {
|
||||
$this->collapsible();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isCollapsed(?ComponentContainer $item = null): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->isCollapsed, ['item' => $item]);
|
||||
}
|
||||
|
||||
public function collapsible(bool | Closure | null $condition = true): static
|
||||
{
|
||||
$this->isCollapsible = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isCollapsible(): bool
|
||||
{
|
||||
return (bool) ($this->evaluate($this->isCollapsible) ?? false);
|
||||
}
|
||||
|
||||
public function persistCollapsed(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->shouldPersistCollapsed = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function shouldPersistCollapsed(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->shouldPersistCollapsed);
|
||||
}
|
||||
}
|
||||
22
vendor/filament/forms/src/Components/Concerns/CanBeCompacted.php
vendored
Normal file
22
vendor/filament/forms/src/Components/Concerns/CanBeCompacted.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait CanBeCompacted
|
||||
{
|
||||
protected bool | Closure $isCompact = false;
|
||||
|
||||
public function compact(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->isCompact = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isCompact(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->isCompact);
|
||||
}
|
||||
}
|
||||
35
vendor/filament/forms/src/Components/Concerns/CanBeConcealed.php
vendored
Normal file
35
vendor/filament/forms/src/Components/Concerns/CanBeConcealed.php
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Filament\Forms\Components\Component;
|
||||
use Filament\Forms\Components\Contracts\CanConcealComponents;
|
||||
|
||||
trait CanBeConcealed
|
||||
{
|
||||
protected Component | bool | null $cachedConcealingComponent = null;
|
||||
|
||||
public function getConcealingComponent(): ?Component
|
||||
{
|
||||
if (filled($this->cachedConcealingComponent)) {
|
||||
return $this->cachedConcealingComponent ?: null;
|
||||
}
|
||||
|
||||
$parentComponent = $this->getContainer()->getParentComponent();
|
||||
|
||||
if (! $parentComponent) {
|
||||
$this->cachedConcealingComponent = false;
|
||||
} elseif ($parentComponent instanceof CanConcealComponents && $parentComponent->canConcealComponents()) {
|
||||
$this->cachedConcealingComponent = $parentComponent;
|
||||
} else {
|
||||
$this->cachedConcealingComponent = $parentComponent->getConcealingComponent();
|
||||
}
|
||||
|
||||
return $this->cachedConcealingComponent ?: null;
|
||||
}
|
||||
|
||||
public function isConcealed(): bool
|
||||
{
|
||||
return (bool) $this->getConcealingComponent();
|
||||
}
|
||||
}
|
||||
49
vendor/filament/forms/src/Components/Concerns/CanBeDisabled.php
vendored
Normal file
49
vendor/filament/forms/src/Components/Concerns/CanBeDisabled.php
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Filament\Forms\Components\Component;
|
||||
use Filament\Forms\Contracts\HasForms;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
trait CanBeDisabled
|
||||
{
|
||||
protected bool | Closure $isDisabled = false;
|
||||
|
||||
public function disabled(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->isDisabled = $condition;
|
||||
$this->dehydrated(fn (Component $component): bool => ! $component->evaluate($condition));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string | array<string> $operations
|
||||
*/
|
||||
public function disabledOn(string | array $operations): static
|
||||
{
|
||||
$this->disabled(static function (HasForms $livewire, string $operation) use ($operations): bool {
|
||||
foreach (Arr::wrap($operations) as $disabledOperation) {
|
||||
if ($disabledOperation === $operation || $livewire instanceof $disabledOperation) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isDisabled(): bool
|
||||
{
|
||||
return $this->evaluate($this->isDisabled) || $this->getContainer()->isDisabled();
|
||||
}
|
||||
|
||||
public function isEnabled(): bool
|
||||
{
|
||||
return ! $this->isDisabled();
|
||||
}
|
||||
}
|
||||
135
vendor/filament/forms/src/Components/Concerns/CanBeHidden.php
vendored
Normal file
135
vendor/filament/forms/src/Components/Concerns/CanBeHidden.php
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Filament\Forms\Components\Component;
|
||||
use Filament\Forms\Contracts\HasForms;
|
||||
use Filament\Forms\Get;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
trait CanBeHidden
|
||||
{
|
||||
protected bool | Closure $isHidden = false;
|
||||
|
||||
protected bool | Closure $isVisible = true;
|
||||
|
||||
public function hidden(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->isHidden = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string | array<string> $operations
|
||||
*/
|
||||
public function hiddenOn(string | array $operations): static
|
||||
{
|
||||
$this->hidden(static function (HasForms $livewire, string $operation) use ($operations): bool {
|
||||
foreach (Arr::wrap($operations) as $hiddenOperation) {
|
||||
if ($hiddenOperation === $operation || $livewire instanceof $hiddenOperation) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hiddenWhenAllChildComponentsHidden(): static
|
||||
{
|
||||
$this->hidden(static function (Component $component): bool {
|
||||
foreach ($component->getChildComponentContainers() as $childComponentContainer) {
|
||||
foreach ($childComponentContainer->getComponents(withHidden: false) as $childComponent) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string | array<string> $paths
|
||||
*/
|
||||
public function whenTruthy(string | array $paths): static
|
||||
{
|
||||
$paths = Arr::wrap($paths);
|
||||
|
||||
$this->hidden(static function (Get $get) use ($paths): bool {
|
||||
foreach ($paths as $path) {
|
||||
if (! $get($path)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string | array<string> $paths
|
||||
*/
|
||||
public function whenFalsy(string | array $paths): static
|
||||
{
|
||||
$paths = Arr::wrap($paths);
|
||||
|
||||
$this->hidden(static function (Get $get) use ($paths): bool {
|
||||
foreach ($paths as $path) {
|
||||
if ((bool) $get($path)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function visible(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->isVisible = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string | array<string> $operations
|
||||
*/
|
||||
public function visibleOn(string | array $operations): static
|
||||
{
|
||||
$this->visible(static function (string $operation, HasForms $livewire) use ($operations): bool {
|
||||
foreach (Arr::wrap($operations) as $visibleOperation) {
|
||||
if ($visibleOperation === $operation || $livewire instanceof $visibleOperation) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isHidden(): bool
|
||||
{
|
||||
if ($this->evaluate($this->isHidden)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return ! $this->evaluate($this->isVisible);
|
||||
}
|
||||
|
||||
public function isVisible(): bool
|
||||
{
|
||||
return ! $this->isHidden();
|
||||
}
|
||||
}
|
||||
26
vendor/filament/forms/src/Components/Concerns/CanBeInline.php
vendored
Normal file
26
vendor/filament/forms/src/Components/Concerns/CanBeInline.php
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait CanBeInline
|
||||
{
|
||||
protected bool | Closure $isInline = true;
|
||||
|
||||
public function inline(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->isInline = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isInline(): bool
|
||||
{
|
||||
if ($this->hasInlineLabel()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) $this->evaluate($this->isInline);
|
||||
}
|
||||
}
|
||||
83
vendor/filament/forms/src/Components/Concerns/CanBeLengthConstrained.php
vendored
Normal file
83
vendor/filament/forms/src/Components/Concerns/CanBeLengthConstrained.php
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Filament\Forms\Components\Contracts\CanHaveNumericState;
|
||||
|
||||
trait CanBeLengthConstrained
|
||||
{
|
||||
protected int | Closure | null $length = null;
|
||||
|
||||
protected int | Closure | null $maxLength = null;
|
||||
|
||||
protected int | Closure | null $minLength = null;
|
||||
|
||||
public function length(int | Closure | null $length): static
|
||||
{
|
||||
$this->length = $length;
|
||||
$this->maxLength = $length;
|
||||
$this->minLength = $length;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function maxLength(int | Closure | null $length): static
|
||||
{
|
||||
$this->maxLength = $length;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function minLength(int | Closure | null $length): static
|
||||
{
|
||||
$this->minLength = $length;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLength(): ?int
|
||||
{
|
||||
return $this->evaluate($this->length);
|
||||
}
|
||||
|
||||
public function getMaxLength(): ?int
|
||||
{
|
||||
return $this->evaluate($this->maxLength);
|
||||
}
|
||||
|
||||
public function getMinLength(): ?int
|
||||
{
|
||||
return $this->evaluate($this->minLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string>
|
||||
*/
|
||||
public function getLengthValidationRules(): array
|
||||
{
|
||||
$isNumeric = $this instanceof CanHaveNumericState && $this->isNumeric();
|
||||
|
||||
if (filled($length = $this->getLength())) {
|
||||
return $isNumeric ?
|
||||
["digits:{$length}"] :
|
||||
["size:{$length}"];
|
||||
}
|
||||
|
||||
$rules = [];
|
||||
|
||||
if (filled($maxLength = $this->getMaxLength())) {
|
||||
$rules[] = $isNumeric ?
|
||||
"max_digits:{$maxLength}" :
|
||||
"max:{$maxLength}";
|
||||
}
|
||||
|
||||
if (filled($minLength = $this->getMinLength())) {
|
||||
$rules[] = $isNumeric ?
|
||||
"min_digits:{$minLength}" :
|
||||
"min:{$minLength}";
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
||||
22
vendor/filament/forms/src/Components/Concerns/CanBeMarkedAsRequired.php
vendored
Normal file
22
vendor/filament/forms/src/Components/Concerns/CanBeMarkedAsRequired.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait CanBeMarkedAsRequired
|
||||
{
|
||||
protected bool | Closure | null $isMarkedAsRequired = null;
|
||||
|
||||
public function markAsRequired(bool | Closure | null $condition = true): static
|
||||
{
|
||||
$this->isMarkedAsRequired = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isMarkedAsRequired(): bool
|
||||
{
|
||||
return $this->evaluate($this->isMarkedAsRequired) ?? $this->isRequired();
|
||||
}
|
||||
}
|
||||
22
vendor/filament/forms/src/Components/Concerns/CanBeNative.php
vendored
Normal file
22
vendor/filament/forms/src/Components/Concerns/CanBeNative.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait CanBeNative
|
||||
{
|
||||
protected bool | Closure $isNative = true;
|
||||
|
||||
public function native(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->isNative = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isNative(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->isNative);
|
||||
}
|
||||
}
|
||||
22
vendor/filament/forms/src/Components/Concerns/CanBePreloaded.php
vendored
Normal file
22
vendor/filament/forms/src/Components/Concerns/CanBePreloaded.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait CanBePreloaded
|
||||
{
|
||||
protected bool | Closure $isPreloaded = false;
|
||||
|
||||
public function preload(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->isPreloaded = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isPreloaded(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->isPreloaded);
|
||||
}
|
||||
}
|
||||
42
vendor/filament/forms/src/Components/Concerns/CanBeReadOnly.php
vendored
Normal file
42
vendor/filament/forms/src/Components/Concerns/CanBeReadOnly.php
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Filament\Forms\Contracts\HasForms;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
trait CanBeReadOnly
|
||||
{
|
||||
protected bool | Closure $isReadOnly = false;
|
||||
|
||||
public function readOnly(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->isReadOnly = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string | array<string> $operations
|
||||
*/
|
||||
public function readOnlyOn(string | array $operations): static
|
||||
{
|
||||
$this->readOnly(static function (HasForms $livewire, string $operation) use ($operations): bool {
|
||||
foreach (Arr::wrap($operations) as $readOnlyOperation) {
|
||||
if ($readOnlyOperation === $operation || $livewire instanceof $readOnlyOperation) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isReadOnly(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->isReadOnly);
|
||||
}
|
||||
}
|
||||
29
vendor/filament/forms/src/Components/Concerns/CanBeRepeated.php
vendored
Normal file
29
vendor/filament/forms/src/Components/Concerns/CanBeRepeated.php
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Filament\Forms\Components\Repeater;
|
||||
|
||||
trait CanBeRepeated
|
||||
{
|
||||
protected Repeater | bool | null $cachedParentRepeater = null;
|
||||
|
||||
public function getParentRepeater(): ?Repeater
|
||||
{
|
||||
if (filled($this->cachedParentRepeater)) {
|
||||
return $this->cachedParentRepeater ?: null;
|
||||
}
|
||||
|
||||
$parentComponent = $this->getContainer()->getParentComponent();
|
||||
|
||||
if (! $parentComponent) {
|
||||
$this->cachedParentRepeater = false;
|
||||
} elseif ($parentComponent instanceof Repeater) {
|
||||
$this->cachedParentRepeater = $parentComponent;
|
||||
} else {
|
||||
$this->cachedParentRepeater = $parentComponent->getParentRepeater();
|
||||
}
|
||||
|
||||
return $this->cachedParentRepeater ?: null;
|
||||
}
|
||||
}
|
||||
118
vendor/filament/forms/src/Components/Concerns/CanBeSearchable.php
vendored
Normal file
118
vendor/filament/forms/src/Components/Concerns/CanBeSearchable.php
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Support\Htmlable;
|
||||
|
||||
trait CanBeSearchable
|
||||
{
|
||||
protected bool | Closure $isSearchable = false;
|
||||
|
||||
protected string | Htmlable | Closure | null $noSearchResultsMessage = null;
|
||||
|
||||
protected int | Closure $searchDebounce = 1000;
|
||||
|
||||
protected string | Closure | null $searchingMessage = null;
|
||||
|
||||
protected string | Htmlable | Closure | null $searchPrompt = null;
|
||||
|
||||
protected bool | Closure $shouldSearchLabels = true;
|
||||
|
||||
protected bool | Closure $shouldSearchValues = false;
|
||||
|
||||
public function searchable(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->isSearchable = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function noSearchResultsMessage(string | Htmlable | Closure | null $message): static
|
||||
{
|
||||
$this->noSearchResultsMessage = $message;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function searchDebounce(int | Closure $debounce): static
|
||||
{
|
||||
$this->searchDebounce = $debounce;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function searchingMessage(string | Closure | null $message): static
|
||||
{
|
||||
$this->searchingMessage = $message;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function searchPrompt(string | Htmlable | Closure | null $message): static
|
||||
{
|
||||
$this->searchPrompt = $message;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function searchLabels(bool | Closure | null $condition = true): static
|
||||
{
|
||||
$this->shouldSearchLabels = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function searchValues(bool | Closure | null $condition = true): static
|
||||
{
|
||||
$this->shouldSearchValues = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getNoSearchResultsMessage(): string | Htmlable
|
||||
{
|
||||
return $this->evaluate($this->noSearchResultsMessage) ?? __('filament-forms::components.select.no_search_results_message');
|
||||
}
|
||||
|
||||
public function getSearchPrompt(): string | Htmlable
|
||||
{
|
||||
return $this->evaluate($this->searchPrompt) ?? __('filament-forms::components.select.search_prompt');
|
||||
}
|
||||
|
||||
public function shouldSearchLabels(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->shouldSearchLabels);
|
||||
}
|
||||
|
||||
public function shouldSearchValues(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->shouldSearchValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string>
|
||||
*/
|
||||
public function getSearchableOptionFields(): array
|
||||
{
|
||||
return [
|
||||
...($this->shouldSearchLabels() ? ['label'] : []),
|
||||
...($this->shouldSearchValues() ? ['value'] : []),
|
||||
];
|
||||
}
|
||||
|
||||
public function getSearchDebounce(): int
|
||||
{
|
||||
return $this->evaluate($this->searchDebounce);
|
||||
}
|
||||
|
||||
public function getSearchingMessage(): string
|
||||
{
|
||||
return $this->evaluate($this->searchingMessage) ?? __('filament-forms::components.select.searching_message');
|
||||
}
|
||||
|
||||
public function isSearchable(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->isSearchable);
|
||||
}
|
||||
}
|
||||
853
vendor/filament/forms/src/Components/Concerns/CanBeValidated.php
vendored
Normal file
853
vendor/filament/forms/src/Components/Concerns/CanBeValidated.php
vendored
Normal file
@@ -0,0 +1,853 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Filament\Forms\Components\Contracts\CanBeLengthConstrained;
|
||||
use Filament\Forms\Components\Contracts\HasNestedRecursiveValidationRules;
|
||||
use Filament\Forms\Components\Field;
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
use Illuminate\Validation\Rules\Unique;
|
||||
|
||||
trait CanBeValidated
|
||||
{
|
||||
protected bool | Closure $isRequired = false;
|
||||
|
||||
protected string | Closure | null $regexPattern = null;
|
||||
|
||||
/**
|
||||
* @var array<mixed>
|
||||
*/
|
||||
protected array $rules = [];
|
||||
|
||||
/**
|
||||
* @var array<string, string | Closure>
|
||||
*/
|
||||
protected array $validationMessages = [];
|
||||
|
||||
protected string | Closure | null $validationAttribute = null;
|
||||
|
||||
public function activeUrl(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->rule('active_url', $condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function alpha(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->rule('alpha', $condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function alphaDash(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->rule('alpha_dash', $condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function alphaNum(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->rule('alpha_num', $condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function ascii(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->rule('ascii', $condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function confirmed(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->rule('confirmed', $condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<scalar> | Arrayable | string | Closure $values
|
||||
*/
|
||||
public function doesntStartWith(array | Arrayable | string | Closure $values, bool | Closure $condition = true): static
|
||||
{
|
||||
$this->rule(static function (Field $component) use ($values) {
|
||||
$values = $component->evaluate($values);
|
||||
|
||||
if ($values instanceof Arrayable) {
|
||||
$values = $values->toArray();
|
||||
}
|
||||
|
||||
if (is_array($values)) {
|
||||
$values = implode(',', $values);
|
||||
}
|
||||
|
||||
return 'doesnt_start_with:' . $values;
|
||||
}, $condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<scalar> | Arrayable | string | Closure $values
|
||||
*/
|
||||
public function doesntEndWith(array | Arrayable | string | Closure $values, bool | Closure $condition = true): static
|
||||
{
|
||||
$this->rule(static function (Field $component) use ($values) {
|
||||
$values = $component->evaluate($values);
|
||||
|
||||
if ($values instanceof Arrayable) {
|
||||
$values = $values->toArray();
|
||||
}
|
||||
|
||||
if (is_array($values)) {
|
||||
$values = implode(',', $values);
|
||||
}
|
||||
|
||||
return 'doesnt_end_with:' . $values;
|
||||
}, $condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<scalar> | Arrayable | string | Closure $values
|
||||
*/
|
||||
public function endsWith(array | Arrayable | string | Closure $values, bool | Closure $condition = true): static
|
||||
{
|
||||
$this->rule(static function (Field $component) use ($values) {
|
||||
$values = $component->evaluate($values);
|
||||
|
||||
if ($values instanceof Arrayable) {
|
||||
$values = $values->toArray();
|
||||
}
|
||||
|
||||
if (is_array($values)) {
|
||||
$values = implode(',', $values);
|
||||
}
|
||||
|
||||
return 'ends_with:' . $values;
|
||||
}, $condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function enum(string | Closure $enum): static
|
||||
{
|
||||
$this->rule(static function (Field $component) use ($enum) {
|
||||
$enum = $component->evaluate($enum);
|
||||
|
||||
return new Enum($enum);
|
||||
}, static fn (Field $component): bool => filled($component->evaluate($enum)));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function exists(string | Closure | null $table = null, string | Closure | null $column = null, ?Closure $modifyRuleUsing = null): static
|
||||
{
|
||||
$this->rule(static function (Field $component, ?string $model) use ($column, $modifyRuleUsing, $table) {
|
||||
$table = $component->evaluate($table) ?? $model;
|
||||
$column = $component->evaluate($column) ?? $component->getName();
|
||||
|
||||
$rule = Rule::exists($table, $column);
|
||||
|
||||
if ($modifyRuleUsing) {
|
||||
$rule = $component->evaluate($modifyRuleUsing, [
|
||||
'rule' => $rule,
|
||||
]) ?? $rule;
|
||||
}
|
||||
|
||||
return $rule;
|
||||
}, static fn (Field $component, ?string $model): bool => (bool) ($component->evaluate($table) ?? $model));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function filled(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->rule('filled', $condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hexColor(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->rule('hex_color', $condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<scalar> | Arrayable | string | Closure $values
|
||||
*/
|
||||
public function in(array | Arrayable | string | Closure $values, bool | Closure $condition = true): static
|
||||
{
|
||||
$this->rule(static function (Field $component) use ($values) {
|
||||
$values = $component->evaluate($values);
|
||||
|
||||
if ($values instanceof Arrayable) {
|
||||
$values = $values->toArray();
|
||||
}
|
||||
|
||||
if (is_string($values)) {
|
||||
$values = array_map('trim', explode(',', $values));
|
||||
}
|
||||
|
||||
return Rule::in($values);
|
||||
}, $condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function ip(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->rule('ip', $condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function ipv4(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->rule('ipv4', $condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function ipv6(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->rule('ipv6', $condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function json(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->rule('json', $condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function macAddress(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->rule('mac_address', $condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function multipleOf(int | Closure $value): static
|
||||
{
|
||||
$this->rule(static function (Field $component) use ($value) {
|
||||
return 'multiple_of:' . $component->evaluate($value);
|
||||
}, static fn (Field $component): bool => filled($component->evaluate($value)));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<scalar> | Arrayable | string | Closure $values
|
||||
*/
|
||||
public function notIn(array | Arrayable | string | Closure $values, bool | Closure $condition = true): static
|
||||
{
|
||||
$this->rule(static function (Field $component) use ($values) {
|
||||
$values = $component->evaluate($values);
|
||||
|
||||
if ($values instanceof Arrayable) {
|
||||
$values = $values->toArray();
|
||||
}
|
||||
|
||||
if (is_string($values)) {
|
||||
$values = array_map('trim', explode(',', $values));
|
||||
}
|
||||
|
||||
return Rule::notIn($values);
|
||||
}, $condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function notRegex(string | Closure | null $pattern): static
|
||||
{
|
||||
$this->rule(static function (Field $component) use ($pattern) {
|
||||
return 'not_regex:' . $component->evaluate($pattern);
|
||||
}, static fn (Field $component): bool => filled($component->evaluate($pattern)));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function nullable(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->required(static function (Field $component) use ($condition): bool {
|
||||
return ! $component->evaluate($condition);
|
||||
});
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function prohibited(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->rule('prohibited', $condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function prohibitedIf(string | Closure $statePath, mixed $stateValues, bool $isStatePathAbsolute = false): static
|
||||
{
|
||||
return $this->multiFieldValueComparisonRule('prohibited_if', $statePath, $stateValues, $isStatePathAbsolute);
|
||||
}
|
||||
|
||||
public function prohibitedUnless(string | Closure $statePath, mixed $stateValues, bool $isStatePathAbsolute = false): static
|
||||
{
|
||||
return $this->multiFieldValueComparisonRule('prohibited_unless', $statePath, $stateValues, $isStatePathAbsolute);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string> | string | Closure $statePaths
|
||||
*/
|
||||
public function prohibits(array | string | Closure $statePaths, bool $isStatePathAbsolute = false): static
|
||||
{
|
||||
return $this->multiFieldComparisonRule('prohibits', $statePaths, $isStatePathAbsolute);
|
||||
}
|
||||
|
||||
public function required(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->isRequired = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function requiredIf(string | Closure $statePath, mixed $stateValues, bool $isStatePathAbsolute = false): static
|
||||
{
|
||||
return $this->multiFieldValueComparisonRule('required_if', $statePath, $stateValues, $isStatePathAbsolute);
|
||||
}
|
||||
|
||||
public function requiredIfAccepted(string | Closure $statePath, bool $isStatePathAbsolute = false): static
|
||||
{
|
||||
return $this->fieldComparisonRule('required_if_accepted', $statePath, $isStatePathAbsolute);
|
||||
}
|
||||
|
||||
public function requiredUnless(string | Closure $statePath, mixed $stateValues, bool $isStatePathAbsolute = false): static
|
||||
{
|
||||
return $this->multiFieldValueComparisonRule('required_unless', $statePath, $stateValues, $isStatePathAbsolute);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string | array<string> | Closure $statePaths
|
||||
*/
|
||||
public function requiredWith(string | array | Closure $statePaths, bool $isStatePathAbsolute = false): static
|
||||
{
|
||||
return $this->multiFieldComparisonRule('required_with', $statePaths, $isStatePathAbsolute);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string | array<string> | Closure $statePaths
|
||||
*/
|
||||
public function requiredWithAll(string | array | Closure $statePaths, bool $isStatePathAbsolute = false): static
|
||||
{
|
||||
return $this->multiFieldComparisonRule('required_with_all', $statePaths, $isStatePathAbsolute);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string | array<string> | Closure $statePaths
|
||||
*/
|
||||
public function requiredWithout(string | array | Closure $statePaths, bool $isStatePathAbsolute = false): static
|
||||
{
|
||||
return $this->multiFieldComparisonRule('required_without', $statePaths, $isStatePathAbsolute);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string | array<string> | Closure $statePaths
|
||||
*/
|
||||
public function requiredWithoutAll(string | array | Closure $statePaths, bool $isStatePathAbsolute = false): static
|
||||
{
|
||||
return $this->multiFieldComparisonRule('required_without_all', $statePaths, $isStatePathAbsolute);
|
||||
}
|
||||
|
||||
public function regex(string | Closure | null $pattern): static
|
||||
{
|
||||
$this->regexPattern = $pattern;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<scalar> | Arrayable | string | Closure $values
|
||||
*/
|
||||
public function startsWith(array | Arrayable | string | Closure $values, bool | Closure $condition = true): static
|
||||
{
|
||||
$this->rule(static function (Field $component) use ($values) {
|
||||
$values = $component->evaluate($values);
|
||||
|
||||
if ($values instanceof Arrayable) {
|
||||
$values = $values->toArray();
|
||||
}
|
||||
|
||||
if (is_array($values)) {
|
||||
$values = implode(',', $values);
|
||||
}
|
||||
|
||||
return 'starts_with:' . $values;
|
||||
}, $condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function string(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->rule('string', $condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function ulid(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->rule('ulid', $condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function uuid(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->rule('uuid', $condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function rule(mixed $rule, bool | Closure $condition = true): static
|
||||
{
|
||||
$this->rules = [
|
||||
...$this->rules,
|
||||
[$rule, $condition],
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string | array<mixed> | Closure $rules
|
||||
*/
|
||||
public function rules(string | array | Closure $rules, bool | Closure $condition = true): static
|
||||
{
|
||||
if ($rules instanceof Closure) {
|
||||
$this->rules = [
|
||||
...$this->rules,
|
||||
[$rules, $condition],
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
if (is_string($rules)) {
|
||||
$rules = explode('|', $rules);
|
||||
}
|
||||
|
||||
$this->rules = [
|
||||
...$this->rules,
|
||||
...array_map(static fn (string | object $rule): array => [$rule, $condition], $rules),
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function after(string | Closure $date, bool $isStatePathAbsolute = false): static
|
||||
{
|
||||
return $this->dateComparisonRule('after', $date, $isStatePathAbsolute);
|
||||
}
|
||||
|
||||
public function afterOrEqual(string | Closure $date, bool $isStatePathAbsolute = false): static
|
||||
{
|
||||
return $this->dateComparisonRule('after_or_equal', $date, $isStatePathAbsolute);
|
||||
}
|
||||
|
||||
public function before(string | Closure $date, bool $isStatePathAbsolute = false): static
|
||||
{
|
||||
return $this->dateComparisonRule('before', $date, $isStatePathAbsolute);
|
||||
}
|
||||
|
||||
public function beforeOrEqual(string | Closure $date, bool $isStatePathAbsolute = false): static
|
||||
{
|
||||
return $this->dateComparisonRule('before_or_equal', $date, $isStatePathAbsolute);
|
||||
}
|
||||
|
||||
public function different(string | Closure $statePath, bool $isStatePathAbsolute = false): static
|
||||
{
|
||||
return $this->fieldComparisonRule('different', $statePath, $isStatePathAbsolute);
|
||||
}
|
||||
|
||||
public function gt(string | Closure $statePath, bool $isStatePathAbsolute = false): static
|
||||
{
|
||||
return $this->fieldComparisonRule('gt', $statePath, $isStatePathAbsolute);
|
||||
}
|
||||
|
||||
public function gte(string | Closure $statePath, bool $isStatePathAbsolute = false): static
|
||||
{
|
||||
return $this->fieldComparisonRule('gte', $statePath, $isStatePathAbsolute);
|
||||
}
|
||||
|
||||
public function lt(string | Closure $statePath, bool $isStatePathAbsolute = false): static
|
||||
{
|
||||
return $this->fieldComparisonRule('lt', $statePath, $isStatePathAbsolute);
|
||||
}
|
||||
|
||||
public function lte(string | Closure $statePath, bool $isStatePathAbsolute = false): static
|
||||
{
|
||||
return $this->fieldComparisonRule('lte', $statePath, $isStatePathAbsolute);
|
||||
}
|
||||
|
||||
public function same(string | Closure $statePath, bool $isStatePathAbsolute = false): static
|
||||
{
|
||||
return $this->fieldComparisonRule('same', $statePath, $isStatePathAbsolute);
|
||||
}
|
||||
|
||||
public function unique(string | Closure | null $table = null, string | Closure | null $column = null, Model | Closure | null $ignorable = null, bool $ignoreRecord = false, ?Closure $modifyRuleUsing = null): static
|
||||
{
|
||||
$this->rule(static function (Field $component, ?string $model) use ($column, $ignorable, $ignoreRecord, $modifyRuleUsing, $table) {
|
||||
$table = $component->evaluate($table) ?? $model;
|
||||
$column = $component->evaluate($column) ?? $component->getName();
|
||||
$ignorable = ($ignoreRecord && ! $ignorable) ?
|
||||
$component->getRecord() :
|
||||
$component->evaluate($ignorable);
|
||||
|
||||
$rule = Rule::unique($table, $column)
|
||||
->when(
|
||||
$ignorable,
|
||||
fn (Unique $rule) => $rule->ignore(
|
||||
$ignorable->getOriginal($ignorable->getKeyName()),
|
||||
$ignorable->getQualifiedKeyName(),
|
||||
),
|
||||
);
|
||||
|
||||
if ($modifyRuleUsing) {
|
||||
$rule = $component->evaluate($modifyRuleUsing, [
|
||||
'rule' => $rule,
|
||||
]) ?? $rule;
|
||||
}
|
||||
|
||||
return $rule;
|
||||
}, fn (Field $component, ?string $model): bool => (bool) ($component->evaluate($table) ?? $model));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function distinct(): static
|
||||
{
|
||||
$this->rule(static function (Field $component, mixed $state) {
|
||||
return function (string $attribute, mixed $value, Closure $fail) use ($component, $state) {
|
||||
if (blank($state)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$repeater = $component->getParentRepeater();
|
||||
|
||||
if (! $repeater) {
|
||||
return;
|
||||
}
|
||||
|
||||
$repeaterStatePath = $repeater->getStatePath();
|
||||
|
||||
$componentItemStatePath = (string) str($component->getStatePath())
|
||||
->after("{$repeaterStatePath}.")
|
||||
->after('.');
|
||||
|
||||
$repeaterItemKey = (string) str($component->getStatePath())
|
||||
->after("{$repeaterStatePath}.")
|
||||
->beforeLast(".{$componentItemStatePath}");
|
||||
|
||||
$repeaterSiblingState = Arr::except($repeater->getState(), [$repeaterItemKey]);
|
||||
|
||||
if (empty($repeaterSiblingState)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$validationMessages = $component->getValidationMessages();
|
||||
|
||||
if (is_bool($state)) {
|
||||
$isSiblingItemSelected = collect($repeaterSiblingState)
|
||||
->pluck($componentItemStatePath)
|
||||
->contains(true);
|
||||
|
||||
if ($state && $isSiblingItemSelected) {
|
||||
$fail(__($validationMessages['distinct.only_one_must_be_selected'] ?? 'filament-forms::validation.distinct.only_one_must_be_selected', ['attribute' => $component->getValidationAttribute()]));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($state || $isSiblingItemSelected) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fail(__($validationMessages['distinct.must_be_selected'] ?? 'filament-forms::validation.distinct.must_be_selected', ['attribute' => $component->getValidationAttribute()]));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_array($state)) {
|
||||
$hasSiblingStateIntersections = collect($repeaterSiblingState)
|
||||
->filter(fn (array $item): bool => filled(array_intersect(data_get($item, $componentItemStatePath, []), $state)))
|
||||
->isNotEmpty();
|
||||
|
||||
if (! $hasSiblingStateIntersections) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fail(__($validationMessages['distinct'] ?? 'validation.distinct', ['attribute' => $component->getValidationAttribute()]));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$hasDuplicateSiblingState = collect($repeaterSiblingState)
|
||||
->pluck($componentItemStatePath)
|
||||
->contains($state);
|
||||
|
||||
if (! $hasDuplicateSiblingState) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fail(__($validationMessages['distinct'] ?? 'validation.distinct', ['attribute' => $component->getValidationAttribute()]));
|
||||
};
|
||||
});
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function validationAttribute(string | Closure | null $label): static
|
||||
{
|
||||
$this->validationAttribute = $label;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string | Closure> $messages
|
||||
*/
|
||||
public function validationMessages(array $messages): static
|
||||
{
|
||||
$this->validationMessages = $messages;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRegexPattern(): ?string
|
||||
{
|
||||
return $this->evaluate($this->regexPattern);
|
||||
}
|
||||
|
||||
public function getRequiredValidationRule(): string
|
||||
{
|
||||
return $this->isRequired() ? 'required' : 'nullable';
|
||||
}
|
||||
|
||||
public function getValidationAttribute(): string
|
||||
{
|
||||
return $this->evaluate($this->validationAttribute) ?? Str::lcfirst($this->getLabel());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function getValidationMessages(): array
|
||||
{
|
||||
$messages = [];
|
||||
|
||||
foreach ($this->validationMessages as $rule => $message) {
|
||||
$messages[$rule] = $this->evaluate($message);
|
||||
}
|
||||
|
||||
return array_filter($messages);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<mixed>
|
||||
*/
|
||||
public function getValidationRules(): array
|
||||
{
|
||||
$rules = [
|
||||
$this->getRequiredValidationRule(),
|
||||
...($this instanceof CanBeLengthConstrained ? $this->getLengthValidationRules() : []),
|
||||
];
|
||||
|
||||
if (filled($regexPattern = $this->getRegexPattern())) {
|
||||
$rules[] = "regex:{$regexPattern}";
|
||||
}
|
||||
|
||||
foreach ($this->rules as [$rule, $condition]) {
|
||||
if (is_numeric($rule)) {
|
||||
$rules[] = $this->evaluate($condition);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $this->evaluate($condition)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$rule = $this->evaluate($rule);
|
||||
|
||||
if (is_array($rule)) {
|
||||
$rules = [
|
||||
...$rules,
|
||||
...$rule,
|
||||
];
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$rules[] = $rule;
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, array<string, string>> $messages
|
||||
*/
|
||||
public function dehydrateValidationMessages(array &$messages): void
|
||||
{
|
||||
$statePath = $this->getStatePath();
|
||||
|
||||
if (count($componentMessages = $this->getValidationMessages())) {
|
||||
foreach ($componentMessages as $rule => $message) {
|
||||
$messages["{$statePath}.{$rule}"] = $message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, array<mixed>> $rules
|
||||
*/
|
||||
public function dehydrateValidationRules(array &$rules): void
|
||||
{
|
||||
$statePath = $this->getStatePath();
|
||||
|
||||
if (count($componentRules = $this->getValidationRules())) {
|
||||
$rules[$statePath] = $componentRules;
|
||||
}
|
||||
|
||||
if (! $this instanceof HasNestedRecursiveValidationRules) {
|
||||
return;
|
||||
}
|
||||
|
||||
$nestedRecursiveValidationRules = $this->getNestedRecursiveValidationRules();
|
||||
|
||||
if (! count($nestedRecursiveValidationRules)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$rules["{$statePath}.*"] = $nestedRecursiveValidationRules;
|
||||
}
|
||||
|
||||
public function dehydrateValidationAttributes(array &$attributes): void
|
||||
{
|
||||
$attributes[$this->getStatePath()] = $this->getValidationAttribute();
|
||||
}
|
||||
|
||||
public function isRequired(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->isRequired);
|
||||
}
|
||||
|
||||
public function dateComparisonRule(string $rule, string | Closure $date, bool $isStatePathAbsolute = false): static
|
||||
{
|
||||
$this->rule(static function (Field $component) use ($date, $isStatePathAbsolute, $rule): string {
|
||||
$date = $component->evaluate($date);
|
||||
|
||||
if (! (strtotime($date) || $isStatePathAbsolute)) {
|
||||
$containerStatePath = $component->getContainer()->getStatePath();
|
||||
|
||||
if ($containerStatePath) {
|
||||
$date = "{$containerStatePath}.{$date}";
|
||||
}
|
||||
}
|
||||
|
||||
return "{$rule}:{$date}";
|
||||
}, fn (Field $component): bool => (bool) $component->evaluate($date));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function fieldComparisonRule(string $rule, string | Closure $statePath, bool $isStatePathAbsolute = false): static
|
||||
{
|
||||
$this->rule(static function (Field $component) use ($isStatePathAbsolute, $rule, $statePath): string {
|
||||
$statePath = $component->evaluate($statePath);
|
||||
|
||||
if (! $isStatePathAbsolute) {
|
||||
$containerStatePath = $component->getContainer()->getStatePath();
|
||||
|
||||
if ($containerStatePath) {
|
||||
$statePath = "{$containerStatePath}.{$statePath}";
|
||||
}
|
||||
}
|
||||
|
||||
return "{$rule}:{$statePath}";
|
||||
}, fn (Field $component): bool => (bool) $component->evaluate($statePath));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string> | string | Closure $statePaths
|
||||
*/
|
||||
public function multiFieldComparisonRule(string $rule, array | string | Closure $statePaths, bool $isStatePathAbsolute = false): static
|
||||
{
|
||||
$this->rule(static function (Field $component) use ($isStatePathAbsolute, $rule, $statePaths): string {
|
||||
$statePaths = $component->evaluate($statePaths);
|
||||
|
||||
if (! $isStatePathAbsolute) {
|
||||
if (is_string($statePaths)) {
|
||||
$statePaths = explode(',', $statePaths);
|
||||
}
|
||||
|
||||
$containerStatePath = $component->getContainer()->getStatePath();
|
||||
|
||||
if ($containerStatePath) {
|
||||
$statePaths = array_map(function ($statePath) use ($containerStatePath) {
|
||||
$statePath = trim($statePath);
|
||||
|
||||
return "{$containerStatePath}.{$statePath}";
|
||||
}, $statePaths);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($statePaths)) {
|
||||
$statePaths = implode(',', $statePaths);
|
||||
}
|
||||
|
||||
return "{$rule}:{$statePaths}";
|
||||
}, fn (Field $component): bool => (bool) $component->evaluate($statePaths));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function multiFieldValueComparisonRule(string $rule, string | Closure $statePath, mixed $stateValues, bool $isStatePathAbsolute = false): static
|
||||
{
|
||||
$this->rule(static function (Field $component) use ($isStatePathAbsolute, $rule, $statePath, $stateValues): string {
|
||||
$statePath = $component->evaluate($statePath);
|
||||
$stateValues = $component->evaluate($stateValues);
|
||||
|
||||
if (! $isStatePathAbsolute) {
|
||||
$containerStatePath = $component->getContainer()->getStatePath();
|
||||
|
||||
if ($containerStatePath) {
|
||||
$statePath = "{$containerStatePath}.{$statePath}";
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($stateValues)) {
|
||||
$stateValues = implode(',', $stateValues);
|
||||
} elseif (is_bool($stateValues)) {
|
||||
$stateValues = $stateValues ? 'true' : 'false';
|
||||
}
|
||||
|
||||
return "{$rule}:{$statePath},{$stateValues}";
|
||||
}, fn (Field $component): bool => (bool) $component->evaluate($statePath));
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
55
vendor/filament/forms/src/Components/Concerns/CanDisableOptions.php
vendored
Normal file
55
vendor/filament/forms/src/Components/Concerns/CanDisableOptions.php
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
trait CanDisableOptions
|
||||
{
|
||||
protected bool | Closure | null $isOptionDisabled = null;
|
||||
|
||||
public function disableOptionWhen(bool | Closure $callback): static
|
||||
{
|
||||
$this->isOptionDisabled = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string>
|
||||
*/
|
||||
public function getEnabledOptions(): array
|
||||
{
|
||||
return collect($this->getOptions())
|
||||
->reduce(function (Collection $carry, $label, $value): Collection {
|
||||
if (is_array($label)) {
|
||||
return $carry->merge($label);
|
||||
}
|
||||
|
||||
return $carry->put($value, $label);
|
||||
}, collect())
|
||||
->filter(fn ($label, $value) => ! $this->isOptionDisabled($value, $label))
|
||||
->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array-key $value
|
||||
*/
|
||||
public function isOptionDisabled($value, string $label): bool
|
||||
{
|
||||
if ($this->isOptionDisabled === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) $this->evaluate($this->isOptionDisabled, [
|
||||
'label' => $label,
|
||||
'value' => $value,
|
||||
]);
|
||||
}
|
||||
|
||||
public function hasDynamicDisabledOptions(): bool
|
||||
{
|
||||
return $this->isOptionDisabled instanceof Closure;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Filament\Forms\Components\Component;
|
||||
use Filament\Forms\Components\Contracts\CanDisableOptions;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
trait CanDisableOptionsWhenSelectedInSiblingRepeaterItems
|
||||
{
|
||||
public function disableOptionsWhenSelectedInSiblingRepeaterItems(): static
|
||||
{
|
||||
$this->distinct();
|
||||
$this->live();
|
||||
|
||||
$this->disableOptionWhen(static function (Component & CanDisableOptions $component, string $value, mixed $state) {
|
||||
$repeater = $component->getParentRepeater();
|
||||
|
||||
if (! $repeater) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return collect($repeater->getState())
|
||||
->pluck(
|
||||
(string) str($component->getStatePath())
|
||||
->after("{$repeater->getStatePath()}.")
|
||||
->after('.'),
|
||||
)
|
||||
->flatten()
|
||||
->diff(Arr::wrap($state))
|
||||
->filter(fn (mixed $siblingItemState): bool => filled($siblingItemState))
|
||||
->contains($value);
|
||||
});
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
84
vendor/filament/forms/src/Components/Concerns/CanFixIndistinctState.php
vendored
Normal file
84
vendor/filament/forms/src/Components/Concerns/CanFixIndistinctState.php
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Filament\Forms\Components\Component;
|
||||
use Filament\Forms\Set;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
trait CanFixIndistinctState
|
||||
{
|
||||
public function fixIndistinctState(): static
|
||||
{
|
||||
$this->distinct();
|
||||
$this->live();
|
||||
|
||||
$this->afterStateUpdated(static function (Component $component, mixed $state, Set $set) {
|
||||
if (blank($state)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$repeater = $component->getParentRepeater();
|
||||
|
||||
if (! $repeater) {
|
||||
return;
|
||||
}
|
||||
|
||||
$repeaterStatePath = $repeater->getStatePath();
|
||||
|
||||
$componentItemStatePath = (string) str($component->getStatePath())
|
||||
->after("{$repeaterStatePath}.")
|
||||
->after('.');
|
||||
|
||||
$repeaterItemKey = (string) str($component->getStatePath())
|
||||
->after("{$repeaterStatePath}.")
|
||||
->beforeLast(".{$componentItemStatePath}");
|
||||
|
||||
$repeaterSiblingState = Arr::except($repeater->getState(), [$repeaterItemKey]);
|
||||
|
||||
if (empty($repeaterSiblingState)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_array($state)) {
|
||||
collect($repeaterSiblingState)
|
||||
->filter(fn (array $itemState): bool => filled(array_intersect(data_get($itemState, $componentItemStatePath, []), $state)))
|
||||
->map(fn (array $itemState): array => collect(data_get($itemState, $componentItemStatePath) ?? [])
|
||||
->diff($state)
|
||||
->values()
|
||||
->all())
|
||||
->each(fn (array $newSiblingItemState, string $itemKey) => $set(
|
||||
path: "{$repeaterStatePath}.{$itemKey}.{$componentItemStatePath}",
|
||||
state: $newSiblingItemState,
|
||||
isAbsolute: true,
|
||||
));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
collect($repeaterSiblingState)
|
||||
->map(fn (array $itemState): mixed => data_get($itemState, $componentItemStatePath))
|
||||
->filter(function (mixed $siblingItemComponentState) use ($state): bool {
|
||||
if ($siblingItemComponentState === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (blank($siblingItemComponentState)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $siblingItemComponentState === $state;
|
||||
})
|
||||
->each(fn (mixed $siblingItemComponentState, string $itemKey) => $set(
|
||||
path: "{$repeaterStatePath}.{$itemKey}.{$componentItemStatePath}",
|
||||
state: match ($siblingItemComponentState) {
|
||||
true => false,
|
||||
default => null,
|
||||
},
|
||||
isAbsolute: true,
|
||||
));
|
||||
});
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
38
vendor/filament/forms/src/Components/Concerns/CanGenerateUuids.php
vendored
Normal file
38
vendor/filament/forms/src/Components/Concerns/CanGenerateUuids.php
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
trait CanGenerateUuids
|
||||
{
|
||||
protected Closure | bool | null $generateUuidUsing = null;
|
||||
|
||||
public function generateUuidUsing(Closure | bool | null $callback): static
|
||||
{
|
||||
$this->generateUuidUsing = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function generateUuid(): ?string
|
||||
{
|
||||
if ($this->generateUuidUsing) {
|
||||
return $this->evaluate($this->generateUuidUsing);
|
||||
}
|
||||
|
||||
if ($this->generateUuidUsing === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (string) Str::uuid();
|
||||
}
|
||||
|
||||
public static function fake(): Closure
|
||||
{
|
||||
return static::configureUsing(
|
||||
fn ($component) => $component->generateUuidUsing(false),
|
||||
);
|
||||
}
|
||||
}
|
||||
60
vendor/filament/forms/src/Components/Concerns/CanLimitItemsLength.php
vendored
Normal file
60
vendor/filament/forms/src/Components/Concerns/CanLimitItemsLength.php
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Filament\Forms\Components\Component;
|
||||
|
||||
trait CanLimitItemsLength
|
||||
{
|
||||
protected int | Closure | null $maxItems = null;
|
||||
|
||||
protected int | Closure | null $minItems = null;
|
||||
|
||||
public function maxItems(int | Closure | null $count): static
|
||||
{
|
||||
$this->maxItems = $count;
|
||||
|
||||
$this->rule('array');
|
||||
$this->rule(static function (Component $component): string {
|
||||
/** @var static $component */
|
||||
$count = $component->getMaxItems();
|
||||
|
||||
return "max:{$count}";
|
||||
});
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function minItems(int | Closure | null $count): static
|
||||
{
|
||||
$this->minItems = $count;
|
||||
|
||||
$this->rule('array');
|
||||
$this->rule(static function (Component $component): string {
|
||||
/** @var static $component */
|
||||
$count = $component->getMinItems();
|
||||
|
||||
return "min:{$count}";
|
||||
});
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getMaxItems(): ?int
|
||||
{
|
||||
return $this->evaluate($this->maxItems);
|
||||
}
|
||||
|
||||
public function getMinItems(): ?int
|
||||
{
|
||||
return $this->evaluate($this->minItems);
|
||||
}
|
||||
|
||||
public function getItemsCount(): int
|
||||
{
|
||||
$state = $this->getState();
|
||||
|
||||
return is_array($state) ? count($state) : 0;
|
||||
}
|
||||
}
|
||||
32
vendor/filament/forms/src/Components/Concerns/CanSelectPlaceholder.php
vendored
Normal file
32
vendor/filament/forms/src/Components/Concerns/CanSelectPlaceholder.php
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait CanSelectPlaceholder
|
||||
{
|
||||
protected bool | Closure | null $canSelectPlaceholder = true;
|
||||
|
||||
public function selectablePlaceholder(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->canSelectPlaceholder = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `selectablePlaceholder()` instead.
|
||||
*/
|
||||
public function disablePlaceholderSelection(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->selectablePlaceholder(fn (): bool => ! $this->evaluate($condition));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function canSelectPlaceholder(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->canSelectPlaceholder);
|
||||
}
|
||||
}
|
||||
111
vendor/filament/forms/src/Components/Concerns/CanSpanColumns.php
vendored
Normal file
111
vendor/filament/forms/src/Components/Concerns/CanSpanColumns.php
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait CanSpanColumns
|
||||
{
|
||||
/**
|
||||
* @var array<string, int | string | Closure | null>
|
||||
*/
|
||||
protected array $columnSpan = [
|
||||
'default' => 1,
|
||||
'sm' => null,
|
||||
'md' => null,
|
||||
'lg' => null,
|
||||
'xl' => null,
|
||||
'2xl' => null,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array<string, int | string | Closure | null>
|
||||
*/
|
||||
protected array $columnStart = [
|
||||
'default' => null,
|
||||
'sm' => null,
|
||||
'md' => null,
|
||||
'lg' => null,
|
||||
'xl' => null,
|
||||
'2xl' => null,
|
||||
];
|
||||
|
||||
/**
|
||||
* @param array<string, int | string | Closure | null> | int | string | Closure | null $span
|
||||
*/
|
||||
public function columnSpan(array | int | string | Closure | null $span): static
|
||||
{
|
||||
if (! is_array($span)) {
|
||||
$span = [
|
||||
'default' => $span,
|
||||
];
|
||||
}
|
||||
|
||||
$this->columnSpan = [
|
||||
...$this->columnSpan,
|
||||
...$span,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function columnSpanFull(): static
|
||||
{
|
||||
$this->columnSpan('full');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, int | string | Closure | null> | int | string | Closure | null $start
|
||||
*/
|
||||
public function columnStart(array | int | string | Closure | null $start): static
|
||||
{
|
||||
if (! is_array($start)) {
|
||||
$start = [
|
||||
'default' => $start,
|
||||
];
|
||||
}
|
||||
|
||||
$this->columnStart = [
|
||||
...$this->columnStart,
|
||||
...$start,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, int | string | Closure | null> | int | string | null
|
||||
*/
|
||||
public function getColumnSpan(int | string | null $breakpoint = null): array | int | string | null
|
||||
{
|
||||
$span = $this->columnSpan;
|
||||
|
||||
if ($breakpoint !== null) {
|
||||
return $this->evaluate($span[$breakpoint] ?? null);
|
||||
}
|
||||
|
||||
return array_map(
|
||||
fn (array | int | string | Closure | null $value): array | int | string | null => $this->evaluate($value),
|
||||
$span,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, int | string | Closure | null> | int | string | null
|
||||
*/
|
||||
public function getColumnStart(int | string | null $breakpoint = null): array | int | string | null
|
||||
{
|
||||
$start = $this->columnStart;
|
||||
|
||||
if ($breakpoint !== null) {
|
||||
return $this->evaluate($start[$breakpoint] ?? null);
|
||||
}
|
||||
|
||||
return array_map(
|
||||
fn (array | int | string | Closure | null $value): array | int | string | null => $this->evaluate($value),
|
||||
$start,
|
||||
);
|
||||
}
|
||||
}
|
||||
29
vendor/filament/forms/src/Components/Concerns/Cloneable.php
vendored
Normal file
29
vendor/filament/forms/src/Components/Concerns/Cloneable.php
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Filament\Forms\Components\Component;
|
||||
|
||||
trait Cloneable
|
||||
{
|
||||
protected function cloneChildComponents(): static
|
||||
{
|
||||
if (is_array($this->childComponents)) {
|
||||
$this->childComponents = array_map(
|
||||
fn (Component $component): Component => $component->getClone(),
|
||||
$this->childComponents,
|
||||
);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getClone(): static
|
||||
{
|
||||
$clone = clone $this;
|
||||
$clone->flushCachedAbsoluteStatePath();
|
||||
$clone->cloneChildComponents();
|
||||
|
||||
return $clone;
|
||||
}
|
||||
}
|
||||
285
vendor/filament/forms/src/Components/Concerns/EntanglesStateWithSingularRelationship.php
vendored
Normal file
285
vendor/filament/forms/src/Components/Concerns/EntanglesStateWithSingularRelationship.php
vendored
Normal file
@@ -0,0 +1,285 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Filament\Forms\ComponentContainer;
|
||||
use Filament\Forms\Components\Component;
|
||||
use Filament\Forms\Components\Contracts\CanEntangleWithSingularRelationships;
|
||||
use Filament\Forms\Contracts\HasForms;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphOne;
|
||||
|
||||
trait EntanglesStateWithSingularRelationship
|
||||
{
|
||||
protected ?Model $cachedExistingRecord = null;
|
||||
|
||||
protected ?string $relationship = null;
|
||||
|
||||
protected ?Closure $mutateRelationshipDataBeforeCreateUsing = null;
|
||||
|
||||
protected ?Closure $mutateRelationshipDataBeforeFillUsing = null;
|
||||
|
||||
protected ?Closure $mutateRelationshipDataBeforeSaveUsing = null;
|
||||
|
||||
public function relationship(string $name, bool | Closure $condition = true): static
|
||||
{
|
||||
$this->relationship = $name;
|
||||
$this->statePath($name);
|
||||
|
||||
$this->loadStateFromRelationshipsUsing(static function (Component | CanEntangleWithSingularRelationships $component) {
|
||||
$component->clearCachedExistingRecord();
|
||||
|
||||
$component->fillFromRelationship();
|
||||
});
|
||||
|
||||
$this->saveRelationshipsBeforeChildrenUsing(static function (Component | CanEntangleWithSingularRelationships $component, HasForms $livewire) use ($condition): void {
|
||||
$record = $component->getCachedExistingRecord();
|
||||
|
||||
if (! $component->evaluate($condition)) {
|
||||
$record?->delete();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($record) {
|
||||
return;
|
||||
}
|
||||
|
||||
$relationship = $component->getRelationship();
|
||||
|
||||
if ($relationship instanceof BelongsTo) {
|
||||
return;
|
||||
}
|
||||
|
||||
$data = $component->getChildComponentContainer()->getState(shouldCallHooksBefore: false);
|
||||
$data = $component->mutateRelationshipDataBeforeCreate($data);
|
||||
|
||||
$relatedModel = $component->getRelatedModel();
|
||||
|
||||
$translatableContentDriver = $livewire->makeFilamentTranslatableContentDriver();
|
||||
|
||||
if ($translatableContentDriver) {
|
||||
$record = $translatableContentDriver->makeRecord($relatedModel, $data);
|
||||
} else {
|
||||
$record = new $relatedModel();
|
||||
$record->fill($data);
|
||||
}
|
||||
|
||||
$relationship->save($record);
|
||||
|
||||
$component->cachedExistingRecord($record);
|
||||
});
|
||||
|
||||
$this->saveRelationshipsUsing(static function (Component | CanEntangleWithSingularRelationships $component, HasForms $livewire) use ($condition): void {
|
||||
if (! $component->evaluate($condition)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$data = $component->getChildComponentContainer()->getState(shouldCallHooksBefore: false);
|
||||
|
||||
$record = $component->getCachedExistingRecord();
|
||||
|
||||
$translatableContentDriver = $livewire->makeFilamentTranslatableContentDriver();
|
||||
|
||||
if ($record) {
|
||||
$data = $component->mutateRelationshipDataBeforeSave($data);
|
||||
|
||||
$translatableContentDriver ?
|
||||
$translatableContentDriver->updateRecord($record, $data) :
|
||||
$record->fill($data)->save();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$relationship = $component->getRelationship();
|
||||
|
||||
if (! ($relationship instanceof BelongsTo)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$data = $component->mutateRelationshipDataBeforeCreate($data);
|
||||
|
||||
$relatedModel = $component->getRelatedModel();
|
||||
|
||||
if ($translatableContentDriver) {
|
||||
$record = $translatableContentDriver->makeRecord($relatedModel, $data);
|
||||
} else {
|
||||
$record = new $relatedModel();
|
||||
$record->fill($data);
|
||||
}
|
||||
|
||||
$record->save();
|
||||
|
||||
$relationship->associate($record);
|
||||
$relationship->getParent()->save();
|
||||
|
||||
$component->cachedExistingRecord($record);
|
||||
});
|
||||
|
||||
$this->dehydrated(false);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function fillFromRelationship(): void
|
||||
{
|
||||
$record = $this->getCachedExistingRecord();
|
||||
|
||||
if (! $record) {
|
||||
$this->getChildComponentContainer()->fill(andCallHydrationHooks: false, andFillStateWithNull: false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$data = $this->mutateRelationshipDataBeforeFill(
|
||||
$this->getStateFromRelatedRecord($record),
|
||||
);
|
||||
|
||||
$this->getChildComponentContainer()->fill($data, andCallHydrationHooks: false, andFillStateWithNull: false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
protected function getStateFromRelatedRecord(Model $record): array
|
||||
{
|
||||
if ($translatableContentDriver = $this->getLivewire()->makeFilamentTranslatableContentDriver()) {
|
||||
return $translatableContentDriver->getRecordAttributesToArray($record);
|
||||
}
|
||||
|
||||
return $record->attributesToArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array-key $key
|
||||
*/
|
||||
public function getChildComponentContainer($key = null): ComponentContainer
|
||||
{
|
||||
$container = parent::getChildComponentContainer($key);
|
||||
|
||||
$relationship = $this->getRelationship();
|
||||
|
||||
if (! $relationship) {
|
||||
return $container;
|
||||
}
|
||||
|
||||
return $container->model($this->getCachedExistingRecord() ?? $this->getRelatedModel());
|
||||
}
|
||||
|
||||
public function getRelationship(): BelongsTo | HasOne | MorphOne | null
|
||||
{
|
||||
$name = $this->getRelationshipName();
|
||||
|
||||
if (blank($name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->getModelInstance()->{$name}();
|
||||
}
|
||||
|
||||
public function getRelationshipName(): ?string
|
||||
{
|
||||
return $this->relationship;
|
||||
}
|
||||
|
||||
public function getRelatedModel(): ?string
|
||||
{
|
||||
return $this->getRelationship()?->getModel()::class;
|
||||
}
|
||||
|
||||
public function cachedExistingRecord(?Model $record): static
|
||||
{
|
||||
$this->cachedExistingRecord = $record;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCachedExistingRecord(): ?Model
|
||||
{
|
||||
if ($this->cachedExistingRecord) {
|
||||
return $this->cachedExistingRecord;
|
||||
}
|
||||
|
||||
$record = $this->getRelationship()?->getResults();
|
||||
|
||||
if (! $record?->exists) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->cachedExistingRecord = $record;
|
||||
}
|
||||
|
||||
public function clearCachedExistingRecord(): void
|
||||
{
|
||||
$this->cachedExistingRecord = null;
|
||||
}
|
||||
|
||||
public function mutateRelationshipDataBeforeCreateUsing(?Closure $callback): static
|
||||
{
|
||||
$this->mutateRelationshipDataBeforeCreateUsing = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $data
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function mutateRelationshipDataBeforeCreate(array $data): array
|
||||
{
|
||||
if ($this->mutateRelationshipDataBeforeCreateUsing instanceof Closure) {
|
||||
$data = $this->evaluate($this->mutateRelationshipDataBeforeCreateUsing, [
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function mutateRelationshipDataBeforeSaveUsing(?Closure $callback): static
|
||||
{
|
||||
$this->mutateRelationshipDataBeforeSaveUsing = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $data
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function mutateRelationshipDataBeforeFill(array $data): array
|
||||
{
|
||||
if ($this->mutateRelationshipDataBeforeFillUsing instanceof Closure) {
|
||||
$data = $this->evaluate($this->mutateRelationshipDataBeforeFillUsing, [
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function mutateRelationshipDataBeforeFillUsing(?Closure $callback): static
|
||||
{
|
||||
$this->mutateRelationshipDataBeforeFillUsing = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $data
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function mutateRelationshipDataBeforeSave(array $data): array
|
||||
{
|
||||
if ($this->mutateRelationshipDataBeforeSaveUsing instanceof Closure) {
|
||||
$data = $this->evaluate($this->mutateRelationshipDataBeforeSaveUsing, [
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
128
vendor/filament/forms/src/Components/Concerns/HasActions.php
vendored
Normal file
128
vendor/filament/forms/src/Components/Concerns/HasActions.php
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Filament\Forms\Components\Actions\Action;
|
||||
use Filament\Forms\Components\Contracts\HasAffixActions;
|
||||
use Filament\Forms\Components\Contracts\HasExtraItemActions;
|
||||
use Filament\Forms\Components\Contracts\HasFooterActions;
|
||||
use Filament\Forms\Components\Contracts\HasHeaderActions;
|
||||
use Filament\Forms\Components\Contracts\HasHintActions;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
trait HasActions
|
||||
{
|
||||
/**
|
||||
* @var array<Action> | null
|
||||
*/
|
||||
protected ?array $cachedActions = null;
|
||||
|
||||
/**
|
||||
* @var array<string, Action | Closure>
|
||||
*/
|
||||
protected array $actions = [];
|
||||
|
||||
protected Model | string | null $actionFormModel = null;
|
||||
|
||||
/**
|
||||
* @param array<Action | Closure> $actions
|
||||
*/
|
||||
public function registerActions(array $actions): static
|
||||
{
|
||||
$this->actions = [
|
||||
...$this->actions,
|
||||
...$actions,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAction(string $name): ?Action
|
||||
{
|
||||
return $this->getActions()[$name] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, Action>
|
||||
*/
|
||||
public function getActions(): array
|
||||
{
|
||||
return $this->cachedActions ??= $this->cacheActions();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<Action>
|
||||
*/
|
||||
public function cacheActions(): array
|
||||
{
|
||||
$this->cachedActions = [];
|
||||
|
||||
if ($this instanceof HasAffixActions) {
|
||||
$this->cachedActions = [
|
||||
...$this->cachedActions,
|
||||
...$this->getPrefixActions(),
|
||||
...$this->getSuffixActions(),
|
||||
];
|
||||
}
|
||||
|
||||
if ($this instanceof HasExtraItemActions) {
|
||||
$this->cachedActions = [
|
||||
...$this->cachedActions,
|
||||
...$this->getExtraItemActions(),
|
||||
];
|
||||
}
|
||||
|
||||
if ($this instanceof HasFooterActions) {
|
||||
$this->cachedActions = [
|
||||
...$this->cachedActions,
|
||||
...$this->getFooterActions(),
|
||||
];
|
||||
}
|
||||
|
||||
if ($this instanceof HasHeaderActions) {
|
||||
$this->cachedActions = [
|
||||
...$this->cachedActions,
|
||||
...$this->getHeaderActions(),
|
||||
];
|
||||
}
|
||||
|
||||
if ($this instanceof HasHintActions) {
|
||||
$this->cachedActions = [
|
||||
...$this->cachedActions,
|
||||
...$this->getHintActions(),
|
||||
];
|
||||
}
|
||||
|
||||
foreach ($this->actions as $registeredAction) {
|
||||
foreach (Arr::wrap($this->evaluate($registeredAction)) as $action) {
|
||||
$this->cachedActions[$action->getName()] = $this->prepareAction($action);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->cachedActions;
|
||||
}
|
||||
|
||||
public function prepareAction(Action $action): Action
|
||||
{
|
||||
return $action->component($this);
|
||||
}
|
||||
|
||||
public function actionFormModel(Model | string | null $model): static
|
||||
{
|
||||
$this->actionFormModel = $model;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getActionFormModel(): Model | string | null
|
||||
{
|
||||
return $this->actionFormModel ?? $this->getRecord() ?? $this->getModel();
|
||||
}
|
||||
|
||||
public function hasAction(string $name): bool
|
||||
{
|
||||
return array_key_exists($name, $this->getActions());
|
||||
}
|
||||
}
|
||||
269
vendor/filament/forms/src/Components/Concerns/HasAffixes.php
vendored
Normal file
269
vendor/filament/forms/src/Components/Concerns/HasAffixes.php
vendored
Normal file
@@ -0,0 +1,269 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Filament\Forms\Components\Actions\Action;
|
||||
use Filament\Support\Enums\ActionSize;
|
||||
use Illuminate\Contracts\Support\Htmlable;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
trait HasAffixes
|
||||
{
|
||||
/**
|
||||
* @var array<Action> | null
|
||||
*/
|
||||
protected ?array $cachedSuffixActions = null;
|
||||
|
||||
/**
|
||||
* @var array<Action | Closure>
|
||||
*/
|
||||
protected array $suffixActions = [];
|
||||
|
||||
protected string | Htmlable | Closure | null $suffixLabel = null;
|
||||
|
||||
/**
|
||||
* @var array<Action> | null
|
||||
*/
|
||||
protected ?array $cachedPrefixActions = null;
|
||||
|
||||
/**
|
||||
* @var array<Action | Closure>
|
||||
*/
|
||||
protected array $prefixActions = [];
|
||||
|
||||
protected string | Htmlable | Closure | null $prefixLabel = null;
|
||||
|
||||
protected string | Closure | null $prefixIcon = null;
|
||||
|
||||
/**
|
||||
* @var string | array{50: string, 100: string, 200: string, 300: string, 400: string, 500: string, 600: string, 700: string, 800: string, 900: string, 950: string} | Closure | null
|
||||
*/
|
||||
protected string | array | Closure | null $prefixIconColor = null;
|
||||
|
||||
protected string | Closure | null $suffixIcon = null;
|
||||
|
||||
/**
|
||||
* @var string | array{50: string, 100: string, 200: string, 300: string, 400: string, 500: string, 600: string, 700: string, 800: string, 900: string, 950: string} | Closure | null
|
||||
*/
|
||||
protected string | array | Closure | null $suffixIconColor = null;
|
||||
|
||||
protected bool | Closure $isPrefixInline = false;
|
||||
|
||||
protected bool | Closure $isSuffixInline = false;
|
||||
|
||||
public function prefix(string | Htmlable | Closure | null $label, bool | Closure $isInline = false): static
|
||||
{
|
||||
$this->prefixLabel = $label;
|
||||
$this->inlinePrefix($isInline);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function postfix(string | Htmlable | Closure | null $label, bool | Closure $isInline = false): static
|
||||
{
|
||||
return $this->suffix($label, $isInline);
|
||||
}
|
||||
|
||||
public function prefixAction(Action | Closure $action, bool | Closure $isInline = false): static
|
||||
{
|
||||
$this->prefixActions([$action], $isInline);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<Action | Closure> $actions
|
||||
*/
|
||||
public function prefixActions(array $actions, bool | Closure $isInline = false): static
|
||||
{
|
||||
$this->prefixActions = [
|
||||
...$this->prefixActions,
|
||||
...$actions,
|
||||
];
|
||||
$this->inlinePrefix($isInline);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function suffixAction(Action | Closure $action, bool | Closure $isInline = false): static
|
||||
{
|
||||
$this->suffixActions([$action], $isInline);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<Action | Closure> $actions
|
||||
*/
|
||||
public function suffixActions(array $actions, bool | Closure $isInline = false): static
|
||||
{
|
||||
$this->suffixActions = [
|
||||
...$this->suffixActions,
|
||||
...$actions,
|
||||
];
|
||||
$this->inlineSuffix($isInline);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function suffix(string | Htmlable | Closure | null $label, bool | Closure $isInline = false): static
|
||||
{
|
||||
$this->suffixLabel = $label;
|
||||
$this->inlineSuffix($isInline);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function inlinePrefix(bool | Closure $isInline = true): static
|
||||
{
|
||||
$this->isPrefixInline = $isInline;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function inlineSuffix(bool | Closure $isInline = true): static
|
||||
{
|
||||
$this->isSuffixInline = $isInline;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function prefixIcon(string | Closure | null $icon, bool | Closure $isInline = false): static
|
||||
{
|
||||
$this->prefixIcon = $icon;
|
||||
$this->inlinePrefix($isInline);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string | array{50: string, 100: string, 200: string, 300: string, 400: string, 500: string, 600: string, 700: string, 800: string, 900: string, 950: string} | Closure | null $color
|
||||
*/
|
||||
public function prefixIconColor(string | array | Closure | null $color = null): static
|
||||
{
|
||||
$this->prefixIconColor = $color;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function suffixIcon(string | Closure | null $icon, bool | Closure $isInline = false): static
|
||||
{
|
||||
$this->suffixIcon = $icon;
|
||||
$this->inlineSuffix($isInline);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string | array{50: string, 100: string, 200: string, 300: string, 400: string, 500: string, 600: string, 700: string, 800: string, 900: string, 950: string} | Closure | null $color
|
||||
*/
|
||||
public function suffixIconColor(string | array | Closure | null $color = null): static
|
||||
{
|
||||
$this->suffixIconColor = $color;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<Action>
|
||||
*/
|
||||
public function getPrefixActions(): array
|
||||
{
|
||||
return $this->cachedPrefixActions ?? $this->cachePrefixActions();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<Action>
|
||||
*/
|
||||
public function cachePrefixActions(): array
|
||||
{
|
||||
$this->cachedPrefixActions = [];
|
||||
|
||||
foreach ($this->prefixActions as $prefixAction) {
|
||||
foreach (Arr::wrap($this->evaluate($prefixAction)) as $action) {
|
||||
$this->cachedPrefixActions[$action->getName()] = $this->prepareAction(
|
||||
$action
|
||||
->defaultSize(ActionSize::Small)
|
||||
->defaultView(Action::ICON_BUTTON_VIEW),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->cachedPrefixActions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<Action>
|
||||
*/
|
||||
public function getSuffixActions(): array
|
||||
{
|
||||
return $this->cachedSuffixActions ?? $this->cacheSuffixActions();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<Action>
|
||||
*/
|
||||
public function cacheSuffixActions(): array
|
||||
{
|
||||
$this->cachedSuffixActions = [];
|
||||
|
||||
foreach ($this->suffixActions as $suffixAction) {
|
||||
foreach (Arr::wrap($this->evaluate($suffixAction)) as $action) {
|
||||
$this->cachedSuffixActions[$action->getName()] = $this->prepareAction(
|
||||
$action
|
||||
->defaultSize(ActionSize::Small)
|
||||
->defaultView(Action::ICON_BUTTON_VIEW),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->cachedSuffixActions;
|
||||
}
|
||||
|
||||
public function getPrefixLabel(): string | Htmlable | null
|
||||
{
|
||||
return $this->evaluate($this->prefixLabel);
|
||||
}
|
||||
|
||||
public function getSuffixLabel(): string | Htmlable | null
|
||||
{
|
||||
return $this->evaluate($this->suffixLabel);
|
||||
}
|
||||
|
||||
public function getPrefixIcon(): ?string
|
||||
{
|
||||
return $this->evaluate($this->prefixIcon);
|
||||
}
|
||||
|
||||
public function getSuffixIcon(): ?string
|
||||
{
|
||||
return $this->evaluate($this->suffixIcon);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string | array{50: string, 100: string, 200: string, 300: string, 400: string, 500: string, 600: string, 700: string, 800: string, 900: string, 950: string} | null
|
||||
*/
|
||||
public function getPrefixIconColor(): string | array | null
|
||||
{
|
||||
return $this->evaluate($this->prefixIconColor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string | array{50: string, 100: string, 200: string, 300: string, 400: string, 500: string, 600: string, 700: string, 800: string, 900: string, 950: string} | null
|
||||
*/
|
||||
public function getSuffixIconColor(): string | array | null
|
||||
{
|
||||
return $this->evaluate($this->suffixIconColor);
|
||||
}
|
||||
|
||||
public function isPrefixInline(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->isPrefixInline);
|
||||
}
|
||||
|
||||
public function isSuffixInline(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->isSuffixInline);
|
||||
}
|
||||
}
|
||||
82
vendor/filament/forms/src/Components/Concerns/HasChildComponents.php
vendored
Normal file
82
vendor/filament/forms/src/Components/Concerns/HasChildComponents.php
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Filament\Forms\ComponentContainer;
|
||||
use Filament\Forms\Components\Component;
|
||||
|
||||
trait HasChildComponents
|
||||
{
|
||||
/**
|
||||
* @var array<Component> | Closure
|
||||
*/
|
||||
protected array | Closure $childComponents = [];
|
||||
|
||||
/**
|
||||
* @param array<Component> | Closure $components
|
||||
*/
|
||||
public function childComponents(array | Closure $components): static
|
||||
{
|
||||
$this->childComponents = $components;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<Component> | Closure $components
|
||||
*/
|
||||
public function schema(array | Closure $components): static
|
||||
{
|
||||
$this->childComponents($components);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<Component>
|
||||
*/
|
||||
public function getChildComponents(): array
|
||||
{
|
||||
return $this->evaluate($this->childComponents);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array-key $key
|
||||
*/
|
||||
public function getChildComponentContainer($key = null): ComponentContainer
|
||||
{
|
||||
if (filled($key) && array_key_exists($key, $containers = $this->getChildComponentContainers())) {
|
||||
return $containers[$key];
|
||||
}
|
||||
|
||||
return ComponentContainer::make($this->getLivewire())
|
||||
->parentComponent($this)
|
||||
->components($this->getChildComponents());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<ComponentContainer>
|
||||
*/
|
||||
public function getChildComponentContainers(bool $withHidden = false): array
|
||||
{
|
||||
if (! $this->hasChildComponentContainer($withHidden)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [$this->getChildComponentContainer()];
|
||||
}
|
||||
|
||||
public function hasChildComponentContainer(bool $withHidden = false): bool
|
||||
{
|
||||
if ((! $withHidden) && $this->isHidden()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->getChildComponents() === []) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
60
vendor/filament/forms/src/Components/Concerns/HasColors.php
vendored
Normal file
60
vendor/filament/forms/src/Components/Concerns/HasColors.php
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Filament\Support\Contracts\HasColor as ColorInterface;
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
use UnitEnum;
|
||||
|
||||
trait HasColors
|
||||
{
|
||||
/**
|
||||
* @var array<string | array{50: string, 100: string, 200: string, 300: string, 400: string, 500: string, 600: string, 700: string, 800: string, 900: string, 950: string} | null> | Arrayable | Closure | null
|
||||
*/
|
||||
protected array | Arrayable | Closure | null $colors = null;
|
||||
|
||||
/**
|
||||
* @param array<string | array{50: string, 100: string, 200: string, 300: string, 400: string, 500: string, 600: string, 700: string, 800: string, 900: string, 950: string} | null> | Arrayable | Closure | null $colors
|
||||
*/
|
||||
public function colors(array | Arrayable | Closure | null $colors): static
|
||||
{
|
||||
$this->colors = $colors;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string | array{50: string, 100: string, 200: string, 300: string, 400: string, 500: string, 600: string, 700: string, 800: string, 900: string, 950: string} | null
|
||||
*/
|
||||
public function getColor(mixed $value): string | array | null
|
||||
{
|
||||
return $this->getColors()[$value] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string | array{50: string, 100: string, 200: string, 300: string, 400: string, 500: string, 600: string, 700: string, 800: string, 900: string, 950: string} | null>
|
||||
*/
|
||||
public function getColors(): array
|
||||
{
|
||||
$colors = $this->evaluate($this->colors);
|
||||
|
||||
if ($colors instanceof Arrayable) {
|
||||
$colors = $colors->toArray();
|
||||
}
|
||||
|
||||
if (
|
||||
is_string($this->options) &&
|
||||
enum_exists($enum = $this->options) &&
|
||||
is_a($enum, ColorInterface::class, allow_string: true)
|
||||
) {
|
||||
return array_reduce($enum::cases(), function (array $carry, ColorInterface & UnitEnum $case): array {
|
||||
$carry[$case?->value ?? $case->name] = $case->getColor();
|
||||
|
||||
return $carry;
|
||||
}, []);
|
||||
}
|
||||
|
||||
return $colors ?? [];
|
||||
}
|
||||
}
|
||||
51
vendor/filament/forms/src/Components/Concerns/HasContainerGridLayout.php
vendored
Normal file
51
vendor/filament/forms/src/Components/Concerns/HasContainerGridLayout.php
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
trait HasContainerGridLayout
|
||||
{
|
||||
/**
|
||||
* @var array<string, int | string | null> | null
|
||||
*/
|
||||
protected ?array $gridColumns = null;
|
||||
|
||||
/**
|
||||
* @param array<string, int | string | null> | int | string | null $columns
|
||||
*/
|
||||
public function grid(array | int | string | null $columns = 2): static
|
||||
{
|
||||
if (! is_array($columns)) {
|
||||
$columns = [
|
||||
'lg' => $columns,
|
||||
];
|
||||
}
|
||||
|
||||
$this->gridColumns = [
|
||||
...($this->gridColumns ?? []),
|
||||
...$columns,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, int | string | null> | int | string | null
|
||||
*/
|
||||
public function getGridColumns(?string $breakpoint = null): array | int | string | null
|
||||
{
|
||||
$columns = $this->gridColumns ?? [
|
||||
'default' => 1,
|
||||
'sm' => null,
|
||||
'md' => null,
|
||||
'lg' => null,
|
||||
'xl' => null,
|
||||
'2xl' => null,
|
||||
];
|
||||
|
||||
if ($breakpoint !== null) {
|
||||
return $columns[$breakpoint] ?? null;
|
||||
}
|
||||
|
||||
return $columns;
|
||||
}
|
||||
}
|
||||
38
vendor/filament/forms/src/Components/Concerns/HasDatalistOptions.php
vendored
Normal file
38
vendor/filament/forms/src/Components/Concerns/HasDatalistOptions.php
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
|
||||
trait HasDatalistOptions
|
||||
{
|
||||
/**
|
||||
* @var array<string> | Arrayable | Closure | null
|
||||
*/
|
||||
protected array | Arrayable | Closure | null $datalistOptions = null;
|
||||
|
||||
/**
|
||||
* @param array<string> | Arrayable | Closure | null $options
|
||||
*/
|
||||
public function datalist(array | Arrayable | Closure | null $options): static
|
||||
{
|
||||
$this->datalistOptions = $options;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string> | null
|
||||
*/
|
||||
public function getDatalistOptions(): ?array
|
||||
{
|
||||
$options = $this->evaluate($this->datalistOptions);
|
||||
|
||||
if ($options instanceof Arrayable) {
|
||||
$options = $options->toArray();
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
72
vendor/filament/forms/src/Components/Concerns/HasDescriptions.php
vendored
Normal file
72
vendor/filament/forms/src/Components/Concerns/HasDescriptions.php
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Filament\Support\Contracts\HasDescription;
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
use Illuminate\Contracts\Support\Htmlable;
|
||||
use UnitEnum;
|
||||
|
||||
trait HasDescriptions
|
||||
{
|
||||
/**
|
||||
* @var array<string | Htmlable> | Arrayable | Closure
|
||||
*/
|
||||
protected array | Arrayable | Closure $descriptions = [];
|
||||
|
||||
/**
|
||||
* @param array<string | Htmlable> | Arrayable | Closure $descriptions
|
||||
*/
|
||||
public function descriptions(array | Arrayable | Closure $descriptions): static
|
||||
{
|
||||
$this->descriptions = $descriptions;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array-key $value
|
||||
*/
|
||||
public function hasDescription($value): bool
|
||||
{
|
||||
return array_key_exists($value, $this->getDescriptions());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array-key $value
|
||||
*/
|
||||
public function getDescription($value): string | Htmlable | null
|
||||
{
|
||||
return $this->getDescriptions()[$value] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string | Htmlable>
|
||||
*/
|
||||
public function getDescriptions(): array
|
||||
{
|
||||
$descriptions = $this->evaluate($this->descriptions);
|
||||
|
||||
if ($descriptions instanceof Arrayable) {
|
||||
$descriptions = $descriptions->toArray();
|
||||
}
|
||||
|
||||
if (
|
||||
empty($descriptions) &&
|
||||
is_string($this->options) &&
|
||||
enum_exists($this->options) &&
|
||||
is_a($this->options, HasDescription::class, allow_string: true)
|
||||
) {
|
||||
$descriptions = array_reduce($this->options::cases(), function (array $carry, HasDescription & UnitEnum $case): array {
|
||||
if (filled($description = $case->getDescription())) {
|
||||
$carry[$case?->value ?? $case->name] = $description;
|
||||
}
|
||||
|
||||
return $carry;
|
||||
}, []);
|
||||
}
|
||||
|
||||
return $descriptions;
|
||||
}
|
||||
}
|
||||
14
vendor/filament/forms/src/Components/Concerns/HasExtraAlpineAttributes.php
vendored
Normal file
14
vendor/filament/forms/src/Components/Concerns/HasExtraAlpineAttributes.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Filament\Support\Concerns\HasExtraAlpineAttributes as BaseTrait;
|
||||
|
||||
/**
|
||||
* @deprecated Use `\Filament\Support\Concerns\HasExtraAlpineAttributes` instead.
|
||||
* @see BaseTrait
|
||||
*/
|
||||
trait HasExtraAlpineAttributes
|
||||
{
|
||||
use BaseTrait;
|
||||
}
|
||||
14
vendor/filament/forms/src/Components/Concerns/HasExtraAttributes.php
vendored
Normal file
14
vendor/filament/forms/src/Components/Concerns/HasExtraAttributes.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Filament\Support\Concerns\HasExtraAttributes as BaseTrait;
|
||||
|
||||
/**
|
||||
* @deprecated Use `\Filament\Support\Concerns\HasExtraAttributes` instead.
|
||||
* @see BaseTrait
|
||||
*/
|
||||
trait HasExtraAttributes
|
||||
{
|
||||
use BaseTrait;
|
||||
}
|
||||
47
vendor/filament/forms/src/Components/Concerns/HasExtraFieldWrapperAttributes.php
vendored
Normal file
47
vendor/filament/forms/src/Components/Concerns/HasExtraFieldWrapperAttributes.php
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\View\ComponentAttributeBag;
|
||||
|
||||
trait HasExtraFieldWrapperAttributes
|
||||
{
|
||||
/**
|
||||
* @var array<array<mixed> | Closure>
|
||||
*/
|
||||
protected array $extraFieldWrapperAttributes = [];
|
||||
|
||||
/**
|
||||
* @param array<mixed> | Closure $attributes
|
||||
*/
|
||||
public function extraFieldWrapperAttributes(array | Closure $attributes, bool $merge = false): static
|
||||
{
|
||||
if ($merge) {
|
||||
$this->extraFieldWrapperAttributes[] = $attributes;
|
||||
} else {
|
||||
$this->extraFieldWrapperAttributes = [$attributes];
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<mixed>
|
||||
*/
|
||||
public function getExtraFieldWrapperAttributes(): array
|
||||
{
|
||||
$temporaryAttributeBag = new ComponentAttributeBag();
|
||||
|
||||
foreach ($this->extraFieldWrapperAttributes as $extraFieldWrapperAttributes) {
|
||||
$temporaryAttributeBag = $temporaryAttributeBag->merge($this->evaluate($extraFieldWrapperAttributes));
|
||||
}
|
||||
|
||||
return $temporaryAttributeBag->getAttributes();
|
||||
}
|
||||
|
||||
public function getExtraFieldWrapperAttributesBag(): ComponentAttributeBag
|
||||
{
|
||||
return new ComponentAttributeBag($this->getExtraFieldWrapperAttributes());
|
||||
}
|
||||
}
|
||||
47
vendor/filament/forms/src/Components/Concerns/HasExtraInputAttributes.php
vendored
Normal file
47
vendor/filament/forms/src/Components/Concerns/HasExtraInputAttributes.php
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\View\ComponentAttributeBag;
|
||||
|
||||
trait HasExtraInputAttributes
|
||||
{
|
||||
/**
|
||||
* @var array<array<mixed> | Closure>
|
||||
*/
|
||||
protected array $extraInputAttributes = [];
|
||||
|
||||
/**
|
||||
* @param array<mixed> | Closure $attributes
|
||||
*/
|
||||
public function extraInputAttributes(array | Closure $attributes, bool $merge = false): static
|
||||
{
|
||||
if ($merge) {
|
||||
$this->extraInputAttributes[] = $attributes;
|
||||
} else {
|
||||
$this->extraInputAttributes = [$attributes];
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<mixed>
|
||||
*/
|
||||
public function getExtraInputAttributes(): array
|
||||
{
|
||||
$temporaryAttributeBag = new ComponentAttributeBag();
|
||||
|
||||
foreach ($this->extraInputAttributes as $extraInputAttributes) {
|
||||
$temporaryAttributeBag = $temporaryAttributeBag->merge($this->evaluate($extraInputAttributes));
|
||||
}
|
||||
|
||||
return $temporaryAttributeBag->getAttributes();
|
||||
}
|
||||
|
||||
public function getExtraInputAttributeBag(): ComponentAttributeBag
|
||||
{
|
||||
return new ComponentAttributeBag($this->getExtraInputAttributes());
|
||||
}
|
||||
}
|
||||
63
vendor/filament/forms/src/Components/Concerns/HasExtraItemActions.php
vendored
Normal file
63
vendor/filament/forms/src/Components/Concerns/HasExtraItemActions.php
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Filament\Forms\Components\Actions\Action;
|
||||
use Filament\Support\Enums\ActionSize;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
trait HasExtraItemActions
|
||||
{
|
||||
/**
|
||||
* @var array<Action | Closure>
|
||||
*/
|
||||
protected array $extraItemActions = [];
|
||||
|
||||
/**
|
||||
* @var array<Action> | null
|
||||
*/
|
||||
protected ?array $cachedExtraItemActions = null;
|
||||
|
||||
/**
|
||||
* @param array<Action | Closure> $actions
|
||||
*/
|
||||
public function extraItemActions(array $actions): static
|
||||
{
|
||||
$this->extraItemActions = [
|
||||
...$this->extraItemActions,
|
||||
...$actions,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<Action>
|
||||
*/
|
||||
public function getExtraItemActions(): array
|
||||
{
|
||||
return $this->cachedExtraItemActions ?? $this->cacheExtraItemActions();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<Action>
|
||||
*/
|
||||
public function cacheExtraItemActions(): array
|
||||
{
|
||||
$this->cachedExtraItemActions = [];
|
||||
|
||||
foreach ($this->extraItemActions as $extraItemAction) {
|
||||
foreach (Arr::wrap($this->evaluate($extraItemAction)) as $action) {
|
||||
$this->cachedExtraItemActions[$action->getName()] = $this->prepareAction(
|
||||
$action
|
||||
->defaultColor('gray')
|
||||
->defaultSize(ActionSize::Small)
|
||||
->defaultView(Action::ICON_BUTTON_VIEW),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->cachedExtraItemActions;
|
||||
}
|
||||
}
|
||||
29
vendor/filament/forms/src/Components/Concerns/HasFieldWrapper.php
vendored
Normal file
29
vendor/filament/forms/src/Components/Concerns/HasFieldWrapper.php
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait HasFieldWrapper
|
||||
{
|
||||
protected string | Closure | null $fieldWrapperView = null;
|
||||
|
||||
public function fieldWrapperView(string | Closure | null $view): static
|
||||
{
|
||||
$this->fieldWrapperView = $view;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFieldWrapperView(): string
|
||||
{
|
||||
return $this->getCustomFieldWrapperView() ??
|
||||
$this->getContainer()->getCustomFieldWrapperView() ??
|
||||
'filament-forms::field-wrapper';
|
||||
}
|
||||
|
||||
public function getCustomFieldWrapperView(): ?string
|
||||
{
|
||||
return $this->evaluate($this->fieldWrapperView);
|
||||
}
|
||||
}
|
||||
133
vendor/filament/forms/src/Components/Concerns/HasFileAttachments.php
vendored
Normal file
133
vendor/filament/forms/src/Components/Concerns/HasFileAttachments.php
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Filesystem\Filesystem;
|
||||
use Illuminate\Filesystem\FilesystemAdapter;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use League\Flysystem\UnableToCheckFileExistence;
|
||||
use Livewire\Features\SupportFileUploads\TemporaryUploadedFile;
|
||||
use SplFileInfo;
|
||||
use Throwable;
|
||||
|
||||
trait HasFileAttachments
|
||||
{
|
||||
protected string | Closure | null $fileAttachmentsDirectory = null;
|
||||
|
||||
protected string | Closure | null $fileAttachmentsDiskName = null;
|
||||
|
||||
protected ?Closure $getUploadedAttachmentUrlUsing = null;
|
||||
|
||||
protected ?Closure $saveUploadedFileAttachmentsUsing = null;
|
||||
|
||||
protected string | Closure $fileAttachmentsVisibility = 'public';
|
||||
|
||||
public function fileAttachmentsDirectory(string | Closure | null $directory): static
|
||||
{
|
||||
$this->fileAttachmentsDirectory = $directory;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function fileAttachmentsDisk(string | Closure | null $name): static
|
||||
{
|
||||
$this->fileAttachmentsDiskName = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function saveUploadedFileAttachment(TemporaryUploadedFile $attachment): ?string
|
||||
{
|
||||
if ($callback = $this->saveUploadedFileAttachmentsUsing) {
|
||||
$file = $this->evaluate($callback, [
|
||||
'file' => $attachment,
|
||||
]);
|
||||
} else {
|
||||
$file = $this->handleFileAttachmentUpload($attachment);
|
||||
}
|
||||
|
||||
if ($callback = $this->getUploadedAttachmentUrlUsing) {
|
||||
return $this->evaluate($callback, [
|
||||
'file' => $file,
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->handleUploadedAttachmentUrlRetrieval($file);
|
||||
}
|
||||
|
||||
public function fileAttachmentsVisibility(string | Closure $visibility): static
|
||||
{
|
||||
$this->fileAttachmentsVisibility = $visibility;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUploadedAttachmentUrlUsing(?Closure $callback): static
|
||||
{
|
||||
$this->getUploadedAttachmentUrlUsing = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function saveUploadedFileAttachmentsUsing(?Closure $callback): static
|
||||
{
|
||||
$this->saveUploadedFileAttachmentsUsing = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFileAttachmentsDirectory(): ?string
|
||||
{
|
||||
return $this->evaluate($this->fileAttachmentsDirectory);
|
||||
}
|
||||
|
||||
public function getFileAttachmentsDisk(): Filesystem
|
||||
{
|
||||
return Storage::disk($this->getFileAttachmentsDiskName());
|
||||
}
|
||||
|
||||
public function getFileAttachmentsDiskName(): string
|
||||
{
|
||||
return $this->evaluate($this->fileAttachmentsDiskName) ?? config('filament.default_filesystem_disk');
|
||||
}
|
||||
|
||||
public function getFileAttachmentsVisibility(): string
|
||||
{
|
||||
return $this->evaluate($this->fileAttachmentsVisibility);
|
||||
}
|
||||
|
||||
protected function handleFileAttachmentUpload(SplFileInfo $file): mixed
|
||||
{
|
||||
$storeMethod = $this->getFileAttachmentsVisibility() === 'public' ? 'storePublicly' : 'store';
|
||||
|
||||
return $file->{$storeMethod}($this->getFileAttachmentsDirectory(), $this->getFileAttachmentsDiskName());
|
||||
}
|
||||
|
||||
protected function handleUploadedAttachmentUrlRetrieval(mixed $file): ?string
|
||||
{
|
||||
/** @var FilesystemAdapter $storage */
|
||||
$storage = $this->getFileAttachmentsDisk();
|
||||
|
||||
try {
|
||||
if (! $storage->exists($file)) {
|
||||
return null;
|
||||
}
|
||||
} catch (UnableToCheckFileExistence $exception) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($storage->getVisibility($file) === 'private') {
|
||||
try {
|
||||
return $storage->temporaryUrl(
|
||||
$file,
|
||||
now()->addMinutes(5),
|
||||
);
|
||||
} catch (Throwable $exception) {
|
||||
// This driver does not support creating temporary URLs.
|
||||
}
|
||||
}
|
||||
|
||||
return $storage->url($file);
|
||||
}
|
||||
}
|
||||
60
vendor/filament/forms/src/Components/Concerns/HasFooterActions.php
vendored
Normal file
60
vendor/filament/forms/src/Components/Concerns/HasFooterActions.php
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Filament\Forms\Components\Actions\Action;
|
||||
use Filament\Support\Concerns\HasFooterActionsAlignment;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
trait HasFooterActions
|
||||
{
|
||||
use HasFooterActionsAlignment;
|
||||
|
||||
/**
|
||||
* @var array<Action> | null
|
||||
*/
|
||||
protected ?array $cachedFooterActions = null;
|
||||
|
||||
/**
|
||||
* @var array<Action | Closure>
|
||||
*/
|
||||
protected array $footerActions = [];
|
||||
|
||||
/**
|
||||
* @param array<Action | Closure> $actions
|
||||
*/
|
||||
public function footerActions(array $actions): static
|
||||
{
|
||||
$this->footerActions = [
|
||||
...$this->footerActions,
|
||||
...$actions,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<Action>
|
||||
*/
|
||||
public function getFooterActions(): array
|
||||
{
|
||||
return $this->cachedFooterActions ?? $this->cacheFooterActions();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<Action>
|
||||
*/
|
||||
public function cacheFooterActions(): array
|
||||
{
|
||||
$this->cachedFooterActions = [];
|
||||
|
||||
foreach ($this->footerActions as $footerAction) {
|
||||
foreach (Arr::wrap($this->evaluate($footerAction)) as $action) {
|
||||
$this->cachedFooterActions[$action->getName()] = $this->prepareAction($action);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->cachedFooterActions;
|
||||
}
|
||||
}
|
||||
22
vendor/filament/forms/src/Components/Concerns/HasGridDirection.php
vendored
Normal file
22
vendor/filament/forms/src/Components/Concerns/HasGridDirection.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait HasGridDirection
|
||||
{
|
||||
protected string | Closure | null $gridDirection = null;
|
||||
|
||||
public function gridDirection(string | Closure | null $gridDirection): static
|
||||
{
|
||||
$this->gridDirection = $gridDirection;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getGridDirection(): ?string
|
||||
{
|
||||
return $this->evaluate($this->gridDirection);
|
||||
}
|
||||
}
|
||||
57
vendor/filament/forms/src/Components/Concerns/HasHeaderActions.php
vendored
Normal file
57
vendor/filament/forms/src/Components/Concerns/HasHeaderActions.php
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Filament\Forms\Components\Actions\Action;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
trait HasHeaderActions
|
||||
{
|
||||
/**
|
||||
* @var array<Action> | null
|
||||
*/
|
||||
protected ?array $cachedHeaderActions = null;
|
||||
|
||||
/**
|
||||
* @var array<Action | Closure>
|
||||
*/
|
||||
protected array $headerActions = [];
|
||||
|
||||
/**
|
||||
* @param array<Action | Closure> $actions
|
||||
*/
|
||||
public function headerActions(array $actions): static
|
||||
{
|
||||
$this->headerActions = [
|
||||
...$this->headerActions,
|
||||
...$actions,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<Action>
|
||||
*/
|
||||
public function getHeaderActions(): array
|
||||
{
|
||||
return $this->cachedHeaderActions ?? $this->cacheHeaderActions();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<Action>
|
||||
*/
|
||||
public function cacheHeaderActions(): array
|
||||
{
|
||||
$this->cachedHeaderActions = [];
|
||||
|
||||
foreach ($this->headerActions as $headerAction) {
|
||||
foreach (Arr::wrap($this->evaluate($headerAction)) as $action) {
|
||||
$this->cachedHeaderActions[$action->getName()] = $this->prepareAction($action);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->cachedHeaderActions;
|
||||
}
|
||||
}
|
||||
23
vendor/filament/forms/src/Components/Concerns/HasHelperText.php
vendored
Normal file
23
vendor/filament/forms/src/Components/Concerns/HasHelperText.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Support\Htmlable;
|
||||
|
||||
trait HasHelperText
|
||||
{
|
||||
protected string | Htmlable | Closure | null $helperText = null;
|
||||
|
||||
public function helperText(string | Htmlable | Closure | null $text): static
|
||||
{
|
||||
$this->helperText = $text;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHelperText(): string | Htmlable | null
|
||||
{
|
||||
return $this->evaluate($this->helperText);
|
||||
}
|
||||
}
|
||||
136
vendor/filament/forms/src/Components/Concerns/HasHint.php
vendored
Normal file
136
vendor/filament/forms/src/Components/Concerns/HasHint.php
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Filament\Forms\Components\Actions\Action;
|
||||
use Filament\Support\Enums\ActionSize;
|
||||
use Illuminate\Contracts\Support\Htmlable;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
trait HasHint
|
||||
{
|
||||
protected string | Htmlable | Closure | null $hint = null;
|
||||
|
||||
/**
|
||||
* @var array<Action> | null
|
||||
*/
|
||||
protected ?array $cachedHintActions = null;
|
||||
|
||||
/**
|
||||
* @var array<Action | Closure>
|
||||
*/
|
||||
protected array $hintActions = [];
|
||||
|
||||
/**
|
||||
* @var string | array{50: string, 100: string, 200: string, 300: string, 400: string, 500: string, 600: string, 700: string, 800: string, 900: string, 950: string} | Closure | null
|
||||
*/
|
||||
protected string | array | Closure | null $hintColor = null;
|
||||
|
||||
protected string | Closure | null $hintIcon = null;
|
||||
|
||||
protected string | Closure | null $hintIconTooltip = null;
|
||||
|
||||
public function hint(string | Htmlable | Closure | null $hint): static
|
||||
{
|
||||
$this->hint = $hint;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string | array{50: string, 100: string, 200: string, 300: string, 400: string, 500: string, 600: string, 700: string, 800: string, 900: string, 950: string} | Closure | null $color
|
||||
*/
|
||||
public function hintColor(string | array | Closure | null $color): static
|
||||
{
|
||||
$this->hintColor = $color;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hintIcon(string | Closure | null $icon, string | Closure | null $tooltip = null): static
|
||||
{
|
||||
$this->hintIcon = $icon;
|
||||
$this->hintIconTooltip($tooltip);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hintIconTooltip(string | Closure | null $tooltip): static
|
||||
{
|
||||
$this->hintIconTooltip = $tooltip;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hintAction(Action | Closure $action): static
|
||||
{
|
||||
$this->hintActions([$action]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<Action | Closure> $actions
|
||||
*/
|
||||
public function hintActions(array $actions): static
|
||||
{
|
||||
$this->hintActions = [
|
||||
...$this->hintActions,
|
||||
...$actions,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHint(): string | Htmlable | null
|
||||
{
|
||||
return $this->evaluate($this->hint);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string | array{50: string, 100: string, 200: string, 300: string, 400: string, 500: string, 600: string, 700: string, 800: string, 900: string, 950: string} | null
|
||||
*/
|
||||
public function getHintColor(): string | array | null
|
||||
{
|
||||
return $this->evaluate($this->hintColor);
|
||||
}
|
||||
|
||||
public function getHintIcon(): ?string
|
||||
{
|
||||
return $this->evaluate($this->hintIcon);
|
||||
}
|
||||
|
||||
public function getHintIconTooltip(): ?string
|
||||
{
|
||||
return $this->evaluate($this->hintIconTooltip);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<Action>
|
||||
*/
|
||||
public function getHintActions(): array
|
||||
{
|
||||
return $this->cachedHintActions ?? $this->cacheHintActions();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<Action>
|
||||
*/
|
||||
public function cacheHintActions(): array
|
||||
{
|
||||
$this->cachedHintActions = [];
|
||||
|
||||
foreach ($this->hintActions as $hintAction) {
|
||||
foreach (Arr::wrap($this->evaluate($hintAction)) as $action) {
|
||||
$this->cachedHintActions[$action->getName()] = $this->prepareAction(
|
||||
$action
|
||||
->defaultSize(ActionSize::Small)
|
||||
->defaultView(Action::LINK_VIEW),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->cachedHintActions;
|
||||
}
|
||||
}
|
||||
58
vendor/filament/forms/src/Components/Concerns/HasIcons.php
vendored
Normal file
58
vendor/filament/forms/src/Components/Concerns/HasIcons.php
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Filament\Support\Contracts\HasIcon as IconInterface;
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
use Illuminate\Contracts\Support\Htmlable;
|
||||
use UnitEnum;
|
||||
|
||||
trait HasIcons
|
||||
{
|
||||
/**
|
||||
* @var array<string | Htmlable | null> | Arrayable | Closure | null
|
||||
*/
|
||||
protected array | Arrayable | Closure | null $icons = null;
|
||||
|
||||
/**
|
||||
* @param array<string | Htmlable | null> | Arrayable | Closure | null $icons
|
||||
*/
|
||||
public function icons(array | Arrayable | Closure | null $icons): static
|
||||
{
|
||||
$this->icons = $icons;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getIcon(mixed $value): string | Htmlable | null
|
||||
{
|
||||
return $this->getIcons()[$value] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string | Htmlable | null>
|
||||
*/
|
||||
public function getIcons(): array
|
||||
{
|
||||
$icons = $this->evaluate($this->icons);
|
||||
|
||||
if ($icons instanceof Arrayable) {
|
||||
$icons = $icons->toArray();
|
||||
}
|
||||
|
||||
if (
|
||||
is_string($this->options) &&
|
||||
enum_exists($enum = $this->options) &&
|
||||
is_a($enum, IconInterface::class, allow_string: true)
|
||||
) {
|
||||
return array_reduce($enum::cases(), function (array $carry, IconInterface & UnitEnum $case): array {
|
||||
$carry[$case?->value ?? $case->name] = $case->getIcon();
|
||||
|
||||
return $carry;
|
||||
}, []);
|
||||
}
|
||||
|
||||
return $icons ?? [];
|
||||
}
|
||||
}
|
||||
22
vendor/filament/forms/src/Components/Concerns/HasId.php
vendored
Normal file
22
vendor/filament/forms/src/Components/Concerns/HasId.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait HasId
|
||||
{
|
||||
protected string | Closure | null $id = null;
|
||||
|
||||
public function id(string | Closure | null $id): static
|
||||
{
|
||||
$this->id = $id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getId(): ?string
|
||||
{
|
||||
return $this->evaluate($this->id);
|
||||
}
|
||||
}
|
||||
22
vendor/filament/forms/src/Components/Concerns/HasInlineLabel.php
vendored
Normal file
22
vendor/filament/forms/src/Components/Concerns/HasInlineLabel.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait HasInlineLabel
|
||||
{
|
||||
protected bool | Closure | null $hasInlineLabel = null;
|
||||
|
||||
public function inlineLabel(bool | Closure | null $condition = true): static
|
||||
{
|
||||
$this->hasInlineLabel = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hasInlineLabel(): ?bool
|
||||
{
|
||||
return $this->evaluate($this->hasInlineLabel) ?? $this->getContainer()->hasInlineLabel();
|
||||
}
|
||||
}
|
||||
22
vendor/filament/forms/src/Components/Concerns/HasInputMode.php
vendored
Normal file
22
vendor/filament/forms/src/Components/Concerns/HasInputMode.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait HasInputMode
|
||||
{
|
||||
protected string | Closure | null $inputMode = null;
|
||||
|
||||
public function inputMode(string | Closure | null $mode): static
|
||||
{
|
||||
$this->inputMode = $mode;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getInputMode(): ?string
|
||||
{
|
||||
return $this->evaluate($this->inputMode);
|
||||
}
|
||||
}
|
||||
22
vendor/filament/forms/src/Components/Concerns/HasKey.php
vendored
Normal file
22
vendor/filament/forms/src/Components/Concerns/HasKey.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait HasKey
|
||||
{
|
||||
protected string | Closure | null $key = null;
|
||||
|
||||
public function key(string | Closure | null $key): static
|
||||
{
|
||||
$this->key = $key;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getKey(): ?string
|
||||
{
|
||||
return $this->evaluate($this->key);
|
||||
}
|
||||
}
|
||||
60
vendor/filament/forms/src/Components/Concerns/HasLabel.php
vendored
Normal file
60
vendor/filament/forms/src/Components/Concerns/HasLabel.php
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Support\Htmlable;
|
||||
|
||||
trait HasLabel
|
||||
{
|
||||
protected bool | Closure $isLabelHidden = false;
|
||||
|
||||
protected string | Htmlable | Closure | null $label = null;
|
||||
|
||||
protected bool $shouldTranslateLabel = false;
|
||||
|
||||
/**
|
||||
* @deprecated Use `hiddenLabel()` instead.
|
||||
*/
|
||||
public function disableLabel(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->hiddenLabel($condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hiddenLabel(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->isLabelHidden = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function label(string | Htmlable | Closure | null $label): static
|
||||
{
|
||||
$this->label = $label;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function translateLabel(bool $shouldTranslateLabel = true): static
|
||||
{
|
||||
$this->shouldTranslateLabel = $shouldTranslateLabel;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLabel(): string | Htmlable | null
|
||||
{
|
||||
$label = $this->evaluate($this->label);
|
||||
|
||||
return (is_string($label) && $this->shouldTranslateLabel) ?
|
||||
__($label) :
|
||||
$label;
|
||||
}
|
||||
|
||||
public function isLabelHidden(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->isLabelHidden);
|
||||
}
|
||||
}
|
||||
22
vendor/filament/forms/src/Components/Concerns/HasLoadingMessage.php
vendored
Normal file
22
vendor/filament/forms/src/Components/Concerns/HasLoadingMessage.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait HasLoadingMessage
|
||||
{
|
||||
protected string | Closure | null $loadingMessage = null;
|
||||
|
||||
public function loadingMessage(string | Closure | null $message): static
|
||||
{
|
||||
$this->loadingMessage = $message;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLoadingMessage(): string
|
||||
{
|
||||
return $this->evaluate($this->loadingMessage) ?? __('filament-forms::components.select.loading_message');
|
||||
}
|
||||
}
|
||||
22
vendor/filament/forms/src/Components/Concerns/HasMaxHeight.php
vendored
Normal file
22
vendor/filament/forms/src/Components/Concerns/HasMaxHeight.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait HasMaxHeight
|
||||
{
|
||||
protected string | Closure | null $maxHeight = null;
|
||||
|
||||
public function maxHeight(string | Closure | null $height): static
|
||||
{
|
||||
$this->maxHeight = $height;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getMaxHeight(): ?string
|
||||
{
|
||||
return $this->evaluate($this->maxHeight);
|
||||
}
|
||||
}
|
||||
23
vendor/filament/forms/src/Components/Concerns/HasMaxWidth.php
vendored
Normal file
23
vendor/filament/forms/src/Components/Concerns/HasMaxWidth.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Filament\Support\Enums\MaxWidth;
|
||||
|
||||
trait HasMaxWidth
|
||||
{
|
||||
protected MaxWidth | string | Closure | null $maxWidth = null;
|
||||
|
||||
public function maxWidth(MaxWidth | string | Closure | null $width): static
|
||||
{
|
||||
$this->maxWidth = $width;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getMaxWidth(): MaxWidth | string | null
|
||||
{
|
||||
return $this->evaluate($this->maxWidth);
|
||||
}
|
||||
}
|
||||
44
vendor/filament/forms/src/Components/Concerns/HasMeta.php
vendored
Normal file
44
vendor/filament/forms/src/Components/Concerns/HasMeta.php
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
trait HasMeta
|
||||
{
|
||||
/**
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
protected array $meta = [];
|
||||
|
||||
public function meta(string $key, mixed $value): static
|
||||
{
|
||||
$this->meta[$key] = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string | array<string> | null $keys
|
||||
*/
|
||||
public function getMeta(string | array | null $keys = null): mixed
|
||||
{
|
||||
if (is_array($keys)) {
|
||||
return Arr::only($this->meta, $keys);
|
||||
}
|
||||
|
||||
if (is_string($keys)) {
|
||||
return Arr::get($this->meta, $keys);
|
||||
}
|
||||
|
||||
return $this->meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string | array<string> $keys
|
||||
*/
|
||||
public function hasMeta(string | array $keys): bool
|
||||
{
|
||||
return Arr::has($this->meta, $keys);
|
||||
}
|
||||
}
|
||||
22
vendor/filament/forms/src/Components/Concerns/HasMinHeight.php
vendored
Normal file
22
vendor/filament/forms/src/Components/Concerns/HasMinHeight.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait HasMinHeight
|
||||
{
|
||||
protected string | Closure | null $minHeight = '11.25rem';
|
||||
|
||||
public function minHeight(string | Closure | null $height): static
|
||||
{
|
||||
$this->minHeight = $height;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getMinHeight(): ?string
|
||||
{
|
||||
return $this->evaluate($this->minHeight);
|
||||
}
|
||||
}
|
||||
35
vendor/filament/forms/src/Components/Concerns/HasName.php
vendored
Normal file
35
vendor/filament/forms/src/Components/Concerns/HasName.php
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Illuminate\Contracts\Support\Htmlable;
|
||||
|
||||
trait HasName
|
||||
{
|
||||
protected string $name;
|
||||
|
||||
public function name(string $name): static
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function getLabel(): string | Htmlable | null
|
||||
{
|
||||
$label = parent::getLabel() ?? (string) str($this->getName())
|
||||
->afterLast('.')
|
||||
->kebab()
|
||||
->replace(['-', '_'], ' ')
|
||||
->ucfirst();
|
||||
|
||||
return (is_string($label) && $this->shouldTranslateLabel) ?
|
||||
__($label) :
|
||||
$label;
|
||||
}
|
||||
}
|
||||
48
vendor/filament/forms/src/Components/Concerns/HasNestedRecursiveValidationRules.php
vendored
Normal file
48
vendor/filament/forms/src/Components/Concerns/HasNestedRecursiveValidationRules.php
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait HasNestedRecursiveValidationRules
|
||||
{
|
||||
/**
|
||||
* @var array<mixed>
|
||||
*/
|
||||
protected array $nestedRecursiveValidationRules = [];
|
||||
|
||||
/**
|
||||
* @param string | array<mixed> $rules
|
||||
*/
|
||||
public function nestedRecursiveRules(string | array $rules, bool | Closure $condition = true): static
|
||||
{
|
||||
if (is_string($rules)) {
|
||||
$rules = explode('|', $rules);
|
||||
}
|
||||
|
||||
$this->nestedRecursiveValidationRules = [
|
||||
...$this->nestedRecursiveValidationRules,
|
||||
...array_map(static fn (string | object $rule): array => [$rule, $condition], $rules),
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<mixed>
|
||||
*/
|
||||
public function getNestedRecursiveValidationRules(): array
|
||||
{
|
||||
$rules = [];
|
||||
|
||||
foreach ($this->nestedRecursiveValidationRules as [$rule, $condition]) {
|
||||
if (is_numeric($rule)) {
|
||||
$rules[] = $this->evaluate($condition);
|
||||
} elseif ($this->evaluate($condition)) {
|
||||
$rules[] = $this->evaluate($rule);
|
||||
}
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
||||
64
vendor/filament/forms/src/Components/Concerns/HasOptions.php
vendored
Normal file
64
vendor/filament/forms/src/Components/Concerns/HasOptions.php
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Filament\Support\Contracts\HasLabel as LabelInterface;
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
use UnitEnum;
|
||||
|
||||
trait HasOptions
|
||||
{
|
||||
/**
|
||||
* @var array<string | array<string>> | Arrayable | string | Closure | null
|
||||
*/
|
||||
protected array | Arrayable | string | Closure | null $options = null;
|
||||
|
||||
/**
|
||||
* @param array<string | array<string>> | Arrayable | string | Closure | null $options
|
||||
*/
|
||||
public function options(array | Arrayable | string | Closure | null $options): static
|
||||
{
|
||||
$this->options = $options;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string | array<string>>
|
||||
*/
|
||||
public function getOptions(): array
|
||||
{
|
||||
$options = $this->evaluate($this->options) ?? [];
|
||||
|
||||
if (
|
||||
is_string($options) &&
|
||||
enum_exists($enum = $options)
|
||||
) {
|
||||
if (is_a($enum, LabelInterface::class, allow_string: true)) {
|
||||
return array_reduce($enum::cases(), function (array $carry, LabelInterface & UnitEnum $case): array {
|
||||
$carry[$case?->value ?? $case->name] = $case->getLabel() ?? $case->name;
|
||||
|
||||
return $carry;
|
||||
}, []);
|
||||
}
|
||||
|
||||
return array_reduce($enum::cases(), function (array $carry, UnitEnum $case): array {
|
||||
$carry[$case?->value ?? $case->name] = $case->name;
|
||||
|
||||
return $carry;
|
||||
}, []);
|
||||
}
|
||||
|
||||
if ($options instanceof Arrayable) {
|
||||
$options = $options->toArray();
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
public function hasDynamicOptions(): bool
|
||||
{
|
||||
return $this->options instanceof Closure;
|
||||
}
|
||||
}
|
||||
31
vendor/filament/forms/src/Components/Concerns/HasPivotData.php
vendored
Normal file
31
vendor/filament/forms/src/Components/Concerns/HasPivotData.php
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait HasPivotData
|
||||
{
|
||||
/**
|
||||
* @var array<string, mixed> | Closure
|
||||
*/
|
||||
protected array | Closure $pivotData = [];
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> | Closure $data
|
||||
*/
|
||||
public function pivotData(array | Closure $data): static
|
||||
{
|
||||
$this->pivotData = $data;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function getPivotData(): array
|
||||
{
|
||||
return $this->evaluate($this->pivotData) ?? [];
|
||||
}
|
||||
}
|
||||
22
vendor/filament/forms/src/Components/Concerns/HasPlaceholder.php
vendored
Normal file
22
vendor/filament/forms/src/Components/Concerns/HasPlaceholder.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait HasPlaceholder
|
||||
{
|
||||
protected string | Closure | null $placeholder = null;
|
||||
|
||||
public function placeholder(string | Closure | null $placeholder): static
|
||||
{
|
||||
$this->placeholder = $placeholder;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPlaceholder(): ?string
|
||||
{
|
||||
return $this->evaluate($this->placeholder);
|
||||
}
|
||||
}
|
||||
29
vendor/filament/forms/src/Components/Concerns/HasPreview.php
vendored
Normal file
29
vendor/filament/forms/src/Components/Concerns/HasPreview.php
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\View\View;
|
||||
|
||||
trait HasPreview
|
||||
{
|
||||
protected string | Closure | null $preview = null;
|
||||
|
||||
public function preview(string | Closure | null $preview): static
|
||||
{
|
||||
$this->preview = $preview;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $data
|
||||
*/
|
||||
public function renderPreview(array $data): View
|
||||
{
|
||||
return view(
|
||||
$this->evaluate($this->preview),
|
||||
$data,
|
||||
);
|
||||
}
|
||||
}
|
||||
517
vendor/filament/forms/src/Components/Concerns/HasState.php
vendored
Normal file
517
vendor/filament/forms/src/Components/Concerns/HasState.php
vendored
Normal file
@@ -0,0 +1,517 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Filament\Forms\Components\Component;
|
||||
use Filament\Forms\Get;
|
||||
use Filament\Forms\Set;
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Str;
|
||||
use Livewire\Livewire;
|
||||
|
||||
use function Livewire\store;
|
||||
|
||||
trait HasState
|
||||
{
|
||||
protected ?Closure $afterStateHydrated = null;
|
||||
|
||||
/**
|
||||
* @var array<Closure>
|
||||
*/
|
||||
protected array $afterStateUpdated = [];
|
||||
|
||||
protected ?Closure $beforeStateDehydrated = null;
|
||||
|
||||
protected mixed $defaultState = null;
|
||||
|
||||
protected ?Closure $dehydrateStateUsing = null;
|
||||
|
||||
protected ?Closure $mutateDehydratedStateUsing = null;
|
||||
|
||||
protected ?Closure $mutateStateForValidationUsing = null;
|
||||
|
||||
protected bool $hasDefaultState = false;
|
||||
|
||||
protected bool | Closure $isDehydrated = true;
|
||||
|
||||
protected bool | Closure $isDehydratedWhenHidden = false;
|
||||
|
||||
protected ?string $statePath = null;
|
||||
|
||||
protected string $cachedAbsoluteStatePath;
|
||||
|
||||
/**
|
||||
* @var string | array<string> | Closure | null
|
||||
*/
|
||||
protected string | array | Closure | null $stripCharacters = null;
|
||||
|
||||
/**
|
||||
* @var array<string>
|
||||
*/
|
||||
protected array $cachedStripCharacters;
|
||||
|
||||
public function afterStateHydrated(?Closure $callback): static
|
||||
{
|
||||
$this->afterStateHydrated = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function clearAfterStateUpdatedHooks(): static
|
||||
{
|
||||
$this->afterStateUpdated = [];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function afterStateUpdated(?Closure $callback): static
|
||||
{
|
||||
$this->afterStateUpdated[] = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function beforeStateDehydrated(?Closure $callback): static
|
||||
{
|
||||
$this->beforeStateDehydrated = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function callAfterStateHydrated(): static
|
||||
{
|
||||
if ($callback = $this->afterStateHydrated) {
|
||||
$this->evaluate($callback);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function callAfterStateUpdated(): static
|
||||
{
|
||||
foreach ($this->afterStateUpdated as $callback) {
|
||||
$runId = spl_object_id($callback) . md5(json_encode($this->getState()));
|
||||
|
||||
if (store($this)->has('executedAfterStateUpdatedCallbacks', iKey: $runId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->callAfterStateUpdatedHook($callback);
|
||||
|
||||
store($this)->push('executedAfterStateUpdatedCallbacks', value: $runId, iKey: $runId);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function callAfterStateUpdatedHook(Closure $hook): void
|
||||
{
|
||||
$this->evaluate($hook, [
|
||||
'old' => $this->getOldState(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function callBeforeStateDehydrated(): static
|
||||
{
|
||||
if ($callback = $this->beforeStateDehydrated) {
|
||||
$this->evaluate($callback);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function default(mixed $state): static
|
||||
{
|
||||
$this->defaultState = $state;
|
||||
$this->hasDefaultState = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function dehydrated(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->isDehydrated = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function dehydratedWhenHidden(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->isDehydratedWhenHidden = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function formatStateUsing(?Closure $callback): static
|
||||
{
|
||||
$this->afterStateHydrated(fn (Component $component) => $component->state($component->evaluate($callback)));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function getStateToDehydrate(): array
|
||||
{
|
||||
if ($callback = $this->dehydrateStateUsing) {
|
||||
return [$this->getStatePath() => $this->evaluate($callback)];
|
||||
}
|
||||
|
||||
return [$this->getStatePath() => $this->getState()];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $state
|
||||
*/
|
||||
public function dehydrateState(array &$state, bool $isDehydrated = true): void
|
||||
{
|
||||
if (! ($isDehydrated && $this->isDehydrated())) {
|
||||
if ($this->hasStatePath()) {
|
||||
Arr::forget($state, $this->getStatePath());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If the component is not dehydrated, but it has child components,
|
||||
// we need to dehydrate the child component containers while
|
||||
// informing them that they are not dehydrated, so that their
|
||||
// child components get removed from the state.
|
||||
foreach ($this->getChildComponentContainers() as $container) {
|
||||
$container->dehydrateState($state, isDehydrated: false);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->getStatePath(isAbsolute: false)) {
|
||||
foreach ($this->getStateToDehydrate() as $key => $value) {
|
||||
Arr::set($state, $key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->getChildComponentContainers() as $container) {
|
||||
if ($container->isHidden()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$container->dehydrateState($state, $isDehydrated);
|
||||
}
|
||||
}
|
||||
|
||||
public function dehydrateStateUsing(?Closure $callback): static
|
||||
{
|
||||
$this->dehydrateStateUsing = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> | null $hydratedDefaultState
|
||||
*/
|
||||
public function hydrateState(?array &$hydratedDefaultState, bool $andCallHydrationHooks = true): void
|
||||
{
|
||||
$this->hydrateDefaultState($hydratedDefaultState);
|
||||
|
||||
foreach ($this->getChildComponentContainers(withHidden: true) as $container) {
|
||||
$container->hydrateState($hydratedDefaultState, $andCallHydrationHooks);
|
||||
}
|
||||
|
||||
if ($andCallHydrationHooks) {
|
||||
$this->callAfterStateHydrated();
|
||||
}
|
||||
}
|
||||
|
||||
public function fill(): void
|
||||
{
|
||||
$defaults = [];
|
||||
|
||||
$this->hydrateDefaultState($defaults);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> | null $hydratedDefaultState
|
||||
*/
|
||||
public function hydrateDefaultState(?array &$hydratedDefaultState): void
|
||||
{
|
||||
if ($hydratedDefaultState === null) {
|
||||
$this->loadStateFromRelationships();
|
||||
|
||||
$state = $this->getState();
|
||||
|
||||
// Hydrate all arrayable state objects as arrays by converting
|
||||
// them to collections, then using `toArray()`.
|
||||
if (is_array($state) || $state instanceof Arrayable) {
|
||||
$this->state(collect($state)->toArray());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$statePath = $this->getStatePath();
|
||||
|
||||
if (Arr::has($hydratedDefaultState, $statePath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! $this->hasDefaultState()) {
|
||||
$this->hasStatePath() && $this->state(null);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$defaultState = $this->getDefaultState();
|
||||
|
||||
$this->state($defaultState);
|
||||
|
||||
Arr::set($hydratedDefaultState, $statePath, $defaultState);
|
||||
}
|
||||
|
||||
public function fillStateWithNull(): void
|
||||
{
|
||||
if (! Arr::has((array) $this->getLivewire(), $this->getStatePath())) {
|
||||
$this->state(null);
|
||||
}
|
||||
|
||||
foreach ($this->getChildComponentContainers(withHidden: true) as $container) {
|
||||
$container->fillStateWithNull();
|
||||
}
|
||||
}
|
||||
|
||||
public function mutateDehydratedState(mixed $state): mixed
|
||||
{
|
||||
$state = $this->stripCharactersFromState($state);
|
||||
|
||||
if (! $this->mutateDehydratedStateUsing) {
|
||||
return $state;
|
||||
}
|
||||
|
||||
return $this->evaluate(
|
||||
$this->mutateDehydratedStateUsing,
|
||||
['state' => $state],
|
||||
);
|
||||
}
|
||||
|
||||
public function mutateStateForValidation(mixed $state): mixed
|
||||
{
|
||||
$state = $this->stripCharactersFromState($state);
|
||||
|
||||
if (! $this->mutateStateForValidationUsing) {
|
||||
return $state;
|
||||
}
|
||||
|
||||
return $this->evaluate(
|
||||
$this->mutateStateForValidationUsing,
|
||||
['state' => $state],
|
||||
);
|
||||
}
|
||||
|
||||
protected function stripCharactersFromState(mixed $state): mixed
|
||||
{
|
||||
if (! is_string($state)) {
|
||||
return $state;
|
||||
}
|
||||
|
||||
$stripCharacters = $this->getStripCharacters();
|
||||
|
||||
if (empty($stripCharacters)) {
|
||||
return $state;
|
||||
}
|
||||
|
||||
return str_replace($stripCharacters, '', $state);
|
||||
}
|
||||
|
||||
public function mutatesDehydratedState(): bool
|
||||
{
|
||||
return ($this->mutateDehydratedStateUsing instanceof Closure) || $this->hasStripCharacters();
|
||||
}
|
||||
|
||||
public function mutatesStateForValidation(): bool
|
||||
{
|
||||
return ($this->mutateStateForValidationUsing instanceof Closure) || $this->hasStripCharacters();
|
||||
}
|
||||
|
||||
public function hasStripCharacters(): bool
|
||||
{
|
||||
return filled($this->getStripCharacters());
|
||||
}
|
||||
|
||||
public function mutateDehydratedStateUsing(?Closure $callback): static
|
||||
{
|
||||
$this->mutateDehydratedStateUsing = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function mutateStateForValidationUsing(?Closure $callback): static
|
||||
{
|
||||
$this->mutateStateForValidationUsing = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function state(mixed $state): static
|
||||
{
|
||||
$livewire = $this->getLivewire();
|
||||
|
||||
data_set($livewire, $this->getStatePath(), $this->evaluate($state));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function statePath(?string $path): static
|
||||
{
|
||||
$this->statePath = $path;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDefaultState(): mixed
|
||||
{
|
||||
return $this->evaluate($this->defaultState);
|
||||
}
|
||||
|
||||
public function getState(): mixed
|
||||
{
|
||||
$state = data_get($this->getLivewire(), $this->getStatePath());
|
||||
|
||||
if (is_array($state)) {
|
||||
return $state;
|
||||
}
|
||||
|
||||
if (blank($state)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $state;
|
||||
}
|
||||
|
||||
public function getOldState(): mixed
|
||||
{
|
||||
if (! Livewire::isLivewireRequest()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$state = $this->getLivewire()->getOldFormState($this->getStatePath());
|
||||
|
||||
if (blank($state)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $state;
|
||||
}
|
||||
|
||||
public function getStatePath(bool $isAbsolute = true): string
|
||||
{
|
||||
if (! $isAbsolute) {
|
||||
return $this->statePath ?? '';
|
||||
}
|
||||
|
||||
if (isset($this->cachedAbsoluteStatePath)) {
|
||||
return $this->cachedAbsoluteStatePath;
|
||||
}
|
||||
|
||||
$pathComponents = [];
|
||||
|
||||
if ($containerStatePath = $this->getContainer()->getStatePath()) {
|
||||
$pathComponents[] = $containerStatePath;
|
||||
}
|
||||
|
||||
if ($this->hasStatePath()) {
|
||||
$pathComponents[] = $this->statePath;
|
||||
}
|
||||
|
||||
return $this->cachedAbsoluteStatePath = implode('.', $pathComponents);
|
||||
}
|
||||
|
||||
public function hasStatePath(): bool
|
||||
{
|
||||
return filled($this->statePath);
|
||||
}
|
||||
|
||||
protected function hasDefaultState(): bool
|
||||
{
|
||||
return $this->hasDefaultState;
|
||||
}
|
||||
|
||||
public function isDehydrated(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->isDehydrated);
|
||||
}
|
||||
|
||||
public function isDehydratedWhenHidden(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->isDehydratedWhenHidden);
|
||||
}
|
||||
|
||||
public function isHiddenAndNotDehydrated(): bool
|
||||
{
|
||||
if (! $this->isHidden()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ! $this->isDehydratedWhenHidden();
|
||||
}
|
||||
|
||||
public function getGetCallback(): Get
|
||||
{
|
||||
return new Get($this);
|
||||
}
|
||||
|
||||
public function getSetCallback(): Set
|
||||
{
|
||||
return new Set($this);
|
||||
}
|
||||
|
||||
public function generateRelativeStatePath(string | Component $path, bool $isAbsolute = false): string
|
||||
{
|
||||
if ($path instanceof Component) {
|
||||
return $path->getStatePath();
|
||||
}
|
||||
|
||||
if ($isAbsolute) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
$containerPath = $this->getContainer()->getStatePath();
|
||||
|
||||
while (str($path)->startsWith('../')) {
|
||||
$containerPath = Str::contains($containerPath, '.') ?
|
||||
(string) str($containerPath)->beforeLast('.') :
|
||||
null;
|
||||
|
||||
$path = (string) str($path)->after('../');
|
||||
}
|
||||
|
||||
if (blank($containerPath)) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
return "{$containerPath}.{$path}";
|
||||
}
|
||||
|
||||
protected function flushCachedAbsoluteStatePath(): void
|
||||
{
|
||||
unset($this->cachedAbsoluteStatePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string | array<string> | Closure | null $characters
|
||||
*/
|
||||
public function stripCharacters(string | array | Closure | null $characters): static
|
||||
{
|
||||
$this->stripCharacters = $characters;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string>
|
||||
*/
|
||||
public function getStripCharacters(): array
|
||||
{
|
||||
return $this->cachedStripCharacters ??= Arr::wrap($this->evaluate($this->stripCharacters));
|
||||
}
|
||||
}
|
||||
22
vendor/filament/forms/src/Components/Concerns/HasStep.php
vendored
Normal file
22
vendor/filament/forms/src/Components/Concerns/HasStep.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait HasStep
|
||||
{
|
||||
protected int | float | string | Closure | null $step = null;
|
||||
|
||||
public function step(int | float | string | Closure | null $interval): static
|
||||
{
|
||||
$this->step = $interval;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getStep(): int | float | string | null
|
||||
{
|
||||
return $this->evaluate($this->step);
|
||||
}
|
||||
}
|
||||
54
vendor/filament/forms/src/Components/Concerns/HasToggleColors.php
vendored
Normal file
54
vendor/filament/forms/src/Components/Concerns/HasToggleColors.php
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait HasToggleColors
|
||||
{
|
||||
/**
|
||||
* @var string | array{50: string, 100: string, 200: string, 300: string, 400: string, 500: string, 600: string, 700: string, 800: string, 900: string, 950: string} | Closure | null
|
||||
*/
|
||||
protected string | array | Closure | null $offColor = null;
|
||||
|
||||
/**
|
||||
* @var string | array{50: string, 100: string, 200: string, 300: string, 400: string, 500: string, 600: string, 700: string, 800: string, 900: string, 950: string} | Closure | null
|
||||
*/
|
||||
protected string | array | Closure | null $onColor = null;
|
||||
|
||||
/**
|
||||
* @param string | array{50: string, 100: string, 200: string, 300: string, 400: string, 500: string, 600: string, 700: string, 800: string, 900: string, 950: string} | Closure | null $color
|
||||
*/
|
||||
public function offColor(string | array | Closure | null $color): static
|
||||
{
|
||||
$this->offColor = $color;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string | array{50: string, 100: string, 200: string, 300: string, 400: string, 500: string, 600: string, 700: string, 800: string, 900: string, 950: string} | Closure | null $color
|
||||
*/
|
||||
public function onColor(string | array | Closure | null $color): static
|
||||
{
|
||||
$this->onColor = $color;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string | array{50: string, 100: string, 200: string, 300: string, 400: string, 500: string, 600: string, 700: string, 800: string, 900: string, 950: string} | null
|
||||
*/
|
||||
public function getOffColor(): string | array | null
|
||||
{
|
||||
return $this->evaluate($this->offColor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string | array{50: string, 100: string, 200: string, 300: string, 400: string, 500: string, 600: string, 700: string, 800: string, 900: string, 950: string} | null
|
||||
*/
|
||||
public function getOnColor(): string | array | null
|
||||
{
|
||||
return $this->evaluate($this->onColor);
|
||||
}
|
||||
}
|
||||
46
vendor/filament/forms/src/Components/Concerns/HasToggleIcons.php
vendored
Normal file
46
vendor/filament/forms/src/Components/Concerns/HasToggleIcons.php
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait HasToggleIcons
|
||||
{
|
||||
protected string | Closure | null $offIcon = null;
|
||||
|
||||
protected string | Closure | null $onIcon = null;
|
||||
|
||||
public function offIcon(string | Closure | null $icon): static
|
||||
{
|
||||
$this->offIcon = $icon;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function onIcon(string | Closure | null $icon): static
|
||||
{
|
||||
$this->onIcon = $icon;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getOffIcon(): ?string
|
||||
{
|
||||
return $this->evaluate($this->offIcon);
|
||||
}
|
||||
|
||||
public function getOnIcon(): ?string
|
||||
{
|
||||
return $this->evaluate($this->onIcon);
|
||||
}
|
||||
|
||||
public function hasOffIcon(): bool
|
||||
{
|
||||
return (bool) $this->getOffIcon();
|
||||
}
|
||||
|
||||
public function hasOnIcon(): bool
|
||||
{
|
||||
return (bool) $this->getOnIcon();
|
||||
}
|
||||
}
|
||||
22
vendor/filament/forms/src/Components/Concerns/HasUploadingMessage.php
vendored
Normal file
22
vendor/filament/forms/src/Components/Concerns/HasUploadingMessage.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait HasUploadingMessage
|
||||
{
|
||||
protected string | Closure | null $uploadingMessage = null;
|
||||
|
||||
public function uploadingMessage(string | Closure | null $message): static
|
||||
{
|
||||
$this->uploadingMessage = $message;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUploadingMessage(): string
|
||||
{
|
||||
return $this->evaluate($this->uploadingMessage) ?? __('filament::components/button.messages.uploading_file');
|
||||
}
|
||||
}
|
||||
75
vendor/filament/forms/src/Components/Concerns/InteractsWithToolbarButtons.php
vendored
Normal file
75
vendor/filament/forms/src/Components/Concerns/InteractsWithToolbarButtons.php
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait InteractsWithToolbarButtons
|
||||
{
|
||||
public function disableAllToolbarButtons(bool $condition = true): static
|
||||
{
|
||||
if ($condition) {
|
||||
$this->toolbarButtons = [];
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string> $buttonsToDisable
|
||||
*/
|
||||
public function disableToolbarButtons(array $buttonsToDisable = []): static
|
||||
{
|
||||
$this->toolbarButtons = array_values(array_filter(
|
||||
$this->getToolbarButtons(),
|
||||
static fn ($button) => ! in_array($button, $buttonsToDisable),
|
||||
));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string> $buttonsToEnable
|
||||
*/
|
||||
public function enableToolbarButtons(array $buttonsToEnable = []): static
|
||||
{
|
||||
$this->toolbarButtons = [
|
||||
...$this->getToolbarButtons(),
|
||||
...$buttonsToEnable,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string> | Closure $buttons
|
||||
*/
|
||||
public function toolbarButtons(array | Closure $buttons = []): static
|
||||
{
|
||||
$this->toolbarButtons = $buttons;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string>
|
||||
*/
|
||||
public function getToolbarButtons(): array
|
||||
{
|
||||
return $this->evaluate($this->toolbarButtons);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string | array<string> $button
|
||||
*/
|
||||
public function hasToolbarButton(string | array $button): bool
|
||||
{
|
||||
if (is_array($button)) {
|
||||
$buttons = $button;
|
||||
|
||||
return (bool) count(array_intersect($buttons, $this->getToolbarButtons()));
|
||||
}
|
||||
|
||||
return in_array($button, $this->getToolbarButtons());
|
||||
}
|
||||
}
|
||||
51
vendor/filament/forms/src/Components/Concerns/ListensToEvents.php
vendored
Normal file
51
vendor/filament/forms/src/Components/Concerns/ListensToEvents.php
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Concerns;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait ListensToEvents
|
||||
{
|
||||
/**
|
||||
* @var array<string, array<Closure>>
|
||||
*/
|
||||
protected array $listeners = [];
|
||||
|
||||
public function dispatchEvent(string $event, mixed ...$parameters): static
|
||||
{
|
||||
foreach ($this->getListeners($event) as $callback) {
|
||||
$callback($this, ...$parameters);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, array<Closure>> $listeners
|
||||
*/
|
||||
public function registerListeners(array $listeners): static
|
||||
{
|
||||
foreach ($listeners as $event => $callbacks) {
|
||||
$this->listeners[$event] = [
|
||||
...$this->getListeners($event),
|
||||
...$callbacks,
|
||||
];
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string | int, array<Closure> | Closure>
|
||||
*/
|
||||
public function getListeners(?string $event = null): array
|
||||
{
|
||||
$listeners = $this->listeners;
|
||||
|
||||
if ($event) {
|
||||
return $listeners[$event] ?? [];
|
||||
}
|
||||
|
||||
return $listeners;
|
||||
}
|
||||
}
|
||||
17
vendor/filament/forms/src/Components/Contracts/CanBeLengthConstrained.php
vendored
Normal file
17
vendor/filament/forms/src/Components/Contracts/CanBeLengthConstrained.php
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Contracts;
|
||||
|
||||
interface CanBeLengthConstrained
|
||||
{
|
||||
public function getLength(): ?int;
|
||||
|
||||
public function getMaxLength(): ?int;
|
||||
|
||||
public function getMinLength(): ?int;
|
||||
|
||||
/**
|
||||
* @return array<string>
|
||||
*/
|
||||
public function getLengthValidationRules(): array;
|
||||
}
|
||||
8
vendor/filament/forms/src/Components/Contracts/CanConcealComponents.php
vendored
Normal file
8
vendor/filament/forms/src/Components/Contracts/CanConcealComponents.php
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Contracts;
|
||||
|
||||
interface CanConcealComponents
|
||||
{
|
||||
public function canConcealComponents(): bool;
|
||||
}
|
||||
10
vendor/filament/forms/src/Components/Contracts/CanDisableOptions.php
vendored
Normal file
10
vendor/filament/forms/src/Components/Contracts/CanDisableOptions.php
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Contracts;
|
||||
|
||||
use Closure;
|
||||
|
||||
interface CanDisableOptions
|
||||
{
|
||||
public function disableOptionWhen(bool | Closure $callback): static;
|
||||
}
|
||||
41
vendor/filament/forms/src/Components/Contracts/CanEntangleWithSingularRelationships.php
vendored
Normal file
41
vendor/filament/forms/src/Components/Contracts/CanEntangleWithSingularRelationships.php
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Forms\Components\Contracts;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphOne;
|
||||
|
||||
interface CanEntangleWithSingularRelationships
|
||||
{
|
||||
public function cachedExistingRecord(?Model $record): static;
|
||||
|
||||
public function clearCachedExistingRecord(): void;
|
||||
|
||||
public function fillFromRelationship(): void;
|
||||
|
||||
public function getCachedExistingRecord(): ?Model;
|
||||
|
||||
public function getRelatedModel(): ?string;
|
||||
|
||||
public function getRelationship(): BelongsTo | HasOne | MorphOne | null;
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $data
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function mutateRelationshipDataBeforeFill(array $data): array;
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $data
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function mutateRelationshipDataBeforeCreate(array $data): array;
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $data
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function mutateRelationshipDataBeforeSave(array $data): array;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user