Mercurial > hg > isophonics-drupal-site
comparison core/modules/update/update.authorize.inc @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | 129ea1e6d783 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
1 <?php | |
2 | |
3 /** | |
4 * @file | |
5 * Callbacks and related functions invoked by authorize.php to update projects. | |
6 * | |
7 * We use the Batch API to actually update each individual project on the site. | |
8 * All of the code in this file is run at a low bootstrap level (modules are not | |
9 * loaded), so these functions cannot assume access to the rest of the code of | |
10 * the Update Manager module. | |
11 */ | |
12 | |
13 use Drupal\Core\Updater\UpdaterException; | |
14 use Drupal\Core\Url; | |
15 | |
16 /** | |
17 * Updates existing projects when invoked by authorize.php. | |
18 * | |
19 * Callback for system_authorized_init() in | |
20 * update_manager_update_ready_form_submit(). | |
21 * | |
22 * @param $filetransfer | |
23 * The FileTransfer object created by authorize.php for use during this | |
24 * operation. | |
25 * @param $projects | |
26 * A nested array of projects to install into the live webroot, keyed by | |
27 * project name. Each subarray contains the following keys: | |
28 * - project: The canonical project short name. | |
29 * - updater_name: The name of the Drupal\Core\Updater\Updater class to use | |
30 * for this project. | |
31 * - local_url: The locally installed location of new code to update with. | |
32 * | |
33 * @return \Symfony\Component\HttpFoundation\Response|null | |
34 * The result of processing the batch that updates the projects. If this is | |
35 * an instance of \Symfony\Component\HttpFoundation\Response the calling code | |
36 * should use that response for the current page request. | |
37 */ | |
38 function update_authorize_run_update($filetransfer, $projects) { | |
39 $operations = []; | |
40 foreach ($projects as $project_info) { | |
41 $operations[] = [ | |
42 'update_authorize_batch_copy_project', | |
43 [ | |
44 $project_info['project'], | |
45 $project_info['updater_name'], | |
46 $project_info['local_url'], | |
47 $filetransfer, | |
48 ], | |
49 ]; | |
50 } | |
51 | |
52 $batch = [ | |
53 'init_message' => t('Preparing to update your site'), | |
54 'operations' => $operations, | |
55 'finished' => 'update_authorize_update_batch_finished', | |
56 'file' => drupal_get_path('module', 'update') . '/update.authorize.inc', | |
57 ]; | |
58 batch_set($batch); | |
59 | |
60 // Since authorize.php has its own method for setting the page title, set it | |
61 // manually here rather than passing it in to batch_set() as would normally | |
62 // be done. | |
63 $_SESSION['authorize_page_title'] = t('Installing updates'); | |
64 | |
65 // Invoke the batch via authorize.php. | |
66 return system_authorized_batch_process(); | |
67 } | |
68 | |
69 /** | |
70 * Installs a new project when invoked by authorize.php. | |
71 * | |
72 * Callback for system_authorized_init() in | |
73 * update_manager_install_form_submit(). | |
74 * | |
75 * @param FileTransfer $filetransfer | |
76 * The FileTransfer object created by authorize.php for use during this | |
77 * operation. | |
78 * @param string $project | |
79 * The canonical project short name; i.e., the name of the module, theme, or | |
80 * profile. | |
81 * @param string $updater_name | |
82 * The name of the Drupal\Core\Updater\Updater class to use for installing | |
83 * this project. | |
84 * @param string $local_url | |
85 * The URL to the locally installed temp directory where the project has | |
86 * already been downloaded and extracted into. | |
87 * | |
88 * @return \Symfony\Component\HttpFoundation\Response|null | |
89 * The result of processing the batch that installs the project. If this is | |
90 * an instance of \Symfony\Component\HttpFoundation\Response the calling code | |
91 * should use that response for the current page request. | |
92 */ | |
93 function update_authorize_run_install($filetransfer, $project, $updater_name, $local_url) { | |
94 $operations[] = [ | |
95 'update_authorize_batch_copy_project', | |
96 [ | |
97 $project, | |
98 $updater_name, | |
99 $local_url, | |
100 $filetransfer, | |
101 ], | |
102 ]; | |
103 | |
104 // @todo Instantiate our Updater to set the human-readable title? | |
105 $batch = [ | |
106 'init_message' => t('Preparing to install'), | |
107 'operations' => $operations, | |
108 // @todo Use a different finished callback for different messages? | |
109 'finished' => 'update_authorize_install_batch_finished', | |
110 'file' => drupal_get_path('module', 'update') . '/update.authorize.inc', | |
111 ]; | |
112 batch_set($batch); | |
113 | |
114 // Since authorize.php has its own method for setting the page title, set it | |
115 // manually here rather than passing it in to batch_set() as would normally | |
116 // be done. | |
117 $_SESSION['authorize_page_title'] = t('Installing %project', ['%project' => $project]); | |
118 | |
119 // Invoke the batch via authorize.php. | |
120 return system_authorized_batch_process(); | |
121 } | |
122 | |
123 /** | |
124 * Implements callback_batch_operation(). | |
125 * | |
126 * Copies project to its proper place when authorized to do so. | |
127 * | |
128 * @param string $project | |
129 * The canonical short name of the project being installed. | |
130 * @param string $updater_name | |
131 * The name of the Drupal\Core\Updater\Updater class to use for installing | |
132 * this project. | |
133 * @param string $local_url | |
134 * The URL to the locally installed temp directory where the project has | |
135 * already been downloaded and extracted into. | |
136 * @param FileTransfer $filetransfer | |
137 * The FileTransfer object to use for performing this operation. | |
138 * @param array $context | |
139 * Reference to an array used for Batch API storage. | |
140 */ | |
141 function update_authorize_batch_copy_project($project, $updater_name, $local_url, $filetransfer, &$context) { | |
142 | |
143 // Initialize some variables in the Batch API $context array. | |
144 if (!isset($context['results']['log'])) { | |
145 $context['results']['log'] = []; | |
146 } | |
147 if (!isset($context['results']['log'][$project])) { | |
148 $context['results']['log'][$project] = []; | |
149 } | |
150 | |
151 if (!isset($context['results']['tasks'])) { | |
152 $context['results']['tasks'] = []; | |
153 } | |
154 | |
155 // The batch API uses a session, and since all the arguments are serialized | |
156 // and unserialized between requests, although the FileTransfer object itself | |
157 // will be reconstructed, the connection pointer itself will be lost. However, | |
158 // the FileTransfer object will still have the connection variable, even | |
159 // though the connection itself is now gone. So, although it's ugly, we have | |
160 // to unset the connection variable at this point so that the FileTransfer | |
161 // object will re-initiate the actual connection. | |
162 unset($filetransfer->connection); | |
163 | |
164 if (!empty($context['results']['log'][$project]['#abort'])) { | |
165 $context['finished'] = 1; | |
166 return; | |
167 } | |
168 | |
169 $updater = new $updater_name($local_url, \Drupal::getContainer()->get('update.root')); | |
170 | |
171 try { | |
172 if ($updater->isInstalled()) { | |
173 // This is an update. | |
174 $tasks = $updater->update($filetransfer); | |
175 } | |
176 else { | |
177 $tasks = $updater->install($filetransfer); | |
178 } | |
179 } | |
180 catch (UpdaterException $e) { | |
181 _update_batch_create_message($context['results']['log'][$project], t('Error installing / updating'), FALSE); | |
182 _update_batch_create_message($context['results']['log'][$project], $e->getMessage(), FALSE); | |
183 $context['results']['log'][$project]['#abort'] = TRUE; | |
184 return; | |
185 } | |
186 | |
187 _update_batch_create_message($context['results']['log'][$project], t('Installed %project_name successfully', ['%project_name' => $project])); | |
188 if (!empty($tasks)) { | |
189 $context['results']['tasks'] += $tasks; | |
190 } | |
191 | |
192 // This particular operation is now complete, even though the batch might | |
193 // have other operations to perform. | |
194 $context['finished'] = 1; | |
195 } | |
196 | |
197 /** | |
198 * Batch callback: Performs actions when the authorized update batch is done. | |
199 * | |
200 * This processes the results and stashes them into SESSION such that | |
201 * authorize.php will render a report. Also responsible for putting the site | |
202 * back online and clearing the update status storage after a successful update. | |
203 * | |
204 * @param $success | |
205 * TRUE if the batch operation was successful; FALSE if there were errors. | |
206 * @param $results | |
207 * An associative array of results from the batch operation. | |
208 */ | |
209 function update_authorize_update_batch_finished($success, $results) { | |
210 foreach ($results['log'] as $messages) { | |
211 if (!empty($messages['#abort'])) { | |
212 $success = FALSE; | |
213 } | |
214 } | |
215 $offline = \Drupal::state()->get('system.maintenance_mode'); | |
216 if ($success) { | |
217 // Now that the update completed, we need to clear the available update data | |
218 // and recompute our status, so prevent show bogus results. | |
219 _update_authorize_clear_update_status(); | |
220 | |
221 // Take the site out of maintenance mode if it was previously that way. | |
222 if ($offline && isset($_SESSION['maintenance_mode']) && $_SESSION['maintenance_mode'] == FALSE) { | |
223 \Drupal::state()->set('system.maintenance_mode', FALSE); | |
224 $page_message = [ | |
225 'message' => t('Update was completed successfully. Your site has been taken out of maintenance mode.'), | |
226 'type' => 'status', | |
227 ]; | |
228 } | |
229 else { | |
230 $page_message = [ | |
231 'message' => t('Update was completed successfully.'), | |
232 'type' => 'status', | |
233 ]; | |
234 } | |
235 } | |
236 elseif (!$offline) { | |
237 $page_message = [ | |
238 'message' => t('Update failed! See the log below for more information.'), | |
239 'type' => 'error', | |
240 ]; | |
241 } | |
242 else { | |
243 $page_message = [ | |
244 'message' => t('Update failed! See the log below for more information. Your site is still in maintenance mode.'), | |
245 'type' => 'error', | |
246 ]; | |
247 } | |
248 // Since we're doing an update of existing code, always add a task for | |
249 // running update.php. | |
250 $url = Url::fromRoute('system.db_update'); | |
251 $results['tasks'][] = t('Your modules have been downloaded and updated.'); | |
252 $results['tasks'][] = [ | |
253 '#type' => 'link', | |
254 '#url' => $url, | |
255 '#title' => t('Run database updates'), | |
256 // Since this is being called outsite of the primary front controller, | |
257 // the base_url needs to be set explicitly to ensure that links are | |
258 // relative to the site root. | |
259 // @todo Simplify with https://www.drupal.org/node/2548095 | |
260 '#options' => [ | |
261 'absolute' => TRUE, | |
262 'base_url' => $GLOBALS['base_url'], | |
263 ], | |
264 '#access' => $url->access(\Drupal::currentUser()) | |
265 ]; | |
266 | |
267 // Unset the variable since it is no longer needed. | |
268 unset($_SESSION['maintenance_mode']); | |
269 | |
270 // Set all these values into the SESSION so authorize.php can display them. | |
271 $_SESSION['authorize_results']['success'] = $success; | |
272 $_SESSION['authorize_results']['page_message'] = $page_message; | |
273 $_SESSION['authorize_results']['messages'] = $results['log']; | |
274 $_SESSION['authorize_results']['tasks'] = $results['tasks']; | |
275 $_SESSION['authorize_page_title'] = t('Update manager'); | |
276 } | |
277 | |
278 /** | |
279 * Implements callback_batch_finished(). | |
280 * | |
281 * Performs actions when the authorized install batch is done. | |
282 * | |
283 * This processes the results and stashes them into SESSION such that | |
284 * authorize.php will render a report. Also responsible for putting the site | |
285 * back online after a successful install if necessary. | |
286 * | |
287 * @param $success | |
288 * TRUE if the batch operation was a success; FALSE if there were errors. | |
289 * @param $results | |
290 * An associative array of results from the batch operation. | |
291 */ | |
292 function update_authorize_install_batch_finished($success, $results) { | |
293 foreach ($results['log'] as $messages) { | |
294 if (!empty($messages['#abort'])) { | |
295 $success = FALSE; | |
296 } | |
297 } | |
298 $offline = \Drupal::state()->get('system.maintenance_mode'); | |
299 if ($success) { | |
300 // Take the site out of maintenance mode if it was previously that way. | |
301 if ($offline && isset($_SESSION['maintenance_mode']) && $_SESSION['maintenance_mode'] == FALSE) { | |
302 \Drupal::state()->set('system.maintenance_mode', FALSE); | |
303 $page_message = [ | |
304 'message' => t('Installation was completed successfully. Your site has been taken out of maintenance mode.'), | |
305 'type' => 'status', | |
306 ]; | |
307 } | |
308 else { | |
309 $page_message = [ | |
310 'message' => t('Installation was completed successfully.'), | |
311 'type' => 'status', | |
312 ]; | |
313 } | |
314 } | |
315 elseif (!$success && !$offline) { | |
316 $page_message = [ | |
317 'message' => t('Installation failed! See the log below for more information.'), | |
318 'type' => 'error', | |
319 ]; | |
320 } | |
321 else { | |
322 $page_message = [ | |
323 'message' => t('Installation failed! See the log below for more information. Your site is still in maintenance mode.'), | |
324 'type' => 'error', | |
325 ]; | |
326 } | |
327 | |
328 // Unset the variable since it is no longer needed. | |
329 unset($_SESSION['maintenance_mode']); | |
330 | |
331 // Set all these values into the SESSION so authorize.php can display them. | |
332 $_SESSION['authorize_results']['success'] = $success; | |
333 $_SESSION['authorize_results']['page_message'] = $page_message; | |
334 $_SESSION['authorize_results']['messages'] = $results['log']; | |
335 $_SESSION['authorize_results']['tasks'] = $results['tasks']; | |
336 $_SESSION['authorize_page_title'] = t('Update manager'); | |
337 } | |
338 | |
339 /** | |
340 * Creates a structure of log messages. | |
341 * | |
342 * @param array $project_results | |
343 * An associative array of results from the batch operation. | |
344 * @param string $message | |
345 * A string containing a log message. | |
346 * @param bool $success | |
347 * (optional) TRUE if the operation the message is about was a success, FALSE | |
348 * if there were errors. Defaults to TRUE. | |
349 */ | |
350 function _update_batch_create_message(&$project_results, $message, $success = TRUE) { | |
351 $project_results[] = ['message' => $message, 'success' => $success]; | |
352 } | |
353 | |
354 /** | |
355 * Clears available update status data. | |
356 * | |
357 * Since this function is run at such a low bootstrap level, the Update Manager | |
358 * module is not loaded. So, we can't just call update_storage_clear(). However, | |
359 * the key-value backend is available, so we just call that. | |
360 * | |
361 * Note that we do not want to delete items related to currently pending fetch | |
362 * attempts. | |
363 * | |
364 * @see update_authorize_update_batch_finished() | |
365 * @see update_storage_clear() | |
366 */ | |
367 function _update_authorize_clear_update_status() { | |
368 \Drupal::keyValueExpirable('update')->deleteAll(); | |
369 \Drupal::keyValueExpirable('update_available_release')->deleteAll(); | |
370 } |