Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
279 / 279 |
|
100.00% |
4 / 4 |
CRAP | n/a |
0 / 0 |
|
visitors_install | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
3 | |||
visitors_schema | |
100.00% |
213 / 213 |
|
100.00% |
1 / 1 |
1 | |||
visitors_requirements | |
100.00% |
14 / 14 |
|
100.00% |
1 / 1 |
3 | |||
visitors_update_30000 | |
100.00% |
41 / 41 |
|
100.00% |
1 / 1 |
9 |
1 | <?php |
2 | |
3 | /** |
4 | * @file |
5 | * Install/uninstall visitors module. |
6 | */ |
7 | |
8 | use Drupal\Component\Serialization\Yaml; |
9 | use Drupal\Core\Entity\EntityTypeInterface; |
10 | use Drupal\Core\Url; |
11 | |
12 | /** |
13 | * Implements hook_install(). |
14 | */ |
15 | function visitors_install($is_syncing) { |
16 | if ($is_syncing) { |
17 | return; |
18 | } |
19 | if (!\Drupal::moduleHandler()->moduleExists('statistics')) { |
20 | return; |
21 | } |
22 | $settings = \Drupal::service('config.factory')->getEditable('visitors.settings'); |
23 | $settings->set('counter.enabled', FALSE) |
24 | ->save(); |
25 | |
26 | \Drupal::messenger()->addWarning(t( |
27 | 'The Statistics module is installed. <a href="@url">Convert the Statistics node views</a> to Visitors page views.', |
28 | ['@url' => Url::fromRoute('visitors.statistics_migrate')->toString()] |
29 | )); |
30 | |
31 | } |
32 | |
33 | /** |
34 | * Implements hook_schema(). |
35 | */ |
36 | function visitors_schema() { |
37 | |
38 | $schema['visitors_visit'] = [ |
39 | 'fields' => [ |
40 | 'id' => [ |
41 | 'description' => 'Primary key', |
42 | 'type' => 'serial', |
43 | 'not null' => TRUE, |
44 | ], |
45 | 'visitor_id' => [ |
46 | 'description' => 'Unique id, provided by the visitor', |
47 | 'type' => 'varchar', |
48 | 'length' => 32, |
49 | 'not null' => FALSE, |
50 | 'default' => NULL, |
51 | ], |
52 | 'uid' => [ |
53 | 'description' => 'The user of the session', |
54 | 'type' => 'int', |
55 | 'not null' => FALSE, |
56 | ], |
57 | 'localtime' => [ |
58 | 'description' => 'Seconds since midnight, in the local of the visitor', |
59 | 'type' => 'int', |
60 | 'size' => 'medium', |
61 | 'not null' => FALSE, |
62 | 'default' => NULL, |
63 | ], |
64 | 'returning' => [ |
65 | 'description' => 'Is the visitor returning, or new', |
66 | 'type' => 'int', |
67 | 'size' => 'tiny', |
68 | ], |
69 | 'total_visits' => [ |
70 | 'description' => 'Total visits', |
71 | 'type' => 'int', |
72 | 'not null' => TRUE, |
73 | 'default' => 0, |
74 | ], |
75 | 'total_page_views' => [ |
76 | 'description' => 'Total page views this visit', |
77 | 'type' => 'int', |
78 | 'not null' => TRUE, |
79 | 'default' => 0, |
80 | ], |
81 | 'total_events' => [ |
82 | 'description' => 'Total events this visit', |
83 | 'type' => 'int', |
84 | 'not null' => TRUE, |
85 | 'default' => 0, |
86 | ], |
87 | 'entry' => [ |
88 | 'description' => 'First page view', |
89 | 'type' => 'int', |
90 | 'not null' => FALSE, |
91 | 'default' => NULL, |
92 | ], |
93 | 'entry_time' => [ |
94 | 'description' => 'The time the visit was started', |
95 | 'type' => 'int', |
96 | 'not null' => FALSE, |
97 | 'default' => NULL, |
98 | ], |
99 | 'exit' => [ |
100 | 'description' => 'Last page view', |
101 | 'type' => 'int', |
102 | 'not null' => FALSE, |
103 | 'default' => NULL, |
104 | ], |
105 | 'exit_time' => [ |
106 | 'description' => 'The time the visit was ended', |
107 | 'type' => 'int', |
108 | 'not null' => FALSE, |
109 | 'default' => NULL, |
110 | ], |
111 | 'total_time' => [ |
112 | 'description' => 'The total time of the visit', |
113 | 'type' => 'int', |
114 | 'not null' => FALSE, |
115 | 'default' => NULL, |
116 | ], |
117 | 'time_since_first' => [ |
118 | 'description' => 'Seconds since the visitor\'s first visit', |
119 | 'type' => 'int', |
120 | 'not null' => FALSE, |
121 | 'default' => NULL, |
122 | ], |
123 | 'time_since_last' => [ |
124 | 'description' => 'Seconds since the visitor\'s last visit', |
125 | 'type' => 'int', |
126 | 'not null' => FALSE, |
127 | 'default' => NULL, |
128 | ], |
129 | 'bot' => [ |
130 | 'description' => 'Is the visitor a bot', |
131 | 'type' => 'int', |
132 | 'size' => 'tiny', |
133 | 'not null' => FALSE, |
134 | 'default' => NULL, |
135 | ], |
136 | 'config_id' => [ |
137 | 'description' => 'The fingerprint id', |
138 | 'type' => 'varchar', |
139 | 'length' => 16, |
140 | 'not null' => TRUE, |
141 | ], |
142 | 'config_resolution' => [ |
143 | 'description' => 'The screen resolution', |
144 | 'type' => 'varchar', |
145 | 'length' => 18, |
146 | 'not null' => FALSE, |
147 | 'default' => NULL, |
148 | ], |
149 | 'config_pdf' => [ |
150 | 'description' => 'Has PDF support', |
151 | 'type' => 'int', |
152 | 'size' => 'tiny', |
153 | 'not null' => FALSE, |
154 | 'default' => NULL, |
155 | ], |
156 | 'config_flash' => [ |
157 | 'description' => 'Has Flash support', |
158 | 'type' => 'int', |
159 | 'size' => 'tiny', |
160 | 'not null' => FALSE, |
161 | 'default' => NULL, |
162 | ], |
163 | 'config_java' => [ |
164 | 'description' => 'Has Java support', |
165 | 'type' => 'int', |
166 | 'size' => 'tiny', |
167 | 'not null' => FALSE, |
168 | 'default' => NULL, |
169 | ], |
170 | 'config_quicktime' => [ |
171 | 'description' => 'Has Quicktime support', |
172 | 'type' => 'int', |
173 | 'size' => 'tiny', |
174 | 'not null' => FALSE, |
175 | 'default' => NULL, |
176 | ], |
177 | 'config_realplayer' => [ |
178 | 'description' => 'Has Realplayer support', |
179 | 'type' => 'int', |
180 | 'size' => 'tiny', |
181 | 'not null' => FALSE, |
182 | 'default' => NULL, |
183 | ], |
184 | 'config_windowsmedia' => [ |
185 | 'description' => 'Has Windows Media support', |
186 | 'type' => 'int', |
187 | 'size' => 'tiny', |
188 | 'not null' => FALSE, |
189 | 'default' => NULL, |
190 | ], |
191 | 'config_silverlight' => [ |
192 | 'description' => 'Has Silverlight support', |
193 | 'type' => 'int', |
194 | 'size' => 'tiny', |
195 | 'not null' => FALSE, |
196 | 'default' => NULL, |
197 | ], |
198 | 'config_cookie' => [ |
199 | 'description' => 'Has cookie support', |
200 | 'type' => 'int', |
201 | 'size' => 'tiny', |
202 | 'not null' => FALSE, |
203 | 'default' => NULL, |
204 | ], |
205 | 'config_browser_engine' => [ |
206 | 'description' => 'The browser engine', |
207 | 'type' => 'varchar', |
208 | 'length' => '10', |
209 | 'not null' => FALSE, |
210 | 'default' => NULL, |
211 | ], |
212 | 'config_browser_name' => [ |
213 | 'description' => 'The browser name', |
214 | 'type' => 'varchar', |
215 | 'length' => '2', |
216 | 'not null' => FALSE, |
217 | 'default' => NULL, |
218 | ], |
219 | 'config_browser_version' => [ |
220 | 'description' => 'The browser version', |
221 | 'type' => 'varchar', |
222 | 'length' => '20', |
223 | 'not null' => FALSE, |
224 | 'default' => NULL, |
225 | ], |
226 | 'config_client_type' => [ |
227 | 'description' => 'The client type', |
228 | 'type' => 'varchar', |
229 | 'length' => '100', |
230 | 'not null' => FALSE, |
231 | 'default' => NULL, |
232 | ], |
233 | 'config_device_brand' => [ |
234 | 'description' => 'The device brand', |
235 | 'type' => 'varchar', |
236 | 'length' => '100', |
237 | 'not null' => FALSE, |
238 | 'default' => NULL, |
239 | ], |
240 | 'config_device_model' => [ |
241 | 'description' => 'The device model', |
242 | 'type' => 'varchar', |
243 | 'length' => '100', |
244 | 'not null' => FALSE, |
245 | 'default' => NULL, |
246 | ], |
247 | 'config_device_type' => [ |
248 | 'description' => 'The device type', |
249 | 'type' => 'varchar', |
250 | 'length' => '100', |
251 | 'not null' => FALSE, |
252 | 'default' => NULL, |
253 | ], |
254 | 'config_os' => [ |
255 | 'description' => 'The operating system', |
256 | 'type' => 'varchar', |
257 | 'length' => '3', |
258 | 'not null' => FALSE, |
259 | 'default' => NULL, |
260 | ], |
261 | 'config_os_version' => [ |
262 | 'description' => 'The operating system version', |
263 | 'type' => 'varchar', |
264 | 'length' => '100', |
265 | 'not null' => FALSE, |
266 | 'default' => NULL, |
267 | ], |
268 | 'location_browser_lang' => [ |
269 | 'description' => 'The browser language', |
270 | 'type' => 'varchar', |
271 | 'length' => 20, |
272 | 'not null' => FALSE, |
273 | 'default' => NULL, |
274 | ], |
275 | 'location_ip' => [ |
276 | 'description' => 'The IP address', |
277 | 'type' => 'varchar', |
278 | 'length' => 45, |
279 | 'not null' => TRUE, |
280 | 'default' => '', |
281 | ], |
282 | 'location_continent' => [ |
283 | 'description' => 'The continent of the visitor', |
284 | 'type' => 'varchar', |
285 | 'length' => 2, |
286 | 'not null' => FALSE, |
287 | 'default' => '', |
288 | ], |
289 | 'location_country' => [ |
290 | 'description' => 'The country of the visitor', |
291 | 'type' => 'varchar', |
292 | 'length' => 2, |
293 | 'not null' => FALSE, |
294 | 'default' => '', |
295 | ], |
296 | 'location_region' => [ |
297 | 'description' => 'The region of the visitor', |
298 | 'type' => 'varchar', |
299 | 'length' => 128, |
300 | 'not null' => FALSE, |
301 | 'default' => '', |
302 | ], |
303 | 'location_city' => [ |
304 | 'description' => 'The city of the visitor', |
305 | 'type' => 'varchar', |
306 | 'length' => 128, |
307 | 'not null' => FALSE, |
308 | 'default' => '', |
309 | ], |
310 | 'location_latitude' => [ |
311 | 'description' => 'The latitude from the IP address', |
312 | 'type' => 'numeric', |
313 | 'precision' => 13, |
314 | 'scale' => 10, |
315 | 'default' => NULL, |
316 | ], |
317 | 'location_longitude' => [ |
318 | 'description' => 'The longitude from the IP address', |
319 | 'type' => 'numeric', |
320 | 'precision' => 13, |
321 | 'scale' => 10, |
322 | 'default' => NULL, |
323 | ], |
324 | 'referer_keyword' => [ |
325 | 'description' => 'The referer keyword', |
326 | 'type' => 'varchar', |
327 | 'length' => 255, |
328 | 'not null' => FALSE, |
329 | 'default' => NULL, |
330 | ], |
331 | 'referer_name' => [ |
332 | 'description' => 'The referer name', |
333 | 'type' => 'varchar', |
334 | 'length' => 255, |
335 | 'not null' => FALSE, |
336 | 'default' => NULL, |
337 | ], |
338 | 'referer_type' => [ |
339 | 'description' => 'The referer type', |
340 | 'type' => 'varchar', |
341 | 'length' => 32, |
342 | 'not null' => FALSE, |
343 | 'default' => NULL, |
344 | ], |
345 | 'referer_url' => [ |
346 | 'description' => 'The referer URL', |
347 | 'type' => 'varchar', |
348 | 'length' => 1500, |
349 | 'not null' => FALSE, |
350 | 'default' => NULL, |
351 | ], |
352 | ], |
353 | 'primary key' => ['id'], |
354 | 'indexes' => [ |
355 | 'visitor_id' => ['visitor_id'], |
356 | 'bot' => ['bot'], |
357 | 'exit_time' => ['exit_time'], |
358 | 'uid' => ['uid'], |
359 | ], |
360 | ]; |
361 | |
362 | $schema['visitors_event'] = [ |
363 | 'fields' => [ |
364 | 'id' => [ |
365 | 'description' => 'Primary key', |
366 | 'type' => 'serial', |
367 | 'not null' => TRUE, |
368 | ], |
369 | 'visit_id' => [ |
370 | 'description' => 'The visitors_visit id', |
371 | 'type' => 'int', |
372 | ], |
373 | 'page_view' => [ |
374 | 'description' => 'The unique page view id', |
375 | 'type' => 'varchar', |
376 | 'length' => 32, |
377 | 'not null' => FALSE, |
378 | 'default' => NULL, |
379 | ], |
380 | 'plugin' => [ |
381 | 'description' => 'The plugin that generated the event', |
382 | 'type' => 'varchar', |
383 | 'length' => 255, |
384 | 'not null' => FALSE, |
385 | 'default' => NULL, |
386 | ], |
387 | 'event' => [ |
388 | 'description' => 'The event', |
389 | 'type' => 'varchar', |
390 | 'length' => 255, |
391 | 'not null' => FALSE, |
392 | 'default' => NULL, |
393 | ], |
394 | 'plugin_int_1' => [ |
395 | 'description' => 'The first event int variable', |
396 | 'type' => 'int', |
397 | 'not null' => FALSE, |
398 | 'default' => NULL, |
399 | ], |
400 | 'plugin_int_2' => [ |
401 | 'description' => 'The second event int variable', |
402 | 'type' => 'int', |
403 | 'not null' => FALSE, |
404 | 'default' => NULL, |
405 | ], |
406 | 'plugin_var_1' => [ |
407 | 'description' => 'The first event varchar variable', |
408 | 'type' => 'varchar', |
409 | 'length' => 255, |
410 | 'not null' => FALSE, |
411 | 'default' => NULL, |
412 | ], |
413 | 'plugin_var_2' => [ |
414 | 'description' => 'The second event varchar variable', |
415 | 'type' => 'varchar', |
416 | 'length' => 255, |
417 | 'not null' => FALSE, |
418 | 'default' => NULL, |
419 | ], |
420 | 'plugin_var_3' => [ |
421 | 'description' => 'The third event varchar variable', |
422 | 'type' => 'varchar', |
423 | 'length' => 255, |
424 | 'not null' => FALSE, |
425 | 'default' => NULL, |
426 | ], |
427 | 'plugin_var_4' => [ |
428 | 'description' => 'The fourth event varchar variable', |
429 | 'type' => 'varchar', |
430 | 'length' => 255, |
431 | 'not null' => FALSE, |
432 | 'default' => NULL, |
433 | ], |
434 | 'title' => [ |
435 | 'description' => 'The page title', |
436 | 'type' => 'text', |
437 | 'not null' => TRUE, |
438 | ], |
439 | 'uid' => [ |
440 | 'description' => 'The user who viewed the page', |
441 | 'type' => 'int', |
442 | ], |
443 | 'url_prefix' => [ |
444 | 'description' => 'The protocol and if started with www', |
445 | 'type' => 'int', |
446 | 'size' => 'small', |
447 | ], |
448 | 'url' => [ |
449 | 'description' => 'The page URL', |
450 | 'type' => 'text', |
451 | 'not null' => TRUE, |
452 | ], |
453 | 'path' => [ |
454 | 'description' => 'The Drupal path', |
455 | 'type' => 'varchar', |
456 | 'length' => 255, |
457 | 'not null' => TRUE, |
458 | 'default' => '', |
459 | ], |
460 | 'route' => [ |
461 | 'description' => 'The Drupal route name', |
462 | 'type' => 'varchar', |
463 | 'length' => 255, |
464 | 'not null' => TRUE, |
465 | 'default' => '', |
466 | ], |
467 | 'referrer_url' => [ |
468 | 'description' => 'The referrer URL', |
469 | 'type' => 'text', |
470 | 'not null' => TRUE, |
471 | ], |
472 | 'server' => [ |
473 | 'description' => 'The server that generated the response', |
474 | 'type' => 'varchar', |
475 | 'length' => 255, |
476 | 'not null' => FALSE, |
477 | 'default' => NULL, |
478 | ], |
479 | 'pf_network' => [ |
480 | 'description' => 'Network performance', |
481 | 'type' => 'int', |
482 | 'not null' => FALSE, |
483 | 'default' => NULL, |
484 | ], |
485 | 'pf_server' => [ |
486 | 'description' => 'Server performance', |
487 | 'type' => 'int', |
488 | 'not null' => FALSE, |
489 | 'default' => NULL, |
490 | ], |
491 | 'pf_transfer' => [ |
492 | 'description' => 'Transfer performance', |
493 | 'type' => 'int', |
494 | 'not null' => FALSE, |
495 | 'default' => NULL, |
496 | ], |
497 | 'pf_dom_processing' => [ |
498 | 'description' => 'DOM processing performance', |
499 | 'type' => 'int', |
500 | 'not null' => FALSE, |
501 | 'default' => NULL, |
502 | ], |
503 | 'pf_dom_complete' => [ |
504 | 'description' => 'DOM complete performance', |
505 | 'type' => 'int', |
506 | 'not null' => FALSE, |
507 | 'default' => NULL, |
508 | ], |
509 | 'pf_on_load' => [ |
510 | 'description' => 'On load performance', |
511 | 'type' => 'int', |
512 | 'not null' => FALSE, |
513 | 'default' => NULL, |
514 | ], |
515 | 'pf_total' => [ |
516 | 'description' => 'Total performance', |
517 | 'type' => 'int', |
518 | 'not null' => FALSE, |
519 | 'default' => NULL, |
520 | ], |
521 | 'created' => [ |
522 | 'description' => 'The time the request was made', |
523 | 'type' => 'int', |
524 | ], |
525 | ], |
526 | 'primary key' => ['id'], |
527 | 'indexes' => [ |
528 | 'visit_id' => ['visit_id'], |
529 | 'created' => ['created'], |
530 | ], |
531 | ]; |
532 | |
533 | $schema['visitors_counter'] = [ |
534 | 'fields' => [ |
535 | 'entity_id' => [ |
536 | 'description' => 'The entity id for these visits.', |
537 | 'type' => 'int', |
538 | 'unsigned' => TRUE, |
539 | 'not null' => TRUE, |
540 | 'default' => 0, |
541 | ], |
542 | 'entity_type' => [ |
543 | 'type' => 'varchar_ascii', |
544 | 'not null' => TRUE, |
545 | 'default' => 'node', |
546 | 'length' => EntityTypeInterface::ID_MAX_LENGTH, |
547 | 'description' => 'The entity_type of the entity for these visits.', |
548 | ], |
549 | 'total' => [ |
550 | 'description' => 'The total number of times the entity has been viewed.', |
551 | 'type' => 'int', |
552 | 'unsigned' => TRUE, |
553 | 'not null' => TRUE, |
554 | 'default' => 0, |
555 | 'size' => 'big', |
556 | ], |
557 | 'today' => [ |
558 | 'description' => 'The total number of times the entity has been viewed today.', |
559 | 'type' => 'int', |
560 | 'unsigned' => TRUE, |
561 | 'not null' => TRUE, |
562 | 'default' => 0, |
563 | 'size' => 'medium', |
564 | ], |
565 | 'timestamp' => [ |
566 | 'description' => 'The most recent time the entity has been viewed.', |
567 | 'type' => 'int', |
568 | 'unsigned' => TRUE, |
569 | 'not null' => TRUE, |
570 | 'default' => 0, |
571 | ], |
572 | ], |
573 | 'primary key' => ['entity_type', 'entity_id'], |
574 | ]; |
575 | |
576 | return $schema; |
577 | } |
578 | |
579 | /** |
580 | * Implements hook_requirements(). |
581 | */ |
582 | function visitors_requirements($phase) { |
583 | $requirements = []; |
584 | if ($phase != 'runtime') { |
585 | return $requirements; |
586 | } |
587 | $device = \Drupal::service('visitors.device'); |
588 | if (!$device->hasLibrary()) { |
589 | $requirements['visitors_device'] = [ |
590 | 'title' => t('Device Detector'), |
591 | 'value' => t('Not found'), |
592 | 'severity' => REQUIREMENT_WARNING, |
593 | 'description' => t('The <a href=":url">Device Detector</a> library is strongly encouraged by the Visitors module. Composer will download the library automatically.', [ |
594 | ':url' => 'https://github.com/matomo-org/device-detector', |
595 | ]), |
596 | ]; |
597 | } |
598 | |
599 | return $requirements; |
600 | } |
601 | |
602 | /** |
603 | * Upgrade to Visitors 3. |
604 | */ |
605 | function visitors_update_30000(&$sandbox) { |
606 | |
607 | if (!isset($sandbox['current'])) { |
608 | $sandbox['current'] = 0; |
609 | $sandbox['max'] = 4; |
610 | } |
611 | |
612 | // Change visitors.settings to visitors.settings. |
613 | if ($sandbox['current'] == 0) { |
614 | $config_factory = \Drupal::configFactory(); |
615 | |
616 | $config = $config_factory->getEditable('visitors.config'); |
617 | $config_data = $config->getRawData(); |
618 | |
619 | $settings = $config_factory->getEditable('visitors.settings'); |
620 | $settings->setData($config_data)->save(); |
621 | |
622 | $config->delete(); |
623 | } |
624 | |
625 | if ($sandbox['current'] == 1) { |
626 | $schema = \Drupal::database()->schema(); |
627 | // @todo replace visitors_schema() with static before an initial release. |
628 | $visitors_schema = visitors_schema(); |
629 | $schema->createTable('visitors_visit', $visitors_schema['visitors_visit']); |
630 | $schema->createTable('visitors_event', $visitors_schema['visitors_event']); |
631 | } |
632 | |
633 | if ($sandbox['current'] == 2) { |
634 | $config_factory = \Drupal::configFactory(); |
635 | |
636 | // @todo This needs to be replace with static before an initial release. |
637 | $view = file_get_contents(__DIR__ . '/config/optional/views.view.visitors.yml'); |
638 | $config_data = Yaml::decode($view); |
639 | $config_factory->getEditable('views.view.visitors')->setData($config_data)->save(); |
640 | |
641 | // @todo This needs to be replace with static before an initial release. |
642 | $spam = file_get_contents(__DIR__ . '/config/install/visitors.spam.yml'); |
643 | $config_data = Yaml::decode($spam); |
644 | $config_factory->getEditable('visitors.spam')->setData($config_data)->save(); |
645 | |
646 | // @todo This needs to be replace with static before an initial release. |
647 | $ai_assistants = file_get_contents(__DIR__ . '/config/install/visitors.ai_assistants.yml'); |
648 | $config_data = Yaml::decode($ai_assistants); |
649 | $config_factory->getEditable('visitors.ai_assistants')->setData($config_data)->save(); |
650 | |
651 | // @todo This needs to be replace with static before an initial release. |
652 | $search_engine = file_get_contents(__DIR__ . '/config/install/visitors.search_engines.yml'); |
653 | $config_data = Yaml::decode($search_engine); |
654 | $config_factory->getEditable('visitors.search_engine')->setData($config_data)->save(); |
655 | |
656 | // @todo This needs to be replace with static before an initial release. |
657 | $social_networks = file_get_contents(__DIR__ . '/config/install/visitors.social_networks.yml'); |
658 | $config_data = Yaml::decode($social_networks); |
659 | $config_factory->getEditable('visitors.social_networks')->setData($config_data)->save(); |
660 | |
661 | // Check if views 'views.view.visitors_geoip' exists, and delete it. |
662 | $geoip_view = $config_factory->getEditable('views.view.visitors_geoip'); |
663 | if ($geoip_view) { |
664 | $geoip_view->delete(); |
665 | } |
666 | |
667 | } |
668 | |
669 | if ($sandbox['current'] == 3) { |
670 | $visitors_geoip_is_installed = \Drupal::moduleHandler()->moduleExists('visitors_geoip'); |
671 | if ($visitors_geoip_is_installed) { |
672 | \Drupal::service('module_installer')->uninstall(['visitors_geoip']); |
673 | } |
674 | } |
675 | |
676 | $sandbox['current'] += 1; |
677 | |
678 | $sandbox['#finished'] = ($sandbox['max'] == $sandbox['current']) ? 1 : $sandbox['current'] / $sandbox['max']; |
679 | } |