|
Server : Apache System : Linux server.mata-lashes.com 3.10.0-1160.90.1.el7.x86_64 #1 SMP Thu May 4 15:21:22 UTC 2023 x86_64 User : matalashes ( 1004) PHP Version : 8.1.29 Disable Function : NONE Directory : /home/matalashes/www/simulasikite.mata-lashes.com/system/Config/ |
Upload File : |
<?php
/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <admin@codeigniter.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace CodeIgniter\Config;
use CodeIgniter\Model;
use Config\Services;
/**
* Factories for creating instances.
*
* Factories allow dynamic loading of components by their path
* and name. The "shared instance" implementation provides a
* large performance boost and helps keep code clean of lengthy
* instantiation checks.
*
* @method static BaseConfig config(...$arguments)
* @method static Model models(...$arguments)
*/
class Factories
{
/**
* Store of component-specific options, usually
* from CodeIgniter\Config\Factory.
*
* @var array<string, array>
*/
protected static $options = [];
/**
* Explicit options for the Config
* component to prevent logic loops.
*
* @var array<string, mixed>
*/
private static $configOptions = [
'component' => 'config',
'path' => 'Config',
'instanceOf' => null,
'getShared' => true,
'preferApp' => true,
];
/**
* Mapping of class basenames (no namespace) to
* their instances.
*
* @var array<string, string[]>
*/
protected static $basenames = [];
/**
* Store for instances of any component that
* has been requested as "shared".
* A multi-dimensional array with components as
* keys to the array of name-indexed instances.
*
* @var array<string, array>
*/
protected static $instances = [];
/**
* Loads instances based on the method component name. Either
* creates a new instance or returns an existing shared instance.
*
* @return mixed
*/
public static function __callStatic(string $component, array $arguments)
{
// First argument is the name, second is options
$name = trim(array_shift($arguments), '\\ ');
$options = array_shift($arguments) ?? [];
// Determine the component-specific options
$options = array_merge(self::getOptions(strtolower($component)), $options);
if (! $options['getShared']) {
if ($class = self::locateClass($options, $name)) {
return new $class(...$arguments);
}
return null;
}
$basename = self::getBasename($name);
// Check for an existing instance
if (isset(self::$basenames[$options['component']][$basename])) {
$class = self::$basenames[$options['component']][$basename];
// Need to verify if the shared instance matches the request
if (self::verifyInstanceOf($options, $class)) {
return self::$instances[$options['component']][$class];
}
}
// Try to locate the class
if (! $class = self::locateClass($options, $name)) {
return null;
}
self::$instances[$options['component']][$class] = new $class(...$arguments);
self::$basenames[$options['component']][$basename] = $class;
return self::$instances[$options['component']][$class];
}
/**
* Finds a component class
*
* @param array $options The array of component-specific directives
* @param string $name Class name, namespace optional
*/
protected static function locateClass(array $options, string $name): ?string
{
// Check for low-hanging fruit
if (class_exists($name, false) && self::verifyPreferApp($options, $name) && self::verifyInstanceOf($options, $name)) {
return $name;
}
// Determine the relative class names we need
$basename = self::getBasename($name);
$appname = $options['component'] === 'config'
? 'Config\\' . $basename
: rtrim(APP_NAMESPACE, '\\') . '\\' . $options['path'] . '\\' . $basename;
// If an App version was requested then see if it verifies
if ($options['preferApp'] && class_exists($appname) && self::verifyInstanceOf($options, $name)) {
return $appname;
}
// If we have ruled out an App version and the class exists then try it
if (class_exists($name) && self::verifyInstanceOf($options, $name)) {
return $name;
}
// Have to do this the hard way...
$locator = Services::locator();
// Check if the class was namespaced
if (strpos($name, '\\') !== false) {
if (! $file = $locator->locateFile($name, $options['path'])) {
return null;
}
$files = [$file];
}
// No namespace? Search for it
// Check all namespaces, prioritizing App and modules
elseif (! $files = $locator->search($options['path'] . DIRECTORY_SEPARATOR . $name)) {
return null;
}
// Check all files for a valid class
foreach ($files as $file) {
$class = $locator->getClassname($file);
if ($class && self::verifyInstanceOf($options, $class)) {
return $class;
}
}
return null;
}
/**
* Verifies that a class & config satisfy the "preferApp" option
*
* @param array $options The array of component-specific directives
* @param string $name Class name, namespace optional
*/
protected static function verifyPreferApp(array $options, string $name): bool
{
// Anything without that restriction passes
if (! $options['preferApp']) {
return true;
}
// Special case for Config since its App namespace is actually \Config
if ($options['component'] === 'config') {
return strpos($name, 'Config') === 0;
}
return strpos($name, APP_NAMESPACE) === 0;
}
/**
* Verifies that a class & config satisfy the "instanceOf" option
*
* @param array $options The array of component-specific directives
* @param string $name Class name, namespace optional
*/
protected static function verifyInstanceOf(array $options, string $name): bool
{
// Anything without that restriction passes
if (! $options['instanceOf']) {
return true;
}
return is_a($name, $options['instanceOf'], true);
}
/**
* Returns the component-specific configuration
*
* @param string $component Lowercase, plural component name
*
* @return array<string, mixed>
*/
public static function getOptions(string $component): array
{
$component = strtolower($component);
// Check for a stored version
if (isset(self::$options[$component])) {
return self::$options[$component];
}
$values = $component === 'config'
// Handle Config as a special case to prevent logic loops
? self::$configOptions
// Load values from the best Factory configuration (will include Registrars)
: config('Factory')->{$component} ?? [];
return self::setOptions($component, $values);
}
/**
* Normalizes, stores, and returns the configuration for a specific component
*
* @param string $component Lowercase, plural component name
*
* @return array<string, mixed> The result after applying defaults and normalization
*/
public static function setOptions(string $component, array $values): array
{
// Allow the config to replace the component name, to support "aliases"
$values['component'] = strtolower($values['component'] ?? $component);
// Reset this component so instances can be rediscovered with the updated config
self::reset($values['component']);
// If no path was available then use the component
$values['path'] = trim($values['path'] ?? ucfirst($values['component']), '\\ ');
// Add defaults for any missing values
$values = array_merge(Factory::$default, $values);
// Store the result to the supplied name and potential alias
self::$options[$component] = $values;
self::$options[$values['component']] = $values;
return $values;
}
/**
* Resets the static arrays, optionally just for one component
*
* @param string $component Lowercase, plural component name
*/
public static function reset(?string $component = null)
{
if ($component) {
unset(
static::$options[$component],
static::$basenames[$component],
static::$instances[$component]
);
return;
}
static::$options = [];
static::$basenames = [];
static::$instances = [];
}
/**
* Helper method for injecting mock instances
*
* @param string $component Lowercase, plural component name
* @param string $name The name of the instance
*/
public static function injectMock(string $component, string $name, object $instance)
{
// Force a configuration to exist for this component
$component = strtolower($component);
self::getOptions($component);
$class = get_class($instance);
$basename = self::getBasename($name);
self::$instances[$component][$class] = $instance;
self::$basenames[$component][$basename] = $class;
}
/**
* Gets a basename from a class name, namespaced or not.
*/
public static function getBasename(string $name): string
{
// Determine the basename
if ($basename = strrchr($name, '\\')) {
return substr($basename, 1);
}
return $name;
}
}