1<?php
2
3namespace Drupal\config\Form;
4
5use Drupal\Core\Archiver\ArchiveTar;
6use Drupal\Core\Config\StorageInterface;
7use Drupal\Core\File\FileSystemInterface;
8use Drupal\Core\Form\FormBase;
9use Drupal\Core\Form\FormStateInterface;
10use Drupal\Core\Site\Settings;
11use Symfony\Component\DependencyInjection\ContainerInterface;
12
13/**
14 * Defines the configuration import form.
15 *
16 * @internal
17 */
18class ConfigImportForm extends FormBase {
19
20  /**
21   * The configuration storage.
22   *
23   * @var \Drupal\Core\Config\StorageInterface
24   */
25  protected $configStorage;
26
27  /**
28   * The file system service.
29   *
30   * @var \Drupal\Core\File\FileSystemInterface
31   */
32  protected $fileSystem;
33
34  /**
35   * The settings object.
36   *
37   * @var \Drupal\Core\Site\Settings
38   */
39  protected $settings;
40
41  /**
42   * Constructs a new ConfigImportForm.
43   *
44   * @param \Drupal\Core\Config\StorageInterface $config_storage
45   *   The configuration storage.
46   * @param \Drupal\Core\File\FileSystemInterface $file_system
47   *   The file system service.
48   * @param \Drupal\Core\Site\Settings $settings
49   *   The settings object.
50   */
51  public function __construct(StorageInterface $config_storage, FileSystemInterface $file_system, Settings $settings) {
52    $this->configStorage = $config_storage;
53    $this->fileSystem = $file_system;
54    $this->settings = $settings;
55  }
56
57  /**
58   * {@inheritdoc}
59   */
60  public static function create(ContainerInterface $container) {
61    return new static(
62      $container->get('config.storage.sync'),
63      $container->get('file_system'),
64      $container->get('settings')
65    );
66  }
67
68  /**
69   * {@inheritdoc}
70   */
71  public function getFormId() {
72    return 'config_import_form';
73  }
74
75  /**
76   * {@inheritdoc}
77   */
78  public function buildForm(array $form, FormStateInterface $form_state) {
79    $directory = $this->settings->get('config_sync_directory');
80    $directory_is_writable = is_writable($directory);
81    if (!$directory_is_writable) {
82      $this->messenger()->addError($this->t('The directory %directory is not writable.', ['%directory' => $directory]));
83    }
84    $form['import_tarball'] = [
85      '#type' => 'file',
86      '#title' => $this->t('Configuration archive'),
87      '#description' => $this->t('Allowed types: @extensions.', ['@extensions' => 'tar.gz tgz tar.bz2']),
88    ];
89
90    $form['submit'] = [
91      '#type' => 'submit',
92      '#value' => $this->t('Upload'),
93      '#disabled' => !$directory_is_writable,
94    ];
95    return $form;
96  }
97
98  /**
99   * {@inheritdoc}
100   */
101  public function validateForm(array &$form, FormStateInterface $form_state) {
102    $all_files = $this->getRequest()->files->get('files', []);
103    if (!empty($all_files['import_tarball'])) {
104      $file_upload = $all_files['import_tarball'];
105      if ($file_upload->isValid()) {
106        $form_state->setValue('import_tarball', $file_upload->getRealPath());
107        return;
108      }
109    }
110
111    $form_state->setErrorByName('import_tarball', $this->t('The file could not be uploaded.'));
112  }
113
114  /**
115   * {@inheritdoc}
116   */
117  public function submitForm(array &$form, FormStateInterface $form_state) {
118    if ($path = $form_state->getValue('import_tarball')) {
119      $this->configStorage->deleteAll();
120      try {
121        $archiver = new ArchiveTar($path, 'gz');
122        $files = [];
123        foreach ($archiver->listContent() as $file) {
124          $files[] = $file['filename'];
125        }
126        $archiver->extractList($files, $this->settings->get('config_sync_directory'), '', FALSE, FALSE);
127        $this->messenger()->addStatus($this->t('Your configuration files were successfully uploaded and are ready for import.'));
128        $form_state->setRedirect('config.sync');
129      }
130      catch (\Exception $e) {
131        $this->messenger()->addError($this->t('Could not extract the contents of the tar file. The error message is <em>@message</em>', ['@message' => $e->getMessage()]));
132      }
133      $this->fileSystem->unlink($path);
134    }
135  }
136
137}
138