Ошибки панели администрирования или опыт разработки Laravel Orchid

от автора

В прошлом на хабре публиковалась статья «Orchid CMS — ещё одна CMS на Laravel», а теперь спустя два года и больше 100 релизов попробуем разобрать ошибки и проблемы которые стояли на пути разработки.

1. Позиционирование

В самом заголовке предыдущей статьи и во многих других указывалась, аббревиатура CMS, что во влажных мечтах должно было привлечь больше интереса к разработке. Одновременно с этим, пакет не предлагал ни каких готовых решений в тиражировании веб-сайтов, а только управление в администрировании.

В итоге было только хуже… Само это сочетание отталкивало опытных пользователей устанавливать, а новички ожидали увидеть привычные для себя возможности, вместо, некоторой свободы.

2. Формы

Когда речь заходит об панелях администрирования, впервую очередь имеет значение формы и как с ними работать. Для примера будем рассматривать форму построенную на blade-шаблонах, которая отображает и позволяет редактировать данные некоторого объекта:

<form action="...">    <input type="text" name="title">    <input type="text" name="price">    <input type="submit" value="Изменить"> </form>

Менеджеры, редакторы и пользователи в целом хотят видеть как можно больше об объекте редактирования и в этом нет ни каких проблем если всю информацию можно взять из одной таблицы, но когда информация очень растянута?

Самым популярным решением, что я видел, было просто разделение формы на несколько классов и файлов с представлением. Они отображались в виде вкладок на форме, информация в которых была бы сгруппирована по связям:

<form action="..." id="main">    <input type="text" name="title">    <input type="text" name="price">    <input type="submit" value="Изменить"> </form>  <form action="..." id="editors">    <!-- Связи с редакторами -->    <input type="submit" value="Применить"> </form>  <form action="..."  id="history">    <!-- История изменений -->    <input type="submit" value="Восстановить"> </form>

Именно это и было воспроизведено… Конечно с небольшими изменениями и особенностями, но смысл оставался прежним. В создании отдельного класса группирующего все обработки в виде других форм:

Накладывая на предыдущие примеры, в коде каждая форма выглядела приблизительно следующим образом:

class Example extends Form {     public $name = 'General';      public function rules(): array     {         return [             'title' => 'required|max:160'         ];     }      public function display(): View     {         return view('main');     }      public function persist(Model $model)     {         //..         return $model->save();     } }

И формирование в контроллере всей группы:

class ExampleController extends Controller {     public function index(Model $model)     {         $form = new FormGroup([             Example::class             // editors..             // history..         ]);          return $form->render($model);     } }

Кроме разделения самой формы и небольшой организации кода это не принесло ни каких других результатов. В итоге:

  • Такой способ ни как не помогал решать дублирование нескольких элементов, например, поле «Заголовок» у объекта мог встречаться множество раз, но полной копии формы ни разу.
  • При отличных от «стандартных» действий нужно было создавать отдельный метод контроллера, что напрочь портило весь смысл деления формы.
  • Ни каких плюсов в автоматизации построения представления, все так же необходимо указывать вручную.

3. CRUD

Самый спорный вариант, который очень часто фигурирует в новостных лентах и блогах разработчиков. Такой подход используется почти всеми альтернативными пакетами, сделали и его. По примеру одной известной системы где все храниться в одной таблице была создана модель с динамическим JSON полем:

В отдельном классе описывались необходимые для создания и редактирования поля, а так же базовые действия:

class Example extends Behavior {     public $name = 'Main';      public function rules(): array     {         return [             'title' => 'required|max:160'         ];     }      public function fields(): array     {         return [             Input::make('title')                 ->type('text')                 ->max(160)                 ->required(),         ];     } }

Благодаря такому подходу, написание простейшего кода было быстрым из-за полного отсутствия работы с представлением, но принесло не мало проблем:

  • Нестандартные операции не доступны в рамках объекта.
  • Динамическое представление, вроде модальных окон с загрузкой информации недоступно.
  • При малейшем отклонении, например, построения графиков мы снова возвращаемся к написанию blade шаблонов со стилями и сценариями.
  • Невозможность использовать данные из отличных от базы данных источников.
  • Работа только в рамках одной таблицы, это можно было исправить, но в первой и последней реализации так было.

Исправление

Вариант с CRUD был основан на полном автоматизации представления, что в итоге привело к новой реализации. Как некоторый эталон на этот раз был взят продукт Visual Studio LightSwitch, который позволял пользоваться человеку без глубоких знаний разработки.

Естественно такого эффекта нам не нужно и это даже не является целью, при этом почти все технические возможности присутствовали в Laravel или пользовательских реализаций.
Решено было сосредоточится только на одно единственном аспекте — Экраны.

Экран — это все, что пользователь видит на странице и какие действия может совершать.
Все это описывается в одном классе, он не знает откуда берутся данные, это может быть: база данных, API или любые другие внешние источники. Построение внешнего вида основано на слоях и всё, что необходимо было сделать это лишь определить какие данные будут показаны в том или ином шаблоне.

Слой же может представлять из себя некоторый макет, который может быть таблицей, строкой, графиком и т.п. При этом каждый макет может включать в себя другой макет, то есть вложенность. Например экран делится двумя колонками, в левой поля для заполнения, справа справочная таблица и график и т.д.

Для управления над данными отображаемые на экране предусмотрены команды, которые берут на себя обработку.

class ExampleScreen extends Screen {     public $name = 'Example Screen';      public function query(Model $model): array     {         return [             'model' => $model         ];     }      public function commandBar(): array     {         return [             Link::make('Веб-сайт')                 ->link('http://orchid.software/ru')                 ->icon('icon-globe-alt'),         ];     }      public function layout(): array     {         return [             Layout::rows([                 Input::make('model.title')                     ->type('text')                     ->max(160)                     ->required(),             ])         ];     } }

Остановка произошла на таком варианте, так как он держит здоровый баланс между полным написанием и автоматической генерации, при этом оставаясь понятным.


ссылка на оригинал статьи https://habr.com/ru/post/460471/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *