Fields
The Qore fields are described below in alphabetical order. Relational field can be found here: Relation fields.
Action button
An action button will call the given resource action when the user clicks on it:
ActionButton::make('Label', 'name')
->deselectOnIndexByDefault()
->forAction($this->action(MyActionClass::class))
Button
You can add a button to your resource pages that runs some PHP code:
Button::make('Buttons!', 'button_1')
->onClick(function (ButtonClickEvent $event) {
dd('button was clicked!');
})
Optionally you can customise it:
->setOutline()
->setColor('primary')
->setTextColor('primary')
->setIconRight('arrow_forward')
->setIconLeft(null)
->setDense(false)
->setCaps(false)
->setSize('md')
->setFlat(false)
->setTo('/resources/users/create') // Internal route url, don't open in new tab
->setHref('https://google.com', true) // External route url, open in new tab
->setFormClassName('q-ma-mx')
->setDetailClassName('bg-negative')
->setIndexClassName('bg-positive')
You can change the response message and display it as error:
->onClick(function (ButtonClickEvent $event) {
$event->getResponse()->setMessage('My message!')->setFailed();
})
To show a confirm prompt:
->withDialog('Hello from confirm dialog!')
->withDialog('This is with a type!', 'error') // 'error'|'positive'|'info'
You can also include fields:
->onClick(function (ButtonClickEvent $event) {
dd($event->getDialogFormState());
})
->withFields(function (ButtonFieldsResponse $response) {
$response->setFields(new FieldCollection(
Text::make('Some', 'text')
->rules('required')
));
})
Other useful functions:
->onClick(function (ButtonClickEvent $event) {
$event->getForm(); // The `ManagesForm` instance if this field exists in a form
$event->getModel(); // The model instance if we have one
})
->withFields(function (ButtonFieldsResponse $response) {
$response->setFieldLayout(...); // You can provide a `FieldLayout` here
$response->getModel(); // The model instance if we have one
$response->getParentState(); // The state from the related (parent) form
$response->getParentMeta(); // The metadata from the related (parent) form
$response->onFormReady(function(ManagesForm $form) {
$form->setSubmitButtonLabel('Hi!'); // Set the submit label when the form is ready
});
})
Parts of the Button are cached. The key for this cache is based on the name of your field (and the resource name if the field exists inside a QoreResource). So be careful not having 2 buttons with the same name, and make sure to refresh your page once to bust the cache.
If the Button field is used in a QoreResource, then the create
and update
policies are checked by default.
However, if your Button exists in a custom form, then you will need to authorise manually in the onClick
closure.
The onClick
and withFields
Closures will be stored as a SerializableClosure
. If you ever run into unexpected
problems, please visit the docs: https://github.com/laravel/serializable-closure
Checkbox
A checkbox is very straight forward:
Checkbox::make(__('Check 1'), 'check_1')
Checkbox::make(__('Check 2'), 'check_2')
->default(true)
Choice
Choice behaves like a radio button:
Choice::make(__('crm::crm.Layout'), 'crm_layout_mode')
->rules('in:tabs,cards', 'required')
->setMaxWidth('md')
->options([
[
'value' => 'tabs',
'label' => __('crm::crm.Tabs'),
'description' => __('crm::crm.Show fields in seperate tabs')
],
[
'value' => 'cards',
'label' => __('crm::crm.Cards'),
'description' => __('crm::crm.Show fields in seperate cards')
]
])
Optionally make it look denser:
Choice::make(__('crm::crm.Layout'), 'crm_layout_mode')
->dense()
Code
Adds a field where users can fill code
:
Code::make(__('Content'), 'content')
->setLanguage('twig') // or html, css etc.
->rules('required', 'string'),
Color
Adds a field where users can pick a color:
Color::make(__('Primary color'), 'primary_color')
->default($tenant->getPreference('primary_color'))
CompanyName
Most companies have the same base information: company name, coc number, vat number, address, etc.
The companyName
field can be used with the Kvk plugin to auto fill company
information
If the Kvk plugin is active you can define the name of your Kvk Field and your Address Field
with the fieldNames
method:
CompanyName::make(__('Company name'), 'company_name')
->fieldNames('kvk_number', 'address')
->rules('required'),
The first argument of the fieldnames method should be filled with the name of the Kvk field
The second argument of the method shoud be filled with the name of your Address Field
Country
By default users can only select activated countries
The Country
field can be used to assign a country to for example a user or employee:
public function fields(): FieldCollection
{
return new FieldCollection(
Country::make(__('Country'), 'country'),
}
Important to know is that the country field extends the BelongsTo
field, so your model needs to have the same
belongsTo relation to work.
CreatedAt
CreatedAt is a wrapper around DateTime, and cannot be edited
CreatedAt::make()
Currency Select
A currency code is a 3 character based code (e.g.: EUR
) and can be selected:
CurrencySelect::make(__('Currency'), 'currency')
->default(preference('currency'))
Date
Adds a date picker:
Date::make(__('Active from'), 'active_from')
->rules('nullable', 'date')
You can optionally show a "Diff for humans" for detail & index instead of showing the actual date:
Date::make(__('Active from'), 'active_from')
->displayUsingDiffForHumans(bool $onShow = true, bool $onIndex = true)
It is possible to set minimum date, maximum date, disabled dates and enabled dates.
You can set a minimum date:
Date::make('Date', 'updated_at')
->minDate(Carbon::now()->subWeek())
// Or:
->minDate(function(?Model $model) {
return Carbon::now()->subWeek();
})
You can set a maximum date:
->maxDate(Carbon::now()->addWeek())
// Or:
->maxDate(fn (?Model $model) => now()->addWeek())
You can also disable a range of dates. Qore accepts an array of Carbon instances, but you can also supply arrays that contain exactly 2 Carbon dates (min and max date):
->disabledDates([Carbon::now()->addDays(1)])
// Or:
->disabledDates(function(?Model $model) {
return [
Carbon::now()->addDays(1),
];
})
// Disable tomorrow, and next week, and next month:
->disabledDates(function(?Model $model) {
return [
Carbon::now()->addDays(1),
[Carbon::now()->addWeeks(1), Carbon::now()->addWeeks(2)],
[Carbon::now()->addMonths(1), Carbon::now()->addMonths(2)],
];
})
You can also specify only enabled dates (syntax same as ->disabledDates
)
// Only today is enabled:
->enabledDates([Carbon::today()])
// Every date is disabled, except:
->enabledDates(function(?Model $model) {
return [
Carbon::now()->addDays(1),
[Carbon::now()->addWeeks(1), Carbon::now()->addWeeks(2)],
[Carbon::now()->addMonths(1), Carbon::now()->addMonths(2)],
];
})
Please note that you will have to add validation yourself
DateTime
Adds a datetime picker:
DateTime::make(__('Planned at'), 'planned_at')
->rules('nullable', 'date', 'after_or_equal:now')
You can optionally show a "Diff for humans" for detail & index instead of showing the actual date time:
DateTime::make(__('Planned at'), 'planned_at')
->displayUsingDiffForHumans(bool $onShow = true, bool $onIndex = true)
Furthermore, most Date
field features should work on this field too.
DetailButton
You can add a button to you index tables which will open a dialog which contains some information:
DetailsButton::make(__('Details'), 'metadata')
->displayUsing(function($value, Model $model) {
return 'Hello world';
})
You can also use a HTML string:
DetailsButton::make(__('Details'), 'metadata')
->displayUsing(function($value, Model $model) {
return '<h1>Hello world</h1>'
})
->setDialogWidth(1200)
->asHtml(),
Duration
You can add a duration field:
Duration::make(__('Every'), 'duration')
The value of this field will be of type: int
.
Customization
You can enable/disable different units by calling the disable
function for every unit:
Duration::make(__('Every'), 'duration')
->disableDays()
->disableMinutes(disable: false)
By default the seconds & days units are disabled
Setting a default can be done by either sending a CarbonInterval, or by sending the seconds to the field:
Duration::make(__('Every'), 'duration')
->default(100) # 100 seconds
->default(CarbonInterval::minutes(5))
You can change the step of certain units:
Duration::make(__('Every'), 'duration')
->secondsStep(30)
->minutesStep(15)
You can also call ->step()
to change the step of all units at the same time
You can change the way the field is displayed in Tables, by calling the prettyPrint
function:
Duration::make(__('Every'), 'duration')
->prettyPrint()
Duration::make(__('Every'), 'duration')
->prettyPrint('%d-%H:%i:%s') # or with a custom format
This will change the displayUsing
option of the field, if you are implementing a custom one you shouldn't use this
Validation
This field represents it's value with seconds, but for simplicity you can call the min
& max
functions which will
automatically convert CarbonIntervals to seconds and append the rule to the list of rules
Duration::make(__('Every'), 'duration')
->min(CarbonInterval::minutes(10))
->max(CarbonInterval::minutes(60))
EncryptedText
Make sure you know:
- The definition of encryption
- The difference between encoding, hashing and encryption
When you have a field where you would store sensitive data (for example an authorization key or token), you can use
a EncryptedText
:
EncryptedText::make(__('API Token'), 'api_token'),
The contents of this field will be encrypted and stored in the database. Upon retrieval, it will be decrypted.
In the front-end the content will be masked until the user manually clicks on the "eye" button.
Hiding the toggle 'show' icon
->preventToggle()
Showing the 'copy to clipboard' icon
->showClipboard()
Without model
If for some reason you use this field without model (for example an extension settings page)
Make sure to decrypt the value before assigning it as default value.
EncryptedText::make(__('nmbrs::settings.auth.key'), 'auth_token')
->default(Illuminate\Support\Facades\Crypt::decrypt($myToken))
Make sure to encrypt the value before saving.
$myEncryptedToken = Illuminate\Support\Facades\Crypt::encrypt($data['auth_token'])
FilePicker
File picker allows file uploads:
use Qore\System\Fields\FilePicker;
FilePicker::make('Contract', 'contract')
You can have specific rules:
->rules('nullable', 'mimes:pdf', 'max:2000'),
Or multiple:
->multiple()
On file fields you can chain the function ->setStorageDisk()
which expects the name of the storage disk to store files
on different disks. To set the default storage disk u can use the ENV variable MEDIA_DISK
which defaults to public
.
->setStorageDisk(...)
When having multiple on the filepicker field, you might want to limit the number of files being uploaded. In this case you can add a specific rule on this field:
->rules('max_files:3', 'min_files:1')
Max or min will still work on the size of individual files.
Like the Image
field, you need to add the following to your model:
class MyModel extends Model implements HasMedia
{
use InteractsWithMedia;
// ..
}
Make sure you don't have any relationship methods on your model that have the same name as the field name you are using, as it will cause conflicts / unexpected behaviour.
Heading
If you want to have a subtitle in for example your User create / edit form you can do this by defining the Heading
field:
By default the heading field is hidden on index and show page.
available methods on Heading
field:
withParagraph()
: adds a paragraph under theHeading
fieldwithDivider()
: adds a separator line under the heading
public function fieldLayout(bool $forDetail, ?Model $model = null): ?FieldLayout
{
return (new FieldLayout())
->column('heading')
}
public function fields(): FieldCollection
{
return new FieldCollection(
Heading::make(__('Heading'), 'heading')
->withParagraph('paragraph')
->withDivider()
->preventFill(),
}
Just like the Paragraph
field, ->asHtml()
is supported for the paragraph, and you can update the contents of the
paragraph dynamically:
Heading::make('Heading', 'heading')
->asHtml()
->withParagraph('Hello world'),
BelongsTo::make(__('Some field'), 'some_name', SomeResource::class)
->setMaxWidth('md')
->onUpdate(function (ManagesForm $form, $id){
$form->setFieldData(
'heading',
'message',
'<strong>MY</strong> new message'
);
}),
Id
Show the ID of the model, only for displaying:
Id::make()
->deselectOnIndexByDefault()
Image
The image
field extends the Field
class, by default the image
field only accepts single image upload:
use Qore\System\Fields\Image;
Image::make('Foto', 'photo');
You can allow the user the paste an external image URL:
Image::make('Foto', 'photo')
->allowFromUrl()
If you want to accept multiple images at the same time you can add the multiple
method:
use Qore\System\Fields\Image;
Image::make('Foto', 'photo')
->multiple();
When having multiple on the image field, you might want to limit the number of images being uploaded. In this case you can add a specific rule on this field:
->rules('max_files:3', 'min_files:1')
Max or min will still work on the size of individual images.
The Image
field is provided with an image editor so the user can edit the image before upload. The aspect ratio of the
image is not set by default, and the user is provided the option to crop the image. if you want to use a fixed aspect
ratio you can do so by adding the aspectRatio
method:
use Qore\System\Fields\Image;
Image::make('Foto', 'photo')
->multiple()
->aspectRatio(23/9);
By default, the Image
field has the edit button to edit images with. If you wish to disable this edit button you can
use the hideEditButton
method.
use Qore\System\Fields\Image;
Image::make('Foto', 'photo')
->hideEditButton();
You can set the width that an Image will take on either the Index or Detail page by calling the following functions.
Image::make(__('Image'), 'image')
// you can also use 'xs', 'sm', 'md', 'lg', 'xl'
->setDetailMaxWidth(500) // set the width of image (images) on the Detail page
->setIndexMaxWidth(50) // set the width of image (images) on the Index table cell
->setImageMaxWidth(500), // set the width of image (images) on both the Detail & Index page
In the case of images (multiple), each individual field will use the width that was set.
Like the FilePicker
field, you need to add the following to your model:
class MyModel extends Model implements HasMedia
{
use InteractsWithMedia;
// ..
}
Make sure you don't have any relationship methods on your model that have the same name as the field name you are using, as it will cause conflicts / unexpected behaviour.
If you want to edit images in the back-end, please see Other tools
MaterialIconSelect
Lets the user select an icon from the supported Quasar 1 material icons.
use Qore\System\Fields\MaterialIconSelect;
MaterialIconSelect::make(__('qore::system.Icon'), 'icon');
MediaSelect
Similarly to FilePicker
field, you can upload files or choose existing media with the MediaSelect
field:
MediaSelect::make('Media', 'media')
The media that could be selected is dependent on the permissions of the authorized user.
Like the FilePicker
field, your model needs to implement the HasMedia
trait.
Please note that when you add ->rules('required')
, that it will fail on the edit page when the user does not add any
new media. In this case it's better to use ->createRules('required')
. For the ->editRules
you will have access to
the model in order to do validation.
Month
The month field makes it possible to select a month and a year:
use Qore\System\Fields\Month;
Month::make('Maand', 'my_date_column')
Number
Adds a numeric input:
Number::make(__('Value'), 'rate')
->rules('required', 'numeric', 'not_in:0')
Form values affix
Numeric form inputs can be prefixed or suffixed.
return Number::make(__('Estimate'), 'estimate')
->withPrefix('$')
->withSuffix('Monthly')
Affixing currency symbols.
Countries present currency symbols differently.
withCurrencySymbol()
can be used. Where to place this symbol will be determined in the background based on the request
user's locale.
return Number::make(__('Estimate'), 'estimate')
->withCurrencySymbol('$')
Decimals
By default, decimals are not allowed, you can however allow them:
Number::make(__('Value'), 'rate')
->allowDecimals() // 2 by default
// or
->allowDecimals(10)
Validation
By default any numeric input is valid, however you can set a valid range for the field by using min
, max
or between
:
Number::make('estimate', 'estimate')
->min(0)
->max(800)
// or
->between(0, 800);
To add steps to the front-end, use step
:
Number::make('estimate', 'estimate')
->step(0.2);
Paragraph
If you want to display a piece of text or HTML, you can do so by defining the Paragraph
field:
by default the paragraph field is hidden on index and show page.
Paragraph::make(__('Paragraph'), 'paragraph')
You can also define a type:
Paragraph::make(__('Paragraph'), 'paragraph')
->type('warning')
By default, the label will be used for the text. You can also supply HTML there.
In some cases you want the text to be changed dynamically, you can set the data
message
for the field:
Paragraph::make(__('Warning message'), 'warning')
->setMaxWidth('lg')
->type('warning'),
BelongsTo::make(__('Some field'), 'some_name', SomeResource::class)
->setMaxWidth('md')
->onUpdate(function (ManagesForm $form, $id){
$form->setFieldData(
'warning',
'message',
__('My new message')
);
}),
Phone
The phone field automatically validates and formats the users' input.
The data is stored as json, for example your migration may look like this:
$table->json('phone_1')->nullable();
And in the model:
protected $casts = [
'phone_1' => 'array'
];
By default, the default country is selected. You can modify this:
Phone::make(__('Phone'), 'phone')
->country('NL')
All active countries are selectable in the dropdown. You can change this however.
To make all countries selectable:
Phone::make(__('Phone'), 'phone')
->country('NL')
->selectableCountries('*')
Only make the following countries selectable:
Phone::make(__('Phone'), 'phone')
->country('NL')
->selectableCountries('NL', 'US', 'DE')
Place
In order to fully make use of address fields you have to include the postcode
and or geocoding
plugins.
Please see Other tools for more info
The place field will include fields like zipcode, a house number, an addition, a street and more (based on selected country):
Place::make(__('Bezoek adres'), 'address_1')
Places are stored as json, for example your migration may look like this:
$table->json('address_1')->nullable();
And in the model:
protected $casts = [
'address_1' => 'array'
];
The display value is determined by which country is selected. The full_name
attribute of the json value will be used
for this. If you wish, you can of course have a different display value:
Place::make(__('Adres'), 'address_1')
->displayUsing(function(array $address) {
return [
'full_name' => $address['zipcode'] . ' ' . $address['province']
];
})
You can enable displaying a map on the detail page:
Place::make(__('Adres'), 'address_1')
->withMap(true)
By default, the default country is selected. All active countries are selectable in the dropdown. You can modify this:
Place::make(__('Adres'), 'address_1')
->country('NL')
Sometimes the customer wants to select a different address based on the state of the form. For example, when an organization is selected, the user may want to switch between addresses. You can achieve this by setting the field data via another field:
$form->setFieldData(
'address',
'selectable_addresses',
$addresses->map(function (Address $address) use ($addressMapper) {
return [
...$addressMapper($address),
'full_name' => $address->full_name,
'label' => $address->label
];
})->toArray()
);
PreferenceSelect
Wrapper around Select
field which will add options for known preferences
automatically:
PreferenceSelect::make(__('Date format'), 'date_format')
->default(preference('date_format'))
Price
Wrapper around Number
field which allows for decimals and adds valuta symbol:
Price::make(__('invoicing::invoicing.Danger amount'), 'danger_amount')
->rules('numeric', 'not_in:0', 'min:0')
Rating
Wrapper around Number
field which implements the QRating
component from quasar:
Rating::make(__('Rating'), 'rating') // the field expects the column in the DB to be number
You can use any settings available in the QRating Quasar Component:
// all settings from the Rating component in Quasar can be changed
Rating::make(__('Rating'), 'rating')
->size('md')
->color('primary')
->icon(['settings', 'manufacturing'])
->maxIcons(10) // set the max amount of the field to 10 icons (rule isn't added by default)
RelatedToMany
Wrapper around BelongsToMany
field which allows models to relate to eachother, for example, an organization
could relate to many other relatives
:
RelatedToMany::make(__('Organization Relatives'), 'relatives', $this->resourceClass())
->rules('nullable', 'exists:organizations,id')
->withRelationalDisplay(function (Model $model) {
$title = $model->name;
if ($model->addresses->count() > 0) {
$title .= ', ' . $model->addresses->first()->residence;
}
return $title;
})
->withoutAttaching()
->deselectOnIndexByDefault()
Relation Table
Sometimes you just need to show a custom table with custom columns and data without needing another resource.
You can achieve this:
RelationTableField::make('Hobbies', 'hobbies')
->columns(new ColumnCollection(
Text::make('Name', 'name'),
))
// Use the model
->query(function (?Model $employee) {
return $employee->hobbies()->practicing();
})
// or a query
->query(\App\Models\Tenant\Hobbies::query())
Repeater
The Repeater field makes it possible to repeat fields in a Form and allows the user to add and delete rows.
A basic example:
Repeater::make('My repeated', 'my_column')
->fields(new FieldCollection(
Text::make('Hello repeater!', 'repeat')
->setRepeatedWidth(200) // The width of this field
->default('Hello world')
->rules('required', 'min:3'),
Checkbox::make('Check!', 'check')
))
By default, the value (array) is stored as json. In this case, the data will be stored in the my_column
column. This
means that you need a cast on your model:
protected $casts = [
'my_column' => 'array'
];
Often though, you will probably not want to save the value. In that case you can add fillLazyUsing
on the field:
Repeater::make('My repeated', 'my_column')
->fillLazyUsing(function(Model $model, array $data) {
// dd($data)
})
The Repeater is quite large by default, you can set it to dense. You can also set the layout to vertical.
Repeater::make('My repeated', 'my_column')
->dense()
->vertical() // 1 field per row
The Repeater field holds an array as its value inside a form. If you would like to set the state of this field, you will
have to pass an array that also includes a uuid
.
In the following example a Button field will set the state for the Repeater field:
Repeater::make('My repeated', 'my_column')
->fields(new FieldCollection(
Text::make('Hello repeater!', 'repeat'),
Button::make('Button support!', 'button')
->hideOnShow()
->onClick(function(ButtonClickEvent $event) {
if ($event->getForm()) {
$rowIndex = $event->getMetadata('row_index');
$dialogState = $event->getDialogFormState();
$currentState = $event->getForm()->getState('my_column');
$currentState[$rowIndex]['repeat'] = $dialogState['hello'];
$event->getForm()->setState('my_column', $currentState);
}
})
->withFields(function(ButtonFieldsResponse $response) {
$response->setFields(new FieldCollection(
Text::make('Hello', 'hello')
));
})
)),
Please note that some functionality is limited or disabled for repeatable fields.
Only a handful of fields are now repeatable (
like Text
, Textarea
, Select
, Button
, Checkbox
, BelongsTo
, BelongsToMany
, Date
, DateTime
),
however most fields can be made repeatable easily.
If you want to create your own Repeatable field, or make an existing field repeatable, you need to add the following
interface to your field: FieldIsRepeatable
.
You can then optionally override methods in your field if necessary (BelongsToMany
example):
public function getRepeatedFormValue(mixed $value, Model $model): mixed
{
if ($value) {
return json_decode($value);
}
return [];
}
public function getRepeatedDisplayValue(mixed $value, Model $model): mixed
{
if (is_null($value)) {
return null;
}
$value = $this->otherResource->model()::whereIn('id', json_decode($value))->get();
return $value->map(function (Model $model) {
return array_merge([
'id' => $model->id,
'url' => $this->otherResource->url($model->id),
'title' => $this->otherResource->modelTitle($model)
], $this->otherResource->toHttpResource($model)->toArray(request()));
});
}
In your Field.vue
in the front-end, you will receive 3 props: isRepeated
, repeatedIndex
and dense
. Based on
these props you can adjust your field to work well as a repeatable.
When the field is cleared, and you want Qore to add at least one row, you can add the following:
->notEmptyOnNull()
You can set the maximum amount of rows:
->max(5)
You can disallow deleting rows:
->deletable(false)
Metadata in repeater
You can set the field meta for a repeater field using dot notation. Keep in mind that this meta will be the same for each row.
Repeater::make('My repeater', 'my_repeater')
->fields(new FieldCollection(
Text::make('Text 1', 'text_1'),
BetterTime::make('Time', 'time')
->withMinuteInterval(30)
->withoutDropdown()
)),
Text::make('Name', 'name')
->onUpdate(function(ManagesForm $form) {
$form->setFieldMeta('my_repeater', 'fields.time.minuteInterval', 5);
})
Repeater sort order
You can allow the user to sort the rows in the repeater field by calling the draggable
method:
Repeater::make('My repeater', 'my_repeater')->draggable()
Select
Select works like a dropdown:
Select::make(__('Type'), 'type')
->options([
[
'value' => 'container',
'label' => 'Container'
]
])
->default('container')
->rules('required', 'in:container')
Optionally, you can also supply a description, group, or disable:
Select::make(__('Type'), 'type')
->options([
[
'value' => '1',
'label' => 'Option 1',
'description' => 'My description'
],
[
'group' => 'My group',
'disable' => true,
],
[
'value' => '2',
'label' => 'Option 2',
'disable' => true
],
])
If you want to change the options based on the state of the form:
$form->setFieldData(
'type',
'options',
[...]
);
Select Enums
Instead of supplying options, you can also pass in an Enum
:
Select::make('Ticket category', 'category')
->forEnum(TicketType::class)
->setColumnStyle(function (TableDataStyler $styler, Model $model) {
if ($model->category === 'bug') {
$styler->setRowClass('bg-red-1');
}
})
By default, it will use all enum cases as options. Qore will check if the following methods exists on your
enum: label
, description
, options
.
Your Enum may look like this:
<?php
namespace App\Enums;
enum TicketType: string
{
case SUPPORT = 'support';
case BUG = 'bug';
case QUESTION = 'question';
// Label per case (optional but recommended)
public function label(): string
{
return match($this) {
self::SUPPORT => __('Support ticket'),
self::BUG => __('Support bug'),
self::QUESTION => __('Support question'),
};
}
// Description per case (optional)
public function description(): string
{
return match($this) {
self::SUPPORT => __('Description for Support'),
self::BUG => __('Description for Bug'),
self::QUESTION => __('Description for Question'),
};
}
/* Override the options manually (optional)
public static function options(): array
{
return [
[
'label' => 'Bug',
'value' => 'bug'
],
[
'label' => 'Question',
'value' => 'question'
],
];
}
*/
}
Select Validation
When supplying options, by default validation will be added from the field. The rule In
will include all option
values.
You can disable this by supplying false
in the last parameter:
public function options(
array $options,
string $valueKey = 'value',
string $labelKey = 'label',
bool $addRule = true
)
// Or when working with Enum:
public function forEnum(string $enumClass, bool $addRule = true)
Separator
by default the separator field is hidden on index and show page.
The Separator
field can be used to add a separator between your fields:
public function fieldLayout(bool $forDetail, ?Model $model = null): ?FieldLayout
{
return (new FieldLayout())
->column('separator')
}
public function fields(): FieldCollection
{
return new FieldCollection(
Separator::make(__('Separator'), 'separator')
->preventFill(),
}
Slider
The Slider class extends the Number class, providing a specialized component for creating slider input fields with additional customization options. The main features of the Slider class include:
- Snap to Steps: The snap method enables the slider to snap to defined steps.
- Display Current Value Label: The label method allows the slider to display a label with the current value.
- Display Markers: The markers method adds markers along the slider track.
- Vertical Orientation: The vertical method switches the slider to a vertical orientation.
- Reverse Orientation: The reverse method reverses the direction of the slider.
- Always Show Label: The labelAlways method ensures the label with the current value is always visible.
// Enables snap to steps
$field->snap():
// Displays a label with the current value
$field->label():
// Displays markers along the slider
$field->markers():
// Displays the slider vertically
$field->vertical():
// Reverses the slider direction
$field->reverse():
// Always shows the label with the current value
$field->labelAlways():
In addition to these methods, the methods from the Number field are also available for use
Set min
$field->min(int):
$field->max(int):
$field->between(int, int):
$field->step(int):
SerialNumber
This field will automatically generate & show a serial number for your resource. The name of the field should match one of your database serial numbers.
SerialNumber::make(__('Serial number'), 'serial_number', 'organizations')
SimpleEditor
When you need textarea, but with a few functionalities like making some text bold, you can use the SimpleEditor field. This is a lightweight WYSIWYG editor:
SimpleEditor::make(__('My description'), 'description')
SettingSelect
Wrapper around Select
field which corresponds to config/components.php
:
SettingSelect::make(__('2FA required for everyone'), '2fa_required')
->forComponent('authentication')
->hideClearButton()
->default(setting('authentication', '2fa_required'))
Status
Wrapper around Select
field which shows a color per option:
Status::make(__('mailing::mailing.Status'), 'status')
->setColumnWidth(200)
->statuses([
[
'value' => 'error',
'label' => __('mailing::mailing.Error'),
'color' => 'negative',
],
[
'value' => 'pending',
'label' => __('mailing::mailing.Pending'),
'color' => 'grey-9',
],
[
'value' => 'planned',
'label' => __('mailing::mailing.Planned'),
'color' => 'primary',
],
[
'value' => 'queued',
'label' => __('mailing::mailing.Queued'),
'color' => 'blue-6',
],
[
'value' => 'sent',
'label' => __('mailing::mailing.Sent'),
'color' => 'positive',
]
])
Text
Simple text field:
Text::make(__('Name'), 'name')
->default(auth()->user()->name)
->setMaxWidth('sm')
Optionally set attributes:
->withAttributes([
'type' => 'email'
])
Textarea
Simple textarea field:
Textarea::make('Omschrijving', 'description')
Time
For the Time field you will need a string
column in the database.
Time::make(__('Arrival time'), 'arrival_time')
->rules('required')
You can also force time intervals, for example only quarters like 10:00, 10:15 etc.:
Time::make(__('Arrival time'), 'arrival_time')
->minuteOptions(Time::$FIFTEEN_MINUTES_INTERVAL)
->rules('required')
You can choose to use a 24-hour format:
Time::make(__('Arrival time'), 'arrival_time')
->use24hFormat()
BetterTime
For the BetterTime field you will need a string
column in the database.
BetterTime::make(__('Start time'), 'start_time')
->rules('required')
Configuration
The BetterTime field uses vue2-timepicker which comes with
comprehensive configuration.
The field currently supports a small subset of these configurations:
-
minuteInterval(int $interval, bool $validate = true)
Sets the minuteInterval for the field. If set to 5, the user will be able to select [5, 10, ... 50, 55].
If validate
is set to true a validation rule will be applied to check the minute interval.
-
setHourRange/setMinuteRange(array $range, bool $validate = true)
Sets the range for hours/minutes that a user can choose from.
When [5, 10, [20, 30]]
is used the user will be able to pick from [5,6,7,8,9,10,20,21,22 ... 28, 29, 30]
If validate
is set to true a validation rule will be applied to check if the submitted hour/minute is in the given
range.
-
hideDisabledItems(bool $hide)
Hides the disabled items, for example when using minuteInterval = 5
, minutes 1, 2, 3, 4, 6, ...
will be hidden. When
using a range, values outside this range will be hidden.
TwigTemplate
Wrapper around Wysiwyg, but adds twig tag support:
TwigTemplate::make(__('Content'), 'content')
->rules('required', 'string')
UpdatedAt
UpdatedAt is a wrapper around DateTime, and cannot be edited
UpdatedAt::make()
VariableValue
Wrapper around BelongsTo
field, which uses the tenant_variable_values
table:
VariableValue::make(__('Type'), 'type')
->forVariable(tenant_variable('address types'))
->hideClearButton()
VatNumber
If you want to validate the VatNumber (VAT) of a company you can use the VatNumber field.
The VatNumber field
validates the filled in number and will return if the number is valid or not.
If you want to check that the company name is the same as the company name of the checked VatNumber number,
you can achieve that by using the setCompanyField
method:
VatNumber::make(__('VatNumber number'), 'btw_number')
->setCompanyField('company_name')
->rules('required')
Now the VatNumber field
will show visually a warning if the names are not equal.
Validation
The VatNumber
field uses the VatValidator
client to validate.
The VatValidator can be used outside of the field, by calling it statically.
It has 2 methods:
validateVatNumber()
This function will use the validateVatFormat
and combine it with the getVatInfo
.
Besides checking for the format, it will also query the EU API to check wether that VAT is valid.
When setting the setCompanyField
on the VAT Number, the company value from getVatInfo
will be used for validation.
VatValidator::validateVatNumber('NL854564354B01'); //return boolean true (VAT format valid & it exists)
VatValidator::validateVatNumber('NL854564354B02'); //return boolean false (VAT format valid & VAT doesn't exist)
validateVatFormat()
This function cheks the format of a VAT. It will use regex to check if the string matches the specified countries format.
VatValidator::validateVatFormat('RO999999999'); //return boolean true
VatValidator::validateVatFormat('RX00000000000'); //return boolean false
getVatInfo()
This function retrieves data from the EU API about a certain VAT number. The following data is retrieved:
VatValidator::getVatInfo('NL854564354B01');
// returns the following array:
[
'countryCode' => string
'vatNumber' => string,
'valid' => bool,
'name' => string, // company name
'address' => string
]
Website
The website field will add http(s)://
and check the validity of an url:
Website::make(__('Website'), 'website')
If you only want to accept websites that are online at the moment (websites that return a 200
response):
Website::make(__('Website'), 'website')
->demandOnlineWebsite()
Wysiwyg
if you want to use a what you see is what you get
editor you can use the Wysiwyg
field. By default you get a very
minimal wysiwyg editor, you can change this by overwriting the advanced
method:
public function fields(): FieldCollection
{
return new FieldCollection(
Wysiwyg::make('wysiwyg', 'wysiwyg')
->advanced(),
}
You can also set some default options:
public function fields(): FieldCollection
{
return new FieldCollection(
Wysiwyg::make('wysiwyg', 'wysiwyg')
->defaultHeight(400)
->defaultFontFamily('Tahoma')
->defaultFontSize(12)
}
The field also supports variables:
->withTwig()
->withVariables([
'Variable group 1' => [
'organization.name',
'organization.number'
],
'Variable group 2' => [
'organization.city',
'organization.country_name'
]
]);
the content of the field can be very long so make sure in your migration you set the field type to longtext
public function up()
{
Schema::create('wysiwyg', function (Blueprint $table) {
$table->longText('wysiwyg')->nullable();
});
}
Purify
Content will be purified by default (remove potential malicious code).
You can override or disable purifying by using the purifyUsing
method:
Wysiwyg::make('Content', 'my_editor')
->purifyUsing(function(Model $model, ?string $content) {
return $content;
})