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 Geo
description: Provides geospatial features that other modules can use.
type: module
package: farmOS
core_version_requirement: ^10
dependencies:
- geofield:geofield

View File

@@ -0,0 +1,37 @@
<?php
/**
* @file
* Install, update and uninstall function for the farm_geo module.
*/
/**
* Implements hook_requirements().
*/
function farm_geo_requirements($phase) {
$requirements = [];
// Do not check requirements in the update phase.
// The REQUIREMENT_WARNING severity prevents updates from being run.
if ($phase == 'update') {
return $requirements;
}
// Check for php-geos extension.
if (geoPHP::geosInstalled()) {
$severity = REQUIREMENT_OK;
// phpcs:ignore Squiz.PHP.LowercasePHPFunctions.CallUppercase -- GEOSVersion() function is defined in php-geos.
$message = t('GEOS PHP extension installed. GEOS version @version', ['@version' => GEOSVersion()]);
}
else {
$severity = REQUIREMENT_WARNING;
$message = t('The GEOS PHP extension is not installed. While not required, it is strongly recommended for accurate geometry arithmetic. See %link for more information.', ['%link' => 'https://geophp.net/geos.html']);
}
$requirements['geos'] = [
'title' => t('GEOS PHP extension'),
'severity' => $severity,
'value' => $message,
];
return $requirements;
}

View File

@@ -0,0 +1,6 @@
services:
serializer.farm_geo.geometry.content_entity_geometry:
class: Drupal\farm_geo\Normalizer\ContentEntityGeometryNormalizer
arguments: ['@geofield.geophp']
tags:
- { name: normalizer, priority: 10 }

View File

@@ -0,0 +1,44 @@
<?php
namespace Drupal\farm_geo;
/**
* An object that wraps the GeoPHP Geometry with additional properties.
*
* As suggested by the GeoPHP maintainer:
*
* @see https://github.com/phayes/geoPHP/issues/25#issuecomment-5576661
* @see https://github.com/phayes/geoPHP/pull/41#issuecomment-6983505
*/
class GeometryWrapper {
/**
* The geometry to wrap.
*
* @var \Geometry
* The GeoPHP Geometry object.
*/
public \Geometry $geometry;
/**
* Properties associated with the geometry.
*
* @var array
* Associative array of property values.
*/
public array $properties;
/**
* GeometryWrapper constructor.
*
* @param \Geometry $geometry
* The GeoPHP geometry object.
* @param array $properties
* Associative array of property values.
*/
public function __construct(\Geometry $geometry, array $properties = []) {
$this->geometry = $geometry;
$this->properties = $properties;
}
}

View File

@@ -0,0 +1,119 @@
<?php
namespace Drupal\farm_geo\Normalizer;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\farm_geo\GeometryWrapper;
use Drupal\geofield\GeoPHP\GeoPHPInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\SerializerAwareInterface;
use Symfony\Component\Serializer\SerializerAwareTrait;
/**
* Normalizes content entities into arrays of GeometryWrapper objects.
*
* This can be used for encoding entities into geospatial files.
*
* The entity's geofield name must be provided with $context['geofield'].
*
* @see \Drupal\farm_geo\GeometryWrapper
*/
class ContentEntityGeometryNormalizer implements NormalizerInterface, SerializerAwareInterface {
use SerializerAwareTrait;
/**
* The GeoPHP service.
*
* @var \Drupal\geofield\GeoPHP\GeoPHPInterface
*/
protected $geoPHP;
/**
* ContentEntityGeometryNormalizer 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 = []) {
// Build GeometryWrapper objects.
$geometries = [];
// Bail if no geofield field is provided.
if (empty($context['geofield'])) {
return $geometries;
}
// Check the entity geofield.
$geofield = $context['geofield'];
$entity = $object;
if (!$entity->hasField($geofield)) {
return NULL;
}
// If the geofield is empty, bail.
if ($entity->get($geofield)->isEmpty()) {
return NULL;
}
// Check WKT value.
$field_value = $entity->get($geofield)->first();
$wkt = $field_value->get('value')->getValue();
if (empty($wkt)) {
return NULL;
}
// Load WKT as a GeoPHP Geometry object.
$geometry = $this->geoPHP->load($wkt, 'wkt');
// Build geometry properties.
$properties = [
'id' => $entity->uuid(),
'name' => htmlspecialchars($entity->label()),
'entity_type' => $entity->getEntityTypeId(),
'bundle' => $entity->bundle(),
'internal_id' => $entity->id(),
];
// Add entity notes as the description.
if ($entity->hasField('notes')) {
$notes = $entity->get('notes')->first()->getValue();
if (!empty($notes['value'])) {
$properties['description'] = $notes['value'];
}
}
// Normalize the GeometryWrapper object to the target type.
$geometry_wrapper = new GeometryWrapper($geometry, $properties);
return $this->serializer->normalize($geometry_wrapper, $format, $context);
}
/**
* {@inheritdoc}
*/
public function supportsNormalization($data, $format = NULL) {
// Check that the data is a content entity.
// Only formats that are prefixed with "geometry_" are supported.
// This makes it easier for other modules to provide geometry encoders.
return $data instanceof ContentEntityInterface && strpos($format, 'geometry_') === 0;
}
/**
* {@inheritdoc}
*/
public function getSupportedTypes(?string $format): array {
return [
ContentEntityInterface::class => TRUE,
];
}
}

View File

@@ -0,0 +1,110 @@
<?php
namespace Drupal\farm_geo\Traits;
/**
* Provides methods to work with WKT.
*/
trait WktTrait {
/**
* Reduce a WKT geometry.
*
* @param string $wkt
* The geometry in WKT format.
*
* @return string
* The reduced geometry in WKT format.
*/
public function reduceWkt(string $wkt) {
$geometry = \geoPHP::load($wkt, 'wkt');
$geometry = \geoPHP::geometryReduce($geometry);
return $geometry->out('wkt');
}
/**
* Combine WKT geometries.
*
* This does not use Geometry::union(), which is only available when GEOS is
* installed.
*
* @param array $geoms
* An array of WKT geometry strings.
*
* @return string
* Returns a combined WKT geometry string.
*/
public function combineWkt(array $geoms) {
// If no geometries were found, return an empty string.
if (empty($geoms)) {
return '';
}
// If there is more than one geometry, we will wrap it all in a
// GEOMETRYCOLLECTION() at the end.
$geometrycollection = FALSE;
if (count($geoms) > 1) {
$geometrycollection = TRUE;
}
// Build an array of WKT strings.
$wkt_strings = [];
foreach ($geoms as $geom) {
// If the geometry is empty, skip it.
if (empty($geom)) {
continue;
}
// Convert to a GeoPHP geometry object.
$geometry = \geoPHP::load($geom, 'wkt');
// If this is a geometry collection, multi-point, multi-linestring, or
// multi-polygon, then extract its components and add them individually to
// the array.
$multigeometries = [
'GeometryCollection',
'MultiPoint',
'MultiLineSting',
'MultiPolygon',
];
if (in_array($geometry->geometryType(), $multigeometries)) {
// Iterate through the geometry components and add each to the array.
$components = $geometry->getComponents();
foreach ($components as $component) {
$wkt_strings[] = $component->out('wkt');
}
// Set $geometrycollection to TRUE in case there was only one geometry
// in the $geoms parameter of this function, so that we know to wrap the
// WKT in a GEOMETRYCOLLECTION() at the end.
$geometrycollection = TRUE;
}
// Otherwise, add it to the array.
else {
$wkt_strings[] = $geometry->out('wkt');
}
}
// Combine all the WKT strings together into one.
$wkt = implode(',', $wkt_strings);
// If the WKT is empty, return it.
if (empty($wkt)) {
return $wkt;
}
// If there is more than one geometry, wrap them all in a geometry
// collection.
if ($geometrycollection) {
$wkt = 'GEOMETRYCOLLECTION (' . $wkt . ')';
}
// Return the combined WKT.
return $wkt;
}
}