/** * Tests the hooks. */ public function testHooks() { $view = Views::getView('test_view'); $view->setDisplay(); // Test each hook is found in the implementations array and is invoked. foreach (static::$hooks as $hook => $type) { $this->assertTrue($this->moduleHandler->implementsHook('views_test_data', $hook), format_string('The hook @hook was registered.', array('@hook' => $hook))); if ($hook == 'views_post_render') { $this->moduleHandler->invoke('views_test_data', $hook, array($view, &$view->display_handler->output, $view->display_handler->getPlugin('cache'))); continue; } switch ($type) { case 'view': $this->moduleHandler->invoke('views_test_data', $hook, array($view)); break; case 'alter': $data = array(); $this->moduleHandler->invoke('views_test_data', $hook, array($data)); break; default: $this->moduleHandler->invoke('views_test_data', $hook); } $this->assertTrue($this->container->get('state')->get('views_hook_test_' . $hook), format_string('The %hook hook was invoked.', array('%hook' => $hook))); // Reset the module implementations cache, so we ensure that the // .views.inc file is loaded actively. $this->moduleHandler->resetImplementations(); } }
/** * {@inheritdoc} */ protected function execute(InputInterface $input, OutputInterface $output) { $io = new DrupalStyle($input, $output); $modules = $input->getArgument('module'); if (!$this->lock->acquire('cron', 900.0)) { $io->warning($this->trans('commands.cron.execute.messages.lock')); return 1; } if (in_array('all', $modules)) { $modules = $this->moduleHandler->getImplementations('cron'); } foreach ($modules as $module) { if (!$this->moduleHandler->implementsHook($module, 'cron')) { $io->warning(sprintf($this->trans('commands.cron.execute.messages.module-invalid'), $module)); continue; } try { $io->info(sprintf($this->trans('commands.cron.execute.messages.executing-cron'), $module)); $this->moduleHandler->invoke($module, 'cron'); } catch (\Exception $e) { watchdog_exception('cron', $e); $io->error($e->getMessage()); } } $this->state->set('system.cron_last', REQUEST_TIME); $this->lock->release('cron'); $this->chainQueue->addCommand('cache:rebuild', ['cache' => 'all']); $io->success($this->trans('commands.cron.execute.messages.success')); return 0; }
/** * Implements Drupal\Component\Plugin\Discovery\DiscoveryInterface::getDefinitions(). */ public function getDefinitions() { $definitions = array(); foreach ($this->moduleHandler->getImplementations($this->hook) as $module) { $result = $this->moduleHandler->invoke($module, $this->hook); foreach ($result as $plugin_id => $definition) { $definition['module'] = $module; $definitions[$plugin_id] = $definition; } } return $definitions; }
/** * {@inheritdoc} */ public function isReserved($alias, $source, $langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED) { // Check if this alias already exists. if ($existing_source = $this->aliasManager->getPathByAlias($alias, $langcode)) { if ($existing_source != $alias) { // If it is an alias for the provided source, it is allowed to keep using // it. If not, then it is reserved. return $existing_source != $source; } } // Then check if there is a route with the same path. if ($this->isRoute($alias)) { return TRUE; } // Finally check if any other modules have reserved the alias. $args = array($alias, $source, $langcode); $implementations = $this->moduleHandler->getImplementations('pathauto_is_alias_reserved'); foreach ($implementations as $module) { $result = $this->moduleHandler->invoke($module, 'pathauto_is_alias_reserved', $args); if (!empty($result)) { // As soon as the first module says that an alias is in fact reserved, // then there is no point in checking the rest of the modules. return TRUE; } } return FALSE; }
/** * 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 { $modules = $this->moduleHandler->getImplementations('views_data'); $data = []; foreach ($modules as $module) { $views_data = $this->moduleHandler->invoke($module, 'views_data'); // Set the provider key for each base table. foreach ($views_data as &$table) { if (isset($table['table']) && !isset($table['table']['provider'])) { $table['table']['provider'] = $module; } } $data = NestedArray::mergeDeep($data, $views_data); } $this->moduleHandler->alter('views_data', $data); $this->processEntityTypes($data); // Keep a record with all data. $this->cacheSet($this->baseCid, $data); return $data; } }
/** * Prepares search results for rendering. * * @param \Drupal\Core\Database\StatementInterface $found * Results found from a successful search query execute() method. * * @return array * Array of search result item render arrays (empty array if no results). */ protected function prepareResults(StatementInterface $found) { $results = array(); $node_storage = $this->entityManager->getStorage('node'); $node_render = $this->entityManager->getViewBuilder('node'); $keys = $this->keywords; foreach ($found as $item) { // Render the node. /** @var \Drupal\node\NodeInterface $node */ $node = $node_storage->load($item->sid)->getTranslation($item->langcode); $build = $node_render->view($node, 'search_result', $item->langcode); /** @var \Drupal\node\NodeTypeInterface $type*/ $type = $this->entityManager->getStorage('node_type')->load($node->bundle()); unset($build['#theme']); $build['#pre_render'][] = array($this, 'removeSubmittedInfo'); // Fetch comment count for snippet. $rendered = SafeMarkup::set($this->renderer->renderPlain($build) . ' ' . SafeMarkup::escape($this->moduleHandler->invoke('comment', 'node_update_index', array($node, $item->langcode)))); $extra = $this->moduleHandler->invokeAll('node_search_result', array($node, $item->langcode)); $language = $this->languageManager->getLanguage($item->langcode); $username = array('#theme' => 'username', '#account' => $node->getOwner()); $result = array('link' => $node->url('canonical', array('absolute' => TRUE, 'language' => $language)), 'type' => SafeMarkup::checkPlain($type->label()), 'title' => $node->label(), 'node' => $node, 'extra' => $extra, 'score' => $item->calculated_score, 'snippet' => search_excerpt($keys, $rendered, $item->langcode), 'langcode' => $node->language()->getId()); if ($type->displaySubmitted()) { $result += array('user' => $this->renderer->renderPlain($username), 'date' => $node->getChangedTime()); } $results[] = $result; } return $results; }
/** * {@inheritdoc} */ public function buildForm(array $form, array &$form_state) { $role_names = array(); $role_permissions = array(); foreach ($this->getRoles() as $role_name => $role) { // Retrieve role names for columns. $role_names[$role_name] = String::checkPlain($role->label()); // Fetch permissions for the roles. $role_permissions[$role_name] = $role->getPermissions(); } // Store $role_names for use when saving the data. $form['role_names'] = array('#type' => 'value', '#value' => $role_names); // Render role/permission overview: $options = array(); $module_info = system_rebuild_module_data(); $hide_descriptions = system_admin_compact_mode(); // Get a list of all the modules implementing a hook_permission() and sort by // display name. $modules = array(); foreach ($this->moduleHandler->getImplementations('permission') as $module) { $modules[$module] = $module_info[$module]->info['name']; } asort($modules); $form['system_compact_link'] = array('#theme' => 'system_compact_link'); $form['permissions'] = array('#type' => 'table', '#header' => array($this->t('Permission')), '#id' => 'permissions', '#sticky' => TRUE); foreach ($role_names as $name) { $form['permissions']['#header'][] = array('data' => $name, 'class' => array('checkbox')); } foreach ($modules as $module => $display_name) { if ($permissions = $this->moduleHandler->invoke($module, 'permission')) { // Module name. $form['permissions'][$module] = array(array('#wrapper_attributes' => array('colspan' => count($role_names) + 1, 'class' => array('module'), 'id' => 'module-' . $module), '#markup' => $module_info[$module]->info['name'])); foreach ($permissions as $perm => $perm_item) { // Fill in default values for the permission. $perm_item += array('description' => '', 'restrict access' => FALSE, 'warning' => !empty($perm_item['restrict access']) ? $this->t('Warning: Give to trusted roles only; this permission has security implications.') : ''); $options[$perm] = $perm_item['title']; // Show the permission description. if (!$hide_descriptions) { $user_permission_description = $perm_item['description']; // Append warning message. if (!empty($perm_item['warning'])) { $user_permission_description .= ' <em class="permission-warning">' . $perm_item['warning'] . '</em>'; } } $form['permissions'][$perm]['description'] = array('#wrapper_attributes' => array('class' => array('permission')), '#type' => 'item', '#markup' => $perm_item['title'], '#description' => $user_permission_description); $options[$perm] = ''; foreach ($role_names as $rid => $name) { $form['permissions'][$perm][$rid] = array('#title' => $name . ': ' . $perm_item['title'], '#title_display' => 'invisible', '#wrapper_attributes' => array('class' => array('checkbox')), '#type' => 'checkbox', '#default_value' => in_array($perm, $role_permissions[$rid]) ? 1 : 0, '#attributes' => array('class' => array('rid-' . $rid)), '#parents' => array($rid, $perm)); } } } } $form['actions'] = array('#type' => 'actions'); $form['actions']['submit'] = array('#type' => 'submit', '#value' => $this->t('Save permissions')); $form['#attached']['library'][] = 'user/drupal.user.permissions'; return $form; }
/** * {@inheritdoc} */ public function build() { // Do not show on a 403 or 404 page. if ($this->request->attributes->has('exception')) { return []; } $implementations = $this->moduleHandler->getImplementations('help'); $build = []; $args = [$this->routeMatch->getRouteName(), $this->routeMatch]; foreach ($implementations as $module) { // Don't add empty strings to $build array. if ($help = $this->moduleHandler->invoke($module, 'help', $args)) { // Convert strings to #markup render arrays so that they will XSS admin // filtered. $build[] = is_array($help) ? $help : ['#markup' => $help]; } } return $build; }
/** * {@inheritdoc} */ protected function thirdPartySettingsForm(PluginSettingsInterface $plugin, FieldDefinitionInterface $field_definition, array $form, array &$form_state) { $settings_form = array(); // Invoke hook_field_formatter_third_party_settings_form(), keying resulting // subforms by module name. foreach ($this->moduleHandler->getImplementations('field_formatter_third_party_settings_form') as $module) { $settings_form[$module] = $this->moduleHandler->invoke($module, 'field_formatter_third_party_settings_form', array($plugin, $field_definition, $this->mode, $form, $form_state)); } return $settings_form; }
/** * Form constructor for the comment overview administration form. * * @param array $form * An associative array containing the structure of the form. * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. * @param string $type * The type of the overview form ('approval' or 'new'). * * @return array * The form structure. */ public function buildForm(array $form, FormStateInterface $form_state, $type = 'new') { // Build an 'Update options' form. $form['options'] = array('#type' => 'details', '#title' => $this->t('Update options'), '#open' => TRUE, '#attributes' => array('class' => array('container-inline'))); if ($type == 'approval') { $options['publish'] = $this->t('Publish the selected comments'); } else { $options['unpublish'] = $this->t('Unpublish the selected comments'); } $options['delete'] = $this->t('Delete the selected comments'); $form['options']['operation'] = array('#type' => 'select', '#title' => $this->t('Action'), '#title_display' => 'invisible', '#options' => $options, '#default_value' => 'publish'); $form['options']['submit'] = array('#type' => 'submit', '#value' => $this->t('Update')); // Load the comments that need to be displayed. $status = $type == 'approval' ? CommentInterface::NOT_PUBLISHED : CommentInterface::PUBLISHED; $header = array('subject' => array('data' => $this->t('Subject'), 'specifier' => 'subject'), 'author' => array('data' => $this->t('Author'), 'specifier' => 'name', 'class' => array(RESPONSIVE_PRIORITY_MEDIUM)), 'posted_in' => array('data' => $this->t('Posted in'), 'class' => array(RESPONSIVE_PRIORITY_LOW)), 'changed' => array('data' => $this->t('Updated'), 'specifier' => 'changed', 'sort' => 'desc', 'class' => array(RESPONSIVE_PRIORITY_LOW)), 'operations' => $this->t('Operations')); $cids = $this->commentStorage->getQuery()->condition('status', $status)->tableSort($header)->pager(50)->execute(); /** @var $comments \Drupal\comment\CommentInterface[] */ $comments = $this->commentStorage->loadMultiple($cids); // Build a table listing the appropriate comments. $options = array(); $destination = $this->getDestinationArray(); $commented_entity_ids = array(); $commented_entities = array(); foreach ($comments as $comment) { $commented_entity_ids[$comment->getCommentedEntityTypeId()][] = $comment->getCommentedEntityId(); } foreach ($commented_entity_ids as $entity_type => $ids) { $commented_entities[$entity_type] = $this->entityManager->getStorage($entity_type)->loadMultiple($ids); } foreach ($comments as $comment) { /** @var $commented_entity \Drupal\Core\Entity\EntityInterface */ $commented_entity = $commented_entities[$comment->getCommentedEntityTypeId()][$comment->getCommentedEntityId()]; $username = array('#theme' => 'username', '#account' => $comment->getOwner()); $body = ''; if (!empty($comment->comment_body->value)) { $body = $comment->comment_body->value; } $comment_permalink = $comment->permalink(); $attributes = $comment_permalink->getOption('attributes') ?: array(); $attributes += array('title' => Unicode::truncate($body, 128)); $comment_permalink->setOption('attributes', $attributes); $options[$comment->id()] = array('title' => array('data' => array('#title' => $comment->getSubject() ?: $comment->id())), 'subject' => array('data' => array('#type' => 'link', '#title' => $comment->getSubject(), '#url' => $comment_permalink)), 'author' => drupal_render($username), 'posted_in' => array('data' => array('#type' => 'link', '#title' => $commented_entity->label(), '#access' => $commented_entity->access('view'), '#url' => $commented_entity->urlInfo())), 'changed' => $this->dateFormatter->format($comment->getChangedTime(), 'short')); $comment_uri_options = $comment->urlInfo()->getOptions(); $links = array(); $links['edit'] = array('title' => $this->t('Edit'), 'url' => Url::fromRoute('entity.comment.edit_form', ['comment' => $comment->id()], $comment_uri_options + ['query' => $destination])); if ($this->moduleHandler->moduleExists('content_translation') && $this->moduleHandler->invoke('content_translation', 'translate_access', array($comment))->isAllowed()) { $links['translate'] = array('title' => $this->t('Translate'), 'url' => Url::fromRoute('entity.comment.content_translation_overview', ['comment' => $comment->id()], $comment_uri_options + ['query' => $destination])); } $options[$comment->id()]['operations']['data'] = array('#type' => 'operations', '#links' => $links); } $form['comments'] = array('#type' => 'tableselect', '#header' => $header, '#options' => $options, '#empty' => $this->t('No comments available.')); $form['pager'] = array('#type' => 'pager'); return $form; }
/** * Invokes any cron handlers implementing hook_cron. */ protected function invokeCronHandlers() { // Iterate through the modules calling their cron handlers (if any): foreach ($this->moduleHandler->getImplementations('cron') as $module) { // Do not let an exception thrown by one module disturb another. try { $this->moduleHandler->invoke($module, 'cron'); } catch (\Exception $e) { watchdog_exception('cron', $e); } } }
public function getValueOptions() { if (!isset($this->value_options)) { $module_info = system_get_info('module'); // Get a list of all the modules implementing a hook_permission() and sort by // display name. $modules = array(); foreach ($this->moduleHandler->getImplementations('permission') as $module) { $modules[$module] = $module_info[$module]['name']; } asort($modules); $this->value_options = array(); foreach ($modules as $module => $display_name) { if ($permissions = $this->moduleHandler->invoke($module, 'permission')) { foreach ($permissions as $perm => $perm_item) { $this->value_options[$display_name][$perm] = String::checkPlain(strip_tags($perm_item['title'])); } } } } else { return $this->value_options; } }
/** * Tests that getFieldDefinitions() method sets the 'provider' definition key. * * @covers ::getFieldDefinitions * @covers ::buildBundleFieldDefinitions */ public function testGetFieldDefinitionsProvider() { $this->setUpEntityWithFieldDefinition(TRUE); $module = 'entity_manager_test_module'; // @todo Mock FieldDefinitionInterface once it exposes a proper provider // setter. See https://www.drupal.org/node/2225961. $field_definition = $this->prophesize(BaseFieldDefinition::class); // We expect two calls as the field definition will be returned from both // base and bundle entity field info hook implementations. $field_definition->getProvider()->shouldBeCalled(); $field_definition->setProvider($module)->shouldBeCalledTimes(2); $field_definition->setName(0)->shouldBeCalledTimes(2); $field_definition->setTargetEntityTypeId('test_entity_type')->shouldBeCalled(); $field_definition->setTargetBundle(NULL)->shouldBeCalled(); $field_definition->setTargetBundle('test_bundle')->shouldBeCalled(); $this->moduleHandler->getImplementations(Argument::type('string'))->willReturn([$module]); $this->moduleHandler->invoke($module, 'entity_base_field_info', [$this->entityType])->willReturn([$field_definition->reveal()]); $this->moduleHandler->invoke($module, 'entity_bundle_field_info', Argument::type('array'))->willReturn([$field_definition->reveal()]); $this->entityManager->getFieldDefinitions('test_entity_type', 'test_bundle'); }
/** * Parses a given library file and allows module to alter it. * * This method sets the parsed information onto the library property. * * @param string $extension * The name of the extension that registered a library. * @param string $path * The relative path to the extension. * * @return array * An array of parsed library data. * * @throws \Drupal\Core\Asset\Exception\InvalidLibraryFileException * Thrown when a parser exception got thrown. */ protected function parseLibraryInfo($extension, $path) { $libraries = []; $library_file = $path . '/' . $extension . '.libraries.yml'; if (file_exists($this->root . '/' . $library_file)) { try { $libraries = Yaml::decode(file_get_contents($this->root . '/' . $library_file)); } catch (InvalidDataTypeException $e) { // Rethrow a more helpful exception to provide context. throw new InvalidLibraryFileException(sprintf('Invalid library definition in %s: %s', $library_file, $e->getMessage()), 0, $e); } } // Allow modules to add dynamic library definitions. $hook = 'library_info_build'; if ($this->moduleHandler->implementsHook($extension, $hook)) { $libraries = NestedArray::mergeDeep($libraries, $this->moduleHandler->invoke($extension, $hook)); } // Allow modules to alter the module's registered libraries. $this->moduleHandler->alter('library_info', $libraries, $extension); return $libraries; }
/** * {@inheritdoc} */ public function isReserved($alias, $source, $langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED) { // First check whether the alias exists for another source. if ($this->aliasStorageHelper->exists($alias, $source, $langcode)) { return TRUE; } // Then check if there is a route with the same path. if ($this->isRoute($alias)) { return TRUE; } // Finally check if any other modules have reserved the alias. $args = array($alias, $source, $langcode); $implementations = $this->moduleHandler->getImplementations('pathauto_is_alias_reserved'); foreach ($implementations as $module) { $result = $this->moduleHandler->invoke($module, 'pathauto_is_alias_reserved', $args); if (!empty($result)) { // As soon as the first module says that an alias is in fact reserved, // then there is no point in checking the rest of the modules. return TRUE; } } return FALSE; }
/** * Prepares search results for rendering. * * @param \Drupal\Core\Database\StatementInterface $found * Results found from a successful search query execute() method. * * @return array * Array of search result item render arrays (empty array if no results). */ protected function prepareResults(StatementInterface $found) { $results = array(); $node_storage = $this->entityManager->getStorage('node'); $node_render = $this->entityManager->getViewBuilder('node'); $keys = $this->keywords; foreach ($found as $item) { // Render the node. /** @var \Drupal\node\NodeInterface $node */ $node = $node_storage->load($item->sid)->getTranslation($item->langcode); $build = $node_render->view($node, 'search_result', $item->langcode); /** @var \Drupal\node\NodeTypeInterface $type*/ $type = $this->entityManager->getStorage('node_type')->load($node->bundle()); unset($build['#theme']); $build['#pre_render'][] = array($this, 'removeSubmittedInfo'); // Fetch comments for snippet. $rendered = $this->renderer->renderPlain($build); $this->addCacheableDependency(CacheableMetadata::createFromRenderArray($build)); $rendered .= ' ' . $this->moduleHandler->invoke('comment', 'node_update_index', [$node]); $extra = $this->moduleHandler->invokeAll('node_search_result', [$node]); $language = $this->languageManager->getLanguage($item->langcode); $username = array('#theme' => 'username', '#account' => $node->getOwner()); $result = array('link' => $node->url('canonical', array('absolute' => TRUE, 'language' => $language)), 'type' => $type->label(), 'title' => $node->label(), 'node' => $node, 'extra' => $extra, 'score' => $item->calculated_score, 'snippet' => search_excerpt($keys, $rendered, $item->langcode), 'langcode' => $node->language()->getId()); $this->addCacheableDependency($node); // We have to separately add the node owner's cache tags because search // module doesn't use the rendering system, it does its own rendering // without taking cacheability metadata into account. So we have to do it // explicitly here. $this->addCacheableDependency($node->getOwner()); if ($type->displaySubmitted()) { $result += array('user' => $this->renderer->renderPlain($username), 'date' => $node->getChangedTime()); } $results[] = $result; } return $results; }
/** * Invokes any cron handlers implementing hook_cron. */ protected function invokeCronHandlers() { $module_previous = ''; // Iterate through the modules calling their cron handlers (if any): foreach ($this->moduleHandler->getImplementations('cron') as $module) { if (!$module_previous) { $this->logger->notice('Starting execution of @module_cron().', ['@module' => $module]); } else { $this->logger->notice('Starting execution of @module_cron(), execution of @module_previous_cron() took @time.', ['@module' => $module, '@module_previous' => $module_previous, '@time' => Timer::read('cron_' . $module_previous) . 'ms']); } Timer::start('cron_' . $module); // Do not let an exception thrown by one module disturb another. try { $this->moduleHandler->invoke($module, 'cron'); } catch (\Exception $e) { watchdog_exception('cron', $e); } Timer::stop('cron_' . $module); $module_previous = $module; } if ($module_previous) { $this->logger->notice('Execution of @module_previous_cron() took @time.', ['@module_previous' => $module_previous, '@time' => Timer::read('cron_' . $module_previous) . 'ms']); } }
/** * {@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} */ public function execute() { $results = array(); if (!$this->isSearchExecutable()) { return $results; } $keys = $this->keywords; // Build matching conditions. $query = $this->database->select('search_index', 'i', array('target' => 'replica'))->extend('Drupal\\search\\SearchQuery')->extend('Drupal\\Core\\Database\\Query\\PagerSelectExtender'); $query->join('node_field_data', 'n', 'n.nid = i.sid'); $query->condition('n.status', 1)->addTag('node_access')->searchExpression($keys, $this->getPluginId()); // Handle advanced search filters in the f query string. // \Drupal::request()->query->get('f') is an array that looks like this in // the URL: ?f[]=type:page&f[]=term:27&f[]=term:13&f[]=langcode:en // So $parameters['f'] looks like: // array('type:page', 'term:27', 'term:13', 'langcode:en'); // We need to parse this out into query conditions, some of which go into // the keywords string, and some of which are separate conditions. $parameters = $this->getParameters(); if (!empty($parameters['f']) && is_array($parameters['f'])) { $filters = array(); // Match any query value that is an expected option and a value // separated by ':' like 'term:27'. $pattern = '/^(' . implode('|', array_keys($this->advanced)) . '):([^ ]*)/i'; foreach ($parameters['f'] as $item) { if (preg_match($pattern, $item, $m)) { // Use the matched value as the array key to eliminate duplicates. $filters[$m[1]][$m[2]] = $m[2]; } } // Now turn these into query conditions. This assumes that everything in // $filters is a known type of advanced search. foreach ($filters as $option => $matched) { $info = $this->advanced[$option]; // Insert additional conditions. By default, all use the OR operator. $operator = empty($info['operator']) ? 'OR' : $info['operator']; $where = new Condition($operator); foreach ($matched as $value) { $where->condition($info['column'], $value); } $query->condition($where); if (!empty($info['join'])) { $query->join($info['join']['table'], $info['join']['alias'], $info['join']['condition']); } } } // Add the ranking expressions. $this->addNodeRankings($query); // Run the query and load results. $find = $query->fields('i', array('langcode'))->groupBy('i.langcode')->limit(10)->execute(); // Check query status and set messages if needed. $status = $query->getStatus(); if ($status & SearchQuery::EXPRESSIONS_IGNORED) { drupal_set_message($this->t('Your search used too many AND/OR expressions. Only the first @count terms were included in this search.', array('@count' => $this->searchSettings->get('and_or_limit'))), 'warning'); } if ($status & SearchQuery::LOWER_CASE_OR) { drupal_set_message($this->t('Search for either of the two terms with uppercase <strong>OR</strong>. For example, <strong>cats OR dogs</strong>.'), 'warning'); } if ($status & SearchQuery::NO_POSITIVE_KEYWORDS) { drupal_set_message(\Drupal::translation()->formatPlural($this->searchSettings->get('index.minimum_word_size'), 'You must include at least one positive keyword with 1 character or more.', 'You must include at least one positive keyword with @count characters or more.'), 'warning'); } $node_storage = $this->entityManager->getStorage('node'); $node_render = $this->entityManager->getViewBuilder('node'); foreach ($find as $item) { // Render the node. /** @var \Drupal\node\NodeInterface $node */ $node = $node_storage->load($item->sid)->getTranslation($item->langcode); $build = $node_render->view($node, 'search_result', $item->langcode); unset($build['#theme']); // Fetch comment count for snippet. $node->rendered = SafeMarkup::set(drupal_render($build) . ' ' . SafeMarkup::escape($this->moduleHandler->invoke('comment', 'node_update_index', array($node, $item->langcode)))); $extra = $this->moduleHandler->invokeAll('node_search_result', array($node, $item->langcode)); $language = language_load($item->langcode); $username = array('#theme' => 'username', '#account' => $node->getOwner()); $results[] = array('link' => $node->url('canonical', array('absolute' => TRUE, 'language' => $language)), 'type' => String::checkPlain($this->entityManager->getStorage('node_type')->load($node->bundle())->label()), 'title' => $node->label(), 'user' => drupal_render($username), 'date' => $node->getChangedTime(), 'node' => $node, 'extra' => $extra, 'score' => $item->calculated_score, 'snippet' => search_excerpt($keys, $node->rendered, $item->langcode), 'langcode' => $node->language()->getId()); } return $results; }
/** * Builds a table row for the system modules page. * * @param array $modules * The list existing modules. * @param \Drupal\Core\Extension\Extension $module * The module for which to build the form row. * @param $distribution * * @return array * The form row for the given module. */ protected function buildRow(array $modules, Extension $module, $distribution) { // Set the basic properties. $row['#required'] = array(); $row['#requires'] = array(); $row['#required_by'] = array(); $row['name']['#markup'] = $module->info['name']; $row['description']['#markup'] = $this->t($module->info['description']); $row['version']['#markup'] = $module->info['version']; // Generate link for module's help page, if there is one. $row['links']['help'] = array(); if ($this->moduleHandler->moduleExists('help') && $module->status && in_array($module->getName(), $this->moduleHandler->getImplementations('help'))) { if ($this->moduleHandler->invoke($module->getName(), 'help', array('help.page.' . $module->getName(), $this->routeMatch))) { $row['links']['help'] = array('#type' => 'link', '#title' => $this->t('Help'), '#url' => Url::fromRoute('help.page', ['name' => $module->getName()]), '#options' => array('attributes' => array('class' => array('module-link', 'module-link-help'), 'title' => $this->t('Help')))); } } // Generate link for module's permission, if the user has access to it. $row['links']['permissions'] = array(); if ($module->status && \Drupal::currentUser()->hasPermission('administer permissions') && in_array($module->getName(), $this->moduleHandler->getImplementations('permission'))) { $row['links']['permissions'] = array('#type' => 'link', '#title' => $this->t('Permissions'), '#url' => Url::fromRoute('user.admin_permissions'), '#options' => array('fragment' => 'module-' . $module->getName(), 'attributes' => array('class' => array('module-link', 'module-link-permissions'), 'title' => $this->t('Configure permissions')))); } // Generate link for module's configuration page, if it has one. $row['links']['configure'] = array(); if ($module->status && isset($module->info['configure'])) { $route_parameters = isset($module->info['configure_parameters']) ? $module->info['configure_parameters'] : array(); if ($this->accessManager->checkNamedRoute($module->info['configure'], $route_parameters, $this->currentUser)) { $links = $this->menuLinkManager->loadLinksByRoute($module->info['configure']); /** @var \Drupal\Core\Menu\MenuLinkInterface $link */ $link = reset($links); // Most configure links have a corresponding menu link, though some just // have a route. if ($link) { $description = $link->getDescription(); } else { $request = new Request(); $request->attributes->set('_route_name', $module->info['configure']); $route_object = $this->routeProvider->getRouteByName($module->info['configure']); $request->attributes->set('_route', $route_object); $request->attributes->add($route_parameters); $description = $this->titleResolver->getTitle($request, $route_object); } $row['links']['configure'] = array('#type' => 'link', '#title' => $this->t('Configure'), '#url' => Url::fromRoute($module->info['configure'], $route_parameters), '#options' => array('attributes' => array('class' => array('module-link', 'module-link-configure'), 'title' => $description))); } } // Present a checkbox for installing and indicating the status of a module. $row['enable'] = array('#type' => 'checkbox', '#title' => $this->t('Install'), '#default_value' => (bool) $module->status, '#disabled' => (bool) $module->status); // Disable the checkbox for required modules. if (!empty($module->info['required'])) { // Used when displaying modules that are required by the installation profile $row['enable']['#disabled'] = TRUE; $row['#required_by'][] = $distribution . (!empty($module->info['explanation']) ? ' (' . $module->info['explanation'] . ')' : ''); } // Check the compatibilities. $compatible = TRUE; // Initialize an empty array of reasons why the module is incompatible. Add // each reason as a separate element of the array. $reasons = array(); // Check the core compatibility. if ($module->info['core'] != \Drupal::CORE_COMPATIBILITY) { $compatible = FALSE; $reasons[] = $this->t('This version is not compatible with Drupal !core_version and should be replaced.', array('!core_version' => \Drupal::CORE_COMPATIBILITY)); } // Ensure this module is compatible with the currently installed version of PHP. if (version_compare(phpversion(), $module->info['php']) < 0) { $compatible = FALSE; $required = $module->info['php'] . (substr_count($module->info['php'], '.') < 2 ? '.*' : ''); $reasons[] = $this->t('This module requires PHP version @php_required and is incompatible with PHP version !php_version.', array('@php_required' => $required, '!php_version' => phpversion())); } // If this module is not compatible, disable the checkbox. if (!$compatible) { $status = implode(' ', $reasons); $row['enable']['#disabled'] = TRUE; $row['description']['#markup'] = $status; $row['#attributes']['class'][] = 'incompatible'; } // If this module requires other modules, add them to the array. foreach ($module->requires as $dependency => $version) { if (!isset($modules[$dependency])) { $row['#requires'][$dependency] = $this->t('@module (<span class="admin-missing">missing</span>)', array('@module' => Unicode::ucfirst($dependency))); $row['enable']['#disabled'] = TRUE; } elseif (empty($modules[$dependency]->hidden)) { $name = $modules[$dependency]->info['name']; // Disable the module's checkbox if it is incompatible with the // dependency's version. if ($incompatible_version = drupal_check_incompatibility($version, str_replace(\Drupal::CORE_COMPATIBILITY . '-', '', $modules[$dependency]->info['version']))) { $row['#requires'][$dependency] = $this->t('@module (<span class="admin-missing">incompatible with</span> version @version)', array('@module' => $name . $incompatible_version, '@version' => $modules[$dependency]->info['version'])); $row['enable']['#disabled'] = TRUE; } elseif ($modules[$dependency]->info['core'] != \Drupal::CORE_COMPATIBILITY) { $row['#requires'][$dependency] = $this->t('@module (<span class="admin-missing">incompatible with</span> this version of Drupal core)', array('@module' => $name)); $row['enable']['#disabled'] = TRUE; } elseif ($modules[$dependency]->status) { $row['#requires'][$dependency] = $this->t('@module', array('@module' => $name)); } else { $row['#requires'][$dependency] = $this->t('@module (<span class="admin-disabled">disabled</span>)', array('@module' => $name)); } } } // If this module is required by other modules, list those, and then make it // impossible to disable this one. foreach ($module->required_by as $dependent => $version) { if (isset($modules[$dependent]) && empty($modules[$dependent]->info['hidden'])) { if ($modules[$dependent]->status == 1 && $module->status == 1) { $row['#required_by'][$dependent] = $this->t('@module', array('@module' => $modules[$dependent]->info['name'])); $row['enable']['#disabled'] = TRUE; } else { $row['#required_by'][$dependent] = $this->t('@module (<span class="admin-disabled">disabled</span>)', array('@module' => $modules[$dependent]->info['name'])); } } } return $row; }
/** * Builds field storage definitions for an entity type. * * @param string $entity_type_id * The entity type ID. Only entity types that implement * \Drupal\Core\Entity\FieldableEntityInterface are supported * * @return \Drupal\Core\Field\FieldStorageDefinitionInterface[] * An array of field storage definitions, keyed by field name. */ protected function buildFieldStorageDefinitions($entity_type_id) { $entity_type = $this->entityTypeManager->getDefinition($entity_type_id); $field_definitions = []; // Retrieve base field definitions from modules. foreach ($this->moduleHandler->getImplementations('entity_field_storage_info') as $module) { $module_definitions = $this->moduleHandler->invoke($module, 'entity_field_storage_info', [$entity_type]); if (!empty($module_definitions)) { // Ensure the provider key actually matches the name of the provider // defining the field. foreach ($module_definitions as $field_name => $definition) { // @todo Remove this check once FieldDefinitionInterface exposes a // proper provider setter. See https://www.drupal.org/node/2225961. if ($definition instanceof BaseFieldDefinition) { $definition->setProvider($module); } $field_definitions[$field_name] = $definition; } } } // Invoke alter hook. $this->moduleHandler->alter('entity_field_storage_info', $field_definitions, $entity_type); return $field_definitions; }