Generator/YMLFile.php
protected function expandInlineItems($yaml_data_array, &$yaml) {
    if (empty($this->component_data['inline_levels_extra'])) {
      return;
    }

    foreach ($this->component_data['inline_levels_extra'] as $extra_expansion_rule) {
      // The rule address may use wildcards. Get a list of actual properties
      // to expand.
      $rule_address = $extra_expansion_rule['address'];
      $properties_to_expand = [];

      // Iterate recursively through the whole YAML data structure.
      $iterator = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($yaml_data_array), \RecursiveIteratorIterator::SELF_FIRST);
      foreach ($iterator as $key => $value) {
        $depth = $iterator->getDepth();
        if ($depth != count($rule_address) - 1) {
          // The current item's depth does not match the rule's address: skip.
          // Note that the iterator's notion of depth is zero-based.
          continue;
        }

        // Get the address of the iterator's current location.
        // See https://stackoverflow.com/questions/7590662/walk-array-recursively-and-print-the-path-of-the-walk
        $current_address = [];
        for ($i = 0; $i <= $depth; $i++) {
          $current_address[] = $iterator->getSubIterator($i)->key();
        }

        // Compare the current address with the rule address.
        for ($i = 0; $i <= $depth; $i++) {
          if ($rule_address[$i] == '*') {
            // Wildcard matches anything: pass this level.
            continue;
          }

          if ($rule_address[$i] != $current_address[$i]) {
            // There is a mismatch: give up on this item in the iterator and
            // move on to the next.
            continue 2;
          }
        }

        // If we are still here, all levels of the current address passed the
        // comparison with the rule address: the address is valid.
        $properties_to_expand[] = $current_address;
      }

      foreach ($properties_to_expand as $property) {
        // Get the value for the property.
        $value = NestedArray::getValue($yaml_data_array, $property);
        // Create a YAML subarray that has the key for the value.
        $key = end($property);
        $yaml_data_sub_array = [
          $key => $value,
        ];

        $yaml_parser = new \Symfony\Component\Yaml\Yaml;

        $original = $yaml_parser->dump($yaml_data_sub_array, 1, static::YAML_INDENT);
        $replacement = $yaml_parser->dump($yaml_data_sub_array, 2, static::YAML_INDENT);

        // We need to put the right indent at the front of all lines.
        // The indent is one level less than the level of the address, which
        // itself is one less than the count of the address array.
        $indent = str_repeat('  ', static::YAML_INDENT * (count($property) - 2));
        $original = $indent . $original;
        $replacement = preg_replace('@^@m', $indent, $replacement);

        // Replace the inlined original YAML text with the multi-line
        // replacement.
        // WARNING: this is a bit dicey, as we might be replacing multiple
        // instances of this data, at ANY level!
        // However, since the only use of this so far is for services.yml
        // file tags, that's not a problem: YAGNI.
        // A better way to do this -- but far more complicated -- might be to
        // replace the data with a  placeholder token before we  generate the
        // YAML, so we are sure we are replacing the right thing.
        $yaml = str_replace($original, $replacement, $yaml);
      }
    }
  }
protected function expandInlineItems($yaml_data_array, &$yaml) {
    if (empty($this->component_data['inline_levels_extra'])) {
      return;
    }

    foreach ($this->component_data['inline_levels_extra'] as $extra_expansion_rule) {
      // The rule address may use wildcards. Get a list of actual properties
      // to expand.
      $rule_address = $extra_expansion_rule['address'];
      $properties_to_expand = [];

      // Iterate recursively through the whole YAML data structure.
      $iterator = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($yaml_data_array), \RecursiveIteratorIterator::SELF_FIRST);
      foreach ($iterator as $key => $value) {
        $depth = $iterator->getDepth();
        if ($depth != count($rule_address) - 1) {
          // The current item's depth does not match the rule's address: skip.
          // Note that the iterator's notion of depth is zero-based.
          continue;
        }

        // Get the address of the iterator's current location.
        // See https://stackoverflow.com/questions/7590662/walk-array-recursively-and-print-the-path-of-the-walk
        $current_address = [];
        for ($i = 0; $i <= $depth; $i++) {
          $current_address[] = $iterator->getSubIterator($i)->key();
        }

        // Compare the current address with the rule address.
        for ($i = 0; $i <= $depth; $i++) {
          if ($rule_address[$i] == '*') {
            // Wildcard matches anything: pass this level.
            continue;
          }

          if ($rule_address[$i] != $current_address[$i]) {
            // There is a mismatch: give up on this item in the iterator and
            // move on to the next.
            continue 2;
          }
        }

        // If we are still here, all levels of the current address passed the
        // comparison with the rule address: the address is valid.
        $properties_to_expand[] = $current_address;
      }

      foreach ($properties_to_expand as $property) {
        // Get the value for the property.
        $value = NestedArray::getValue($yaml_data_array, $property);
        // Create a YAML subarray that has the key for the value.
        $key = end($property);
        $yaml_data_sub_array = [
          $key => $value,
        ];

        $yaml_parser = new \Symfony\Component\Yaml\Yaml;

        $original = $yaml_parser->dump($yaml_data_sub_array, 1, static::YAML_INDENT);
        $replacement = $yaml_parser->dump($yaml_data_sub_array, 2, static::YAML_INDENT);

        // We need to put the right indent at the front of all lines.
        // The indent is one level less than the level of the address, which
        // itself is one less than the count of the address array.
        $indent = str_repeat('  ', static::YAML_INDENT * (count($property) - 2));
        $original = $indent . $original;
        $replacement = preg_replace('@^@m', $indent, $replacement);

        // Replace the inlined original YAML text with the multi-line
        // replacement.
        // WARNING: this is a bit dicey, as we might be replacing multiple
        // instances of this data, at ANY level!
        // However, since the only use of this so far is for services.yml
        // file tags, that's not a problem: YAGNI.
        // A better way to do this -- but far more complicated -- might be to
        // replace the data with a  placeholder token before we  generate the
        // YAML, so we are sure we are replacing the right thing.
        $yaml = str_replace($original, $replacement, $yaml);
      }
    }
  }
protected function expandInlineItems ( $ yaml_data_array , & $ yaml ) { if ( empty ( $ this -> component_data [ 'inline_levels_extra' ] ) ) { return ; } foreach ( $ this -> component_data [ 'inline_levels_extra' ] as $ extra_expansion_rule ) { // The rule address may use wildcards. Get a list of actual properties // to expand. $ rule_address = $ extra_expansion_rule [ 'address' ] ; $ properties_to_expand = [ ] ; // Iterate recursively through the whole YAML data structure. $ iterator = new \ RecursiveIteratorIterator ( new \ RecursiveArrayIterator ( $ yaml_data_array ) , \ RecursiveIteratorIterator :: SELF_FIRST ) ; foreach ( $ iterator as $ key => $ value ) { $ depth = $ iterator -> getDepth ( ) ; if ( $ depth != count ( $ rule_address ) - 1 ) { // The current item's depth does not match the rule's address: skip. // Note that the iterator's notion of depth is zero-based. continue ; } // Get the address of the iterator's current location. // See https://stackoverflow.com/questions/7590662/walk-array-recursively-and-print-the-path-of-the-walk $ current_address = [ ] ; for ( $ i = 0 ; $ i <= $ depth ; $ i ++ ) { $ current_address [ ] = $ iterator -> getSubIterator ( $ i ) -> key ( ) ; } // Compare the current address with the rule address. for ( $ i = 0 ; $ i <= $ depth ; $ i ++ ) { if ( $ rule_address [ $ i ] == '*' ) { // Wildcard matches anything: pass this level. continue ; } if ( $ rule_address [ $ i ] != $ current_address [ $ i ] ) { // There is a mismatch: give up on this item in the iterator and // move on to the next. continue 2 ; } } // If we are still here, all levels of the current address passed the // comparison with the rule address: the address is valid. $ properties_to_expand [ ] = $ current_address ; } foreach ( $ properties_to_expand as $ property ) { // Get the value for the property. $ value = NestedArray :: getValue ( $ yaml_data_array , $ property ) ; // Create a YAML subarray that has the key for the value. $ key = end ( $ property ) ; $ yaml_data_sub_array = [ $ key => $ value , ] ; $ yaml_parser = new \ Symfony \ Component \ Yaml \ Yaml ; $ original = $ yaml_parser -> dump ( $ yaml_data_sub_array , 1 , static :: YAML_INDENT ) ; $ replacement = $ yaml_parser -> dump ( $ yaml_data_sub_array , 2 , static :: YAML_INDENT ) ; // We need to put the right indent at the front of all lines. // The indent is one level less than the level of the address, which // itself is one less than the count of the address array. $ indent = str_repeat ( '  ' , static :: YAML_INDENT * ( count ( $ property ) - 2 ) ) ; $ original = $ indent . $ original ; $ replacement = preg_replace ( '@^@m' , $ indent , $ replacement ) ; // Replace the inlined original YAML text with the multi-line // replacement. // WARNING: this is a bit dicey, as we might be replacing multiple // instances of this data, at ANY level! // However, since the only use of this so far is for services.yml // file tags, that's not a problem: YAGNI. // A better way to do this -- but far more complicated -- might be to // replace the data with a  placeholder token before we  generate the // YAML, so we are sure we are replacing the right thing. $ yaml = str_replace ( $ original , $ replacement , $ yaml ) ; } } }
Change specified YAML properties from inlined to expanded.

We need this because some Drupal YAML files have variable levels of
inlining, and Symfony's YAML dumper does not support this, nor plan to:
see https://github.com/symfony/symfony/issues/19014#event-688175812.

For example, a services.yml file has 'arguments' and 'tags' at the same
level, but while 'arguments' is inlined, 'tags' is expanded, and inlined
one level lower:

@code
forum_manager:
class: Drupal\forum\ForumManager
arguments: ['@config.factory', '@entity.manager', '@database', '@string_translation', '@comment.manager']
tags:
- { name: backend_overridable }
@endcode

The properties to expand are specified in the 'inline_levels_extra'
component data. This is an array of rules, keyed by an arbitrary name,
where each rule is an array consisting of:
- 'address': An address array of the property or properties to expand.
This supports verbatim address pieces, and a '*' for a wildcard.
- 'level': NOT YET USED.

TODO: this is not currently run for YAML which puts line breaks between
blocks: there's no use case for this yet.

@param array $yaml_data_array
The original YAML data array.
@param string &$yaml
The generated YAML text.
Change specified YAML properties from inlined to expanded .