Exemplo n.º 1
0
 /**
  * {@inheritdoc}
  */
 public function viewMultiple(array $entities = array(), $view_mode = 'full', $langcode = NULL)
 {
     /** @var \Drupal\block\BlockInterface[] $entities */
     $build = array();
     foreach ($entities as $entity) {
         $entity_id = $entity->id();
         $plugin = $entity->getPlugin();
         $plugin_id = $plugin->getPluginId();
         $base_id = $plugin->getBaseId();
         $derivative_id = $plugin->getDerivativeId();
         $configuration = $plugin->getConfiguration();
         // Create the render array for the block as a whole.
         // @see template_preprocess_block().
         $build[$entity_id] = array('#theme' => 'block', '#attributes' => array(), '#contextual_links' => array('block' => array('route_parameters' => array('block' => $entity->id()))), '#weight' => $entity->get('weight'), '#configuration' => $configuration, '#plugin_id' => $plugin_id, '#base_plugin_id' => $base_id, '#derivative_plugin_id' => $derivative_id, '#id' => $entity->id(), '#block' => $entity);
         $build[$entity_id]['#configuration']['label'] = String::checkPlain($configuration['label']);
         // Set cache tags; these always need to be set, whether the block is
         // cacheable or not, so that the page cache is correctly informed.
         $build[$entity_id]['#cache']['tags'] = NestedArray::mergeDeepArray(array($this->getCacheTag(), $entity->getCacheTag(), $entity->getListCacheTags(), $plugin->getCacheTags()));
         if ($plugin->isCacheable()) {
             $build[$entity_id]['#pre_render'][] = array($this, 'buildBlock');
             // Generic cache keys, with the block plugin's custom keys appended
             // (usually cache context keys like 'cache_context.user.roles').
             $default_cache_keys = array('entity_view', 'block', $entity->id(), $entity->language()->getId(), 'cache_context.theme');
             $max_age = $plugin->getCacheMaxAge();
             $build[$entity_id]['#cache'] += array('keys' => array_merge($default_cache_keys, $plugin->getCacheKeys()), 'bin' => $plugin->getCacheBin(), 'expire' => $max_age === Cache::PERMANENT ? Cache::PERMANENT : REQUEST_TIME + $max_age);
         } else {
             $build[$entity_id] = $this->buildBlock($build[$entity_id]);
         }
         // Don't run in ::buildBlock() to ensure cache keys can be altered. If an
         // alter hook wants to modify the block contents, it can append another
         // #pre_render hook.
         $this->moduleHandler()->alter(array('block_view', "block_view_{$base_id}"), $build[$entity_id], $plugin);
     }
     return $build;
 }
Exemplo n.º 2
0
 /**
  * {@inheritdoc}
  */
 public function alter(&$libraries, &$extension = NULL, &$context2 = NULL)
 {
     if ($extension === 'bootstrap') {
         $provider = $this->theme->getProvider();
         if ($assets = $provider->getAssets()) {
             $libraries['base-theme'] = NestedArray::mergeDeepArray([$assets, $libraries['base-theme']], TRUE);
             // Add a specific version and theme CSS overrides file.
             // @todo This should be retrieved by the Provider API.
             $version = $this->theme->getSetting('cdn_' . $provider->getPluginId() . '_version') ?: Bootstrap::FRAMEWORK_VERSION;
             $libraries['base-theme']['version'] = $version;
             $provider_theme = $this->theme->getSetting('cdn_' . $provider->getPluginId() . '_theme') ?: 'bootstrap';
             $provider_theme = $provider_theme === 'bootstrap' || $provider_theme === 'bootstrap_theme' ? '' : "-{$provider_theme}";
             foreach ($this->theme->getAncestry(TRUE) as $ancestor) {
                 $overrides = $ancestor->getPath() . "/css/{$version}/overrides{$provider_theme}.min.css";
                 if (file_exists($overrides)) {
                     // Since this uses a relative path to the ancestor from DRUPAL_ROOT,
                     // we must prefix the entire path with / so it doesn't append the
                     // active theme's path (which would duplicate the prefix).
                     $libraries['base-theme']['css']['theme']["/{$overrides}"] = [];
                     break;
                 }
             }
         }
     }
 }
Exemplo n.º 3
0
 /**
  * Drush execution method. Runs imports on the supplied manifest.
  */
 public function import()
 {
     /** @var \Drupal\migrate\MigrateTemplateStorage $template_storage */
     $template_storage = \Drupal::service('migrate.template_storage');
     $this->setupLegacyDb();
     $migration_ids = [];
     $migrations = [];
     foreach ($this->migrationList as $migration_info) {
         if (is_array($migration_info)) {
             // The migration is stored as the key in the info array.
             $migration_id = key($migration_info);
         } else {
             // If it wasn't an array then the info is just the migration_id.
             $migration_id = $migration_info;
         }
         $template = $template_storage->getTemplateByName($migration_id) ?: [];
         if (is_array($migration_info)) {
             // If there is some existing global overrides then we merge them in.
             if (isset($GLOBALS['config'][$migration_id])) {
                 $migration_info = NestedArray::mergeDeep($GLOBALS['config'][$migration_id], $migration_info);
             }
             $migration_info = NestedArray::mergeDeepArray([$template, $migration_info], TRUE);
         } else {
             $migration_info = $template;
         }
         if ($migration_info) {
             /** @var \Drupal\migrate\Entity\Migration[] $migrations */
             $migrations = \Drupal::service('migrate.migration_builder')->createMigrations([$migration_id => $migration_info]);
             foreach ($migrations as $migration) {
                 $migration_ids[] = $migration->id();
                 if (!Migration::load($migration->id())) {
                     $migration->save();
                 }
             }
             // We use these migration_ids to run migrations. If we didn't create
             // anything we pass it on and this will trigger non-existent migrations
             // messages or resolved by migration loading.
             // @todo this can return false positives in the non-existent migration
             // logic if the builder explicitly returned no results. For example, no
             // taxonomies will cause some things to be empty.
             if (!$migrations) {
                 $migration_ids[] = $migration_id;
             }
         }
     }
     // Load all the migrations at once so they're correctly ordered.
     foreach (Migration::loadMultiple($migration_ids) as $migration) {
         $executable = $this->executeMigration($migration);
         // Store all the migrations for later.
         $migrations[$migration->id()] = array('executable' => $executable, 'migration' => $migration, 'source' => $migration->get('source'), 'destination' => $migration->get('destination'));
     }
     // Warn the user if any migrations were not found.
     $nonexistent_migrations = array_diff($migration_ids, array_keys($migrations));
     if (count($nonexistent_migrations) > 0) {
         drush_log(dt('The following migrations were not found: @migrations', array('@migrations' => implode(', ', $nonexistent_migrations))), 'warning');
     }
     return $migrations;
 }
Exemplo n.º 4
0
 /**
  * Implements \Symfony\Component\Serializer\Normalizer\NormalizerInterface::normalize()
  */
 public function normalize($field, $format = NULL, array $context = array())
 {
     $normalized_field_items = array();
     $entity = $field->getEntity();
     $field_name = $field->getName();
     $field_definition = $field->getFieldDefinition();
     $normalized_field_items = $this->normalizeFieldItems($field, $format, $context);
     $normalized = NestedArray::mergeDeepArray($normalized_field_items);
     return $normalized;
 }
 /**
  * Returns the display objects used to render a set of entities.
  *
  * Depending on the configuration of the view mode for each bundle, this can
  * be either the display object associated to the view mode, or the 'default'
  * display.
  *
  * This method should only be used internally when rendering an entity. When
  * assigning suggested display options for a component in a given view mode,
  * entity_get_display() should be used instead, in order to avoid
  * inadvertently modifying the output of other view modes that might happen to
  * use the 'default' display too. Those options will then be effectively
  * applied only if the view mode is configured to use them.
  *
  * hook_entity_view_display_alter() is invoked on each display, allowing 3rd
  * party code to alter the display options held in the display before they are
  * used to generate render arrays.
  *
  * @param \Drupal\Core\Entity\FieldableEntityInterface[] $entities
  *   The entities being rendered. They should all be of the same entity type.
  * @param string $view_mode
  *   The view mode being rendered.
  *
  * @return \Drupal\Core\Entity\Display\EntityViewDisplayInterface[]
  *   The display objects to use to render the entities, keyed by entity
  *   bundle.
  *
  * @see entity_get_display()
  * @see hook_entity_view_display_alter()
  */
 public static function collectRenderDisplays($entities, $view_mode)
 {
     if (empty($entities)) {
         return array();
     }
     // Collect entity type and bundles.
     $entity_type = current($entities)->getEntityTypeId();
     $bundles = array();
     foreach ($entities as $entity) {
         $bundles[$entity->bundle()] = TRUE;
     }
     $bundles = array_keys($bundles);
     // For each bundle, check the existence and status of:
     // - the display for the view mode,
     // - the 'default' display.
     $candidate_ids = array();
     foreach ($bundles as $bundle) {
         if ($view_mode != 'default') {
             $candidate_ids[$bundle][] = $entity_type . '.' . $bundle . '.' . $view_mode;
         }
         $candidate_ids[$bundle][] = $entity_type . '.' . $bundle . '.default';
     }
     $results = \Drupal::entityQuery('entity_view_display')->condition('id', NestedArray::mergeDeepArray($candidate_ids))->condition('status', TRUE)->execute();
     // For each bundle, select the first valid candidate display, if any.
     $load_ids = array();
     foreach ($bundles as $bundle) {
         foreach ($candidate_ids[$bundle] as $candidate_id) {
             if (isset($results[$candidate_id])) {
                 $load_ids[$bundle] = $candidate_id;
                 break;
             }
         }
     }
     // Load the selected displays.
     $storage = \Drupal::entityManager()->getStorage('entity_view_display');
     $displays = $storage->loadMultiple($load_ids);
     $displays_by_bundle = array();
     foreach ($bundles as $bundle) {
         // Use the selected display if any, or create a fresh runtime object.
         if (isset($load_ids[$bundle])) {
             $display = $displays[$load_ids[$bundle]];
         } else {
             $display = $storage->create(array('targetEntityType' => $entity_type, 'bundle' => $bundle, 'mode' => $view_mode, 'status' => TRUE));
         }
         // Let the display know which view mode was originally requested.
         $display->originalMode = $view_mode;
         // Let modules alter the display.
         $display_context = array('entity_type' => $entity_type, 'bundle' => $bundle, 'view_mode' => $view_mode);
         \Drupal::moduleHandler()->alter('entity_view_display', $display, $display_context);
         $displays_by_bundle[$bundle] = $display;
     }
     return $displays_by_bundle;
 }
Exemplo n.º 6
0
 /**
  * Retrieves enabled plugins' files, keyed by plugin ID.
  *
  * For CKEditor plugins that implement:
  *  - CKEditorPluginButtonsInterface, not CKEditorPluginContextualInterface,
  *     a plugin is enabled if at least one of its buttons is in the toolbar;
  *  - CKEditorPluginContextualInterface, not CKEditorPluginButtonsInterface,
  *     a plugin is enabled if its isEnabled() method returns TRUE
  *  - both of these interfaces, a plugin is enabled if either is the case.
  *
  * Internal plugins (those that are part of the bundled build of CKEditor) are
  * excluded by default, since they are loaded implicitly. If you need to know
  * even implicitly loaded (i.e. internal) plugins, then set the optional
  * second parameter.
  *
  * @param \Drupal\editor\Entity\Editor $editor
  *   A configured text editor object.
  * @param bool $include_internal_plugins
  *   Defaults to FALSE. When set to TRUE, plugins whose isInternal() method
  *   returns TRUE will also be included.
  * @return array
  *   A list of the enabled CKEditor plugins, with the plugin IDs as keys and
  *   the Drupal root-relative plugin files as values.
  *   For internal plugins, the value is NULL.
  */
 public function getEnabledPluginFiles(Editor $editor, $include_internal_plugins = FALSE)
 {
     $plugins = array_keys($this->getDefinitions());
     // Flatten each row.
     $toolbar_rows = array();
     $settings = $editor->getSettings();
     foreach ($settings['toolbar']['rows'] as $row_number => $row) {
         $toolbar_rows[] = array_reduce($settings['toolbar']['rows'][$row_number], function (&$result, $button_group) {
             return array_merge($result, $button_group['items']);
         }, array());
     }
     $toolbar_buttons = array_unique(NestedArray::mergeDeepArray($toolbar_rows));
     $enabled_plugins = array();
     $additional_plugins = array();
     foreach ($plugins as $plugin_id) {
         $plugin = $this->createInstance($plugin_id);
         if (!$include_internal_plugins && $plugin->isInternal()) {
             continue;
         }
         $enabled = FALSE;
         // Enable this plugin if it provides a button that has been enabled.
         if ($plugin instanceof CKEditorPluginButtonsInterface) {
             $plugin_buttons = array_keys($plugin->getButtons());
             $enabled = count(array_intersect($toolbar_buttons, $plugin_buttons)) > 0;
         }
         // Otherwise enable this plugin if it declares itself as enabled.
         if (!$enabled && $plugin instanceof CKEditorPluginContextualInterface) {
             $enabled = $plugin->isEnabled($editor);
         }
         if ($enabled) {
             $enabled_plugins[$plugin_id] = $plugin->isInternal() ? NULL : $plugin->getFile();
             // Check if this plugin has dependencies that also need to be enabled.
             $additional_plugins = array_merge($additional_plugins, array_diff($plugin->getDependencies($editor), $additional_plugins));
         }
     }
     // Add the list of dependent plugins.
     foreach ($additional_plugins as $plugin_id) {
         $plugin = $this->createInstance($plugin_id);
         $enabled_plugins[$plugin_id] = $plugin->isInternal() ? NULL : $plugin->getFile();
     }
     // Always return plugins in the same order.
     asort($enabled_plugins);
     return $enabled_plugins;
 }
Exemplo n.º 7
0
 /**
  * {@inheritdoc}
  */
 public function alter(&$libraries, &$extension = NULL, &$context2 = NULL)
 {
     if ($extension === 'bootstrap') {
         // Retrieve the theme's CDN provider and assets.
         $provider = $this->theme->getProvider();
         $assets = $provider ? $provider->getAssets() : [];
         // Immediately return if there is no provider or assets.
         if (!$provider || !$assets) {
             return;
         }
         // Merge the assets into the library info.
         $libraries['theme'] = NestedArray::mergeDeepArray([$assets, $libraries['theme']], TRUE);
         // Add a specific version and theme CSS overrides file.
         // @todo This should be retrieved by the Provider API.
         $version = $this->theme->getSetting('cdn_' . $provider->getPluginId() . '_version') ?: Bootstrap::FRAMEWORK_VERSION;
         $libraries['theme']['version'] = $version;
         $provider_theme = $this->theme->getSetting('cdn_' . $provider->getPluginId() . '_theme') ?: 'bootstrap';
         $provider_theme = $provider_theme === 'bootstrap' || $provider_theme === 'bootstrap_theme' ? '' : "-{$provider_theme}";
         foreach ($this->theme->getAncestry(TRUE) as $ancestor) {
             $overrides = $ancestor->getPath() . "/css/{$version}/overrides{$provider_theme}.min.css";
             if (file_exists($overrides)) {
                 // Since this uses a relative path to the ancestor from DRUPAL_ROOT,
                 // we must prepend the entire path with forward slash (/) so it
                 // doesn't prepend the active theme's path.
                 $overrides = "/{$overrides}";
                 // The overrides file must also be stored in the "base" category so
                 // it isn't added after any potential sub-theme's "theme" category.
                 // There's no weight, so it will be added after the provider's assets.
                 // @see https://www.drupal.org/node/2770613
                 $libraries['theme']['css']['base'][$overrides] = [];
                 break;
             }
         }
     } elseif ($extension === 'core') {
         // Replace core dialog/jQuery UI implementations with Bootstrap Modals.
         if ($this->theme->getSetting('modal_enabled')) {
             $libraries['drupal.dialog']['override'] = 'bootstrap/drupal.dialog';
             $libraries['drupal.dialog.ajax']['override'] = 'bootstrap/drupal.dialog.ajax';
         }
     }
 }
Exemplo n.º 8
0
 /**
  * Implements \Symfony\Component\Serializer\Normalizer\NormalizerInterface::normalize()
  */
 public function normalize($field, $format = NULL, array $context = array())
 {
     $normalized_field_items = array();
     // Get the field definition.
     $entity = $field->getEntity();
     $field_name = $field->getName();
     $field_definition = $field->getFieldDefinition();
     // If this field is not translatable, it can simply be normalized without
     // separating it into different translations.
     if (!$field_definition->isTranslatable()) {
         $normalized_field_items = $this->normalizeFieldItems($field, $format, $context);
     } else {
         foreach ($entity->getTranslationLanguages() as $language) {
             $context['langcode'] = $language->id;
             $translation = $entity->getTranslation($language->id);
             $translated_field = $translation->get($field_name);
             $normalized_field_items = array_merge($normalized_field_items, $this->normalizeFieldItems($translated_field, $format, $context));
         }
     }
     // Merge deep so that links set in entity reference normalizers are merged
     // into the links property.
     $normalized = NestedArray::mergeDeepArray($normalized_field_items);
     return $normalized;
 }
Exemplo n.º 9
0
 /**
  * {@inheritdoc}
  */
 public function alter(&$libraries, &$extension = NULL, &$context2 = NULL)
 {
     if ($extension === 'bootstrap') {
         // Retrieve the theme's CDN provider and assets.
         $provider = $this->theme->getProvider();
         $assets = $provider ? $provider->getAssets() : [];
         // Immediately return if there is no provider or assets.
         if (!$provider || !$assets) {
             return;
         }
         // Merge the assets into the library info.
         $libraries['base-theme'] = NestedArray::mergeDeepArray([$assets, $libraries['base-theme']], TRUE);
         // Add a specific version and theme CSS overrides file.
         // @todo This should be retrieved by the Provider API.
         $version = $this->theme->getSetting('cdn_' . $provider->getPluginId() . '_version') ?: Bootstrap::FRAMEWORK_VERSION;
         $libraries['base-theme']['version'] = $version;
         $provider_theme = $this->theme->getSetting('cdn_' . $provider->getPluginId() . '_theme') ?: 'bootstrap';
         $provider_theme = $provider_theme === 'bootstrap' || $provider_theme === 'bootstrap_theme' ? '' : "-{$provider_theme}";
         foreach ($this->theme->getAncestry(TRUE) as $ancestor) {
             $overrides = $ancestor->getPath() . "/css/{$version}/overrides{$provider_theme}.min.css";
             if (file_exists($overrides)) {
                 // Since this uses a relative path to the ancestor from DRUPAL_ROOT,
                 // we must prefix the entire path with / so it doesn't append the
                 // active theme's path (which would duplicate the prefix).
                 $libraries['base-theme']['css']['theme']["/{$overrides}"] = [];
                 break;
             }
         }
     } elseif ($extension === 'core') {
         // Replace core dialog/jQuery UI implementations with Bootstrap Modals.
         if ($this->theme->getSetting('modal_enabled')) {
             $libraries['drupal.dialog']['override'] = 'bootstrap/drupal.dialog';
             $libraries['drupal.dialog.ajax']['override'] = 'bootstrap/drupal.dialog.ajax';
         }
     }
 }
Exemplo n.º 10
0
 /**
  * Sets a configuration override for the given name.
  *
  * @param string $name
  *   The configuration object name to override.
  * @param array $values
  *   The values in the configuration object to override.
  *
  * @return $this
  */
 public function setOverride($name, array $values)
 {
     if (in_array($name, $this->names)) {
         if (isset($this->overrides[$name])) {
             // Existing overrides take precedence since these will have been added
             // by events with a higher priority.
             $this->overrides[$name] = NestedArray::mergeDeepArray(array($values, $this->overrides[$name]), TRUE);
         } else {
             $this->overrides[$name] = $values;
         }
     }
     return $this;
 }
Exemplo n.º 11
0
 /**
  * {@inheritdoc}
  */
 public function mergeProcessOfProperty($property, array $process_of_property)
 {
     // If we already have a process value then merge the incoming process array
     //otherwise simply set it.
     $current_process = $this->getProcess();
     if (isset($current_process[$property])) {
         $this->process = NestedArray::mergeDeepArray([$current_process, $this->getProcessNormalized([$property => $process_of_property])], TRUE);
     } else {
         $this->setProcessOfProperty($property, $process_of_property);
     }
     return $this;
 }
Exemplo n.º 12
0
 /**
  * Gets original data from this configuration object.
  *
  * Original data is the data as it is immediately after loading from
  * configuration storage before any changes. If this is a new configuration
  * object it will be an empty array.
  *
  * @see \Drupal\Core\Config\Config::get()
  *
  * @param string $key
  *   A string that maps to a key within the configuration data.
  * @param bool $apply_overrides
  *   Apply any overrides to the original data. Defaults to TRUE.
  *
  * @return mixed
  *   The data that was requested.
  */
 public function getOriginal($key = '', $apply_overrides = TRUE)
 {
     $original_data = $this->originalData;
     if ($apply_overrides) {
         // Apply overrides.
         if (isset($this->moduleOverrides) && is_array($this->moduleOverrides)) {
             $original_data = NestedArray::mergeDeepArray(array($original_data, $this->moduleOverrides), TRUE);
         }
         if (isset($this->settingsOverrides) && is_array($this->settingsOverrides)) {
             $original_data = NestedArray::mergeDeepArray(array($original_data, $this->settingsOverrides), TRUE);
         }
     }
     if (empty($key)) {
         return $original_data;
     } else {
         $parts = explode('.', $key);
         if (count($parts) == 1) {
             return isset($original_data[$key]) ? $original_data[$key] : NULL;
         } else {
             $value = NestedArray::getValue($original_data, $parts, $key_exists);
             return $key_exists ? $value : NULL;
         }
     }
 }
Exemplo n.º 13
0
 /**
  * Gets the enabled toolbar buttons in the given text editor instance.
  *
  * @param \Drupal\editor\Entity\Editor $editor
  *   A configured text editor object.
  *
  * @return string[]
  *   A list of the toolbar buttons enabled in the given text editor instance.
  */
 public static function getEnabledButtons(Editor $editor)
 {
     $toolbar_rows = [];
     $settings = $editor->getSettings();
     foreach ($settings['toolbar']['rows'] as $row_number => $row) {
         $toolbar_rows[] = array_reduce($settings['toolbar']['rows'][$row_number], function (&$result, $button_group) {
             return array_merge($result, $button_group['items']);
         }, []);
     }
     return array_unique(NestedArray::mergeDeepArray($toolbar_rows));
 }
Exemplo n.º 14
0
 /**
  * {@inheritdoc}
  */
 public function mergeAttachments(array $a, array $b)
 {
     // If both #attached arrays contain drupalSettings, then merge them
     // correctly; adding the same settings multiple times needs to behave
     // idempotently.
     if (!empty($a['drupalSettings']) && !empty($b['drupalSettings'])) {
         $drupalSettings = NestedArray::mergeDeepArray(array($a['drupalSettings'], $b['drupalSettings']), TRUE);
         // No need for re-merging them.
         unset($a['drupalSettings']);
         unset($b['drupalSettings']);
     }
     // Apply the normal merge.
     $a = array_merge_recursive($a, $b);
     if (isset($drupalSettings)) {
         // Save the custom merge for the drupalSettings.
         $a['drupalSettings'] = $drupalSettings;
     }
     return $a;
 }
 /**
  * Pre-render callback: Renders a processed text element into #markup.
  *
  * Runs all the enabled filters on a piece of text.
  *
  * Note: Because filters can inject JavaScript or execute PHP code, security
  * is vital here. When a user supplies a text format, you should validate it
  * using $format->access() before accepting/using it. This is normally done in
  * the validation stage of the Form API. You should for example never make a
  * preview of content in a disallowed format.
  *
  * @param array $element
  *   A structured array with the following key-value pairs:
  *   - #text: containing the text to be filtered
  *   - #format: containing the machine name of the filter format to be used to
  *     filter the text. Defaults to the fallback format.
  *   - #langcode: the language code of the text to be filtered, e.g. 'en' for
  *     English. This allows filters to be language-aware so language-specific
  *     text replacement can be implemented. Defaults to an empty string.
  *   - #filter_types_to_skip: an array of filter types to skip, or an empty
  *     array (default) to skip no filter types. All of the format's filters
  *     will be applied, except for filters of the types that are marked to be
  *     skipped. FilterInterface::TYPE_HTML_RESTRICTOR is the only type that
  *     cannot be skipped.
  *
  * @return array
  *   The passed-in element with the filtered text in '#markup'.
  *
  * @ingroup sanitization
  */
 public static function preRenderText($element)
 {
     $format_id = $element['#format'];
     $filter_types_to_skip = $element['#filter_types_to_skip'];
     $text = $element['#text'];
     $langcode = $element['#langcode'];
     if (!isset($format_id)) {
         $format_id = static::configFactory()->get('filter.settings')->get('fallback_format');
     }
     // If the requested text format does not exist, the text cannot be filtered.
     /** @var \Drupal\filter\Entity\FilterFormat $format **/
     if (!($format = FilterFormat::load($format_id))) {
         static::logger('filter')->alert('Missing text format: %format.', array('%format' => $format_id));
         $element['#markup'] = '';
         return $element;
     }
     $filter_must_be_applied = function (FilterInterface $filter) use($filter_types_to_skip) {
         $enabled = $filter->status === TRUE;
         $type = $filter->getType();
         // Prevent FilterInterface::TYPE_HTML_RESTRICTOR from being skipped.
         $filter_type_must_be_applied = $type == FilterInterface::TYPE_HTML_RESTRICTOR || !in_array($type, $filter_types_to_skip);
         return $enabled && $filter_type_must_be_applied;
     };
     // Convert all Windows and Mac newlines to a single newline, so filters only
     // need to deal with one possibility.
     $text = str_replace(array("\r\n", "\r"), "\n", $text);
     // Get a complete list of filters, ordered properly.
     /** @var \Drupal\filter\Plugin\FilterInterface[] $filters **/
     $filters = $format->filters();
     // Give filters a chance to escape HTML-like data such as code or formulas.
     foreach ($filters as $filter) {
         if ($filter_must_be_applied($filter)) {
             $text = $filter->prepare($text, $langcode);
         }
     }
     // Perform filtering.
     $cache_tags = array();
     $all_assets = array();
     $all_post_render_cache_callbacks = array();
     foreach ($filters as $filter) {
         if ($filter_must_be_applied($filter)) {
             $result = $filter->process($text, $langcode);
             $all_assets[] = $result->getAssets();
             $cache_tags = Cache::mergeTags($cache_tags, $result->getCacheTags());
             $all_post_render_cache_callbacks[] = $result->getPostRenderCacheCallbacks();
             $text = $result->getProcessedText();
         }
     }
     // Filtering done, store in #markup.
     $element['#markup'] = $text;
     // Collect all cache tags.
     if (isset($element['#cache']) && isset($element['#cache']['tags'])) {
         // Merge the original cache tags array.
         $cache_tags = Cache::mergeTags($cache_tags, $element['#cache']['tags']);
     }
     // Prepend the text format's cache tags array.
     $cache_tags = Cache::mergeTags($cache_tags, $format->getCacheTag());
     $element['#cache']['tags'] = $cache_tags;
     // Collect all attached assets.
     if (isset($element['#attached'])) {
         // Prepend the original attached assets array.
         array_unshift($all_assets, $element['#attached']);
     }
     $element['#attached'] = NestedArray::mergeDeepArray($all_assets);
     // Collect all #post_render_cache callbacks.
     if (isset($element['#post_render_cache'])) {
         // Prepend the original attached #post_render_cache array.
         array_unshift($all_assets, $element['#post_render_cache']);
     }
     $element['#post_render_cache'] = NestedArray::mergeDeepArray($all_post_render_cache_callbacks);
     return $element;
 }
Exemplo n.º 16
0
 /**
  * Returns the JavaScript settings assets for this response's libraries.
  *
  * Gathers all drupalSettings from all libraries in the attached assets
  * collection and merges them, then it merges individual attached settings,
  * and finally invokes hook_js_settings_alter() to allow alterations of
  * JavaScript settings by modules and themes.
  *
  * @param \Drupal\Core\Asset\AttachedAssetsInterface $assets
  *   The assets attached to the current response.
  * @return array
  *   A (possibly optimized) collection of JavaScript assets.
  */
 protected function getJsSettingsAssets(AttachedAssetsInterface $assets)
 {
     $settings = [];
     foreach ($this->getLibrariesToLoad($assets) as $library) {
         list($extension, $name) = explode('/', $library, 2);
         $definition = $this->libraryDiscovery->getLibraryByName($extension, $name);
         if (isset($definition['drupalSettings'])) {
             $settings = NestedArray::mergeDeepArray([$settings, $definition['drupalSettings']], TRUE);
         }
     }
     // Attached settings win over settings in libraries.
     $settings = NestedArray::mergeDeepArray([$settings, $assets->getSettings()], TRUE);
     return $settings;
 }
 /**
  * Merges multiple values into the array.
  *
  * @param array $values
  *   An associative key/value array.
  * @param bool $recursive
  *   Flag determining whether or not to recursively merge key/value pairs.
  */
 public function merge(array $values, $recursive = TRUE)
 {
     if ($recursive) {
         $this->array = NestedArray::mergeDeepArray([$this->array, $values], TRUE);
     } else {
         $this->array += $values;
     }
 }
Exemplo n.º 18
0
 /**
  * Returns the JavaScript settings assets for this response's libraries.
  *
  * Gathers all drupalSettings from all libraries in the attached assets
  * collection and merges them, then it merges individual attached settings,
  * and finally invokes hook_js_settings_alter() to allow alterations of
  * JavaScript settings by modules and themes.
  *
  * @param \Drupal\Core\Asset\AttachedAssetsInterface $assets
  *   The assets attached to the current response.
  * @return array
  *   A (possibly optimized) collection of JavaScript assets.
  */
 protected function getJsSettingsAssets(AttachedAssetsInterface $assets)
 {
     $settings = [];
     foreach ($this->getLibrariesToLoad($assets) as $library) {
         list($extension, $name) = explode('/', $library, 2);
         $definition = $this->libraryDiscovery->getLibraryByName($extension, $name);
         if (isset($definition['drupalSettings'])) {
             $settings = NestedArray::mergeDeepArray([$settings, $definition['drupalSettings']], TRUE);
         }
     }
     // Attached settings win over settings in libraries.
     $settings = NestedArray::mergeDeepArray([$settings, $assets->getSettings()], TRUE);
     // Allow modules and themes to alter the JavaScript settings.
     $this->moduleHandler->alter('js_settings', $settings, $assets);
     $this->themeManager->alter('js_settings', $settings, $assets);
     return $settings;
 }
 /**
  * {@inheritdoc}
  */
 public function getJsAssets(AttachedAssetsInterface $assets, $optimize)
 {
     $theme_info = $this->themeManager->getActiveTheme();
     // Add the theme name to the cache key since themes may implement
     // hook_library_info_alter(). Additionally add the current language to
     // support translation of JavaScript files via hook_js_alter().
     $libraries_to_load = $this->getLibrariesToLoad($assets);
     $cid = 'js:' . $theme_info->getName() . ':' . $this->languageManager->getCurrentLanguage()->getId() . ':' . Crypt::hashBase64(serialize($libraries_to_load)) . (int) (count($assets->getSettings()) > 0) . (int) $optimize;
     if ($cached = $this->cache->get($cid)) {
         list($js_assets_header, $js_assets_footer, $settings, $settings_in_header) = $cached->data;
     } else {
         $javascript = [];
         $default_options = ['type' => 'file', 'group' => JS_DEFAULT, 'weight' => 0, 'cache' => TRUE, 'preprocess' => TRUE, 'attributes' => [], 'version' => NULL, 'browsers' => []];
         // Collect all libraries that contain JS assets and are in the header.
         $header_js_libraries = [];
         foreach ($libraries_to_load as $library) {
             list($extension, $name) = explode('/', $library, 2);
             $definition = $this->libraryDiscovery->getLibraryByName($extension, $name);
             if (isset($definition['js']) && !empty($definition['header'])) {
                 $header_js_libraries[] = $library;
             }
         }
         // The current list of header JS libraries are only those libraries that
         // are in the header, but their dependencies must also be loaded for them
         // to function correctly, so update the list with those.
         $header_js_libraries = $this->libraryDependencyResolver->getLibrariesWithDependencies($header_js_libraries);
         foreach ($libraries_to_load as $library) {
             list($extension, $name) = explode('/', $library, 2);
             $definition = $this->libraryDiscovery->getLibraryByName($extension, $name);
             if (isset($definition['js'])) {
                 foreach ($definition['js'] as $options) {
                     $options += $default_options;
                     // 'scope' is a calculated option, based on which libraries are
                     // marked to be loaded from the header (see above).
                     $options['scope'] = in_array($library, $header_js_libraries) ? 'header' : 'footer';
                     // Preprocess can only be set if caching is enabled and no
                     // attributes are set.
                     $options['preprocess'] = $options['cache'] && empty($options['attributes']) ? $options['preprocess'] : FALSE;
                     // Always add a tiny value to the weight, to conserve the insertion
                     // order.
                     $options['weight'] += count($javascript) / 1000;
                     // Local and external files must keep their name as the associative
                     // key so the same JavaScript file is not added twice.
                     $javascript[$options['data']] = $options;
                 }
             }
         }
         // Allow modules and themes to alter the JavaScript assets.
         $this->moduleHandler->alter('js', $javascript, $assets);
         $this->themeManager->alter('js', $javascript, $assets);
         // Sort JavaScript assets, so that they appear in the correct order.
         uasort($javascript, 'static::sort');
         // Prepare the return value: filter JavaScript assets per scope.
         $js_assets_header = [];
         $js_assets_footer = [];
         foreach ($javascript as $key => $item) {
             if ($item['scope'] == 'header') {
                 $js_assets_header[$key] = $item;
             } elseif ($item['scope'] == 'footer') {
                 $js_assets_footer[$key] = $item;
             }
         }
         if ($optimize) {
             $collection_optimizer = \Drupal::service('asset.js.collection_optimizer');
             $js_assets_header = $collection_optimizer->optimize($js_assets_header);
             $js_assets_footer = $collection_optimizer->optimize($js_assets_footer);
         }
         // If the core/drupalSettings library is being loaded or is already
         // loaded, get the JavaScript settings assets, and convert them into a
         // single "regular" JavaScript asset.
         $libraries_to_load = $this->getLibrariesToLoad($assets);
         $settings_required = in_array('core/drupalSettings', $libraries_to_load) || in_array('core/drupalSettings', $this->libraryDependencyResolver->getLibrariesWithDependencies($assets->getAlreadyLoadedLibraries()));
         $settings_have_changed = count($libraries_to_load) > 0 || count($assets->getSettings()) > 0;
         // Initialize settings to FALSE since they are not needed by default. This
         // distinguishes between an empty array which must still allow
         // hook_js_settings_alter() to be run.
         $settings = FALSE;
         if ($settings_required && $settings_have_changed) {
             $settings = $this->getJsSettingsAssets($assets);
             // Allow modules to add cached JavaScript settings.
             foreach ($this->moduleHandler->getImplementations('js_settings_build') as $module) {
                 $function = $module . '_' . 'js_settings_build';
                 $function($settings, $assets);
             }
         }
         $settings_in_header = in_array('core/drupalSettings', $header_js_libraries);
         $this->cache->set($cid, [$js_assets_header, $js_assets_footer, $settings, $settings_in_header], CacheBackendInterface::CACHE_PERMANENT, ['library_info']);
     }
     if ($settings !== FALSE) {
         // Attached settings override both library definitions and
         // hook_js_settings_build().
         $settings = NestedArray::mergeDeepArray([$settings, $assets->getSettings()], TRUE);
         // Allow modules and themes to alter the JavaScript settings.
         $this->moduleHandler->alter('js_settings', $settings, $assets);
         $this->themeManager->alter('js_settings', $settings, $assets);
         // Update the $assets object accordingly, so that it reflects the final
         // settings.
         $assets->setSettings($settings);
         $settings_as_inline_javascript = ['type' => 'setting', 'group' => JS_SETTING, 'weight' => 0, 'browsers' => [], 'data' => $settings];
         $settings_js_asset = ['drupalSettings' => $settings_as_inline_javascript];
         // Prepend to the list of JS assets, to render it first. Preferably in
         // the footer, but in the header if necessary.
         if ($settings_in_header) {
             $js_assets_header = $settings_js_asset + $js_assets_header;
         } else {
             $js_assets_footer = $settings_js_asset + $js_assets_footer;
         }
     }
     return [$js_assets_header, $js_assets_footer];
 }
Exemplo n.º 20
0
 /**
  * {@inheritdoc}
  */
 public function viewElements(FieldItemListInterface $items)
 {
     $elements = array();
     // Check if the formatter involves a link.
     if ($this->getSetting('image_link') == 'content') {
         $uri = $items->getEntity()->urlInfo();
         // @todo Remove when theme_responsive_image_formatter() has support for route name.
         $uri['path'] = $items->getEntity()->getSystemPath();
     } elseif ($this->getSetting('image_link') == 'file') {
         $link_file = TRUE;
     }
     $breakpoint_styles = array();
     $fallback_image_style = '';
     $responsive_image_mapping = entity_load('responsive_image_mapping', $this->getSetting('responsive_image_mapping'));
     if ($responsive_image_mapping) {
         foreach ($responsive_image_mapping->getMappings() as $breakpoint_name => $multipliers) {
             // Make sure there are multipliers.
             if (!empty($multipliers)) {
                 // Make sure that the breakpoint exists and is enabled.
                 // @todo add the following when breakpoint->status is added again:
                 // $responsive_image_mapping->breakpointGroup->breakpoints[$breakpoint_name]->status
                 $breakpoint = $responsive_image_mapping->getBreakpointGroup()->getBreakpointById($breakpoint_name);
                 if ($breakpoint) {
                     // Determine the enabled multipliers.
                     $multipliers = array_intersect_key($multipliers, $breakpoint->multipliers);
                     foreach ($multipliers as $multiplier => $image_style) {
                         // Make sure the multiplier still exists.
                         if (!empty($image_style)) {
                             // First mapping found is used as fallback.
                             if (empty($fallback_image_style)) {
                                 $fallback_image_style = $image_style;
                             }
                             if (!isset($breakpoint_styles[$breakpoint_name])) {
                                 $breakpoint_styles[$breakpoint_name] = array();
                             }
                             $breakpoint_styles[$breakpoint_name][$multiplier] = $image_style;
                         }
                     }
                 }
             }
         }
     }
     // Check if the user defined a custom fallback image style.
     if ($this->getSetting('fallback_image_style')) {
         $fallback_image_style = $this->getSetting('fallback_image_style');
     }
     // Collect cache tags to be added for each item in the field.
     $all_cache_tags = array();
     if ($responsive_image_mapping) {
         $all_cache_tags[] = $responsive_image_mapping->getCacheTag();
         foreach ($breakpoint_styles as $breakpoint_name => $style_per_multiplier) {
             foreach ($style_per_multiplier as $multiplier => $image_style_name) {
                 $image_style = entity_load('image_style', $image_style_name);
                 $all_cache_tags[] = $image_style->getCacheTag();
             }
         }
     }
     if ($fallback_image_style) {
         $image_style = entity_load('image_style', $fallback_image_style);
         $all_cache_tags[] = $image_style->getCacheTag();
     }
     $cache_tags = NestedArray::mergeDeepArray($all_cache_tags);
     foreach ($items as $delta => $item) {
         if (isset($link_file)) {
             $uri = array('path' => file_create_url($item->entity->getFileUri()), 'options' => array());
         }
         $elements[$delta] = array('#theme' => 'responsive_image_formatter', '#attached' => array('library' => array('core/picturefill')), '#item' => $item, '#image_style' => $fallback_image_style, '#breakpoints' => $breakpoint_styles, '#path' => isset($uri) ? $uri : '', '#cache' => array('tags' => $cache_tags));
     }
     return $elements;
 }
 /**
  * {@inheritdoc}
  */
 public function mergeOverrideArrayDefinition(array $other_definition)
 {
     $this->arrayDefinition = NestedArray::mergeDeepArray([$this->arrayDefinition, $other_definition], TRUE);
     return $this;
 }
Exemplo n.º 22
0
 /**
  * Updates all configuration translations for the names / languages provided.
  *
  * To be used when interface translation changes result in the need to update
  * configuration translations to keep them in sync.
  *
  * @param array $names
  *   Array of names of configuration objects to update.
  * @param array $langcodes
  *   (optional) Array of language codes to update. Defaults to all
  *   configurable languages.
  *
  * @return int
  *   Total number of configuration override and active configuration objects
  *   updated (saved or removed).
  */
 public function updateConfigTranslations(array $names, array $langcodes = array())
 {
     $langcodes = $langcodes ? $langcodes : array_keys($this->languageManager->getLanguages());
     $count = 0;
     foreach ($names as $name) {
         $translatable = $this->getTranslatableDefaultConfig($name);
         if (empty($translatable)) {
             // If there is nothing translatable in this configuration or not
             // supported, skip it.
             continue;
         }
         $active_langcode = $this->getActiveConfigLangcode($name);
         $active = $this->configStorage->read($name);
         foreach ($langcodes as $langcode) {
             $processed = $this->processTranslatableData($name, $active, $translatable, $langcode);
             if ($langcode != $active_langcode) {
                 // If the language code is not the same as the active storage
                 // language, we should update a configuration override.
                 if (!empty($processed)) {
                     // Update translation data in configuration override.
                     $this->saveTranslationOverride($name, $langcode, $processed);
                     $count++;
                 } else {
                     $override = $this->languageManager->getLanguageConfigOverride($langcode, $name);
                     if (!$override->isNew()) {
                         $data = $this->filterOverride($override->get(), $translatable);
                         if (empty($data)) {
                             // Delete language override if there is no data left at all.
                             // This means all prior translations in the override were locale
                             // managed.
                             $this->deleteTranslationOverride($name, $langcode);
                             $count++;
                         } else {
                             // If there were translatable elements besides locale managed
                             // items, save with only those, and remove the ones managed
                             // by locale only.
                             $this->saveTranslationOverride($name, $langcode, $data);
                             $count++;
                         }
                     }
                 }
             } elseif (locale_is_translatable($langcode)) {
                 // If the language code is the active storage language, we should
                 // update. If it is English, we should only update if English is also
                 // translatable.
                 $active = NestedArray::mergeDeepArray(array($active, $processed), TRUE);
                 $this->saveTranslationActive($name, $active);
                 $count++;
             }
         }
     }
     return $count;
 }
Exemplo n.º 23
0
 /**
  * Get arbitrary overrides for the named configuration objects from modules.
  *
  * @param array $names
  *   The names of the configuration objects to get overrides for.
  *
  * @return array
  *   An array of overrides keyed by the configuration object name.
  */
 protected function loadOverrides(array $names)
 {
     $overrides = array();
     foreach ($this->configFactoryOverrides as $override) {
         // Existing overrides take precedence since these will have been added
         // by events with a higher priority.
         $overrides = NestedArray::mergeDeepArray(array($override->loadOverrides($names), $overrides), TRUE);
     }
     return $overrides;
 }
Exemplo n.º 24
0
 /**
  * Preprocess theme hook variables.
  *
  * @param array $variables
  *   The variables array, passed by reference.
  * @param string $hook
  *   The name of the theme hook.
  * @param array $info
  *   The theme hook info.
  */
 public static function preprocess(array &$variables, $hook, array $info)
 {
     static $theme;
     if (!isset($theme)) {
         $theme = self::getTheme();
     }
     static $preprocess_manager;
     if (!isset($preprocess_manager)) {
         $preprocess_manager = new PreprocessManager($theme);
     }
     // Ensure that any default theme hook variables exist. Due to how theme
     // hook suggestion alters work, the variables provided are from the
     // original theme hook, not the suggestion.
     if (isset($info['variables'])) {
         $variables = NestedArray::mergeDeepArray([$info['variables'], $variables], TRUE);
     }
     // Add extra variables to all theme hooks.
     foreach (Bootstrap::extraVariables() as $key => $value) {
         if (!isset($variables[$key])) {
             $variables[$key] = $value;
         }
     }
     // Add active theme context.
     // @see https://www.drupal.org/node/2630870
     if (!isset($variables['theme'])) {
         $variables['theme'] = $theme->getInfo();
         $variables['theme']['name'] = $theme->getName();
         $variables['theme']['path'] = $theme->getPath();
         $variables['theme']['title'] = $theme->getTitle();
         $variables['theme']['settings'] = $theme->settings()->get();
         $variables['theme']['has_glyphicons'] = $theme->hasGlyphicons();
         $variables['theme']['query_string'] = \Drupal::getContainer()->get('state')->get('system.css_js_query_string') ?: '0';
     }
     // Invoke necessary preprocess plugin.
     if (isset($info['bootstrap preprocess'])) {
         if ($preprocess_manager->hasDefinition($info['bootstrap preprocess'])) {
             $class = $preprocess_manager->createInstance($info['bootstrap preprocess'], ['theme' => $theme]);
             /** @var \Drupal\bootstrap\Plugin\Preprocess\PreprocessInterface $class */
             $class->preprocess($variables, $hook, $info);
         }
     }
 }
Exemplo n.º 25
0
 /**
  * Implements \Drupal\ckeditor\Plugin\CKEditorPluginInterface::getConfig().
  */
 public function getConfig(Editor $editor)
 {
     // Reasonable defaults that provide expected basic behavior.
     $config = array('customConfig' => '', 'pasteFromWordPromptCleanup' => TRUE, 'resize_dir' => 'vertical', 'justifyClasses' => array('text-align-left', 'text-align-center', 'text-align-right', 'text-align-justify'), 'entities' => FALSE);
     // Add the allowedContent setting, which ensures CKEditor only allows tags
     // and attributes that are allowed by the text format for this text editor.
     list($config['allowedContent'], $config['disallowedContent']) = $this->generateACFSettings($editor);
     // Add the format_tags setting, if its button is enabled.
     $toolbar_rows = array();
     $settings = $editor->getSettings();
     foreach ($settings['toolbar']['rows'] as $row_number => $row) {
         $toolbar_rows[] = array_reduce($settings['toolbar']['rows'][$row_number], function (&$result, $button_group) {
             return array_merge($result, $button_group['items']);
         }, array());
     }
     $toolbar_buttons = array_unique(NestedArray::mergeDeepArray($toolbar_rows));
     if (in_array('Format', $toolbar_buttons)) {
         $config['format_tags'] = $this->generateFormatTagsSetting($editor);
     }
     return $config;
 }
Exemplo n.º 26
0
 /**
  * {@inheritdoc}
  */
 public function getDefinition($base_plugin_id, $exception_on_invalid = TRUE)
 {
     $definitions = $this->getDefinitions();
     if (isset($definitions[$base_plugin_id])) {
         $type = $base_plugin_id;
     } elseif (strpos($base_plugin_id, '.') && ($name = $this->getFallbackName($base_plugin_id))) {
         // Found a generic name, replacing the last element by '*'.
         $type = $name;
     } else {
         // If we don't have definition, return the 'undefined' element.
         $type = 'undefined';
     }
     $definition = $definitions[$type];
     // Check whether this type is an extension of another one and compile it.
     if (isset($definition['type'])) {
         $merge = $this->getDefinition($definition['type'], $exception_on_invalid);
         // Preserve integer keys on merge, so sequence item types can override
         // parent settings as opposed to adding unused second, third, etc. items.
         $definition = NestedArray::mergeDeepArray(array($merge, $definition), TRUE);
         // Unset type so we try the merge only once per type.
         unset($definition['type']);
         $this->definitions[$type] = $definition;
     }
     // Add type and default definition class.
     $definition += array('definition_class' => '\\Drupal\\Core\\TypedData\\DataDefinition', 'type' => $type);
     return $definition;
 }
Exemplo n.º 27
0
 /**
  * Merges data into a configuration object.
  *
  * @param array $data_to_merge
  *   An array containing data to merge.
  *
  * @return $this
  *   The configuration object.
  */
 public function merge(array $data_to_merge)
 {
     // Preserve integer keys so that configuration keys are not changed.
     $this->setData(NestedArray::mergeDeepArray(array($this->data, $data_to_merge), TRUE));
     return $this;
 }
 /**
  * Tests that array keys values on the first array are ignored when merging.
  *
  * Even if the initial ordering would place the data from the second array
  * before those in the first one, they are still appended, and the keys on
  * the first array are deleted and regenerated.
  *
  * @covers ::mergeDeepArray
  */
 public function testMergeOutOfSequenceKeys()
 {
     $a = array('subkey' => array(10 => 'A', 30 => 'B'));
     $b = array('subkey' => array(20 => 'C', 0 => 'D'));
     // Drupal core behavior.
     $expected = array('subkey' => array(0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D'));
     $actual = NestedArray::mergeDeepArray(array($a, $b));
     $this->assertSame($expected, $actual, 'drupal_array_merge_deep() ignores numeric key order when merging.');
 }
Exemplo n.º 29
0
 /**
  * Processes an AJAX response into current content.
  *
  * This processes the AJAX response as ajax.js does. It uses the response's
  * JSON data, an array of commands, to update $this->content using equivalent
  * DOM manipulation as is used by ajax.js.
  * It does not apply custom AJAX commands though, because emulation is only
  * implemented for the AJAX commands that ship with Drupal core.
  *
  * @param string $content
  *   The current HTML content.
  * @param array $ajax_response
  *   An array of AJAX commands.
  * @param array $ajax_settings
  *   An array of AJAX settings which will be used to process the response.
  * @param array $drupal_settings
  *   An array of settings to update the value of drupalSettings for the
  *   currently-loaded page.
  *
  * @see drupalPostAjaxForm()
  * @see ajax.js
  */
 protected function drupalProcessAjaxResponse($content, array $ajax_response, array $ajax_settings, array $drupal_settings)
 {
     // ajax.js applies some defaults to the settings object, so do the same
     // for what's used by this function.
     $ajax_settings += array('method' => 'replaceWith');
     // DOM can load HTML soup. But, HTML soup can throw warnings, suppress
     // them.
     $dom = new \DOMDocument();
     @$dom->loadHTML($content);
     // XPath allows for finding wrapper nodes better than DOM does.
     $xpath = new \DOMXPath($dom);
     foreach ($ajax_response as $command) {
         // Error messages might be not commands.
         if (!is_array($command)) {
             continue;
         }
         switch ($command['command']) {
             case 'settings':
                 $drupal_settings = NestedArray::mergeDeepArray([$drupal_settings, $command['settings']], TRUE);
                 break;
             case 'insert':
                 $wrapperNode = NULL;
                 // When a command doesn't specify a selector, use the
                 // #ajax['wrapper'] which is always an HTML ID.
                 if (!isset($command['selector'])) {
                     $wrapperNode = $xpath->query('//*[@id="' . $ajax_settings['wrapper'] . '"]')->item(0);
                 } elseif (in_array($command['selector'], array('head', 'body'))) {
                     $wrapperNode = $xpath->query('//' . $command['selector'])->item(0);
                 }
                 if ($wrapperNode) {
                     // ajax.js adds an enclosing DIV to work around a Safari bug.
                     $newDom = new \DOMDocument();
                     // DOM can load HTML soup. But, HTML soup can throw warnings,
                     // suppress them.
                     @$newDom->loadHTML('<div>' . $command['data'] . '</div>');
                     // Suppress warnings thrown when duplicate HTML IDs are encountered.
                     // This probably means we are replacing an element with the same ID.
                     $newNode = @$dom->importNode($newDom->documentElement->firstChild->firstChild, TRUE);
                     $method = isset($command['method']) ? $command['method'] : $ajax_settings['method'];
                     // The "method" is a jQuery DOM manipulation function. Emulate
                     // each one using PHP's DOMNode API.
                     switch ($method) {
                         case 'replaceWith':
                             $wrapperNode->parentNode->replaceChild($newNode, $wrapperNode);
                             break;
                         case 'append':
                             $wrapperNode->appendChild($newNode);
                             break;
                         case 'prepend':
                             // If no firstChild, insertBefore() falls back to
                             // appendChild().
                             $wrapperNode->insertBefore($newNode, $wrapperNode->firstChild);
                             break;
                         case 'before':
                             $wrapperNode->parentNode->insertBefore($newNode, $wrapperNode);
                             break;
                         case 'after':
                             // If no nextSibling, insertBefore() falls back to
                             // appendChild().
                             $wrapperNode->parentNode->insertBefore($newNode, $wrapperNode->nextSibling);
                             break;
                         case 'html':
                             foreach ($wrapperNode->childNodes as $childNode) {
                                 $wrapperNode->removeChild($childNode);
                             }
                             $wrapperNode->appendChild($newNode);
                             break;
                     }
                 }
                 break;
                 // @todo Add suitable implementations for these commands in order to
                 //   have full test coverage of what ajax.js can do.
             // @todo Add suitable implementations for these commands in order to
             //   have full test coverage of what ajax.js can do.
             case 'remove':
                 break;
             case 'changed':
                 break;
             case 'css':
                 break;
             case 'data':
                 break;
             case 'restripe':
                 break;
             case 'add_css':
                 break;
             case 'update_build_id':
                 $buildId = $xpath->query('//input[@name="form_build_id" and @value="' . $command['old'] . '"]')->item(0);
                 if ($buildId) {
                     $buildId->setAttribute('value', $command['new']);
                 }
                 break;
         }
     }
     $content = $dom->saveHTML();
     $this->setRawContent($content);
     $this->setDrupalSettings($drupal_settings);
 }
Exemplo n.º 30
0
 /**
  * Updates all configuration translations for the names / languages provided.
  *
  * To be used when interface translation changes result in the need to update
  * configuration translations to keep them in sync.
  *
  * @param array $names
  *   Array of names of configuration objects to update.
  * @param array $langcodes
  *   (optional) Array of language codes to update. Defaults to all
  *   configurable languages.
  *
  * @return int
  *   Total number of configuration override and active configuration objects
  *   updated (saved or removed).
  */
 public function updateConfigTranslations(array $names, array $langcodes = array())
 {
     $langcodes = $langcodes ? $langcodes : array_keys($this->languageManager->getLanguages());
     $count = 0;
     foreach ($names as $name) {
         $translatable = $this->getTranslatableDefaultConfig($name);
         if (empty($translatable)) {
             // If there is nothing translatable in this configuration or not
             // supported, skip it.
             continue;
         }
         $active_langcode = $this->getActiveConfigLangcode($name);
         $active = $this->configStorage->read($name);
         foreach ($langcodes as $langcode) {
             $processed = $this->processTranslatableData($name, $active, $translatable, $langcode);
             // If the language code is not the same as the active storage
             // language, we should update the configuration override.
             if ($langcode != $active_langcode) {
                 $override = $this->languageManager->getLanguageConfigOverride($langcode, $name);
                 // Filter out locale managed configuration keys so that translations
                 // removed from Locale will be reflected in the config override.
                 $data = $this->filterOverride($override->get(), $translatable);
                 if (!empty($processed)) {
                     // Merge in the Locale managed translations with existing data.
                     $data = NestedArray::mergeDeepArray(array($data, $processed), TRUE);
                 }
                 if (empty($data) && !$override->isNew()) {
                     // The configuration override contains Locale overrides that no
                     // longer exist.
                     $this->deleteTranslationOverride($name, $langcode);
                     $count++;
                 } elseif (!empty($data)) {
                     // Update translation data in configuration override.
                     $this->saveTranslationOverride($name, $langcode, $data);
                     $count++;
                 }
             } elseif (locale_is_translatable($langcode)) {
                 // If the language code is the active storage language, we should
                 // update. If it is English, we should only update if English is also
                 // translatable.
                 $active = NestedArray::mergeDeepArray(array($active, $processed), TRUE);
                 $this->saveTranslationActive($name, $active);
                 $count++;
             }
         }
     }
     return $count;
 }