SleepingOwlAdmin

Элементы формы (Поля)

В качестве элемента формы может выступать любой класс, которые реализует интерфейс Illuminate\Contracts\Support\Renderable. Для полноцнной работы класс поля должен реализовать интерфейс SleepingOwl\Admin\Contracts\FormElementInterface

Text

Обычное текстовое поле <input type="text" />

AdminFormElement::text(string $key, string $label = null): static

Number

Числовое поле <input type="number" min max step />

AdminFormElement::number(string $key, string $label = null): static

Доступные методы

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

Доступные методы

allowEmptyValue(): static

Если пароль указан для текущего поля, то при валидации будет игнорироваться правило required

hashWithBcrypt(): static

Перед сохранением применить к паролю функцию bcrypt

hashWithMD5(): static

Перед сохранением применить к паролю функцию md5

hashWithSHA1(): static

Перед сохранением применить к паролю функцию sha1

Hidden

AdminFormElement::hidden(string $key): static

Date

Поле для ввода даты (использует javascript календарь http://eonasdan.github.io/bootstrap-datetimepicker/)

AdminFormElement::date(string $key, string $label = null): static

Доступные методы

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

Доступные методы

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

Доступные методы

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

Доступные методы

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->setUploadPath(function(\Illuminate\Http\UploadedFile $file) {
    return $file->getClientOriginalName().'.'.$file->getClientOriginalExtension();
});

maxSize(int $size): static

Указание максимального размера загружаемого изображения (в байтах)

minSize(int $size): static

Указание минимального размера загружаемого изображения (в байтах)

Image

Загрузка файлов происходит через ajax и возвращает строку (относительный путь до файла). При загрузке изображений, файлы проходят валидацию image

AdminFormElement::image(string $key, string $label = null): static

Доступные методы

Для данного поля доступны все методы поля 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

Доступные методы

Для данного поля доступны все методы поля Image

storeAsJson(): static

При сохранении преобразовать массив в json строку

storeAsComaSeparatedValue(): static

При сохранении преобразовать массив в строку с разделителем ","

setAfterSaveCallback()

Этот метод полезен когда нужно сколлектировать логику сохранения изображений и привязываний их в модель Пример

    ->setAfterSaveCallback(function ($value, $model) {
        if ($value) {
            //... сюда приходит value с поля и модель после сохранения
            //... Имейте ввиду что этот колбек вызовется только после всех валидаций и сохранения модели
        }
    })

Textarea

Поле для ввода текста <textarea></textarea>

AdminFormElement::textarea(string $key, string $label = null): static

Доступные методы

setRows(int $rows): static

Указание кол-ва видимых строк

Select

Поле для выбора значения из выпадающего списка (использует javascript пакет https://select2.github.io/)

AdminFormElement::select(string $key, string $label = null, array|Model|string $options = []): static

Доступные методы

setModelForOptions(string|\Illuminate\Database\Eloquent\Model $model, string $titleKey = null): static

Указание модели в качестве элементов списка

setDisplay(string $titleKey): static

Указание поля модели, используемого в качестве заголовка

setFetchColumns(...$columns): static

При использовании модели указание списка загружаемых полей в select

$field->setFetchColumns('title');
$field->setFetchColumns(['title']);
$field->setFetchColumns(['title', 'position']);

setLoadOptionsQueryPreparer(Closure $callback): static

При использовании модели перед загрузкой списка возможность изменения запроса

В анонимную функцию будут переданы

$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

Исключение из списка элементов

Select Ajax (Отдельная благодарность https://github.com/hkd213)

Поле для выбора значения из выпадающего списка с помощью технологии ajax (использует javascript пакет https://select2.github.io/)

AdminFormElement::selectajax(string $key, string $label = null): static

Доступные методы

setModelForOptions(string|\Illuminate\Database\Eloquent\Model $model, string $titleKey = null): static

Указание модели в качестве элементов списка

setDisplay(string $titleKey): static | required

Указание поля модели, используемого в качестве заголовка.
Поле одновременно играет роль поля источника для запроса ->setDisplay('name') будет искать в указанной модели по этому полю.

setSearchUrl(string $url): static

Указание своего собственного источника поиска данных При этом использованный setDisplay будет играть роль ключа в источнике

AdminFormElement::selectajax('name')
    ->setSearchUrl(
        route('name.route')
    )

exclude(array $keys): static

Исключение из списка элементов

MultiSelect Ajax (Отдельная благодарность https://github.com/hkd213)

Поле для выбора множества значений из выпадающего списка с помощью технологии ajax (использует javascript пакет https://select2.github.io/)

AdminFormElement::multiselectajax(string $key, string $label = null): static

Доступные методы

setModelForOptions(string|\Illuminate\Database\Eloquent\Model $model, string $titleKey = null): static

Указание модели в качестве элементов списка

setDisplay(string $titleKey): static | required

Указание поля модели, используемого в качестве заголовка.
Поле одновременно играет роль поля источника для запроса ->setDisplay('name') будет искать в указанной модели по этому полю.

setSearchUrl(string $url): static

Указание своего собственного источника поиска данных При этом использованный setDisplay будет играть роль ключа в источнике

AdminFormElement::selectajax('name')
    ->setSearchUrl(
        route('name.route')
    )

exclude(array $keys): static

Исключение из списка элементов

Предложения и пожелания будут рассматриваться в чате Gitter обращаться по нику @aios

DependentSelect

Поле для ввода зависимых значений (использует javascript пакет http://plugins.krajee.com/dependent-dropdown)

AdminFormElement::dependentselect(string $key, string $label = null, array $depends = []): static

Доступные методы

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

Доступные методы

Доступны все методы поля Select

taggable(): static

Возможность указывать собственные варианты значений

isDeleteRelatedItem(): static

Если значение было ранее выбрано и сейчас убирается из списка, удалить его из БД. (необходимо протестировать)

Wysiwyg

Добавление поля с визуальным текстовым редактором

AdminFormElement::wysiwyg(string $key, string $label = null, string $editor = null): static

Доступные методы

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

Checkbox

AdminFormElement::checkbox(string $key, string $label = null): static

Radio

Доступны все методы из поля Select

AdminFormElement::radio(string $key, string $label = null, array|Model|string $options = []): static

Custom

Поле для вывода обычного HTML кода.

AdminFormElement::custom(Closure $callback = null): static

Доступные методы

setCallback(Closure $callback): static

Функция, которая будет вызвана при сохранении поля

setDisplay(string|Closure|\Illuminate\Contracts\Support\Htmlable|\Illuminate\Contracts\View\View $display)

HTML, который будет выведен в форме

$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

View

Поле для вывода view шаблона в качестве элемента формы

Во view шаблон будет передан объект модели $model

AdminFormElement::view(string $view, array $data = [], Closure $callback = null): static

Доступные методы

Доступны все методы поля 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:

Валидация

Данный тип поля поддерживает валидацию загружаемых файлов

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', 'Поле обязательно для заполнения');