Статьи

Как создать плагин для виджета OctoberCMS

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

OctoberCMS

Что мы собираемся построить

Я предполагаю, что многие из вас использовали WordPress . На панели инструментов у нас есть быстрый виджет проекта. В этой статье мы увидим, как мы можем создать аналогичный для OctoberCMS.

Quick Notes Widget
Quick Note Widget Listing

Регистрация плагинов

Чтобы начать сборку нашего плагина, мы будем использовать командную утилиту для скаффолдинга.

php artisan create:plugin RAFIE.quicknote 

Команда создаст файл Plugin.php и папку updates содержащую файл version.yaml .

 public function pluginDetails(){ return [ 'name' => 'Quick Note Widget', 'description' => 'Add and manage some drafts when you\'re in a hurry.', 'author' => 'RAFIE Younes', 'icon' => 'icon-pencil' ]; } 

После регистрации нашего плагина нам нужно обновить наш файл version.yaml .

 // uploads/version.yaml 1.0.1: First version of quicknote 1.0.2: - Created Notes Table - create_notes_table.php 

Использование моделей

Для создания наших файлов миграции и модели мы можем использовать команду php artisan create:model RAFIE.quicknote Note . Наш updates/create_notes_table.php миграции updates/create_notes_table.php обрабатывает создание таблицы notes и будет иметь следующую структуру.

Notes Table Structure

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

 public function up(){ Schema::create('rafie_quicknote_notes', function($table){ $table->engine = 'InnoDB'; $table->increments('id'); $table->string('title', 255); $table->text('description')->nullable(); $table->integer('user_id')->unsigned()->index(); $table->timestamps(); }); } public function down(){ Schema::dropIfExists('rafie_quicknote_notes'); } 

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

 artisan plugin:refresh RAFIE.quicknote 

Если вы поклонник Laravel, вы знаете, что каждый класс модели должен расширять Illuminate\Database\Eloquent\Model для использования eloquent, но у OctoberCMS есть класс October\Rain\Database\Model который расширяет класс модели Eloquent и обеспечивает большую расширяемость , как метод extend .

 public function boot(){ User::extend(function($model){ $model->hasMany['notes'] = ['RAFIE\Quicknote\Models\Notes']; }); } 

Внутри файла Plugin.php мы переопределяем метод boot , который Plugin.php при каждом запросе, и расширяем модель User чтобы иметь много примечаний.

 class Note extends Model{ // used for automatic validation using the defined rules. use \October\Rain\Database\Traits\Validation; public $table = 'rafie_quicknote_notes'; protected $guarded = ['*']; protected $rules = [ 'title' => 'required|min:4' ]; public $belongsTo = [ 'user' => [ 'Backend\Models\User' ] ]; } 

В наших файлах models/Note.php у нас есть базовое определение модели. Кроме того, атрибут belongsTo определяет отношение нашей модели. Проверка автоматически обрабатывается признаком проверки с использованием определенных правил.

Виджеты OctoberCMS

Виджеты OctoberCMS — это блоки контента, которые могут быть по-разному интегрированы в ваш шрифт или сервер. Есть три разных вида виджетов.

Универсальные виджеты

Общие виджеты — это функциональные возможности пакетов, которые можно внедрить на страницу. Они ведут себя как компоненты и хранятся в папке widgets . Вы можете прочитать больше в документации .

Виджеты форм

Виджеты форм немного особенные, они позволяют создавать новые типы элементов управления, которые могут использоваться другими плагинами или самой CMS. Хорошим примером из документации является CodeEditor управления CodeEditor используемый для создания страниц, а также есть поле поиска, используемое во многих местах и ​​встроенное по умолчанию в нашу страницу управления заметками.

Виджеты отчетов

Виджеты отчетов являются наиболее известным типом виджетов. Они добавляют контент в определенном контексте, в данном случае на приборной панели. В новой установке OctoberCMS у нас есть виджет SYSTEM STATUS отображающий доступные обновления и статус веб-сайта.

Леса наш виджет

Для начала давайте создадим файл QuickNoteWidget.php котором мы сможем определить наш виджет QuickNote, и нам также нужно зарегистрировать наш виджет внутри нашего файла Plugin.php .

 // Plugin.php public function registerReportWidgets(){ return [ 'RAFIE\QuickNote\QuickNoteWidget' => [ 'label' => 'Quick Notes', 'context' => 'dashboard' ] ]; } 
 class QuickNoteWidget extends ReportWidgetBase{ public function render(){ $notes = BackendAuth::getUser()->notes; return $this->makePartial('notes', [ 'notes' => $notes ]); } } 

Виджеты отчета должны расширять класс ReportWidgetBase и переопределять метод визуализации.

Метод BackendAuth::getUser возвращает зарегистрированного пользователя, у которого есть связанный список заметок. Это возможно только потому, что мы определили отношение внутри наших моделей.

OctoberCMS будет искать наши активы в каталоге с тем же именем, что и имя нашего файла виджета в нижнем регистре. Каталог partials содержит наши представления, и они должны начинаться с подчеркивания.

 //quicknotewidget/partials/_notes.htm <div class="report-widget"> <h3>Quick Note</h3> <div class="pane"> <ul class="list-nostyle"> <?php foreach( $notes as $note ): ?> <li class="list-group-item"><?= $note->title ?></li> <?php endforeach ?> </ul> </div> <br/> <?= Form::open([ 'url' => Backend::url('rafie/quicknote/notes/store'), 'method' => 'POST' ]); ?> <div class="form-group"> <input class="form-control" type="text" name="title" placeholder="Title" required /> </div> <div class="form-group"> <textarea class="form-control" name="description" id="" cols="30" rows="10" placeholder="You have something to say?"></textarea> </div> <div class="form-group"> <input type="submit" class="btn btn-primary" value="Submit" /> <a href="<?= Backend::url('rafie/quicknote/notes/index') ?>">Manage your notes</a> </div> <?= Form::close(); ?> </div> 

HTML-код виджета должен содержаться в классе report-widget и при желании иметь <h3> для заголовка виджета. После этого мы перебираем список заметок пользователя и показываем форму для создания новой заметки.

Backend::url('rafie/quicknote/notes/store') сгенерирует ссылку на наш контроллер заметок, где мы можем обработать данные нашей формы. Мы могли бы использовать Ajax-инфраструктуру OctoberCMS для формы, но для простоты мы обычно собираемся отправить форму и поговорить об использовании AJAX позже.

Использование контроллеров

Контроллеры хранятся в папке controllers и могут быть созданы с помощью команды scaffolding.

 php artisan create:controller RAFIE.quicknote Notes 

Controllers folder

Создание заметок

Папка содержит класс нашего контроллера и еще одну папку для наших ресурсов. Когда кто-то нажимает на URL, он анализируется следующим образом: author/plugin/controllerClass/method . В нашем случае это rafie/quicknote/notes/store , если метод не указан, метод index запускается по умолчанию.

 public function store(){ $note = new Models\Note; $note->title = Input::get('title'); $note->description = Input::get('description', null); $note->user_id = BackendAuth::getUser()->id; if( $note->save() ) { \Flash::success('Note added successfully.'); } else{ \Flash::error('Validation error' ); } return \Redirect::to( Backend::url() ); } 

Мы создаем новую заметку, используя нашу модель, и сохраняем ее в базе данных. Flash::success() покажет пользователю флэш-сообщение для подтверждения вставки.

Возможно, вы заметили ссылку « Manage your notes указывающую на rafie/quicknote/notes/index адрес rafie/quicknote/notes/index . Здесь мы собираемся перечислить наши заметки, чтобы пользователь мог добавлять, редактировать и удалять заметки.

Конфигурация виджета

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

 // QuickNoteWidget.php public function defineProperties(){ return [ 'title' => [ 'title' => 'Widget title', 'default' => 'QUICK NOTE' ], 'showList' => [ 'title' => 'Show notes', 'type' => 'checkbox' ] ]; } 

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

 // quicknotewidget/partials/_notes.htm <h3><?= $this->property('title') ?></h3> <?php if( $this->property('showList') ): ?> <ul class="list-nostyle"> <?php foreach( $notes as $note ): ?> <li class="list-group-item"><?= $note->title ?></li> <?php endforeach ?> </ul> <br/> <?php endif; ?> 

Widget Properties

Использование контроллеров

До сих пор мы говорили о рендеринге виджета отчета и его передаче контроллеру. Теперь мы собираемся создать страницу листинга и поговорим о расширении бэкэнда OctoberCMS путем создания части листинга и управления.

Листинг Примечания

Каждый контроллер имеет файл config_list.yaml котором вы можете определить свой список, и он также сопоставлен с моделью с использованием некоторых атрибутов конфигурации.

 // controllers/notes/config_list.yaml # Model List Column configuration list: $/rafie/quicknote/models/note/columns.yaml # Model Class name modelClass: RAFIE\Quicknote\Models\Note # List Title title: Manage Notes # Link URL for each record recordUrl: rafie/quicknote/notes/update/:id # Message to display if the list is empty noRecordsMessage: backend::lang.list.no_records # Records to display per page recordsPerPage: 20 # Displays the list column set up button showSetup: true # Displays the sorting link on each column showSorting: true # Default sorting column defaultSort: column: created_at direction: desc # Display checkboxes next to each record showCheckboxes: true # Toolbar widget configuration toolbar: # Partial for toolbar buttons buttons: list_toolbar # Search widget configuration search: prompt: backend::lang.list.search_prompt 

Атрибуты, как правило, хорошо объяснены, но давайте добавим некоторые пояснения к некоторым:

  • list: путь к определению столбцов списка.
  • showSetup: маленькая кнопка для переключения отображения столбцов.
  • showCheckboxes: показать флажок для каждой строки, используемой для массовых действий.
  • Панель инструментов -> кнопка: частичное имя, если вы хотите показать некоторые элементы управления над таблицей, например, New или Delete .
 // rafie/quicknote/models/note/columns.yaml columns: id: label: ID title: label: TITLE searchable: true description: label: DESCRIPTION searchable: true created_at: label: CREATED AT type: date invisible: true updated_at: label: UPDATED AT type: date invisible: true 

Файл columns.yaml отображает нашу таблицу базы данных в список, используя label , searchable и т. Д. Проверьте документы для полного списка атрибутов.

 // controllers/Notes.php public function index(){ $this->makeLists(); $this->makeView('index'); } // controllers/notes/index.htm <?= $this->listRender() ?> 

Внутри нашего метода Notes@index мы анализируем конфигурацию списка и отображаем ее в нашем представлении индекса. Вы также можете добавить дополнительную разметку, если у вас есть дополнительные поля.

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

 // controllers/Notes.php public function listExtendQueryBefore($query){ $user_id = BackendAuth::getUser()->id; $query->where('user_id', '=', $user_id); } 

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

 // controllers/Notes.php public function listOverrideColumnValue($record, $columnName){ if( $columnName == "description" && empty($record->description) ) return "[EMPTY]"; } 

Вы можете объединить listOverrideColumnValue с listExtendColumns чтобы добавить новые столбцы и вставить новые значения, например, добавить кнопку «пометить как прочитанную» для каждой строки и т. Д.

 public function listExtendColumns($list){ $list->addColumns([ 'action' => [ 'label' => 'Actions', 'sortable' => false ] ]); } 

Если вы помните, внутри нашего config_list.yaml у нас было поле list_toolbar :

 // controllers/notes/_list_toolbar.htm <div data-control="toolbar"> <a href="<?= Backend::url('rafie/quicknote/notes/create') ?>" class="btn btn-primary oc-icon-plus">New Note</a> <button id = "remove_notes" class="btn btn-primary oc-icon-trash-o" data-request="onDelete" data-trigger-type="enable" data-trigger = ".list-checkbox input[type='checkbox']" data-trigger-condition="checked" data-request-success="$el.attr('disabled', 'disabled');" disabled > Remove Note(s)</button> </div> <script> $("#remove_notes").click(function(){ $(this).data('request-data', { notes: $('.list-checkbox input[type=\'checkbox\']').listWidget('getChecked') }) }); </script> 

Новые заметки

Я знаю, что мы уже создали форму для добавления новых заметок, но давайте рассмотрим другой способ сопоставления форм с моделями.

Файл controllers/notes/config_form.yaml отвечает за отображение формы создания / обновления с использованием указанной модели, и его также можно настроить с помощью файла models/note/fields.yaml .

 // controllers/notes/config_form.yaml # Record name name: Note # Model Form Field configuration form: $/rafie/quicknote/models/note/fields.yaml # Model Class name modelClass: RAFIE\Quicknote\Models\Note # Default redirect location defaultRedirect: rafie/quicknote/notes # Create page create: title: Create Notes redirectClose: rafie/quicknote/notes # Update page update: title: Edit Notes redirectClose: rafie/quicknote/notes 

Атрибуты конфигурации являются информативными. Атрибут form отображается на models/note/fields.yaml который решает, как должна отображаться форма. Вы можете прочитать о доступном атрибуте в документах .

 fields: title: placeholder: Title description: type: textarea size: huge placeholder: You have something to say? important: type: hint path: @/plugins/rafie/quicknote/models/note/partials/create_note_hint.htm 

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

Create note form

Если вы заметили страницу URL rafie/quicknote/notes/create , вам может быть интересно, где мы представили форму? Ответ — Backend\Behaviors\FormController реализованный нашим контроллером — он заботится об отображении формы с помощью наших файлов конфигурации.

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

 public function formBeforeCreate($model){ $model->user_id = BackendAuth::getUser()->id; } 

Класс FormController предоставляет набор методов для подключения к событиям формы. Метод formBeforeCreate используется для обновления модели перед сохранением, и вы также можете подключиться к formAfterCreate для formAfterCreate некоторых специальных событий.

Обновление заметок

Для формы обновления нам не понадобятся какие-либо изменения, потому что мы сопоставили поля формы с нашей моделью заметок. Тем не менее, вам может понадобиться добавить некоторые функции. Если у вас есть какой-то код, который нужно выполнить, вы можете использовать метод update и вызвать родительский метод update как расширение. Обязательно изучите класс FormController чтобы увидеть список доступных методов.

 public function update($recordId, $context = null) { //some code here return $this->asExtension('FormController')->update($recordId, $context); } 

Удаление заметок

У нас есть два способа реализовать действие удаления:

  • Используя форму обновления:
    При использовании формы обновления у вас есть значок корзины в правом нижнем углу браузера, и он уже настроен для вас.
  • Использование массового действия:
    Вы помните, что мы установили для showCheckboxes значение true в файле config_list.yaml . Нам нужно только настроить кнопку удаления заметок.

В частичном _list_toolbar.htm есть кнопка New Note . Мы добавим нашу кнопку удаления заметок, используя Ajax-фреймворк OctoberCMS. Если вы не знакомы с AJAX-фреймворком, обязательно ознакомьтесь со статьей, посвященной моей теме OctoberCMS

 // controllers/notes/_list_toolbar.htm <button id = "remove_notes" class="btn btn-primary oc-icon-trash-o" data-request="onDelete" data-trigger-type="enable" data-trigger = ".list-checkbox input[type='checkbox']" data-trigger-condition="checked" data-request-success="$el.attr('disabled', 'disabled');" disabled > Remove Note(s)</button> 

Единственные специальные атрибуты:
— data-trigger: добавить прослушиватель событий для указанного элемента.
— data-trigger-condition: условие может быть checked или значение, если установлено value[myvalue] . Проверьте триггер API для получения дополнительной информации.
— data-request-success: код JavaScript, который будет выполнен после успешного запроса.

 // controllers/notes/_list_toolbar.htm <script> $("#remove_notes").click(function(){ $(this).data('request-data', { notes: $('.list-checkbox input[type=\'checkbox\']').listWidget('getChecked') }) }); </script> 

При событиях щелчка мы должны передать выбранные идентификаторы атрибуту request-data чтобы мы могли обработать их на стороне сервера. Наш контроллер должен иметь метод onDelete для обработки запроса.

 // controllers/Notes.php public function onDelete(){ $user_id = BackendAuth::getUser()->id; $notes = post("notes"); Note::whereIn('id', $notes) ->where('user_id', '=', $user_id) ->delete(); \Flash::success('Notes Successfully deleted.'); return $this->listRefresh(); } 

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

Вывод

Система виджетов OctoberCMS является мощной и гибкой, и она предоставляет набор компонентов для создания и расширения других плагинов. Вы можете посмотреть окончательный результат на Github , и если у вас есть какие-либо вопросы или мнения, дайте мне знать в комментариях!