В предыдущей статье мы говорили об основах создания плагина OctoberCMS. В этом разделе мы углубимся и рассмотрим, как мы можем расширить бэкэнд OctoberCMS с помощью виджетов.
Что мы собираемся построить
Я предполагаю, что многие из вас использовали WordPress . На панели инструментов у нас есть быстрый виджет проекта. В этой статье мы увидим, как мы можем создать аналогичный для OctoberCMS.
Регистрация плагинов
Чтобы начать сборку нашего плагина, мы будем использовать командную утилиту для скаффолдинга.
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
и будет иметь следующую структуру.
Поскольку каждая заметка принадлежит пользователю, у нас есть поле 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
Создание заметок
Папка содержит класс нашего контроллера и еще одну папку для наших ресурсов. Когда кто-то нажимает на 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; ?>
Использование контроллеров
До сих пор мы говорили о рендеринге виджета отчета и его передаче контроллеру. Теперь мы собираемся создать страницу листинга и поговорим о расширении бэкэнда 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
Мы создаем только один текстовый ввод для заголовка и огромную текстовую область для описания. Подсказка — это часть, которую вы можете использовать для отображения уведомлений пользователю.
Если вы заметили страницу 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 , и если у вас есть какие-либо вопросы или мнения, дайте мне знать в комментариях!