PosAddressConfigBuilder.php

PHOTO EMBED

Tue Oct 18 2022 22:11:26 GMT+0000 (Coordinated Universal Time)

Saved by @igor #drupal #mysql

<?php

namespace Drupal\pos_field_address;

use Drupal\Core\Cache\Cache;
use Drupal\Component\Serialization\Yaml;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Messenger\MessengerInterface;

/**
 * Class PosAddressConfigBuilder.
 */
class PosAddressConfigBuilder {

  const COUNTRIES = 'countries.yml';

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

  /**
   * Messenger.
   *
   * @var \Drupal\Core\Messenger\MessengerInterface
   */
  protected $messenger;

  /**
   * PosAddressConfigBuilder constructor.
   *
   * @param \Drupal\Core\Cache\CacheBackendInterface $cache
   *   Cache.
   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
   *   Messenger.
   */
  public function __construct(CacheBackendInterface $cache, MessengerInterface $messenger) {
    $this->cache = $cache;
    $this->messenger = $messenger;
  }

  /**
   * Parse file.
   *
   * @param string $file
   *   Filename.
   *
   * @return bool|mixed
   *   File content.
   */
  private function parseFile($file) {
    $cache_name = 'address__' . str_replace('.yml', '', $file);
    if ($cached = $this->cache->get($cache_name)) {
      return $cached->data;
    }
    $path = realpath(__DIR__) . '/../values/' . $file;
    if (!is_file($path)) {
      return FALSE;
    }
    $content = file_get_contents($path);
    if ($content === FALSE) {
      return $content;
    }
    $content = Yaml::decode($content);
    $this->cache->set($cache_name, $content, Cache::PERMANENT);

    return $content;
  }

  /**
   * Get country codes.
   *
   * @return array
   *   Country codes.
   */
  public function getCountryCodes() {
    return array_keys($this->getCountriesDetailed());
  }

  /**
   * Get country list.
   *
   * @param array $allowed_countries
   *   Allowed countries.
   *
   * @return array|bool|mixed
   *   Countries.
   */
  public function getCountries(array $allowed_countries = []) {
    $countries = $this->getCountriesDetailed();
    foreach ($countries as $country_code => $country) {
      if (empty($allowed_countries) || in_array($country_code, $allowed_countries)) {
        $countries[$country_code] = $country['country'];
      }
      else {
        unset($countries[$country_code]);
      }
    }
    return $countries;
  }

  /**
   * Detailed country data.
   *
   * @return array|bool|mixed
   *   Data.
   */
  public function getCountriesDetailed() {
    $countries_detailed = &drupal_static('address_countries_detailed');
    if (!isset($countries_detailed)) {
      $countries_detailed = $this->parseFile(self::COUNTRIES);
    }
    return $countries_detailed;
  }

  /**
   * Country schema.
   *
   * @param string $country_code
   *   Country code.
   *
   * @return bool|mixed
   *   Schema.
   */
  public function getCountrySchema($country_code, $force_input_schema = FALSE) {
    $countries = $this->getCountriesDetailed();
    if ($countries === FALSE || !array_key_exists($country_code, $countries)) {
      return FALSE;
    }
    if ($force_input_schema) {
      return ['input' => t('Input')];
    }
    return $countries[$country_code]['schema'];
  }

  public function isOriginallyInputCountrySchema($country_code) {
    $schema = $this->getCountrySchema($country_code);
    if ($schema === FALSE) {
      return TRUE;
    }
    return array_key_exists('input', $schema);
  }

  /**
   * Check if country schema exists.
   *
   * @param string $country_code
   *   Country code.
   *
   * @return bool
   *   Does schema exist?
   */
  public function countrySchemaExists($country_code) {
    $countries = $this->getCountriesDetailed();
    if ($countries === FALSE || !array_key_exists($country_code, $countries)) {
      return FALSE;
    }
    return TRUE;
  }

  /**
   * Returns tree for single country.
   */
  public function getTree($country_code) {
    $tree = &drupal_static('address_countries_schema_' . $country_code);
    if (!isset($tree)) {
      $tree = $this->parseFile($country_code . '.yml');
    }
    if ($tree === FALSE) {
      return [];
    }
    return $tree === FALSE ? [] : $tree;
  }

  /**
   * Returns data at depth.
   */
  public function getCurrentDepthData($country_code, $data = [], $filter = FALSE, $filter_cache_context = FALSE, $force_input_schema = FALSE) {
    $microtime = microtime(TRUE);
    $tree = $this->cache->get($filter_cache_context);
    if ($filter !== FALSE && $filter_cache_context !== FALSE && $tree) {
      $tree = $tree->data;
    }
    else {
      $tree = $this->getTree($country_code);
      if ($filter !== FALSE) {
        $this->filterTree($tree, $filter, $country_code);
        if ($filter_cache_context !== FALSE) {
          $this->cache->set($filter_cache_context, $tree);
        }
      }
    }
    $schema = $this->getCountrySchema($country_code, $force_input_schema);
    if ($schema === FALSE) {
      return FALSE;
    }

    $return_data = [];
    $current_depth_data = $tree;
    $return_data['country'] = $tree;
    if (empty($schema)) {
      return [];
    }
    elseif (key($schema) == 'input') {
      return $return_data['country'];
    }
    do {
      if (current($data) !== FALSE) {
        $current_code = current($data);
      }
      else {
        $current_code = key($current_depth_data[key($schema)]);
      }
      $current_depth_data = $current_depth_data[key($schema)];

      if (!array_key_exists($current_code, $current_depth_data)) {
        $current_code = key($current_depth_data);
      }

      $return_data[key($schema)] = $current_depth_data[$current_code];
      $return_data[key($schema)]['code'] = $current_code;
      $current_depth_data = $current_depth_data[$current_code];
      if ((microtime(TRUE) - $microtime) > 2) {
        $this->messenger->addMessage('Report this problem to administrator');
        break;
      }
      next($data);
    } while (next($schema) !== FALSE);

    return $return_data;
  }

  /**
   * Filters tree.
   */
  private function filterTree(&$tree, $filter, $country_code) {
    if (!is_array($filter)) {
      return $tree;
    }
    $schema = $this->getCountrySchema($country_code);

    foreach ($filter as $key => $value) {
      if ($value[0] !== $country_code) {
        unset($filter[$key]);
      }
    }

    foreach ($schema as $schema_key => $label) {
      $this->unsetUnexisting($tree, $filter, $schema, $schema_key);
    }
  }

  /**
   * Deletes locations not in filter.
   */
  private function unsetUnexisting(&$tree, $filter, $schema, $schema_key) {
    $tree_copy = $tree;
    $filter_key = 1;
    reset($schema);
    $this->goToCurrentDepth($tree[key($schema)], $filter, $schema, $filter_key, $schema_key);
    return $tree_copy;
  }

  /**
   * Go through the depth.
   *
   * @param array $tree
   *   Tree.
   * @param mixed $filter
   *   Filter.
   * @param array $schema
   *   Schema.
   * @param mixed $filter_key
   *   Filter key.
   * @param mixed $schema_key
   *   Schema key.
   */
  private function goToCurrentDepth(array &$tree, &$filter, array &$schema, &$filter_key, $schema_key) {
    if (key($schema) === $schema_key) {
      foreach ($tree as $key => $value) {
        $found = FALSE;
        foreach ($filter as $filter_code) {
          if ($filter_code[$filter_key] == $key) {
            $found = TRUE;
            break;
          }
        }
        if (!$found) {
          unset($tree[$key]);
        }
      }
    }
    else {
      next($schema);
      $current_key = key($schema);
      $filter_key++;
      $current_filter = $filter_key;
      foreach ($tree as $code_key => $code) {
        $this->goToCurrentDepth($tree[$code_key][$current_key], $filter, $schema, $filter_key, $schema_key);
        $filter_key = $current_filter;
        reset($schema);
        while (key($schema) !== $current_key) {
          next($schema);
        }
      }
    }
  }

  /**
   * Get select schema.
   *
   * @param string $country_code
   *   Country code.
   *
   * @return array
   *   Schema.
   */
  public function getSelectSchema($country_code) {
    $tree = $this->getTree($country_code);
    $schema = $this->getCountrySchema($country_code);
    $values = [];
    $codes = [];
    end($schema);
    $this->getSubnames($tree, key($schema), $values, $codes, TRUE, $country_code);
    return array_combine($codes, $values);
  }

  /**
   * Get subnames.
   *
   * @param array $current_tree
   *   Current tree.
   * @param mixed $last_schema_key
   *   Last schema key.
   * @param array $values
   *   Values.
   * @param array $codes
   *   Codes.
   * @param mixed $first
   *   First.
   * @param string $country_code
   *   Country code.
   *
   * @return array
   *   Subnames.
   */
  private function getSubnames(array $current_tree, $last_schema_key, array &$values, array &$codes, $first, $country_code = '') {
    $keys = array_keys($current_tree);
    if (!array_key_exists($country_code, $this->getCountriesDetailed())) {
      $country_name = '';
    }
    else {
      $country_name = $this->getCountriesDetailed()[$country_code]['country'];
    }

    $schema_key = FALSE;
    foreach ($keys as $key) {
      if ($key != 'name') {
        $schema_key = $key;
      }
    }
    $subnames = [];
    if (empty($current_tree)) {
      return [];
    }
    foreach ($current_tree[$schema_key] as $code => $tree) {
      if ($first) {
        $subnames = $this->getSubnames($tree, $last_schema_key, $values, $codes, FALSE);
        foreach ($subnames as $subname) {
          $values[] = $country_name . '->' . $tree['name'] . '->' . $subname['name'];
          $codes[] = $country_code . '{||}' . $code . '{||}' . $subname['code'];
        }
      }
      elseif ($last_schema_key === $schema_key) {
        $subnames[] = ['name' => $tree['name'], 'code' => $code];
      }
      else {
        $return_value = $this->getSubnames($tree, $last_schema_key, $values, $codes, FALSE);
        foreach ($return_value as $subname) {
          $subnames[] = [
            'name' => $tree['name'] . '->' . $subname['name'],
            'code' => $code . '{||}' . $subname['code'],
          ];
        }
      }
    }
    if (!$first) {
      return $subnames;
    }
  }

  /**
   * Get all options for country schema element.
   *
   * @param string $country_code
   *   Country code.
   * @param mixed $schema_key
   *   Schema key.
   *
   * @return array
   *   Options.
   */
  public function getAllOptionsForCountrySchemaElement($country_code, $schema_key) {
    $tree = $this->getTree($country_code);
    $country_schema = $this->getCountrySchema($country_code);
    $values = [];
    if (!empty($country_schema)) {
      $this->getAllValuesToGivenDepth($tree[key($country_schema)], $country_schema, $schema_key, $values);
    }
    return $values;
  }

  /**
   * Get all values to given depth.
   *
   * @param array $tree
   *   Tree.
   * @param array $country_schema
   *   Schema.
   * @param mixed $schema_key
   *   Schema key.
   * @param array $values
   *   Values.
   * @param array $current_depth_value
   *   Current value.
   */
  public function getAllValuesToGivenDepth(array $tree, array &$country_schema, $schema_key, array &$values, array $current_depth_value = []) {
    $current_key_schema = key($country_schema);
    next($country_schema);
    foreach ($tree as $value => $sub_tree) {
      $current_depth_value[$current_key_schema] = (string) $value;
      if ($schema_key === $current_key_schema) {
        $values[] = [
          'name' => $sub_tree['name'],
          'value' => $current_depth_value,
        ];
      }
      else {
        $this->getAllValuesToGivenDepth($sub_tree[key($country_schema)], $country_schema, $schema_key, $values, $current_depth_value);
      }
    }
    prev($country_schema);
  }

  /**
   * Validates if data is valid.
   */
  public function validateValue($country_code, $data) {
    $tree = $this->getTree($country_code);
    $schema = $this->getCountrySchema($country_code);
    if (key($schema) === 'input' && is_string($data)) {
      return TRUE;
    }
    if (count($data) == 0 && !empty($tree)) {
      return TRUE;
    }
    elseif (count($data) == 0 && empty($tree)) {
      return FALSE;
    }
    foreach ($schema as $schema_key => $label) {
      if (array_key_exists(current($data), $tree[$schema_key])) {
        $tree = $tree[$schema_key][current($data)];
      }
      else {
        return FALSE;
      }
      if (next($data) === FALSE) {
        break;
      }
    }
    return TRUE;
  }

  /**
   * Returns all schema keys that exists.
   */
  public function getAllSchemaKeys() {
    $detailed_countries = $this->getCountriesDetailed();
    $all_schema_keys = [];
    foreach ($detailed_countries as $detailed_country) {
      foreach ($detailed_country['schema'] as $key => $label) {
        if (!in_array($key, $all_schema_keys)) {
          $all_schema_keys[] = $key;
        }
      }
    }
    return $all_schema_keys;
  }

}
content_copyCOPY