clean install

This commit is contained in:
2024-12-10 15:08:16 +01:00
commit e14eb2d8fd
31193 changed files with 3555714 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
name: farmOS KML
description: Provides KML features for farmOS.
type: module
package: farmOS
core_version_requirement: ^10
dependencies:
- farm:farm_geo

View File

@@ -0,0 +1,25 @@
<?php
/**
* @file
* Post update functions for farm_kml module.
*/
use Drupal\system\Entity\Action;
/**
* Move KML export actions to new farm_export_kml module.
*/
function farm_kml_post_update_move_kml_export_actions(&$sandbox = NULL) {
// Delete the existing KML export action config entities.
$configs = Action::loadMultiple(['asset_kml_action', 'log_kml_action']);
foreach ($configs as $config) {
$config->delete();
}
// Install the farm_export_kml module. This will recreate the actions.
if (!\Drupal::service('module_handler')->moduleExists('farm_export_kml')) {
\Drupal::service('module_installer')->install(['farm_export_kml']);
}
}

View File

@@ -0,0 +1,10 @@
services:
serializer.farm_kml.kml.encoder:
class: Drupal\farm_kml\Encoder\Kml
tags:
- { name: encoder, priority: 10, format: geometry_kml }
serializer.farm_kml.kml.geometry_wrapper:
class: Drupal\farm_kml\Normalizer\KmlNormalizer
arguments: ['@geofield.geophp']
tags:
- { name: normalizer, priority: 10 }

View File

@@ -0,0 +1,105 @@
<?php
namespace Drupal\farm_kml\Encoder;
use Drupal\serialization\Encoder\XmlEncoder;
/**
* Provides a KML encoder that extends from the XML encoder.
*
* An array of Placemark data prepared for XmlEncoder is expected when encoding.
*
* When decoding, the array of Placemark data is returned with an additional
* "xml" key containing the individual placemark XML in a string.
*
* @see \Symfony\Component\Serializer\Encoder\XmlEncoder
*
* @phpstan-ignore-next-line
*/
class Kml extends XmlEncoder {
/**
* {@inheritdoc}
*/
protected static $format = ['geometry_kml'];
/**
* {@inheritdoc}
*/
public function encode($data, $format, array $context = []): string {
// Build XML document to encode.
$xml = [
'@xmlns' => 'http://earth.google.com/kml/2.1',
'Document' => [
'Placemark' => array_filter(array_values($data)),
],
];
// Provide default context for the KML format.
$xml_context = [
'xml_version' => '1.0',
'xml_encoding' => 'UTF-8',
'xml_format_output' => TRUE,
'xml_root_node_name' => 'kml',
] + $context;
// Encode using the XML encoder.
return $this->getBaseEncoder()->encode($xml, 'xml', $xml_context);
}
/**
* {@inheritdoc}
*/
public function decode($data, $format, array $context = []): mixed {
// Start an array of decoded placemark data.
$decoded_placemarks = [];
// Build an XML object.
$xml = simplexml_load_string($data);
// If empty, or failed to parse, bail.
if (empty($xml)) {
return $decoded_placemarks;
}
// Determine the root. Sometimes it is "Document".
$root = $xml;
if (isset($xml->Document)) {
$root = $xml->Document;
}
// Start an array of placemarks to decode.
$placemarks = [];
// If the KML is organized into folders, iterate through them.
if (isset($root->Folder)) {
foreach ($root->Folder as $folder) {
if (isset($folder->Placemark)) {
foreach ($folder->Placemark as $placemark) {
$placemarks[] = $placemark;
}
}
}
}
// Also check the root for any placemarks.
if (isset($root->Placemark)) {
foreach ($root->Placemark as $placemark) {
$placemarks[] = $placemark;
}
}
// Decode each placemark into an array.
// Include the individual placemark as an XML string.
foreach ($placemarks as $placemark) {
$geometry = (array) $placemark;
$geometry['xml'] = $placemark->asXML();
$decoded_placemarks[] = $geometry;
}
return $decoded_placemarks;
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace Drupal\farm_kml;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceModifierInterface;
/**
* Adds kml as known format.
*/
class FarmKmlServiceProvider implements ServiceModifierInterface {
/**
* {@inheritdoc}
*/
public function alter(ContainerBuilder $container) {
if ($container->has('http_middleware.negotiation') && is_a($container->getDefinition('http_middleware.negotiation')->getClass(), '\Drupal\Core\StackMiddleware\NegotiationMiddleware', TRUE)) {
$container->getDefinition('http_middleware.negotiation')->addMethodCall('registerFormat', ['kml', ['application/vnd.google-earth.kml+xml']]);
}
}
}

View File

@@ -0,0 +1,160 @@
<?php
namespace Drupal\farm_kml\Normalizer;
use Drupal\farm_geo\GeometryWrapper;
use Drupal\geofield\GeoPHP\GeoPHPInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
/**
* Normalizes GeometryWrapper objects into array for the Kml encoder.
*
* @see \Drupal\farm_kml\Encoder\Kml
*/
class KmlNormalizer implements NormalizerInterface, DenormalizerInterface {
/**
* The supported format.
*/
const FORMAT = 'geometry_kml';
/**
* The supported type to denormalize to.
*/
const TYPE = GeometryWrapper::class;
/**
* The GeoPHP service.
*
* @var \Drupal\geofield\GeoPHP\GeoPHPInterface
*/
protected $geoPHP;
/**
* KMLNormalizer constructor.
*
* @param \Drupal\geofield\GeoPHP\GeoPHPInterface $geo_PHP
* The GeoPHP service.
*/
public function __construct(GeoPHPInterface $geo_PHP) {
$this->geoPHP = $geo_PHP;
}
/**
* {@inheritdoc}
*/
public function normalize($object, $format = NULL, array $context = []) {
/** @var \Drupal\farm_geo\GeometryWrapper $object */
// Convert the geometry to KML.
$kml_string = $object->geometry->out('kml');
// Parse the KML string into an XML object.
// This is necessary so that we can encode the KML into XML with the
// rest of the asset data.
$kml = simplexml_load_string($kml_string);
$kml_name = $kml->getName();
$kml_value = $kml->children();
// Build a placemark definition.
$placemark = [
'#' => [
$kml_name => $kml_value,
],
];
// Add an ID if provided.
if (isset($object->properties['id'])) {
$placemark['@id'] = $object->properties['id'];
}
// Add standard KML properties if provided.
$properties = $this->supportedProperties();
foreach ($properties as $property_name) {
if (isset($object->properties[$property_name])) {
$placemark['#'][$property_name] = $object->properties[$property_name];
}
}
return $placemark;
}
/**
* {@inheritdoc}
*/
public function supportsNormalization($data, $format = NULL) {
return $data instanceof GeometryWrapper && $format == static::FORMAT;
}
/**
* {@inheritdoc}
*/
public function denormalize($data, $type, $format = NULL, array $context = []) {
// Build array of geometry wrappers to return.
$geometries = [];
foreach ($data as $placemark) {
// Skip if there is no XML key.
if (empty($placemark['xml'])) {
continue;
}
// Load KML into a Geometry object.
$geometry = $this->geoPHP->load($placemark['xml'], 'kml');
// Create an empty collection if no geometry was loaded.
if (empty($geometry)) {
$geometry = new \GeometryCollection();
}
// Build properties.
$properties = [];
// Add an ID if provided.
if (isset($placemark['@attributes']['id'])) {
$properties['id'] = $placemark['@attributes']['id'];
}
// Add standard KML properties if included.
$keys = $this->supportedProperties();
foreach ($keys as $property_name) {
if (isset($placemark[$property_name])) {
$properties[$property_name] = $placemark[$property_name];
}
}
$wrapper = new GeometryWrapper($geometry, $properties);
$geometries[] = $wrapper;
}
return $geometries;
}
/**
* {@inheritdoc}
*/
public function supportsDenormalization($data, $type, $format = NULL) {
return $type === static::TYPE && $format === static::FORMAT;
}
/**
* Define supported properties.
*
* @return string[]
* An array of property names (strings).
*/
protected function supportedProperties() {
return ['name', 'entity_type', 'bundle', 'internal_id', 'description'];
}
/**
* {@inheritdoc}
*/
public function getSupportedTypes(?string $format): array {
return [
static::TYPE => TRUE,
];
}
}