/** * Returns the help associated with the active menu item. * * @param \Symfony\Component\HttpFoundation\Request $request * The current request. */ protected function getActiveHelp(Request $request) { // Do not show on a 403 or 404 page. if ($request->attributes->has('exception')) { return ''; } $help = $this->moduleHandler->invokeAll('help', array($this->routeMatch->getRouteName(), $this->routeMatch)); return $help ? implode("\n", $help) : ''; }
/** * Builds up all element information. */ protected function buildInfo() { $info = $this->moduleHandler->invokeAll('element_info'); foreach ($info as $element_type => $element) { $info[$element_type]['#type'] = $element_type; } // Allow modules to alter the element type defaults. $this->moduleHandler->alter('element_info', $info); return $info; }
/** * {@inheritdoc} */ public function onBundleDelete($bundle, $entity_type_id) { $this->entityTypeBundleInfo->clearCachedBundles(); // Notify the entity storage. $storage = $this->entityTypeManager->getStorage($entity_type_id); if ($storage instanceof EntityBundleListenerInterface) { $storage->onBundleDelete($bundle, $entity_type_id); } // Invoke hook_entity_bundle_delete() hook. $this->moduleHandler->invokeAll('entity_bundle_delete', [$entity_type_id, $bundle]); $this->entityFieldManager->clearCachedFieldDefinitions(); }
/** * {@inheritdoc} */ public function build() { // Do not show on a 403 or 404 page. if ($this->request->attributes->has('exception')) { return []; } $help = $this->moduleHandler->invokeAll('help', array($this->routeMatch->getRouteName(), $this->routeMatch)); $build = []; // Remove any empty strings from $help. foreach (array_filter($help) as $item) { // Convert strings to #markup render arrays so that they will XSS admin // filtered. $build[] = is_array($item) ? $item : ['#markup' => $item]; } return $build; }
/** * Gathers ranking definitions from hook_ranking(). * * @return array * An array of ranking definitions. */ protected function getRankings() { if (!$this->rankings) { $this->rankings = $this->moduleHandler->invokeAll('ranking'); } return $this->rankings; }
/** * Processes cron queues. */ protected function processQueues() { // Grab the defined cron queues. $queues = $this->moduleHandler->invokeAll('queue_info'); $this->moduleHandler->alter('queue_info', $queues); foreach ($queues as $queue_name => $info) { if (isset($info['cron'])) { // Make sure every queue exists. There is no harm in trying to recreate // an existing queue. $this->queueFactory->get($queue_name)->createQueue(); $callback = $info['worker callback']; $end = time() + (isset($info['cron']['time']) ? $info['cron']['time'] : 15); $queue = $this->queueFactory->get($queue_name); while (time() < $end && ($item = $queue->claimItem())) { try { call_user_func_array($callback, array($item->data)); $queue->deleteItem($item); } catch (SuspendQueueException $e) { // If the worker indicates there is a problem with the whole queue, // release the item and skip to the next queue. $queue->releaseItem($item); watchdog_exception('cron', $e); // Skip to the next queue. continue 2; } catch (\Exception $e) { // In case of any other kind of exception, log it and leave the item // in the queue to be processed again later. watchdog_exception('cron', $e); } } } } }
/** * {@inheritdoc} */ public function addFromEntity(NodeInterface $node) { // Loop for handling the multi-Newsletter options. foreach ($node->simplenews_issue as $simplenews_issue) { $newsletter = $simplenews_issue->entity; $handler = $simplenews_issue->handler; $handler_settings = $simplenews_issue->handler_settings; $recipient_handler = simplenews_get_recipient_handler($newsletter, $handler, $handler_settings); // To send the newsletter, the node id and target email addresses. // are stored in the spool. // Only subscribed recipients are stored in the spool (status = 1). $select = $recipient_handler->buildRecipientQuery(); $select->addExpression('\'node\'', 'entity_type'); $select->addExpression($node->id(), 'entity_id'); $select->addExpression(SIMPLENEWS_SUBSCRIPTION_STATUS_SUBSCRIBED, 'status'); $select->addExpression(REQUEST_TIME, 'timestamp'); $select->condition('s.id', db_select('simplenews_mail_spool', 'r')->fields('r', array('snid'))->condition('entity_id', $node->id(), '='), 'NOT IN'); $simplenews_issue->subscribers = simplenews_count_subscriptions($simplenews_issue->target_id); $this->connection->insert('simplenews_mail_spool')->from($select)->execute(); // Update simplenews newsletter status to send pending. $simplenews_issue->status = SIMPLENEWS_STATUS_SEND_PENDING; // Notify other modules that a newsletter was just spooled. $this->moduleHandler->invokeAll('simplenews_spooled', array($node)); } }
/** * Tests the getAllBundleInfo() method. * * @covers ::getAllBundleInfo */ public function testGetAllBundleInfo() { $this->moduleHandler->invokeAll('entity_bundle_info')->willReturn([]); $this->moduleHandler->alter('entity_bundle_info', Argument::type('array'))->willReturn(NULL); $apple = $this->prophesize(EntityTypeInterface::class); $apple->getLabel()->willReturn('Apple'); $apple->getBundleOf()->willReturn(NULL); $banana = $this->prophesize(EntityTypeInterface::class); $banana->getLabel()->willReturn('Banana'); $banana->getBundleOf()->willReturn(NULL); $this->setUpEntityTypeDefinitions(['apple' => $apple, 'banana' => $banana]); $this->cacheBackend->get('entity_bundle_info:en')->willReturn(FALSE); $this->cacheBackend->set('entity_bundle_info:en', Argument::any(), Cache::PERMANENT, ['entity_types', 'entity_bundles'])->will(function () { $this->get('entity_bundle_info:en')->willReturn((object) ['data' => 'cached data'])->shouldBeCalled(); })->shouldBeCalled(); $this->cacheTagsInvalidator->invalidateTags(['entity_bundles'])->shouldBeCalled(); $this->typedDataManager->clearCachedDefinitions()->shouldBeCalled(); $expected = ['apple' => ['apple' => ['label' => 'Apple']], 'banana' => ['banana' => ['label' => 'Banana']]]; $bundle_info = $this->entityTypeBundleInfo->getAllBundleInfo(); $this->assertSame($expected, $bundle_info); $bundle_info = $this->entityTypeBundleInfo->getAllBundleInfo(); $this->assertSame($expected, $bundle_info); $this->entityTypeBundleInfo->clearCachedBundles(); $bundle_info = $this->entityTypeBundleInfo->getAllBundleInfo(); $this->assertSame('cached data', $bundle_info); }
/** * {@inheritdoc} */ public function save(array $link) { $link += array('access' => 1, 'status' => 1, 'status_override' => 0, 'lastmod' => 0, 'priority' => XMLSITEMAP_PRIORITY_DEFAULT, 'priority_override' => 0, 'changefreq' => 0, 'changecount' => 0, 'language' => LanguageInterface::LANGCODE_NOT_SPECIFIED); // Allow other modules to alter the link before saving. $this->moduleHandler->alter('xmlsitemap_link', $link); // Temporary validation checks. // @todo Remove in final? if ($link['priority'] < 0 || $link['priority'] > 1) { trigger_error(t('Invalid sitemap link priority %priority.<br />@link', array('%priority' => $link['priority'], '@link' => var_export($link, TRUE))), E_USER_ERROR); } if ($link['changecount'] < 0) { trigger_error(t('Negative changecount value. Please report this to <a href="@516928">@516928</a>.<br />@link', array('@516928' => 'http://drupal.org/node/516928', '@link' => var_export($link, TRUE))), E_USER_ERROR); $link['changecount'] = 0; } // Check if this is a changed link and set the regenerate flag if necessary. if (!$this->state->get('xmlsitemap_regenerate_needed')) { $this->checkChangedLink($link, NULL, TRUE); } $queryStatus = \Drupal::database()->merge('xmlsitemap')->key(array('type' => $link['type'], 'id' => $link['id']))->fields(array('loc' => $link['loc'], 'subtype' => $link['subtype'], 'access' => $link['access'], 'status' => $link['status'], 'status_override' => $link['status_override'], 'lastmod' => $link['lastmod'], 'priority' => $link['priority'], 'priority_override' => $link['priority_override'], 'changefreq' => $link['changefreq'], 'changecount' => $link['changecount'], 'language' => $link['language']))->execute(); switch ($queryStatus) { case Merge::STATUS_INSERT: $this->moduleHandler->invokeAll('xmlsitemap_link_insert', array($link)); break; case Merge::STATUS_UPDATE: $this->moduleHandler->invokeAll('xmlsitemap_link_update', array($link)); break; } return $link; }
/** * {@inheritdoc} */ public function delete($conditions) { if (!$conditions) { return; } $path = $this->load($conditions); $query = $this->db->delete('url_alias'); foreach ($conditions as $field => $value) { if ($field == 'source' || $field == 'alias') { // Use LIKE for case-insensitive matching (still stupid). $query->condition($field, $this->db->escapeLike($value), 'LIKE'); } else { if ('langcode' === $field) { // Drupal 7 compat $field = 'language'; } $query->condition($field, $value); } } $deleted = $query->execute(); // @todo Switch to using an event for this instead of a hook. $this->moduleHandler->invokeAll('path_delete', [$path]); \Drupal::service('path.alias_manager')->cacheClear(); return $deleted; }
/** * {@inheritdoc} */ public function getAllBundleInfo() { if (empty($this->bundleInfo)) { $langcode = $this->languageManager->getCurrentLanguage()->getId(); if ($cache = $this->cacheGet("entity_bundle_info:{$langcode}")) { $this->bundleInfo = $cache->data; } else { $this->bundleInfo = $this->moduleHandler->invokeAll('entity_bundle_info'); foreach ($this->entityTypeManager->getDefinitions() as $type => $entity_type) { // First look for entity types that act as bundles for others, load them // and add them as bundles. if ($bundle_entity_type = $entity_type->getBundleEntityType()) { foreach ($this->entityTypeManager->getStorage($bundle_entity_type)->loadMultiple() as $entity) { $this->bundleInfo[$type][$entity->id()]['label'] = $entity->label(); } } elseif (!isset($this->bundleInfo[$type])) { $this->bundleInfo[$type][$type]['label'] = $entity_type->getLabel(); } } $this->moduleHandler->alter('entity_bundle_info', $this->bundleInfo); $this->cacheSet("entity_bundle_info:{$langcode}", $this->bundleInfo, Cache::PERMANENT, ['entity_types', 'entity_bundles']); } } return $this->bundleInfo; }
/** * {@inheritdoc} */ public function getDefinedLanguageTypesInfo() { if (!isset($this->languageTypesInfo)) { $info = $this->moduleHandler->invokeAll('language_types_info'); // Let other modules alter the list of language types. $this->moduleHandler->alter('language_types_info', $info); $this->languageTypesInfo = $info; } return $this->languageTypesInfo; }
/** * {@inheritdoc} */ public function delete($conditions) { $path = $this->load($conditions); $query = $this->connection->delete('url_alias'); foreach ($conditions as $field => $value) { $query->condition($field, $value); } $deleted = $query->execute(); // @todo Switch to using an event for this instead of a hook. $this->moduleHandler->invokeAll('path_delete', array($path)); return $deleted; }
/** * {@inheritdoc} */ public function submitForm(array &$form, array &$form_state) { foreach ($this->mapper->getConfigNames() as $name) { $this->languageManager->getLanguageConfigOverride($this->language->id, $name)->delete(); } // Flush all persistent caches. $this->moduleHandler->invokeAll('cache_flush'); foreach (Cache::getBins() as $service_id => $cache_backend) { $cache_backend->deleteAll(); } drupal_set_message($this->t('@language translation of %label was deleted', array('%label' => $this->mapper->getTitle(), '@language' => $this->language->name))); $form_state['redirect_route'] = $this->getCancelUrl(); }
/** * {@inheritdoc} */ public function uninstall(array $theme_list) { $extension_config = $this->configFactory->getEditable('core.extension'); $theme_config = $this->configFactory->getEditable('system.theme'); $list = $this->listInfo(); foreach ($theme_list as $key) { if (!isset($list[$key])) { throw new \InvalidArgumentException("Unknown theme: {$key}."); } if ($key === $theme_config->get('default')) { throw new \InvalidArgumentException("The current default theme {$key} cannot be uninstalled."); } if ($key === $theme_config->get('admin')) { throw new \InvalidArgumentException("The current admin theme {$key} cannot be uninstalled."); } // Base themes cannot be uninstalled if sub themes are installed, and if // they are not uninstalled at the same time. // @todo https://www.drupal.org/node/474684 and // https://www.drupal.org/node/1297856 themes should leverage the module // dependency system. if (!empty($list[$key]->sub_themes)) { foreach ($list[$key]->sub_themes as $sub_key => $sub_label) { if (isset($list[$sub_key]) && !in_array($sub_key, $theme_list, TRUE)) { throw new \InvalidArgumentException("The base theme {$key} cannot be uninstalled, because theme {$sub_key} depends on it."); } } } } $this->cssCollectionOptimizer->deleteAll(); $current_theme_data = $this->state->get('system.theme.data', array()); foreach ($theme_list as $key) { // The value is not used; the weight is ignored for themes currently. $extension_config->clear("theme.{$key}"); // Remove the theme from the current list. unset($this->list[$key]); // Update the current theme data accordingly. unset($current_theme_data[$key]); // Reset theme settings. $theme_settings =& drupal_static('theme_get_setting'); unset($theme_settings[$key]); // @todo Remove system_list(). $this->systemListReset(); // Remove all configuration belonging to the theme. $this->configManager->uninstall('theme', $key); } $extension_config->save(); $this->state->set('system.theme.data', $current_theme_data); $this->resetSystem(); $this->moduleHandler->invokeAll('themes_uninstalled', [$theme_list]); }
/** * Gets all data invoked by hook_views_data(). * * This is requested from the cache before being rebuilt. * * @return array * An array of all data. */ protected function getData() { $this->fullyLoaded = TRUE; if ($data = $this->cacheGet($this->baseCid)) { return $data->data; } else { $data = $this->moduleHandler->invokeAll('views_data'); $this->moduleHandler->alter('views_data', $data); $this->processEntityTypes($data); // Keep a record with all data. $this->cacheSet($this->baseCid, $data); return $data; } }
/** * {@inheritdoc} */ public function getDefaultSet(AccountInterface $account) { // Allow modules to return a default shortcut set name. Since we can only // have one, we allow the last module which returns a valid result to take // precedence. If no module returns a valid set, fall back on the site-wide // default, which is the lowest-numbered shortcut set. $suggestions = array_reverse($this->moduleHandler->invokeAll('shortcut_default_set', array($account))); $suggestions[] = 'default'; $shortcut_set = NULL; foreach ($suggestions as $name) { if ($shortcut_set = $this->load($name)) { break; } } return $shortcut_set; }
/** * Returns the help associated with the active menu item. * * @param \Symfony\Component\HttpFoundation\Request $request * The current request. * * @return array|string * Render array or string containing the help of the matched route item. */ protected function getActiveHelp(Request $request) { // Do not show on a 403 or 404 page. if ($request->attributes->has('exception')) { return ''; } $help = $this->moduleHandler->invokeAll('help', array($this->routeMatch->getRouteName(), $this->routeMatch)); $build = []; foreach ($help as $item) { if (!is_array($item)) { $item = ['#markup' => $item]; } $build[] = $item; } return $build; }
/** * @todo. */ protected function prepareEvents() { $events = array(); foreach ($this->view->result as $delta => $row) { // Collect all fields for the customize options. $fields = array(); // Collect only date fields. $date_fields = array(); foreach ($this->view->field as $field_name => $field) { $fields[$field_name] = $this->getField($delta, $field_name); if (fullcalendar_field_is_date($field)) { $date_fields[$field_name] = array('value' => $field->getItems($row), 'field_alias' => $field->field_alias, 'field_name' => $field->field_info['field_name'], 'field_info' => $field->field_info); } } // If using a custom date field, filter the fields to process. if (!empty($this->options['fields']['date'])) { $date_fields = array_intersect_key($date_fields, $this->options['fields']['date_field']); } // If there are no date fields (gcal only), return. if (empty($date_fields)) { return $events; } $entity = $row->_entity; $classes = $this->moduleHandler->invokeAll('fullcalendar_classes', array($entity)); $this->moduleHandler->alter('fullcalendar_classes', $classes, $entity); $classes = array_map('drupal_html_class', $classes); $class = implode(' ', array_unique($classes)); $event = array(); foreach ($date_fields as $field) { // Filter fields without value. if (empty($field['value'])) { continue; } foreach ($field['value'] as $index => $item) { $start = $item['raw']['value']; $end = $start; $all_day = FALSE; $uri = $entity->uri(); $event[] = array('#type' => 'link', '#title' => $item['raw']['value'], '#href' => $uri['path'], '#options' => array('html' => TRUE, 'attributes' => array('allDay' => $all_day, 'start' => $start, 'end' => $end, 'editable' => (int) TRUE, 'field' => $field['field_name'], 'index' => $index, 'eid' => $entity->id(), 'entity_type' => $entity->entityType(), 'cn' => $class, 'title' => strip_tags(htmlspecialchars_decode($entity->label(), ENT_QUOTES)), 'class' => array('fullcalendar-event-details')))); } } if (!empty($event)) { $events[$delta] = array('#theme' => 'fullcalendar_event', '#event' => $event, '#entity' => $entity); } } return $events; }
/** * {@inheritdoc} */ public function disable(array $theme_list) { $list = $this->listInfo(); $theme_config = $this->configFactory->get('system.theme'); foreach ($theme_list as $key) { if (!isset($list[$key])) { throw new \InvalidArgumentException("Unknown theme: {$key}."); } if ($key === $theme_config->get('default')) { throw new \InvalidArgumentException("The current default theme {$key} cannot be disabled."); } if ($key === $theme_config->get('admin')) { throw new \InvalidArgumentException("The current admin theme {$key} cannot be disabled."); } // Base themes cannot be disabled if sub themes are enabled, and if they // are not disabled at the same time. if (!empty($list[$key]->sub_themes)) { foreach ($list[$key]->sub_themes as $sub_key => $sub_label) { if (isset($list[$sub_key]) && !in_array($sub_key, $theme_list, TRUE)) { throw new \InvalidArgumentException("The base theme {$key} cannot be disabled, because theme {$sub_key} depends on it."); } } } } $this->clearCssCache(); $extension_config = $this->configFactory->get('core.extension'); $current_theme_data = $this->state->get('system.theme.data', array()); foreach ($theme_list as $key) { // The value is not used; the weight is ignored for themes currently. $extension_config->clear("theme.{$key}")->set("disabled.theme.{$key}", 0); // Remove the theme from the current list. unset($this->list[$key]); // Update the current theme data accordingly. unset($current_theme_data[$key]); // Reset theme settings. $theme_settings =& drupal_static('theme_get_setting'); unset($theme_settings[$key]); // @todo Remove system_list(). $this->systemListReset(); } $extension_config->save(); $this->state->set('system.theme.data', $current_theme_data); $this->resetSystem(); // Invoke hook_themes_disabled after the themes have been disabled. $this->moduleHandler->invokeAll('themes_disabled', array($theme_list)); }
/** * @covers ::getFieldMapByFieldType */ public function testGetFieldMapByFieldType() { // Set up a content entity type. $entity_type = $this->prophesize(ContentEntityTypeInterface::class); $entity_class = EntityManagerTestEntity::class; // Set up the module handler to return two bundles for the fieldable entity // type. $this->moduleHandler->getImplementations('entity_base_field_info')->willReturn([]); $this->moduleHandler->invokeAll('entity_bundle_info')->willReturn(['test_entity_type' => ['first_bundle' => [], 'second_bundle' => []]]); $this->moduleHandler->alter('entity_bundle_info', Argument::type('array'))->willReturn(NULL); // Define an ID field definition as a base field. $id_definition = $this->prophesize(FieldDefinitionInterface::class); $id_definition->getType()->willReturn('integer'); $base_field_definitions = array('id' => $id_definition->reveal()); $entity_class::$baseFieldDefinitions = $base_field_definitions; // Set up the stored bundle field map. $key_value_store = $this->prophesize(KeyValueStoreInterface::class); $this->keyValueFactory->get('entity.definitions.bundle_field_map')->willReturn($key_value_store->reveal()); $key_value_store->getAll()->willReturn(['test_entity_type' => ['by_bundle' => ['type' => 'string', 'bundles' => ['second_bundle' => 'second_bundle']]]]); // Mock the base field definition override. $override_entity_type = $this->prophesize(EntityTypeInterface::class); $this->setUpEntityManager(array('test_entity_type' => $entity_type, 'base_field_override' => $override_entity_type)); $entity_type->getClass()->willReturn($entity_class); $entity_type->getKeys()->willReturn(['default_langcode' => 'default_langcode']); $entity_type->id()->willReturn('test_entity_type'); $entity_type->isSubclassOf(FieldableEntityInterface::class)->willReturn(TRUE); $entity_type->getBundleOf()->shouldBeCalled(); $entity_type->isTranslatable()->shouldBeCalled(); $entity_type->getProvider()->shouldBeCalled(); $override_entity_type->getClass()->willReturn($entity_class); $override_entity_type->isSubclassOf(FieldableEntityInterface::class)->willReturn(FALSE); $override_entity_type->getHandlerClass('storage')->willReturn(TestConfigEntityStorage::class); $override_entity_type->getBundleOf()->shouldBeCalled(); $override_entity_type->getLabel()->shouldBeCalled(); $integerFields = $this->entityManager->getFieldMapByFieldType('integer'); $this->assertCount(1, $integerFields['test_entity_type']); $this->assertArrayNotHasKey('non_fieldable', $integerFields); $this->assertArrayHasKey('id', $integerFields['test_entity_type']); $this->assertArrayNotHasKey('by_bundle', $integerFields['test_entity_type']); $stringFields = $this->entityManager->getFieldMapByFieldType('string'); $this->assertCount(1, $stringFields['test_entity_type']); $this->assertArrayNotHasKey('non_fieldable', $stringFields); $this->assertArrayHasKey('by_bundle', $stringFields['test_entity_type']); $this->assertArrayNotHasKey('id', $stringFields['test_entity_type']); }
/** * Displays the site status report. Can also be used as a pure check. * * @return array * An array of system requirements. */ public function listRequirements() { // Load .install files include_once DRUPAL_ROOT . '/core/includes/install.inc'; drupal_load_updates(); // Check run-time requirements and status information. $requirements = $this->moduleHandler->invokeAll('requirements', array('runtime')); usort($requirements, function ($a, $b) { if (!isset($a['weight'])) { if (!isset($b['weight'])) { return strcmp($a['title'], $b['title']); } return -$b['weight']; } return isset($b['weight']) ? $a['weight'] - $b['weight'] : $a['weight']; }); return $requirements; }
/** * {@inheritdoc} */ public function delete($conditions) { $path = $this->load($conditions); $query = $this->connection->delete('url_alias'); foreach ($conditions as $field => $value) { if ($field == 'source' || $field == 'alias') { // Use LIKE for case-insensitive matching. $query->condition($field, $this->connection->escapeLike($value), 'LIKE'); } else { $query->condition($field, $value); } } $deleted = $query->execute(); // @todo Switch to using an event for this instead of a hook. $this->moduleHandler->invokeAll('path_delete', array($path)); Cache::invalidateTags(['route_match']); return $deleted; }
/** * @covers ::getExtraFields */ function testGetExtraFields() { $this->setUpEntityTypeDefinitions(); $entity_type_id = $this->randomMachineName(); $bundle = $this->randomMachineName(); $language_code = 'en'; $hook_bundle_extra_fields = [$entity_type_id => [$bundle => ['form' => ['foo_extra_field' => ['label' => 'Foo']]]]]; $processed_hook_bundle_extra_fields = $hook_bundle_extra_fields; $processed_hook_bundle_extra_fields[$entity_type_id][$bundle] += ['display' => []]; $cache_id = 'entity_bundle_extra_fields:' . $entity_type_id . ':' . $bundle . ':' . $language_code; $language = new Language(['id' => $language_code]); $this->languageManager->getCurrentLanguage()->willReturn($language)->shouldBeCalledTimes(1); $this->cacheBackend->get($cache_id)->shouldBeCalled(); $this->moduleHandler->invokeAll('entity_extra_field_info')->willReturn($hook_bundle_extra_fields); $this->moduleHandler->alter('entity_extra_field_info', $hook_bundle_extra_fields)->shouldBeCalled(); $this->cacheBackend->set($cache_id, $processed_hook_bundle_extra_fields[$entity_type_id][$bundle], Cache::PERMANENT, ['entity_field_info'])->shouldBeCalled(); $this->assertSame($processed_hook_bundle_extra_fields[$entity_type_id][$bundle], $this->entityFieldManager->getExtraFields($entity_type_id, $bundle)); }
/** * @covers ::getAllBundleInfo */ public function testGetAllBundleInfoWithEntityBundleInfo() { // Ensure that EntityTypeBundleInfo::getAllBundleInfo() does not add // additional bundles if hook_entity_bundle_info() defines some and the // entity_type does not define a bundle entity type. $this->moduleHandler->invokeAll('entity_bundle_info')->willReturn(['banana' => ['fig' => ['label' => 'Fig banana']]]); $this->moduleHandler->alter('entity_bundle_info', Argument::type('array'))->willReturn(NULL); $apple = $this->prophesize(EntityTypeInterface::class); $apple->getLabel()->willReturn('Apple'); $apple->getBundleEntityType()->willReturn(NULL); $banana = $this->prophesize(EntityTypeInterface::class); $banana->getLabel()->willReturn('Banana'); $banana->getBundleEntityType()->willReturn(NULL); $this->setUpEntityTypeDefinitions(['apple' => $apple, 'banana' => $banana]); $expected = ['banana' => ['fig' => ['label' => 'Fig banana']], 'apple' => ['apple' => ['label' => 'Apple']]]; $bundle_info = $this->entityTypeBundleInfo->getAllBundleInfo(); $this->assertSame($expected, $bundle_info); }
/** * Switching back to previous user. * * @return bool * TRUE when switched back, FALSE otherwise. */ public function switchBack() { if (empty($_SESSION['masquerading'])) { return FALSE; } $new_user = $this->entityTypeManager->getStorage('user')->load($_SESSION['masquerading']); // Ensure the flag is cleared. unset($_SESSION['masquerading']); if (!$new_user) { return FALSE; } $account = $this->currentUser; // Call logout hooks when switching from masquerading user. $this->moduleHandler->invokeAll('user_logout', [$account]); // Regenerate the session ID to prevent against session fixation attacks. // @todo Maybe session service migrate. $this->sessionManager->regenerate(); $this->currentUser->setAccount($new_user); \Drupal::service('session')->set('uid', $new_user->id()); // Call all login hooks when switching back to original user. $this->moduleHandler->invokeAll('user_login', [$new_user]); $this->logger->info('User %username stopped masquerading as %old_username.', array('%username' => $new_user->getDisplayName(), '%old_username' => $account->getDisplayName(), 'link' => $this->l($this->t('view'), $new_user->toUrl()))); return TRUE; }
/** * Analyzes a review and return the results. * * @param \Drupal\views\ViewExecutable $view * The view to analyze. * * @return array * An array of analyze results organized into arrays keyed by 'ok', * 'warning' and 'error'. */ public function getMessages(ViewExecutable $view) { $view->initDisplay(); $messages = $this->moduleHandler->invokeAll('views_analyze', array($view)); return $messages; }
/** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { $local_cache = NULL; if ($form_state->getValue('project_url')) { $local_cache = update_manager_file_get($form_state->getValue('project_url')); if (!$local_cache) { drupal_set_message($this->t('Unable to retrieve Drupal project from %url.', array('%url' => $form_state->getValue('project_url'))), 'error'); return; } } elseif ($_FILES['files']['name']['project_upload']) { $validators = array('file_validate_extensions' => array(archiver_get_extensions())); if (!($finfo = file_save_upload('project_upload', $validators, NULL, 0, FILE_EXISTS_REPLACE))) { // Failed to upload the file. file_save_upload() calls // drupal_set_message() on failure. return; } $local_cache = $finfo->getFileUri(); } $directory = _update_manager_extract_directory(); try { $archive = update_manager_archive_extract($local_cache, $directory); } catch (\Exception $e) { drupal_set_message($e->getMessage(), 'error'); return; } $files = $archive->listContents(); if (!$files) { drupal_set_message($this->t('Provided archive contains no files.'), 'error'); return; } // Unfortunately, we can only use the directory name to determine the // project name. Some archivers list the first file as the directory (i.e., // MODULE/) and others list an actual file (i.e., MODULE/README.TXT). $project = strtok($files[0], '/\\'); $archive_errors = $this->moduleHandler->invokeAll('verify_update_archive', array($project, $local_cache, $directory)); if (!empty($archive_errors)) { drupal_set_message(array_shift($archive_errors), 'error'); // @todo: Fix me in D8: We need a way to set multiple errors on the same // form element and have all of them appear! if (!empty($archive_errors)) { foreach ($archive_errors as $error) { drupal_set_message($error, 'error'); } } return; } // Make sure the Updater registry is loaded. drupal_get_updaters(); $project_location = $directory . '/' . $project; try { $updater = Updater::factory($project_location, $this->root); } catch (\Exception $e) { drupal_set_message($e->getMessage(), 'error'); return; } try { $project_title = Updater::getProjectTitle($project_location); } catch (\Exception $e) { drupal_set_message($e->getMessage(), 'error'); return; } if (!$project_title) { drupal_set_message($this->t('Unable to determine %project name.', array('%project' => $project)), 'error'); } if ($updater->isInstalled()) { drupal_set_message($this->t('%project is already installed.', array('%project' => $project_title)), 'error'); return; } $project_real_location = drupal_realpath($project_location); $arguments = array('project' => $project, 'updater_name' => get_class($updater), 'local_url' => $project_real_location); // This process is inherently difficult to test therefore use a state flag. $test_authorize = FALSE; if (drupal_valid_test_ua()) { $test_authorize = \Drupal::state()->get('test_uploaders_via_prompt', FALSE); } // If the owner of the directory we extracted is the same as the owner of // our configuration directory (e.g. sites/default) where we're trying to // install the code, there's no need to prompt for FTP/SSH credentials. // Instead, we instantiate a Drupal\Core\FileTransfer\Local and invoke // update_authorize_run_install() directly. if (fileowner($project_real_location) == fileowner($this->sitePath) && !$test_authorize) { $this->moduleHandler->loadInclude('update', 'inc', 'update.authorize'); $filetransfer = new Local($this->root); $response = call_user_func_array('update_authorize_run_install', array_merge(array($filetransfer), $arguments)); if ($response instanceof Response) { $form_state->setResponse($response); } } else { // The page title must be passed here to ensure it is initially used when // authorize.php loads for the first time with the FTP/SSH credentials // form. system_authorized_init('update_authorize_run_install', __DIR__ . '/../../update.authorize.inc', $arguments, $this->t('Update manager')); $form_state->setRedirectUrl(system_authorized_get_url()); } }
/** * {@inheritdoc} */ public function uninstall(array $module_list, $uninstall_dependents = TRUE) { // Get all module data so we can find dependencies and sort. $module_data = system_rebuild_module_data(); $module_list = $module_list ? array_combine($module_list, $module_list) : array(); if (array_diff_key($module_list, $module_data)) { // One or more of the given modules doesn't exist. return FALSE; } $extension_config = \Drupal::configFactory()->getEditable('core.extension'); $installed_modules = $extension_config->get('module') ?: array(); if (!($module_list = array_intersect_key($module_list, $installed_modules))) { // Nothing to do. All modules already uninstalled. return TRUE; } if ($uninstall_dependents) { // Add dependent modules to the list. The new modules will be processed as // the while loop continues. $profile = drupal_get_profile(); while (list($module) = each($module_list)) { foreach (array_keys($module_data[$module]->required_by) as $dependent) { if (!isset($module_data[$dependent])) { // The dependent module does not exist. return FALSE; } // Skip already uninstalled modules. if (isset($installed_modules[$dependent]) && !isset($module_list[$dependent]) && $dependent != $profile) { $module_list[$dependent] = $dependent; } } } } // Use the validators and throw an exception with the reasons. if ($reasons = $this->validateUninstall($module_list)) { foreach ($reasons as $reason) { $reason_message[] = implode(', ', $reason); } throw new ModuleUninstallValidatorException(format_string('The following reasons prevents the modules from being uninstalled: @reasons', array('@reasons' => implode(', ', $reason_message)))); } // Set the actual module weights. $module_list = array_map(function ($module) use($module_data) { return $module_data[$module]->sort; }, $module_list); // Sort the module list by their weights. asort($module_list); $module_list = array_keys($module_list); // Only process modules that are enabled. A module is only enabled if it is // configured as enabled. Custom or overridden module handlers might contain // the module already, which means that it might be loaded, but not // necessarily installed. foreach ($module_list as $module) { // Clean up all entity bundles (including fields) of every entity type // provided by the module that is being uninstalled. // @todo Clean this up in https://www.drupal.org/node/2350111. $entity_manager = \Drupal::entityManager(); foreach ($entity_manager->getDefinitions() as $entity_type_id => $entity_type) { if ($entity_type->getProvider() == $module) { foreach (array_keys($entity_manager->getBundleInfo($entity_type_id)) as $bundle) { $entity_manager->onBundleDelete($bundle, $entity_type_id); } } } // Allow modules to react prior to the uninstallation of a module. $this->moduleHandler->invokeAll('module_preuninstall', array($module)); // Uninstall the module. module_load_install($module); $this->moduleHandler->invoke($module, 'uninstall'); // Remove all configuration belonging to the module. \Drupal::service('config.manager')->uninstall('module', $module); // Notify interested components that this module's entity types are being // deleted. For example, a SQL-based storage handler can use this as an // opportunity to drop the corresponding database tables. // @todo Clean this up in https://www.drupal.org/node/2350111. foreach ($entity_manager->getDefinitions() as $entity_type) { if ($entity_type->getProvider() == $module) { $entity_manager->onEntityTypeDelete($entity_type); } } // Remove the schema. drupal_uninstall_schema($module); // Remove the module's entry from the config. \Drupal::configFactory()->getEditable('core.extension')->clear("module.{$module}")->save(); // Update the module handler to remove the module. // The current ModuleHandler instance is obsolete with the kernel rebuild // below. $module_filenames = $this->moduleHandler->getModuleList(); unset($module_filenames[$module]); $this->moduleHandler->setModuleList($module_filenames); // Remove any potential cache bins provided by the module. $this->removeCacheBins($module); // Clear the static cache of system_rebuild_module_data() to pick up the // new module, since it merges the installation status of modules into // its statically cached list. drupal_static_reset('system_rebuild_module_data'); // Clear plugin manager caches. \Drupal::getContainer()->get('plugin.cache_clearer')->clearCachedDefinitions(); // Update the kernel to exclude the uninstalled modules. $this->updateKernel($module_filenames); // Update the theme registry to remove the newly uninstalled module. drupal_theme_rebuild(); // Modules can alter theme info, so refresh theme data. // @todo ThemeHandler cannot be injected into ModuleHandler, since that // causes a circular service dependency. // @see https://drupal.org/node/2208429 \Drupal::service('theme_handler')->refreshInfo(); \Drupal::logger('system')->info('%module module uninstalled.', array('%module' => $module)); $schema_store = \Drupal::keyValue('system.schema'); $schema_store->delete($module); } \Drupal::service('router.builder')->setRebuildNeeded(); drupal_get_installed_schema_version(NULL, TRUE); // Let other modules react. $this->moduleHandler->invokeAll('modules_uninstalled', array($module_list)); // Flush all persistent caches. // Any cache entry might implicitly depend on the uninstalled modules, // so clear all of them explicitly. $this->moduleHandler->invokeAll('cache_flush'); foreach (Cache::getBins() as $service_id => $cache_backend) { $cache_backend->deleteAll(); } return TRUE; }
/** * {@inheritdoc} */ protected function execute(InputInterface $input, OutputInterface $output) { $io = new DrupalStyle($input, $output); //Registers namespaces for disabled modules. $this->test_discovery->registerTestNamespaces(); $testClass = $input->getArgument('test-class'); $testMethods = $input->getArgument('test-methods'); $url = $input->getOption('url'); if (!$url) { $io->error($this->trans('commands.test.run.messages.url-required')); return null; } $this->setEnvironment($url); // Create simpletest test id $testId = db_insert('simpletest_test_id')->useDefaults(['test_id'])->execute(); if (is_subclass_of($testClass, 'PHPUnit_Framework_TestCase')) { $io->info($this->trans('commands.test.run.messages.phpunit-pending')); return null; } else { if (!class_exists($testClass)) { $io->error(sprintf($this->trans('commands.test.run.messages.invalid-class'), $testClass)); return 1; } $test = new $testClass($testId); $io->info($this->trans('commands.test.run.messages.starting-test')); Timer::start('run-tests'); $test->run($testMethods); $end = Timer::stop('run-tests'); $io->simple($this->trans('commands.test.run.messages.test-duration') . ': ' . $this->dateFormatter->formatInterval($end['time'] / 1000)); $io->simple($this->trans('commands.test.run.messages.test-pass') . ': ' . $test->results['#pass']); $io->commentBlock($this->trans('commands.test.run.messages.test-fail') . ': ' . $test->results['#fail']); $io->commentBlock($this->trans('commands.test.run.messages.test-exception') . ': ' . $test->results['#exception']); $io->simple($this->trans('commands.test.run.messages.test-debug') . ': ' . $test->results['#debug']); $this->moduleHandler->invokeAll('test_finished', [$test->results]); $io->newLine(); $io->info($this->trans('commands.test.run.messages.test-summary')); $io->newLine(); $currentClass = null; $currentGroup = null; $currentStatus = null; $messages = $this->simpletestScriptLoadMessagesByTestIds([$testId]); foreach ($messages as $message) { if ($currentClass === null || $currentClass != $message->test_class) { $currentClass = $message->test_class; $io->comment($message->test_class); } if ($currentGroup === null || $currentGroup != $message->message_group) { $currentGroup = $message->message_group; } if ($currentStatus === null || $currentStatus != $message->status) { $currentStatus = $message->status; if ($message->status == 'fail') { $io->error($this->trans('commands.test.run.messages.group') . ':' . $message->message_group . ' ' . $this->trans('commands.test.run.messages.status') . ':' . $message->status); $io->newLine(); } else { $io->info($this->trans('commands.test.run.messages.group') . ':' . $message->message_group . ' ' . $this->trans('commands.test.run.messages.status') . ':' . $message->status); $io->newLine(); } } $io->simple($this->trans('commands.test.run.messages.file') . ': ' . str_replace($this->appRoot, '', $message->file)); $io->simple($this->trans('commands.test.run.messages.method') . ': ' . $message->function); $io->simple($this->trans('commands.test.run.messages.line') . ': ' . $message->line); $io->simple($this->trans('commands.test.run.messages.message') . ': ' . $message->message); $io->newLine(); } return null; } }