Make reverse geocoding compatible to BaseFieldDefinition

Created on 18 July 2023, about 1 year ago
Updated 12 December 2023, 10 months ago

Problem/Motivation

When defining a custom Entity with BaseFieldDefinition's, it impossible to configure and apply the reverse geocoding feature of geocoder module.

It turns out, there's a way to provide third_party_settings to BaseFieldDefinition by a simple extends BaseFieldDefinition implements ThirdPartySettingsInterface:

my_module/src/Field/GeocoderBaseFieldDefinition.php:

<?php

namespace Drupal\my_module\Field;

use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Config\Entity\ThirdPartySettingsInterface;

class GeocoderBaseFieldDefinition extends BaseFieldDefinition implements ThirdPartySettingsInterface
{
  /**
   * Third party settings.
   *
   * An array of key/value pairs keyed by provider.
   *
   * @var array[]
   */
  protected $third_party_settings = [
    'geocoder_field' => [
      'skip_not_empty_value' => false,
      'disabled' => false,
      'hidden' => false,
      'providers' => ['googlemaps'],
      'delta_handling' => 'default',
      'failure' => ['handling' => 'empty', 'status_message' => true, 'log' => true],
      'geocode' => ['field' => '', 'delta_handling' => 'default']
    ]
  ];

  /**
   * {@inheritdoc}
   */
  public function getThirdPartySetting($provider, $key, $default = NULL)
  {
    return $this->third_party_settings[$provider][$key] ?? $default;
  }

  /**
   * {@inheritdoc}
   */
  public function getThirdPartySettings($provider)
  {
    return $this->third_party_settings[$provider] ?? [];
  }

  /**
   * {@inheritdoc}
   */
  public function setThirdPartySetting($provider, $key, $value)
  {
    $this->third_party_settings[$provider][$key] = $value;
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function unsetThirdPartySetting($provider, $key)
  {
    unset($this->third_party_settings[$provider][$key]);
    // If the third party is no longer storing any information, completely
    // remove the array holding the settings for this provider.
    if (empty($this->third_party_settings[$provider])) {
      unset($this->third_party_settings[$provider]);
    }
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getThirdPartyProviders()
  {
    return array_keys($this->third_party_settings);
  }
}

Now, in your Drupal\my_module\Entity\my_Entity.php the 'address' and corresponding 'geofield' is declared like so. Notice the GeocoderBaseFieldDefinition::create and calls of GeocoderBaseFieldDefinition::::setThirdPartySetting() to modulate the differences in 'address' and 'geofield':

...
    $fields['address'] = GeocoderBaseFieldDefinition::create('address')
      ->setLabel(t('Addess'))
      ->setTranslatable(FALSE)
      ->setDescription(t('Address for the point of sales'))
      ->setSettings([
        'field_overrides' => [
          'givenName' => ['override' => 'hidden'],
          'additionalName' => ['override' => 'hidden'],
          'familyName' => ['override' => 'hidden'],
          'organization' => ['override' => 'hidden'],
          'dependentLocality' => ['override' => 'hidden'],
          'administrativeArea' => ['override' => 'hidden']
        ]
      ])
      ->setThirdPartySetting('geocoder_field', 'method', 'reverse_geocode')
      ->setThirdPartySetting('geocoder_field', 'field', 'geofield')
      ->setThirdPartySetting('geocoder_field', 'dumper', 'geojson')
      ]);

    $fields['geofield'] = GeocoderBaseFieldDefinition::create('geofield')
      ->setLabel(t('Geofield'))
      ->setTranslatable(FALSE)
      ->setDescription(t('Location of the point of sales'))
      ->setThirdPartySetting('geocoder_field', 'method', 'geocode')
      ->setThirdPartySetting('geocoder_field', 'field', 'address')
      ->setThirdPartySetting('geocoder_field', 'dumper', 'wkt')
      ->setDisplayOptions('form', [
        'type' => 'geofield_map',
        'weight' => -3,
        'settings' => [
          'html5_geolocation' => false,
          'default_value' => ['lat' => 51.37928, 'lon' => 6.91925],
          'map_library' => 'leaflet',
          'map_type_leaflet' => 'OpenStreetMap_Mapnik',
          'click_to_find_marker' => true,
          'click_to_place_marker' => true,
          'click_to_remove_marker' => false,
          'hide_coordinates' => true,
          'map_geocoder' => [
            'control' => 1,
            'settings' => [
              'providers' => [
                'googlemaps' => ['checked' => true]
              ]
            ]
          ]
        ]
      ]);
...

Proposed resolution

To make geocoder accept third_party_settings provided by the custom GeocoderBaseFieldDefinition only slight changes in geocoder module are required, changing a few instanceof targets. It's very simple, check my MR !

Feature request
Status

RTBC

Version

4.0

Component

Code

Created by

🇩🇪Germany tomsaw Essen

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Production build 0.71.5 2024