add trashes
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* 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 Laminas\Escaper\Escaper;
|
||||
use Laminas\Escaper\Exception\ExceptionInterface;
|
||||
use Laminas\Escaper\Exception\InvalidArgumentException as EscaperInvalidArgumentException;
|
||||
use Laminas\Escaper\Exception\RuntimeException;
|
||||
use Psr\Log\AbstractLogger;
|
||||
use Psr\Log\InvalidArgumentException;
|
||||
use Psr\Log\LoggerAwareInterface;
|
||||
use Psr\Log\LoggerAwareTrait;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\LoggerTrait;
|
||||
use Psr\Log\LogLevel;
|
||||
use Psr\Log\NullLogger;
|
||||
|
||||
/**
|
||||
* AUTOLOADER CONFIGURATION
|
||||
*
|
||||
* This file defines the namespaces and class maps so the Autoloader
|
||||
* can find the files as needed.
|
||||
*/
|
||||
class AutoloadConfig
|
||||
{
|
||||
/**
|
||||
* -------------------------------------------------------------------
|
||||
* Namespaces
|
||||
* -------------------------------------------------------------------
|
||||
* This maps the locations of any namespaces in your application to
|
||||
* their location on the file system. These are used by the autoloader
|
||||
* to locate files the first time they have been instantiated.
|
||||
*
|
||||
* The '/app' and '/system' directories are already mapped for you.
|
||||
* you may change the name of the 'App' namespace if you wish,
|
||||
* but this should be done prior to creating any namespaced classes,
|
||||
* else you will need to modify all of those classes for this to work.
|
||||
*
|
||||
* @var array<string, list<string>|string>
|
||||
*/
|
||||
public $psr4 = [];
|
||||
|
||||
/**
|
||||
* -------------------------------------------------------------------
|
||||
* Class Map
|
||||
* -------------------------------------------------------------------
|
||||
* The class map provides a map of class names and their exact
|
||||
* location on the drive. Classes loaded in this manner will have
|
||||
* slightly faster performance because they will not have to be
|
||||
* searched for within one or more directories as they would if they
|
||||
* were being autoloaded through a namespace.
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public $classmap = [];
|
||||
|
||||
/**
|
||||
* -------------------------------------------------------------------
|
||||
* Files
|
||||
* -------------------------------------------------------------------
|
||||
* The files array provides a list of paths to __non-class__ files
|
||||
* that will be autoloaded. This can be useful for bootstrap operations
|
||||
* or for loading functions.
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
public $files = [];
|
||||
|
||||
/**
|
||||
* -------------------------------------------------------------------
|
||||
* Namespaces
|
||||
* -------------------------------------------------------------------
|
||||
* This maps the locations of any namespaces in your application to
|
||||
* their location on the file system. These are used by the autoloader
|
||||
* to locate files the first time they have been instantiated.
|
||||
*
|
||||
* Do not change the name of the CodeIgniter namespace or your application
|
||||
* will break.
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
protected $corePsr4 = [
|
||||
'CodeIgniter' => SYSTEMPATH,
|
||||
'Config' => APPPATH . 'Config',
|
||||
];
|
||||
|
||||
/**
|
||||
* -------------------------------------------------------------------
|
||||
* Class Map
|
||||
* -------------------------------------------------------------------
|
||||
* The class map provides a map of class names and their exact
|
||||
* location on the drive. Classes loaded in this manner will have
|
||||
* slightly faster performance because they will not have to be
|
||||
* searched for within one or more directories as they would if they
|
||||
* were being autoloaded through a namespace.
|
||||
*
|
||||
* @var array<class-string, string>
|
||||
*/
|
||||
protected $coreClassmap = [
|
||||
AbstractLogger::class => SYSTEMPATH . 'ThirdParty/PSR/Log/AbstractLogger.php',
|
||||
InvalidArgumentException::class => SYSTEMPATH . 'ThirdParty/PSR/Log/InvalidArgumentException.php',
|
||||
LoggerAwareInterface::class => SYSTEMPATH . 'ThirdParty/PSR/Log/LoggerAwareInterface.php',
|
||||
LoggerAwareTrait::class => SYSTEMPATH . 'ThirdParty/PSR/Log/LoggerAwareTrait.php',
|
||||
LoggerInterface::class => SYSTEMPATH . 'ThirdParty/PSR/Log/LoggerInterface.php',
|
||||
LoggerTrait::class => SYSTEMPATH . 'ThirdParty/PSR/Log/LoggerTrait.php',
|
||||
LogLevel::class => SYSTEMPATH . 'ThirdParty/PSR/Log/LogLevel.php',
|
||||
NullLogger::class => SYSTEMPATH . 'ThirdParty/PSR/Log/NullLogger.php',
|
||||
ExceptionInterface::class => SYSTEMPATH . 'ThirdParty/Escaper/Exception/ExceptionInterface.php',
|
||||
EscaperInvalidArgumentException::class => SYSTEMPATH . 'ThirdParty/Escaper/Exception/InvalidArgumentException.php',
|
||||
RuntimeException::class => SYSTEMPATH . 'ThirdParty/Escaper/Exception/RuntimeException.php',
|
||||
Escaper::class => SYSTEMPATH . 'ThirdParty/Escaper/Escaper.php',
|
||||
];
|
||||
|
||||
/**
|
||||
* -------------------------------------------------------------------
|
||||
* Core Files
|
||||
* -------------------------------------------------------------------
|
||||
* List of files from the framework to be autoloaded early.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $coreFiles = [];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* Merge the built-in and developer-configured psr4 and classmap,
|
||||
* with preference to the developer ones.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if (isset($_SERVER['CI_ENVIRONMENT']) && $_SERVER['CI_ENVIRONMENT'] === 'testing') {
|
||||
$this->psr4['Tests\Support'] = SUPPORTPATH;
|
||||
$this->classmap['CodeIgniter\Log\TestLogger'] = SYSTEMPATH . 'Test/TestLogger.php';
|
||||
$this->classmap['CIDatabaseTestCase'] = SYSTEMPATH . 'Test/CIDatabaseTestCase.php';
|
||||
}
|
||||
|
||||
$this->psr4 = array_merge($this->corePsr4, $this->psr4);
|
||||
$this->classmap = array_merge($this->coreClassmap, $this->classmap);
|
||||
$this->files = [...$this->coreFiles, ...$this->files];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,301 @@
|
||||
<?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\Autoloader\FileLocatorInterface;
|
||||
use CodeIgniter\Exceptions\ConfigException;
|
||||
use CodeIgniter\Exceptions\RuntimeException;
|
||||
use Config\Encryption;
|
||||
use Config\Modules;
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
|
||||
/**
|
||||
* Class BaseConfig
|
||||
*
|
||||
* Not intended to be used on its own, this class will attempt to
|
||||
* automatically populate the child class' properties with values
|
||||
* from the environment.
|
||||
*
|
||||
* These can be set within the .env file.
|
||||
*
|
||||
* @phpstan-consistent-constructor
|
||||
* @see \CodeIgniter\Config\BaseConfigTest
|
||||
*/
|
||||
class BaseConfig
|
||||
{
|
||||
/**
|
||||
* An optional array of classes that will act as Registrars
|
||||
* for rapidly setting config class properties.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $registrars = [];
|
||||
|
||||
/**
|
||||
* Whether to override properties by Env vars and Registrars.
|
||||
*/
|
||||
public static bool $override = true;
|
||||
|
||||
/**
|
||||
* Has module discovery completed?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected static $didDiscovery = false;
|
||||
|
||||
/**
|
||||
* Is module discovery running or not?
|
||||
*/
|
||||
protected static bool $discovering = false;
|
||||
|
||||
/**
|
||||
* The processing Registrar file for error message.
|
||||
*/
|
||||
protected static string $registrarFile = '';
|
||||
|
||||
/**
|
||||
* The modules configuration.
|
||||
*
|
||||
* @var Modules|null
|
||||
*/
|
||||
protected static $moduleConfig;
|
||||
|
||||
public static function __set_state(array $array)
|
||||
{
|
||||
static::$override = false;
|
||||
$obj = new static();
|
||||
static::$override = true;
|
||||
|
||||
$properties = array_keys(get_object_vars($obj));
|
||||
|
||||
foreach ($properties as $property) {
|
||||
$obj->{$property} = $array[$property];
|
||||
}
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal For testing purposes only.
|
||||
* @testTag
|
||||
*/
|
||||
public static function setModules(Modules $modules): void
|
||||
{
|
||||
static::$moduleConfig = $modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal For testing purposes only.
|
||||
* @testTag
|
||||
*/
|
||||
public static function reset(): void
|
||||
{
|
||||
static::$registrars = [];
|
||||
static::$override = true;
|
||||
static::$didDiscovery = false;
|
||||
static::$moduleConfig = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will attempt to get environment variables with names
|
||||
* that match the properties of the child class.
|
||||
*
|
||||
* The "shortPrefix" is the lowercase-only config class name.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
static::$moduleConfig ??= new Modules();
|
||||
|
||||
if (! static::$override) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->registerProperties();
|
||||
|
||||
$properties = array_keys(get_object_vars($this));
|
||||
$prefix = static::class;
|
||||
$slashAt = strrpos($prefix, '\\');
|
||||
$shortPrefix = strtolower(substr($prefix, $slashAt === false ? 0 : $slashAt + 1));
|
||||
|
||||
foreach ($properties as $property) {
|
||||
$this->initEnvValue($this->{$property}, $property, $prefix, $shortPrefix);
|
||||
|
||||
if ($this instanceof Encryption && $property === 'key') {
|
||||
if (str_starts_with($this->{$property}, 'hex2bin:')) {
|
||||
// Handle hex2bin prefix
|
||||
$this->{$property} = hex2bin(substr($this->{$property}, 8));
|
||||
} elseif (str_starts_with($this->{$property}, 'base64:')) {
|
||||
// Handle base64 prefix
|
||||
$this->{$property} = base64_decode(substr($this->{$property}, 7), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialization an environment-specific configuration setting
|
||||
*
|
||||
* @param array|bool|float|int|string|null $property
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function initEnvValue(&$property, string $name, string $prefix, string $shortPrefix)
|
||||
{
|
||||
if (is_array($property)) {
|
||||
foreach (array_keys($property) as $key) {
|
||||
$this->initEnvValue($property[$key], "{$name}.{$key}", $prefix, $shortPrefix);
|
||||
}
|
||||
} elseif (($value = $this->getEnvValue($name, $prefix, $shortPrefix)) !== false && $value !== null) {
|
||||
if ($value === 'false') {
|
||||
$value = false;
|
||||
} elseif ($value === 'true') {
|
||||
$value = true;
|
||||
}
|
||||
if (is_bool($value)) {
|
||||
$property = $value;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$value = trim($value, '\'"');
|
||||
|
||||
if (is_int($property)) {
|
||||
$value = (int) $value;
|
||||
} elseif (is_float($property)) {
|
||||
$value = (float) $value;
|
||||
}
|
||||
|
||||
// If the default value of the property is `null` and the type is not
|
||||
// `string`, TypeError will happen.
|
||||
// So cannot set `declare(strict_types=1)` in this file.
|
||||
$property = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an environment-specific configuration setting
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected function getEnvValue(string $property, string $prefix, string $shortPrefix)
|
||||
{
|
||||
$shortPrefix = ltrim($shortPrefix, '\\');
|
||||
$underscoreProperty = str_replace('.', '_', $property);
|
||||
|
||||
switch (true) {
|
||||
case array_key_exists("{$shortPrefix}.{$property}", $_ENV):
|
||||
return $_ENV["{$shortPrefix}.{$property}"];
|
||||
|
||||
case array_key_exists("{$shortPrefix}_{$underscoreProperty}", $_ENV):
|
||||
return $_ENV["{$shortPrefix}_{$underscoreProperty}"];
|
||||
|
||||
case array_key_exists("{$shortPrefix}.{$property}", $_SERVER):
|
||||
return $_SERVER["{$shortPrefix}.{$property}"];
|
||||
|
||||
case array_key_exists("{$shortPrefix}_{$underscoreProperty}", $_SERVER):
|
||||
return $_SERVER["{$shortPrefix}_{$underscoreProperty}"];
|
||||
|
||||
case array_key_exists("{$prefix}.{$property}", $_ENV):
|
||||
return $_ENV["{$prefix}.{$property}"];
|
||||
|
||||
case array_key_exists("{$prefix}_{$underscoreProperty}", $_ENV):
|
||||
return $_ENV["{$prefix}_{$underscoreProperty}"];
|
||||
|
||||
case array_key_exists("{$prefix}.{$property}", $_SERVER):
|
||||
return $_SERVER["{$prefix}.{$property}"];
|
||||
|
||||
case array_key_exists("{$prefix}_{$underscoreProperty}", $_SERVER):
|
||||
return $_SERVER["{$prefix}_{$underscoreProperty}"];
|
||||
|
||||
default:
|
||||
$value = getenv("{$shortPrefix}.{$property}");
|
||||
$value = $value === false ? getenv("{$shortPrefix}_{$underscoreProperty}") : $value;
|
||||
$value = $value === false ? getenv("{$prefix}.{$property}") : $value;
|
||||
$value = $value === false ? getenv("{$prefix}_{$underscoreProperty}") : $value;
|
||||
|
||||
return $value === false ? null : $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides external libraries a simple way to register one or more
|
||||
* options into a config file.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
protected function registerProperties()
|
||||
{
|
||||
if (! static::$moduleConfig->shouldDiscover('registrars')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! static::$didDiscovery) {
|
||||
// Discovery must be completed before the first instantiation of any Config class.
|
||||
if (static::$discovering) {
|
||||
throw new ConfigException(
|
||||
'During Auto-Discovery of Registrars,'
|
||||
. ' "' . static::class . '" executes Auto-Discovery again.'
|
||||
. ' "' . clean_path(static::$registrarFile) . '" seems to have bad code.',
|
||||
);
|
||||
}
|
||||
|
||||
static::$discovering = true;
|
||||
|
||||
/** @var FileLocatorInterface */
|
||||
$locator = service('locator');
|
||||
$registrarsFiles = $locator->search('Config/Registrar.php');
|
||||
|
||||
foreach ($registrarsFiles as $file) {
|
||||
// Saves the file for error message.
|
||||
static::$registrarFile = $file;
|
||||
|
||||
$className = $locator->findQualifiedNameFromPath($file);
|
||||
|
||||
if ($className === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
static::$registrars[] = new $className();
|
||||
}
|
||||
|
||||
static::$didDiscovery = true;
|
||||
static::$discovering = false;
|
||||
}
|
||||
|
||||
$shortName = (new ReflectionClass($this))->getShortName();
|
||||
|
||||
// Check the registrar class for a method named after this class' shortName
|
||||
foreach (static::$registrars as $callable) {
|
||||
// ignore non-applicable registrars
|
||||
if (! method_exists($callable, $shortName)) {
|
||||
continue; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$properties = $callable::$shortName();
|
||||
|
||||
if (! is_array($properties)) {
|
||||
throw new RuntimeException('Registrars must return an array of properties and their values.');
|
||||
}
|
||||
|
||||
foreach ($properties as $property => $value) {
|
||||
if (isset($this->{$property}) && is_array($this->{$property}) && is_array($value)) {
|
||||
$this->{$property} = array_merge($this->{$property}, $value);
|
||||
} else {
|
||||
$this->{$property} = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,432 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* 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\Autoloader\Autoloader;
|
||||
use CodeIgniter\Autoloader\FileLocator;
|
||||
use CodeIgniter\Autoloader\FileLocatorCached;
|
||||
use CodeIgniter\Autoloader\FileLocatorInterface;
|
||||
use CodeIgniter\Cache\CacheInterface;
|
||||
use CodeIgniter\Cache\ResponseCache;
|
||||
use CodeIgniter\CLI\Commands;
|
||||
use CodeIgniter\CodeIgniter;
|
||||
use CodeIgniter\Database\ConnectionInterface;
|
||||
use CodeIgniter\Database\MigrationRunner;
|
||||
use CodeIgniter\Debug\Exceptions;
|
||||
use CodeIgniter\Debug\Iterator;
|
||||
use CodeIgniter\Debug\Timer;
|
||||
use CodeIgniter\Debug\Toolbar;
|
||||
use CodeIgniter\Email\Email;
|
||||
use CodeIgniter\Encryption\EncrypterInterface;
|
||||
use CodeIgniter\Exceptions\InvalidArgumentException;
|
||||
use CodeIgniter\Filters\Filters;
|
||||
use CodeIgniter\Format\Format;
|
||||
use CodeIgniter\Honeypot\Honeypot;
|
||||
use CodeIgniter\HTTP\CLIRequest;
|
||||
use CodeIgniter\HTTP\ContentSecurityPolicy;
|
||||
use CodeIgniter\HTTP\CURLRequest;
|
||||
use CodeIgniter\HTTP\IncomingRequest;
|
||||
use CodeIgniter\HTTP\Negotiate;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use CodeIgniter\HTTP\Request;
|
||||
use CodeIgniter\HTTP\RequestInterface;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use CodeIgniter\HTTP\SiteURIFactory;
|
||||
use CodeIgniter\HTTP\URI;
|
||||
use CodeIgniter\Images\Handlers\BaseHandler;
|
||||
use CodeIgniter\Language\Language;
|
||||
use CodeIgniter\Log\Logger;
|
||||
use CodeIgniter\Pager\Pager;
|
||||
use CodeIgniter\Router\RouteCollection;
|
||||
use CodeIgniter\Router\RouteCollectionInterface;
|
||||
use CodeIgniter\Router\Router;
|
||||
use CodeIgniter\Security\Security;
|
||||
use CodeIgniter\Session\Session;
|
||||
use CodeIgniter\Superglobals;
|
||||
use CodeIgniter\Throttle\Throttler;
|
||||
use CodeIgniter\Typography\Typography;
|
||||
use CodeIgniter\Validation\ValidationInterface;
|
||||
use CodeIgniter\View\Cell;
|
||||
use CodeIgniter\View\Parser;
|
||||
use CodeIgniter\View\RendererInterface;
|
||||
use CodeIgniter\View\View;
|
||||
use Config\App;
|
||||
use Config\Autoload;
|
||||
use Config\Cache;
|
||||
use Config\ContentSecurityPolicy as CSPConfig;
|
||||
use Config\Encryption;
|
||||
use Config\Exceptions as ConfigExceptions;
|
||||
use Config\Filters as ConfigFilters;
|
||||
use Config\Format as ConfigFormat;
|
||||
use Config\Honeypot as ConfigHoneyPot;
|
||||
use Config\Images;
|
||||
use Config\Migrations;
|
||||
use Config\Modules;
|
||||
use Config\Optimize;
|
||||
use Config\Pager as ConfigPager;
|
||||
use Config\Services as AppServices;
|
||||
use Config\Session as ConfigSession;
|
||||
use Config\Toolbar as ConfigToolbar;
|
||||
use Config\Validation as ConfigValidation;
|
||||
use Config\View as ConfigView;
|
||||
|
||||
/**
|
||||
* Services Configuration file.
|
||||
*
|
||||
* Services are simply other classes/libraries that the system uses
|
||||
* to do its job. This is used by CodeIgniter to allow the core of the
|
||||
* framework to be swapped out easily without affecting the usage within
|
||||
* the rest of your application.
|
||||
*
|
||||
* This is used in place of a Dependency Injection container primarily
|
||||
* due to its simplicity, which allows a better long-term maintenance
|
||||
* of the applications built on top of CodeIgniter. A bonus side-effect
|
||||
* is that IDEs are able to determine what class you are calling
|
||||
* whereas with DI Containers there usually isn't a way for them to do this.
|
||||
*
|
||||
* Warning: To allow overrides by service providers do not use static calls,
|
||||
* instead call out to \Config\Services (imported as AppServices).
|
||||
*
|
||||
* @see http://blog.ircmaxell.com/2015/11/simple-easy-risk-and-change.html
|
||||
* @see http://www.infoq.com/presentations/Simple-Made-Easy
|
||||
*
|
||||
* @method static CacheInterface cache(Cache $config = null, $getShared = true)
|
||||
* @method static CLIRequest clirequest(App $config = null, $getShared = true)
|
||||
* @method static CodeIgniter codeigniter(App $config = null, $getShared = true)
|
||||
* @method static Commands commands($getShared = true)
|
||||
* @method static void createRequest(App $config, bool $isCli = false)
|
||||
* @method static ContentSecurityPolicy csp(CSPConfig $config = null, $getShared = true)
|
||||
* @method static CURLRequest curlrequest($options = [], ResponseInterface $response = null, App $config = null, $getShared = true)
|
||||
* @method static Email email($config = null, $getShared = true)
|
||||
* @method static EncrypterInterface encrypter(Encryption $config = null, $getShared = false)
|
||||
* @method static Exceptions exceptions(ConfigExceptions $config = null, $getShared = true)
|
||||
* @method static Filters filters(ConfigFilters $config = null, $getShared = true)
|
||||
* @method static Format format(ConfigFormat $config = null, $getShared = true)
|
||||
* @method static Honeypot honeypot(ConfigHoneyPot $config = null, $getShared = true)
|
||||
* @method static BaseHandler image($handler = null, Images $config = null, $getShared = true)
|
||||
* @method static IncomingRequest incomingrequest(?App $config = null, bool $getShared = true)
|
||||
* @method static Iterator iterator($getShared = true)
|
||||
* @method static Language language($locale = null, $getShared = true)
|
||||
* @method static Logger logger($getShared = true)
|
||||
* @method static MigrationRunner migrations(Migrations $config = null, ConnectionInterface $db = null, $getShared = true)
|
||||
* @method static Negotiate negotiator(RequestInterface $request = null, $getShared = true)
|
||||
* @method static Pager pager(ConfigPager $config = null, RendererInterface $view = null, $getShared = true)
|
||||
* @method static Parser parser($viewPath = null, ConfigView $config = null, $getShared = true)
|
||||
* @method static RedirectResponse redirectresponse(App $config = null, $getShared = true)
|
||||
* @method static View renderer($viewPath = null, ConfigView $config = null, $getShared = true)
|
||||
* @method static IncomingRequest|CLIRequest request(App $config = null, $getShared = true)
|
||||
* @method static ResponseInterface response(App $config = null, $getShared = true)
|
||||
* @method static ResponseCache responsecache(?Cache $config = null, ?CacheInterface $cache = null, bool $getShared = true)
|
||||
* @method static Router router(RouteCollectionInterface $routes = null, Request $request = null, $getShared = true)
|
||||
* @method static RouteCollection routes($getShared = true)
|
||||
* @method static Security security(App $config = null, $getShared = true)
|
||||
* @method static Session session(ConfigSession $config = null, $getShared = true)
|
||||
* @method static SiteURIFactory siteurifactory(App $config = null, Superglobals $superglobals = null, $getShared = true)
|
||||
* @method static Superglobals superglobals(array $server = null, array $get = null, bool $getShared = true)
|
||||
* @method static Throttler throttler($getShared = true)
|
||||
* @method static Timer timer($getShared = true)
|
||||
* @method static Toolbar toolbar(ConfigToolbar $config = null, $getShared = true)
|
||||
* @method static Typography typography($getShared = true)
|
||||
* @method static URI uri($uri = null, $getShared = true)
|
||||
* @method static ValidationInterface validation(ConfigValidation $config = null, $getShared = true)
|
||||
* @method static Cell viewcell($getShared = true)
|
||||
*/
|
||||
class BaseService
|
||||
{
|
||||
/**
|
||||
* Cache for instance of any services that
|
||||
* have been requested as a "shared" instance.
|
||||
* Keys should be lowercase service names.
|
||||
*
|
||||
* @var array<string, object> [key => instance]
|
||||
*/
|
||||
protected static $instances = [];
|
||||
|
||||
/**
|
||||
* Factory method list.
|
||||
*
|
||||
* @var array<string, (callable(mixed ...$params): object)> [key => callable]
|
||||
*/
|
||||
protected static array $factories = [];
|
||||
|
||||
/**
|
||||
* Mock objects for testing which are returned if exist.
|
||||
*
|
||||
* @var array<string, object> [key => instance]
|
||||
*/
|
||||
protected static $mocks = [];
|
||||
|
||||
/**
|
||||
* Have we already discovered other Services?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected static $discovered = false;
|
||||
|
||||
/**
|
||||
* A cache of other service classes we've found.
|
||||
*
|
||||
* @var array
|
||||
*
|
||||
* @deprecated 4.5.0 No longer used.
|
||||
*/
|
||||
protected static $services = [];
|
||||
|
||||
/**
|
||||
* A cache of the names of services classes found.
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
private static array $serviceNames = [];
|
||||
|
||||
/**
|
||||
* Simple method to get an entry fast.
|
||||
*
|
||||
* @param string $key Identifier of the entry to look for.
|
||||
*
|
||||
* @return object|null Entry.
|
||||
*/
|
||||
public static function get(string $key): ?object
|
||||
{
|
||||
return static::$instances[$key] ?? static::__callStatic($key, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an entry.
|
||||
*
|
||||
* @param string $key Identifier of the entry.
|
||||
*/
|
||||
public static function set(string $key, object $value): void
|
||||
{
|
||||
if (isset(static::$instances[$key])) {
|
||||
throw new InvalidArgumentException('The entry for "' . $key . '" is already set.');
|
||||
}
|
||||
|
||||
static::$instances[$key] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides an existing entry.
|
||||
*
|
||||
* @param string $key Identifier of the entry.
|
||||
*/
|
||||
public static function override(string $key, object $value): void
|
||||
{
|
||||
static::$instances[$key] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a shared instance of any of the class' services.
|
||||
*
|
||||
* $key must be a name matching a service.
|
||||
*
|
||||
* @param array|bool|float|int|object|string|null ...$params
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
protected static function getSharedInstance(string $key, ...$params)
|
||||
{
|
||||
$key = strtolower($key);
|
||||
|
||||
// Returns mock if exists
|
||||
if (isset(static::$mocks[$key])) {
|
||||
return static::$mocks[$key];
|
||||
}
|
||||
|
||||
if (! isset(static::$instances[$key])) {
|
||||
// Make sure $getShared is false
|
||||
$params[] = false;
|
||||
|
||||
static::$instances[$key] = AppServices::$key(...$params);
|
||||
}
|
||||
|
||||
return static::$instances[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* The Autoloader class is the central class that handles our
|
||||
* spl_autoload_register method, and helper methods.
|
||||
*
|
||||
* @return Autoloader
|
||||
*/
|
||||
public static function autoloader(bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
if (empty(static::$instances['autoloader'])) {
|
||||
static::$instances['autoloader'] = new Autoloader();
|
||||
}
|
||||
|
||||
return static::$instances['autoloader'];
|
||||
}
|
||||
|
||||
return new Autoloader();
|
||||
}
|
||||
|
||||
/**
|
||||
* The file locator provides utility methods for looking for non-classes
|
||||
* within namespaced folders, as well as convenience methods for
|
||||
* loading 'helpers', and 'libraries'.
|
||||
*
|
||||
* @return FileLocatorInterface
|
||||
*/
|
||||
public static function locator(bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
if (empty(static::$instances['locator'])) {
|
||||
$cacheEnabled = class_exists(Optimize::class)
|
||||
&& (new Optimize())->locatorCacheEnabled;
|
||||
|
||||
if ($cacheEnabled) {
|
||||
static::$instances['locator'] = new FileLocatorCached(new FileLocator(static::autoloader()));
|
||||
} else {
|
||||
static::$instances['locator'] = new FileLocator(static::autoloader());
|
||||
}
|
||||
}
|
||||
|
||||
return static::$mocks['locator'] ?? static::$instances['locator'];
|
||||
}
|
||||
|
||||
return new FileLocator(static::autoloader());
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the ability to perform case-insensitive calling of service
|
||||
* names.
|
||||
*
|
||||
* @return object|null
|
||||
*/
|
||||
public static function __callStatic(string $name, array $arguments)
|
||||
{
|
||||
if (isset(static::$factories[$name])) {
|
||||
return static::$factories[$name](...$arguments);
|
||||
}
|
||||
|
||||
$service = static::serviceExists($name);
|
||||
|
||||
if ($service === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $service::$name(...$arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the requested service is defined and return the declaring
|
||||
* class. Return null if not found.
|
||||
*/
|
||||
public static function serviceExists(string $name): ?string
|
||||
{
|
||||
static::buildServicesCache();
|
||||
|
||||
$services = array_merge(self::$serviceNames, [Services::class]);
|
||||
$name = strtolower($name);
|
||||
|
||||
foreach ($services as $service) {
|
||||
if (method_exists($service, $name)) {
|
||||
static::$factories[$name] = [$service, $name];
|
||||
|
||||
return $service;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset shared instances and mocks for testing.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @testTag only available to test code
|
||||
*/
|
||||
public static function reset(bool $initAutoloader = true)
|
||||
{
|
||||
static::$mocks = [];
|
||||
static::$instances = [];
|
||||
static::$factories = [];
|
||||
|
||||
if ($initAutoloader) {
|
||||
static::autoloader()->initialize(new Autoload(), new Modules());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets any mock and shared instances for a single service.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @testTag only available to test code
|
||||
*/
|
||||
public static function resetSingle(string $name)
|
||||
{
|
||||
$name = strtolower($name);
|
||||
unset(static::$mocks[$name], static::$instances[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject mock object for testing.
|
||||
*
|
||||
* @param object $mock
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @testTag only available to test code
|
||||
*/
|
||||
public static function injectMock(string $name, $mock)
|
||||
{
|
||||
static::$instances[$name] = $mock;
|
||||
static::$mocks[strtolower($name)] = $mock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the service cache.
|
||||
*/
|
||||
public static function resetServicesCache(): void
|
||||
{
|
||||
self::$serviceNames = [];
|
||||
static::$discovered = false;
|
||||
}
|
||||
|
||||
protected static function buildServicesCache(): void
|
||||
{
|
||||
if (! static::$discovered) {
|
||||
if ((new Modules())->shouldDiscover('services')) {
|
||||
$locator = static::locator();
|
||||
$files = $locator->search('Config/Services');
|
||||
|
||||
$systemPath = static::autoloader()->getNamespace('CodeIgniter')[0];
|
||||
|
||||
// Get instances of all service classes and cache them locally.
|
||||
foreach ($files as $file) {
|
||||
// Does not search `CodeIgniter` namespace to prevent from loading twice.
|
||||
if (str_starts_with($file, $systemPath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$classname = $locator->findQualifiedNameFromPath($file);
|
||||
|
||||
if ($classname === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($classname !== Services::class) {
|
||||
self::$serviceNames[] = $classname;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static::$discovered = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* 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\Exceptions\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Environment-specific configuration
|
||||
*
|
||||
* @see \CodeIgniter\Config\DotEnvTest
|
||||
*/
|
||||
class DotEnv
|
||||
{
|
||||
/**
|
||||
* The directory where the .env file can be located.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $path;
|
||||
|
||||
/**
|
||||
* Builds the path to our file.
|
||||
*/
|
||||
public function __construct(string $path, string $file = '.env')
|
||||
{
|
||||
$this->path = rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* The main entry point, will load the .env file and process it
|
||||
* so that we end up with all settings in the PHP environment vars
|
||||
* (i.e. getenv(), $_ENV, and $_SERVER)
|
||||
*/
|
||||
public function load(): bool
|
||||
{
|
||||
$vars = $this->parse();
|
||||
|
||||
return $vars !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the .env file into an array of key => value
|
||||
*/
|
||||
public function parse(): ?array
|
||||
{
|
||||
// We don't want to enforce the presence of a .env file, they should be optional.
|
||||
if (! is_file($this->path)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Ensure the file is readable
|
||||
if (! is_readable($this->path)) {
|
||||
throw new InvalidArgumentException("The .env file is not readable: {$this->path}");
|
||||
}
|
||||
|
||||
$vars = [];
|
||||
|
||||
$lines = file($this->path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||
|
||||
foreach ($lines as $line) {
|
||||
// Is it a comment?
|
||||
if (str_starts_with(trim($line), '#')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If there is an equal sign, then we know we are assigning a variable.
|
||||
if (str_contains($line, '=')) {
|
||||
[$name, $value] = $this->normaliseVariable($line);
|
||||
$vars[$name] = $value;
|
||||
$this->setVariable($name, $value);
|
||||
}
|
||||
}
|
||||
|
||||
return $vars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the variable into the environment. Will parse the string
|
||||
* first to look for {name}={value} pattern, ensure that nested
|
||||
* variables are handled, and strip it of single and double quotes.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function setVariable(string $name, string $value = '')
|
||||
{
|
||||
if (getenv($name, true) === false) {
|
||||
putenv("{$name}={$value}");
|
||||
}
|
||||
|
||||
if (empty($_ENV[$name])) {
|
||||
$_ENV[$name] = $value;
|
||||
}
|
||||
|
||||
if (empty($_SERVER[$name])) {
|
||||
$_SERVER[$name] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses for assignment, cleans the $name and $value, and ensures
|
||||
* that nested variables are handled.
|
||||
*/
|
||||
public function normaliseVariable(string $name, string $value = ''): array
|
||||
{
|
||||
// Split our compound string into its parts.
|
||||
if (str_contains($name, '=')) {
|
||||
[$name, $value] = explode('=', $name, 2);
|
||||
}
|
||||
|
||||
$name = trim($name);
|
||||
$value = trim($value);
|
||||
|
||||
// Sanitize the name
|
||||
$name = preg_replace('/^export[ \t]++(\S+)/', '$1', $name);
|
||||
$name = str_replace(['\'', '"'], '', $name);
|
||||
|
||||
// Sanitize the value
|
||||
$value = $this->sanitizeValue($value);
|
||||
$value = $this->resolveNestedVariables($value);
|
||||
|
||||
return [$name, $value];
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips quotes from the environment variable value.
|
||||
*
|
||||
* This was borrowed from the excellent phpdotenv with very few changes.
|
||||
* https://github.com/vlucas/phpdotenv
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
protected function sanitizeValue(string $value): string
|
||||
{
|
||||
if ($value === '') {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Does it begin with a quote?
|
||||
if (strpbrk($value[0], '"\'') !== false) {
|
||||
// value starts with a quote
|
||||
$quote = $value[0];
|
||||
|
||||
$regexPattern = sprintf(
|
||||
'/^
|
||||
%1$s # match a quote at the start of the value
|
||||
( # capturing sub-pattern used
|
||||
(?: # we do not need to capture this
|
||||
[^%1$s\\\\] # any character other than a quote or backslash
|
||||
|\\\\\\\\ # or two backslashes together
|
||||
|\\\\%1$s # or an escaped quote e.g \"
|
||||
)* # as many characters that match the previous rules
|
||||
) # end of the capturing sub-pattern
|
||||
%1$s # and the closing quote
|
||||
.*$ # and discard any string after the closing quote
|
||||
/mx',
|
||||
$quote,
|
||||
);
|
||||
|
||||
$value = preg_replace($regexPattern, '$1', $value);
|
||||
$value = str_replace("\\{$quote}", $quote, $value);
|
||||
$value = str_replace('\\\\', '\\', $value);
|
||||
} else {
|
||||
$parts = explode(' #', $value, 2);
|
||||
$value = trim($parts[0]);
|
||||
|
||||
// Unquoted values cannot contain whitespace
|
||||
if (preg_match('/\s+/', $value) > 0) {
|
||||
throw new InvalidArgumentException('.env values containing spaces must be surrounded by quotes.');
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the nested variables.
|
||||
*
|
||||
* Look for ${varname} patterns in the variable value and replace with an existing
|
||||
* environment variable.
|
||||
*
|
||||
* This was borrowed from the excellent phpdotenv with very few changes.
|
||||
* https://github.com/vlucas/phpdotenv
|
||||
*/
|
||||
protected function resolveNestedVariables(string $value): string
|
||||
{
|
||||
if (str_contains($value, '$')) {
|
||||
$value = preg_replace_callback(
|
||||
'/\${([a-zA-Z0-9_\.]+)}/',
|
||||
function ($matchedPatterns) {
|
||||
$nestedVariable = $this->getVariable($matchedPatterns[1]);
|
||||
|
||||
if ($nestedVariable === null) {
|
||||
return $matchedPatterns[0];
|
||||
}
|
||||
|
||||
return $nestedVariable;
|
||||
},
|
||||
$value,
|
||||
);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search the different places for environment variables and return first value found.
|
||||
*
|
||||
* This was borrowed from the excellent phpdotenv with very few changes.
|
||||
* https://github.com/vlucas/phpdotenv
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected function getVariable(string $name)
|
||||
{
|
||||
switch (true) {
|
||||
case array_key_exists($name, $_ENV):
|
||||
return $_ENV[$name];
|
||||
|
||||
case array_key_exists($name, $_SERVER):
|
||||
return $_SERVER[$name];
|
||||
|
||||
default:
|
||||
$value = getenv($name);
|
||||
|
||||
// switch getenv default to null
|
||||
return $value === false ? null : $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,564 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* 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\Autoloader\FileLocatorInterface;
|
||||
use CodeIgniter\Database\ConnectionInterface;
|
||||
use CodeIgniter\Exceptions\InvalidArgumentException;
|
||||
use CodeIgniter\Model;
|
||||
|
||||
/**
|
||||
* 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|null config(...$arguments)
|
||||
* @method static Model|null models(string $alias, array $options = [], ?ConnectionInterface &$conn = null)
|
||||
* @see \CodeIgniter\Config\FactoriesTest
|
||||
*/
|
||||
final class Factories
|
||||
{
|
||||
/**
|
||||
* Store of component-specific options, usually
|
||||
* from CodeIgniter\Config\Factory.
|
||||
*
|
||||
* @var array<string, array<string, bool|string|null>>
|
||||
*/
|
||||
private static array $options = [];
|
||||
|
||||
/**
|
||||
* Explicit options for the Config
|
||||
* component to prevent logic loops.
|
||||
*
|
||||
* @var array<string, bool|string|null>
|
||||
*/
|
||||
private static array $configOptions = [
|
||||
'component' => 'config',
|
||||
'path' => 'Config',
|
||||
'instanceOf' => null,
|
||||
'getShared' => true,
|
||||
'preferApp' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* Mapping of class aliases to their true Fully Qualified Class Name (FQCN).
|
||||
*
|
||||
* Class aliases can be:
|
||||
* - FQCN. E.g., 'App\Lib\SomeLib'
|
||||
* - short classname. E.g., 'SomeLib'
|
||||
* - short classname with sub-directories. E.g., 'Sub/SomeLib'
|
||||
*
|
||||
* [component => [alias => FQCN]]
|
||||
*
|
||||
* @var array<string, array<string, class-string>>
|
||||
*/
|
||||
private static array $aliases = [];
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* [component => [FQCN => instance]]
|
||||
*
|
||||
* @var array<string, array<class-string, object>>
|
||||
*/
|
||||
private static array $instances = [];
|
||||
|
||||
/**
|
||||
* Whether the component instances are updated?
|
||||
*
|
||||
* @var array<string, true> [component => true]
|
||||
*
|
||||
* @internal For caching only
|
||||
*/
|
||||
private static array $updated = [];
|
||||
|
||||
/**
|
||||
* Define the class to load. You can *override* the concrete class.
|
||||
*
|
||||
* @param string $component Lowercase, plural component name
|
||||
* @param string $alias Class alias. See the $aliases property.
|
||||
* @param class-string $classname FQCN to be loaded
|
||||
*/
|
||||
public static function define(string $component, string $alias, string $classname): void
|
||||
{
|
||||
$component = strtolower($component);
|
||||
|
||||
if (isset(self::$aliases[$component][$alias])) {
|
||||
if (self::$aliases[$component][$alias] === $classname) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException(
|
||||
'Already defined in Factories: ' . $component . ' ' . $alias . ' -> ' . self::$aliases[$component][$alias],
|
||||
);
|
||||
}
|
||||
|
||||
if (! class_exists($classname)) {
|
||||
throw new InvalidArgumentException('No such class: ' . $classname);
|
||||
}
|
||||
|
||||
// Force a configuration to exist for this component.
|
||||
// Otherwise, getOptions() will reset the component.
|
||||
self::getOptions($component);
|
||||
|
||||
self::$aliases[$component][$alias] = $classname;
|
||||
self::$updated[$component] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads instances based on the method component name. Either
|
||||
* creates a new instance or returns an existing shared instance.
|
||||
*
|
||||
* @return object|null
|
||||
*/
|
||||
public static function __callStatic(string $component, array $arguments)
|
||||
{
|
||||
$component = strtolower($component);
|
||||
|
||||
// First argument is the class alias, second is options
|
||||
$alias = trim(array_shift($arguments), '\\ ');
|
||||
$options = array_shift($arguments) ?? [];
|
||||
|
||||
// Determine the component-specific options
|
||||
$options = array_merge(self::getOptions($component), $options);
|
||||
|
||||
if (! $options['getShared']) {
|
||||
if (isset(self::$aliases[$options['component']][$alias])) {
|
||||
$class = self::$aliases[$options['component']][$alias];
|
||||
|
||||
return new $class(...$arguments);
|
||||
}
|
||||
|
||||
// Try to locate the class
|
||||
$class = self::locateClass($options, $alias);
|
||||
if ($class !== null) {
|
||||
return new $class(...$arguments);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check for an existing definition
|
||||
$instance = self::getDefinedInstance($options, $alias, $arguments);
|
||||
if ($instance !== null) {
|
||||
return $instance;
|
||||
}
|
||||
|
||||
// Try to locate the class
|
||||
if (($class = self::locateClass($options, $alias)) === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
self::createInstance($options['component'], $class, $arguments);
|
||||
self::setAlias($options['component'], $alias, $class);
|
||||
|
||||
return self::$instances[$options['component']][$class];
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple method to get the shared instance fast.
|
||||
*/
|
||||
public static function get(string $component, string $alias): ?object
|
||||
{
|
||||
if (isset(self::$aliases[$component][$alias])) {
|
||||
$class = self::$aliases[$component][$alias];
|
||||
|
||||
if (isset(self::$instances[$component][$class])) {
|
||||
return self::$instances[$component][$class];
|
||||
}
|
||||
}
|
||||
|
||||
return self::__callStatic($component, [$alias]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the defined instance. If not exists, creates new one.
|
||||
*
|
||||
* @return object|null
|
||||
*/
|
||||
private static function getDefinedInstance(array $options, string $alias, array $arguments)
|
||||
{
|
||||
// The alias is already defined.
|
||||
if (isset(self::$aliases[$options['component']][$alias])) {
|
||||
$class = self::$aliases[$options['component']][$alias];
|
||||
|
||||
// Need to verify if the shared instance matches the request
|
||||
if (self::verifyInstanceOf($options, $class)) {
|
||||
// Check for an existing instance
|
||||
if (isset(self::$instances[$options['component']][$class])) {
|
||||
return self::$instances[$options['component']][$class];
|
||||
}
|
||||
|
||||
self::createInstance($options['component'], $class, $arguments);
|
||||
|
||||
return self::$instances[$options['component']][$class];
|
||||
}
|
||||
}
|
||||
|
||||
// Try to locate the class
|
||||
if (($class = self::locateClass($options, $alias)) === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check for an existing instance for the class
|
||||
if (isset(self::$instances[$options['component']][$class])) {
|
||||
self::setAlias($options['component'], $alias, $class);
|
||||
|
||||
return self::$instances[$options['component']][$class];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the shared instance.
|
||||
*/
|
||||
private static function createInstance(string $component, string $class, array $arguments): void
|
||||
{
|
||||
self::$instances[$component][$class] = new $class(...$arguments);
|
||||
self::$updated[$component] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets alias
|
||||
*/
|
||||
private static function setAlias(string $component, string $alias, string $class): void
|
||||
{
|
||||
self::$aliases[$component][$alias] = $class;
|
||||
self::$updated[$component] = true;
|
||||
|
||||
// If a short classname is specified, also register FQCN to share the instance.
|
||||
if (! isset(self::$aliases[$component][$class]) && ! self::isNamespaced($alias)) {
|
||||
self::$aliases[$component][$class] = $class;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the component Config?
|
||||
*
|
||||
* @param string $component Lowercase, plural component name
|
||||
*/
|
||||
private static function isConfig(string $component): bool
|
||||
{
|
||||
return $component === 'config';
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a component class
|
||||
*
|
||||
* @param array $options The array of component-specific directives
|
||||
* @param string $alias Class alias. See the $aliases property.
|
||||
*/
|
||||
private static function locateClass(array $options, string $alias): ?string
|
||||
{
|
||||
// Check for low-hanging fruit
|
||||
if (
|
||||
class_exists($alias, false)
|
||||
&& self::verifyPreferApp($options, $alias)
|
||||
&& self::verifyInstanceOf($options, $alias)
|
||||
) {
|
||||
return $alias;
|
||||
}
|
||||
|
||||
// Determine the relative class names we need
|
||||
$basename = self::getBasename($alias);
|
||||
$appname = self::isConfig($options['component'])
|
||||
? 'Config\\' . $basename
|
||||
: rtrim(APP_NAMESPACE, '\\') . '\\' . $options['path'] . '\\' . $basename;
|
||||
|
||||
// If an App version was requested then see if it verifies
|
||||
if (
|
||||
// preferApp is used only for no namespaced class.
|
||||
! self::isNamespaced($alias)
|
||||
&& $options['preferApp'] && class_exists($appname)
|
||||
&& self::verifyInstanceOf($options, $alias)
|
||||
) {
|
||||
return $appname;
|
||||
}
|
||||
|
||||
// If we have ruled out an App version and the class exists then try it
|
||||
if (class_exists($alias) && self::verifyInstanceOf($options, $alias)) {
|
||||
return $alias;
|
||||
}
|
||||
|
||||
// Have to do this the hard way...
|
||||
/** @var FileLocatorInterface */
|
||||
$locator = service('locator');
|
||||
|
||||
// Check if the class alias was namespaced
|
||||
if (self::isNamespaced($alias)) {
|
||||
if (! $file = $locator->locateFile($alias, $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 . $alias)) === []) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check all files for a valid class
|
||||
foreach ($files as $file) {
|
||||
$class = $locator->findQualifiedNameFromPath($file);
|
||||
|
||||
if ($class !== false && self::verifyInstanceOf($options, $class)) {
|
||||
return $class;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the class alias namespaced or not?
|
||||
*
|
||||
* @param string $alias Class alias. See the $aliases property.
|
||||
*/
|
||||
private static function isNamespaced(string $alias): bool
|
||||
{
|
||||
return str_contains($alias, '\\');
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that a class & config satisfy the "preferApp" option
|
||||
*
|
||||
* @param array $options The array of component-specific directives
|
||||
* @param string $alias Class alias. See the $aliases property.
|
||||
*/
|
||||
private static function verifyPreferApp(array $options, string $alias): bool
|
||||
{
|
||||
// Anything without that restriction passes
|
||||
if (! $options['preferApp']) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Special case for Config since its App namespace is actually \Config
|
||||
if (self::isConfig($options['component'])) {
|
||||
return str_starts_with($alias, 'Config');
|
||||
}
|
||||
|
||||
return str_starts_with($alias, APP_NAMESPACE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that a class & config satisfy the "instanceOf" option
|
||||
*
|
||||
* @param array $options The array of component-specific directives
|
||||
* @param string $alias Class alias. See the $aliases property.
|
||||
*/
|
||||
private static function verifyInstanceOf(array $options, string $alias): bool
|
||||
{
|
||||
// Anything without that restriction passes
|
||||
if (! $options['instanceOf']) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return is_a($alias, $options['instanceOf'], true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the component-specific configuration
|
||||
*
|
||||
* @param string $component Lowercase, plural component name
|
||||
*
|
||||
* @return array<string, bool|string|null>
|
||||
*
|
||||
* @internal For testing only
|
||||
* @testTag
|
||||
*/
|
||||
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 = self::isConfig($component)
|
||||
// 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} ?? [];
|
||||
|
||||
// The setOptions() reset the component. So getOptions() may reset
|
||||
// the component.
|
||||
return self::setOptions($component, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes, stores, and returns the configuration for a specific component
|
||||
*
|
||||
* @param string $component Lowercase, plural component name
|
||||
* @param array $values option values
|
||||
*
|
||||
* @return array<string, bool|string|null> The result after applying defaults and normalization
|
||||
*/
|
||||
public static function setOptions(string $component, array $values): array
|
||||
{
|
||||
$component = strtolower($component);
|
||||
|
||||
// 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|null $component Lowercase, plural component name
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function reset(?string $component = null)
|
||||
{
|
||||
if ($component !== null) {
|
||||
unset(
|
||||
self::$options[$component],
|
||||
self::$aliases[$component],
|
||||
self::$instances[$component],
|
||||
self::$updated[$component],
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
self::$options = [];
|
||||
self::$aliases = [];
|
||||
self::$instances = [];
|
||||
self::$updated = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for injecting mock instances
|
||||
*
|
||||
* @param string $component Lowercase, plural component name
|
||||
* @param string $alias Class alias. See the $aliases property.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @internal For testing only
|
||||
* @testTag
|
||||
*/
|
||||
public static function injectMock(string $component, string $alias, object $instance)
|
||||
{
|
||||
$component = strtolower($component);
|
||||
|
||||
// Force a configuration to exist for this component
|
||||
self::getOptions($component);
|
||||
|
||||
$class = $instance::class;
|
||||
|
||||
self::$instances[$component][$class] = $instance;
|
||||
self::$aliases[$component][$alias] = $class;
|
||||
|
||||
if (self::isConfig($component)) {
|
||||
if (self::isNamespaced($alias)) {
|
||||
self::$aliases[$component][self::getBasename($alias)] = $class;
|
||||
} else {
|
||||
self::$aliases[$component]['Config\\' . $alias] = $class;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a basename from a class alias, namespaced or not.
|
||||
*
|
||||
* @internal For testing only
|
||||
* @testTag
|
||||
*/
|
||||
public static function getBasename(string $alias): string
|
||||
{
|
||||
// Determine the basename
|
||||
if ($basename = strrchr($alias, '\\')) {
|
||||
return substr($basename, 1);
|
||||
}
|
||||
|
||||
return $alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets component data for caching.
|
||||
*
|
||||
* @return array{
|
||||
* options: array<string, bool|string|null>,
|
||||
* aliases: array<string, class-string>,
|
||||
* instances: array<class-string, object>,
|
||||
* }
|
||||
*
|
||||
* @internal For caching only
|
||||
*/
|
||||
public static function getComponentInstances(string $component): array
|
||||
{
|
||||
if (! isset(self::$aliases[$component])) {
|
||||
return [
|
||||
'options' => [],
|
||||
'aliases' => [],
|
||||
'instances' => [],
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'options' => self::$options[$component],
|
||||
'aliases' => self::$aliases[$component],
|
||||
'instances' => self::$instances[$component],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets component data
|
||||
*
|
||||
* @internal For caching only
|
||||
*/
|
||||
public static function setComponentInstances(string $component, array $data): void
|
||||
{
|
||||
self::$options[$component] = $data['options'];
|
||||
self::$aliases[$component] = $data['aliases'];
|
||||
self::$instances[$component] = $data['instances'];
|
||||
|
||||
unset(self::$updated[$component]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the component instances are updated?
|
||||
*
|
||||
* @internal For caching only
|
||||
*/
|
||||
public static function isUpdated(string $component): bool
|
||||
{
|
||||
return isset(self::$updated[$component]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Factories Configuration file.
|
||||
*
|
||||
* Provides overriding directives for how
|
||||
* Factories should handle discovery and
|
||||
* instantiation of specific components.
|
||||
* Each property should correspond to the
|
||||
* lowercase, plural component name.
|
||||
*/
|
||||
class Factory extends BaseConfig
|
||||
{
|
||||
/**
|
||||
* Supplies a default set of options to merge for
|
||||
* all unspecified factory components.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $default = [
|
||||
'component' => null,
|
||||
'path' => null,
|
||||
'instanceOf' => null,
|
||||
'getShared' => true,
|
||||
'preferApp' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* Specifies that Models should always favor child
|
||||
* classes to allow easy extension of module Models.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $models = [
|
||||
'preferApp' => true,
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* 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\Filters\Cors;
|
||||
use CodeIgniter\Filters\CSRF;
|
||||
use CodeIgniter\Filters\DebugToolbar;
|
||||
use CodeIgniter\Filters\ForceHTTPS;
|
||||
use CodeIgniter\Filters\Honeypot;
|
||||
use CodeIgniter\Filters\InvalidChars;
|
||||
use CodeIgniter\Filters\PageCache;
|
||||
use CodeIgniter\Filters\PerformanceMetrics;
|
||||
use CodeIgniter\Filters\SecureHeaders;
|
||||
|
||||
/**
|
||||
* Filters configuration
|
||||
*/
|
||||
class Filters extends BaseConfig
|
||||
{
|
||||
/**
|
||||
* Configures aliases for Filter classes to
|
||||
* make reading things nicer and simpler.
|
||||
*
|
||||
* @var array<string, class-string|list<class-string>>
|
||||
*
|
||||
* [filter_name => classname]
|
||||
* or [filter_name => [classname1, classname2, ...]]
|
||||
*/
|
||||
public array $aliases = [
|
||||
'csrf' => CSRF::class,
|
||||
'toolbar' => DebugToolbar::class,
|
||||
'honeypot' => Honeypot::class,
|
||||
'invalidchars' => InvalidChars::class,
|
||||
'secureheaders' => SecureHeaders::class,
|
||||
'cors' => Cors::class,
|
||||
'forcehttps' => ForceHTTPS::class,
|
||||
'pagecache' => PageCache::class,
|
||||
'performance' => PerformanceMetrics::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* List of special required filters.
|
||||
*
|
||||
* The filters listed here are special. They are applied before and after
|
||||
* other kinds of filters, and always applied even if a route does not exist.
|
||||
*
|
||||
* Filters set by default provide framework functionality. If removed,
|
||||
* those functions will no longer work.
|
||||
*
|
||||
* @see https://codeigniter.com/user_guide/incoming/filters.html#provided-filters
|
||||
*
|
||||
* @var array{before: list<string>, after: list<string>}
|
||||
*/
|
||||
public array $required = [
|
||||
'before' => [
|
||||
'forcehttps', // Force Global Secure Requests
|
||||
'pagecache', // Web Page Caching
|
||||
],
|
||||
'after' => [
|
||||
'pagecache', // Web Page Caching
|
||||
'performance', // Performance Metrics
|
||||
'toolbar', // Debug Toolbar
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* List of filter aliases that are always
|
||||
* applied before and after every request.
|
||||
*
|
||||
* @var array<string, array<string, array<string, string>>>|array<string, list<string>>
|
||||
*/
|
||||
public array $globals = [
|
||||
'before' => [
|
||||
// 'honeypot',
|
||||
// 'csrf',
|
||||
// 'invalidchars',
|
||||
],
|
||||
'after' => [
|
||||
// 'honeypot',
|
||||
// 'secureheaders',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* List of filter aliases that works on a
|
||||
* particular HTTP method (GET, POST, etc.).
|
||||
*
|
||||
* Example:
|
||||
* 'POST' => ['foo', 'bar']
|
||||
*
|
||||
* If you use this, you should disable auto-routing because auto-routing
|
||||
* permits any HTTP method to access a controller. Accessing the controller
|
||||
* with a method you don't expect could bypass the filter.
|
||||
*
|
||||
* @var array<string, list<string>>
|
||||
*/
|
||||
public array $methods = [];
|
||||
|
||||
/**
|
||||
* List of filter aliases that should run on any
|
||||
* before or after URI patterns.
|
||||
*
|
||||
* Example:
|
||||
* 'isLoggedIn' => ['before' => ['account/*', 'profiles/*']]
|
||||
*
|
||||
* @var array<string, array<string, list<string>>>
|
||||
*/
|
||||
public array $filters = [];
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Describes foreign characters for transliteration with the text helper.
|
||||
*/
|
||||
class ForeignCharacters
|
||||
{
|
||||
/**
|
||||
* The list of foreign characters.
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public $characterList = [
|
||||
'/ä|æ|ǽ/' => 'ae',
|
||||
'/ö|œ/' => 'oe',
|
||||
'/ü/' => 'ue',
|
||||
'/Ä/' => 'Ae',
|
||||
'/Ü/' => 'Ue',
|
||||
'/Ö/' => 'Oe',
|
||||
'/À|Á|Â|Ã|Ä|Å|Ǻ|Ā|Ă|Ą|Ǎ|Α|Ά|Ả|Ạ|Ầ|Ẫ|Ẩ|Ậ|Ằ|Ắ|Ẵ|Ẳ|Ặ|А/' => 'A',
|
||||
'/à|á|â|ã|å|ǻ|ā|ă|ą|ǎ|ª|α|ά|ả|ạ|ầ|ấ|ẫ|ẩ|ậ|ằ|ắ|ẵ|ẳ|ặ|а/' => 'a',
|
||||
'/Б/' => 'B',
|
||||
'/б/' => 'b',
|
||||
'/Ç|Ć|Ĉ|Ċ|Č/' => 'C',
|
||||
'/ç|ć|ĉ|ċ|č/' => 'c',
|
||||
'/Д/' => 'D',
|
||||
'/д/' => 'd',
|
||||
'/Ð|Ď|Đ|Δ/' => 'Dj',
|
||||
'/ð|ď|đ|δ/' => 'dj',
|
||||
'/È|É|Ê|Ë|Ē|Ĕ|Ė|Ę|Ě|Ε|Έ|Ẽ|Ẻ|Ẹ|Ề|Ế|Ễ|Ể|Ệ|Е|Э/' => 'E',
|
||||
'/è|é|ê|ë|ē|ĕ|ė|ę|ě|έ|ε|ẽ|ẻ|ẹ|ề|ế|ễ|ể|ệ|е|э/' => 'e',
|
||||
'/Ф/' => 'F',
|
||||
'/ф/' => 'f',
|
||||
'/Ĝ|Ğ|Ġ|Ģ|Γ|Г|Ґ/' => 'G',
|
||||
'/ĝ|ğ|ġ|ģ|γ|г|ґ/' => 'g',
|
||||
'/Ĥ|Ħ/' => 'H',
|
||||
'/ĥ|ħ/' => 'h',
|
||||
'/Ì|Í|Î|Ï|Ĩ|Ī|Ĭ|Ǐ|Į|İ|Η|Ή|Ί|Ι|Ϊ|Ỉ|Ị|И|Ы/' => 'I',
|
||||
'/ì|í|î|ï|ĩ|ī|ĭ|ǐ|į|ı|η|ή|ί|ι|ϊ|ỉ|ị|и|ы|ї/' => 'i',
|
||||
'/Ĵ/' => 'J',
|
||||
'/ĵ/' => 'j',
|
||||
'/Ķ|Κ|К/' => 'K',
|
||||
'/ķ|κ|к/' => 'k',
|
||||
'/Ĺ|Ļ|Ľ|Ŀ|Ł|Λ|Л/' => 'L',
|
||||
'/ĺ|ļ|ľ|ŀ|ł|λ|л/' => 'l',
|
||||
'/М/' => 'M',
|
||||
'/м/' => 'm',
|
||||
'/Ñ|Ń|Ņ|Ň|Ν|Н/' => 'N',
|
||||
'/ñ|ń|ņ|ň|ʼn|ν|н/' => 'n',
|
||||
'/Ò|Ó|Ô|Õ|Ō|Ŏ|Ǒ|Ő|Ơ|Ø|Ǿ|Ο|Ό|Ω|Ώ|Ỏ|Ọ|Ồ|Ố|Ỗ|Ổ|Ộ|Ờ|Ớ|Ỡ|Ở|Ợ|О/' => 'O',
|
||||
'/ò|ó|ô|õ|ō|ŏ|ǒ|ő|ơ|ø|ǿ|º|ο|ό|ω|ώ|ỏ|ọ|ồ|ố|ỗ|ổ|ộ|ờ|ớ|ỡ|ở|ợ|о/' => 'o',
|
||||
'/П/' => 'P',
|
||||
'/п/' => 'p',
|
||||
'/Ŕ|Ŗ|Ř|Ρ|Р/' => 'R',
|
||||
'/ŕ|ŗ|ř|ρ|р/' => 'r',
|
||||
'/Ś|Ŝ|Ş|Ș|Š|Σ|С/' => 'S',
|
||||
'/ś|ŝ|ş|ș|š|ſ|σ|ς|с/' => 's',
|
||||
'/Ț|Ţ|Ť|Ŧ|τ|Т/' => 'T',
|
||||
'/ț|ţ|ť|ŧ|т/' => 't',
|
||||
'/Ù|Ú|Û|Ũ|Ū|Ŭ|Ů|Ű|Ų|Ư|Ǔ|Ǖ|Ǘ|Ǚ|Ǜ|Ũ|Ủ|Ụ|Ừ|Ứ|Ữ|Ử|Ự|У/' => 'U',
|
||||
'/ù|ú|û|ũ|ū|ŭ|ů|ű|ų|ư|ǔ|ǖ|ǘ|ǚ|ǜ|υ|ύ|ϋ|ủ|ụ|ừ|ứ|ữ|ử|ự|у/' => 'u',
|
||||
'/Ƴ|Ɏ|Ỵ|Ẏ|Ӳ|Ӯ|Ў|Ý|Ÿ|Ŷ|Υ|Ύ|Ϋ|Ỳ|Ỹ|Ỷ|Ỵ|Й/' => 'Y',
|
||||
'/ẙ|ʏ|ƴ|ɏ|ỵ|ẏ|ӳ|ӯ|ў|ý|ÿ|ŷ|ỳ|ỹ|ỷ|ỵ|й/' => 'y',
|
||||
'/В/' => 'V',
|
||||
'/в/' => 'v',
|
||||
'/Ŵ/' => 'W',
|
||||
'/ŵ/' => 'w',
|
||||
'/Ź|Ż|Ž|Ζ|З/' => 'Z',
|
||||
'/ź|ż|ž|ζ|з/' => 'z',
|
||||
'/Æ|Ǽ/' => 'AE',
|
||||
'/ß/' => 'ss',
|
||||
'/IJ/' => 'IJ',
|
||||
'/ij/' => 'ij',
|
||||
'/Œ/' => 'OE',
|
||||
'/ƒ/' => 'f',
|
||||
'/ξ/' => 'ks',
|
||||
'/π/' => 'p',
|
||||
'/β/' => 'v',
|
||||
'/μ/' => 'm',
|
||||
'/ψ/' => 'ps',
|
||||
'/Ё/' => 'Yo',
|
||||
'/ё/' => 'yo',
|
||||
'/Є/' => 'Ye',
|
||||
'/є/' => 'ye',
|
||||
'/Ї/' => 'Yi',
|
||||
'/Ж/' => 'Zh',
|
||||
'/ж/' => 'zh',
|
||||
'/Х/' => 'Kh',
|
||||
'/х/' => 'kh',
|
||||
'/Ц/' => 'Ts',
|
||||
'/ц/' => 'ts',
|
||||
'/Ч/' => 'Ch',
|
||||
'/ч/' => 'ch',
|
||||
'/Ш/' => 'Sh',
|
||||
'/ш/' => 'sh',
|
||||
'/Щ/' => 'Shch',
|
||||
'/щ/' => 'shch',
|
||||
'/Ъ|ъ|Ь|ь/' => '',
|
||||
'/Ю/' => 'Yu',
|
||||
'/ю/' => 'yu',
|
||||
'/Я/' => 'Ya',
|
||||
'/я/' => 'ya',
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Publisher Configuration
|
||||
*
|
||||
* Defines basic security restrictions for the Publisher class
|
||||
* to prevent abuse by injecting malicious files into a project.
|
||||
*/
|
||||
class Publisher extends BaseConfig
|
||||
{
|
||||
/**
|
||||
* A list of allowed destinations with a (pseudo-)regex
|
||||
* of allowed files for each destination.
|
||||
* Attempts to publish to directories not in this list will
|
||||
* result in a PublisherException. Files that do no fit the
|
||||
* pattern will cause copy/merge to fail.
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public $restrictions = [
|
||||
ROOTPATH => '*',
|
||||
FCPATH => '#\.(?css|js|map|htm?|xml|json|webmanifest|tff|eot|woff?|gif|jpe?g|tiff?|png|webp|bmp|ico|svg)$#i',
|
||||
];
|
||||
|
||||
/**
|
||||
* Disables Registrars to prevent modules from altering the restrictions.
|
||||
*/
|
||||
final protected function registerProperties(): void
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Routing configuration
|
||||
*/
|
||||
class Routing extends BaseConfig
|
||||
{
|
||||
/**
|
||||
* For Defined Routes.
|
||||
* An array of files that contain route definitions.
|
||||
* Route files are read in order, with the first match
|
||||
* found taking precedence.
|
||||
*
|
||||
* Default: APPPATH . 'Config/Routes.php'
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
public array $routeFiles = [
|
||||
APPPATH . 'Config/Routes.php',
|
||||
];
|
||||
|
||||
/**
|
||||
* For Defined Routes and Auto Routing.
|
||||
* The default namespace to use for Controllers when no other
|
||||
* namespace has been specified.
|
||||
*
|
||||
* Default: 'App\Controllers'
|
||||
*/
|
||||
public string $defaultNamespace = 'App\Controllers';
|
||||
|
||||
/**
|
||||
* For Auto Routing.
|
||||
* The default controller to use when no other controller has been
|
||||
* specified.
|
||||
*
|
||||
* Default: 'Home'
|
||||
*/
|
||||
public string $defaultController = 'Home';
|
||||
|
||||
/**
|
||||
* For Defined Routes and Auto Routing.
|
||||
* The default method to call on the controller when no other
|
||||
* method has been set in the route.
|
||||
*
|
||||
* Default: 'index'
|
||||
*/
|
||||
public string $defaultMethod = 'index';
|
||||
|
||||
/**
|
||||
* For Auto Routing.
|
||||
* Whether to translate dashes in URIs for controller/method to underscores.
|
||||
* Primarily useful when using the auto-routing.
|
||||
*
|
||||
* Default: false
|
||||
*/
|
||||
public bool $translateURIDashes = false;
|
||||
|
||||
/**
|
||||
* Sets the class/method that should be called if routing doesn't
|
||||
* find a match. It can be the controller/method name like: Users::index
|
||||
*
|
||||
* This setting is passed to the Router class and handled there.
|
||||
*
|
||||
* If you want to use a closure, you will have to set it in the
|
||||
* routes file by calling:
|
||||
*
|
||||
* $routes->set404Override(function() {
|
||||
* // Do something here
|
||||
* });
|
||||
*
|
||||
* Example:
|
||||
* public $override404 = 'App\Errors::show404';
|
||||
*/
|
||||
public ?string $override404 = null;
|
||||
|
||||
/**
|
||||
* If TRUE, the system will attempt to match the URI against
|
||||
* Controllers by matching each segment against folders/files
|
||||
* in APPPATH/Controllers, when a match wasn't found against
|
||||
* defined routes.
|
||||
*
|
||||
* If FALSE, will stop searching and do NO automatic routing.
|
||||
*/
|
||||
public bool $autoRoute = false;
|
||||
|
||||
/**
|
||||
* For Defined Routes.
|
||||
* If TRUE, will enable the use of the 'prioritize' option
|
||||
* when defining routes.
|
||||
*
|
||||
* Default: false
|
||||
*/
|
||||
public bool $prioritize = false;
|
||||
|
||||
/**
|
||||
* For Defined Routes.
|
||||
* If TRUE, matched multiple URI segments will be passed as one parameter.
|
||||
*
|
||||
* Default: false
|
||||
*/
|
||||
public bool $multipleSegmentsOneParam = false;
|
||||
|
||||
/**
|
||||
* For Auto Routing (Improved).
|
||||
* Map of URI segments and namespaces.
|
||||
*
|
||||
* The key is the first URI segment. The value is the controller namespace.
|
||||
* E.g.,
|
||||
* [
|
||||
* 'blog' => 'Acme\Blog\Controllers',
|
||||
* ]
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public array $moduleRoutes = [];
|
||||
|
||||
/**
|
||||
* For Auto Routing (Improved).
|
||||
* Whether to translate dashes in URIs for controller/method to CamelCase.
|
||||
* E.g., blog-controller -> BlogController
|
||||
*
|
||||
* If you enable this, $translateURIDashes is ignored.
|
||||
*
|
||||
* Default: false
|
||||
*/
|
||||
public bool $translateUriToCamelCase = false;
|
||||
}
|
||||
@@ -0,0 +1,866 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* 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\Cache\CacheFactory;
|
||||
use CodeIgniter\Cache\CacheInterface;
|
||||
use CodeIgniter\Cache\ResponseCache;
|
||||
use CodeIgniter\CLI\Commands;
|
||||
use CodeIgniter\CodeIgniter;
|
||||
use CodeIgniter\Database\ConnectionInterface;
|
||||
use CodeIgniter\Database\MigrationRunner;
|
||||
use CodeIgniter\Debug\Exceptions;
|
||||
use CodeIgniter\Debug\Iterator;
|
||||
use CodeIgniter\Debug\Timer;
|
||||
use CodeIgniter\Debug\Toolbar;
|
||||
use CodeIgniter\Email\Email;
|
||||
use CodeIgniter\Encryption\EncrypterInterface;
|
||||
use CodeIgniter\Encryption\Encryption;
|
||||
use CodeIgniter\Filters\Filters;
|
||||
use CodeIgniter\Format\Format;
|
||||
use CodeIgniter\Honeypot\Honeypot;
|
||||
use CodeIgniter\HTTP\CLIRequest;
|
||||
use CodeIgniter\HTTP\ContentSecurityPolicy;
|
||||
use CodeIgniter\HTTP\CURLRequest;
|
||||
use CodeIgniter\HTTP\IncomingRequest;
|
||||
use CodeIgniter\HTTP\Negotiate;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use CodeIgniter\HTTP\Request;
|
||||
use CodeIgniter\HTTP\RequestInterface;
|
||||
use CodeIgniter\HTTP\Response;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use CodeIgniter\HTTP\SiteURIFactory;
|
||||
use CodeIgniter\HTTP\URI;
|
||||
use CodeIgniter\HTTP\UserAgent;
|
||||
use CodeIgniter\Images\Handlers\BaseHandler;
|
||||
use CodeIgniter\Language\Language;
|
||||
use CodeIgniter\Log\Logger;
|
||||
use CodeIgniter\Pager\Pager;
|
||||
use CodeIgniter\Router\RouteCollection;
|
||||
use CodeIgniter\Router\RouteCollectionInterface;
|
||||
use CodeIgniter\Router\Router;
|
||||
use CodeIgniter\Security\Security;
|
||||
use CodeIgniter\Session\Handlers\BaseHandler as SessionBaseHandler;
|
||||
use CodeIgniter\Session\Handlers\Database\MySQLiHandler;
|
||||
use CodeIgniter\Session\Handlers\Database\PostgreHandler;
|
||||
use CodeIgniter\Session\Handlers\DatabaseHandler;
|
||||
use CodeIgniter\Session\Session;
|
||||
use CodeIgniter\Superglobals;
|
||||
use CodeIgniter\Throttle\Throttler;
|
||||
use CodeIgniter\Typography\Typography;
|
||||
use CodeIgniter\Validation\Validation;
|
||||
use CodeIgniter\Validation\ValidationInterface;
|
||||
use CodeIgniter\View\Cell;
|
||||
use CodeIgniter\View\Parser;
|
||||
use CodeIgniter\View\RendererInterface;
|
||||
use CodeIgniter\View\View;
|
||||
use Config\App;
|
||||
use Config\Cache;
|
||||
use Config\ContentSecurityPolicy as ContentSecurityPolicyConfig;
|
||||
use Config\ContentSecurityPolicy as CSPConfig;
|
||||
use Config\Database;
|
||||
use Config\Email as EmailConfig;
|
||||
use Config\Encryption as EncryptionConfig;
|
||||
use Config\Exceptions as ExceptionsConfig;
|
||||
use Config\Filters as FiltersConfig;
|
||||
use Config\Format as FormatConfig;
|
||||
use Config\Honeypot as HoneypotConfig;
|
||||
use Config\Images;
|
||||
use Config\Logger as LoggerConfig;
|
||||
use Config\Migrations;
|
||||
use Config\Modules;
|
||||
use Config\Pager as PagerConfig;
|
||||
use Config\Paths;
|
||||
use Config\Routing;
|
||||
use Config\Security as SecurityConfig;
|
||||
use Config\Services as AppServices;
|
||||
use Config\Session as SessionConfig;
|
||||
use Config\Toolbar as ToolbarConfig;
|
||||
use Config\Validation as ValidationConfig;
|
||||
use Config\View as ViewConfig;
|
||||
use InvalidArgumentException;
|
||||
use Locale;
|
||||
|
||||
/**
|
||||
* Services Configuration file.
|
||||
*
|
||||
* Services are simply other classes/libraries that the system uses
|
||||
* to do its job. This is used by CodeIgniter to allow the core of the
|
||||
* framework to be swapped out easily without affecting the usage within
|
||||
* the rest of your application.
|
||||
*
|
||||
* This is used in place of a Dependency Injection container primarily
|
||||
* due to its simplicity, which allows a better long-term maintenance
|
||||
* of the applications built on top of CodeIgniter. A bonus side-effect
|
||||
* is that IDEs are able to determine what class you are calling
|
||||
* whereas with DI Containers there usually isn't a way for them to do this.
|
||||
*
|
||||
* @see http://blog.ircmaxell.com/2015/11/simple-easy-risk-and-change.html
|
||||
* @see http://www.infoq.com/presentations/Simple-Made-Easy
|
||||
* @see \CodeIgniter\Config\ServicesTest
|
||||
*/
|
||||
class Services extends BaseService
|
||||
{
|
||||
/**
|
||||
* The cache class provides a simple way to store and retrieve
|
||||
* complex data for later.
|
||||
*
|
||||
* @return CacheInterface
|
||||
*/
|
||||
public static function cache(?Cache $config = null, bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('cache', $config);
|
||||
}
|
||||
|
||||
$config ??= config(Cache::class);
|
||||
|
||||
return CacheFactory::getHandler($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* The CLI Request class provides for ways to interact with
|
||||
* a command line request.
|
||||
*
|
||||
* @return CLIRequest
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public static function clirequest(?App $config = null, bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('clirequest', $config);
|
||||
}
|
||||
|
||||
$config ??= config(App::class);
|
||||
|
||||
return new CLIRequest($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* CodeIgniter, the core of the framework.
|
||||
*
|
||||
* @return CodeIgniter
|
||||
*/
|
||||
public static function codeigniter(?App $config = null, bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('codeigniter', $config);
|
||||
}
|
||||
|
||||
$config ??= config(App::class);
|
||||
|
||||
return new CodeIgniter($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* The commands utility for running and working with CLI commands.
|
||||
*
|
||||
* @return Commands
|
||||
*/
|
||||
public static function commands(bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('commands');
|
||||
}
|
||||
|
||||
return new Commands();
|
||||
}
|
||||
|
||||
/**
|
||||
* Content Security Policy
|
||||
*
|
||||
* @return ContentSecurityPolicy
|
||||
*/
|
||||
public static function csp(?CSPConfig $config = null, bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('csp', $config);
|
||||
}
|
||||
|
||||
$config ??= config(ContentSecurityPolicyConfig::class);
|
||||
|
||||
return new ContentSecurityPolicy($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* The CURL Request class acts as a simple HTTP client for interacting
|
||||
* with other servers, typically through APIs.
|
||||
*
|
||||
* @return CURLRequest
|
||||
*/
|
||||
public static function curlrequest(array $options = [], ?ResponseInterface $response = null, ?App $config = null, bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('curlrequest', $options, $response, $config);
|
||||
}
|
||||
|
||||
$config ??= config(App::class);
|
||||
$response ??= new Response($config);
|
||||
|
||||
return new CURLRequest(
|
||||
$config,
|
||||
new URI($options['baseURI'] ?? null),
|
||||
$response,
|
||||
$options,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Email class allows you to send email via mail, sendmail, SMTP.
|
||||
*
|
||||
* @param array|EmailConfig|null $config
|
||||
*
|
||||
* @return Email
|
||||
*/
|
||||
public static function email($config = null, bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('email', $config);
|
||||
}
|
||||
|
||||
if (empty($config) || (! is_array($config) && ! $config instanceof EmailConfig)) {
|
||||
$config = config(EmailConfig::class);
|
||||
}
|
||||
|
||||
return new Email($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Encryption class provides two-way encryption.
|
||||
*
|
||||
* @param bool $getShared
|
||||
*
|
||||
* @return EncrypterInterface Encryption handler
|
||||
*/
|
||||
public static function encrypter(?EncryptionConfig $config = null, $getShared = false)
|
||||
{
|
||||
if ($getShared === true) {
|
||||
return static::getSharedInstance('encrypter', $config);
|
||||
}
|
||||
|
||||
$config ??= config(EncryptionConfig::class);
|
||||
$encryption = new Encryption($config);
|
||||
|
||||
return $encryption->initialize($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Exceptions class holds the methods that handle:
|
||||
*
|
||||
* - set_exception_handler
|
||||
* - set_error_handler
|
||||
* - register_shutdown_function
|
||||
*
|
||||
* @return Exceptions
|
||||
*/
|
||||
public static function exceptions(
|
||||
?ExceptionsConfig $config = null,
|
||||
bool $getShared = true,
|
||||
) {
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('exceptions', $config);
|
||||
}
|
||||
|
||||
$config ??= config(ExceptionsConfig::class);
|
||||
|
||||
return new Exceptions($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters allow you to run tasks before and/or after a controller
|
||||
* is executed. During before filters, the request can be modified,
|
||||
* and actions taken based on the request, while after filters can
|
||||
* act on or modify the response itself before it is sent to the client.
|
||||
*
|
||||
* @return Filters
|
||||
*/
|
||||
public static function filters(?FiltersConfig $config = null, bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('filters', $config);
|
||||
}
|
||||
|
||||
$config ??= config(FiltersConfig::class);
|
||||
|
||||
return new Filters($config, AppServices::get('request'), AppServices::get('response'));
|
||||
}
|
||||
|
||||
/**
|
||||
* The Format class is a convenient place to create Formatters.
|
||||
*
|
||||
* @return Format
|
||||
*/
|
||||
public static function format(?FormatConfig $config = null, bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('format', $config);
|
||||
}
|
||||
|
||||
$config ??= config(FormatConfig::class);
|
||||
|
||||
return new Format($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Honeypot provides a secret input on forms that bots should NOT
|
||||
* fill in, providing an additional safeguard when accepting user input.
|
||||
*
|
||||
* @return Honeypot
|
||||
*/
|
||||
public static function honeypot(?HoneypotConfig $config = null, bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('honeypot', $config);
|
||||
}
|
||||
|
||||
$config ??= config(HoneypotConfig::class);
|
||||
|
||||
return new Honeypot($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Acts as a factory for ImageHandler classes and returns an instance
|
||||
* of the handler. Used like service('image')->withFile($path)->rotate(90)->save();
|
||||
*
|
||||
* @return BaseHandler
|
||||
*/
|
||||
public static function image(?string $handler = null, ?Images $config = null, bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('image', $handler, $config);
|
||||
}
|
||||
|
||||
$config ??= config(Images::class);
|
||||
assert($config instanceof Images);
|
||||
|
||||
$handler = $handler !== null && $handler !== '' && $handler !== '0' ? $handler : $config->defaultHandler;
|
||||
$class = $config->handlers[$handler];
|
||||
|
||||
return new $class($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Iterator class provides a simple way of looping over a function
|
||||
* and timing the results and memory usage. Used when debugging and
|
||||
* optimizing applications.
|
||||
*
|
||||
* @return Iterator
|
||||
*/
|
||||
public static function iterator(bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('iterator');
|
||||
}
|
||||
|
||||
return new Iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Responsible for loading the language string translations.
|
||||
*
|
||||
* @return Language
|
||||
*/
|
||||
public static function language(?string $locale = null, bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('language', $locale)->setLocale($locale);
|
||||
}
|
||||
|
||||
if (AppServices::get('request') instanceof IncomingRequest) {
|
||||
$requestLocale = AppServices::get('request')->getLocale();
|
||||
} else {
|
||||
$requestLocale = Locale::getDefault();
|
||||
}
|
||||
|
||||
// Use '?:' for empty string check
|
||||
$locale = $locale !== null && $locale !== '' && $locale !== '0' ? $locale : $requestLocale;
|
||||
|
||||
return new Language($locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Logger class is a PSR-3 compatible Logging class that supports
|
||||
* multiple handlers that process the actual logging.
|
||||
*
|
||||
* @return Logger
|
||||
*/
|
||||
public static function logger(bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('logger');
|
||||
}
|
||||
|
||||
return new Logger(config(LoggerConfig::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the appropriate Migration runner.
|
||||
*
|
||||
* @return MigrationRunner
|
||||
*/
|
||||
public static function migrations(?Migrations $config = null, ?ConnectionInterface $db = null, bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('migrations', $config, $db);
|
||||
}
|
||||
|
||||
$config ??= config(Migrations::class);
|
||||
|
||||
return new MigrationRunner($config, $db);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Negotiate class provides the content negotiation features for
|
||||
* working the request to determine correct language, encoding, charset,
|
||||
* and more.
|
||||
*
|
||||
* @return Negotiate
|
||||
*/
|
||||
public static function negotiator(?RequestInterface $request = null, bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('negotiator', $request);
|
||||
}
|
||||
|
||||
$request ??= AppServices::get('request');
|
||||
|
||||
return new Negotiate($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ResponseCache.
|
||||
*
|
||||
* @return ResponseCache
|
||||
*/
|
||||
public static function responsecache(?Cache $config = null, ?CacheInterface $cache = null, bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('responsecache', $config, $cache);
|
||||
}
|
||||
|
||||
$config ??= config(Cache::class);
|
||||
$cache ??= AppServices::get('cache');
|
||||
|
||||
return new ResponseCache($config, $cache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the appropriate pagination handler.
|
||||
*
|
||||
* @return Pager
|
||||
*/
|
||||
public static function pager(?PagerConfig $config = null, ?RendererInterface $view = null, bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('pager', $config, $view);
|
||||
}
|
||||
|
||||
$config ??= config(PagerConfig::class);
|
||||
$view ??= AppServices::renderer(null, null, false);
|
||||
|
||||
return new Pager($config, $view);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Parser is a simple template parser.
|
||||
*
|
||||
* @return Parser
|
||||
*/
|
||||
public static function parser(?string $viewPath = null, ?ViewConfig $config = null, bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('parser', $viewPath, $config);
|
||||
}
|
||||
|
||||
$viewPath = $viewPath !== null && $viewPath !== '' && $viewPath !== '0' ? $viewPath : (new Paths())->viewDirectory;
|
||||
$config ??= config(ViewConfig::class);
|
||||
|
||||
return new Parser($config, $viewPath, AppServices::get('locator'), CI_DEBUG, AppServices::get('logger'));
|
||||
}
|
||||
|
||||
/**
|
||||
* The Renderer class is the class that actually displays a file to the user.
|
||||
* The default View class within CodeIgniter is intentionally simple, but this
|
||||
* service could easily be replaced by a template engine if the user needed to.
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public static function renderer(?string $viewPath = null, ?ViewConfig $config = null, bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('renderer', $viewPath, $config);
|
||||
}
|
||||
|
||||
$viewPath = $viewPath !== null && $viewPath !== '' && $viewPath !== '0' ? $viewPath : (new Paths())->viewDirectory;
|
||||
$config ??= config(ViewConfig::class);
|
||||
|
||||
return new View($config, $viewPath, AppServices::get('locator'), CI_DEBUG, AppServices::get('logger'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current Request object.
|
||||
*
|
||||
* createRequest() injects IncomingRequest or CLIRequest.
|
||||
*
|
||||
* @return CLIRequest|IncomingRequest
|
||||
*
|
||||
* @deprecated The parameter $config and $getShared are deprecated.
|
||||
*/
|
||||
public static function request(?App $config = null, bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('request', $config);
|
||||
}
|
||||
|
||||
// @TODO remove the following code for backward compatibility
|
||||
return AppServices::incomingrequest($config, $getShared);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the current Request object, either IncomingRequest or CLIRequest.
|
||||
*
|
||||
* This method is called from CodeIgniter::getRequestObject().
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public static function createRequest(App $config, bool $isCli = false): void
|
||||
{
|
||||
if ($isCli) {
|
||||
$request = AppServices::clirequest($config);
|
||||
} else {
|
||||
$request = AppServices::incomingrequest($config);
|
||||
|
||||
// guess at protocol if needed
|
||||
$request->setProtocolVersion($_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.1');
|
||||
}
|
||||
|
||||
// Inject the request object into Services.
|
||||
static::$instances['request'] = $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* The IncomingRequest class models an HTTP request.
|
||||
*
|
||||
* @return IncomingRequest
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public static function incomingrequest(?App $config = null, bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('request', $config);
|
||||
}
|
||||
|
||||
$config ??= config(App::class);
|
||||
|
||||
return new IncomingRequest(
|
||||
$config,
|
||||
AppServices::get('uri'),
|
||||
'php://input',
|
||||
new UserAgent(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Response class models an HTTP response.
|
||||
*
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public static function response(?App $config = null, bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('response', $config);
|
||||
}
|
||||
|
||||
$config ??= config(App::class);
|
||||
|
||||
return new Response($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Redirect class provides nice way of working with redirects.
|
||||
*
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public static function redirectresponse(?App $config = null, bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('redirectresponse', $config);
|
||||
}
|
||||
|
||||
$config ??= config(App::class);
|
||||
$response = new RedirectResponse($config);
|
||||
$response->setProtocolVersion(AppServices::get('request')->getProtocolVersion());
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Routes service is a class that allows for easily building
|
||||
* a collection of routes.
|
||||
*
|
||||
* @return RouteCollection
|
||||
*/
|
||||
public static function routes(bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('routes');
|
||||
}
|
||||
|
||||
return new RouteCollection(AppServices::get('locator'), new Modules(), config(Routing::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* The Router class uses a RouteCollection's array of routes, and determines
|
||||
* the correct Controller and Method to execute.
|
||||
*
|
||||
* @return Router
|
||||
*/
|
||||
public static function router(?RouteCollectionInterface $routes = null, ?Request $request = null, bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('router', $routes, $request);
|
||||
}
|
||||
|
||||
$routes ??= AppServices::get('routes');
|
||||
$request ??= AppServices::get('request');
|
||||
|
||||
return new Router($routes, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Security class provides a few handy tools for keeping the site
|
||||
* secure, most notably the CSRF protection tools.
|
||||
*
|
||||
* @return Security
|
||||
*/
|
||||
public static function security(?SecurityConfig $config = null, bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('security', $config);
|
||||
}
|
||||
|
||||
$config ??= config(SecurityConfig::class);
|
||||
|
||||
return new Security($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the session manager.
|
||||
*
|
||||
* @return Session
|
||||
*/
|
||||
public static function session(?SessionConfig $config = null, bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('session', $config);
|
||||
}
|
||||
|
||||
$config ??= config(SessionConfig::class);
|
||||
|
||||
$logger = AppServices::get('logger');
|
||||
|
||||
$driverName = $config->driver;
|
||||
|
||||
if ($driverName === DatabaseHandler::class) {
|
||||
$DBGroup = $config->DBGroup ?? config(Database::class)->defaultGroup;
|
||||
|
||||
$driverPlatform = Database::connect($DBGroup)->getPlatform();
|
||||
|
||||
if ($driverPlatform === 'MySQLi') {
|
||||
$driverName = MySQLiHandler::class;
|
||||
} elseif ($driverPlatform === 'Postgre') {
|
||||
$driverName = PostgreHandler::class;
|
||||
}
|
||||
}
|
||||
|
||||
if (! class_exists($driverName) || ! is_a($driverName, SessionBaseHandler::class, true)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Invalid session handler "%s" provided.',
|
||||
$driverName,
|
||||
));
|
||||
}
|
||||
|
||||
/** @var SessionBaseHandler $driver */
|
||||
$driver = new $driverName($config, AppServices::get('request')->getIPAddress());
|
||||
$driver->setLogger($logger);
|
||||
|
||||
$session = new Session($driver, $config);
|
||||
$session->setLogger($logger);
|
||||
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
// PHP Session emits the headers according to `session.cache_limiter`.
|
||||
// See https://www.php.net/manual/en/function.session-cache-limiter.php.
|
||||
// The headers are not managed by CI's Response class.
|
||||
// So, we remove CI's default Cache-Control header.
|
||||
AppServices::get('response')->removeHeader('Cache-Control');
|
||||
|
||||
$session->start();
|
||||
}
|
||||
|
||||
return $session;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Factory for SiteURI.
|
||||
*
|
||||
* @return SiteURIFactory
|
||||
*/
|
||||
public static function siteurifactory(
|
||||
?App $config = null,
|
||||
?Superglobals $superglobals = null,
|
||||
bool $getShared = true,
|
||||
) {
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('siteurifactory', $config, $superglobals);
|
||||
}
|
||||
|
||||
$config ??= config('App');
|
||||
$superglobals ??= AppServices::get('superglobals');
|
||||
|
||||
return new SiteURIFactory($config, $superglobals);
|
||||
}
|
||||
|
||||
/**
|
||||
* Superglobals.
|
||||
*
|
||||
* @return Superglobals
|
||||
*/
|
||||
public static function superglobals(
|
||||
?array $server = null,
|
||||
?array $get = null,
|
||||
bool $getShared = true,
|
||||
) {
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('superglobals', $server, $get);
|
||||
}
|
||||
|
||||
return new Superglobals($server, $get);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Throttler class provides a simple method for implementing
|
||||
* rate limiting in your applications.
|
||||
*
|
||||
* @return Throttler
|
||||
*/
|
||||
public static function throttler(bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('throttler');
|
||||
}
|
||||
|
||||
return new Throttler(AppServices::get('cache'));
|
||||
}
|
||||
|
||||
/**
|
||||
* The Timer class provides a simple way to Benchmark portions of your
|
||||
* application.
|
||||
*
|
||||
* @return Timer
|
||||
*/
|
||||
public static function timer(bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('timer');
|
||||
}
|
||||
|
||||
return new Timer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the debug toolbar.
|
||||
*
|
||||
* @return Toolbar
|
||||
*/
|
||||
public static function toolbar(?ToolbarConfig $config = null, bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('toolbar', $config);
|
||||
}
|
||||
|
||||
$config ??= config(ToolbarConfig::class);
|
||||
|
||||
return new Toolbar($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* The URI class provides a way to model and manipulate URIs.
|
||||
*
|
||||
* @param string|null $uri The URI string
|
||||
*
|
||||
* @return URI The current URI if $uri is null.
|
||||
*/
|
||||
public static function uri(?string $uri = null, bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('uri', $uri);
|
||||
}
|
||||
|
||||
if ($uri === null) {
|
||||
$appConfig = config(App::class);
|
||||
$factory = AppServices::siteurifactory($appConfig, AppServices::get('superglobals'));
|
||||
|
||||
return $factory->createFromGlobals();
|
||||
}
|
||||
|
||||
return new URI($uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Validation class provides tools for validating input data.
|
||||
*
|
||||
* @return ValidationInterface
|
||||
*/
|
||||
public static function validation(?ValidationConfig $config = null, bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('validation', $config);
|
||||
}
|
||||
|
||||
$config ??= config(ValidationConfig::class);
|
||||
|
||||
return new Validation($config, AppServices::get('renderer'));
|
||||
}
|
||||
|
||||
/**
|
||||
* View cells are intended to let you insert HTML into view
|
||||
* that has been generated by any callable in the system.
|
||||
*
|
||||
* @return Cell
|
||||
*/
|
||||
public static function viewcell(bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('viewcell');
|
||||
}
|
||||
|
||||
return new Cell(AppServices::get('cache'));
|
||||
}
|
||||
|
||||
/**
|
||||
* The Typography class provides a way to format text in semantically relevant ways.
|
||||
*
|
||||
* @return Typography
|
||||
*/
|
||||
public static function typography(bool $getShared = true)
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('typography');
|
||||
}
|
||||
|
||||
return new Typography();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* 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\View\ViewDecoratorInterface;
|
||||
|
||||
/**
|
||||
* View configuration
|
||||
*
|
||||
* @phpstan-type parser_callable (callable(mixed): mixed)
|
||||
* @phpstan-type parser_callable_string (callable(mixed): mixed)&string
|
||||
*/
|
||||
class View extends BaseConfig
|
||||
{
|
||||
/**
|
||||
* When false, the view method will clear the data between each
|
||||
* call.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $saveData = true;
|
||||
|
||||
/**
|
||||
* Parser Filters map a filter name with any PHP callable. When the
|
||||
* Parser prepares a variable for display, it will chain it
|
||||
* through the filters in the order defined, inserting any parameters.
|
||||
*
|
||||
* To prevent potential abuse, all filters MUST be defined here
|
||||
* in order for them to be available for use within the Parser.
|
||||
*
|
||||
* @psalm-suppress UndefinedDocblockClass
|
||||
*
|
||||
* @var array<string, string>
|
||||
* @phpstan-var array<string, parser_callable_string>
|
||||
*/
|
||||
public $filters = [];
|
||||
|
||||
/**
|
||||
* Parser Plugins provide a way to extend the functionality provided
|
||||
* by the core Parser by creating aliases that will be replaced with
|
||||
* any callable. Can be single or tag pair.
|
||||
*
|
||||
* @psalm-suppress UndefinedDocblockClass
|
||||
*
|
||||
* @var array<string, callable|list<string>|string>
|
||||
* @phpstan-var array<string, list<parser_callable_string>|parser_callable_string|parser_callable>
|
||||
*/
|
||||
public $plugins = [];
|
||||
|
||||
/**
|
||||
* Built-in View filters.
|
||||
*
|
||||
* @psalm-suppress UndefinedDocblockClass
|
||||
*
|
||||
* @var array<string, string>
|
||||
* @phpstan-var array<string, parser_callable_string>
|
||||
*/
|
||||
protected $coreFilters = [
|
||||
'abs' => '\abs',
|
||||
'capitalize' => '\CodeIgniter\View\Filters::capitalize',
|
||||
'date' => '\CodeIgniter\View\Filters::date',
|
||||
'date_modify' => '\CodeIgniter\View\Filters::date_modify',
|
||||
'default' => '\CodeIgniter\View\Filters::default',
|
||||
'esc' => '\CodeIgniter\View\Filters::esc',
|
||||
'excerpt' => '\CodeIgniter\View\Filters::excerpt',
|
||||
'highlight' => '\CodeIgniter\View\Filters::highlight',
|
||||
'highlight_code' => '\CodeIgniter\View\Filters::highlight_code',
|
||||
'limit_words' => '\CodeIgniter\View\Filters::limit_words',
|
||||
'limit_chars' => '\CodeIgniter\View\Filters::limit_chars',
|
||||
'local_currency' => '\CodeIgniter\View\Filters::local_currency',
|
||||
'local_number' => '\CodeIgniter\View\Filters::local_number',
|
||||
'lower' => '\strtolower',
|
||||
'nl2br' => '\CodeIgniter\View\Filters::nl2br',
|
||||
'number_format' => '\number_format',
|
||||
'prose' => '\CodeIgniter\View\Filters::prose',
|
||||
'round' => '\CodeIgniter\View\Filters::round',
|
||||
'strip_tags' => '\strip_tags',
|
||||
'title' => '\CodeIgniter\View\Filters::title',
|
||||
'upper' => '\strtoupper',
|
||||
];
|
||||
|
||||
/**
|
||||
* Built-in View plugins.
|
||||
*
|
||||
* @psalm-suppress UndefinedDocblockClass
|
||||
*
|
||||
* @var array<string, callable|list<string>|string>
|
||||
* @phpstan-var array<string, array<parser_callable_string>|parser_callable_string|parser_callable>
|
||||
*/
|
||||
protected $corePlugins = [
|
||||
'csp_script_nonce' => '\CodeIgniter\View\Plugins::cspScriptNonce',
|
||||
'csp_style_nonce' => '\CodeIgniter\View\Plugins::cspStyleNonce',
|
||||
'current_url' => '\CodeIgniter\View\Plugins::currentURL',
|
||||
'previous_url' => '\CodeIgniter\View\Plugins::previousURL',
|
||||
'mailto' => '\CodeIgniter\View\Plugins::mailto',
|
||||
'safe_mailto' => '\CodeIgniter\View\Plugins::safeMailto',
|
||||
'lang' => '\CodeIgniter\View\Plugins::lang',
|
||||
'validation_errors' => '\CodeIgniter\View\Plugins::validationErrors',
|
||||
'route' => '\CodeIgniter\View\Plugins::route',
|
||||
'siteURL' => '\CodeIgniter\View\Plugins::siteURL',
|
||||
];
|
||||
|
||||
/**
|
||||
* View Decorators are class methods that will be run in sequence to
|
||||
* have a chance to alter the generated output just prior to caching
|
||||
* the results.
|
||||
*
|
||||
* All classes must implement CodeIgniter\View\ViewDecoratorInterface
|
||||
*
|
||||
* @var list<class-string<ViewDecoratorInterface>>
|
||||
*/
|
||||
public array $decorators = [];
|
||||
|
||||
/**
|
||||
* Merge the built-in and developer-configured filters and plugins,
|
||||
* with preference to the developer ones.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->filters = array_merge($this->coreFilters, $this->filters);
|
||||
$this->plugins = array_merge($this->corePlugins, $this->plugins);
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user