You are here

public function KmlEncoder::encode in KML 8

Overrides XmlEncoder::encode

File

src/Encoder/KmlEncoder.php, line 22

Class

KmlEncoder
Encodes KML data in XML.

Namespace

Drupal\kml\Encoder

Code

public function encode($data, $format, array $context = []) {
  $files2zip = [];
  $kmldata['Document'] = [
    'Placemark' => $data,
  ];
  foreach ($kmldata['Document']['Placemark'] as $i => &$placemark) {
    $folder = NULL;
    foreach ($placemark as $tag => $value) {
      switch ($tag) {
        case 'name':
        case 'description':
        case 'styleUrl':

          // Everything is ok as it is; no break here as we don't want to unset the perfectly correct original key.
          continue 2;
        case 'Folder':
          $folder = $value;
          break;

        // Leave 'coordinates' for backward compatibility.
        case 'coordinates':
        case 'Point_coordinates':
          $placemark['Point'] = [
            'coordinates' => $value,
          ];
          break;
        case 'LineString_coordinates':
          $placemark['LineString'] = [
            'coordinates' => $value,
          ];
          break;
        case 'icon':

          // If making a kmz, zip local icons into the archive and make sure the urls we write into kml are relative with no leading slash.
          if ($format == 'kmz' && !empty($value) && $this
            ->isLocal($value)) {
            $placemark['Style']['IconStyle']['Icon'] = [
              'href' => urldecode(ltrim($this
                ->relativizeUrl($value), '/')),
            ];
            $files2zip[DRUPAL_ROOT . '/' . $placemark['Style']['IconStyle']['Icon']['href']] = $placemark['Style']['IconStyle']['Icon']['href'];
          }
          else {

            // Else make sure all icon urls are absolute.
            $placemark['Style']['IconStyle']['Icon'] = [
              'href' => $this
                ->absolutizeUrl($value),
            ];
          }
          break;
        case 'atom_author':
          $placemark['atom:author']['atom:name'] = $value;
          break;
        case 'atom_link':
          $placemark['atom:link'] = [
            '@href' => $value,
          ];
          break;
        case 'gx_media_links':
          $placemark['ExtendedData']['Data'] = [
            '@name' => 'gx_media_links',
            'value' => $value,
          ];
          break;

        // Preformatted KML, as from GeoField in "escaped" mode.
        default:
          $value = html_entity_decode($value);
          if (substr($value, 0, 1) !== '<' || substr($value, -1) !== '>') {

            // Definitely not KML, just leave it alone.
            continue 2;
          }
          $kmlFragment = simplexml_load_string($value);

          // Merge recursively instead of simple assign to not accidentally overwrite the work of another field.
          // Recursively cast the SimpleXMLElementobject to array by means of json_encode/decode.
          // NB Can NOT just plant the object into the data array (even though Symfony xml encoder supports that)
          // for a variety of reasons too long to document here.
          $placemark = array_merge_recursive($placemark, [
            $kmlFragment
              ->getName() => json_decode(json_encode($kmlFragment
              ->children()), TRUE),
          ]);
      }

      // Clean up the original item as we just created a new correct one.
      unset($placemark[$tag]);
    }
    if ($folder !== NULL) {
      if (!isset($kmldata['Document']['Folder'])) {
        $kmldata['Document']['Folder'] = [];
      }
      $folderIndex = array_search($folder, array_column($kmldata['Document']['Folder'], 'name'));
      if ($folderIndex === FALSE) {
        $folderIndex = count($kmldata['Document']['Folder']);
        $kmldata['Document']['Folder'][$folderIndex]['name'] = $folder;
      }
      $kmldata['Document']['Folder'][$folderIndex]['Placemark'][] = $placemark;
      unset($kmldata['Document']['Placemark'][$i]);
    }
  }
  if (!count($kmldata['Document']['Placemark'])) {
    unset($kmldata['Document']['Placemark']);
  }
  $kml_header = empty($context['views_style_plugin']->options['kml_settings']['kml_header']) ? '' : \Drupal::token()
    ->replace($context['views_style_plugin']->options['kml_settings']['kml_header']);
  $context['xml_format_output'] = 'formatOutput';
  $context['xml_encoding'] = 'UTF-8';
  $context['xml_root_node_name'] = 'kml';
  $kmldata['@xmlns'] = 'http://www.opengis.net/kml/2.2';
  $kml = parent::getBaseEncoder()
    ->encode($kmldata, $format, $context);
  if (!empty($kml_header)) {
    $kml = str_replace("<Document>", "<Document>\n" . $kml_header, $kml);
  }
  if ($format == 'kmz') {
    $file_system = \Drupal::service('file_system');
    $temp_zip = file_unmanaged_save_data('', file_directory_temp() . '/kml_export.zip', FILE_EXISTS_RENAME);
    $zip = archiver_get_archiver($file_system
      ->realpath($temp_zip))
      ->getArchive();
    $temp_kml = $file_system
      ->realpath(file_unmanaged_save_data($kml, file_directory_temp() . '/doc.kml', FILE_EXISTS_RENAME));
    $zip
      ->addFile($temp_kml, 'doc.kml');
    foreach ($files2zip as $filename => $localname) {
      $zip
        ->addFile($filename, $localname);
    }
    $zip
      ->close();
    $kml = file_get_contents($temp_zip);
  }
  return $kml;
}