Элементы формы (Поля)
- Text
- Number
- Password
- Hidden
- Date
- Datetime
- Time
- File
- Image
- Images
- Textarea
- Select
- DependentSelect
- Multi Select
- Select Ajax
- Multi Select Ajax
- Wysiwyg
- Ckeditor
- Checkbox
- Radio
- Belong To
- Has Many
- Many To Many
- Html
- Custom
- View
- Upload
- API
В качестве элемента формы может выступать любой класс, которые реализует интерфейс Illuminate\Contracts\Support\Renderable.
Для полноценной работы класс поля должен реализовать интерфейс SleepingOwl\Admin\Contracts\FormElementInterface
Text
Обычное текстовое поле <input type="text" />
AdminFormElement::text(string $key, string $label = null): static
$key- Ключ поля$label- Заголовок
Number
Числовое поле <input type="number" min max step />
AdminFormElement::number(string $key, string $label = null): static
$key- Ключ поля$label- Заголовок
Доступные методы
setMin(int $min): static
Указание минимального допустимого значения
$field->setMin(10);
setMax(int $max): static
Указание максимального допустимого значения
$field->setMax(100);
setStep(int $step): static
Указание шага
$field->setStep(5);
Password
Поле для ввода пароля <input type="password" />
AdminFormElement::password(string $key, string $label = null): static
$key- Ключ поля$label- Заголовок
Доступные методы
allowEmptyValue(): static
Если пароль указан для текущего поля, то при валидации будет игнорироваться правило required
hashWithBcrypt(): static
Перед сохранением применить к паролю функцию bcrypt
hashWithMD5(): static
Перед сохранением применить к паролю функцию md5
hashWithSHA1(): static
Перед сохранением применить к паролю функцию sha1
Hidden
AdminFormElement::hidden(string $key): static
$key- Ключ поля
Date
Поле для ввода даты (использует javascript календарь http://eonasdan.github.io/bootstrap-datetimepicker/)
AdminFormElement::date(string $key, string $label = null): static
$key- Ключ поля$label- Заголовок
Доступные методы
setFormat(string $format): static
Указание формата хранения даты в БД (По умолчанию: Y-m-d)
setPickerFormat(string $format): static
Указание формата отображения даты в поле (По умолчанию значение из конфига config('sleeping_owl.dateFormat'))
setCurrentDate(): static
Установка текущей даты, если значение не указано
Datetime
Поле для ввода даты и времени (использует javascript календарь http://eonasdan.github.io/bootstrap-datetimepicker/)
AdminFormElement::datetime(string $key, string $label = null): static
$key- Ключ поля$label- Заголовок
Доступные методы
setFormat(string $format): static
Указание формата хранения даты в БД (По умолчанию: Y-m-d H:i:s)
setPickerFormat(string $format): static
Указание формата отображения даты в поле (По умолчанию значение из конфига config('sleeping_owl.datetimeFormat'))
setCurrentDate(): static
Установка текущей даты, если значение не указано
setSeconds(): static
Показывать секунды в поле
Time
Поле для ввода времени (использует javascript календарь http://eonasdan.github.io/bootstrap-datetimepicker/)
AdminFormElement::time(string $key, string $label = null): static
$key- Ключ поля$label- Заголовок
Доступные методы
setFormat(string $format): static
Указание формата хранения даты в БД (По умолчанию: H:i:s)
setPickerFormat(string $format): static
Указание формата отображения даты в поле (По умолчанию значение из конфига config('sleeping_owl.timeFormat'))
File
Поле для загрузки файла. Загрузка файлов происходит через ajax и возвращает строку (относительный путь до файла).
AdminFormElement::file(string $key, string $label = null): static
$key- Ключ поля$label- Заголовок
Доступные методы
setUploadPath(Closure $uploadPath): static
Указание пути сохранения файла ** Путь должен начинаться относительно папки public и не должен содержать название файла!**
В анонимную функцию будет передан объект загружаемого файла \Illuminate\Http\UploadedFile $file
$field->setUploadPath(function(\Illuminate\Http\UploadedFile $file) {
return 'files'; // public/files
});
setSaveCallback(Closure $callable): static
Имплемент своей логики сохранения и обработки файла
В анонимную функцию будет переданы все параметры обычного сохранения файла
[
\Illuminate\Http\UploadedFile $file - объект загружаемого файла,
$path -директория куда якобы должен быть сохранен файл,
$filename - имя файла якобы сгенерированное самим элементом,
$settings - опции заданные методом setUploadOptions
]
Все методы сохранения файлов сейчас должны возвращать json объект для двух данных json_encode([‘value’ => ‘тут полная ссылка или относительный path на картинку’, ‘url’ => ‘тут только полная ссылка на файл’])
Пример использования
AdminFormElement::images('some_images', "Some Label")->setSaveCallback(function ($file, $path, $filename, $settings) use ($id) {
//Здесь ваша логика на сохранение картинки
$result = $youimage;
return ['path' => $result['url'], 'value' => $result['path|url']];
}),
Способ передачи модели не был найден - потому можно в примере найти use ($id) и использовать в колбеке нахождение модели через ID. Полезно когда нужно сохранить картинку после обработки в отношение с другой моделью. В этом моменте мы и открываем пользователям грань тонкого мышления и обработки фотографий таким образом, какой нужен именно вам. Колбек используется поверх всех сохранений, а значит вызвав его, вы прервете все сохранения на стороне админки. Позже это доработается до принятия некого интерфейса подачи на вход контроллера, класса и возможно целой экосистемы. Всем удачи
setUploadFileName(Closure $fileName): static
Указание имени файла
В анонимную функцию будет передан объект загружаемого файла \Illuminate\Http\UploadedFile $file
$field->setUploadFileName(function(\Illuminate\Http\UploadedFile $file) {
return $file->getClientOriginalName().'doctrine-meta'.$file->getClientOriginalExtension();
});
maxSize(int $size): static
Указание максимального размера загружаемого изображения (в байтах)
minSize(int $size): static
Указание минимального размера загружаемого изображения (в байтах)
Image
Загрузка файлов происходит через ajax и возвращает строку (относительный путь до файла).
При загрузке изображений, файлы проходят валидацию image
AdminFormElement::image(string $key, string $label = null): static
$key- Ключ поля$label- Заголовок
Доступные методы
Для данного поля доступны все методы поля File
setUploadSettings(array settings)
Указание настроек для обработки загружаемого изображения.
Обработка изображений
Для возможности обработки изображений при сохранении вам необходимо подключить пакет intervention/image и добавить сервис провайдер. Установить пакет можно помощью командной строки
$ composer require intervention/image
После установки пакета необходимо добавить сервис провайдер
Intervention\Image\ImageServiceProviderLaravel5::class,
в соответствующий раздел providers файла config/app.php:
После подключения пакета можно использовать фильтры пакета через метод setUploadSettings.
Пример
$field->setUploadSettings([
'orientate' => [],
'resize' => [1280, null, function ($constraint) {
$constraint->upsize();
$constraint->aspectRatio();
}],
'fit' => [200, 300, function ($constraint) {
$constraint->upsize();
$constraint->aspectRatio();
}]
]);
Ключем массива выступает название фильтра, например resize, в качестве значения массива передается массив аргументов, которые будут переданы в эту функцию. Т.е. после передачи настроек итератор пройдется по всем элементам массива и сделает вызов call_user_func_array($key, $value)
Наглядный пример
$image = \Intervention\Image\Facades\Image::make($file)
call_user_func_array([$image, 'resize'], [1280, null, function ($constraint) {
$constraint->upsize();
$constraint->aspectRatio();
}])
Images
Загрузка файлов происходит через ajax и возвращает строку (относительный путь до файла).
При загрузке изображений, файлы проходят валидацию image
При сохранении поля в модель передается массив изображений.
AdminFormElement::images(string $key, string $label = null): static
$key- Ключ поля$label- Заголовок
Доступные методы
Для данного поля доступны все методы поля Image
storeAsJson(): static
При сохранении преобразовать массив в json строку
draggable(boolean) (по умолчанию true)
Принудительное отключение сортировки изображений
storeAsComaSeparatedValue(): static
При сохранении преобразовать массив в строку с разделителем “,”
setAfterSaveCallback()
Этот метод полезен когда нужно сколлектировать логику сохранения изображений и привязываний их в модель Пример
->setAfterSaveCallback(function ($value, $model) {
if ($value) {
//... сюда приходит value с поля и модель после сохранения
//... Имейте ввиду что этот колбек вызовется только после всех валидаций и сохранения модели
}
})
Textarea
Поле для ввода текста <textarea></textarea>
AdminFormElement::textarea(string $key, string $label = null): static
$key- Ключ поля$label- Заголовок
Доступные методы
setRows(int $rows): static
Указание кол-ва видимых строк
Select
Поле для выбора значения из выпадающего списка (использует javascript пакет https://select2.github.io/)
AdminFormElement::select(string $key, string $label = null, array|Model|string $options = []): static
$key- Ключ поля$label- Заголовок$options- Данные- При передаче массива, он будет использован в качестве значений
- При передаче объекта модели, будут использованы ее значения
Доступные методы
setModelForOptions(string|\Illuminate\Database\Eloquent\Model $model, string $titleKey = null): static
Указание модели в качестве элементов списка
$titleKey- Смотри методsetDisplay
setDisplay(string $titleKey): static
Указание поля модели, используемого в качестве заголовка
setFetchColumns(...$columns): static
При использовании модели указание списка загружаемых полей в select
$field->setFetchColumns('title');
$field->setFetchColumns(['title']);
$field->setFetchColumns(['title', 'position']);
setLoadOptionsQueryPreparer(Closure $callback): static
При использовании модели перед загрузкой списка возможность изменения запроса
В анонимную функцию будут переданы
$element- текущий объект Select$query- текущий запрос на получение спсика
$field->setLoadOptionsQueryPreparer(function($element, $query) {
return $query
->where('column', 'value')
->where('owner_id', $element->getModel()->author_id)
})
setOptions(array $options): static
Указание элементов списка
setEnum(array $options): static
Указание элементов списка не содержащего ключей (в качестве ключей будут использованы значения массива)
setSortable(bool $sortable)
Установка атрибута для сортировки элементов списка по алфавиту (по умолчанию сортировка включена)
nullable(): static
Возможность оставлять поле пустым
exclude(array $keys): static
Исключение из списка элементов
setUsageKey($key)
Изменение ключа сохранения
AdminFormElement::select('role_id', 'Роль', Role::class)
->setUsageKey('new_id'),
Select Ajax
Отдельная благодарность https://github.com/hkd213
Поле для выбора значения из выпадающего списка с помощью технологии ajax (использует javascript пакет https://select2.github.io/). Рекомендуется использовать в том случае, если кол-во элементов списка слишком велико для обычного select, и сильно увеличивает время загрузки страницы.
AdminFormElement::selectajax(string $key, string $label = null): static
$key- Ключ поля$label- Заголовок
Доступные методы
setModelForOptions(string|\Illuminate\Database\Eloquent\Model $model, string $titleKey = null): static
Указание модели в качестве элементов списка
$titleKey- Смотри методsetDisplay
setSearch(string|array $search): static
Указание поля/полей таблицы базы данных, по которым будет происходить поиск подходящих значений.
В случае, если в качестве аргумента передана строка, поиск будет производиться по одноименному полю в таблице БД:
->setSearch('title')
Результат:
SELECT * FROM `table` WHERE (`title` LIKE '%query%')
Если передать массив значений, то поиск будет производиться по каждому из этих полей, с условием ИЛИ:
->setSearch(['name', 'surname'])
Результат:
SELECT * FROM `table` WHERE (
`name` LIKE '%query%'
OR `surname` LIKE '%query%'
)
Также есть возможность указать правила поиска для каждого из передаваемых полей. Всего есть 4 вида правил (обращайте внимание на расположения знака процента в SQL LIKE запросе ):
equal- четкое соответствие:WHERE a LIKE 'query'(идентичноWHERE a = 'query')begins_with- значение поля начинается как введенный запрос:WHERE a LIKE 'query%'ends_with- значение поля заканчивается как введенный запрос:WHERE a LIKE '%query'contains- значение поля содержит введенный запрос:WHERE a LIKE '%query%'. Данное правило используется по-умолчанию
Примеры работы с правилами поиска:
->setSearch([
'id' => 'equal',
'name' => 'contains',
'first_name' => 'begins_with',
'last_name' => 'ends_with',
])
Результат:
SELECT * FROM `table` WHERE (
`id` LIKE 'query'
OR `name` LIKE '%query%'
OR `first_name` LIKE 'query%'
OR `last_name` LIKE '%query'
)
Доступно использование значений из связанных полей через функцию замыкание (dependent-функционал, см. ниже):
->setSearch(function($element) {
if ($element->getDependValue('user.role') == 'admin') {
// Если в связанном поле выбрано значение 'admin',
// то выполняем расширенный поиск: по name или жестко по id:
return [
'id' => 'equal',
'name'
];
} else {
// Иначе - будем искать только по полю name:
return 'name';
}
})
setDisplay(string|\Closure $display): static | required
Данный метод позволяет задать содержимое и внешний вид каждого элемента выпадающего списка.
В качестве значения можно передать строку - в этом случае в качестве содержимого каждого элемента списка будет браться значение одноименного столбца каждой записи из БД. В случае передачи строки использовать метод setSearch() не обязательно - поле одновременно будет играть роль поля источника для запроса: ->setDisplay('name') будет искать в указанной модели по этому полю.
Также в качестве значения можно передать функцию-замыкание. В этом случае обязательно нужно указать поле таблицы БД, по которому будет производиться поиск (через ->setSearch():
AdminFormElement::selectajax('user_id', 'Пользователь')
->setModelForOptions(\App\User::class)
->setSearch('name')
->setDisplay(function ($model) {
return $model->name . ' (id=' . $model->id . ')';
})
Данный код будет осуществлять поиск в таблице БД по полю name (->where('name', 'LIKE', "%{$request->q}%")). При этом при формировании списка элементов (option) для выпадающего списка (select) будет использоваться переданная функция-замыкание, в которую будет передаваться Eloquent-модель каждой подходящей записи из БД. В данном случае к имени пользователя будет добавляться его id: Иван Петров (id=77)
setLoadOptionsQueryPreparer(\Closure $callback): static
Данный метод позволяет использовать функцию-замыкание, через которую при необходимости можно дополнительно модифицировать запрос к БД, например - указать сортировку:
AdminFormElement::selectajax('user_id', 'Пользователь')
->setModelForOptions(\App\User::class)
->setSearch('name')
->setDisplay(function ($model) {
return $model->name . ' (id=' . $model->id . ')';
})
->setLoadOptionsQueryPreparer(function ($element, $query) {
return $query->orderBy('id', 'DESC');
})
Доступно использование значений из связанных полей через функцию замыкание (dependent-функционал, см. ниже):
->setLoadOptionsQueryPreparer(function($element, $query) {
if ($element->getDependValue('user.role') == 'admin') {
$query = $query->orderBy('id', 'DESC');
} else {
$query = $query->orderBy('name', 'ASC');
}
return $query;
})
setSearchUrl(string $url): static
Указание своего собственного источника поиска данных При этом использованный setDisplay будет играть роль ключа в источнике
AdminFormElement::selectajax('name')
->setSearchUrl(
route('name.route')
)
- Если указан кастомный источник то поиск по модели производится не будет
- Если указана модель то поиск будет производиться внутри SleepingOwl
exclude(array $keys): static
Исключение записей из списка элементов по id. В качестве аргумента передается массив идентификаторов, которые будут исключены при поиске подходящих значений:
AdminFormElement::selectajax('user_id', 'Пользователь')
->setModelForOptions(\App\User::class)
->setDisplay('name')
->exclude([1, 2, 3])
Однако иногда кол-во записей, которые нужно исключить из выборки, может быть достаточно большим. В этом случае рекомендуется не передавать конкретные значения (если это позволяет сделать логика приложения), а модифицировать запрос к БД, используя join совместно с методом setLoadOptionsQueryPreparer:
AdminFormElement::selectajax('user_id', 'Пользователь')
->setModelForOptions(\App\User::class)
->setDisplay('name')
->setLoadOptionsQueryPreparer(function ($element, $query) {
return $query
->leftJoin('banned_users', 'banned_users.user_id', '=', 'users.id')
->where('banned_users.user_id', null)
->selectRaw('users.*, banned_users.user_id')
;
})
setMinSymbols(integer $min): static
Указания минимального кол-ва введенных символов, после которого будет совершаться ajax-запрос с поиском. Значение по-умолчанию: 3.
Dependent-функционал
При использовании элемента selectAjax доступны расширенные возможности элемента dependentSelect.
setDataDepends(array $depends): static
Указание ключей полей, при изменении значения в которых производить обновление текущего поля.
setModelForOptionsCallback(Closure $callback): static
Указание функции-замыкания для определения модели, которая будет использована в качестве элементов списка. Схожа принципом работы с методом setModelForOptions.
В функции-замыкания, установленные через методы setModelForOptionsCallback, setSearch, setLoadOptionsQueryPreparer, передается объект $element с доступным методом getDependValue(), который позволяет получить значение из связанного поля:
->setModelForOptionsCallback(function ($element) {
// В зависимости от выбранного значения в связанном поле будем
// использовать разные модели данных для поиска и отображения:
$role = $element->getDependValue('user.role');
$array = [
'admin' => \App\Admin::class,
'user' => \App\User::class
];
if (
$role
&& isset($array[$role])
&& null !== ($class_name = $array[$role])
&& class_exists($class_name)
) {
return new $class_name;
}
return null;
})
Комплексный пример работы с dependent-функционалом поля selectAjax - управление записями с полиморфной связью:
AdminFormElement::select('entity_type', 'Сущность')
->setOptions([
'admin' => 'Администраторы',
'user' => 'Пользователи'
])
->setSortable(false)
->setDefaultValue('admin')
->required()
,
AdminFormElement::selectajax('entity_id', 'ID сущности')
->setMinSymbols(2)
->setDataDepends(['entity_type'])
->setModelForOptionsCallback(function ($element) {
$entity_type = $element->getDependValue('entity_type');
$entity_classes = [
'admin' => \App\Admin::class,
'user' => \App\User::class,
];
if (
$entity_type
&& isset($entity_classes[$entity_type])
&& null !== ($class_name = $entity_classes[$entity_type])
&& class_exists($class_name)
) {
return new $class_name;
}
return null;
})
->setSearch(function ($element) {
return [
'id' => 'equal',
'name',
];
})
->setDisplay(function ($model, $element = null) {
return $model->name . ' ' . $model->surname . ' (id=' . $model->id . ')';
})
->setLoadOptionsQueryPreparer(function($element, $query) {
if ($element->getDependValue('entity_type') == 'admin') {
$query = $query->where('admin_status', 1);
}
$query = $query->orderBy('name', 'ASC');
return $query;
})
->required()
,
MultiSelect Ajax
Отдельная благодарность https://github.com/hkd213
Поле для выбора множества значений из выпадающего списка с помощью технологии ajax (использует javascript пакет https://select2.github.io/)
AdminFormElement::multiselectajax(string $key, string $label = null): static
$key- Ключ поля$label- Заголовок
Доступные методы
Для данного поля доступны все методы поля selectajax
Предложения и пожелания будут рассматриваться в чате Gitter обращаться по нику @aios
Также можно обратиться к @sngrl в чате Telegram
DependentSelect
Поле для ввода зависимых значений (использует javascript пакет http://plugins.krajee.com/dependent-dropdown)
AdminFormElement::dependentselect(string $key, string $label = null, array $depends = []): static
$key- Ключ поля$label- Заголовок$depends- (Смотри метод setDataDepends)
Доступные методы
setDataDepends(string|array $field): static
Указание ключей полей, при изменении значения в которых производить обновление текущего поля
setModelForOptions(string|\Illuminate\Database\Eloquent\Model $model): static
Указание модели, которая будет использована в качестве элементов списка.
setDisplay(string $titleKey): static
Указание поля модели, используемого в качестве заголовка
setLoadOptionsQueryPreparer(Closure $callback): static
Правила фильтрации списка
$field->setLoadOptionsQueryPreparer(function($element, $query) {
// метод getDependValue используется для получения значения связанного поля
// При загрузке формы метод вернет $model->getAttribute($key)
// При выполнении ajax запроса $request->input('depdrop_all_params.{$key}')
return $query->where('country_id', $element->getDependValue('country_id'));
})
Пример использования
AdminFormElement::select('country_id', 'Country')
->setModelForOptions(Country::class, 'title'),
AdminFormElement::dependentselect('city_id', 'City')
->setModelForOptions(\App\Model\City::class, 'title')
->setDataDepends(['country_id'])
->setLoadOptionsQueryPreparer(function($item, $query) {
return $query->where('country_id', $item->getDependValue('country_id'));
})
MultiSelect
AdminFormElement::multiselect(string $key, string $label = null, array|Model|string $options = []): static
$key- Ключ поля$label- Заголовок$options- Данные- При передаче массива, он будет использован в качестве значений
- При передаче объекта модели, будут использованы ее значения
Доступные методы
Доступны все методы поля Select
taggable(): static
Возможность указывать собственные варианты значений
isDeleteRelatedItem(): static
Если значение было ранее выбрано и сейчас убирается из списка, удалить его из БД. (необходимо протестировать)
Wysiwyg
Добавление поля с визуальным текстовым редактором
AdminFormElement::wysiwyg(string $key, string $label = null, string $editor = null): static
$key- Ключ поля$label- Заголовок$editor- Смотри метод setEditor
Доступные методы
setFilteredValueToField(string $field): static
Указание поля, где будет храниться преобразованный текст в HTML (Используется для редакторов типа markdown)
disableFilter(): static
Отключить фильтр (При использовании markdown редактора, перед сохранением значения, он его компилирует в HTML)
setEditor(string $editor): static
указание редактора текста (Доступны редакторы ckeditor, tinymce, simplemde)
setHeight(int $height): static
Указание высоты поля ввода в px
setParameters(array $parameters): static
Передача дополнительных настроек в редактор (Будут преобразованы в json)
Ckeditor
Алиас для поля Wysiwyg с подключением редактора ckeditor
AdminFormElement::ckeditor(string $key, string $label = null): static
$key- Ключ поля$label- Заголовок
Checkbox
AdminFormElement::checkbox(string $key, string $label = null): static
$key- Ключ поля$label- Заголовок
Radio
Доступны все методы из поля Select
AdminFormElement::radio(string $key, string $label = null, array|Model|string $options = []): static
$key- Ключ поля$label- Заголовок
Belong To
belongTo создаёт форму в которой можно динамически добавлять/удалять связанные отношения. Удобно использовать, если из одной формы мы можем создавать модель связной модели один к одному.
AdminFormElement::belongsTo(string $relationName, array $elements): static
$relationName- Название метода в котором реализуется связь belongsTo$elements- Элементы формы для связанной модели
Пример использования
AdminFormElement::belongsTo('item', [
AdminFormElement::text('name', 'Тип')
AdminFormElement::select('armor_id', 'Броня', Armor::class)->setDisplay('value'),
])
Has Many
hasMany создаёт форму в которой можно динамически добавлять/удалять связанные отношения. Чтобы не создавать отдельную страницу для отношения, можно создать ее в форме редактирования с помощью этого элемента. Например, если у пользователя есть адреса(улица, город, дом), удобно создать таб на странице редактирования пользователя, вызвать там hasMany и добавить адреса как отдельные сущности. После сохранения все адреса создадутся отдельными записями и будут выводиться в форме редактирования пользователя.
AdminFormElement::hasMany(string $relationName, array $elements): static
$relationName- Название метода в котором реализуется связь hasMany$elements- Элементы формы для связанной модели
Пример использования
Можно создать много сущностей по типу улица, город, дом. Это всё делается в форме одной строчкой.
AdminFormElement::hasMany('addresses', [
AdminFormElement::text('field_address', 'Название сущности адреса')
])
Many To Many
Элемент создан для удобного редактирования pivot полей без необходимости создавать дополнительную модель. Первым параметром идет название отношения модели, вторым - массив с элементами для наполнения отношения. По умолчанию добавляется AdminFormElement::select(), который выводит список данных второй связанной модели и два action добавить/удалить. Таким образом, если у тебя есть Model User и Model Role, связанные belongsToMany/morphToMany select с ролями(Model Role) уже будет добавлен автоматом.
AdminFormElement::manyToMany(string $relationName, array $elements): static
$relationName- Название метода в котором реализуется связь belongsToMany или morphToMany$elements- Элементы формы для связующей таблицы(pivot)
Доступные методы
setRelatedElementDisplayName(String|Closure $callback): static
Устанавливает поле для вывода связной модели в select
Пример использования
Удобно использовать этот элемент с tabs.
У нас есть промежуточная таблица user_color с pivot полями (user_id, role_id ,name, color_id, images, is_done, date), и feature_entity c pivot полями (feature_id , entity_id , entity_type, equip, date).
В нашей модели Role реализуем методы users связь belongsToMany и features связь morphToMany.
В секции Roles:
$manyToMany = AdminForm::form()->addElement(
new FormElements(
[
AdminFormElement::manyToMany('users', [
AdminFormElement::text('name', 'Название'),
AdminFormElement::select('color_id', 'Цвет', Colot::class)->setDisplay('name_color'),
AdminFormElement::images('images', 'Фото'),
AdminFormElement::checkbox('is_done', 'Готово?'),
AdminFormElement::datetime('date', 'Дата оплаты'),
])->setRelatedElementDisplayName(function ($model){
return $model->full_name;
})
])
);
$morphToMany = AdminForm::form()->addElement(
new FormElements(
[
AdminFormElement::manyToMany('features', [
AdminFormElement::text('equip', 'Экипирован'),
AdminFormElement::datetime('date', 'Время'),
])->setRelatedElementDisplayName('title')
])
);
$tabs = AdminDisplay::tabbed([]);
$tabs->appendTab($manyToMany, 'Много ко многим');
$tabs->appendTab($morphToMany, 'Один ко многим через модель');
Custom
Поле для вывода обычного HTML кода.
AdminFormElement::custom(Closure $callback = null): static
$callback- функция, которая будет вызвана при сохранении поля
Доступные методы
setCallback(Closure $callback): static
Функция, которая будет вызвана при сохранении поля
setDisplay(string|Closure|\Illuminate\Contracts\Support\Htmlable|\Illuminate\Contracts\View\View $display)
HTML, который будет выведен в форме
- При передаче объекта
\Illuminate\Contracts\View\View, в него будет передан объект модели$model. - При передаче анонимной функции, в нее будет передат первым аргументов объект модели.
$field->setDisplay(function(Model $model) {
return (string);
});
$field->setDisplay(view('app.custom'));
Html
Поле для вывода обычного HTML кода.
Данное поле алиас поля Custom, с передачей через конструктор html в поле setDisplay
AdminFormElement::html(
string|Closure|\Illuminate\Contracts\Support\Htmlable|\Illuminate\Contracts\View\View $html,
Closure $callback = null
): static
$html- HTML, который будет выведен в форме$callback- Функция, которая будет вызвана в момент сохранения формы
View
Поле для вывода view шаблона в качестве элемента формы
Во view шаблон будет передан объект модели $model
AdminFormElement::view(string $view, array $data = [], Closure $callback = null): static
$view- путь до шаблона$data- массив который будет передан в шаблон (также туда будет передана модель)$callback- функция, которая будет вызвана при сохранении поля
Доступные методы
Доступны все методы поля Custom
setView(string $path): static
Путь до шаблона
setData(array $data): static
Массив который будет передан в шаблон
Upload
Поле используется для загрузки файлов на сервер посредством <input type="upload" />.
При добавлении поля, форма должна автоматически получить html атрибут enctype="multipart/form-data".
Если этого не произошло, вы можете добавить атрибут вручную:
return AdminForm::panel()
....
->setHtmlAttribute('enctype', 'multipart/form-data');
Для работы с этим полем существует специальный трейт KodiComponents\Support\Upload, который поможет с загрузкой прикрепленного файла и сохранением ссылки на него в БД. (При желании данный трейт можно использовать отдельно, используя composer пакет kodicomponents/support)
Пример использования:
class User extends Model
{
use \KodiComponents\Support\Upload;
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'image' => 'image', // or file | upload
];
}
После добавления трейта в модель необходимо в $casts указать поля, которые должны работать с файлами. Для файлов необходимо указать тип file или upload, для изображений image. В качестве файла ожидается объект Illuminate\Http\UploadedFile
Если тип файла указан image, то можно указать правила обработки изображения (Для работы с изображениями используется пакет http://image.intervention.io/)
/**
* @return array
*/
public function getUploadSettings()
{
return [
'image' => [ // Ключ поля
// Название функции, которую необходимо применить к изображению http://image.intervention.io/api/fit и параметры передаваемые в нее
'fit' => [300, 300, function ($constraint) {
$constraint->upsize();
$constraint->aspectRatio();
}],
'crop' => [300, 300], // http://image.intervention.io/api/crop
...
],
'image_small' => [
...
]
];
}
По умолчанию путь сохранения файла: public\storage\{table_name}\{field_name}\{file_name_hash:2chars}\{uniqid}.{ext}.
При желании можно указать свой формат имени файла
/**
* @param UploadedFile $file
*
* @return string
*/
protected function getUploadFilename(\Illuminate\Http\UploadedFile $file)
{
return md5($this->id).'.'.$file->getClientOriginalExtension();
}
Путь хранения файла пока что изменить невозможно.
В случае если у вас несколько файлов изображений, например, миниатюра и большое изображение и вы хотите загружать их через одно поле, то можно сделать следующим образом:
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'image' => 'image',
'thumb' => 'image',
];
/**
* @return array
*/
public function getUploadSettings()
{
return [
'image' => [
'orientate' => [],
'resize' => [1280, null, function ($constraint) {
$constraint->upsize();
$constraint->aspectRatio();
}]
],
'thumb' => [
'orientate' => [],
'fit' => [200, 300, function ($constraint) {
$constraint->upsize();
$constraint->aspectRatio();
}]
]
];
}
/**
* @param \Illuminate\Http\UploadedFile $file
*/
public function setUploadImageAttribute(\Illuminate\Http\UploadedFile $file = null)
{
if (is_null($file)) {
return;
}
foreach ($this->getUploadFields() as $field) {
$this->{$field.'_file'} = $file;
}
}
И в форме указываем AdminFormElement::upload('upload_image', 'Image'), т.е. прикрепленный файл через поле с ключем upload_image будет передан в модель в созданный нами мутатор setUploadImageAttribute, где файл будет передан в нужные нам поля и сохранен согласно их правилам.
Также для загруженного файла доступны ссылка на файл и абсолютный путь. Например рассмотрим поле с ключем image:
$user->imagepublic\storage\users\image\23n4b23hj4b.jpg$user->image_path\var\www\site.com\public\storage\users\image\23n4b23hj4b.jpg-
$user->image_urlhttp:\\site.com\storage\users\image\23n4b23hj4b.jpg
Валидация
Данный тип поля поддерживает валидацию загружаемых файлов
- https://laravel.com/docs/5.4/validation#rule-image
- https://laravel.com/docs/5.4/validation#rule-mimetypes
- https://laravel.com/docs/5.4/validation#rule-mimes
AdminFormElement::upload('image', 'Image')->addValidationRule('image')
// or for file
AdminFormElement::upload('pdf', 'PDF')->addValidationRule('mimes:pdf'),
Ограничение использования трейта
!!!Трейт переопределяет методы getAttribute, mutateAttribute, setAttribute, в случае, если они переопределены у вас в модели, могут возникнуть проблемы в работе!!!
API
addValidationRule(string $rule, string $message = null): static
Добавление правила валидации
setValidationRules(array $rules): static
Добавление правил валидации в виде массива
required(string $message = null): static
Поле обязательно для заполнения
unique(string $message = null): static
Поле должно быть уникальным
addValidationMessage(string $rule, string $message): static
Изменение сообщения для правила валидации
setView(\Illuminate\View\View|string $view): static
Указания шаблона для отображения. При передаче пути до шаблона, поиск будет производиться с учетом view namespace sleepingowl::
При передаче объекта \Illuminate\View\View, в него будут переданы данные поля и произведен вывод
setPath(string $path): static
Указание ключа поля.
setLabel(string $label): static
Указание заголовка поля.
setDefaultValue(mixed $defaultValue): static
Указание значения по умолчанию
setHelpText(string|\Illuminate\Contracts\Support\Htmlable $helpText): static
Указание вспомогательного текста
setReadonly(bool|Closure $status): static
Установка атрибута “только для чтения”.
Если поле только для чтения, то оно будет игнорироваться при валидации и сохранении.
Пример
$field->setReadOnly(true);
$field->setReadOnly(function($model) {
return $model->author_id != auth()->id();
});
$field->setReadOnly(function($model) {
return !auth()->check();
});
setValueSkipped(bool|Closure $valueSkipped)
Установка атрибута пропуска записи значения поля в модель. По умолчанию false.
Если значение поля должно быть пропущено, то правила валидации будут применены, но в модель значение не установится.
Например, вы хотите чтобы при создании пользователя проверялись соответствия полей password (пароль) и password_confirmation (подтверждение), но вам не нужно чтобы поле password_confirmation записывалось в модель:
AdminFormElement::text('password', 'Password')->required();
AdminFormElement::text('password_confirmation', 'Password confirmation')
->setValueSkipped(true)
->required()
->addValidationRule('same:password', 'Passwords must match!');
setVisibilityCondition(Closure $condition): static
Указания условия видимости поля (https://github.com/LaravelRUS/SleepingOwlAdmin/issues/377)
Если поле скрыто, то оно будет игнорироваться при валидации и сохранении.
Пример
$field->setVisibilityCondition(function($model) {
return auth()->user()->isAdmin();
});
$field->setVisibilityCondition(function($model) {
return $model->author_id == auth()->id();
});
mutateValue(Closure $mutator): static
Изменение значения поля перед передачей в модель
Пример
$field->mutateValue(function($value) {
return bcrypt($value);
})
Примеры указания правил валидации
Для каждого элемента формы AdminFormElement можно указывать правила валидации.
Пример
AdminFormElement::text('title', 'Title')
->required()
->unique();
Если вы хотите переопределить стандартное сообщение для правила, вы можете воспользоваться одним из способов:
AdminFormElement::text('title', 'Title')
->required('Поле обязательно для заполнения')
->unique('Поле должно содержать уникальное значение')
// Или
AdminFormElement::text('title', 'Title')
->addValidationRule('required', 'Поле обязательно для заполнения')
->addValidationRule('number', 'Поле должно быть числом');
// Или
AdminFormElement::text('title', 'Title')
->required()
->addValidationMessage('required', 'Поле обязательно для заполнения');