module_builder-8.x-3.x-dev/src/Form/ModuleNameForm.php

src/Form/ModuleNameForm.php
<?php

namespace Drupal\module_builder\Form;

use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Extension\ModuleExtensionList;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\module_builder\DrupalCodeBuilder;
use MutableTypedData\Data\DataItem;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Form for editing basic information, and also for adding new module entities.
 */
class ModuleNameForm extends ComponentSectionForm {

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('module_builder.drupal_code_builder'),
      $container->get('extension.list.module'),
    );
  }

  /**
   * Creates a ModuleNameForm instance.
   *
   * @param \Drupal\module_builder\DrupalCodeBuilder $code_builder
   *   The drupal code builder service.
   * @param \Drupal\Core\Extension\ModuleExtensionList $moduleExtensionList
   *   The module extension list service.
   */
  public function __construct(
    DrupalCodeBuilder $code_builder,
    protected ModuleExtensionList $moduleExtensionList,
  ) {
    parent::__construct($code_builder);
  }

  /**
   * {@inheritdoc}
   */
  protected function getFormComponentProperties(DataItem $data) {
    // Get the list of component properties this section form uses from the
    // handler, which gets them from the entity type annotation.
    $component_entity_type_id = $this->entity->getEntityTypeId();
    $component_sections_handler = $this->entityTypeManager->getHandler($component_entity_type_id, 'component_sections');

    // Need to override this method to hardcode the form operation name, because
    // there is a mismatch between our system which wants this to be the 'name'
    // op, but uses the 'edit' op's route and form class.
    // TODO: clean up!
    $operation = 'name';
    $component_properties_to_use = $component_sections_handler->getSectionFormComponentProperties($operation);
    return $component_properties_to_use;
  }

  /**
   * {@inheritdoc}
   */
  public function form(array $form, FormStateInterface $form_state) {
    $module = $this->entity;

    // The name.
    $form['name'] = array(
      '#type' => 'textfield',
      '#title' => $this->t('Readable name'),
      '#maxlength' => 255,
      '#default_value' => isset($module->name) ? $module->name : '',
      '#description' => $this->t("The form of the module name that appears in the UI."),
      '#required' => TRUE,
    );

    // The machine name.
    $form['id'] = array(
      '#type' => 'machine_name',
      '#title' => $this->t('Name'),
      '#description' => $this->t("The module's machine name, used in function and file names. May only contain lowercase letters, numbers, and underscores."),
      '#maxlength' => 32,
      '#default_value' => $module->id,
      '#machine_name' => array(
        'exists' => '\Drupal\module_builder\Entity\ModuleBuilderModule::load',
        'source' => ['name'],
        'standalone' => TRUE,
      ),
    );

    $form['location'] = [
      '#type' => 'details',
      '#title' => $this->t('Write location'),
      '#tree' => TRUE,
      '#weight' => 20,
    ];
    $form['location']['#open'] = ($module->location['location_type'] ?? 'standard') != 'standard';

    $form['location']['location_type'] = [
      '#type' => 'radios',
      '#title' => $this->t('Write location'),
      '#options' => [
        'standard' => $this->t("Standard. Writes to the existing module's location if it exists, 'modules/custom' if that exists, and finally 'modules'."),
        'test' => $this->t("Test module. Writes inside a /tests/modules/ folder inside another module."),
        'sub' => $this->t("Submodule. Writes inside a /modules/ folder inside another module."),
        'custom' => $this->t("Custom location. Use an absolute path to write outside the current project."),
      ],
      '#default_value' => $module->location['location_type'] ?? 'standard',
    ];

    $module_list = $this->moduleExtensionList->getList();
    $map_module_to_name = fn ($module) => $module->info['name'];

    // Submodules can go inside a top-level module.
    $sub_parent_modules = array_filter($module_list, function ($module) {
      $pathname = $module->getPathname();

      // Get the info file pathname within the main modules folder.
      // Figure out how much of the pathname to trim.
      $trim_offset = match (TRUE) {
        str_starts_with($pathname, 'core/modules/') => 13,
        str_starts_with($pathname, 'modules/contrib/') => 16,
        str_starts_with($pathname, 'modules/custom/') => 15,
        // This goes last so it only gets used for sites that don't have contrib
        // and custom folders.
        str_starts_with($pathname, 'modules/') => 8,
        default => 0,
      };

      // Project modules are directly within a modules discovery folder, and so
      // their info file once trimmed only contains 1 '/', because it's of the
      // format module_name/module_name.info.yml.
      $pathname_within_modules_folder = substr($pathname, $trim_offset);

      return substr_count($pathname_within_modules_folder, '/') == 1;
    });

    $form['location']['parent_module'] = [
      '#type' => 'select',
      '#title' => $this->t('Parent module of submodule'),
      '#description' => $this->t("."),
      '#options' => array_map($map_module_to_name, $sub_parent_modules),
      '#empty_value' => '',
      '#sort_options' => TRUE,
      '#default_value' => $module->location['parent_module'] ?? '',
      '#states' => [
        'visible' => [
          ':input[name="location[location_type]"]' => ['value' => 'sub'],
        ],
        'required' => [
          ':input[name="location[location_type]"]' => ['value' => 'sub'],
        ],
      ],
    ];

    // Test modules can go inside any module, except for other testing modules.
    $test_parent_modules = array_filter($module_list, fn ($module) => $module->info['package'] != 'Testing');

    $form['location']['test_parent_module'] = [
      '#type' => 'select',
      '#title' => $this->t('Parent module of test module'),
      '#description' => $this->t("."),
      '#options' => array_map($map_module_to_name, $test_parent_modules),
      '#empty_value' => '',
      '#sort_options' => TRUE,
      '#default_value' => $module->location['test_parent_module'] ?? '',
      '#states' => [
        'visible' => [
          ':input[name="location[location_type]"]' => ['value' => 'test'],
        ],
        'required' => [
          ':input[name="location[location_type]"]' => ['value' => 'test'],
        ],
      ],
    ];

    $form['location']['custom'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Custom write location'),
      '#maxlength' => 128,
      '#default_value' => $module->location['custom'] ?? '',
      '#description' => $this->t("A sub-path inside the Drupal root into which to place this module. Do not include the module name."),
      '#states' => [
        'visible' => [
          ':input[name="location[location_type]"]' => ['value' => 'custom'],
        ],
        'required' => [
          ':input[name="location[location_type]"]' => ['value' => 'custom'],
        ],
      ],
    ];

    $form = parent::form($form, $form_state);

    return $form;
  }

  /**
   * Returns an array of supported actions for the current entity form.
   */
  protected function actions(array $form, FormStateInterface $form_state) {
    $actions = parent::actions($form, $form_state);

    if ($this->entity->isNew()) {
      $button = $actions['submit'];
      $button['#value'] = $this->t('Save basic information');
      // Babysit core bug: dropbutton with only one item looks wrong.
      unset($button['#dropbutton']);

      $actions = [
        'submit' => $button,
      ];
    }

    return $actions;
  }

  /**
   * Copies top-level form values to entity properties
   *
   * This should not change existing entity properties that are not being edited
   * by this form.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The entity the current form should operate upon.
   * @param array $form
   *   A nested array of form elements comprising the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   */
  protected function copyFormValuesToEntity(EntityInterface $entity, array $form, FormStateInterface $form_state) {
    $values = $form_state->getValues();

    if ($this->entity instanceof EntityWithPluginCollectionInterface) {
      // Do not manually update values represented by plugin collections.
      $values = array_diff_key($values, $this->entity->getPluginCollections());
    }

    // Zap unrelated values in the  location values.
    $additional_key = match ($values['location']['location_type']) {
      'standard' => NULL,
      'test' => 'test_parent_module',
      'sub' => 'parent_module',
      'custom' => 'custom',
    };
    $location_keys = [
      'location_type' => TRUE,
      $additional_key => TRUE,
    ];
    $values['location'] = array_intersect_key($values['location'], $location_keys);

    // Set the base properties.
    foreach (['name', 'id', 'location'] as $key) {
      $entity->set($key, $values[$key]);

      // Remove so it doesn't end up in the $entity->data array.
      unset($values[$key]);
    }

    // Call the parent to set the data array properties.
    parent::copyFormValuesToEntity($entity, $form, $form_state);
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc