Laravel Nova встановлюється з великим та дивовижним списком полів. Ці поля за замовчуванням досить розумні, і вони підходять майже для будь-якої ситуації. Але що, якщо у вас ситуація, коли інтерфейс відповідає вашим потребам, але поля обробляють дані по-різному. Ви змушені створювати власне поле? Ну, можливо, ні.
Поля Laravel Nova мають безліч методів, що дозволяють налаштувати їх поведінку. Як ви можете прочитати в документах, ви можете налаштувати спосіб гідратації відповідної моделі, приєднавши зворотний виклик fillUsing (). І ви можете налаштувати спосіб розв’язання поля, приєднавши зворотний виклик resolUsing (). Тож давайте використаємо ці функції та створимо своє власне «спеціальне» поле.
Уявіть, що у вас є модель повідомлення, яка представляє повідомлення, яке може відображатися у декількох областях, таких як: веб-сайт, програма та RSS. Ви хочете легко запитувати ці повідомлення за їх обсягом, тому ви додали 3 логічні поля: scope_website, scope_app і scope_rss.
Так, ви могли б скласти категорії та створити зведену таблицю; але у вас були лише ці сфери, і тоді ви згадали, що це був приклад ..
<?php namespace App\Nova\Resources; use App\Nova\Resource; use Illuminate\Http\Request; use Laravel\Nova\Fields\BooleanGroup; class MessageResource extends Resource { // ... public function fields(Request $request): array { return [ BooleanGroup::make('Scopes')->options($options = [ 'scope_website' => 'Website', 'scope_app' => 'Application', 'scope_rss' => 'RSS Feed', ]) ]; } }
Замість того, щоб додавати 3 різні поля до Ресурсу Nova, ми хочемо додати BooleanGroup цих областей. За замовчуванням поле BooleanGroup зберігатиме свої параметри у вигляді BLOB-масиву на одному атрибуті. Щоб змінити цю поведінку, ми збираємося налаштувати гідратацію нашого поля, викликавши метод fillUsing за допомогою цієї функції зворотного виклику:
use App\Model\Message; use Laravel\Nova\Http\Requests\NovaRequest; // this function goes inside ->fillUsing(...) function (NovaRequest $request, Message $model, string $attribute, string $requestAttribute) { // Make sure the `scopes` value exists on the request. if (!$request->exists($requestAttribute)) { return; } // Decode the values because it is send as a JSON blob. $values = json_decode($request[$requestAttribute], true); // Hydrate the model. foreach ($values as $key => $value) { $model->{$key} = $value; } }
Функція зворотного виклику для fillUsing () отримує 4 параметри:
Переконавшись, що ми опублікували значення, ми можемо зіставити всі ці параметри з їх атрибутом моделі. Ефективно називаючи щось на зразок:
$model->scope_website = 1; // or 0
Тепер, коли ми фактично зберігаємо логічні значення за правильними атрибутами, настав час поглянути на розв’язання поля в Nova. Хоча для моделі можуть бути встановлені сфери дії, усі прапорці будуть вимкнені. Це тому, що поле все ще намагається отримати їх значення з $ model-> scopes; який не існує. Тож дозволяє це виправити, додавши дозвіл зворотного виклику за допомогою
Ви могли помітити, що ми визначили наші параметри поля всередині змінної $ options. Це було навмисно, бо нам потрібні ключі від цих варіантів. На цей час метод callUlbackback не має доступу до самого поля для отримання цих опцій. Це наш обхідний шлях.
// this function goes inside ->resolveUsing(...) function ($value, Message $model, string $attribute) use ($options) { $keys = array_keys($options); $values = array_map(function($value, $key) use ($model) { return $model->{$key}; }, $options, $keys); return array_combine($keys, $values); }
Функція зворотного виклику для резолюції Using () отримує 3 параметри:
`mixed $value`
Значення, яке Laravel Nova намагалася отримати `Message $model`
модель Модель, яка надала значення рядокstring $attribute
` Ім'я атрибута на моделі (знову нам це не знадобиться)
Єдине, що потрібно зробити для нашого зворотного виклику, це отримати значення для кожного логічного значення з модель і повернути ці значення у вигляді масиву. Цей код трохи безлад. Побачити, що відбувається, непросто, і нам потрібно використовувати значення в межах декількох областей функцій. Давайте трохи очистимо це, використовуючи скорочені функції і деякі laravel збирають магію:
fn($value, Message $model) => collect($options)->map(fn($value, $key) => $model->{$key})
Ось, хороший однокласник, який вирішує поле з правильних атрибутів моделі. Коли ви оновлюєте свою сторінку Nova, прапорці повинні правильно вказувати їх статус.
Для розваги, припустимо, вам потрібно вибрати принаймні один обсяг . Вашим першим інстинктом може бути просто встановити -> required () на полі, але це насправді не працює, хоча це дасть гарну зірочку * на формі. На щастя, ми також можемо додати власне правило перевірки, викликавши в полі метод rules ().
$field->rules('required', function (string $attribute, $value, callable $fail) { if (!array_filter(json_decode($value, true) ?? [])) { return $fail(sprintf('The "%s" field must have at least one option selected.', $attribute)); } })
Встановлення необхідного правила `required
` також додасть зірочку `*` до форми. Зворотний дзвінок швидко перевіряє, чи було повернуто якесь значення як істинне. Якщо ні; ми називаємо виклик `$fail
` і вказуємо причину невдалої перевірки.
І все; власне поле, фактично не будуючи власне поле.