Создание своего первого модуля в Drupal 8 — это отличный способ начать изучение разработки на этой платформе.
Если вы заинтересованы в разработке на Drupal с технической стороны, а также вам нравится что будет в Drupal 8, да и вообще какой будет Drupal, то самое время начинать учиться кодить под него. Сейчас как раз тот период, когда можно без спешки сидеть и изучать всё новое.
В данной статье не будет ничего сверх-необычного и сложного. Мы создадим модуль, с учётом всех структурных изменений, который будет регистрировать страничку и отдавать по ней Hello World.
Для тех кто знаком с Drupal 7
Раздел посвященный для тех кто уже знаком с Drupal 7. Если же вы под него не программировали, можете смело пропускать.
Итак, вы знакомы c программированием под Drupal 7? Это очень хорошо, стартануть будет немного проще, но всё же, грубо говоря, придется учиться заново. Слишком сильно перелопатили ядро. Первым делом, рекомендую выучить основы ООП в php, если вы с ними не знакомы, конечно, ибо они станут первой стеной на пути к изучению. Могу посоветовать небольшой цикл обучающих материалов на Codecademy. Можно за пол часа понять всю суть ООП, как его использовать в php и т.д., а опыт придет уже непосредственно в момент применения этого всего в Drupal 8.
Что касается API, тут всё немного может оказаться для вас печальным. Подавляющее большинство хуков убрали с концами, поэтому это может вызвать на первых этапах непонимание. Учитывая что пока документация гуглится очень сложно, а среди нагугленного часто попадаются неактуальные, я собираю список изменений среди популярных функций и их замен, возможно окажется полезным.
В остальном же, принципы и идеология остались неизменными. Изменились лишь средства и подходы к разработке, многое упростили, многое усложнили, а некоторое и вовсе убрали, хотя, быть может, это кажется только мне и сейчас, а потом окажется упрощением. Многое может вызывать когнитивный диссонанс, но это нормально, учитывая каким измениям подвергся Drupal.
Общие изменения
В Drupal 8 пересмотрели вообще все. Если идти по пунктикам создания модуля, то изменения начинаются с самых первых пунктов. Теперь модули располагаются не в /sites/all/modules, а в корневой папке /modules.
Все info файлы, а также многие функции, например, hook_menu(), заменены .yml файлами в корне модуля.
Появился стандарт PSR-4, который влияет на структуру папок. Допустим, файлы отвечающие за формы, должны находиться строго по адресу: mymodulename/src/Form, а также подобные мелочи, не учитывая которые, модуль будет работать некорректно. Но к ним привыкаешь после первого же раза, слишком уж мелкие изменения, зато, надо заметить, удобные и правильные. Теперь не будет хаоса в модулях.
Создаем структуру
Для начала выполняем следующие действия:
- В корневой папке modules создаем папку для нашего модуля: helloworld. ( При условии что наш модуль будет называться helloworld).
- Создаем пустой файл helloworld.info.yml.
Эти шаги - набор минимум для создания модуля. Теперь пройдемся по файликам.
helloworld.info.yml
Данный файл, как и в 7 версии, отвечает за базовую информацию о модуле, разница лишь в том, что теперь это всё хранится в новом формате.
Давайте добавим в него следующие строки:
# INFO: Комментарии указываются в yml через хэштег.
# Название модуля (отображается в списке модулей).
name: Hello World
# Описание модуля. Пишется исключительно на английском.
description: 'HelloWorld module - is my first module!'
# Объявляем что это модуль.
type: module
# Версия ядра для которого модуль.
core: 8.x
# Версия модуля.
version: 1.0
# Пакет для модуля. По-сути, просто раздел в модулях где будет распологаться наш модуль.
package: Examples
Более подробно прочитать о .info.yml файлах и что там может быть можно в официальной документации.
На этом базовая подготовка закончена. Модуль должен появится в списке и его уже можно будет включать/удалять.
Создаем страницу с Hello World
Теперь нам необходимо зарегистрировать url нашей будущей страницы и вывести на ней Hello World.
Для начала нам нужно создать контроллер, который будет отвечать за вывод на страницу:
- Создаем в корневой папке модуля новую папку: src.
- Создаем в папке src новую папку: Controller. Папка так и должна называться с большой буквы.
- Теперь создаем файлик с нашим контроллером, его имя уже не особо имеет значения, давайте назовём его: HelloWorldController.php. Название должно начинаться с большой буквы. (ЗАКРЫВАЮЩИЙ ?> не нужен!)
<?php
/**
* @file
* Contains \Drupal\helloworld\Controller\HelloWorldController.
* ^ Пишется по следующему типу:
* - \Drupal - это указывает что данный файл относится к ядру Drupal, ведь
* теперь там еще есть Symfony.
* - helloworld - название модуля.
* - Controller - тип файла. Папка src опускается всегда.
* - HelloWorldController - название нашего класса.
*/
/**
* Пространство имен нашего контроллера. Обратите внимание что оно схоже с тем
* что описано выше, только опускается название нашего класса.
*/
namespace Drupal\helloworld\Controller;
/**
* Используем друпальный класс ControllerBase. Мы будем от него наследоваться,
* а он за нас сделает все обязательные вещи которые присущи всем контроллерам.
*/
use Drupal\Core\Controller\ControllerBase;
/**
* Объявляем наш класс-контроллер.
*/
class HelloWorldController extends ControllerBase {
/**
* {@inheritdoc}
*
* В Drupal 8 очень многое строится на renderable arrays и при отдаче
* из данной функции содержимого для страницы, мы также должны вернуть
* массив который спокойно пройдет через drupal_render().
*/
public function helloWorld() {
$output = array();
$output['#title'] = 'HelloWorld page title';
$output['#markup'] = 'Hello World!';
return $output;
}
}
Контроллер есть, функция отвечающая за вывод тоже, осталось только зарегистрировать страницу, при обращении на которую будет дергаться наш контроллер. Делается все это роутингами, для этого нам понадобится в корневой папке модуля создать новый файл: helloworld.routing.yml.
Данный файл описывает адреса страниц, и что по их обращению будет сделано. Для тех кто знаком с Drupal 7, вы увидите сильное сходство с hook_menu() - ведь это на его замену пришли роутинги и в частности, данная функция заменена этим файлом.
Итак, мы создали файл для роутингов, теперь заполним его:
# Первым делом объявляется машинное имя роута. Оно составляетсям из:
# название_модуля.машинное_название_роута.
helloworld.hellopage:
# Указываем путь роута, с лидирующим слешем.
path: '/hello'
# Значения по умолчанию
defaults:
# Функция контроллера отвечающая за содержимое.
_controller: '\Drupal\helloworld\Controller\HelloWorldController::helloWorld'
# В данном разделе указываются необходимые требования для роута.
requirements:
# Мы будем показывать страницу только тем, у кого есть права на просмотр
# содержимого.
_permission: 'view content'
Сохраняем. Включаем модуль и заходим по адресу: /hello
BINGO!
Готовый модуль прикреплен к материалу.
Ссылки
Комментарии
Спасибо, исправил.
Как-то они сильно намудрили с API для Drupal 8, с 6 и 7 всё понятно, а тут надо сначала с симфони разобраться... В общем бред, на мой взгляд...
Эх,
Как жаль что на битрикс приходится переходить
Почтим минутой молчания.
Результат работы приведенного кода при перехоже по "/hello" - Page not found
Кеш чистили?
Не помогло ...
В маршрутизаторе, изменив в 9-ой строке "_content" на "_controller", как и показано на офсайте (https://www.drupal.org/node/2464207), всё заработало.
Еще что непонятно: в примере роутера используется _permission: 'view content', но он нигде не определен, почему так?
Он определяется ядром друпала. Модуль node
Вроде 'access content' должно быть
Довольно часто люди, приезжающие в Москву или Подмосковье по виду работы бывающих в служебных поездках, а фирма или предприятие то которое их командирует в командировку оплачивает им это поездку, но лишь при условии, что они предоставят своей организации отчетные документы о проживании. Не каждая компания по сдаче квартир или гостиниц может предоставлять данную документацию. Мы как раз та компания которая может вам помочь в это вопросе. Всем приезжающим мы даём отчетные документы для командировочных за проживание в квартире или гостинице г. Москва, или помогаем их восстановить в случае утраты по каким либо причинам.
Скажите, а для чего создавать папку src в корневой папке ? Если просто в модуле создать папку Controller, разве так не будет работать ?
Роман, стандарт PSR-4 обязывает
А подскажите, пожалуйста, как туда темплейтину свою впихнуть (твиговскую). Я что-то пробовал но не получилось. Где-то что-то не так. Я вроде делал все как надо. Прописывал _theme в модуле, но.... Заранее спасибо.
return [
'#theme' => 'template_name',
];
Обясни мне, начинающему, что не так с роутингом?
http://joxi.ru/E2pMbNWi9qPEWA
Почему пробелы необходимы в моем случае? без них не работает. И вызывает ошибку при чистке кеша. Я сутки проколупался, пока не дотямкал.. писал руками, не вносил пробелы. сравнил с твоим решением - вот в них все дело.
У yml файлов очень жесткая структура. Пробелы являются отступами иерархии и парсер понимает что к чему принадлежит. Без них, каждая строка без пробелов для него роут. Их обязательно соблюдать. Я не знаю что тут обьяснить ещё, тут проблема не в роуте, а синтаксисе yaml. Грубо говоря, это превращается в массив и используется как необходимо. Если у вас бы вместо массива $array['route.name']['_controller']
пришли два $array['route.name']
и $array['_controller']
, вы бы тоже не поняли что за контроллер и к кому он относится.
Напиши, пожалуйста, как работать со своей таблицей в базе данных в своем модуле. В интернетах полно описаний типа $query = \Drupal::database()->update('example'); $query->fields([ 'field_1' => $value_1, 'field_2' => $value_2, 'field_3' => $value_3, ]); $query->condition('field_4', $value_4); $query->execute();
Но они не работают, так как в том же интернете нашел фразу " Однако, если вы создаёте собственный модуль, который оперирует своими таблицами, то операции добавления и изменения придётся описывать вручную." Как это лучше сделать? Заранее благодарен.
Решил проблему, дело было не в бабине )
Здравствуйте ) Я просто хотел упомянуть, что мне очень понравилась эта статья !!!
Никлан, дорогой, напиши, будь добр, статью про работу с form API, для изменений node edit - изменение полей, добавление новых элементов и ещё чего. На Drupal 7, легко изменял вс что мне угодно было в node edit, а теперь в ступоре. Никак не могу понять, с чего начать и примеров толком нет в буржуйНете. Сейчас, пробую на данном примере добраться до нужного типа материала, чтобы прописать туда свои классы, вставить виртуальное поле autocomplete для "Place Autocomplete Address Form", чтобы из него передавать нужные мне значения в поля таксономии (Страна, Регион, Город) ибо готовых решений нет. У тебя прекрасно получается совмещать талант разработчика и писателя :) Очень благодарен тебе за тот формат подачи материала с прикреплёнными файлами - ты миссионер Drupal 8 ни только в России, но и во всём, русскоговорящем обществе. Благодарю тебя, Человечище :) Drupal 8 - это нечто. Я все личные проекты переношу на него, после этого, на Семерку сложно смотреть
Не очень понимаю в чем проблема. В 8-у Form API перехал из 7-и без изменений. Ну может вообще в каких-то мелочах, но в целом он такой же. Даже хуки остались те же.
То что вы описываете, попахивает Field Widget Plugin, а не альтером форм редактирования нод. Рекомендую просто глянуть пример виджета тут: https://niklan.net/blog/132
Спасибо, до сих пор полезная статья :) Один вопрос - регистрация целой страницы это хорошо, но если, скажем, надо выводить результат работы модуля в блок, который можно повесить на любой странице? Если ли такие же простые варианты?
Использовать Block Plugin.
Page not found. даже из прилагаемого файла всё скопировал, бесполезно. Может из-за какой-то несовместимости в версиях? Пробую на 8.8.6.
Кэш ребилдили? Можно сделать при помощи команды drush cache:rebuild
или на странице /rebuild.php
.
Добрый день, делаю по вашему уроку, к сожалению такую ошибку выдало в итоге, что может быть? - ReflectionException: Class \Drupal\numeric_matrix\Controller\NumericmatrixController does not exist in ReflectionMethod->__construct() (line 123 of core/lib/Drupal/Core/Entity/EntityResolverManager.php).
Без кода не ясно что происходит.
Ссылка в начале статьи на codecademy уже не рабочая. Наверное стоит заменить на следующую - https://www.codecademy.com/learn/learn-php/modules/classes-and-objects-in-php
Спасибо, поправил.
Сделал всё по данной инструкции, всё работает. Но почему-то страница, предоставляемая модулем доступна только авторизованным пользователям сайта, по крайней мере администратору. Из-под анонимуса получаю "Доступ запрещён Вы не авторизированы для доступа к этой странице."
Все, что в D7 делали в template.php, теперь нужно на каждую задачу писать отдельный модуль?
Не понимаю как вы к такому выводу пришли, но нет, не нужно. Хотите писать отдельные модули, пишите, но можно и в одном.
Плюс template.php
никуда не делся, он теперь просто называется THEMENAME.theme
и работает точно также.
Также не совсем ясно как это связано с модулями. В теме ничего кроме того что нужно теме не пишется, тема для разметки, а не для логики. Код с логикой и в Drupal 7 писали в модулях, а не в template.php
.
Доступ запрещён Вы не авторизированы для доступа к этой странице.
elloworld.module
Тут нам ничего для текущего модуля не нужно. Просто добавим следующие строки (ЗАКРЫВАЮЩИЙ ?> не нужен):Если файл не обязателен теперь.https://www.drupal.org/node/2217931