PosAddressConfigBuilder.php
Tue Oct 18 2022 22:11:26 GMT+0000 (Coordinated Universal Time)
<?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; } }
Comments