Commit 1138052b authored by Michael Stenta's avatar Michael Stenta
Browse files

Issue #3284690: Provide a service for querying the Soil Data Access API

parent 71b6889b
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
services:
  nrcs.soil_data_access:
    class: Drupal\farm_nrcs\SoilDataAccess
    arguments: [ '@http_client' ]
  nrcs_map_render_event_subscriber:
    class: Drupal\farm_nrcs\EventSubscriber\MapRenderEventSubscriber
    tags:

src/SoilDataAccess.php

0 → 100644
+105 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\farm_nrcs;

use Drupal\Component\Serialization\Json;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Soil Data Access.
 */
class SoilDataAccess implements SoilDataAccessInterface {

  /**
   * The HTTP client.
   *
   * @var \GuzzleHttp\Client
   */
  protected $httpClient;

  /**
   * Class constructor.
   *
   * @param \GuzzleHttp\Client $http_client
   *   The HTTP client.
   */
  public function __construct(Client $http_client) {
    $this->httpClient = $http_client;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('http_client'),
    );
  }

  /**
   * {@inheritdoc}
   */
  public function mapunitWktQuery(string $wkt): array {

    // Define the columns to query.
    $columns = [
      'muname',
      'musym',
      'nationalmusym',
    ];

    // Assemble the SQL query that will be sent to the Soil Data Access API.
    $parts = [];
    foreach ($columns as $col) {
      $parts[] =  'MU.' . $col;
    }
    $query = "SELECT " . implode(', ', $parts) . " FROM SDA_Get_Mukey_from_intersection_with_WktWgs84('" . $wkt . "') K LEFT JOIN mapunit MU ON K.mukey = MU.mukey";

    // Run the query.
    $response = $this->tabularRestQuery($query);

    // Create an associative array of data.
    $data = [];
    if (!empty($response['Table'])) {
      foreach ($response['Table'] as $i => $result) {
        foreach ($result as $j => $value) {
          $data[$i][$columns[$j]] = $value;
        }
      }
    }

    // Return the data.
    return $data;
  }

  /**
   * {@inheritdoc}
   */
  public function tabularRestQuery(string $query): array {

    // Send request to the Soil Data Access API.
    try {
      $url = 'https://sdmdataaccess.sc.egov.usda.gov/tabular/post.rest';
      $options = [
        'headers' => [
          'Content-Type' => 'application/json',
          'Accept' => 'application/json',
        ],
        'json' => [
          'query' => $query,
          'format' => 'json',
        ],
      ];
      /** @var \GuzzleHttp\Psr7\Response $response */
      $response = $this->httpClient->request('POST', $url, $options);
    }
    catch (RequestException $e) {
      watchdog_exception('farmier', $e);
    }

    // Decode the JSON response and return the result.
    return Json::decode($response->getBody()->getContents());
  }
}
+33 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\farm_nrcs;

/**
 * Soil Data Access interface.
 */
interface SoilDataAccessInterface {

  /**
   * Query for mapunit data by a given WKT geometry.
   *
   * @param string $wkt
   *   The WKT geometry to query for.
   *
   * @return array
   *   Returns an array of mapunit data. Each result is an associative array
   *   with muname, musym, and nationalmusym values.
   */
  public function mapunitWktQuery(string $wkt): array;

  /**
   * Send an SQL query to the Soil Data Access tabular REST API endpoint.
   *
   * @param string $query
   *   The WKT geometry to query for.
   *
   * @return array
   *   Returns data from the API endpoint, decoded from JSON.
   */
  public function tabularRestQuery(string $query): array;

}
+56 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\Tests\farm_nrcs\Kernel;

use Drupal\KernelTests\KernelTestBase;

/**
 * Tests for the NRCS Soil Data Access service.
 *
 * @group farm
 */
class SoilDataAccessTest extends KernelTestBase {

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'farm_nrcs',
  ];

  /**
   * Test Soil Data Access service.
   */
  public function testSoilDataAccessService() {

    // Test getting data for a specific point.
    $expected = [
      [
        'muname' => 'Paxton and Montauk fine sandy loams, 3 to 8 percent slopes',
        'musym' => '84B',
        'nationalmusym' => '2t2qn',
      ],
    ];
    $data = \Drupal::service('nrcs.soil_data_access')->mapunitWktQuery('POINT(-71.82165840851076 41.87079806075624)');
    $this->assertNotEmpty($data);
    $this->assertEquals($expected, $data);

    // Test getting data for a polygon.
    $expected = [
      [
        'muname' => 'Canton and Charlton fine sandy loams, 3 to 15 percent slopes, extremely stony',
        'musym' => '62C',
        'nationalmusym' => '2wks7',
      ],
      [
        'muname' => 'Paxton and Montauk fine sandy loams, 3 to 8 percent slopes',
        'musym' => '84B',
        'nationalmusym' => '2t2qn',
      ]
    ];
    $data = \Drupal::service('nrcs.soil_data_access')->mapunitWktQuery('POLYGON((-71.81960962792417 41.8692198884186,-71.81904972300649 41.869218787257466,-71.81903355459855 41.868068944318594,-71.81954571476324 41.86796457836036,-71.81960962792417 41.8692198884186))');
    $this->assertNotEmpty($data);
    $this->assertEquals($expected, $data);
  }

}