Skip to content

Drupal 8

andyceo edited this page Mar 15, 2017 · 3 revisions

Вопросы-ответы по Drupal 8

Что такое плагины?

Как использовать свой Symfony2 бандл в модуле Drupal?

symfony2 bundle as module

Как мигрировать данные с помощью модуля Migrate?

Процедура написания миграции полей:

  • source
  • process
  • destination
  • migration
  • написать yml-файлик

Как мигрировать мультиязычный контент?

[22:47:24] Andy Postnikov: там ведь должен выываться addTranslation
[23:47:22] Andy Postnikov: <chx> andypost: there's some work standard for multilingual stuf in the sandbox
[23:49:40] Andy Postnikov: https://www.drupal.org/node/2105305/git-instructions/drupal6-i18n/nonmaintainer полагаю оно

Источники:

Ресурсы по Drupal 8?

Как использовать Ajax-формы?

  1. В элементе формы, на изменения которого нужно реагировать аяксом, реализовать свойство #ajax.
  2. Написать php-коллбек в классе формы, который будет возвращать тот элемент страницы, который нужно перерисовать. В коллбеке нужно возвращать только тот элемент, который планируется перестроить. Не надо пытаться изменить $form и $form_state.
  3. Вся перестройка формы осуществляется только в конструкторе формы, в зависимости от переданных в форму параметров ($form_state)
  4. Примеры:
  • форма экспорта ConfigSingleExportForm (\Drupal\config\Form\ConfigSingleExportForm)

Последовательность вызовов при срабатывании Ajax в формах:

  1. build (происходит только когда Ajax сработал первый раз, все последующие срабатывания ajax начинаются с validate)
  2. validate
  3. build
  4. ajax callback

Как в своем модуле предоставить блок?

  • Нужно написать плагин блока. Он представляет из себя php-файл с классом плагина. Класс описан аннотацией блокового плагина. php-файл нужно положить в папку yourmodule/src/Plugin/Block/YourModuleBlock.php. Примеры:
    • UserLoginBlock (\Drupal\user\Plugin\Block\UserLoginBlock)
    • BookNavigationBlock (\Drupal\book\Plugin\Block\BookNavigationBlock)

Как создать свое поле?

Нужно создать плагин типа FieldType. Также не забыть определить метод isEmpty(). Также, если какое-то свойство (property) поля - вычисляемое, то можно реализовать метод preSave(), в котором это поле будет вычисляться. В аннотации поля, нужно указать default_widget = "SOME_WIDGET" и default_formatter = "SOME_FORMATTER". Можно не указывать дефолтные виджеты и форматтеры, только в этом случае нужно поставить флаг в аннотации no_ui = TRUE.

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

Сущности (Entity API)

Как создать свою сущность?

  1. class YourEntity extends ContentEntityBase implements YourEntityInterface {
  2. class Slide extends ContentEntityBase { - предпочтительный вариант
  3. class Slide extends Entity {

Как определить базовые поля в сущности?

  • Через реализацию метода baseFieldDefinitions($entity_type). Все получаемые поля являются типа FieldItemList. Внутри метода пишем что-то вроде:

      $fields['your_field'] = FieldDefinition::create('integer')
        ->setLabel(t('Campaign ID'))
        ->траливали();
    
      $fields['uuid'] = FieldDefinition::create('uuid')
        ->setLabel(t('UUID'))
        ->setDescription(t('The YOUR_ENTITY UUID.'))
        ->setRequired(TRUE)
        ->setReadOnly(TRUE);
    
  • Поле uuid - обязательное для любой сущности. распределенный первичный ключ

  • Все возможные типы полей можно посмотреть здесь: core/lib/Drupal/Core/Field/Plugin/Field/FieldType. на момент написания этого текста (30.05.2014) их 17.

  • Краткое описание сеттеров поля (которые FieldDefinition):

    • setLabel() - задает метку поля (string)
    • setDescription() - задает описание поля (string)
    • setReadOnly() - объявляет поле только для чтения, неизменяемое поле (обычно для первичных ключей) (boolean)
    • setRequired() - объявляет поле обязательным для заполнения (boolean)
    • setSetting() - задает настройки поля в терминах поля Drupal 7. Влияет на схему данных (ограничения на хранение поля, схему БД) (array)
    • setDisplayOptions(string $display_context = 'view' or 'form', array $options()) - если 'form' - то задает опции отображения поля в режиме формы (ввод значений в поле). Аналогично объекту form_display у сущности (entity). Если 'view',
    • setDisplayConfigurable(string $display_context = 'view' or 'form', boolean $flag) - устанавливает флаг, что данный $display_context (который может быть 'view' или 'form') можно (или нельзя) настраивать из админки.
    • setPropertyConstraints - задает ограничения при сохранении поля
    • setClass
    • setComputed
    • setConstraints
    • setDataType
    • setItemDefinition
    • setName
    • setQueryable
    • setTranslatable

Где пример самого чистого кода сущностей?

CustomBlock.php

Какие таблицы создаются для сущности?

Entity tables image

Какие возможные контроллеры могут быть у сущности?

controllers = {
  "storage" = "Drupal\yourentity\YourEntityStorage",
  "view_builder" = "Drupal\yourentity\YourEntityViewBuilder",
  "access" = "Drupal\yourentity\YourEntityAccessController",
  "list_builder" = "Drupal\yourentity\YourEntityListBuilder",
  "form" = {
    "default" = "Drupal\yourentity\YourEntityForm",
    "delete" = "Drupal\yourentity\Form\YourEntityDeleteForm",
    "edit" = "Drupal\yourentity\YourEntityForm"
  },
},
  • storage - хранилище сущности. Обязателен. Чтобы выбрать, какой контроллер использовать для вашей сущности, можно руководствоваться следующими правилами:

    • для простой сущности без полей - простой контроллер по умолчанию EntityDatabaseStorage. При этом сохранение в бд придется писать самому, руками. Пример: Drupal\menu_link\Entity\MenuLink
    • для сущности, у которой поля определяются через baseFieldDefinitions(), нужно использовать ContentEntityDatabaseStorage - тогда, если в форме вы поля назвали так же, как в схеме, сохранение произойдет автоматически.
  • view_builder - контроллер, отвечающий за отображение сущности.

  • access - контроллер, отвечающий за доступ к сущности. Позволяет работать с ограничениями доступа к сущности.

  • list_builder - контроллер списка сущности. Он отвечает за генерацию страницы со списком сущностей этого типа. Создается через сервис EntityManager, поэтому на его вход (в конструктор) идут 4 параметра:

    • EntityTypeInterface $entity_info

    • EntityStorageControllerInterface $storage

    • ModuleHandlerInterface $module_handler

    • QueryFactory $query_factor Конструктор должен быть объявлен так:

        public function __construct(EntityTypeInterface $entity_info, EntityStorageInterface $storage, ModuleHandlerInterface $module_handler, QueryFactory $query_factory) {
          parent::__construct($entity_info, $storage, $module_handler);
          $this->queryFactory = $query_factory;
          // enter your specific code here
        }
      

    Также необходимо реализовать метод createInstance(), который создаст экземпляр лист-контроллера.

        public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_info) {
          return new static(
            $entity_info,
            $container->get('entity.manager')->getStorage($entity_info->id()),
            $container->get('module_handler'),
            $container->get('entity.query')
          );
        }
    

    Как правило, контроллер списка должен содержать следующий набор методов:

    • load()
    • buildHeader()
    • buildRow()
    • render()
  • form - массив форм. Формы сущности - это класс, реализующий интерфейс EntityFormInterface. Этот класс является расширенным вариантом обычной формы FormInterface. Самое основное отличие от класса обычной формы - это то, что форма, реализуемая через EntityForm, обязательно связана с сущностью. Это форма именно для сущности. См. Change notice

    • default
    • delete
    • edit

Из всех контроллеров, необходимым для работы с сущностью является только storage-контроллер.

Как сделать поле revisionable, если этого не было сделано изначально?

  1. Ставим в сущности к полю флаг revionable: ->setRevisionable(TRUE)

  2. Затем прогоняем апдейт базы данных

  3. Перенести контент из основной таблицы сущности (base_table) в таблицу с ревизиями:

     UPDATE `base_table_revision` r
     JOIN `base_table` bt ON r.id = bt.id
     SET r.field1 = bt.field1,
         r.field2 = bt.field2,
         r.fieldn = bt.fieldn;
    

Как удалить revisionable для сущности?

Внимание! Все нижеперечисленное, стоит делать, не перемешивая с другими обновлениями схемы этой сущности, особенно, не добавлять новых полей во время этого апдейта; сначала убрать ревизии, а только потом - добавить новое поле. Это связано с тем, что Drupal 8 сделает добавление нового поля только один раз в таблицу, и однажды добавив его, будет думать, что оно там уже есть, даже несмотря на то, что его там нет.

  1. Удаляем из кода все, связанное с ревизиями (из аннотации, убираем у всех полей флаг setRevisionable(TRUE))
  2. Переименовываем base_table в какой-нибудь base_table1
  3. Создаем копию таблицы base_table1 (только структура!) и называем ее base_table. Т.е. создаем копию старой таблицы base_table, но без контента. Это важно, т.к. Drupal обновляет поля только если нет контента.
  4. Проводим апдейт бд из админки под рутом.
  5. Затем, вручную удаляем из переименованной таблицы base_table1 поле revision_id. Удаляем (или переименовываем) таблицу base_table_revision. (где-то на этом шаге, у меня сама собой удалилась таблица base_table_revision).
  6. Переименовываем таблицу base_table1 обратно в base_table.
  7. Заходим в отчеты - отчет о состоянии и проводим еще одно обновление бд, где будут перечислены все поля.
  8. После этого все готово. Можно на всякий случай сделать drush cr, и продолжать работать.

Как пользоваться подсистемой конфигурации Drupal 8?

Если подразумеваются настройки, то нужно:

  1. Создать папки yourmodule/config и yourmodule/config/schema
  2. Создать схему конфига: yourmodule/config/schema/yourmodule.schema.yml. Подробнее о схеме конфига: Configuration schema/metadata
  3. Создать конфиг по умолчанию: yourmodule/config/yourmodule.settings.yml, который содержит настройки по умолчанию.

Где можно посмотреть все возможные типы полей, поддерживаемых схемой БД Drupal?

Ищем функцию getFieldTypeMap() и в классе core/lib/Drupal/Core/Database/Driver/mysql/Schema.php для MySQL увидим, как и какие типы схемы базы данных Drupal соответвуют типам полей в MySQL. Аналогично можно посмотреть для pgsql и sqlite.

Я создал поле типа entity reference, по ошибке оно указывает на неправильную сущность. Можно ли это поменять?

Да. Нужно обновить конфигурацию. Например, нужно поменять ссылку с сущности user на сущность person для Field storage и самого Field (в данном примере поле называется field_person, находится оно в сущности user и ссылается на person):

drush cset field.storage.user.field_person settings.target_type person
drush cset field.field.user.user.field_person settings.handler 'default:person'
drush cr

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

Основные API

Render, render array, themeing

Views

Работа с базой данных

Прямые запросы

Если прямой запрос к базе данных, то смотреть класс \Drupal\Core\Database\Query\Select.

Он имплементирует интерфейсы:

  • Drupal\Core\Database\Query\SelectInterface
  • Drupal\Core\Database\Query\ConditionInterface
    • condition()
    • where()
    • isNull($field)
    • isNotNull($field)
    • exists(SelectInterface $select) - Sets a condition that the specified subquery returns values.
    • notExists(SelectInterface $select) - Sets a condition that the specified subquery returns no values.
    • andConditionGroup()
    • orConditionGroup()

Тесты

Node grants (права на ноды с помощью таблицы node_access)

Концепция простая: на ноды вешаются замки, а пользователю выдаются ключи. От какого замка ключ подошел - настолько нода и приоткрывается пользователю. Важно помнить, что при сохранении ноды вы не обладаете информацией о том, какой пользователь будет смотреть ноду (нет информации о будущих пользователях). А при выдаче ключей пользователю вы не знаете, какие ноды он соберется смотреть.

Поэтому при сложных случаях, следует все признаки ноды закодировать в один grant id (gid) или realm, а динамические, типа совпадение отдела пользователя с отделом материала - в другой.

Используются два хука:

Подробнее по ссылкам:

Сборка

Предположим, что мы уже находимся в сборочной директории, например /tmp/build.

git clone --branch 8.2.x https://git.drupal.org/project/drupal.git

# Installing contrib modules
cd drupal/modules
mkdir contrib
cd contrib
git clone contrib_module1
git clone contrib_module2

# Installing your modules
cd ..
mkdir custom
cd custom
git clone your_module1
git clone your_module2

# Installing your installation profile
cd ../../profiles
git clone your_profile

# Run composer
cd ..
composer install

# Create needed folders and files and get them write permissions
cd sites/default
mkdir -p files/translations files/simpletest
cp default.settings.php settings.php
chown -R www-data: files/ settings.php

Ссылки:

Разные ссылки

Sidebar is under construction

Clone this wiki locally