Advertisement
ArcaniSGK507

Untitled

Mar 24th, 2025
195
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 7.58 KB | None | 0 0
  1. <?php
  2.  
  3. declare(strict_types=1);
  4.  
  5. /**
  6.  * Last Hammer Framework 2.0
  7.  * PHP Version 8.3 (Required).
  8.  *
  9.  * @see https://github.com/arcanisgk/LH-Framework
  10.  *
  11.  * @author    Walter Nuñez (arcanisgk/founder) <[email protected]>
  12.  * @copyright 2017 - 2024
  13.  * @license   http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  14.  * @note      This program is distributed in the hope that it will be useful
  15.  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  16.  * or FITNESS FOR A PARTICULAR PURPOSE.
  17.  */
  18.  
  19. namespace Asset\Framework\Core;
  20.  
  21. use Asset\Framework\Trait\SingletonTrait;
  22. use Exception;
  23. use RuntimeException;
  24.  
  25. /**
  26.  * Class that handles: Framework Configuration Usage
  27.  *
  28.  * @package Asset\Framework\Core\ConfigLoader;
  29.  */
  30. class ConfigLoader
  31. {
  32.  
  33.     use SingletonTrait;
  34.  
  35.     private const string ENVIRONMENT_FILE = 'environment.json';
  36.  
  37.     private const array CONFIG_ENVIRONMENTS = ['local', 'dev', 'qa', 'pro'];
  38.  
  39.     private const string CONFIG_PATH = 'Asset'.DS.'resource'.DS.'config';
  40.  
  41.     /**
  42.      * @var array
  43.      */
  44.     private array $configCache = [];
  45.  
  46.     /**
  47.      * @var string
  48.      */
  49.     private string $currentEnvironment;
  50.  
  51.     /**
  52.      * @return bool
  53.      */
  54.     public static function checkFullConfig(): bool
  55.     {
  56.  
  57.         return CONFIG->app->project->getProjectConfig();
  58.     }
  59.  
  60.     /**
  61.      * @return void
  62.      * @throws Exception
  63.      */
  64.     public function loadConfigurations(): void
  65.     {
  66.         if (!defined('CONFIG')) {
  67.             $configs      = $this->loadAndValidateConfigs();
  68.             $configObject = $this->createConfigObject($configs);
  69.             define('CONFIG', $configObject);
  70.         }
  71.     }
  72.  
  73.     /**
  74.      * @return array
  75.      * @throws Exception
  76.      */
  77.     private function loadAndValidateConfigs(): array
  78.     {
  79.         $this->loadEnvironment();
  80.  
  81.         return $this->loadConfigurationFiles();
  82.     }
  83.  
  84.     /**
  85.      * @return void
  86.      */
  87.     private function loadEnvironment(): void
  88.     {
  89.         $envFile = PD.DS.self::CONFIG_PATH.DS.self::ENVIRONMENT_FILE;
  90.  
  91.         if (!file_exists($envFile)) {
  92.             throw new RuntimeException("Environment configuration file not found: $envFile");
  93.         }
  94.  
  95.         $envContent = file_get_contents($envFile);
  96.         if ($envContent === false) {
  97.             throw new RuntimeException("Unable to read environment configuration file");
  98.         }
  99.  
  100.         $envData = json_decode($envContent, true);
  101.         if (!isset($envData['environment']) || !in_array($envData['environment'], self::CONFIG_ENVIRONMENTS)) {
  102.             throw new RuntimeException("Invalid environment specified in configuration");
  103.         }
  104.  
  105.         $this->currentEnvironment = $envData['environment'];
  106.     }
  107.  
  108.     /**
  109.      * @return array
  110.      */
  111.     private function loadConfigurationFiles(): array
  112.     {
  113.         $configs    = [];
  114.         $configPath = PD.DS.self::CONFIG_PATH.DS.$this->currentEnvironment;
  115.  
  116.         if (!is_dir($configPath)) {
  117.             throw new RuntimeException(
  118.                 "Configuration directory not found for environment: $this->currentEnvironment"
  119.             );
  120.         }
  121.  
  122.         $jsonFiles = glob($configPath.DS.'*.json');
  123.         if (empty($jsonFiles)) {
  124.  
  125.             $backupPath = PD.DS.self::CONFIG_PATH.DS.'backup';
  126.             $jsonFiles  = glob($backupPath.DS.'*.json');
  127.  
  128.             if (empty($jsonFiles)) {
  129.                 throw new RuntimeException("No configuration files found in environment or backup directory");
  130.             }
  131.         }
  132.  
  133.         foreach ($jsonFiles as $file) {
  134.             $jsonContent = file_get_contents($file);
  135.             if ($jsonContent === false) {
  136.                 continue;
  137.             }
  138.  
  139.             $configData = json_decode($jsonContent, true);
  140.             if (json_last_error() !== JSON_ERROR_NONE) {
  141.                 throw new RuntimeException("Invalid JSON in configuration file: ".basename($file));
  142.             }
  143.  
  144.             $section           = strtolower(basename($file, '.json'));
  145.             $configs[$section] = $this->convertKeysToCamelCase($configData);
  146.         }
  147.         $configs['environment'] = $this->currentEnvironment;
  148.        
  149.         return $configs;
  150.     }
  151.  
  152.     /**
  153.      * @param array $array
  154.      * @return array
  155.      */
  156.     private function convertKeysToCamelCase(array $array): array
  157.     {
  158.         $result = [];
  159.         foreach ($array as $key => $value) {
  160.             $camelKey          = lcfirst(
  161.                 str_replace(
  162.                     ' ',
  163.                     '',
  164.                     ucwords(
  165.                         str_replace(
  166.                             '_',
  167.                             ' ',
  168.                             str_replace('-', ' ', $key)
  169.                         )
  170.                     )
  171.                 )
  172.             );
  173.             $result[$camelKey] = is_array($value) ? $this->convertKeysToCamelCase($value) : $value;
  174.         }
  175.  
  176.         return $result;
  177.     }
  178.  
  179.     /**
  180.      * @param array $data
  181.      * @return object
  182.      */
  183.     private function createConfigObject(array $data): object
  184.     {
  185.  
  186.         return new class($data) {
  187.  
  188.             private array $properties;
  189.  
  190.             public function __construct(array $data)
  191.             {
  192.                 $this->properties = array_map(
  193.                     fn($value) => is_array($value) ? new self($value) : $value,
  194.                     $data
  195.                 );
  196.             }
  197.  
  198.             public function __get(string $name)
  199.             {
  200.                 if (isset($this->properties[$name]) && $this->properties[$name] instanceof self) {
  201.                     return $this->properties[$name];
  202.                 }
  203.  
  204.                 throw new Exception(
  205.                     "Direct property access to '$name' is not allowed. Use getter methods instead (e.g. get".ucfirst(
  206.                         $name
  207.                     )."())"
  208.                 );
  209.             }
  210.  
  211.             public function __call(string $name, array $arguments): mixed
  212.             {
  213.                 if (!str_starts_with($name, 'get')) {
  214.                     throw new Exception("Only getter methods are allowed. Method '$name' not found.");
  215.                 }
  216.                 $property = lcfirst(substr($name, 3));
  217.                 if (isset($this->properties[$property])) {
  218.                     return $this->properties[$property];
  219.                 }
  220.                 throw new Exception("Getter method '$name' does not exist.");
  221.             }
  222.  
  223.             public function __debugInfo()
  224.             {
  225.                 return ['debug' => '### Only For Implementation Purposes ###', 'Usage' => $this->buildDebugInfo()];
  226.             }
  227.  
  228.             private function buildDebugInfo(mixed &$debugInfo = null, string $parentPath = null): mixed
  229.             {
  230.  
  231.                 foreach ($this->properties as $key => $value) {
  232.  
  233.                     if ($value instanceof self) {
  234.                         $currentPath     = $parentPath ? $parentPath.'->'.$key : 'CONFIG->'.$key;
  235.                         $debugInfo[$key] = [];
  236.                         $value->buildDebugInfo($debugInfo[$key], $currentPath);
  237.                     } else {
  238.                         $path            = $parentPath ?? 'CONFIG';
  239.                         $debugInfo[$key] = [
  240.                             'type'     => '[getter]',
  241.                             'value'    => $value,
  242.                             'property' => $key,
  243.                             'path'     => $path.'->get'.ucfirst($key).'()',
  244.                         ];
  245.                     }
  246.                 }
  247.  
  248.                 return $debugInfo;
  249.             }
  250.         };
  251.     }
  252. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement