first commit

This commit is contained in:
2024-07-15 12:33:27 +02:00
commit ce50ae282b
22084 changed files with 2623791 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
entity.{{ entity_type_id }}.add_form:
route_name: 'entity.{{ entity_type_id }}.add_form'
title: 'Add {{ entity_type_label|lower }}'
appears_on:
- entity.{{ entity_type_id }}.collection

View File

@@ -0,0 +1,5 @@
entity.{{ entity_type_id }}.overview:
title: {{ entity_type_label|pluralize }}
parent: system.admin_structure
description: 'List of {{ entity_type_label|lower|pluralize }} to extend site functionality.'
route_name: entity.{{ entity_type_id }}.collection

View File

@@ -0,0 +1,2 @@
administer {{ entity_type_id }}:
title: 'Administer {{ entity_type_label|lower }}'

View File

@@ -0,0 +1,31 @@
entity.{{ entity_type_id }}.collection:
path: '/admin/structure/{{ entity_type_id|u2h }}'
defaults:
_entity_list: '{{ entity_type_id }}'
_title: '{{ entity_type_label }} configuration'
requirements:
_permission: 'administer {{ entity_type_id }}'
entity.{{ entity_type_id }}.add_form:
path: '/admin/structure/{{ entity_type_id }}/add'
defaults:
_entity_form: '{{ entity_type_id }}.add'
_title: 'Add {{ entity_type_label|article|lower }}'
requirements:
_permission: 'administer {{ entity_type_id }}'
entity.{{ entity_type_id }}.edit_form:
path: '/admin/structure/{{ entity_type_id|u2h }}/{{ '{' }}{{ entity_type_id }}{{ '}' }}'
defaults:
_entity_form: '{{ entity_type_id }}.edit'
_title: 'Edit {{ entity_type_label|article|lower }}'
requirements:
_permission: 'administer {{ entity_type_id }}'
entity.{{ entity_type_id }}.delete_form:
path: '/admin/structure/{{ entity_type_id|u2h }}/{{ '{' }}{{ entity_type_id }}{{ '}' }}/delete'
defaults:
_entity_form: '{{ entity_type_id }}.delete'
_title: 'Delete {{ entity_type_label|article|lower }}'
requirements:
_permission: 'administer {{ entity_type_id }}'

View File

@@ -0,0 +1,70 @@
<?php
declare(strict_types=1);
namespace Drupal\{{ machine_name }}\Entity;
{% apply sort_namespaces %}
use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\{{ machine_name }}\{{ class_prefix }}Interface;
{% endapply %}
/**
* Defines the {{ entity_type_label|lower }} entity type.
*
* @ConfigEntityType(
* id = "{{ entity_type_id }}",
* label = @Translation("{{ entity_type_label }}"),
* label_collection = @Translation("{{ entity_type_label|pluralize }}"),
* label_singular = @Translation("{{ entity_type_label|lower }}"),
* label_plural = @Translation("{{ entity_type_label|pluralize|lower }}"),
* label_count = @PluralTranslation(
* singular = "@count {{ entity_type_label|lower }}",
* plural = "@count {{ entity_type_label|pluralize|lower }}",
* ),
* handlers = {
* "list_builder" = "Drupal\{{ machine_name }}\{{ class_prefix }}ListBuilder",
* "form" = {
* "add" = "Drupal\{{ machine_name }}\Form\{{ class_prefix }}Form",
* "edit" = "Drupal\{{ machine_name }}\Form\{{ class_prefix }}Form",
* "delete" = "Drupal\Core\Entity\EntityDeleteForm",
* },
* },
* config_prefix = "{{ entity_type_id }}",
* admin_permission = "administer {{ entity_type_id }}",
* links = {
* "collection" = "/admin/structure/{{ entity_type_id|u2h }}",
* "add-form" = "/admin/structure/{{ entity_type_id|u2h }}/add",
* "edit-form" = "/admin/structure/{{ entity_type_id|u2h }}/{{ '{' }}{{ entity_type_id }}{{ '}' }}",
* "delete-form" = "/admin/structure/{{ entity_type_id|u2h }}/{{ '{' }}{{ entity_type_id }}{{ '}' }}/delete",
* },
* entity_keys = {
* "id" = "id",
* "label" = "label",
* "uuid" = "uuid",
* },
* config_export = {
* "id",
* "label",
* "description",
* },
* )
*/
final class {{ class_prefix }} extends ConfigEntityBase implements {{ class_prefix }}Interface {
/**
* The example ID.
*/
protected string $id;
/**
* The example label.
*/
protected string $label;
/**
* The example description.
*/
protected string $description;
}

View File

@@ -0,0 +1,14 @@
<?php
declare(strict_types=1);
namespace Drupal\{{ machine_name }};
use Drupal\Core\Config\Entity\ConfigEntityInterface;
/**
* Provides an interface defining {{ entity_type_label|article|lower }} entity type.
*/
interface {{ class_prefix }}Interface extends ConfigEntityInterface {
}

View File

@@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace Drupal\{{ machine_name }};
use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
use Drupal\Core\Entity\EntityInterface;
/**
* Provides a listing of {{ entity_type_label|lower|pluralize }}.
*/
final class {{ class_prefix }}ListBuilder extends ConfigEntityListBuilder {
/**
* {@inheritdoc}
*/
public function buildHeader(): array {
$header['label'] = $this->t('Label');
$header['id'] = $this->t('Machine name');
$header['status'] = $this->t('Status');
return $header + parent::buildHeader();
}
/**
* {@inheritdoc}
*/
public function buildRow(EntityInterface $entity): array {
/** @var \Drupal\{{ machine_name }}\{{ class_prefix }}Interface $entity */
$row['label'] = $entity->label();
$row['id'] = $entity->id();
$row['status'] = $entity->status() ? $this->t('Enabled') : $this->t('Disabled');
return $row + parent::buildRow($entity);
}
}

View File

@@ -0,0 +1,71 @@
<?php
declare(strict_types=1);
namespace Drupal\{{ machine_name }}\Form;
use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Form\FormStateInterface;
use Drupal\{{ machine_name }}\Entity\{{ class_prefix }};
/**
* {{ entity_type_label }} form.
*/
final class {{ class_prefix }}Form extends EntityForm {
/**
* {@inheritdoc}
*/
public function form(array $form, FormStateInterface $form_state): array {
$form = parent::form($form, $form_state);
$form['label'] = [
'#type' => 'textfield',
'#title' => $this->t('Label'),
'#maxlength' => 255,
'#default_value' => $this->entity->label(),
'#required' => TRUE,
];
$form['id'] = [
'#type' => 'machine_name',
'#default_value' => $this->entity->id(),
'#machine_name' => [
'exists' => [{{ class_prefix }}::class, 'load'],
],
'#disabled' => !$this->entity->isNew(),
];
$form['status'] = [
'#type' => 'checkbox',
'#title' => $this->t('Enabled'),
'#default_value' => $this->entity->status(),
];
$form['description'] = [
'#type' => 'textarea',
'#title' => $this->t('Description'),
'#default_value' => $this->entity->get('description'),
];
return $form;
}
/**
* {@inheritdoc}
*/
public function save(array $form, FormStateInterface $form_state): int {
$result = parent::save($form, $form_state);
$message_args = ['%label' => $this->entity->label()];
$this->messenger()->addStatus(
match($result) {
\SAVED_NEW => $this->t('Created new example %label.', $message_args),
\SAVED_UPDATED => $this->t('Updated example %label.', $message_args),
}
);
$form_state->setRedirectUrl($this->entity->toUrl('collection'));
return $result;
}
}

View File

@@ -0,0 +1,19 @@
{% if bundle %}
{{ entity_type_id }}.type_add:
title: 'Add {{ entity_type_label|lower }} type'
route_name: entity.{{ entity_type_id }}_type.add_form
appears_on:
- entity.{{ entity_type_id }}_type.collection
{{ entity_type_id }}.add_page:
title: 'Add {{ entity_type_label|lower }}'
route_name: entity.{{ entity_type_id }}.add_page
appears_on:
- entity.{{ entity_type_id }}.collection
{% else %}
{{ entity_type_id }}.add_form:
title: 'Add {{ entity_type_label|lower }}'
route_name: entity.{{ entity_type_id }}.add_form
appears_on:
- entity.{{ entity_type_id }}.collection
{% endif %}

View File

@@ -0,0 +1,10 @@
entity.{{ entity_type_id }}.edit_form:
route_name: entity.{{ entity_type_id }}.edit_form
group: {{ entity_type_id }}
title: 'Edit'
entity.{{ entity_type_id }}.delete_form:
route_name: entity.{{ entity_type_id }}.delete_form
group: {{ entity_type_id }}
title: 'Delete'
weight: 10

View File

@@ -0,0 +1,20 @@
{% if fieldable_no_bundle %}
entity.{{ entity_type_id }}.settings:
title: '{{ entity_type_label }}'
description: 'Configure {{ entity_type_label|article }} entity type.'
route_name: entity.{{ entity_type_id }}.settings
parent: system.admin_structure
{% elseif bundle %}
entity.{{ entity_type_id }}_type.collection:
title: '{{ entity_type_label }} types'
description: 'Manage and CRUD actions on {{ entity_type_label }} type.'
parent: system.admin_structure
route_name: entity.{{ entity_type_id }}_type.collection
{% endif %}
entity.{{ entity_type_id }}.collection:
title: '{{ entity_type_label|pluralize }}'
description: 'List of {{ entity_type_label|pluralize|lower }}.'
route_name: entity.{{ entity_type_id }}.collection
parent: system.admin_content

View File

@@ -0,0 +1,37 @@
{% if fieldable_no_bundle %}
entity.{{ entity_type_id }}.settings:
title: 'Settings'
route_name: entity.{{ entity_type_id }}.settings
base_route: entity.{{ entity_type_id }}.settings
{% endif %}
{# Tabs are not needed when there is no canonical view page. #}
{% if canonical %}
entity.{{ entity_type_id }}.view:
title: 'View'
route_name: entity.{{ entity_type_id }}.canonical
base_route: entity.{{ entity_type_id }}.canonical
entity.{{ entity_type_id }}.edit_form:
title: 'Edit'
route_name: entity.{{ entity_type_id }}.edit_form
base_route: entity.{{ entity_type_id }}.canonical
entity.{{ entity_type_id }}.delete_form:
title: 'Delete'
route_name: entity.{{ entity_type_id }}.delete_form
base_route: entity.{{ entity_type_id }}.canonical
weight: 10
{% endif %}
entity.{{ entity_type_id }}.collection:
title: '{{ entity_type_label|pluralize }}'
route_name: entity.{{ entity_type_id }}.collection
base_route: system.admin_content
weight: 10
{% if bundle %}
entity.{{ entity_type_id }}_type.edit_form:
title: 'Edit'
route_name: entity.{{ entity_type_id }}_type.edit_form
base_route: entity.{{ entity_type_id }}_type.edit_form
entity.{{ entity_type_id }}_type.collection:
title: 'List'
route_name: entity.{{ entity_type_id }}_type.collection
base_route: entity.{{ entity_type_id }}_type.collection
{% endif %}

View File

@@ -0,0 +1,104 @@
<?php
declare(strict_types=1);
/**
* @file
* Provides {{ entity_type_label|article|lower }} entity type.
*/
{% apply sort_namespaces %}
use Drupal\Core\Render\Element;
{% if author_base_field %}
use Drupal\user\UserInterface;
{% endif %}
{% endapply %}
/**
* Implements hook_theme().
*/
function {{ machine_name }}_theme(): array {
return [
'{{ entity_type_id }}' => ['render element' => 'elements'],
];
}
/**
* Prepares variables for {{ entity_type_label|lower }} templates.
*
* Default template: {{ template_name }}.
*
* @param array $variables
* An associative array containing:
* - elements: An associative array containing the {{ entity_type_label|lower }} information and any
* fields attached to the entity.
* - attributes: HTML attributes for the containing element.
*/
function template_preprocess_{{ entity_type_id }}(array &$variables): void {
$variables['view_mode'] = $variables['elements']['#view_mode'];
foreach (Element::children($variables['elements']) as $key) {
$variables['content'][$key] = $variables['elements'][$key];
}
}
{% if author_base_field %}
/**
* Implements hook_user_cancel().
*/
function {{ machine_name }}_user_cancel($edit, UserInterface $account, $method): void {
switch ($method) {
{% if status_base_field %}
case 'user_cancel_block_unpublish':
// Unpublish {{ entity_type_label|lower|pluralize }}.
$storage = \Drupal::entityTypeManager()->getStorage('{{ entity_type_id }}');
${{ entity_type_id }}_ids = $storage->getQuery()
->condition('uid', $account->id())
->condition('status', 1)
->accessCheck(FALSE)
->execute();
foreach ($storage->loadMultiple(${{ entity_type_id }}_ids) as ${{ entity_type_id }}) {
${{ entity_type_id }}->set('status', FALSE)->save();
}
break;
{% endif %}
case 'user_cancel_reassign':
// Anonymize {{ entity_type_label|lower|pluralize }}.
$storage = \Drupal::entityTypeManager()->getStorage('{{ entity_type_id }}');
${{ entity_type_id }}_ids = $storage->getQuery()
->condition('uid', $account->id())
->accessCheck(FALSE)
->execute();
foreach ($storage->loadMultiple(${{ entity_type_id }}_ids) as ${{ entity_type_id }}) {
${{ entity_type_id }}->setOwnerId(0)->save();
}
break;
}
}
/**
* Implements hook_ENTITY_TYPE_predelete() for user entities.
*/
function {{ machine_name }}_user_predelete(UserInterface $account): void {
// Delete {{ entity_type_label|lower|pluralize }} that belong to this account.
$storage = \Drupal::entityTypeManager()->getStorage('{{ entity_type_id }}');
${{ entity_type_id }}_ids = $storage->getQuery()
->condition('uid', $account->id())
->accessCheck(FALSE)
->execute();
$storage->delete(
$storage->loadMultiple(${{ entity_type_id }}_ids)
);
{% if revisionable %}
// Delete old revisions.
${{ entity_type_id }}_ids = $storage->getQuery()
->allRevisions()
->condition('uid', $account->id())
->accessCheck(FALSE)
->execute();
foreach (array_keys(${{ entity_type_id }}_ids) as $revision_id) {
$storage->deleteRevision($revision_id);
}
{% endif %}
}
{% endif %}

View File

@@ -0,0 +1,26 @@
{{ permissions.administer }}:
{% if bundle %}
title: 'Administer {{ entity_type_label|lower }} types'
description: 'Maintain the types of {{ entity_type_id_short|replace({'_': ' '}) }} entity.'
{% else %}
title: 'Administer {{ entity_type_label|lower|pluralize }}'
{% endif %}
restrict access: true
{% if access_controller %}
{{ permissions.view }}:
title: 'View {{ entity_type_label|lower }}'
{{ permissions.edit }}:
title: 'Edit {{ entity_type_label|lower }}'
{{ permissions.delete }}:
title: 'Delete {{ entity_type_label|lower }}'
{{ permissions.create }}:
title: 'Create {{ entity_type_label|lower }}'
{% endif %}
{% if revisionable and access_controller %}
{{ permissions.view_revision }}:
title: 'View {{ entity_type_label|lower }} revision'
{{ permissions.revert_revision }}:
title: 'Revert {{ entity_type_label|lower }} revision'
{{ permissions.delete_revision }}:
title: 'Delete {{ entity_type_label|lower }} revision'
{% endif %}

View File

@@ -0,0 +1,9 @@
{% if fieldable_no_bundle %}
entity.{{ entity_type_id }}.settings:
path: 'admin/structure/{{ entity_type_id|u2h }}'
defaults:
_form: '\Drupal\{{ machine_name }}\Form\{{ class }}SettingsForm'
_title: '{{ entity_type_label }}'
requirements:
_permission: '{{ permissions.administer }}'
{% endif %}

View File

@@ -0,0 +1,316 @@
<?php
declare(strict_types=1);
namespace Drupal\{{ machine_name }}\Entity;
{% apply sort_namespaces %}
{% if not revisionable %}
use Drupal\Core\Entity\ContentEntityBase;
{% endif %}
{% if author_base_field %}
use Drupal\Core\Entity\EntityStorageInterface;
{% endif %}
{% if has_base_fields %}
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
{% endif %}
{% if revisionable %}
use Drupal\Core\Entity\RevisionableContentEntityBase;
{% endif %}
use Drupal\{{ machine_name }}\{{ class }}Interface;
{% if author_base_field %}
use Drupal\user\EntityOwnerTrait;
{% endif %}
{% if changed_base_field %}
use Drupal\Core\Entity\EntityChangedTrait;
{% endif %}
{% endapply %}
/**
* Defines the {{ entity_type_label|lower }} entity class.
*
* @ContentEntityType(
* id = "{{ entity_type_id }}",
* label = @Translation("{{ entity_type_label }}"),
* label_collection = @Translation("{{ entity_type_label|pluralize }}"),
* label_singular = @Translation("{{ entity_type_label|lower }}"),
* label_plural = @Translation("{{ entity_type_label|pluralize|lower }}"),
* label_count = @PluralTranslation(
* singular = "@count {{ entity_type_label|pluralize|lower }}",
* plural = "@count {{ entity_type_label|pluralize|lower }}",
* ),
{% if bundle %}
* bundle_label = @Translation("{{ entity_type_label }} type"),
{% endif %}
* handlers = {
* "list_builder" = "Drupal\{{ machine_name }}\{{ class }}ListBuilder",
* "views_data" = "Drupal\views\EntityViewsData",
{% if access_controller %}
* "access" = "Drupal\{{ machine_name }}\{{ class }}AccessControlHandler",
{% endif %}
* "form" = {
* "add" = "Drupal\{{ machine_name }}\Form\{{ class }}Form",
* "edit" = "Drupal\{{ machine_name }}\Form\{{ class }}Form",
* "delete" = "Drupal\Core\Entity\ContentEntityDeleteForm",
* "delete-multiple-confirm" = "Drupal\Core\Entity\Form\DeleteMultipleForm",
{% if revisionable %}
* "revision-delete" = \Drupal\Core\Entity\Form\RevisionDeleteForm::class,
* "revision-revert" = \Drupal\Core\Entity\Form\RevisionRevertForm::class,
{% endif %}
* },
* "route_provider" = {
{% if canonical %}
* "html" = "Drupal\Core\Entity\Routing\AdminHtmlRouteProvider",
{% else %}
* "html" = "Drupal\{{ machine_name }}\Routing\{{ class }}HtmlRouteProvider",
{% endif %}
{% if revisionable %}
* "revision" = \Drupal\Core\Entity\Routing\RevisionHtmlRouteProvider::class,
{% endif %}
* },
* },
* base_table = "{{ entity_type_id }}",
{% if translatable %}
* data_table = "{{ entity_type_id }}_field_data",
{% endif %}
{% if revisionable %}
* revision_table = "{{ entity_type_id }}_revision",
{% endif %}
{% if revisionable and translatable %}
* revision_data_table = "{{ entity_type_id }}_field_revision",
{% endif %}
{% if revisionable %}
* show_revision_ui = TRUE,
{% endif %}
{% if translatable %}
* translatable = TRUE,
{% endif %}
* admin_permission = "{{ permissions.administer }}",
* entity_keys = {
* "id" = "id",
{% if revisionable %}
* "revision" = "revision_id",
{% endif %}
{% if translatable %}
* "langcode" = "langcode",
{% endif %}
{% if bundle %}
* "bundle" = "bundle",
{% endif %}
* "label" = "{{ label_base_field ? 'label' : 'id' }}",
{% if author_base_field %}
* "uuid" = "uuid",
* "owner" = "uid",
{% else %}
* "uuid" = "uuid",
{% endif %}
* },
{% if revisionable %}
* revision_metadata_keys = {
* "revision_user" = "revision_uid",
* "revision_created" = "revision_timestamp",
* "revision_log_message" = "revision_log",
* },
{% endif %}
* links = {
* "collection" = "/admin/content/{{ entity_type_id_short|u2h }}",
{% if bundle %}
* "add-form" = "{{ entity_base_path }}/add/{{ '{' }}{{ entity_type_id }}{{ '_type}' }}",
* "add-page" = "{{ entity_base_path }}/add",
{% else %}
* "add-form" = "{{ entity_base_path }}/add",
{% endif %}
* "canonical" = "{{ entity_base_path }}/{{ '{' }}{{ entity_type_id }}{{ '}' }}",
{% if canonical %}
* "edit-form" = "{{ entity_base_path }}/{{ '{' }}{{ entity_type_id }}{{ '}' }}/edit",
{% else %}
* "edit-form" = "{{ entity_base_path }}/{{ '{' }}{{ entity_type_id }}{{ '}' }}",
{% endif %}
* "delete-form" = "{{ entity_base_path }}/{{ '{' }}{{ entity_type_id }}{{ '}' }}/delete",
* "delete-multiple-form" = "/admin/content/{{ entity_type_id_short|u2h }}/delete-multiple",
{% if revisionable %}
* "revision" = "{{ entity_base_path }}/{{ '{' }}{{ entity_type_id }}{{ '}' }}/revision/{{ '{' }}{{ entity_type_id ~ '_revision' }}{{ '}' }}/view",
* "revision-delete-form" = "{{ entity_base_path }}/{{ '{' }}{{ entity_type_id }}{{ '}' }}/revision/{{ '{' }}{{ entity_type_id ~ '_revision' }}{{ '}' }}/delete",
* "revision-revert-form" = "{{ entity_base_path }}/{{ '{' }}{{ entity_type_id }}{{ '}' }}/revision/{{ '{' }}{{ entity_type_id ~ '_revision' }}{{ '}' }}/revert",
* "version-history" = "{{ entity_base_path }}/{{ '{' }}{{ entity_type_id }}{{ '}' }}/revisions",
{% endif %}
* },
{% if bundle %}
* bundle_entity_type = "{{ entity_type_id }}_type",
* field_ui_base_route = "entity.{{ entity_type_id }}_type.edit_form",
{% elseif fieldable %}
* field_ui_base_route = "entity.{{ entity_type_id }}.settings",
{% endif %}
* )
*/
final class {{ class }} extends {% if revisionable %}Revisionable{% endif %}ContentEntityBase implements {{ class }}Interface {
{% if changed_base_field or author_base_field %}
{% if changed_base_field %}
use EntityChangedTrait;
{% endif %}
{# use EntityCreatedTrait once it is added to Drupal core #}
{# @see https://www.drupal.org/node/2833378 #}
{% if author_base_field %}
use EntityOwnerTrait;
{% endif %}
{% endif %}
{% if author_base_field %}
/**
* {@inheritdoc}
*/
public function preSave(EntityStorageInterface $storage): void {
parent::preSave($storage);
if (!$this->getOwnerId()) {
// If no owner has been set explicitly, make the anonymous user the owner.
$this->setOwnerId(0);
}
}
{% endif %}
{% if has_base_fields %}
/**
* {@inheritdoc}
*/
public static function baseFieldDefinitions(EntityTypeInterface $entity_type): array {
$fields = parent::baseFieldDefinitions($entity_type);
{% if label_base_field %}
$fields['label'] = BaseFieldDefinition::create('string')
{% if revisionable %}
->setRevisionable(TRUE)
{% endif %}
{% if translatable %}
->setTranslatable(TRUE)
{% endif %}
->setLabel(t('Label'))
->setRequired(TRUE)
->setSetting('max_length', 255)
->setDisplayOptions('form', [
'type' => 'string_textfield',
'weight' => -5,
])
->setDisplayConfigurable('form', TRUE)
->setDisplayOptions('view', [
'label' => 'hidden',
'type' => 'string',
'weight' => -5,
])
->setDisplayConfigurable('view', TRUE);
{% endif %}
{% if status_base_field %}
$fields['status'] = BaseFieldDefinition::create('boolean')
{% if revisionable %}
->setRevisionable(TRUE)
{% endif %}
->setLabel(t('Status'))
->setDefaultValue(TRUE)
->setSetting('on_label', 'Enabled')
->setDisplayOptions('form', [
'type' => 'boolean_checkbox',
'settings' => [
'display_label' => FALSE,
],
'weight' => 0,
])
->setDisplayConfigurable('form', TRUE)
->setDisplayOptions('view', [
'type' => 'boolean',
'label' => 'above',
'weight' => 0,
'settings' => [
'format' => 'enabled-disabled',
],
])
->setDisplayConfigurable('view', TRUE);
{% endif %}
{% if description_base_field %}
$fields['description'] = BaseFieldDefinition::create('text_long')
{% if revisionable %}
->setRevisionable(TRUE)
{% endif %}
{% if translatable %}
->setTranslatable(TRUE)
{% endif %}
->setLabel(t('Description'))
->setDisplayOptions('form', [
'type' => 'text_textarea',
'weight' => 10,
])
->setDisplayConfigurable('form', TRUE)
->setDisplayOptions('view', [
'type' => 'text_default',
'label' => 'above',
'weight' => 10,
])
->setDisplayConfigurable('view', TRUE);
{% endif %}
{% if author_base_field %}
$fields['uid'] = BaseFieldDefinition::create('entity_reference')
{% if revisionable %}
->setRevisionable(TRUE)
{% endif %}
{% if translatable %}
->setTranslatable(TRUE)
{% endif %}
->setLabel(t('Author'))
->setSetting('target_type', 'user')
->setDefaultValueCallback(self::class . '::getDefaultEntityOwner')
->setDisplayOptions('form', [
'type' => 'entity_reference_autocomplete',
'settings' => [
'match_operator' => 'CONTAINS',
'size' => 60,
'placeholder' => '',
],
'weight' => 15,
])
->setDisplayConfigurable('form', TRUE)
->setDisplayOptions('view', [
'label' => 'above',
'type' => 'author',
'weight' => 15,
])
->setDisplayConfigurable('view', TRUE);
{% endif %}
{% if created_base_field %}
$fields['created'] = BaseFieldDefinition::create('created')
->setLabel(t('Authored on'))
{% if translatable %}
->setTranslatable(TRUE)
{% endif %}
->setDescription(t('The time that the {{ entity_type_label|lower }} was created.'))
->setDisplayOptions('view', [
'label' => 'above',
'type' => 'timestamp',
'weight' => 20,
])
->setDisplayConfigurable('form', TRUE)
->setDisplayOptions('form', [
'type' => 'datetime_timestamp',
'weight' => 20,
])
->setDisplayConfigurable('view', TRUE);
{% endif %}
{% if changed_base_field %}
$fields['changed'] = BaseFieldDefinition::create('changed')
->setLabel(t('Changed'))
{% if translatable %}
->setTranslatable(TRUE)
{% endif %}
->setDescription(t('The time that the {{ entity_type_label|lower }} was last edited.'));
{% endif %}
return $fields;
}
{% endif %}
}

View File

@@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
namespace Drupal\{{ machine_name }}\Entity;
use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
/**
* Defines the {{ entity_type_label }} type configuration entity.
*
* @ConfigEntityType(
* id = "{{ entity_type_id }}_type",
* label = @Translation("{{ entity_type_label }} type"),
* label_collection = @Translation("{{ entity_type_label }} types"),
* label_singular = @Translation("{{ entity_type_label|lower }} type"),
* label_plural = @Translation("{{ entity_type_label|pluralize|lower }} types"),
* label_count = @PluralTranslation(
* singular = "@count {{ entity_type_label|pluralize|lower }} type",
* plural = "@count {{ entity_type_label|pluralize|lower }} types",
* ),
* handlers = {
* "form" = {
* "add" = "Drupal\{{ machine_name }}\Form\{{ class }}TypeForm",
* "edit" = "Drupal\{{ machine_name }}\Form\{{ class }}TypeForm",
* "delete" = "Drupal\Core\Entity\EntityDeleteForm",
* },
* "list_builder" = "Drupal\{{ machine_name }}\{{ class }}TypeListBuilder",
* "route_provider" = {
* "html" = "Drupal\Core\Entity\Routing\AdminHtmlRouteProvider",
* },
* },
* admin_permission = "{{ permissions.administer }}",
* bundle_of = "{{ entity_type_id }}",
* config_prefix = "{{ entity_type_id }}_type",
* entity_keys = {
* "id" = "id",
* "label" = "label",
* "uuid" = "uuid",
* },
* links = {
* "add-form" = "/admin/structure/{{ entity_type_id }}_types/add",
* "edit-form" = "/admin/structure/{{ entity_type_id }}_types/manage/{{ '{' ~ entity_type_id ~ '_type}' }}",
* "delete-form" = "/admin/structure/{{ entity_type_id }}_types/manage/{{ '{' ~ entity_type_id ~ '_type}' }}/delete",
* "collection" = "/admin/structure/{{ entity_type_id }}_types",
* },
* config_export = {
* "id",
* "label",
* "uuid",
* },
* )
*/
final class {{ class }}Type extends ConfigEntityBundleBase {
/**
* The machine name of this {{ entity_type_label|lower }} type.
*/
protected string $id;
/**
* The human-readable name of the {{ entity_type_label|lower }} type.
*/
protected string $label;
}

View File

@@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
namespace Drupal\{{ machine_name }};
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\EntityAccessControlHandler;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Session\AccountInterface;
/**
* Defines the access control handler for the {{ entity_type_label|lower }} entity type.
*
* phpcs:disable Drupal.Arrays.Array.LongLineDeclaration
*
* @see https://www.drupal.org/project/coder/issues/3185082
*/
final class {{ class }}AccessControlHandler extends EntityAccessControlHandler {
/**
* {@inheritdoc}
*/
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account): AccessResult {
if ($account->hasPermission($this->entityType->getAdminPermission())) {
return AccessResult::allowed()->cachePerPermissions();
}
return match($operation) {
'view' => AccessResult::allowedIfHasPermission($account, '{{ permissions.view }}'),
'update' => AccessResult::allowedIfHasPermission($account, '{{ permissions.edit }}'),
'delete' => AccessResult::allowedIfHasPermission($account, '{{ permissions.delete }}'),
{% if revisionable %}
'delete revision' => AccessResult::allowedIfHasPermission($account, '{{ permissions.delete_revision }}'),
'view all revisions', 'view revision' => AccessResult::allowedIfHasPermissions($account, ['{{ permissions.view_revision }}', '{{ permissions.view }}']),
'revert' => AccessResult::allowedIfHasPermissions($account, ['{{ permissions.revert_revision }}', '{{ permissions.edit }}']),
{% endif %}
default => AccessResult::neutral(),
};
}
/**
* {@inheritdoc}
*/
protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL): AccessResult {
return AccessResult::allowedIfHasPermissions($account, ['{{ permissions.create }}', '{{ permissions.administer }}'], 'OR');
}
}

View File

@@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace Drupal\{{ machine_name }};
use Drupal\Core\Entity\ContentEntityInterface;
{% if changed_base_field %}
use Drupal\Core\Entity\EntityChangedInterface;
{% endif %}
{% if author_base_field %}
use Drupal\user\EntityOwnerInterface;
{% endif %}
/**
* Provides an interface defining {{ entity_type_label|article|lower }} entity type.
*/
interface {{ class }}Interface extends ContentEntityInterface{% if author_base_field %}, EntityOwnerInterface{% endif %}{% if changed_base_field %}, EntityChangedInterface{% endif %} {
}

View File

@@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
namespace Drupal\{{ machine_name }};
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityListBuilder;
/**
* Provides a list controller for the {{ entity_type_label|lower }} entity type.
*/
final class {{ class }}ListBuilder extends EntityListBuilder {
/**
* {@inheritdoc}
*/
public function buildHeader(): array {
$header['id'] = $this->t('ID');
{% if label_base_field %}
$header['label'] = $this->t('Label');
{% endif %}
{% if status_base_field %}
$header['status'] = $this->t('Status');
{% endif %}
{% if author_base_field %}
$header['uid'] = $this->t('Author');
{% endif %}
{% if created_base_field %}
$header['created'] = $this->t('Created');
{% endif %}
{% if changed_base_field %}
$header['changed'] = $this->t('Updated');
{% endif %}
return $header + parent::buildHeader();
}
/**
* {@inheritdoc}
*/
public function buildRow(EntityInterface $entity): array {
/** @var \Drupal\{{ machine_name }}\{{ class }}Interface $entity */
$row['id'] = $entity->{{ label_base_field or not canonical ? 'id' : 'toLink' }}();
{% if label_base_field %}
$row['label'] = $entity->{{ canonical ? 'toLink' : 'label' }}();
{% endif %}
{% if status_base_field %}
$row['status'] = $entity->get('status')->value ? $this->t('Enabled') : $this->t('Disabled');
{% endif %}
{% if author_base_field %}
$username_options = [
'label' => 'hidden',
'settings' => ['link' => $entity->get('uid')->entity->isAuthenticated()],
];
$row['uid']['data'] = $entity->get('uid')->view($username_options);
{% endif %}
{% if created_base_field %}
$row['created']['data'] = $entity->get('created')->view(['label' => 'hidden']);
{% endif %}
{% if changed_base_field %}
$row['changed']['data'] = $entity->get('changed')->view(['label' => 'hidden']);
{% endif %}
return $row + parent::buildRow($entity);
}
}

View File

@@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace Drupal\{{ machine_name }};
use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Url;
/**
* Defines a class to build a listing of {{ entity_type_label|lower }} type entities.
*
* @see \Drupal\{{ machine_name }}\Entity\{{ class }}Type
*/
final class {{ class }}TypeListBuilder extends ConfigEntityListBuilder {
/**
* {@inheritdoc}
*/
public function buildHeader(): array {
$header['label'] = $this->t('Label');
return $header + parent::buildHeader();
}
/**
* {@inheritdoc}
*/
public function buildRow(EntityInterface $entity): array {
$row['label'] = $entity->label();
return $row + parent::buildRow($entity);
}
/**
* {@inheritdoc}
*/
public function render(): array {
$build = parent::render();
$build['table']['#empty'] = $this->t(
'No {{ entity_type_label|lower }} types available. <a href=":link">Add {{ entity_type_label|lower }} type</a>.',
[':link' => Url::fromRoute('entity.{{ entity_type_id }}_type.add_form')->toString()],
);
return $build;
}
}

View File

@@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
namespace Drupal\{{ machine_name }}\Form;
use Drupal\Core\Entity\ContentEntityForm;
use Drupal\Core\Form\FormStateInterface;
/**
* Form controller for the {{ entity_type_label|lower }} entity edit forms.
*/
final class {{ class }}Form extends ContentEntityForm {
/**
* {@inheritdoc}
*/
public function save(array $form, FormStateInterface $form_state): int {
$result = parent::save($form, $form_state);
$message_args = ['%label' => $this->entity->toLink()->toString()];
$logger_args = [
'%label' => $this->entity->label(),
'link' => $this->entity->toLink($this->t('View'))->toString(),
];
switch ($result) {
case SAVED_NEW:
$this->messenger()->addStatus($this->t('New {{ entity_type_label|lower }} %label has been created.', $message_args));
$this->logger('{{ machine_name }}')->notice('New {{ entity_type_label|lower }} %label has been created.', $logger_args);
break;
case SAVED_UPDATED:
$this->messenger()->addStatus($this->t('The {{ entity_type_label|lower }} %label has been updated.', $message_args));
$this->logger('{{ machine_name }}')->notice('The {{ entity_type_label|lower }} %label has been updated.', $logger_args);
break;
default:
throw new \LogicException('Could not save the entity.');
}
{% if canonical %}
$form_state->setRedirectUrl($this->entity->toUrl());
{% else %}
$form_state->setRedirectUrl($this->entity->toUrl('collection'));
{% endif %}
return $result;
}
}

View File

@@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
namespace Drupal\{{ machine_name }}\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
/**
* Configuration form for {{ entity_type_label|article|lower }} entity type.
*/
final class {{ class }}SettingsForm extends FormBase {
/**
* {@inheritdoc}
*/
public function getFormId(): string {
return '{{ entity_type_id }}_settings';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state): array {
$form['settings'] = [
'#markup' => $this->t('Settings form for {{ entity_type_label|article|lower }} entity type.'),
];
$form['actions'] = [
'#type' => 'actions',
'submit' => [
'#type' => 'submit',
'#value' => $this->t('Save'),
],
];
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state): void {
$this->messenger()->addStatus($this->t('The configuration has been updated.'));
}
}

View File

@@ -0,0 +1,79 @@
<?php
declare(strict_types=1);
namespace Drupal\{{ machine_name }}\Form;
{% apply sort_namespaces %}
use Drupal\Core\Entity\BundleEntityFormBase;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\{{ machine_name }}\Entity\{{ class }}Type;
{% endapply %}
/**
* Form handler for {{ entity_type_label|lower }} type forms.
*/
final class {{ class }}TypeForm extends BundleEntityFormBase {
/**
* {@inheritdoc}
*/
public function form(array $form, FormStateInterface $form_state): array {
$form = parent::form($form, $form_state);
if ($this->operation === 'edit') {
$form['#title'] = $this->t('Edit %label {{ entity_type_label|lower }} type', ['%label' => $this->entity->label()]);
}
$form['label'] = [
'#title' => $this->t('Label'),
'#type' => 'textfield',
'#default_value' => $this->entity->label(),
'#description' => $this->t('The human-readable name of this {{ entity_type_label|lower }} type.'),
'#required' => TRUE,
];
$form['id'] = [
'#type' => 'machine_name',
'#default_value' => $this->entity->id(),
'#maxlength' => EntityTypeInterface::BUNDLE_MAX_LENGTH,
'#machine_name' => [
'exists' => [{{ class }}Type::class, 'load'],
'source' => ['label'],
],
'#description' => $this->t('A unique machine-readable name for this {{ entity_type_label|lower }} type. It must only contain lowercase letters, numbers, and underscores.'),
];
return $this->protectBundleIdElement($form);
}
/**
* {@inheritdoc}
*/
protected function actions(array $form, FormStateInterface $form_state): array {
$actions = parent::actions($form, $form_state);
$actions['submit']['#value'] = $this->t('Save {{ entity_type_label|lower }} type');
$actions['delete']['#value'] = $this->t('Delete {{ entity_type_label|lower }} type');
return $actions;
}
/**
* {@inheritdoc}
*/
public function save(array $form, FormStateInterface $form_state): int {
$result = parent::save($form, $form_state);
$message_args = ['%label' => $this->entity->label()];
$this->messenger()->addStatus(
match($result) {
SAVED_NEW => $this->t('The {{ entity_type_label|lower }} type %label has been added.', $message_args),
SAVED_UPDATED => $this->t('The {{ entity_type_label|lower }} type %label has been updated.', $message_args),
}
);
$form_state->setRedirectUrl($this->entity->toUrl('collection'));
return $result;
}
}

View File

@@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace Drupal\{{ machine_name }}\Routing;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\Routing\AdminHtmlRouteProvider;
use Symfony\Component\Routing\Route;
/**
* Provides HTML routes for entities with administrative pages.
*/
final class {{ class }}HtmlRouteProvider extends AdminHtmlRouteProvider {
/**
* {@inheritdoc}
*/
protected function getCanonicalRoute(EntityTypeInterface $entity_type): ?Route {
return $this->getEditFormRoute($entity_type);
}
}

View File

@@ -0,0 +1,24 @@
{{ '{#' }}
/**
* @file
* Default theme implementation to present {{ entity_type_label|article|lower }} entity.
*
* This template is used when viewing a canonical {{ entity_type_label|lower }} page,
*
* Available variables:
* - content: A list of content items. Use 'content' to print all content, or
* print a subset such as 'content.label'.
* - attributes: HTML attributes for the container element.
*
* @see template_preprocess_{{ entity_type_id }}()
*/
{{ '#}' }}{% verbatim %}
<article{{ attributes }}>
{% if view_mode != 'full' %}
{{ title_prefix }}
{{ title_suffix }}
{% endif %}
{% if content %}
{{- content -}}
{% endif %}
</article>{% endverbatim %}

View File

@@ -0,0 +1,14 @@
<?php
declare(strict_types=1);
namespace {{ namespace }};
use {{ entity_class_fqn }};
/**
* A base bundle class for {{ entity_type_id }} entities.
*/
abstract class {{ base_class }} extends {{ entity_class }} {
}

View File

@@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace {{ namespace }};
{% if not base_class %}
use {{ entity_class_fqn }};
{% endif %}
/**
* A bundle class for {{ entity_type_id }} entities.
*/
final class {{ class }} extends {{ base_class ?: entity_class }} {
}

View File

@@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
/**
* @file
* Primary module hooks for {{ name }} module.
*/
/**
* Implements hook_entity_bundle_info_alter().
*/
function {{ machine_name }}_entity_bundle_info_alter(array &$bundles): void {
{% for bundle_id, class_fqn in classes_fqn %}
if (isset($bundles['{{ entity_type_id }}']['{{ bundle_id }}'])) {
// phpcs:ignore Drupal.Classes.FullyQualifiedNamespace.UseStatementMissing
$bundles['{{ entity_type_id }}']['{{ bundle_id }}']['class'] = {{ class_fqn }}::class;
}
{% endfor %}
}