aero_weather-1.0.3/src/Service/AeroWeatherApi.php

src/Service/AeroWeatherApi.php
<?php

namespace Drupal\aero_weather\Service;

use GuzzleHttp\Exception\ConnectException;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Http\ClientFactory;
use Drupal\Core\Cache\CacheBackendInterface;
use GuzzleHttp\Exception\RequestException;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\Core\File\FileUrlGeneratorInterface;
use Drupal\Core\Render\Markup;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Xss;

/**
 * Service for fetching and caching exchange rate data.
 */
class AeroWeatherApi {

  /**
   * The config factory.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  private $configFactory;

  /**
   * The HTTP client factory.
   *
   * @var \Drupal\Core\Http\ClientFactory
   */
  protected $httpClientFactory;

  /**
   * The cache backend.
   *
   * @var \Drupal\Core\Cache\CacheBackendInterface
   */
  protected $cache;

  /**
   * The logger channel.
   *
   * @var \Psr\Log\LoggerInterface
   */
  protected $logger;

  /**
   * The module handler service.
   *
   * Used to invoke hook_alter() and check module existence.
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
   */
  protected $moduleHandler;

  /**
   * The string translation service.
   *
   * @var \Drupal\Core\StringTranslation\TranslationInterface
   */
  protected $stringTranslation;

  /**
   * The file URL generator service.
   *
   * @var \Drupal\Core\File\FileUrlGeneratorInterface
   */
  protected $fileUrlGenerator;

  /**
   * The file entity storage.
   *
   * @var \Drupal\Core\Entity\EntityStorageInterface
   */
  protected $fileStorage;

  /**
   * AeroWeatherApi constructor.
   *
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The config factory.
   * @param \Drupal\Core\Http\ClientFactory $http_client_factory
   *   The HTTP client factory.
   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
   *   The cache backend.
   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
   *   The logger channel factory.
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
   *   The module handler service.
   * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
   *   The string translation service, used to translate human-readable text
   *   in the service, like country names, into different languages.
   * @param \Drupal\Core\File\FileUrlGeneratorInterface $file_url_generator
   *   The file URL generator service for generating URLs for weather
   *   icons or files.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager service.
   */
  public function __construct(ConfigFactoryInterface $config_factory, ClientFactory $http_client_factory, CacheBackendInterface $cache_backend, LoggerChannelFactoryInterface $logger_factory, ModuleHandlerInterface $module_handler, TranslationInterface $string_translation, FileUrlGeneratorInterface $file_url_generator, EntityTypeManagerInterface $entity_type_manager) {
    $this->configFactory = $config_factory;
    $this->httpClientFactory = $http_client_factory;
    $this->cache = $cache_backend;
    $this->logger = $logger_factory->get('aero_weather');
    $this->moduleHandler = $module_handler;
    $this->stringTranslation = $string_translation;
    $this->fileUrlGenerator = $file_url_generator;
    $this->fileStorage = $entity_type_manager->getStorage('file');
  }

  /**
   * Fetches aero weather from the API, using cache if available.
   *
   * @return array
   *   An array of aero weather or an empty array on failure.
   */
  public function getWeatherData($location_name, $forecast_days = NULL) {
    $config = $this->configFactory->get('aero_weather.settings');
    $apiKey = $config->get('api_key');
    $cacheEnabled = $config->get('cache_enabled');

    $forecast_days = $forecast_days ?? 5;

    $location_hash = $this->generateHashFromText($location_name);

    if (!$apiKey || $location_name == '') {
      return [];
    }

    $cache_id = 'aero_weather_' . $location_hash;
    $cache_entry = $this->cache->get($cache_id);

    // If cache exists, check date validity.
    if ($cacheEnabled && $cache_entry) {
      $cached_data = $cache_entry->data;

      // Validate if the cached date matches today.
      if (isset($cached_data['date']) && $cached_data['date'] === date('Y-m-d')) {
        return $cached_data['location_data'];
      }
    }

    $exchangeRateUrl = "https://api.weatherapi.com/v1/forecast.json?key={$apiKey}&q={$location_name}&days={$forecast_days}";

    $httpClient = $this->httpClientFactory->fromOptions();

    try {
      $response = $httpClient->get($exchangeRateUrl);
      $location_data = json_decode($response->getBody(), TRUE);

      if (isset($location_data['location'])) {

        // Store location_data + cache date.
        $cache_data = [
          'date' => date('Y-m-d'),
          'location_data' => $location_data,
        ];

        // Determine cache expiration (e.g., until tomorrow midnight)
        $expire = 0;
        if ($cacheEnabled) {
          $expire = $this->getCacheTimestamp();
        }

        $this->cache->set($cache_id, $cache_data, $expire);

        return $location_data;
      }
    }
    catch (ConnectException $e) {
      $this->logger->error('Connection error: @message', ['@message' => $e->getMessage()]);
    }
    catch (RequestException $e) {
      $this->logger->error('API request failed: @message', ['@message' => $e->getMessage()]);
    }

    return [];
  }

  /**
   * Retrieves the cache enabled configuration value.
   *
   * @return bool
   *   TRUE if cache is enabled, FALSE otherwise.
   */
  public function isCacheEnabled() {
    return $this->configFactory->get('aero_weather.settings')->get('cache_enabled');
  }

  /**
   * Retrieves the cache duration timestamp with unit conversion.
   *
   * @return int
   *   The cache timestamp in seconds.
   */
  public function getCacheTimestamp() {
    $config = $this->configFactory->get('aero_weather.settings');

    // Retrieve the cache time and unit settings.
    $cache_time = $config->get('cache_time') ?: 1;
    $cache_unit = $config->get('cache_unit') ?: 'hours';

    // Convert the time based on the unit.
    switch ($cache_unit) {
      case 'minutes':
        // Convert minutes to seconds.
        $cache_duration_seconds = $cache_time * 60;
        break;

      case 'hours':
        // Convert hours to seconds.
        $cache_duration_seconds = $cache_time * 60 * 60;
        break;

      default:
        // Default to hours if an unknown unit is found.
        $cache_duration_seconds = $cache_time * 60 * 60;
        break;
    }

    // Return the timestamp (current time + cache duration)
    return time() + $cache_duration_seconds;
  }

  /**
   * Generates a hash for a given string.
   *
   * @param string $text
   *   The string to be hashed.
   *
   * @return string
   *   The generated hash.
   */
  public function generateHashFromText($text) {
    $algorithm = 'sha256';
    $hash = hash($algorithm, $text);
    return $hash;
  }

  /**
   * Fetches all Aero Weather settings including icon file URLs.
   *
   * @return array
   *   An associative array of all Aero Weather settings including:
   *   - api_key: string
   *   - cache_enabled: bool
   *   - cache_time: int
   *   - cache_unit: string
   *   - icon_style: string
   *   - icons: array
   *     - humidity, pressure, wind, uv_index, precipitation, clouds,
   *       visibility, sunrise, sunset
   *       Each element contains:
   *       - upload_url: string|NULL (full URL to uploaded file)
   *       - url: string (URL if set manually)
   *       - font: string (font icon class)
   */
  public function getWeatherIconSettings(): array {
    $config = $this->configFactory->get('aero_weather.settings');

    $icon_elements = [
      'humidity', 'pressure', 'wind', 'uv_index', 'precipitation',
      'clouds', 'visibility', 'sunrise', 'sunset',
    ];

    $icons = [];
    $icon_style = $config->get('icon_style') ?? 'default';

    foreach ($icon_elements as $element) {
      $upload_url = NULL;
      $icon_markup = '';

      // Load uploaded file URL.
      $fids = $config->get("{$element}_upload") ?? [];
      if (!empty($fids)) {
        $file = $this->fileStorage->load(reset($fids));
        if ($file) {
          $upload_url = $this->fileUrlGenerator->generateAbsoluteString($file->getFileUri());
        }
      }

      $url = $config->get("{$element}_url") ?? '';
      $font = $config->get("{$element}_font") ?? '';

      switch ($icon_style) {
        case 'upload_url':
          if (!empty($upload_url)) {
            $icon_markup = '<img src="' . Html::escape($upload_url) . '" alt="' . Html::escape($element) . '" class="w-5 h-5 mlr-2"/>';
          }
          break;

        case 'url':
          if (!empty($url)) {
            $icon_markup = '<img src="' . Html::escape($url) . '" alt="' . Html::escape($element) . '" class="w-5 h-5 mlr-2"/>';
          }
          break;

        case 'font':
          if (!empty($font)) {
            $safe_html = Xss::filter($font, ['i', 'span']);

            // Add extra classes.
            if (strpos($safe_html, 'class="') !== FALSE) {
              $icon_markup = preg_replace('/class="([^"]+)"/', 'class="$1 w-5 h-5 mlr-2"', $safe_html);
            }
            else {
              $icon_markup = str_replace('<i', '<i class="w-5 h-5 mlr-2"', $safe_html);
            }
          }
          break;
      }

      $icons[$element] = !empty($icon_markup) ? Markup::create($icon_markup) : '';
    }

    return $icons;
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc