Drupal 9에서 깨끗한 OOP 배치를 만드는 방법은 무엇입니까?

Drupal 9에서 깨끗한 OOP 배치를 만드는 방법은 무엇입니까?

2022-10-01 last update

22 minutes reading drupal php batch drupal9
OOP 배치의 Drupal 9 핵심 구현을 기다리는 동안 시작점이 필요합니다.

예는 Drupal 9.2.6+(PHP 7.4.2+)에 대한 것입니다.

모듈에 대한 가능한 경로: web/modules/custom
  • 모듈을 만들고 이름을 지정하고module_example 거기에 추가합니다/module_example/module_example.module.
    필수 파일이므로 모듈 폴더에 넣으면 됩니다.
  • module_example.module
    <?php
    /*
     * Every module needs this file.
    */
    
    


  • /module_example/module_example.info.yml 파일을 추가합니다.
    또한 필요한 파일, 모듈에 대한 정보를 입력합니다.
  • module_example.info.yml
    # Change name, description, package on your needs.
    name: Module Example
    type: module
    description: Module example
    package: Module example
    core_version_requirement: ^9
    
    


  • /module_example/module_example.routing.yml 파일을 추가합니다.
    배치를 시작할 양식의 경로를 여기에 입력하십시오.
  • module_example.routing.yml
    # Change here routing name,path,_form,_title for your specific form.
    module_example.admin_form.example_form:
      path: '/admin/config/system/module-example'
      defaults:
        _form: '\Drupal\module_example\Form\ExampleForm'
        _title: 'Form example'
      requirements:
        _user_is_logged_in: 'TRUE'
        _permission: 'administer site configuration'
    


  • /module_example/module_example.services.yml 파일을 추가합니다.
    배치에 필요하며 특별한 정의가 없기 때문에 서비스가 될 것입니다.
  • module_example.services.yml
    # Change here service name, class and arguments to inject for your needs.
    services:
      module_example.batch_example:
        class: Drupal\module_example\Batch\BatchExample
        arguments: ['@messenger', '@extension.list.module']
    
    


  • /module_example/src 폴더를 생성합니다.
  • /module_example/src/Form 폴더를 생성합니다.
  • /module_example/src/Form/ExampleForm.php 파일을 생성합니다.
    어딘가에서 배치를 제어하려면 이 양식이 필요합니다.
    이 예제에서는 양식을 사용합니다.
  • ExampleForm.php
    <?php
    
    namespace Drupal\module_example\Form;
    
    use Drupal\Core\Form\FormBase;
    use Drupal\Core\Form\FormStateInterface;
    use Symfony\Component\DependencyInjection\ContainerInterface;
    
    /**
     * Implements an Example form.
     */
    class ExampleForm extends FormBase {
    
      /**
       * Batch injection.
       *
       * @var \Drupal\module_example\Batch\BatchExample
        *   Grab the path from module_example.services.yml file.
       */
      protected $batch;
    
      /**
       * {@inheritdoc}
       */
      public static function create(ContainerInterface $container) {
        // Instantiates this form class.
        $instance = parent::create($container);
        // Put here injection of your batch service by name from module_example.services.yml file.
        $instance->batch = $container->get('module_example.batch_example');
    
        return $instance;
      }
    
      /**
       * {@inheritdoc}
       */
      public function getFormId() {
        // Any name for your form to indicate it.
        return 'example_of_form';
      }
    
      /**
       * {@inheritdoc}
       */
      public function buildForm(array $form, FormStateInterface $form_state) {
        // No need for t() in admin part.
        // Triggers submitForm() function.
        $form['submit'] = [
          '#type' => 'submit',
          '#prefix' => '<br>',
          '#value' => 'Start batch',
        ];
    
        return $form;
      }
    
      /**
       * {@inheritdoc}
       */
      public function submitForm(array &$form, FormStateInterface $form_state) {
        // As we don't need to change in our batch depending on inputs,
        // just passing empty array or removing param.
        $values = [];
        $this->batch->run($values);
      }
    
    }
    
    


  • /module_example/src/Batch 폴더를 생성합니다.
  • /module_example/src/Batch/BatchExample.php 파일을 추가합니다.
  • BatchExample.php
    <?php
    
    namespace Drupal\module_example\Batch;
    
    use Drupal\Core\Batch\BatchBuilder;
    use Drupal\Core\Messenger\MessengerInterface;
    use Drupal\Core\Extension\ModuleExtensionList;
    use Drupal\Core\DependencyInjection\DependencySerializationTrait;
    
    /**
     * Batch Example.
     */
    class BatchExample {
    
      use DependencySerializationTrait;
    
      /**
       * The messenger.
       *
       * @var \Drupal\Core\Messenger\MessengerInterface
       */
      protected $messenger;
    
      /**
       * Module extension list.
       *
       * @var \Drupal\Core\Extension\ModuleExtensionList
       */
      protected $moduleExtensionList;
    
      /**
       * Constructor.
       *
       * @param \Drupal\Core\Messenger\MessengerInterface $messenger
       *   The messenger.
       * @param \Drupal\Core\Extension\ModuleExtensionList $moduleExtensionList
       *   The module extension list.
       */
      public function __construct(
        MessengerInterface $messenger,
        ModuleExtensionList $moduleExtensionList
      ) {
        $this->messenger = $messenger;
        $this->moduleExtensionList = $moduleExtensionList;
      }
    
      /**
       * The Starting point for batch.
       *
       * @param $values
       *   If you need to change behavior of batch but not much, send values from external.
       */
      public function run($values) {
        // File needs to be placed /module_example/src/Batch or hardcode the name of module.
        $moduleName = basename(dirname(__DIR__, 2));
        $modulePath = $this->moduleExtensionList->getPath($moduleName);
        $batchBuilder = new BatchBuilder();
        $batchBuilder
          // Change batch name here.
          ->setTitle('Example batch')
          ->setInitMessage('Initializing. <br/><b style="color: #f00;">Navigating away will stop the process.</b>')
          ->setProgressMessage('Completed @current of @total. <br/><b style="color: #f00;">Navigating away will stop the process.</b>')
          ->setErrorMessage('Batch has encountered an error.')
          ->setFile($modulePath . '/src/Batch/' . basename(__FILE__));
    
        // Dummy data, grab data on this place.
        $items = [
          ['id' => 0, 'data' => 'item'],
          ['id' => 1, 'data' => 'item'],
          ['id' => 2, 'data' => 'item'],
        ];
        if (!empty($items)) {
          foreach ($items as $item) {
            // Adding operations that we will process on each item in a batch.
            $batchBuilder->addOperation([$this, 'process'], [
              $item,
              // Add how many variables you need here.
            ]);
          }
          $batchBuilder->setFinishCallback([$this, 'finish']);
          // Changing it to array that we can set it in functional way (only way on this moment).
          $batch = $batchBuilder->toArray();
          batch_set($batch);
        }
        else {
          $this->messenger->addMessage('No entities exists');
        }
      }
    
      /**
       * Batch processor.
       */
      public function process($item, &$context) {
        try {
          $id = $item['id'];
          // Display a progress message.
          $context['message'] = "Now processing {$id} entity...";
          // Body of the batch, logic that needs to be presented place here.
          $changed = FALSE;
          // For example we will change item data.
          if (!empty($item['data'])) {
            $item['data'] .= $id; 
            $changed = TRUE;
          }
          if ($changed === TRUE) {
            // Save the changes for your objects here.
          }
          else {
            // Skip this step if something went wrong or changes weren't presented.
            throw new \Exception('Skip if cant handle');
          }
        }
        catch (\Throwable $th) {
          $this->messenger->addError($th->getMessage());
        }
      }
    
      /**
       * Finish operation.
       */
      public function finish($success, $results, $operations, $elapsed) {
        if ($success) {
          // Change success message here.
          $this->messenger->addMessage('Example batch is finished!');
        }
        else {
          $error_operation = reset($operations);
          $arguments = print_r($error_operation[1], TRUE);
          $message = "An error occurred while processing {$error_operation[0]} with arguments: {$arguments}";
          $this->messenger->addMessage($message, 'error');
        }
      }
    
    }
    
    


    기능에 대한 전체 개요가 없는 배치용 골격일 뿐입니다.
    아니요$context['sandbox'] 그리고 여기에서 사용된 다른 곳은 여기에서 공식 문서에서 읽을 수 있습니다. - https://www.drupal.org/docs/7/api/batch-api/overview