default services conflit ?

This commit is contained in:
armansansd
2022-04-27 11:30:43 +02:00
parent 28190a5749
commit 8bb1064a3b
8132 changed files with 900138 additions and 426 deletions

View File

@@ -0,0 +1,148 @@
<?php
namespace Drupal\{{ machine_name }}\Plugin\Field\FieldFormatter;
{% sort %}
{% if datetime %}
use Drupal\Core\Datetime\DrupalDateTime;
{% endif %}
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FormatterBase;
{% if formatter_settings %}
use Drupal\Core\Form\FormStateInterface;
{% endif %}
{% if link %}
use Drupal\Core\Url;
{% endif %}
{% if list %}
use Drupal\{{ machine_name }}\Plugin\Field\FieldType\{{ type_class }};
{% endif %}
{% endsort %}
/**
* Plugin implementation of the '{{ field_id }}_default' formatter.
*
* @FieldFormatter(
* id = "{{ field_id }}_default",
* label = @Translation("Default"),
* field_types = {"{{ field_id }}"}
* )
*/
class {{ formatter_class }} extends FormatterBase {
{% if formatter_settings %}
/**
* {@inheritdoc}
*/
public static function defaultSettings() {
return ['foo' => 'bar'] + parent::defaultSettings();
}
/**
* {@inheritdoc}
*/
public function settingsForm(array $form, FormStateInterface $form_state) {
$settings = $this->getSettings();
$element['foo'] = [
'#type' => 'textfield',
'#title' => $this->t('Foo'),
'#default_value' => $settings['foo'],
];
return $element;
}
/**
* {@inheritdoc}
*/
public function settingsSummary() {
$settings = $this->getSettings();
$summary[] = $this->t('Foo: @foo', ['@foo' => $settings['foo']]);
return $summary;
}
{% endif %}
/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items, $langcode) {
$element = [];
foreach ($items as $delta => $item) {
{% for subfield in subfields %}
{% if subfield.type == 'boolean' %}
$element[$delta]['{{ subfield.machine_name }}'] = [
'#type' => 'item',
'#title' => $this->t('{{ subfield.name }}'),
'#markup' => $item->{{ subfield.machine_name }} ? $this->t('Yes') : $this->t('No'),
];
{% else %}
if ($item->{{ subfield.machine_name }}) {
{% if subfield.list %}
$allowed_values = {{ type_class }}::{{ subfield.allowed_values_method }}();
{% endif %}
{% set item_value %}
{% if subfield.list %}$allowed_values[$item->{{ subfield.machine_name }}]{% else %}$item->{{ subfield.machine_name }}{% endif %}
{% endset %}
{% if subfield.type == 'datetime' %}
$date = DrupalDateTime::createFromFormat('{{ subfield.date_storage_format }}', $item->{{ subfield.machine_name }});
// @DCG: Consider injecting the date formatter service.
// @codingStandardsIgnoreStart
$date_formatter = \Drupal::service('date.formatter');
// @codingStandardsIgnoreStart
$timestamp = $date->getTimestamp();
{% if subfield.list %}
$formatted_date = {{ item_value }};
{% else %}
$formatted_date = $date_formatter->format($timestamp, 'long');
{% endif %}
$iso_date = $date_formatter->format($timestamp, 'custom', 'Y-m-d\TH:i:s') . 'Z';
$element[$delta]['{{ subfield.machine_name }}'] = [
'#type' => 'item',
'#title' => $this->t('{{ subfield.name }}'),
'content' => [
'#theme' => 'time',
'#text' => $formatted_date,
'#html' => FALSE,
'#attributes' => [
'datetime' => $iso_date,
],
'#cache' => [
'contexts' => [
'timezone',
],
],
],
];
{% else %}
$element[$delta]['{{ subfield.machine_name }}'] = [
'#type' => 'item',
'#title' => $this->t('{{ subfield.name }}'),
{% if subfield.link %}
'content' => [
'#type' => 'link',
'#title' => {{ item_value }},
{% if subfield.type == 'email' %}
'#url' => Url::fromUri('mailto:' . $item->{{ subfield.machine_name }}),
{% elseif subfield.type == 'telephone' %}
'#url' => Url::fromUri('tel:' . rawurlencode(preg_replace('/\s+/', '', $item->{{ subfield.machine_name }}))),
{% elseif subfield.type == 'uri' %}
'#url' => Url::fromUri($item->{{ subfield.machine_name }}),
{% endif %}
],
{% else %}
'#markup' => {{ item_value }},
{% endif %}
];
{% endif %}
}
{% endif %}
{% endfor %}
}
return $element;
}
}

View File

@@ -0,0 +1,105 @@
<?php
namespace Drupal\{{ machine_name }}\Plugin\Field\FieldFormatter;
{% sort %}
{% if datetime %}
use Drupal\Core\Datetime\DrupalDateTime;
{% endif %}
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FormatterBase;
{% if list %}
use Drupal\{{ machine_name }}\Plugin\Field\FieldType\{{ type_class }};
{% endif %}
{% endsort %}
/**
* Plugin implementation of the '{{ field_id }}_key_value' formatter.
*
* @FieldFormatter(
* id = "{{ field_id }}_key_value",
* label = @Translation("Key-value"),
* field_types = {"{{ field_id }}"}
* )
*/
class {{ key_value_formatter_class }} extends FormatterBase {
/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items, $langcode) {
$element = [];
foreach ($items as $delta => $item) {
$table = [
'#type' => 'table',
];
{% for subfield in subfields %}
// {{ subfield.name }}.
if ($item->{{ subfield.machine_name }}) {
{% if subfield.type == 'datetime' %}
$date = DrupalDateTime::createFromFormat('{{ subfield.date_storage_format }}', $item->{{ subfield.machine_name }});
$date_formatter = \Drupal::service('date.formatter');
$timestamp = $date->getTimestamp();
{% if subfield.list %}
$allowed_values = {{ type_class }}::{{ subfield.allowed_values_method }}();
$formatted_date = $allowed_values[$item->{{ subfield.machine_name }}];
{% else %}
$formatted_date = $date_formatter->format($timestamp, 'long');
{% endif %}
$iso_date = $date_formatter->format($timestamp, 'custom', 'Y-m-d\TH:i:s') . 'Z';
{% elseif subfield.list %}
$allowed_values = {{ type_class }}::{{ subfield.allowed_values_method }}();
{% endif %}
$table['#rows'][] = [
'data' => [
[
'header' => TRUE,
'data' => [
'#markup' => $this->t('{{ subfield.name }}'),
],
],
[
'data' => [
{% if subfield.type == 'boolean' %}
'#markup' => $item->{{ subfield.machine_name }} ? $this->t('Yes') : $this->t('No'),
{% elseif subfield.type == 'datetime' %}
'#theme' => 'time',
'#text' => $formatted_date,
'#html' => FALSE,
'#attributes' => [
'datetime' => $iso_date,
],
'#cache' => [
'contexts' => [
'timezone',
],
],
{% else %}
{% if subfield.list %}
'#markup' => $allowed_values[$item->{{ subfield.machine_name }}],
{% else %}
'#markup' => $item->{{ subfield.machine_name }},
{% endif %}
{% endif %}
],
],
],
'no_striping' => TRUE,
];
}
{% endfor %}
$element[$delta] = $table;
}
return $element;
}
}

View File

@@ -0,0 +1,4 @@
{{ field_id }}:
css:
component:
css/{{ field_id|u2h }}-widget.css: {}

View File

@@ -0,0 +1,50 @@
{% if storage_settings %}
# Field storage.
field.storage_settings.{{ field_id }}:
type: mapping
label: Example storage settings
mapping:
foo:
type: string
label: Foo
{% endif %}
{% if instance_settings %}
# Field instance.
field.field_settings.{{ field_id }}:
type: mapping
label: Example field settings
mapping:
bar:
type: string
label: Bar
{% endif %}
# Default value.
field.value.{{ field_id }}:
type: mapping
label: Default value
mapping:
{% for subfield in subfields %}
{{ subfield.machine_name }}:
type: {{ subfield.type }}
label: {{ subfield.name }}
{% endfor %}
{% if widget_settings %}
# Field widget.
field.widget.settings.{{ field_id }}:
type: mapping
label: Example widget settings
mapping:
foo:
type: string
label: Foo
{% endif %}
{% if formatter_settings %}
# Field formatter.
field.formatter.settings.{{ field_id }}_default:
type: mapping
label: Example formatter settings
mapping:
foo:
type: string
label: Foo
{% endif %}

View File

@@ -0,0 +1,102 @@
<?php
namespace Drupal\{{ machine_name }}\Plugin\Field\FieldFormatter;
{% sort %}
{% if datetime %}
use Drupal\Core\Datetime\DrupalDateTime;
{% endif %}
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FormatterBase;
{% if list %}
use Drupal\{{ machine_name }}\Plugin\Field\FieldType\{{ type_class }};
{% endif %}
{% endsort %}
/**
* Plugin implementation of the '{{ field_id }}_table' formatter.
*
* @FieldFormatter(
* id = "{{ field_id }}_table",
* label = @Translation("Table"),
* field_types = {"{{ field_id }}"}
* )
*/
class {{ table_formatter_class }} extends FormatterBase {
/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items, $langcode) {
$header[] = '#';
{% for subfield in subfields %}
$header[] = $this->t('{{ subfield.name }}');
{% endfor %}
$table = [
'#type' => 'table',
'#header' => $header,
];
foreach ($items as $delta => $item) {
$row = [];
$row[]['#markup'] = $delta + 1;
{% for subfield in subfields %}
{% if subfield.type == 'boolean' %}
$row[]['#markup'] = $item->{{ subfield.machine_name }} ? $this->t('Yes') : $this->t('No');
{% elseif subfield.type == 'datetime' %}
if ($item->{{ subfield.machine_name }}) {
$date = DrupalDateTime::createFromFormat('{{ subfield.date_storage_format }}', $item->{{ subfield.machine_name }});
$date_formatter = \Drupal::service('date.formatter');
$timestamp = $date->getTimestamp();
{% if subfield.list %}
$allowed_values = {{ type_class }}::{{ subfield.allowed_values_method }}();
$formatted_date = $allowed_values[$item->{{ subfield.machine_name }}];
{% else %}
$formatted_date = $date_formatter->format($timestamp, 'long');
{% endif %}
$iso_date = $date_formatter->format($timestamp, 'custom', 'Y-m-d\TH:i:s') . 'Z';
$row[] = [
'#theme' => 'time',
'#text' => $formatted_date,
'#html' => FALSE,
'#attributes' => [
'datetime' => $iso_date,
],
'#cache' => [
'contexts' => [
'timezone',
],
],
];
}
else {
$row[]['#markup'] = '';
}
{% else %}
{% if subfield.list %}
if ($item->{{ subfield.machine_name }}) {
$allowed_values = {{ type_class }}::{{ subfield.allowed_values_method }}();
$row[]['#markup'] = $allowed_values[$item->{{ subfield.machine_name }}];
}
else {
$row[]['#markup'] = '';
}
{% else %}
$row[]['#markup'] = $item->{{ subfield.machine_name }};
{% endif %}
{% endif %}
{% endfor %}
$table[$delta] = $row;
}
return [$table];
}
}

View File

@@ -0,0 +1,316 @@
<?php
namespace Drupal\{{ machine_name }}\Plugin\Field\FieldType;
{% if random %}
use Drupal\Component\Utility\Random;
{% endif %}
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
{% if storage_settings or instance_settings %}
use Drupal\Core\Form\FormStateInterface;
{% endif %}
{% if email %}
use Drupal\Core\Render\Element\Email;
{% endif %}
use Drupal\Core\TypedData\DataDefinition;
/**
* Defines the '{{ field_id }}' field type.
*
* @FieldType(
* id = "{{ field_id }}",
* label = @Translation("{{ field_label }}"),
* category = @Translation("General"),
* default_widget = "{{ field_id }}",
* default_formatter = "{{ field_id }}_default"
* )
*/
class {{ type_class }} extends FieldItemBase {
{% if storage_settings %}
/**
* {@inheritdoc}
*/
public static function defaultStorageSettings() {
$settings = ['foo' => 'example'];
return $settings + parent::defaultStorageSettings();
}
/**
* {@inheritdoc}
*/
public function storageSettingsForm(array &$form, FormStateInterface $form_state, $has_data) {
$settings = $this->getSettings();
$element['foo'] = [
'#type' => 'textfield',
'#title' => $this->t('Foo'),
'#default_value' => $settings['foo'],
'#disabled' => $has_data,
];
return $element;
}
{% endif %}
{% if instance_settings %}
/**
* {@inheritdoc}
*/
public static function defaultFieldSettings() {
$settings = ['bar' => 'example'];
return $settings + parent::defaultFieldSettings();
}
/**
* {@inheritdoc}
*/
public function fieldSettingsForm(array $form, FormStateInterface $form_state) {
$settings = $this->getSettings();
$element['bar'] = [
'#type' => 'textfield',
'#title' => $this->t('Foo'),
'#default_value' => $settings['bar'],
];
return $element;
}
{% endif %}
/**
* {@inheritdoc}
*/
public function isEmpty() {
{% for subfield in subfields %}
{% set condition %}
{% if subfield.type == 'boolean' %}$this->{{ subfield.machine_name }} == 1{% else %}$this->{{ subfield.machine_name }} !== NULL{% endif %}
{% endset %}
{% if loop.index == 1 %}
if ({{ condition }}) {
{% else %}
elseif ({{ condition }}) {
{% endif %}
return FALSE;
}
{% endfor %}
return TRUE;
}
/**
* {@inheritdoc}
*/
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
{% for subfield in subfields %}
$properties['{{ subfield.machine_name }}'] = DataDefinition::create('{{ subfield.data_type }}')
->setLabel(t('{{ subfield.name }}'));
{% endfor %}
return $properties;
}
/**
* {@inheritdoc}
*/
public function getConstraints() {
$constraints = parent::getConstraints();
{% for subfield in subfields %}
{% if subfield.list %}
$options['{{ subfield.machine_name }}']['AllowedValues'] = array_keys({{ type_class }}::{{ subfield.allowed_values_method }}());
{% endif %}
{% if subfield.required %}
{% if subfield.type == 'boolean' %}
// NotBlank validator is not suitable for booleans because it does not
// recognize '0' as an empty value.
$options['{{ subfield.machine_name }}']['AllowedValues']['choices'] = [1];
$options['{{ subfield.machine_name }}']['AllowedValues']['message'] = $this->t('This value should not be blank.');
{% else %}
$options['{{ subfield.machine_name }}']['NotBlank'] = [];
{% if subfield.type == 'email' %}
$options['{{ subfield.machine_name }}']['Length']['max'] = Email::EMAIL_MAX_LENGTH;
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
{% if list or required %}
$constraint_manager = \Drupal::typedDataManager()->getValidationConstraintManager();
$constraints[] = $constraint_manager->create('ComplexData', $options);
{% endif %}
// @todo Add more constraints here.
return $constraints;
}
/**
* {@inheritdoc}
*/
public static function schema(FieldStorageDefinitionInterface $field_definition) {
$columns = [
{% for subfield in subfields %}
'{{ subfield.machine_name }}' => [
{% if subfield.type == 'boolean' %}
'type' => 'int',
'size' => 'tiny',
{% elseif subfield.type == 'string' %}
'type' => 'varchar',
'length' => 255,
{% elseif subfield.type == 'text' %}
'type' => 'text',
'size' => 'big',
{% elseif subfield.type == 'integer' %}
'type' => 'int',
'size' => 'normal',
{% elseif subfield.type == 'float' %}
'type' => 'float',
'size' => 'normal',
{% elseif subfield.type == 'numeric' %}
'type' => 'numeric',
'precision' => 10,
'scale' => 2,
{% elseif subfield.type == 'email' %}
'type' => 'varchar',
'length' => Email::EMAIL_MAX_LENGTH,
{% elseif subfield.type == 'telephone' %}
'type' => 'varchar',
'length' => 255,
{% elseif subfield.type == 'uri' %}
'type' => 'varchar',
'length' => 2048,
{% elseif subfield.type == 'datetime' %}
'type' => 'varchar',
'length' => 20,
{% endif %}
],
{% endfor %}
];
$schema = [
'columns' => $columns,
// @DCG Add indexes here if necessary.
];
return $schema;
}
/**
* {@inheritdoc}
*/
public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
{% if random %}
$random = new Random();
{% endif %}
{% for subfield in subfields %}
{% if subfield.list %}
$values['{{ subfield.machine_name }}'] = array_rand(self::{{ subfield.allowed_values_method }}());
{% elseif subfield.type == 'boolean' %}
$values['{{ subfield.machine_name }}'] = (bool) mt_rand(0, 1);
{% elseif subfield.type == 'string' %}
$values['{{ subfield.machine_name }}'] = $random->word(mt_rand(1, 255));
{% elseif subfield.type == 'text' %}
$values['{{ subfield.machine_name }}'] = $random->paragraphs(5);
{% elseif subfield.type == 'integer' %}
$values['{{ subfield.machine_name }}'] = mt_rand(-1000, 1000);
{% elseif subfield.type == 'float' %}
$scale = rand(1, 5);
$random_decimal = mt_rand() / mt_getrandmax() * (1000 - 0);
$values['{{ subfield.machine_name }}'] = floor($random_decimal * pow(10, $scale)) / pow(10, $scale);
{% elseif subfield.type == 'numeric' %}
$scale = rand(10, 2);
$random_decimal = -1000 + mt_rand() / mt_getrandmax() * (-1000 - 1000);
$values['{{ subfield.machine_name }}'] = floor($random_decimal * pow(10, $scale)) / pow(10, $scale);
{% elseif subfield.type == 'email' %}
$values['{{ subfield.machine_name }}'] = strtolower($random->name()) . '@example.com';
{% elseif subfield.type == 'telephone' %}
$values['{{ subfield.machine_name }}'] = mt_rand(pow(10, 8), pow(10, 9) - 1);
{% elseif subfield.type == 'uri' %}
$tlds = ['com', 'net', 'gov', 'org', 'edu', 'biz', 'info'];
$domain_length = mt_rand(7, 15);
$protocol = mt_rand(0, 1) ? 'https' : 'http';
$www = mt_rand(0, 1) ? 'www' : '';
$domain = $random->word($domain_length);
$tld = $tlds[mt_rand(0, (count($tlds) - 1))];
$values['{{ subfield.machine_name }}'] = "$protocol://$www.$domain.$tld";
{% elseif subfield.type == 'datetime' %}
$timestamp = \Drupal::time()->getRequestTime() - mt_rand(0, 86400 * 365);
$values['{{ subfield.machine_name }}'] = gmdate('{{ subfield.date_storage_format }}', $timestamp);
{% endif %}
{% endfor %}
return $values;
}
{% for subfield in subfields %}
{% if subfield.list %}
/**
* Returns allowed values for '{{ subfield.machine_name }}' sub-field.
*
* @return array
* The list of allowed values.
*/
public static function {{ subfield.allowed_values_method }}() {
return [
{% if subfield.type == 'string' %}
'alpha' => t('Alpha'),
'beta' => t('Beta'),
'gamma' => t('Gamma'),
{% elseif subfield.type == 'integer' %}
123 => 123,
456 => 456,
789 => 789,
{% elseif subfield.type == 'float' %}
'12.3' => '12.3',
'4.56' => '4.56',
'0.789' => '0.789',
{% elseif subfield.type == 'numeric' %}
'12.35' => '12.35',
'45.65' => '45.65',
'78.95' => '78.95',
{% elseif subfield.type == 'email' %}
'alpha@example.com' => 'alpha@example.com',
'beta@example.com' => 'beta@example.com',
'gamma@example.com' => 'gamma@example.com',
{% elseif subfield.type == 'telephone' %}
'71234567001' => '+7(123)45-67-001',
'71234567002' => '+7(123)45-67-002',
'71234567003' => '+7(123)45-67-003',
{% elseif subfield.type == 'uri' %}
'https://example.com' => 'https://example.com',
'http://www.php.net' => 'http://www.php.net',
'https://www.drupal.org' => 'https://www.drupal.org',
{% elseif subfield.type == 'datetime' %}
{% if subfield.date_type == 'date' %}
'2018-01-01' => '1 January 2018',
'2018-02-01' => '1 February 2018',
'2018-03-01' => '1 March 2018',
{% else %}
'2018-01-01T00:10:10' => '1 January 2018, 00:10:10',
'2018-02-01T00:20:20' => '1 February 2018, 00:20:20',
'2018-03-01T00:30:30' => '1 March 2018, 00:30:30',
{% endif %}
{% endif %}
];
}
{% endif %}
{% endfor %}
}

View File

@@ -0,0 +1,13 @@
{% set class = field_id|u2h ~ '-elements' %}
{% if inline %}
.container-inline.{{ class }} .form-item {
margin: 0 3px;
}
.container-inline.{{ class }} label {
display: block;
}
{% else %}
tr.odd .{{ class }} .form-item {
margin-bottom: 8px;
}
{% endif %}

View File

@@ -0,0 +1,202 @@
<?php
namespace Drupal\{{ machine_name }}\Plugin\Field\FieldWidget;
{% sort %}
{% if datetime %}
use Drupal\Core\Datetime\DrupalDateTime;
{% endif %}
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;
use Symfony\Component\Validator\ConstraintViolationInterface;
{% if list %}
use Drupal\{{ machine_name }}\Plugin\Field\FieldType\{{ type_class }};
{% endif %}
{% endsort %}
/**
* Defines the '{{ field_id }}' field widget.
*
* @FieldWidget(
* id = "{{ field_id }}",
* label = @Translation("{{ field_label }}"),
* field_types = {"{{ field_id }}"},
* )
*/
class {{ widget_class }} extends WidgetBase {
{% if widget_settings %}
/**
* {@inheritdoc}
*/
public static function defaultSettings() {
return ['foo' => 'bar'] + parent::defaultSettings();
}
/**
* {@inheritdoc}
*/
public function settingsForm(array $form, FormStateInterface $form_state) {
$settings = $this->getSettings();
$element['foo'] = [
'#type' => 'textfield',
'#title' => $this->t('Foo'),
'#default_value' => $settings['foo'],
];
return $element;
}
/**
* {@inheritdoc}
*/
public function settingsSummary() {
$settings = $this->getSettings();
$summary[] = $this->t('Foo: @foo', ['@foo' => $settings['foo']]);
return $summary;
}
{% endif %}
/**
* {@inheritdoc}
*/
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
{% for subfield in subfields %}
{% set title %}'#title' => $this->t('{{ subfield.name }}'),{% endset %}
{% set default_value %}'#default_value' => isset($items[$delta]->{{ subfield.machine_name }}) ? $items[$delta]->{{ subfield.machine_name }} : NULL,{% endset %}
{% set size %}'#size' => 20,{% endset %}
{% if subfield.list %}
$element['{{ subfield.machine_name }}'] = [
'#type' => 'select',
{{ title }}
'#options' => ['' => $this->t('- {{ subfield.required ? 'Select a value' : 'None' }} -')] + {{ type_class }}::{{ subfield.allowed_values_method }}(),
{{ default_value }}
];
{% else %}
{% if subfield.type == 'boolean' %}
$element['{{ subfield.machine_name }}'] = [
'#type' => 'checkbox',
{{ title }}
{{ default_value }}
];
{% elseif subfield.type == 'string' %}
$element['{{ subfield.machine_name }}'] = [
'#type' => 'textfield',
{{ title }}
{{ default_value }}
{% if inline %}
{{ size }}
{% endif %}
];
{% elseif subfield.type == 'text' %}
$element['{{ subfield.machine_name }}'] = [
'#type' => 'textarea',
{{ title }}
{{ default_value }}
];
{% elseif subfield.type == 'integer' %}
$element['{{ subfield.machine_name }}'] = [
'#type' => 'number',
{{ title }}
{{ default_value }}
];
{% elseif subfield.type == 'float' %}
$element['{{ subfield.machine_name }}'] = [
'#type' => 'number',
{{ title }}
{{ default_value }}
'#step' => 0.001,
];
{% elseif subfield.type == 'numeric' %}
$element['{{ subfield.machine_name }}'] = [
'#type' => 'number',
{{ title }}
{{ default_value }}
'#step' => 0.01,
];
{% elseif subfield.type == 'email' %}
$element['{{ subfield.machine_name }}'] = [
'#type' => 'email',
{{ title }}
{{ default_value }}
{% if inline %}
{{ size }}
{% endif %}
];
{% elseif subfield.type == 'telephone' %}
$element['{{ subfield.machine_name }}'] = [
'#type' => 'tel',
{{ title }}
{{ default_value }}
{% if inline %}
{{ size }}
{% endif %}
];
{% elseif subfield.type == 'uri' %}
$element['{{ subfield.machine_name }}'] = [
'#type' => 'url',
{{ title }}
{{ default_value }}
{% if inline %}
{{ size }}
{% endif %}
];
{% elseif subfield.type == 'datetime' %}
$element['{{ subfield.machine_name }}'] = [
'#type' => 'datetime',
{{ title }}
'#default_value' => NULL,
{% if subfield.date_type == 'date' %}
'#date_time_element' => 'none',
'#date_time_format' => '',
{% endif %}
];
if (isset($items[$delta]->{{ subfield.machine_name }})) {
$element['{{ subfield.machine_name }}']['#default_value'] = DrupalDateTime::createFromFormat(
'{{ subfield.date_storage_format }}',
$items[$delta]->{{ subfield.machine_name }},
'UTC'
);
}
{% endif %}
{% endif %}
{% endfor %}
$element['#theme_wrappers'] = ['container', 'form_element'];
{% if inline %}
$element['#attributes']['class'][] = 'container-inline';
{% endif %}
$element['#attributes']['class'][] = '{{ field_id|u2h }}-elements';
$element['#attached']['library'][] = '{{ machine_name }}/{{ field_id }}';
return $element;
}
/**
* {@inheritdoc}
*/
public function errorElement(array $element, ConstraintViolationInterface $violation, array $form, FormStateInterface $form_state) {
return isset($violation->arrayPropertyPath[0]) ? $element[$violation->arrayPropertyPath[0]] : $element;
}
/**
* {@inheritdoc}
*/
public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
foreach ($values as $delta => $value) {
{% for subfield in subfields %}
if ($value['{{ subfield.machine_name }}'] === '') {
$values[$delta]['{{ subfield.machine_name }}'] = NULL;
}
{% if subfield.type == 'datetime' %}
if ($value['{{ subfield.machine_name }}'] instanceof DrupalDateTime) {
$values[$delta]['{{ subfield.machine_name }}'] = $value['{{ subfield.machine_name }}']->format('{{ subfield.date_storage_format }}');
}
{% endif %}
{% endfor %}
}
return $values;
}
}

View File

@@ -0,0 +1,18 @@
/**
* @file
* Custom behaviors for {{ layout_name|lower }} layout.
*/
(function (Drupal) {
'use strict';
Drupal.behaviors.{{ layout_machine_name|camelize(false) }} = {
attach: function (context, settings) {
console.log('It works!');
}
};
} (Drupal));

View File

@@ -0,0 +1,16 @@
{{ machine_name }}_{{ layout_machine_name }}:
label: '{{ layout_name }}'
category: '{{ category }}'
path: layouts/{{ layout_machine_name }}
template: {{ layout_machine_name|u2h }}
{% if js or css %}
library: {{ machine_name }}/{{ layout_machine_name }}
{% endif %}
regions:
main:
label: Main content
sidebar:
label: Sidebar
default_region: main
icon_map:
- [main, main, sidebar]

View File

@@ -0,0 +1,10 @@
{{ layout_machine_name }}:
{% if js %}
js:
layouts/{{ layout_machine_name }}/{{ layout_machine_name|u2h }}.js: {}
{% endif %}
{% if css %}
css:
component:
layouts/{{ layout_machine_name }}/{{ layout_machine_name|u2h }}.css: {}
{% endif %}

View File

@@ -0,0 +1,28 @@
.layout--{{ layout_machine_name|u2h }} {
outline: solid 1px orange;
display: flex;
padding: 10px;
}
.layout--{{ layout_machine_name|u2h }} > .layout__region {
outline: solid 1px orange;
margin: 10px;
padding: 20px;
}
.layout--{{ layout_machine_name|u2h }} .layout__region--main {
width: 66%;
}
.layout--{{ layout_machine_name|u2h }} .layout__region--sidebar {
width: 33%;
}
@media all and (max-width: 850px) {
.layout--{{ layout_machine_name|u2h }} {
flex-direction: column;
}
.layout--{{ layout_machine_name|u2h }} > .layout__region {
width: auto;
}
}

View File

@@ -0,0 +1,37 @@
{{ '{' }}#
/**
* @file
* Default theme implementation to display {{ layout_name|lower }} layout.
*
* Available variables:
* - content: The content for this layout.
* - attributes: HTML attributes for the layout wrapper.
*
* @ingroup themeable
*/
#{{ '}' }}
{{ '{' }}%
set classes = [
'layout',
'layout--{{ layout_machine_name|u2h }}',
]
%{{ '}' }}
{% verbatim %}
{% if content %}
<div{{ attributes.addClass(classes) }}>
{% if content.main %}
<div {{ region_attributes.main.addClass('layout__region', 'layout__region--main') }}>
{{ content.main }}
</div>
{% endif %}
{% if content.sidebar %}
<div {{ region_attributes.sidebar.addClass('layout__region', 'layout__region--sidebar') }}>
{{ content.sidebar }}
</div>
{% endif %}
</div>
{% endif %}
{% endverbatim %}

View File

@@ -0,0 +1,40 @@
<?php
namespace Drush\Commands;
use Consolidation\AnnotatedCommand\CommandData;
/**
* Site policy.
*/
class PolicyCommands extends DrushCommands {
/**
* Limit sql-sync operations to remote sites.
*
* @hook validate sql:sync
*
* @throws \Exception
*/
public function sqlSyncValidate(CommandData $commandData) {
$target = $commandData->input()->getArgument('target');
if ($target != '@local') {
throw new \Exception(dt('Per !file, you may never overwrite the remote database.', ['!file' => __FILE__]));
}
}
/**
* Limit rsync operations to remote sites.
*
* @hook validate core:rsync
*
* @throws \Exception
*/
public function rsyncValidate(CommandData $commandData) {
$target = $commandData->input()->getArgument('target');
if (strpos($target, '@prod') == 0) {
throw new \Exception(dt('Per !file, you may never rsync to the remote site.', ['!file' => __FILE__]));
}
}
}

View File

@@ -0,0 +1,16 @@
# Edit or remove this file as needed.
# Docs at https://github.com/drush-ops/drush/blob/master/examples/example.site.yml
prod:
host: example.com
user: prod-user
root: /path/to/drupal
uri: http://www.example.com
stage:
host: stage.example.com
user: stage-user
root: /path/to/drupal
uri: http://stage.example.com
local:
uri: http://localhost

View File

@@ -0,0 +1,28 @@
# Copy and rename this file to .env at root of this project.
#
# A common use case is to supply database credentials via the environment.
# Edit settings.php like so:
#
# $databases['default']['default'] = [
# 'database' => getenv('MYSQL_DATABASE'),
# 'driver' => 'mysql',
# 'host' => getenv('MYSQL_HOST'),
# 'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql',
# 'password' => getenv('MYSQL_PASSWORD'),
# 'port' => getenv('MYSQL_PORT'),
# 'prefix' => '',
# 'username' => getenv('MYSQL_USER'),
# ];
#
# Uncomment and populate as needed.
# MYSQL_DATABASE=
# MYSQL_HOST=
# MYSQL_PASSWORD=
# MYSQL_PORT=
# MYSQL_USER=
{% if drush %}
# Another common use case is to set Drush's --uri via environment.
# DRUSH_OPTIONS_URI=http://localhost
{% endif %}

View File

@@ -0,0 +1,26 @@
# Ignore directories generated by Composer.
{% if drush %}
/drush/contrib/
{% endif %}
/vendor/
/{{ document_root_path }}core/
/{{ document_root_path }}modules/contrib/
/{{ document_root_path }}themes/contrib/
/{{ document_root_path }}profiles/contrib/
/{{ document_root_path }}libraries/
# Ignore sensitive information.
/{{ document_root_path }}sites/*/settings.php
/{{ document_root_path }}sites/*/settings.local.php
# Ignore Drupal's file directory.
/{{ document_root_path }}sites/*/files/
# Ignore SimpleTest multi-site environment.
/{{ document_root_path }}sites/simpletest/
# Ignore files generated by PhpStorm.
/.idea/
# Ignore .env files as they are personal.
/.env

View File

@@ -0,0 +1,16 @@
<?php
/**
* @file
* Loads environment variables from .env files.
*
* This file is included very early.
* @see composer.json For autoload section.
*/
use Symfony\Component\Dotenv\Dotenv;
$file = __DIR__ . '/.env';
if (file_exists($file)) {
(new Dotenv())->load($file);
}

View File

@@ -0,0 +1,13 @@
<?xml version="1.0"?>
<ruleset name="Default">
<description>PHP CodeSniffer configuration for "{{ name }}" project.</description>
<config name="installed_paths" value="vendor/drupal/coder/coder_sniffer"/>
<arg name="colors"/>
<arg value="p"/>
<file>./{{ document_root_path }}modules/custom</file>
{% if drush %}
<file>./drush/Commands</file>
{% endif %}
<rule ref="Drupal"/>
<rule ref="DrupalPractice"/>
</ruleset>

View File

@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copy the samples below into your own phpunit.xml file.-->
<!-- Using this project's bootstrap file allows tests in `ExistingSite`,
`ExistingSiteSelenium2DriverTest`, and `ExistingSiteWebDriverTest`
to run alongside core's test types. -->
<phpunit bootstrap="vendor/weitzman/drupal-test-traits/src/bootstrap-fast.php">
<php>
<env name="DTT_BASE_URL" value="http://example.com"/>
<env name="DTT_API_URL" value="http://localhost:9222"/>
<!-- <env name="DTT_MINK_DRIVER_ARGS" value='["chrome", { "chromeOptions" : { "w3c": false } }, "http://localhost:4444/wd/hub"]'/> -->
<env name="DTT_MINK_DRIVER_ARGS" value='["firefox", null, "http://localhost:4444/wd/hub"]'/>
<env name="DTT_API_OPTIONS" value='{"socketTimeout": 360, "domWaitTimeout": 3600000}' />
<!-- Example BROWSERTEST_OUTPUT_DIRECTORY value: /tmp
Specify a temporary directory for storing debug images and html documents.
These artifacts get copied to /sites/simpletest/browser_output by BrowserTestBase. -->
<env name="BROWSERTEST_OUTPUT_DIRECTORY" value=""/>
<!-- To disable deprecation testing completely uncomment the next line. -->
<!--<env name="SYMFONY_DEPRECATIONS_HELPER" value="disabled"/>-->
<!-- Specify the default directory screenshots should be placed. -->
<!--<env name="DTT_SCREENSHOT_REPORT_DIRECTORY" value=""/>-->
</php>
<testsuites>
<testsuite name="unit">
<directory>./{{ document_root_path }}modules/custom/*/tests/src/Unit</directory>
<!--<directory>./web/profiles/custom/*/tests/src/Unit</directory>-->
</testsuite>
<testsuite name="kernel">
<directory>./{{ document_root_path }}modules/custom/*/tests/src/Kernel</directory>
<!--<directory>./web/profiles/custom/*/tests/src/Kernel</directory>-->
</testsuite>
<testsuite name="existing-site">
<!-- Assumes tests are namespaced as \Drupal\Tests\custom_foo\ExistingSite. -->
<directory>./{{ document_root_path }}modules/custom/*/tests/src/ExistingSite</directory>
<!--<directory>./web/profiles/custom/*/tests/src/ExistingSite</directory>-->
</testsuite>
<testsuite name="existing-site-javascript">
<!-- Assumes tests are namespaced as \Drupal\Tests\custom_foo\ExistingSiteJavascript. -->
<directory>./{{ document_root_path }}modules/custom/*/tests/src/ExistingSiteJavascript</directory>
<!--<directory>./web/profiles/custom/*/tests/src/ExistingSiteJavascript</directory>-->
</testsuite>
</testsuites>
</phpunit>

View File

@@ -0,0 +1,63 @@
#!/usr/bin/env bash
# Synchronize local site instance with remote one.
set -e
ROOT_DIR=$(dirname "$(readlink -f "$0")")/..
function label {
echo -e "\n\e[1;47;44m $* \e[0m"
}
function local_drush {
"$ROOT_DIR"/vendor/drush/drush/drush --root "$ROOT_DIR"/{{ document_root_path }} "$@"
}
SOURCE_ENVIRONMENT=$1
# Source environment from which we copy the database and files.
if [[ -z $SOURCE_ENVIRONMENT ]]; then
read -r -p "Source environment: " SOURCE_ENVIRONMENT
fi
label 'Empty current database'
local_drush sql:drop -y
label "Import database from $SOURCE_ENVIRONMENT"
# @DCG gzip does not make much sense for small databases.
local_drush "@$SOURCE_ENVIRONMENT" sql:dump --gzip | gunzip | local_drush sql:cli
label "Synchronize files with $SOURCE_ENVIRONMENT"
# @DCG To save time and disk space consider using Stage File Proxy module.
TARGET_DIR=$(realpath "$ROOT_DIR"/{{ document_root_path }}sites/default/files)
local_drush core:rsync -y "@$SOURCE_ENVIRONMENT:sites/default/files/" "$TARGET_DIR" || true
label 'Apply DB updates'
local_drush updatedb -y
label 'Import configuration'
local_drush config:import -y
label 'Check config status'
local_drush config:status
label 'Rebuild caches'
local_drush cache:rebuild
label 'Run CRON hooks'
local_drush core:cron
label 'Delete log records'
local_drush watchdog:delete all -y
label 'Warm cache'
URL=$(local_drush core:status --field=uri)
if [[ $URL == *"default"* ]]; then
echo -e "\n\e[91mURL is not set. Skipping.\e[0m" >&2
else
curl -s -o /dev/null -w "URL: %{url_effective}\nStatus code: %{http_code}\nTime total: %{time_total} sec.\n $URL"
fi
label 'Check site status'
local_drush core:status

View File

@@ -0,0 +1,20 @@
<?php
namespace {{ namespace }}\Tests;
use weitzman\DrupalTestTraits\ExistingSiteBase;
/**
* A test for home page.
*/
class HomePageTest extends ExistingSiteBase {
/**
* Test callback.
*/
public function testHomePage() {
$this->drupalGet('');
$this->assertSession()->pageTextContains('Welcome');
}
}

View File

@@ -0,0 +1,26 @@
{
"name": "drupal/{{ machine_name }}",
"type": "{{ type }}",
"description": "{{ description }}",
"keywords": ["Drupal"]{{ drupal_org ? ',' }}
{% if (drupal_org) %}
"license": "GPL-2.0+",
"homepage": "https://www.drupal.org/project/{{ machine_name }}",
"authors": [
{
"name": "Your name here",
"homepage": "https://www.drupal.org/u/your_name_here",
"role": "Maintainer"
},
{
"name": "Contributors",
"homepage": "https://www.drupal.org/node/NID/committers",
"role": "Contributors"
}
],
"support": {
"issues": "https://www.drupal.org/project/issues/{{ machine_name }}",
"source": "http://cgit.drupalcode.org/{{ machine_name }}"
}
{% endif %}
}

View File

@@ -0,0 +1,7 @@
{{ route_name }}:
path: '{{ route_path }}'
defaults:
_title: '{{ route_title }}'
_controller: '\Drupal\{{ machine_name }}\Controller\{{ class }}::build'
requirements:
_permission: '{{ route_permission }}'

View File

@@ -0,0 +1,54 @@
{% import 'lib/di.twig' as di %}
<?php
namespace Drupal\{{ machine_name }}\Controller;
{% sort %}
use Drupal\Core\Controller\ControllerBase;
{% if services %}
use Symfony\Component\DependencyInjection\ContainerInterface;
{{ di.use(services) }}
{% endif %}
{% endsort %}
/**
* Returns responses for {{ name }} routes.
*/
class {{ class }} extends ControllerBase {
{% if services %}
{{ di.properties(services) }}
/**
* The controller constructor.
*
{{ di.annotation(services) }}
*/
public function __construct({{ di.signature(services) }}) {
{{ di.assignment(services) }}
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
{{ di.container(services) }}
);
}
{% endif %}
/**
* Builds the response.
*/
public function build() {
$build['content'] = [
'#type' => 'item',
'#markup' => $this->t('It works!'),
];
return $build;
}
}

View File

@@ -0,0 +1,6 @@
<?php
/**
* @file
* Install, update and uninstall functions for the {{ name }} module.
*/

View File

@@ -0,0 +1,6 @@
<?php
/**
* @file
* Primary module hooks for {{ name }} module.
*/

View File

@@ -0,0 +1,6 @@
<?php
/**
* @file
* Post update functions for the {{ name }} module.
*/

View File

@@ -0,0 +1,6 @@
<?php
/**
* @file
* Builds tokens for the {{ name }} module.
*/

View File

@@ -0,0 +1,6 @@
<?php
/**
* @file
* Views hooks for the {{ name }} module.
*/

View File

@@ -0,0 +1,6 @@
<?php
/**
* @file
* Provide views runtime hooks for the {{ name }} module.
*/

View File

@@ -0,0 +1,59 @@
<?php
namespace Drupal\{{ machine_name }}\Form;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
/**
* Configure {{ name }} settings for this site.
*/
class {{ class }} extends ConfigFormBase {
/**
* {@inheritdoc}
*/
public function getFormId() {
return '{{ form_id }}';
}
/**
* {@inheritdoc}
*/
protected function getEditableConfigNames() {
return ['{{ machine_name }}.settings'];
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['example'] = [
'#type' => 'textfield',
'#title' => $this->t('Example'),
'#default_value' => $this->config('{{ machine_name }}.settings')->get('example'),
];
return parent::buildForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
if ($form_state->getValue('example') != 'example') {
$form_state->setErrorByName('example', $this->t('The value is not correct.'));
}
parent::validateForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->config('{{ machine_name }}.settings')
->set('example', $form_state->getValue('example'))
->save();
parent::submitForm($form, $form_state);
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace Drupal\{{ machine_name }}\Form;
use Drupal\Core\Form\ConfirmFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
/**
* Provides a confirmation form before clearing out the examples.
*/
class {{ class }} extends ConfirmFormBase {
/**
* {@inheritdoc}
*/
public function getFormId() {
return '{{ form_id }}';
}
/**
* {@inheritdoc}
*/
public function getQuestion() {
return $this->t('Are you sure you want to do this?');
}
/**
* {@inheritdoc}
*/
public function getCancelUrl() {
return new Url('system.admin_config');
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
// @DCG Place your code here.
$this->messenger()->addStatus($this->t('Done!'));
$form_state->setRedirectUrl($this->getCancelUrl());
}
}

View File

@@ -0,0 +1,10 @@
{{ route_name }}:
title: {{ link_title }}
{% if link_description %}
description: {{ link_description }}
{% endif %}
{% if link_parent %}
parent: {{ link_parent }}
{% endif %}
route_name: {{ route_name }}
weight: 10

View File

@@ -0,0 +1,7 @@
{{ route_name }}:
path: '{{ route_path }}'
defaults:
_title: '{{ route_title }}'
_form: 'Drupal\{{ machine_name }}\Form\{{ class }}'
requirements:
_permission: '{{ route_permission }}'

View File

@@ -0,0 +1,59 @@
<?php
namespace Drupal\{{ machine_name }}\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
/**
* Provides a {{ name }} form.
*/
class {{ class }} extends FormBase {
/**
* {@inheritdoc}
*/
public function getFormId() {
return '{{ form_id }}';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['message'] = [
'#type' => 'textarea',
'#title' => $this->t('Message'),
'#required' => TRUE,
];
$form['actions'] = [
'#type' => 'actions',
];
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Send'),
];
return $form;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
if (mb_strlen($form_state->getValue('message')) < 10) {
$form_state->setErrorByName('name', $this->t('Message should be at least 10 characters.'));
}
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->messenger()->addStatus($this->t('The message has been sent.'));
$form_state->setRedirect('<front>');
}
}

View File

@@ -0,0 +1,7 @@
/**
* Implements hook_ENTITY_TYPE_access().
*/
function {{ machine_name }}_ENTITY_TYPE_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account) {
// No opinion.
return AccessResult::neutral();
}

View File

@@ -0,0 +1,6 @@
/**
* Implements hook_ENTITY_TYPE_build_defaults_alter().
*/
function {{ machine_name }}_ENTITY_TYPE_build_defaults_alter(array &$build, \Drupal\Core\Entity\EntityInterface $entity, $view_mode) {
}

View File

@@ -0,0 +1,6 @@
/**
* Implements hook_ENTITY_TYPE_create().
*/
function {{ machine_name }}_ENTITY_TYPE_create(\Drupal\Core\Entity\EntityInterface $entity) {
\Drupal::logger('example')->info('ENTITY_TYPE created: @label', ['@label' => $entity->label()]);
}

View File

@@ -0,0 +1,7 @@
/**
* Implements hook_ENTITY_TYPE_create_access().
*/
function {{ machine_name }}_ENTITY_TYPE_create_access(\Drupal\Core\Session\AccountInterface $account, array $context, $entity_bundle) {
// No opinion.
return AccessResult::neutral();
}

View File

@@ -0,0 +1,10 @@
/**
* Implements hook_ENTITY_TYPE_delete().
*/
function {{ machine_name }}_ENTITY_TYPE_delete(Drupal\Core\Entity\EntityInterface $entity) {
// Delete the entity's entry from a fictional table of all entities.
\Drupal::database()->delete('example_entity')
->condition('type', $entity->getEntityTypeId())
->condition('id', $entity->id())
->execute();
}

View File

@@ -0,0 +1,8 @@
/**
* Implements hook_ENTITY_TYPE_field_values_init().
*/
function {{ machine_name }}_ENTITY_TYPE_field_values_init(\Drupal\Core\Entity\FieldableEntityInterface $entity) {
if (!$entity->foo->value) {
$entity->foo->value = 'some_initial_value';
}
}

View File

@@ -0,0 +1,13 @@
/**
* Implements hook_ENTITY_TYPE_insert().
*/
function {{ machine_name }}_ENTITY_TYPE_insert(Drupal\Core\Entity\EntityInterface $entity) {
// Insert the new entity into a fictional table of this type of entity.
\Drupal::database()->insert('example_entity')
->fields([
'id' => $entity->id(),
'created' => REQUEST_TIME,
'updated' => REQUEST_TIME,
])
->execute();
}

View File

@@ -0,0 +1,8 @@
/**
* Implements hook_ENTITY_TYPE_load().
*/
function {{ machine_name }}_ENTITY_TYPE_load($entities) {
foreach ($entities as $entity) {
$entity->foo = mymodule_add_something($entity);
}
}

View File

@@ -0,0 +1,22 @@
/**
* Implements hook_ENTITY_TYPE_predelete().
*/
function {{ machine_name }}_ENTITY_TYPE_predelete(Drupal\Core\Entity\EntityInterface $entity) {
$connection = \Drupal::database();
// Count references to this entity in a custom table before they are removed
// upon entity deletion.
$id = $entity->id();
$type = $entity->getEntityTypeId();
$count = \Drupal::database()->select('example_entity_data')
->condition('type', $type)
->condition('id', $id)
->countQuery()
->execute()
->fetchField();
// Log the count in a table that records this statistic for deleted entities.
$connection->merge('example_deleted_entity_statistics')
->key(['type' => $type, 'id' => $id])
->fields(['count' => $count])
->execute();
}

View File

@@ -0,0 +1,9 @@
/**
* Implements hook_ENTITY_TYPE_prepare_form().
*/
function {{ machine_name }}_ENTITY_TYPE_prepare_form(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Form\FormStateInterface $form_state) {
if ($operation == 'edit') {
$entity->label->value = 'Altered label';
$form_state->set('label_altered', TRUE);
}
}

View File

@@ -0,0 +1,9 @@
/**
* Implements hook_ENTITY_TYPE_presave().
*/
function {{ machine_name }}_ENTITY_TYPE_presave(Drupal\Core\Entity\EntityInterface $entity) {
if ($entity->isTranslatable()) {
$route_match = \Drupal::routeMatch();
\Drupal::service('content_translation.synchronizer')->synchronizeFields($entity, $entity->language()->getId(), $route_match->getParameter('source_langcode'));
}
}

View File

@@ -0,0 +1,8 @@
/**
* Implements hook_ENTITY_TYPE_revision_create().
*/
function {{ machine_name }}_ENTITY_TYPE_revision_create(Drupal\Core\Entity\EntityInterface $new_revision, Drupal\Core\Entity\EntityInterface $entity, $keep_untranslatable_fields) {
// Retain the value from an untranslatable field, which are by default
// synchronized from the default revision.
$new_revision->set('untranslatable_field', $entity->get('untranslatable_field'));
}

View File

@@ -0,0 +1,9 @@
/**
* Implements hook_ENTITY_TYPE_revision_delete().
*/
function {{ machine_name }}_ENTITY_TYPE_revision_delete(Drupal\Core\Entity\EntityInterface $entity) {
$referenced_files_by_field = _editor_get_file_uuids_by_field($entity);
foreach ($referenced_files_by_field as $field => $uuids) {
_editor_delete_file_usage($uuids, $entity, 1);
}
}

View File

@@ -0,0 +1,8 @@
/**
* Implements hook_ENTITY_TYPE_storage_load().
*/
function {{ machine_name }}_ENTITY_TYPE_storage_load(array $entities) {
foreach ($entities as $entity) {
$entity->foo = mymodule_add_something_uncached($entity);
}
}

View File

@@ -0,0 +1,6 @@
/**
* Implements hook_ENTITY_TYPE_translation_create().
*/
function {{ machine_name }}_ENTITY_TYPE_translation_create(\Drupal\Core\Entity\EntityInterface $translation) {
\Drupal::logger('example')->info('ENTITY_TYPE translation created: @label', ['@label' => $translation->label()]);
}

View File

@@ -0,0 +1,10 @@
/**
* Implements hook_ENTITY_TYPE_translation_delete().
*/
function {{ machine_name }}_ENTITY_TYPE_translation_delete(\Drupal\Core\Entity\EntityInterface $translation) {
$variables = [
'@language' => $translation->language()->getName(),
'@label' => $translation->label(),
];
\Drupal::logger('example')->notice('The @language translation of @label has just been deleted.', $variables);
}

View File

@@ -0,0 +1,10 @@
/**
* Implements hook_ENTITY_TYPE_translation_insert().
*/
function {{ machine_name }}_ENTITY_TYPE_translation_insert(\Drupal\Core\Entity\EntityInterface $translation) {
$variables = [
'@language' => $translation->language()->getName(),
'@label' => $translation->getUntranslated()->label(),
];
\Drupal::logger('example')->notice('The @language translation of @label has just been stored.', $variables);
}

View File

@@ -0,0 +1,12 @@
/**
* Implements hook_ENTITY_TYPE_update().
*/
function {{ machine_name }}_ENTITY_TYPE_update(Drupal\Core\Entity\EntityInterface $entity) {
// Update the entity's entry in a fictional table of this type of entity.
\Drupal::database()->update('example_entity')
->fields([
'updated' => REQUEST_TIME,
])
->condition('id', $entity->id())
->execute();
}

View File

@@ -0,0 +1,14 @@
/**
* Implements hook_ENTITY_TYPE_view().
*/
function {{ machine_name }}_ENTITY_TYPE_view(array &$build, \Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode) {
// Only do the extra work if the component is configured to be displayed.
// This assumes a 'mymodule_addition' extra field has been defined for the
// entity bundle in hook_entity_extra_field_info().
if ($display->getComponent('mymodule_addition')) {
$build['mymodule_addition'] = [
'#markup' => mymodule_addition($entity),
'#theme' => 'mymodule_my_additional_field',
];
}
}

View File

@@ -0,0 +1,12 @@
/**
* Implements hook_ENTITY_TYPE_view_alter().
*/
function {{ machine_name }}_ENTITY_TYPE_view_alter(array &$build, Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) {
if ($build['#view_mode'] == 'full' && isset($build['an_additional_field'])) {
// Change its weight.
$build['an_additional_field']['#weight'] = -10;
// Add a #post_render callback to act on the rendered HTML of the entity.
$build['#post_render'][] = 'my_module_node_post_render';
}
}

View File

@@ -0,0 +1,10 @@
/**
* Implements hook_aggregator_fetcher_info_alter().
*/
function {{ machine_name }}_aggregator_fetcher_info_alter(array &$info) {
if (empty($info['foo_fetcher'])) {
return;
}
$info['foo_fetcher']['class'] = Drupal\foo\Plugin\aggregator\fetcher\FooDefaultFetcher::class;
}

View File

@@ -0,0 +1,10 @@
/**
* Implements hook_aggregator_parser_info_alter().
*/
function {{ machine_name }}_aggregator_parser_info_alter(array &$info) {
if (empty($info['foo_parser'])) {
return;
}
$info['foo_parser']['class'] = Drupal\foo\Plugin\aggregator\parser\FooDefaultParser::class;
}

View File

@@ -0,0 +1,10 @@
/**
* Implements hook_aggregator_processor_info_alter().
*/
function {{ machine_name }}_aggregator_processor_info_alter(array &$info) {
if (empty($info['foo_processor'])) {
return;
}
$info['foo_processor']['class'] = Drupal\foo\Plugin\aggregator\processor\FooDefaultProcessor::class;
}

View File

@@ -0,0 +1,9 @@
/**
* Implements hook_ajax_render_alter().
*/
function {{ machine_name }}_ajax_render_alter(array &$data) {
// Inject any new status messages into the content area.
$status_messages = ['#type' => 'status_messages'];
$command = new \Drupal\Core\Ajax\PrependCommand('#block-system-main .content', \Drupal::service('renderer')->renderRoot($status_messages));
$data[] = $command->render();
}

View File

@@ -0,0 +1,6 @@
/**
* Implements hook_archiver_info_alter().
*/
function {{ machine_name }}_archiver_info_alter(&$info) {
$info['tar']['extensions'][] = 'tgz';
}

View File

@@ -0,0 +1,5 @@
/**
* Implements hook_batch_alter().
*/
function {{ machine_name }}_batch_alter(&$batch) {
}

View File

@@ -0,0 +1,13 @@
/**
* Implements hook_block_access().
*/
function {{ machine_name }}_block_access(\Drupal\block\Entity\Block $block, $operation, \Drupal\Core\Session\AccountInterface $account) {
// Example code that would prevent displaying the 'Powered by Drupal' block in
// a region different than the footer.
if ($operation == 'view' && $block->getPluginId() == 'system_powered_by_block') {
return AccessResult::forbiddenIf($block->getRegion() != 'footer')->addCacheableDependency($block);
}
// No opinion.
return AccessResult::neutral();
}

View File

@@ -0,0 +1,7 @@
/**
* Implements hook_block_build_BASE_BLOCK_ID_alter().
*/
function {{ machine_name }}_block_build_BASE_BLOCK_ID_alter(array &$build, \Drupal\Core\Block\BlockPluginInterface $block) {
// Explicitly enable placeholdering of the specific block.
$build['#create_placeholder'] = TRUE;
}

View File

@@ -0,0 +1,9 @@
/**
* Implements hook_block_build_alter().
*/
function {{ machine_name }}_block_build_alter(array &$build, \Drupal\Core\Block\BlockPluginInterface $block) {
// Add the 'user' cache context to some blocks.
if ($block->label() === 'some condition') {
$build['#cache']['contexts'][] = 'user';
}
}

View File

@@ -0,0 +1,7 @@
/**
* Implements hook_block_view_BASE_BLOCK_ID_alter().
*/
function {{ machine_name }}_block_view_BASE_BLOCK_ID_alter(array &$build, \Drupal\Core\Block\BlockPluginInterface $block) {
// Change the title of the specific block.
$build['#title'] = t('New title of the block');
}

View File

@@ -0,0 +1,9 @@
/**
* Implements hook_block_view_alter().
*/
function {{ machine_name }}_block_view_alter(array &$build, \Drupal\Core\Block\BlockPluginInterface $block) {
// Remove the contextual links on all blocks that provide them.
if (isset($build['#contextual_links'])) {
unset($build['#contextual_links']);
}
}

View File

@@ -0,0 +1,8 @@
/**
* Implements hook_cache_flush().
*/
function {{ machine_name }}_cache_flush() {
if (defined('MAINTENANCE_MODE') && MAINTENANCE_MODE == 'update') {
_update_cache_clear();
}
}

View File

@@ -0,0 +1,6 @@
/**
* Implements hook_ckeditor_css_alter().
*/
function {{ machine_name }}_ckeditor_css_alter(array &$css, Editor $editor) {
$css[] = drupal_get_path('module', 'mymodule') . '/css/mymodule-ckeditor.css';
}

View File

@@ -0,0 +1,6 @@
/**
* Implements hook_ckeditor_plugin_info_alter().
*/
function {{ machine_name }}_ckeditor_plugin_info_alter(array &$plugins) {
$plugins['someplugin']['label'] = t('Better name');
}

View File

@@ -0,0 +1,15 @@
/**
* Implements hook_comment_links_alter().
*/
function {{ machine_name }}_comment_links_alter(array &$links, CommentInterface $entity, array &$context) {
$links['mymodule'] = [
'#theme' => 'links__comment__mymodule',
'#attributes' => ['class' => ['links', 'inline']],
'#links' => [
'comment-report' => [
'title' => t('Report'),
'url' => Url::fromRoute('comment_test.report', ['comment' => $entity->id()], ['query' => ['token' => \Drupal::getContainer()->get('csrf_token')->get("comment/{$entity->id()}/report")]]),
],
],
];
}

View File

@@ -0,0 +1,9 @@
/**
* Implements hook_config_import_steps_alter().
*/
function {{ machine_name }}_config_import_steps_alter(&$sync_steps, \Drupal\Core\Config\ConfigImporter $config_importer) {
$deletes = $config_importer->getUnprocessedConfiguration('delete');
if (isset($deletes['field.storage.node.body'])) {
$sync_steps[] = '_additional_configuration_step';
}
}

View File

@@ -0,0 +1,10 @@
/**
* Implements hook_config_schema_info_alter().
*/
function {{ machine_name }}_config_schema_info_alter(&$definitions) {
// Enhance the text and date type definitions with classes to generate proper
// form elements in ConfigTranslationFormBase. Other translatable types will
// appear as a one line textfield.
$definitions['text']['form_element_class'] = '\Drupal\config_translation\FormElement\Textarea';
$definitions['date_format']['form_element_class'] = '\Drupal\config_translation\FormElement\DateFormat';
}

View File

@@ -0,0 +1,34 @@
/**
* Implements hook_config_translation_info().
*/
function {{ machine_name }}_config_translation_info(&$info) {
$entity_type_manager = \Drupal::entityTypeManager();
$route_provider = \Drupal::service('router.route_provider');
// If field UI is not enabled, the base routes of the type
// "entity.field_config.{$entity_type}_field_edit_form" are not defined.
if (\Drupal::moduleHandler()->moduleExists('field_ui')) {
// Add fields entity mappers to all fieldable entity types defined.
foreach ($entity_type_manager->getDefinitions() as $entity_type_id => $entity_type) {
$base_route = NULL;
try {
$base_route = $route_provider->getRouteByName('entity.field_config.' . $entity_type_id . '_field_edit_form');
}
catch (RouteNotFoundException $e) {
// Ignore non-existent routes.
}
// Make sure entity type has field UI enabled and has a base route.
if ($entity_type->get('field_ui_base_route') && !empty($base_route)) {
$info[$entity_type_id . '_fields'] = [
'base_route_name' => 'entity.field_config.' . $entity_type_id . '_field_edit_form',
'entity_type' => 'field_config',
'title' => t('Title'),
'class' => '\Drupal\config_translation\ConfigFieldMapper',
'base_entity_type' => $entity_type_id,
'weight' => 10,
];
}
}
}
}

View File

@@ -0,0 +1,10 @@
/**
* Implements hook_config_translation_info_alter().
*/
function {{ machine_name }}_config_translation_info_alter(&$info) {
// Add additional site settings to the site information screen, so it shows
// up on the translation screen. (Form alter in the elements whose values are
// stored in this config file using regular form altering on the original
// configuration form.)
$info['system.site_information_settings']['names'][] = 'example.site.setting';
}

View File

@@ -0,0 +1,11 @@
/**
* Implements hook_contextual_links_alter().
*/
function {{ machine_name }}_contextual_links_alter(array &$links, $group, array $route_parameters) {
if ($group == 'menu') {
// Dynamically use the menu name for the title of the menu_edit contextual
// link.
$menu = \Drupal::entityTypeManager()->getStorage('menu')->load($route_parameters['menu']);
$links['menu_edit']['title'] = t('Edit menu: @label', ['@label' => $menu->label()]);
}
}

View File

@@ -0,0 +1,6 @@
/**
* Implements hook_contextual_links_plugins_alter().
*/
function {{ machine_name }}_contextual_links_plugins_alter(array &$contextual_links) {
$contextual_links['menu_edit']['title'] = 'Edit the menu';
}

View File

@@ -0,0 +1,8 @@
/**
* Implements hook_contextual_links_view_alter().
*/
function {{ machine_name }}_contextual_links_view_alter(&$element, $items) {
// Add another class to all contextual link lists to facilitate custom
// styling.
$element['#attributes']['class'][] = 'custom-class';
}

View File

@@ -0,0 +1,7 @@
/**
* Implements hook_countries_alter().
*/
function {{ machine_name }}_countries_alter(&$countries) {
// Elbonia is now independent, so add it to the country list.
$countries['EB'] = 'Elbonia';
}

View File

@@ -0,0 +1,34 @@
/**
* Implements hook_cron().
*/
function {{ machine_name }}_cron() {
// Short-running operation example, not using a queue:
// Delete all expired records since the last cron run.
$expires = \Drupal::state()->get('mymodule.last_check', 0);
\Drupal::database()->delete('mymodule_table')
->condition('expires', $expires, '>=')
->execute();
\Drupal::state()->set('mymodule.last_check', REQUEST_TIME);
// Long-running operation example, leveraging a queue:
// Queue news feeds for updates once their refresh interval has elapsed.
$queue = \Drupal::queue('aggregator_feeds');
$ids = \Drupal::entityTypeManager()->getStorage('aggregator_feed')->getFeedIdsToRefresh();
foreach (Feed::loadMultiple($ids) as $feed) {
if ($queue->createItem($feed)) {
// Add timestamp to avoid queueing item more than once.
$feed->setQueuedTime(REQUEST_TIME);
$feed->save();
}
}
$ids = \Drupal::entityQuery('aggregator_feed')
->condition('queued', REQUEST_TIME - (3600 * 6), '<')
->execute();
if ($ids) {
$feeds = Feed::loadMultiple($ids);
foreach ($feeds as $feed) {
$feed->setQueuedTime(0);
$feed->save();
}
}
}

View File

@@ -0,0 +1,7 @@
/**
* Implements hook_css_alter().
*/
function {{ machine_name }}_css_alter(&$css, \Drupal\Core\Asset\AttachedAssetsInterface $assets) {
// Remove defaults.css file.
unset($css[drupal_get_path('module', 'system') . '/defaults.css']);
}

View File

@@ -0,0 +1,6 @@
/**
* Implements hook_data_type_info_alter().
*/
function {{ machine_name }}_data_type_info_alter(&$data_types) {
$data_types['email']['class'] = '\Drupal\mymodule\Type\Email';
}

View File

@@ -0,0 +1,6 @@
/**
* Implements hook_display_variant_plugin_alter().
*/
function {{ machine_name }}_display_variant_plugin_alter(array &$definitions) {
$definitions['full_page']['admin_label'] = t('Block layout');
}

View File

@@ -0,0 +1,7 @@
/**
* Implements hook_editor_info_alter().
*/
function {{ machine_name }}_editor_info_alter(array &$editors) {
$editors['some_other_editor']['label'] = t('A different name');
$editors['some_other_editor']['library']['module'] = 'myeditoroverride';
}

View File

@@ -0,0 +1,9 @@
/**
* Implements hook_editor_js_settings_alter().
*/
function {{ machine_name }}_editor_js_settings_alter(array &$settings) {
if (isset($settings['editor']['formats']['basic_html'])) {
$settings['editor']['formats']['basic_html']['editor'] = 'MyDifferentEditor';
$settings['editor']['formats']['basic_html']['editorSettings']['buttons'] = ['strong', 'italic', 'underline'];
}
}

View File

@@ -0,0 +1,9 @@
/**
* Implements hook_editor_xss_filter_alter().
*/
function {{ machine_name }}_editor_xss_filter_alter(&$editor_xss_filter_class, FilterFormatInterface $format, FilterFormatInterface $original_format = NULL) {
$filters = $format->filters()->getAll();
if (isset($filters['filter_wysiwyg']) && $filters['filter_wysiwyg']->status) {
$editor_xss_filter_class = '\Drupal\filter_wysiwyg\EditorXssFilter\WysiwygFilter';
}
}

View File

@@ -0,0 +1,9 @@
/**
* Implements hook_element_info_alter().
*/
function {{ machine_name }}_element_info_alter(array &$info) {
// Decrease the default size of textfields.
if (isset($info['textfield']['#size'])) {
$info['textfield']['#size'] = 40;
}
}

View File

@@ -0,0 +1,7 @@
/**
* Implements hook_entity_access().
*/
function {{ machine_name }}_entity_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account) {
// No opinion.
return AccessResult::neutral();
}

View File

@@ -0,0 +1,15 @@
/**
* Implements hook_entity_base_field_info().
*/
function {{ machine_name }}_entity_base_field_info(\Drupal\Core\Entity\EntityTypeInterface $entity_type) {
if ($entity_type->id() == 'node') {
$fields = [];
$fields['mymodule_text'] = BaseFieldDefinition::create('string')
->setLabel(t('The text'))
->setDescription(t('A text property added by mymodule.'))
->setComputed(TRUE)
->setClass('\Drupal\mymodule\EntityComputedText');
return $fields;
}
}

View File

@@ -0,0 +1,9 @@
/**
* Implements hook_entity_base_field_info_alter().
*/
function {{ machine_name }}_entity_base_field_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type) {
// Alter the mymodule_text field to use a custom class.
if ($entity_type->id() == 'node' && !empty($fields['mymodule_text'])) {
$fields['mymodule_text']->setClass('\Drupal\anothermodule\EntityComputedText');
}
}

View File

@@ -0,0 +1,6 @@
/**
* Implements hook_entity_build_defaults_alter().
*/
function {{ machine_name }}_entity_build_defaults_alter(array &$build, \Drupal\Core\Entity\EntityInterface $entity, $view_mode) {
}

View File

@@ -0,0 +1,8 @@
/**
* Implements hook_entity_bundle_create().
*/
function {{ machine_name }}_entity_bundle_create($entity_type_id, $bundle) {
// When a new bundle is created, the menu needs to be rebuilt to add the
// Field UI menu item tabs.
\Drupal::service('router.builder')->setRebuildNeeded();
}

View File

@@ -0,0 +1,12 @@
/**
* Implements hook_entity_bundle_delete().
*/
function {{ machine_name }}_entity_bundle_delete($entity_type_id, $bundle) {
// Remove the settings associated with the bundle in my_module.settings.
$config = \Drupal::config('my_module.settings');
$bundle_settings = $config->get('bundle_settings');
if (isset($bundle_settings[$entity_type_id][$bundle])) {
unset($bundle_settings[$entity_type_id][$bundle]);
$config->set('bundle_settings', $bundle_settings);
}
}

View File

@@ -0,0 +1,14 @@
/**
* Implements hook_entity_bundle_field_info().
*/
function {{ machine_name }}_entity_bundle_field_info(\Drupal\Core\Entity\EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) {
// Add a property only to nodes of the 'article' bundle.
if ($entity_type->id() == 'node' && $bundle == 'article') {
$fields = [];
$storage_definitions = mymodule_entity_field_storage_info($entity_type);
$fields['mymodule_bundle_field'] = FieldDefinition::createFromFieldStorageDefinition($storage_definitions['mymodule_bundle_field'])
->setLabel(t('Bundle Field'));
return $fields;
}
}

View File

@@ -0,0 +1,9 @@
/**
* Implements hook_entity_bundle_field_info_alter().
*/
function {{ machine_name }}_entity_bundle_field_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type, $bundle) {
if ($entity_type->id() == 'node' && $bundle == 'article' && !empty($fields['mymodule_text'])) {
// Alter the mymodule_text field to use a custom class.
$fields['mymodule_text']->setClass('\Drupal\anothermodule\EntityComputedText');
}
}

View File

@@ -0,0 +1,7 @@
/**
* Implements hook_entity_bundle_info().
*/
function {{ machine_name }}_entity_bundle_info() {
$bundles['user']['user']['label'] = t('User');
return $bundles;
}

View File

@@ -0,0 +1,6 @@
/**
* Implements hook_entity_bundle_info_alter().
*/
function {{ machine_name }}_entity_bundle_info_alter(&$bundles) {
$bundles['user']['user']['label'] = t('Full account');
}

View File

@@ -0,0 +1,6 @@
/**
* Implements hook_entity_create().
*/
function {{ machine_name }}_entity_create(\Drupal\Core\Entity\EntityInterface $entity) {
\Drupal::logger('example')->info('Entity created: @label', ['@label' => $entity->label()]);
}

View File

@@ -0,0 +1,7 @@
/**
* Implements hook_entity_create_access().
*/
function {{ machine_name }}_entity_create_access(\Drupal\Core\Session\AccountInterface $account, array $context, $entity_bundle) {
// No opinion.
return AccessResult::neutral();
}

View File

@@ -0,0 +1,10 @@
/**
* Implements hook_entity_delete().
*/
function {{ machine_name }}_entity_delete(Drupal\Core\Entity\EntityInterface $entity) {
// Delete the entity's entry from a fictional table of all entities.
\Drupal::database()->delete('example_entity')
->condition('type', $entity->getEntityTypeId())
->condition('id', $entity->id())
->execute();
}

Some files were not shown because too many files have changed in this diff Show More