discoverConfigClasses(); $this->hydrateProperties(); } /** * Scans app/Configs/ for PHP files, instantiates each class, * and indexes them by their key property. */ private function discoverConfigClasses(): void { $files = glob(app_path('Configs/*.php')) ?: []; foreach ($files as $file) { $className = 'App\\Configs\\'.pathinfo($file, PATHINFO_FILENAME); $instance = new $className; $this->configClasses[$instance->key] = $instance; } } /** * Iterates over all discovered config classes, ensures a DB row exists, * resolves typed field values, and assigns them to public properties. */ private function hydrateProperties(): void { try { $dbRecords = ConfigModel::all()->keyBy('key'); foreach ($this->configClasses as $key => $instance) { $record = $this->ensureDbRecord($key, $dbRecords); $jsonValue = Arr::wrap((array) ($record->json_value ?? [])); $this->assignFieldProperties($key, $instance, $jsonValue); } } catch (QueryException) { // Silently skip if configs table does not yet exist during migrations. } } /** * Ensures a database record exists for the given config key, * creating one with an empty json_value if it does not. */ private function ensureDbRecord(string $key, Collection $dbRecords): ConfigModel { if ($dbRecords->has($key)) { return $dbRecords->get($key); } return ConfigModel::firstOrCreate( ['key' => $key], ['json_value' => ''], ); } /** * Resolves each field value from json_value (with default fallback), * applies type casting, and assigns to the matching typed public property. */ private function assignFieldProperties(string $key, object $instance, array $jsonValue): void { foreach ($instance->getFieldKeys() as $fieldKey => $definition) { $type = Arr::get($definition, 'type', 'string'); $rawValue = Arr::get($jsonValue, $fieldKey); if ($rawValue === null || $rawValue === '') { $rawValue = $instance->getDefault($fieldKey); } $castedValue = $this->castValue($rawValue, $type); $propertyName = Str::camel($key).Str::studly($fieldKey); if (property_exists($this, $propertyName)) { $this->{$propertyName} = $castedValue; } } } /** * Casts a raw value to the PHP type defined by the config field type string. */ private function castValue(mixed $value, string $type): mixed { return match ($type) { 'string', 'markdown' => (string) $value, 'int', 'integer' => (int) $value, 'bool', 'boolean' => (bool) $value, 'float' => (float) $value, default => $value, }; } /** * Returns the Config Field class instance for a given group key, * or null when no class has been discovered for that key. */ public function getConfigClassForGroup(string $group): ?object { return Arr::get($this->configClasses, $group); } }