Version 1
[yaffs-website] / web / themes / contrib / bootstrap / src / Plugin / Setting / Schemas.php
1 <?php
2 /**
3  * @file
4  * Contains \Drupal\bootstrap\Plugin\Setting\Schemas.
5  */
6
7 namespace Drupal\bootstrap\Plugin\Setting;
8
9 use Drupal\bootstrap\Annotation\BootstrapSetting;
10 use Drupal\bootstrap\Bootstrap;
11 use Drupal\bootstrap\Plugin\Form\SystemThemeSettings;
12 use Drupal\bootstrap\Utility\Element;
13 use Drupal\Component\Render\FormattableMarkup;
14 use Drupal\Core\Form\FormStateInterface;
15
16 /**
17  * The "schemas" theme setting.
18  *
19  * @ingroup plugins_setting
20  * @ingroup plugins_update
21  *
22  * @BootstrapSetting(
23  *   id = "schemas",
24  *   type = "hidden",
25  *   weight = -20,
26  *   groups = false,
27  * )
28  */
29 class Schemas extends SettingBase {
30
31   /**
32    * {@inheritdoc}
33    */
34   public function alterFormElement(Element $form, FormStateInterface $form_state, $form_id = NULL) {
35     parent::alterFormElement($form, $form_state, $form_id);
36
37     $updates = [];
38     foreach ($this->theme->getPendingUpdates() as $version => $update) {
39       $row = [];
40       $row[] = $update->getSchema();
41       $row[] = new FormattableMarkup('<strong>@title</strong><p class="help-block">@description</p>', [
42         '@title' => $update->getLabel(),
43         '@description' => $update->getDescription(),
44       ]);
45       $row[] = $update->getTheme()->getTitle();
46       $updates[] = [
47         'class' => [$update->getSeverity() ?: 'default'],
48         'data' => $row,
49       ];
50     }
51
52     $form['update'] = [
53       '#type' => 'details',
54       '#title' => $this->t('Theme Updates'),
55       '#panel_type' => !!$updates ? 'primary' : 'default',
56       '#open' => !!$updates,
57       '#weight' => -20,
58     ];
59
60     $form['update']['table'] = [
61       '#type' => 'table',
62       '#header' => [t('Schema'), t('Description'), t('Provider')],
63       '#empty' => t('There are currently no pending updates for this theme.'),
64       '#rows' => $updates,
65     ];
66
67     if ($updates) {
68       $form['update']['actions'] = ['#type' => 'actions'];
69       $form['update']['actions']['update'] = [
70         '#type' => 'submit',
71         '#value' => t('Update theme'),
72         '#icon' => Bootstrap::glyphicon('open'),
73         // @todo Setting a class like this is undesirable, create a suggestion.
74         '#attributes' => [
75           'class' => ['btn-primary'],
76         ],
77         '#submit' => [[get_class($this), 'updateTheme']],
78       ];
79     }
80   }
81
82   /**
83    * Callback for updating a theme.
84    *
85    * @param array $form
86    *   Nested array of form elements that comprise the form.
87    * @param \Drupal\Core\Form\FormStateInterface $form_state
88    *   The current state of the form.
89    */
90   public static function updateTheme(array $form, FormStateInterface $form_state) {
91     if ($theme = SystemThemeSettings::getTheme($form, $form_state)) {
92       // Due to the fact that the batch API stores it's arguments in DB storage,
93       // theme based objects cannot be passed as an operation argument here.
94       // During _batch_page(), the DB item will attempt to restore the arguments
95       // using unserialize() and the autoload fix include added below may not
96       // yet have been invoked to register the theme namespaces. So instead,
97       // we capture the relevant information needed to reconstruct these objects
98       // in the batch processing callback.
99       $theme_name = $theme->getName();
100
101       // Create an operation for each update.
102       $operations = [];
103       foreach ($theme->getPendingUpdates() as $update) {
104         $operations[] = [[__CLASS__, 'batchProcessUpdate'], [$theme_name, $update->getProvider() . ':' . $update->getSchema()]];
105       }
106
107       if ($operations) {
108         $variables = ['@theme_title' => $theme->getTitle()];
109         batch_set([
110           'operations' => $operations,
111           'finished' => [__CLASS__, 'batchFinished'],
112           'title' => t('Updating @theme_title', $variables),
113           'init_message' => \Drupal::translation()->formatPlural(count($operations), 'Initializing 1 theme update for @theme_title...', 'Initializing @count theme updates for @theme_title...', $variables),
114           'progress_message' => t('Processing update @current of @total...', $variables),
115           'error_message' => t('An error was encountered while attempting to update the @theme_title theme.', $variables),
116           'file' => Bootstrap::autoloadFixInclude(),
117         ]);
118       }
119     }
120   }
121
122   /**
123    * Processes an update in a batch operation.
124    *
125    * @param string $theme_name
126    *  The machine name of the theme this update is being applied to.
127    * @param string $update_id
128    *   The combined identifier of the update being applied, e.g.
129    *   provider:schema.
130    * @param array $context
131    *   The batch context.
132    */
133   public static function batchProcessUpdate($theme_name, $update_id, array &$context) {
134     // Reconstruct the theme object this update is being applied to.
135     $theme = Bootstrap::getTheme($theme_name);
136
137     // Reconstruct the update plugin that is being applied.
138     list($provider, $plugin_id) = explode(':', $update_id);
139     $provider = Bootstrap::getTheme($provider);
140
141     /** @type \Drupal\bootstrap\Plugin\Update\UpdateInterface $update */
142     $update = $provider->getUpdateManager()->createInstance($plugin_id, ['theme' => $provider]);
143
144     // Initialize results with theme name and installed schemas.
145     if (!isset($context['results']['theme_name'])) {
146       $context['results']['theme_name'] = $theme_name;
147     }
148     if (!isset($context['results']['schemas'])) {
149       $context['results']['schemas'] = $theme->getSetting('schemas', []);
150     }
151
152     $schemas = &$context['results']['schemas'];
153
154     $variables = [
155       '@theme' => $update->getTheme()->getName(),
156       '@schema' => $update->getSchema(),
157       '@label' => $update->getLabel(),
158     ];
159
160     // Perform the update.
161     try {
162       // Attempt to perform the update.
163       if ($update->update($theme, $context) === FALSE) {
164         throw new \Exception(t('Update failed'));
165       }
166
167       // Store the results.
168       $schemas[$update->getTheme()->getName()] = $update->getSchema();
169
170       $context['results']['success'][] = t('<strong>[@theme][@schema] @label</strong>', $variables);
171     }
172       // Capture any errors.
173     catch (\Exception $e) {
174       $variables['@message'] = $e->getMessage();
175       $context['results']['errors'][] = t('<strong>[@theme][@schema] @label</strong> - @message', $variables);
176     }
177   }
178
179   /**
180    * Batch 'finished' callback
181    *
182    * @param bool $success
183    *   A boolean indicating whether the batch has completed successfully.
184    * @param array $results
185    *   The value(s) set in $context['results'] in
186    *   \Drupal\bootstrap\Plugin\Setting\Update::batchProcess().
187    * @param $operations
188    *   If $success is FALSE, contains the operations that remained unprocessed.
189    */
190   public static function batchFinished($success, $results, $operations) {
191     /** @type \Drupal\bootstrap\Theme $theme */
192     // Reconstruct the theme object this update is being applied to.
193     $theme = Bootstrap::getTheme($results['theme_name']);
194
195     // Save the current state of the installed schemas.
196     $theme->setSetting('schemas', $results['schemas']);
197
198     // Show successful updates.
199     if (!empty($results['success'])) {
200       $list = Element::createStandalone([
201         '#theme' => 'item_list__theme_update',
202         '#items' => $results['success'],
203         '#context' => ['type' => 'success'],
204       ]);
205       drupal_set_message(new FormattableMarkup('@message' . $list->renderPlain(), [
206         '@message' => t('Successfully completed the following theme updates:'),
207       ]));
208     }
209
210     // Show failed errors.
211     if (!empty($results['errors'])) {
212       $list = Element::createStandalone([
213         '#theme' => 'item_list__theme_update',
214         '#items' => $results['errors'],
215         '#context' => ['type' => 'errors'],
216       ]);
217       drupal_set_message(new FormattableMarkup('@message' . $list->renderPlain(), [
218         '@message' => t('The following theme updates could not be completed:'),
219       ]), 'error');
220     }
221   }
222
223 }