init
This commit is contained in:
Vendored
+260
@@ -0,0 +1,260 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 1.2.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core;
|
||||
|
||||
use Cake\Core\Exception\CakeException;
|
||||
|
||||
/**
|
||||
* App is responsible for resource location, and path management.
|
||||
*
|
||||
* ### Adding paths
|
||||
*
|
||||
* Additional paths for Templates and Plugins are configured with Configure now. See config/app.php for an
|
||||
* example. The `App.paths.plugins` and `App.paths.templates` variables are used to configure paths for plugins
|
||||
* and templates respectively. All class based resources should be mapped using your application's autoloader.
|
||||
*
|
||||
* ### Inspecting loaded paths
|
||||
*
|
||||
* You can inspect the currently loaded paths using `App::classPath('Controller')` for example to see loaded
|
||||
* controller paths.
|
||||
*
|
||||
* It is also possible to inspect paths for plugin classes, for instance, to get
|
||||
* the path to a plugin's helpers you would call `App::classPath('View/Helper', 'MyPlugin')`
|
||||
*
|
||||
* ### Locating plugins
|
||||
*
|
||||
* Plugins can be located with App as well. Using Plugin::path('DebugKit') for example, will
|
||||
* give you the full path to the DebugKit plugin.
|
||||
*
|
||||
* @link https://book.cakephp.org/5/en/core-libraries/app.html
|
||||
*/
|
||||
class App
|
||||
{
|
||||
/**
|
||||
* Return the class name namespaced. This method checks if the class is defined on the
|
||||
* application/plugin, otherwise try to load from the CakePHP core
|
||||
*
|
||||
* @param string $class Class name
|
||||
* @param string $type Type of class
|
||||
* @param string $suffix Class name suffix
|
||||
* @return class-string|null Namespaced class name, null if the class is not found.
|
||||
*/
|
||||
public static function className(string $class, string $type = '', string $suffix = ''): ?string
|
||||
{
|
||||
if (str_contains($class, '\\')) {
|
||||
return class_exists($class) ? $class : null;
|
||||
}
|
||||
|
||||
[$plugin, $name] = pluginSplit($class);
|
||||
$fullname = '\\' . str_replace('/', '\\', $type . '\\' . $name) . $suffix;
|
||||
|
||||
$base = $plugin ?: Configure::read('App.namespace');
|
||||
if ($base !== null) {
|
||||
$base = str_replace('/', '\\', rtrim($base, '\\'));
|
||||
|
||||
if (static::_classExistsInBase($fullname, $base)) {
|
||||
/** @var class-string */
|
||||
return $base . $fullname;
|
||||
}
|
||||
}
|
||||
|
||||
if ($plugin || !static::_classExistsInBase($fullname, 'Cake')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var class-string */
|
||||
return 'Cake' . $fullname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the plugin split name of a class
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* ```
|
||||
* App::shortName(
|
||||
* 'SomeVendor\SomePlugin\Controller\Component\TestComponent',
|
||||
* 'Controller/Component',
|
||||
* 'Component'
|
||||
* )
|
||||
* ```
|
||||
*
|
||||
* Returns: SomeVendor/SomePlugin.Test
|
||||
*
|
||||
* ```
|
||||
* App::shortName(
|
||||
* 'SomeVendor\SomePlugin\Controller\Component\Subfolder\TestComponent',
|
||||
* 'Controller/Component',
|
||||
* 'Component'
|
||||
* )
|
||||
* ```
|
||||
*
|
||||
* Returns: SomeVendor/SomePlugin.Subfolder/Test
|
||||
*
|
||||
* ```
|
||||
* App::shortName(
|
||||
* 'Cake\Controller\Component\FlashComponent',
|
||||
* 'Controller/Component',
|
||||
* 'Component'
|
||||
* )
|
||||
* ```
|
||||
*
|
||||
* Returns: Flash
|
||||
*
|
||||
* @param string $class Class name
|
||||
* @param string $type Type of class
|
||||
* @param string $suffix Class name suffix
|
||||
* @return string Plugin split name of class
|
||||
*/
|
||||
public static function shortName(string $class, string $type, string $suffix = ''): string
|
||||
{
|
||||
$class = str_replace('\\', '/', $class);
|
||||
$type = '/' . $type . '/';
|
||||
|
||||
$pos = strrpos($class, $type);
|
||||
if ($pos === false) {
|
||||
return $class;
|
||||
}
|
||||
|
||||
$pluginName = substr($class, 0, $pos);
|
||||
$name = substr($class, $pos + strlen($type));
|
||||
|
||||
if ($suffix) {
|
||||
$name = substr($name, 0, -strlen($suffix));
|
||||
}
|
||||
|
||||
$nonPluginNamespaces = [
|
||||
'Cake',
|
||||
str_replace('\\', '/', (string)Configure::read('App.namespace')),
|
||||
];
|
||||
if (in_array($pluginName, $nonPluginNamespaces, true)) {
|
||||
return $name;
|
||||
}
|
||||
|
||||
return $pluginName . '.' . $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* _classExistsInBase
|
||||
*
|
||||
* Test isolation wrapper
|
||||
*
|
||||
* @param string $name Class name.
|
||||
* @param string $namespace Namespace.
|
||||
* @return bool
|
||||
*/
|
||||
protected static function _classExistsInBase(string $name, string $namespace): bool
|
||||
{
|
||||
return class_exists($namespace . $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to read information of stored path.
|
||||
*
|
||||
* When called without the `$plugin` argument it will return the value of `App.paths.$type` config.
|
||||
*
|
||||
* Default types:
|
||||
* - plugins
|
||||
* - templates
|
||||
* - locales
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* App::path('plugins');
|
||||
* ```
|
||||
*
|
||||
* Will return the value of `App.paths.plugins` config.
|
||||
*
|
||||
* For plugins it can be used to get paths for types `templates` or `locales`.
|
||||
*
|
||||
* @param string $type Type of path
|
||||
* @param string|null $plugin Plugin name
|
||||
* @return array<int|string, string>
|
||||
* @link https://book.cakephp.org/5/en/core-libraries/app.html#finding-paths-to-namespaces
|
||||
*/
|
||||
public static function path(string $type, ?string $plugin = null): array
|
||||
{
|
||||
if ($plugin === null) {
|
||||
return (array)Configure::read('App.paths.' . $type);
|
||||
}
|
||||
|
||||
return match ($type) {
|
||||
'templates' => [Plugin::templatePath($plugin)],
|
||||
'locales' => [Plugin::path($plugin) . 'resources' . DIRECTORY_SEPARATOR . 'locales' . DIRECTORY_SEPARATOR],
|
||||
default => throw new CakeException(sprintf(
|
||||
'Invalid type `%s`. Only path types `templates` and `locales` are supported for plugins.',
|
||||
$type,
|
||||
))
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the path to a class type in the application or a plugin.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* App::classPath('Model/Table');
|
||||
* ```
|
||||
*
|
||||
* Will return the path for tables - e.g. `src/Model/Table/`.
|
||||
*
|
||||
* ```
|
||||
* App::classPath('Model/Table', 'My/Plugin');
|
||||
* ```
|
||||
*
|
||||
* Will return the plugin based path for those.
|
||||
*
|
||||
* @param string $type Package type.
|
||||
* @param string|null $plugin Plugin name.
|
||||
* @return array<string>
|
||||
*/
|
||||
public static function classPath(string $type, ?string $plugin = null): array
|
||||
{
|
||||
if ($plugin !== null) {
|
||||
return [
|
||||
Plugin::classPath($plugin) . $type . DIRECTORY_SEPARATOR,
|
||||
];
|
||||
}
|
||||
|
||||
return [APP . $type . DIRECTORY_SEPARATOR];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full path to a package inside the CakePHP core
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* ```
|
||||
* App::core('Cache/Engine');
|
||||
* ```
|
||||
*
|
||||
* Will return the full path to the cache engines package.
|
||||
*
|
||||
* @param string $type Package type.
|
||||
* @return array<string> Full path to package
|
||||
*/
|
||||
public static function core(string $type): array
|
||||
{
|
||||
if ($type === 'templates') {
|
||||
return [CORE_PATH . 'templates' . DIRECTORY_SEPARATOR];
|
||||
}
|
||||
|
||||
return [CAKE . str_replace('/', DIRECTORY_SEPARATOR, $type) . DIRECTORY_SEPARATOR];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 5.3.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core\Attribute;
|
||||
|
||||
use Attribute;
|
||||
use Cake\Core\Configure as CakeConfigure;
|
||||
use League\Container\Attribute\AttributeInterface;
|
||||
|
||||
/**
|
||||
* Configure attribute for dependency injection container delegate.
|
||||
*
|
||||
* This provides autowiring config data into constructors when delegate is enabled.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* <?php
|
||||
* declare(strict_types=1);
|
||||
*
|
||||
* namespace App\Model\WebService;
|
||||
* use Cake\Core\Attribute\Configure;
|
||||
*
|
||||
* class CustomClient
|
||||
* {
|
||||
* public function __construct(
|
||||
* #[Configure('CustomService.apiKey')] protected string $apiKey,
|
||||
* ) { }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
#[Attribute(Attribute::TARGET_PARAMETER)]
|
||||
class Configure implements AttributeInterface
|
||||
{
|
||||
/**
|
||||
* @param string $name
|
||||
*/
|
||||
public function __construct(private string $name)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function resolve(): mixed
|
||||
{
|
||||
return CakeConfigure::read($this->name);
|
||||
}
|
||||
}
|
||||
+324
@@ -0,0 +1,324 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright 2005-2011, Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 3.6.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core;
|
||||
|
||||
use Cake\Console\CommandCollection;
|
||||
use Cake\Event\EventManagerInterface;
|
||||
use Cake\Http\MiddlewareQueue;
|
||||
use Cake\Routing\RouteBuilder;
|
||||
use Closure;
|
||||
use InvalidArgumentException;
|
||||
use ReflectionClass;
|
||||
|
||||
/**
|
||||
* Base Plugin Class
|
||||
*
|
||||
* Every plugin should extend from this class or implement the interfaces and
|
||||
* include a plugin class in its src root folder.
|
||||
*/
|
||||
class BasePlugin implements PluginInterface
|
||||
{
|
||||
/**
|
||||
* Do bootstrapping or not
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected bool $bootstrapEnabled = true;
|
||||
|
||||
/**
|
||||
* Console middleware
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected bool $consoleEnabled = true;
|
||||
|
||||
/**
|
||||
* Enable middleware
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected bool $middlewareEnabled = true;
|
||||
|
||||
/**
|
||||
* Register container services
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected bool $servicesEnabled = true;
|
||||
|
||||
/**
|
||||
* Load routes or not
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected bool $routesEnabled = true;
|
||||
|
||||
/**
|
||||
* Load events or not
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected bool $eventsEnabled = true;
|
||||
|
||||
/**
|
||||
* The path to this plugin.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected ?string $path = null;
|
||||
|
||||
/**
|
||||
* The class path for this plugin.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected ?string $classPath = null;
|
||||
|
||||
/**
|
||||
* The config path for this plugin.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected ?string $configPath = null;
|
||||
|
||||
/**
|
||||
* The templates path for this plugin.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected ?string $templatePath = null;
|
||||
|
||||
/**
|
||||
* The name of this plugin
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected ?string $name = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array<string, mixed> $options Options
|
||||
*/
|
||||
public function __construct(array $options = [])
|
||||
{
|
||||
foreach (static::VALID_HOOKS as $key) {
|
||||
if (isset($options[$key])) {
|
||||
$this->{"{$key}Enabled"} = (bool)$options[$key];
|
||||
}
|
||||
}
|
||||
foreach (['name', 'path', 'classPath', 'configPath', 'templatePath'] as $path) {
|
||||
if (isset($options[$path])) {
|
||||
$this->{$path} = $options[$path];
|
||||
}
|
||||
}
|
||||
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialization hook called from constructor.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function initialize(): void
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
if ($this->name !== null) {
|
||||
return $this->name;
|
||||
}
|
||||
$parts = explode('\\', static::class);
|
||||
array_pop($parts);
|
||||
|
||||
return $this->name = implode('/', $parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getPath(): string
|
||||
{
|
||||
if ($this->path !== null) {
|
||||
return $this->path;
|
||||
}
|
||||
$reflection = new ReflectionClass($this);
|
||||
$path = dirname((string)$reflection->getFileName());
|
||||
|
||||
// Trim off src
|
||||
if (str_ends_with($path, 'src')) {
|
||||
$path = substr($path, 0, -3);
|
||||
}
|
||||
|
||||
return $this->path = rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getConfigPath(): string
|
||||
{
|
||||
if ($this->configPath !== null) {
|
||||
return $this->configPath;
|
||||
}
|
||||
$path = $this->getPath();
|
||||
|
||||
return $path . 'config' . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getClassPath(): string
|
||||
{
|
||||
if ($this->classPath !== null) {
|
||||
return $this->classPath;
|
||||
}
|
||||
$path = $this->getPath();
|
||||
|
||||
return $path . 'src' . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getTemplatePath(): string
|
||||
{
|
||||
if ($this->templatePath !== null) {
|
||||
return $this->templatePath;
|
||||
}
|
||||
$path = $this->getPath();
|
||||
|
||||
return $this->templatePath = $path . 'templates' . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function enable(string $hook)
|
||||
{
|
||||
$this->checkHook($hook);
|
||||
$this->{"{$hook}Enabled"} = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function disable(string $hook)
|
||||
{
|
||||
$this->checkHook($hook);
|
||||
$this->{"{$hook}Enabled"} = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function isEnabled(string $hook): bool
|
||||
{
|
||||
$this->checkHook($hook);
|
||||
|
||||
return $this->{"{$hook}Enabled"} === true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a hook name is valid
|
||||
*
|
||||
* @param string $hook The hook name to check
|
||||
* @throws \InvalidArgumentException on invalid hooks
|
||||
* @return void
|
||||
*/
|
||||
protected function checkHook(string $hook): void
|
||||
{
|
||||
if (!in_array($hook, static::VALID_HOOKS, true)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'`%s` is not a valid hook name. Must be one of `%s.`',
|
||||
$hook,
|
||||
implode(', ', static::VALID_HOOKS),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function routes(RouteBuilder $routes): void
|
||||
{
|
||||
$path = $this->getConfigPath() . 'routes.php';
|
||||
if (is_file($path)) {
|
||||
$return = require $path;
|
||||
if ($return instanceof Closure) {
|
||||
$return($routes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function bootstrap(PluginApplicationInterface $app): void
|
||||
{
|
||||
$bootstrap = $this->getConfigPath() . 'bootstrap.php';
|
||||
if (is_file($bootstrap)) {
|
||||
require $bootstrap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function console(CommandCollection $commands): CommandCollection
|
||||
{
|
||||
return $commands->addMany($commands->discoverPlugin($this->getName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
|
||||
{
|
||||
return $middlewareQueue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register container services for this plugin.
|
||||
*
|
||||
* @param \Cake\Core\ContainerInterface $container The container to add services to.
|
||||
* @return void
|
||||
*/
|
||||
public function services(ContainerInterface $container): void
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Register application events.
|
||||
*
|
||||
* @param \Cake\Event\EventManagerInterface $eventManager The global event manager to register listeners on
|
||||
* @return \Cake\Event\EventManagerInterface
|
||||
*/
|
||||
public function events(EventManagerInterface $eventManager): EventManagerInterface
|
||||
{
|
||||
return $eventManager;
|
||||
}
|
||||
}
|
||||
+493
@@ -0,0 +1,493 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 1.0.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core;
|
||||
|
||||
use Cake\Cache\Cache;
|
||||
use Cake\Core\Configure\ConfigEngineInterface;
|
||||
use Cake\Core\Configure\Engine\PhpConfig;
|
||||
use Cake\Core\Exception\CakeException;
|
||||
use Cake\Utility\Hash;
|
||||
|
||||
/**
|
||||
* Configuration class. Used for managing runtime configuration information.
|
||||
*
|
||||
* Provides features for reading and writing to the runtime configuration, as well
|
||||
* as methods for loading additional configuration files or storing runtime configuration
|
||||
* for future use.
|
||||
*
|
||||
* @link https://book.cakephp.org/5/en/development/configuration.html
|
||||
*/
|
||||
class Configure
|
||||
{
|
||||
/**
|
||||
* Array of values currently stored in Configure.
|
||||
*
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
protected static array $_values = [
|
||||
'debug' => false,
|
||||
];
|
||||
|
||||
/**
|
||||
* Configured engine classes, used to load config files from resources
|
||||
*
|
||||
* @see \Cake\Core\Configure::load()
|
||||
* @var array<\Cake\Core\Configure\ConfigEngineInterface>
|
||||
*/
|
||||
protected static array $_engines = [];
|
||||
|
||||
/**
|
||||
* Flag to track whether ini_set exists.
|
||||
*
|
||||
* @var bool|null
|
||||
*/
|
||||
protected static ?bool $_hasIniSet = null;
|
||||
|
||||
/**
|
||||
* Used to store a dynamic variable in Configure.
|
||||
*
|
||||
* Usage:
|
||||
* ```
|
||||
* Configure::write('One.key1', 'value of the Configure::One[key1]');
|
||||
* Configure::write(['One.key1' => 'value of the Configure::One[key1]']);
|
||||
* Configure::write('One', [
|
||||
* 'key1' => 'value of the Configure::One[key1]',
|
||||
* 'key2' => 'value of the Configure::One[key2]'
|
||||
* ]);
|
||||
*
|
||||
* Configure::write([
|
||||
* 'One.key1' => 'value of the Configure::One[key1]',
|
||||
* 'One.key2' => 'value of the Configure::One[key2]'
|
||||
* ]);
|
||||
* ```
|
||||
*
|
||||
* @param array<string, mixed>|string $config The key to write, can be a dot notation value.
|
||||
* Alternatively can be an array containing key(s) and value(s).
|
||||
* @param mixed $value Value to set for the given key.
|
||||
* @return void
|
||||
* @link https://book.cakephp.org/5/en/development/configuration.html#writing-configuration-data
|
||||
*/
|
||||
public static function write(array|string $config, mixed $value = null): void
|
||||
{
|
||||
if (!is_array($config)) {
|
||||
$config = [$config => $value];
|
||||
}
|
||||
|
||||
foreach ($config as $name => $valueToInsert) {
|
||||
static::$_values = Hash::insert(static::$_values, $name, $valueToInsert);
|
||||
}
|
||||
|
||||
if (isset($config['debug'])) {
|
||||
static::$_hasIniSet ??= function_exists('ini_set');
|
||||
|
||||
if (static::$_hasIniSet) {
|
||||
ini_set('display_errors', $config['debug'] ? '1' : '0');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to read information stored in Configure. It's not
|
||||
* possible to store `null` values in Configure.
|
||||
*
|
||||
* Usage:
|
||||
* ```
|
||||
* Configure::read('Name'); will return all values for Name
|
||||
* Configure::read('Name.key'); will return only the value of Configure::Name[key]
|
||||
* ```
|
||||
*
|
||||
* @param string|null $var Variable to obtain. Use '.' to access array elements.
|
||||
* @param mixed $default The return value when the configure does not exist
|
||||
* @return mixed Value stored in configure, or null.
|
||||
* @link https://book.cakephp.org/5/en/development/configuration.html#reading-configuration-data
|
||||
*/
|
||||
public static function read(?string $var = null, mixed $default = null): mixed
|
||||
{
|
||||
if ($var === null) {
|
||||
return static::$_values;
|
||||
}
|
||||
|
||||
return Hash::get(static::$_values, $var, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if given variable is set in Configure.
|
||||
*
|
||||
* @param string $var Variable name to check for
|
||||
* @return bool True if variable is there
|
||||
*/
|
||||
public static function check(string $var): bool
|
||||
{
|
||||
if (!$var) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return static::read($var) !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to get information stored in Configure. It's not
|
||||
* possible to store `null` values in Configure.
|
||||
*
|
||||
* Acts as a wrapper around Configure::read() and Configure::check().
|
||||
* The configure key/value pair fetched via this method is expected to exist.
|
||||
* In case it does not an exception will be thrown.
|
||||
*
|
||||
* Usage:
|
||||
* ```
|
||||
* Configure::readOrFail('Name'); will return all values for Name
|
||||
* Configure::readOrFail('Name.key'); will return only the value of Configure::Name[key]
|
||||
* ```
|
||||
*
|
||||
* @param string $var Variable to obtain. Use '.' to access array elements.
|
||||
* @return mixed Value stored in configure.
|
||||
* @throws \Cake\Core\Exception\CakeException if the requested configuration is not set.
|
||||
* @link https://book.cakephp.org/5/en/development/configuration.html#reading-configuration-data
|
||||
*/
|
||||
public static function readOrFail(string $var): mixed
|
||||
{
|
||||
if (!static::check($var)) {
|
||||
throw new CakeException(sprintf('Expected configuration key `%s` not found.', $var));
|
||||
}
|
||||
|
||||
return static::read($var);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to delete a variable from Configure.
|
||||
*
|
||||
* Usage:
|
||||
* ```
|
||||
* Configure::delete('Name'); will delete the entire Configure::Name
|
||||
* Configure::delete('Name.key'); will delete only the Configure::Name[key]
|
||||
* ```
|
||||
*
|
||||
* @param string $var the var to be deleted
|
||||
* @return void
|
||||
* @link https://book.cakephp.org/5/en/development/configuration.html#deleting-configuration-data
|
||||
*/
|
||||
public static function delete(string $var): void
|
||||
{
|
||||
static::$_values = Hash::remove(static::$_values, $var);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to consume information stored in Configure. It's not
|
||||
* possible to store `null` values in Configure.
|
||||
*
|
||||
* Acts as a wrapper around Configure::consume() and Configure::check().
|
||||
* The configure key/value pair consumed via this method is expected to exist.
|
||||
* In case it does not an exception will be thrown.
|
||||
*
|
||||
* @param string $var Variable to consume. Use '.' to access array elements.
|
||||
* @return mixed Value stored in configure.
|
||||
* @throws \Cake\Core\Exception\CakeException if the requested configuration is not set.
|
||||
* @since 3.6.0
|
||||
*/
|
||||
public static function consumeOrFail(string $var): mixed
|
||||
{
|
||||
if (!static::check($var)) {
|
||||
throw new CakeException(sprintf('Expected configuration key `%s` not found.', $var));
|
||||
}
|
||||
|
||||
return static::consume($var);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to read and delete a variable from Configure.
|
||||
*
|
||||
* This is primarily used during bootstrapping to move configuration data
|
||||
* out of configure into the various other classes in CakePHP.
|
||||
*
|
||||
* @param string $var The key to read and remove.
|
||||
* @return mixed The value stored in Configure, or null if the key doesn't exist.
|
||||
*/
|
||||
public static function consume(string $var): mixed
|
||||
{
|
||||
if (!str_contains($var, '.')) {
|
||||
if (!isset(static::$_values[$var])) {
|
||||
return null;
|
||||
}
|
||||
$value = static::$_values[$var];
|
||||
unset(static::$_values[$var]);
|
||||
|
||||
return $value;
|
||||
}
|
||||
$value = Hash::get(static::$_values, $var);
|
||||
static::delete($var);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new engine to Configure. Engines allow you to read configuration
|
||||
* files in various formats/storage locations. CakePHP comes with two built-in engines
|
||||
* PhpConfig and IniConfig. You can also implement your own engine classes in your application.
|
||||
*
|
||||
* To add a new engine to Configure:
|
||||
*
|
||||
* ```
|
||||
* Configure::config('ini', new IniConfig());
|
||||
* ```
|
||||
*
|
||||
* @param string $name The name of the engine being configured. This alias is used later to
|
||||
* read values from a specific engine.
|
||||
* @param \Cake\Core\Configure\ConfigEngineInterface $engine The engine to append.
|
||||
* @return void
|
||||
*/
|
||||
public static function config(string $name, ConfigEngineInterface $engine): void
|
||||
{
|
||||
static::$_engines[$name] = $engine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the Engine objects is configured.
|
||||
*
|
||||
* @param string $name Engine name.
|
||||
* @return bool
|
||||
*/
|
||||
public static function isConfigured(string $name): bool
|
||||
{
|
||||
return isset(static::$_engines[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the names of the configured Engine objects.
|
||||
*
|
||||
* @return array<string>
|
||||
*/
|
||||
public static function configured(): array
|
||||
{
|
||||
$engines = array_keys(static::$_engines);
|
||||
|
||||
return array_map(function (int|string $key) {
|
||||
return (string)$key;
|
||||
}, $engines);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a configured engine. This will unset the engine
|
||||
* and make any future attempts to use it cause an Exception.
|
||||
*
|
||||
* @param string $name Name of the engine to drop.
|
||||
* @return bool Success
|
||||
*/
|
||||
public static function drop(string $name): bool
|
||||
{
|
||||
if (!isset(static::$_engines[$name])) {
|
||||
return false;
|
||||
}
|
||||
unset(static::$_engines[$name]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads stored configuration information from a resource. You can add
|
||||
* config file resource engines with `Configure::config()`.
|
||||
*
|
||||
* Loaded configuration information will be merged with the current
|
||||
* runtime configuration. You can load configuration files from plugins
|
||||
* by preceding the filename with the plugin name.
|
||||
*
|
||||
* `Configure::load('Users.user', 'default')`
|
||||
*
|
||||
* Would load the 'user' config file using the default config engine. You can load
|
||||
* app config files by giving the name of the resource you want loaded.
|
||||
*
|
||||
* ```
|
||||
* Configure::load('setup', 'default');
|
||||
* ```
|
||||
*
|
||||
* If using `default` config and no engine has been configured for it yet,
|
||||
* one will be automatically created using PhpConfig
|
||||
*
|
||||
* @param string $key name of configuration resource to load.
|
||||
* @param string $config Name of the configured engine to use to read the resource identified by $key.
|
||||
* @param bool $merge if config files should be merged instead of simply overridden
|
||||
* @return bool True if load successful.
|
||||
* @throws \Cake\Core\Exception\CakeException if the $config engine is not found
|
||||
* @link https://book.cakephp.org/5/en/development/configuration.html#reading-and-writing-configuration-files
|
||||
*/
|
||||
public static function load(string $key, string $config = 'default', bool $merge = true): bool
|
||||
{
|
||||
$engine = static::_getEngine($config);
|
||||
if (!$engine) {
|
||||
throw new CakeException(
|
||||
sprintf(
|
||||
'Config %s engine not found when attempting to load %s.',
|
||||
$config,
|
||||
$key,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
$values = $engine->read($key);
|
||||
|
||||
if ($merge) {
|
||||
$values = Hash::merge(static::$_values, $values);
|
||||
}
|
||||
|
||||
static::write($values);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump data currently in Configure into $key. The serialization format
|
||||
* is decided by the config engine attached as $config. For example, if the
|
||||
* 'default' adapter is a PhpConfig, the generated file will be a PHP
|
||||
* configuration file loadable by the PhpConfig.
|
||||
*
|
||||
* ### Usage
|
||||
*
|
||||
* Given that the 'default' engine is an instance of PhpConfig.
|
||||
* Save all data in Configure to the file `my_config.php`:
|
||||
*
|
||||
* ```
|
||||
* Configure::dump('my_config', 'default');
|
||||
* ```
|
||||
*
|
||||
* Save only the error handling configuration:
|
||||
*
|
||||
* ```
|
||||
* Configure::dump('error', 'default', ['Error', 'Exception'];
|
||||
* ```
|
||||
*
|
||||
* @param string $key The identifier to create in the config adapter.
|
||||
* This could be a filename or a cache key depending on the adapter being used.
|
||||
* @param string $config The name of the configured adapter to dump data with.
|
||||
* @param array<string> $keys The name of the top-level keys you want to dump.
|
||||
* This allows you save only some data stored in Configure.
|
||||
* @return bool Success
|
||||
* @throws \Cake\Core\Exception\CakeException if the adapter does not implement a `dump` method.
|
||||
*/
|
||||
public static function dump(string $key, string $config = 'default', array $keys = []): bool
|
||||
{
|
||||
$engine = static::_getEngine($config);
|
||||
if (!$engine) {
|
||||
throw new CakeException(sprintf('There is no `%s` config engine.', $config));
|
||||
}
|
||||
$values = static::$_values;
|
||||
if ($keys) {
|
||||
$values = array_intersect_key($values, array_flip($keys));
|
||||
}
|
||||
|
||||
return $engine->dump($key, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configured engine. Internally used by `Configure::load()` and `Configure::dump()`
|
||||
* Will create new PhpConfig for default if not configured yet.
|
||||
*
|
||||
* @param string $config The name of the configured adapter
|
||||
* @return \Cake\Core\Configure\ConfigEngineInterface|null Engine instance or null
|
||||
*/
|
||||
protected static function _getEngine(string $config): ?ConfigEngineInterface
|
||||
{
|
||||
if (!isset(static::$_engines[$config])) {
|
||||
if ($config !== 'default') {
|
||||
return null;
|
||||
}
|
||||
static::config($config, new PhpConfig());
|
||||
}
|
||||
|
||||
return static::$_engines[$config];
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to determine the current version of CakePHP.
|
||||
*
|
||||
* Usage
|
||||
* ```
|
||||
* Configure::version();
|
||||
* ```
|
||||
*
|
||||
* @return string Current version of CakePHP
|
||||
*/
|
||||
public static function version(): string
|
||||
{
|
||||
$version = static::read('Cake.version');
|
||||
if ($version !== null) {
|
||||
return $version;
|
||||
}
|
||||
|
||||
$path = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'config/config.php';
|
||||
if (is_file($path)) {
|
||||
$config = require $path;
|
||||
static::write($config);
|
||||
|
||||
return static::read('Cake.version');
|
||||
}
|
||||
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to write runtime configuration into Cache. Stored runtime configuration can be
|
||||
* restored using `Configure::restore()`. These methods can be used to enable configuration managers
|
||||
* frontends, or other GUI type interfaces for configuration.
|
||||
*
|
||||
* @param string $name The storage name for the saved configuration.
|
||||
* @param string $cacheConfig The cache configuration to save into. Defaults to 'default'
|
||||
* @param array|null $data Either an array of data to store, or leave empty to store all values.
|
||||
* @return bool Success
|
||||
*/
|
||||
public static function store(string $name, string $cacheConfig = 'default', ?array $data = null): bool
|
||||
{
|
||||
$data ??= static::$_values;
|
||||
|
||||
if (!class_exists(Cache::class)) {
|
||||
throw new CakeException('You must install cakephp/cache to use Configure::store()');
|
||||
}
|
||||
|
||||
return Cache::write($name, $data, $cacheConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores configuration data stored in the Cache into configure. Restored
|
||||
* values will overwrite existing ones.
|
||||
*
|
||||
* @param string $name Name of the stored config file to load.
|
||||
* @param string $cacheConfig Name of the Cache configuration to read from.
|
||||
* @return bool Success.
|
||||
*/
|
||||
public static function restore(string $name, string $cacheConfig = 'default'): bool
|
||||
{
|
||||
if (!class_exists(Cache::class)) {
|
||||
throw new CakeException('You must install cakephp/cache to use Configure::restore()');
|
||||
}
|
||||
$values = Cache::read($name, $cacheConfig);
|
||||
if ($values) {
|
||||
static::write($values);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all values stored in Configure.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function clear(): void
|
||||
{
|
||||
static::$_values = [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 1.0.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core\Configure;
|
||||
|
||||
/**
|
||||
* An interface for creating objects compatible with Configure::load()
|
||||
*/
|
||||
interface ConfigEngineInterface
|
||||
{
|
||||
/**
|
||||
* Read a configuration file/storage key
|
||||
*
|
||||
* This method is used for reading configuration information from sources.
|
||||
* These sources can either be static resources like files, or dynamic ones like
|
||||
* a database, or other datasource.
|
||||
*
|
||||
* @param string $key Key to read.
|
||||
* @return array An array of data to merge into the runtime configuration
|
||||
*/
|
||||
public function read(string $key): array;
|
||||
|
||||
/**
|
||||
* Dumps the configure data into the storage key/file of the given `$key`.
|
||||
*
|
||||
* @param string $key The identifier to write to.
|
||||
* @param array $data The data to dump.
|
||||
* @return bool True on success or false on failure.
|
||||
*/
|
||||
public function dump(string $key, array $data): bool;
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 2.0.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core\Configure\Engine;
|
||||
|
||||
use Cake\Core\Configure\ConfigEngineInterface;
|
||||
use Cake\Core\Configure\FileConfigTrait;
|
||||
use Cake\Core\Exception\CakeException;
|
||||
use Cake\Utility\Hash;
|
||||
|
||||
/**
|
||||
* Ini file configuration engine.
|
||||
*
|
||||
* Since IniConfig uses parse_ini_file underneath, you should be aware that this
|
||||
* class shares the same behavior, especially with regards to boolean and null values.
|
||||
*
|
||||
* In addition to the native `parse_ini_file` features, IniConfig also allows you
|
||||
* to create nested array structures through usage of `.` delimited names. This allows
|
||||
* you to create nested arrays structures in an ini config file. For example:
|
||||
*
|
||||
* `db.password = secret` would turn into `['db' => ['password' => 'secret']]`
|
||||
*
|
||||
* You can nest properties as deeply as needed using `.`'s. In addition to using `.` you
|
||||
* can use standard ini section notation to create nested structures:
|
||||
*
|
||||
* ```
|
||||
* [section]
|
||||
* key = value
|
||||
* ```
|
||||
*
|
||||
* Once loaded into Configure, the above would be accessed using:
|
||||
*
|
||||
* `Configure::read('section.key');`
|
||||
*
|
||||
* You can also use `.` separated values in section names to create more deeply
|
||||
* nested structures.
|
||||
*
|
||||
* IniConfig also manipulates how the special ini values of
|
||||
* 'yes', 'no', 'on', 'off', 'null' are handled. These values will be
|
||||
* converted to their boolean equivalents.
|
||||
*
|
||||
* @see https://secure.php.net/parse_ini_file
|
||||
*/
|
||||
class IniConfig implements ConfigEngineInterface
|
||||
{
|
||||
use FileConfigTrait;
|
||||
|
||||
/**
|
||||
* File extension.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected string $_extension = '.ini';
|
||||
|
||||
/**
|
||||
* The section to read, if null all sections will be read.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected ?string $_section = null;
|
||||
|
||||
/**
|
||||
* Build and construct a new ini file parser. The parser can be used to read
|
||||
* ini files that are on the filesystem.
|
||||
*
|
||||
* @param string|null $path Path to load ini config files from. Defaults to CONFIG.
|
||||
* @param string|null $section Only get one section, leave null to parse and fetch
|
||||
* all sections in the ini file.
|
||||
*/
|
||||
public function __construct(?string $path = null, ?string $section = null)
|
||||
{
|
||||
$this->_path = $path ?? CONFIG;
|
||||
$this->_section = $section;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an ini file and return the results as an array.
|
||||
*
|
||||
* @param string $key The identifier to read from. If the key has a . it will be treated
|
||||
* as a plugin prefix. The chosen file must be on the engine's path.
|
||||
* @return array Parsed configuration values.
|
||||
* @throws \Cake\Core\Exception\CakeException when files don't exist.
|
||||
* Or when files contain '..' as this could lead to abusive reads.
|
||||
*/
|
||||
public function read(string $key): array
|
||||
{
|
||||
$file = $this->_getFilePath($key, true);
|
||||
|
||||
$contents = parse_ini_file($file, true);
|
||||
if ($contents === false) {
|
||||
throw new CakeException(sprintf('Cannot parse INI file `%s`', $file));
|
||||
}
|
||||
|
||||
if ($this->_section && isset($contents[$this->_section])) {
|
||||
$values = $this->_parseNestedValues($contents[$this->_section]);
|
||||
} else {
|
||||
$values = [];
|
||||
foreach ($contents as $section => $attribs) {
|
||||
if (is_array($attribs)) {
|
||||
$values[$section] = $this->_parseNestedValues($attribs);
|
||||
} else {
|
||||
$parse = $this->_parseNestedValues([$attribs]);
|
||||
$values[$section] = array_shift($parse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* parses nested values out of keys.
|
||||
*
|
||||
* @param array $values Values to be exploded.
|
||||
* @return array Array of values exploded
|
||||
*/
|
||||
protected function _parseNestedValues(array $values): array
|
||||
{
|
||||
foreach ($values as $key => $value) {
|
||||
if ($value === '1') {
|
||||
$value = true;
|
||||
}
|
||||
if ($value === '') {
|
||||
$value = false;
|
||||
}
|
||||
unset($values[$key]);
|
||||
if (str_contains((string)$key, '.')) {
|
||||
$values = Hash::insert($values, $key, $value);
|
||||
} else {
|
||||
$values[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps the state of Configure data into an ini formatted string.
|
||||
*
|
||||
* @param string $key The identifier to write to. If the key has a . it will be treated
|
||||
* as a plugin prefix.
|
||||
* @param array $data The data to convert to ini file.
|
||||
* @return bool Success.
|
||||
*/
|
||||
public function dump(string $key, array $data): bool
|
||||
{
|
||||
$result = [];
|
||||
foreach ($data as $k => $value) {
|
||||
$isSection = false;
|
||||
if (!str_starts_with($k, '[')) {
|
||||
$result[] = "[{$k}]";
|
||||
$isSection = true;
|
||||
}
|
||||
if (is_array($value)) {
|
||||
$kValues = Hash::flatten($value, '.');
|
||||
foreach ($kValues as $k2 => $v) {
|
||||
$result[] = "{$k2} = " . $this->_value($v);
|
||||
}
|
||||
}
|
||||
if ($isSection) {
|
||||
$result[] = '';
|
||||
}
|
||||
}
|
||||
$contents = trim(implode("\n", $result));
|
||||
|
||||
$filename = $this->_getFilePath($key);
|
||||
|
||||
return file_put_contents($filename, $contents) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a value into the ini equivalent
|
||||
*
|
||||
* @param mixed $value Value to export.
|
||||
* @return string String value for ini file.
|
||||
*/
|
||||
protected function _value(mixed $value): string
|
||||
{
|
||||
return match ($value) {
|
||||
null => 'null',
|
||||
true => 'true',
|
||||
false => 'false',
|
||||
default => (string)$value
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 3.0.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core\Configure\Engine;
|
||||
|
||||
use Cake\Core\Configure\ConfigEngineInterface;
|
||||
use Cake\Core\Configure\FileConfigTrait;
|
||||
use Cake\Core\Exception\CakeException;
|
||||
|
||||
/**
|
||||
* JSON engine allows Configure to load configuration values from
|
||||
* files containing JSON strings.
|
||||
*
|
||||
* An example JSON file would look like::
|
||||
*
|
||||
* ```
|
||||
* {
|
||||
* "debug": false,
|
||||
* "App": {
|
||||
* "namespace": "MyApp"
|
||||
* },
|
||||
* "Security": {
|
||||
* "salt": "its-secret"
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class JsonConfig implements ConfigEngineInterface
|
||||
{
|
||||
use FileConfigTrait;
|
||||
|
||||
/**
|
||||
* File extension.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected string $_extension = '.json';
|
||||
|
||||
/**
|
||||
* Constructor for JSON Config file reading.
|
||||
*
|
||||
* @param string|null $path The path to read config files from. Defaults to CONFIG.
|
||||
*/
|
||||
public function __construct(?string $path = null)
|
||||
{
|
||||
$this->_path = $path ?? CONFIG;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a config file and return its contents.
|
||||
*
|
||||
* Files with `.` in the name will be treated as values in plugins. Instead of
|
||||
* reading from the initialized path, plugin keys will be located using Plugin::path().
|
||||
*
|
||||
* @param string $key The identifier to read from. If the key has a . it will be treated
|
||||
* as a plugin prefix.
|
||||
* @return array Parsed configuration values.
|
||||
* @throws \Cake\Core\Exception\CakeException When files don't exist or when
|
||||
* files contain '..' (as this could lead to abusive reads) or when there
|
||||
* is an error parsing the JSON string.
|
||||
*/
|
||||
public function read(string $key): array
|
||||
{
|
||||
$file = $this->_getFilePath($key, true);
|
||||
|
||||
$jsonContent = file_get_contents($file);
|
||||
if ($jsonContent === false) {
|
||||
throw new CakeException(sprintf('Cannot read file content of `%s`', $file));
|
||||
}
|
||||
$values = json_decode($jsonContent, true);
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
throw new CakeException(sprintf(
|
||||
'Error parsing JSON string fetched from config file `%s.json`: %s',
|
||||
$key,
|
||||
json_last_error_msg(),
|
||||
));
|
||||
}
|
||||
if (!is_array($values)) {
|
||||
throw new CakeException(sprintf(
|
||||
'Decoding JSON config file `%s.json` did not return an array',
|
||||
$key,
|
||||
));
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the provided $data into a JSON string that can be used saved
|
||||
* into a file and loaded later.
|
||||
*
|
||||
* @param string $key The identifier to write to. If the key has a . it will
|
||||
* be treated as a plugin prefix.
|
||||
* @param array $data Data to dump.
|
||||
* @return bool Success
|
||||
*/
|
||||
public function dump(string $key, array $data): bool
|
||||
{
|
||||
$filename = $this->_getFilePath($key);
|
||||
|
||||
return file_put_contents($filename, json_encode($data, JSON_PRETTY_PRINT)) !== false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 2.0.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core\Configure\Engine;
|
||||
|
||||
use Cake\Core\Configure\ConfigEngineInterface;
|
||||
use Cake\Core\Configure\FileConfigTrait;
|
||||
use Cake\Core\Exception\CakeException;
|
||||
|
||||
/**
|
||||
* PHP engine allows Configure to load configuration values from
|
||||
* files containing simple PHP arrays.
|
||||
*
|
||||
* Files compatible with PhpConfig should return an array that
|
||||
* contains all the configuration data contained in the file.
|
||||
*
|
||||
* An example configuration file would look like::
|
||||
*
|
||||
* ```
|
||||
* <?php
|
||||
* return [
|
||||
* 'debug' => false,
|
||||
* 'Security' => [
|
||||
* 'salt' => 'its-secret'
|
||||
* ],
|
||||
* 'App' => [
|
||||
* 'namespace' => 'App'
|
||||
* ]
|
||||
* ];
|
||||
* ```
|
||||
*
|
||||
* @see \Cake\Core\Configure::load() for how to load custom configuration files.
|
||||
*/
|
||||
class PhpConfig implements ConfigEngineInterface
|
||||
{
|
||||
use FileConfigTrait;
|
||||
|
||||
/**
|
||||
* File extension.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected string $_extension = '.php';
|
||||
|
||||
/**
|
||||
* Constructor for PHP Config file reading.
|
||||
*
|
||||
* @param string|null $path The path to read config files from. Defaults to CONFIG.
|
||||
*/
|
||||
public function __construct(?string $path = null)
|
||||
{
|
||||
$this->_path = $path ?? CONFIG;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a config file and return its contents.
|
||||
*
|
||||
* Files with `.` in the name will be treated as values in plugins. Instead of
|
||||
* reading from the initialized path, plugin keys will be located using Plugin::path().
|
||||
*
|
||||
* @param string $key The identifier to read from. If the key has a . it will be treated
|
||||
* as a plugin prefix.
|
||||
* @return array Parsed configuration values.
|
||||
* @throws \Cake\Core\Exception\CakeException when files don't exist or they don't contain `$config`.
|
||||
* Or when files contain '..' as this could lead to abusive reads.
|
||||
*/
|
||||
public function read(string $key): array
|
||||
{
|
||||
$file = $this->_getFilePath($key, true);
|
||||
|
||||
$return = include $file;
|
||||
if (is_array($return)) {
|
||||
return $return;
|
||||
}
|
||||
|
||||
throw new CakeException(sprintf('Config file `%s` did not return an array', $key . '.php.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the provided $data into a string of PHP code that can
|
||||
* be used saved into a file and loaded later.
|
||||
*
|
||||
* @param string $key The identifier to write to. If the key has a . it will be treated
|
||||
* as a plugin prefix.
|
||||
* @param array $data Data to dump.
|
||||
* @return bool Success
|
||||
*/
|
||||
public function dump(string $key, array $data): bool
|
||||
{
|
||||
$contents = '<?php' . "\n" . 'return ' . var_export($data, true) . ';';
|
||||
|
||||
$filename = $this->_getFilePath($key);
|
||||
|
||||
return file_put_contents($filename, $contents) > 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 3.0.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core\Configure;
|
||||
|
||||
use Cake\Core\Exception\CakeException;
|
||||
use Cake\Core\Plugin;
|
||||
use function Cake\Core\pluginSplit;
|
||||
|
||||
/**
|
||||
* Trait providing utility methods for file based config engines.
|
||||
*/
|
||||
trait FileConfigTrait
|
||||
{
|
||||
/**
|
||||
* The path this engine finds files on.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected string $_path = '';
|
||||
|
||||
/**
|
||||
* Get file path
|
||||
*
|
||||
* @param string $key The identifier to write to. If the key has a . it will be treated
|
||||
* as a plugin prefix.
|
||||
* @param bool $checkExists Whether to check if file exists. Defaults to false.
|
||||
* @return string Full file path
|
||||
* @throws \Cake\Core\Exception\CakeException When files don't exist or when
|
||||
* files contain '..' as this could lead to abusive reads.
|
||||
*/
|
||||
protected function _getFilePath(string $key, bool $checkExists = false): string
|
||||
{
|
||||
if (str_contains($key, '..')) {
|
||||
throw new CakeException('Cannot load/dump configuration files with ../ in them.');
|
||||
}
|
||||
|
||||
[$plugin, $key] = pluginSplit($key);
|
||||
|
||||
if ($plugin) {
|
||||
$file = Plugin::configPath($plugin) . $key;
|
||||
} else {
|
||||
$file = $this->_path . $key;
|
||||
}
|
||||
|
||||
$file .= $this->_extension;
|
||||
|
||||
if (!$checkExists || is_file($file)) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
$realPath = realpath($file);
|
||||
if ($realPath !== false && is_file($realPath)) {
|
||||
return $realPath;
|
||||
}
|
||||
|
||||
throw new CakeException(sprintf('Could not load configuration file: `%s`.', $file));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright 2005-2011, Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 3.5.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core;
|
||||
|
||||
use Cake\Console\CommandCollection;
|
||||
|
||||
/**
|
||||
* An interface defining the methods that the
|
||||
* console runner depend on.
|
||||
*/
|
||||
interface ConsoleApplicationInterface
|
||||
{
|
||||
/**
|
||||
* Load all the application configuration and bootstrap logic.
|
||||
*
|
||||
* Override this method to add additional bootstrap logic for your application.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function bootstrap(): void;
|
||||
|
||||
/**
|
||||
* Define the console commands for an application.
|
||||
*
|
||||
* @param \Cake\Console\CommandCollection $commands The CommandCollection to add commands into.
|
||||
* @return \Cake\Console\CommandCollection The updated collection.
|
||||
*/
|
||||
public function console(CommandCollection $commands): CommandCollection;
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 4.2.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core;
|
||||
|
||||
use League\Container\Container as LeagueContainer;
|
||||
|
||||
/**
|
||||
* Dependency Injection container
|
||||
*
|
||||
* Based on the container out of League\Container
|
||||
*/
|
||||
class Container extends LeagueContainer implements ContainerInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 4.2.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core;
|
||||
|
||||
/**
|
||||
* Interface for applications that configure and use a dependency injection container.
|
||||
*/
|
||||
interface ContainerApplicationInterface
|
||||
{
|
||||
/**
|
||||
* Register services to the container
|
||||
*
|
||||
* Registered services can have instances fetched out of the container
|
||||
* using `get()`. Dependencies and parameters will be resolved based
|
||||
* on service definitions.
|
||||
*
|
||||
* @param \Cake\Core\ContainerInterface $container The container to add services to
|
||||
* @return void
|
||||
*/
|
||||
public function services(ContainerInterface $container): void;
|
||||
|
||||
/**
|
||||
* Create a new container and register services.
|
||||
*
|
||||
* This will `register()` services provided by both the application
|
||||
* and any plugins if the application has plugin support.
|
||||
*
|
||||
* @return \Cake\Core\ContainerInterface A populated container
|
||||
*/
|
||||
public function getContainer(): ContainerInterface;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 4.2.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core;
|
||||
|
||||
use League\Container\DefinitionContainerInterface;
|
||||
use Psr\Container\ContainerInterface as PsrContainerInterface;
|
||||
|
||||
/**
|
||||
* Interface for the Dependency Injection Container in CakePHP applications
|
||||
*
|
||||
* This interface extends the PSR-11 container interface and adds
|
||||
* methods to add services and service providers to the container.
|
||||
*
|
||||
* The methods defined in this interface use the conventions provided
|
||||
* by league/container as that is the library that CakePHP uses.
|
||||
*/
|
||||
interface ContainerInterface extends DefinitionContainerInterface
|
||||
{
|
||||
/**
|
||||
* @param \Psr\Container\ContainerInterface $container The container instance to use as delegation
|
||||
* @return \Psr\Container\ContainerInterface
|
||||
*/
|
||||
public function delegate(PsrContainerInterface $container): PsrContainerInterface;
|
||||
}
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 3.0.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core;
|
||||
|
||||
use Cake\Utility\Inflector;
|
||||
|
||||
/**
|
||||
* Provides methods that allow other classes access to conventions based inflections.
|
||||
*/
|
||||
trait ConventionsTrait
|
||||
{
|
||||
/**
|
||||
* Creates a fixture name
|
||||
*
|
||||
* @param string $name Model class name
|
||||
* @return string Singular model key
|
||||
*/
|
||||
protected function _fixtureName(string $name): string
|
||||
{
|
||||
return Inflector::camelize($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the proper entity name (singular) for the specified name
|
||||
*
|
||||
* @param string $name Name
|
||||
* @return string Camelized and plural model name
|
||||
*/
|
||||
protected function _entityName(string $name): string
|
||||
{
|
||||
return Inflector::singularize(Inflector::camelize($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the proper underscored model key for associations
|
||||
*
|
||||
* If the input contains a dot, assume that the right side is the real table name.
|
||||
*
|
||||
* @param string $name Model class name
|
||||
* @return string Singular model key
|
||||
*/
|
||||
protected function _modelKey(string $name): string
|
||||
{
|
||||
[, $name] = pluginSplit($name);
|
||||
|
||||
return Inflector::underscore(Inflector::singularize($name)) . '_id';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the proper model name from a foreign key
|
||||
*
|
||||
* @param string $key Foreign key
|
||||
* @return string Model name
|
||||
*/
|
||||
protected function _modelNameFromKey(string $key): string
|
||||
{
|
||||
$key = str_replace('_id', '', $key);
|
||||
|
||||
return Inflector::camelize(Inflector::pluralize($key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the singular name for use in views.
|
||||
*
|
||||
* @param string $name Name to use
|
||||
* @return string Variable name
|
||||
*/
|
||||
protected function _singularName(string $name): string
|
||||
{
|
||||
return Inflector::variable(Inflector::singularize($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the plural variable name for views
|
||||
*
|
||||
* @param string $name Name to use
|
||||
* @return string Plural name for views
|
||||
*/
|
||||
protected function _variableName(string $name): string
|
||||
{
|
||||
return Inflector::variable($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the singular human name used in views
|
||||
*
|
||||
* @param string $name Controller name
|
||||
* @return string Singular human name
|
||||
*/
|
||||
protected function _singularHumanName(string $name): string
|
||||
{
|
||||
return Inflector::humanize(Inflector::underscore(Inflector::singularize($name)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a camelized version of $name
|
||||
*
|
||||
* @param string $name name
|
||||
* @return string Camelized name
|
||||
*/
|
||||
protected function _camelize(string $name): string
|
||||
{
|
||||
return Inflector::camelize($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the plural human name used in views
|
||||
*
|
||||
* @param string $name Controller name
|
||||
* @return string Plural human name
|
||||
*/
|
||||
protected function _pluralHumanName(string $name): string
|
||||
{
|
||||
return Inflector::humanize(Inflector::underscore($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the correct path for a plugin. Scans $pluginPaths for the plugin you want.
|
||||
*
|
||||
* @param string $pluginName Name of the plugin you want ie. DebugKit
|
||||
* @return string Path to the correct plugin.
|
||||
*/
|
||||
protected function _pluginPath(string $pluginName): string
|
||||
{
|
||||
if (Plugin::isLoaded($pluginName)) {
|
||||
return Plugin::path($pluginName);
|
||||
}
|
||||
|
||||
return current(App::path('plugins')) . $pluginName . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return plugin's namespace
|
||||
*
|
||||
* @param string $pluginName Plugin name
|
||||
* @return string Plugin's namespace
|
||||
*/
|
||||
protected function _pluginNamespace(string $pluginName): string
|
||||
{
|
||||
return str_replace('/', '\\', $pluginName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright 2005-2011, Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 5.1.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core;
|
||||
|
||||
use Cake\Event\EventManagerInterface;
|
||||
|
||||
interface EventAwareApplicationInterface
|
||||
{
|
||||
/**
|
||||
* Register application events.
|
||||
*
|
||||
* @param \Cake\Event\EventManagerInterface $eventManager The global event manager to register listeners on
|
||||
* @return \Cake\Event\EventManagerInterface
|
||||
*/
|
||||
public function events(EventManagerInterface $eventManager): EventManagerInterface;
|
||||
|
||||
/**
|
||||
* @param \Cake\Event\EventManagerInterface $eventManager The global event manager to register listeners on
|
||||
* @return \Cake\Event\EventManagerInterface
|
||||
*/
|
||||
public function pluginEvents(EventManagerInterface $eventManager): EventManagerInterface;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @since 3.0.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Base class that all CakePHP Exceptions extend.
|
||||
*/
|
||||
class CakeException extends RuntimeException
|
||||
{
|
||||
/**
|
||||
* Array of attributes that are passed in from the constructor, and
|
||||
* made available in the view when a development error is displayed.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected array $_attributes = [];
|
||||
|
||||
/**
|
||||
* Template string that has attributes sprintf()'ed into it.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected string $_messageTemplate = '';
|
||||
|
||||
/**
|
||||
* Default exception code
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected int $_defaultCode = 0;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* Allows you to create exceptions that are treated as framework errors and disabled
|
||||
* when debug mode is off.
|
||||
*
|
||||
* @param array|string $message Either the string of the error message, or an array of attributes
|
||||
* that are made available in the view, and sprintf()'d into Exception::$_messageTemplate
|
||||
* @param int|null $code The error code
|
||||
* @param \Throwable|null $previous the previous exception.
|
||||
*/
|
||||
public function __construct(array|string $message = '', ?int $code = null, ?Throwable $previous = null)
|
||||
{
|
||||
if (is_array($message)) {
|
||||
$this->_attributes = $message;
|
||||
$message = vsprintf($this->_messageTemplate, $message);
|
||||
}
|
||||
parent::__construct($message, $code ?? $this->_defaultCode, $previous);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the passed in attributes
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAttributes(): array
|
||||
{
|
||||
return $this->_attributes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @since 5.2.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core\Exception;
|
||||
|
||||
use Throwable;
|
||||
|
||||
interface HttpErrorCodeInterface extends Throwable
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @since 3.0.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core\Exception;
|
||||
|
||||
/**
|
||||
* Exception raised when a plugin could not be found
|
||||
*/
|
||||
class MissingPluginException extends CakeException
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected string $_messageTemplate = 'Plugin `%s` could not be found.';
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright 2005-2011, Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 3.5.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core;
|
||||
|
||||
use Cake\Http\MiddlewareQueue;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
/**
|
||||
* An interface defining the methods that the
|
||||
* http server depend on.
|
||||
*/
|
||||
interface HttpApplicationInterface extends RequestHandlerInterface
|
||||
{
|
||||
/**
|
||||
* Load all the application configuration and bootstrap logic.
|
||||
*
|
||||
* Override this method to add additional bootstrap logic for your application.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function bootstrap(): void;
|
||||
|
||||
/**
|
||||
* Define the HTTP middleware layers for an application.
|
||||
*
|
||||
* @param \Cake\Http\MiddlewareQueue $middlewareQueue The middleware queue to set in your App Class
|
||||
* @return \Cake\Http\MiddlewareQueue
|
||||
*/
|
||||
public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue;
|
||||
}
|
||||
+326
@@ -0,0 +1,326 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 3.0.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core;
|
||||
|
||||
use Cake\Core\Exception\CakeException;
|
||||
use Cake\Utility\Hash;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* A trait for reading and writing instance config
|
||||
*
|
||||
* Implementing objects are expected to declare a `$_defaultConfig` property.
|
||||
*/
|
||||
trait InstanceConfigTrait
|
||||
{
|
||||
/**
|
||||
* Runtime config
|
||||
*
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
protected array $_config = [];
|
||||
|
||||
/**
|
||||
* Whether the config property has already been configured with defaults
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected bool $_configInitialized = false;
|
||||
|
||||
/**
|
||||
* Sets the config.
|
||||
*
|
||||
* ### Usage
|
||||
*
|
||||
* Setting a specific value:
|
||||
*
|
||||
* ```
|
||||
* $this->setConfig('key', $value);
|
||||
* ```
|
||||
*
|
||||
* Setting a nested value:
|
||||
*
|
||||
* ```
|
||||
* $this->setConfig('some.nested.key', $value);
|
||||
* ```
|
||||
*
|
||||
* Updating multiple config settings at the same time:
|
||||
*
|
||||
* ```
|
||||
* $this->setConfig(['one' => 'value', 'another' => 'value']);
|
||||
* ```
|
||||
*
|
||||
* @param array<string, mixed>|string $key The key to set, or a complete array of configs.
|
||||
* @param mixed|null $value The value to set.
|
||||
* @param bool $merge Whether to recursively merge or overwrite existing config, defaults to true.
|
||||
* @return $this
|
||||
* @throws \Cake\Core\Exception\CakeException When trying to set a key that is invalid.
|
||||
*/
|
||||
public function setConfig(array|string $key, mixed $value = null, bool $merge = true)
|
||||
{
|
||||
$this->initCfg();
|
||||
$this->_configWrite($key, $value, $merge);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the config.
|
||||
*
|
||||
* ### Usage
|
||||
*
|
||||
* Reading the whole config:
|
||||
*
|
||||
* ```
|
||||
* $this->getConfig();
|
||||
* ```
|
||||
*
|
||||
* Reading a specific value:
|
||||
*
|
||||
* ```
|
||||
* $this->getConfig('key');
|
||||
* ```
|
||||
*
|
||||
* Reading a nested value:
|
||||
*
|
||||
* ```
|
||||
* $this->getConfig('some.nested.key');
|
||||
* ```
|
||||
*
|
||||
* Reading with default value:
|
||||
*
|
||||
* ```
|
||||
* $this->getConfig('some-key', 'default-value');
|
||||
* ```
|
||||
*
|
||||
* @param string|null $key The key to get or null for the whole config.
|
||||
* @param mixed $default The return value when the key does not exist.
|
||||
* @return ($key is null ? array : mixed) Configuration data at the named key or null if the key does not exist.
|
||||
*/
|
||||
public function getConfig(?string $key = null, mixed $default = null): mixed
|
||||
{
|
||||
$this->initCfg();
|
||||
|
||||
return $this->_configRead($key) ?? $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the config for this specific key.
|
||||
*
|
||||
* The config value for this key must exist, it can never be null.
|
||||
*
|
||||
* @param string $key The key to get.
|
||||
* @return mixed Configuration data at the named key
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function getConfigOrFail(string $key): mixed
|
||||
{
|
||||
$config = $this->getConfig($key);
|
||||
if ($config === null) {
|
||||
throw new InvalidArgumentException(sprintf('Expected configuration `%s` not found.', $key));
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge provided config with existing config. Unlike `config()` which does
|
||||
* a recursive merge for nested keys, this method does a simple merge.
|
||||
*
|
||||
* Setting a specific value:
|
||||
*
|
||||
* ```
|
||||
* $this->configShallow('key', $value);
|
||||
* ```
|
||||
*
|
||||
* Setting a nested value:
|
||||
*
|
||||
* ```
|
||||
* $this->configShallow('some.nested.key', $value);
|
||||
* ```
|
||||
*
|
||||
* Updating multiple config settings at the same time:
|
||||
*
|
||||
* ```
|
||||
* $this->configShallow(['one' => 'value', 'another' => 'value']);
|
||||
* ```
|
||||
*
|
||||
* @param array<string, mixed>|string $key The key to set, or a complete array of configs.
|
||||
* @param mixed|null $value The value to set.
|
||||
* @return $this
|
||||
*/
|
||||
public function configShallow(array|string $key, mixed $value = null)
|
||||
{
|
||||
$this->initCfg();
|
||||
$this->_configWrite($key, $value, 'shallow');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a config key.
|
||||
*
|
||||
* @param string $key Key to delete. It can be a dot separated string to delete nested keys.
|
||||
* @return $this
|
||||
*/
|
||||
public function deleteConfig(string $key)
|
||||
{
|
||||
$this->initCfg();
|
||||
$this->_configDelete($key);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the config with the default config.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function initCfg(): void
|
||||
{
|
||||
if (!$this->_configInitialized) {
|
||||
$this->_config = $this->_defaultConfig;
|
||||
$this->_configInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a config key.
|
||||
*
|
||||
* @param string|null $key Key to read.
|
||||
* @return ($key is null ? array : mixed)
|
||||
*/
|
||||
protected function _configRead(?string $key): mixed
|
||||
{
|
||||
if ($key === null) {
|
||||
return $this->_config;
|
||||
}
|
||||
|
||||
if (!str_contains($key, '.')) {
|
||||
return $this->_config[$key] ?? null;
|
||||
}
|
||||
|
||||
$return = $this->_config;
|
||||
|
||||
foreach (explode('.', $key) as $k) {
|
||||
if (!is_array($return) || !isset($return[$k])) {
|
||||
$return = null;
|
||||
break;
|
||||
}
|
||||
|
||||
$return = $return[$k];
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a config key.
|
||||
*
|
||||
* @param array<string, mixed>|string $key Key to write to.
|
||||
* @param mixed $value Value to write.
|
||||
* @param string|bool $merge True to merge recursively, 'shallow' for simple merge,
|
||||
* false to overwrite, defaults to false.
|
||||
* @return void
|
||||
* @throws \Cake\Core\Exception\CakeException if attempting to clobber existing config
|
||||
*/
|
||||
protected function _configWrite(array|string $key, mixed $value, string|bool $merge = false): void
|
||||
{
|
||||
if (is_string($key) && $value === null) {
|
||||
$this->_configDelete($key);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($merge) {
|
||||
$update = is_array($key) ? $key : [$key => $value];
|
||||
if ($merge === 'shallow') {
|
||||
$this->_config = array_merge($this->_config, Hash::expand($update));
|
||||
} else {
|
||||
$this->_config = Hash::merge($this->_config, Hash::expand($update));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_array($key)) {
|
||||
foreach ($key as $k => $val) {
|
||||
$this->_configWrite($k, $val);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!str_contains($key, '.')) {
|
||||
$this->_config[$key] = $value;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$update = &$this->_config;
|
||||
$stack = explode('.', $key);
|
||||
|
||||
foreach ($stack as $k) {
|
||||
if (!is_array($update)) {
|
||||
throw new CakeException(sprintf('Cannot set `%s` value.', $key));
|
||||
}
|
||||
|
||||
$update[$k] ??= [];
|
||||
|
||||
$update = &$update[$k];
|
||||
}
|
||||
|
||||
$update = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a single config key.
|
||||
*
|
||||
* @param string $key Key to delete.
|
||||
* @return void
|
||||
* @throws \Cake\Core\Exception\CakeException if attempting to clobber existing config
|
||||
*/
|
||||
protected function _configDelete(string $key): void
|
||||
{
|
||||
if (!str_contains($key, '.')) {
|
||||
unset($this->_config[$key]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$update = &$this->_config;
|
||||
$stack = explode('.', $key);
|
||||
$length = count($stack);
|
||||
|
||||
foreach ($stack as $i => $k) {
|
||||
if (!is_array($update)) {
|
||||
throw new CakeException(sprintf('Cannot unset `%s` value.', $key));
|
||||
}
|
||||
|
||||
if (!isset($update[$k])) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ($i === $length - 1) {
|
||||
unset($update[$k]);
|
||||
break;
|
||||
}
|
||||
|
||||
$update = &$update[$k];
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
CakePHP(tm) : The Rapid Development PHP Framework (https://cakephp.org)
|
||||
Copyright (c) 2005-2020, Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+406
@@ -0,0 +1,406 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 3.0.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core;
|
||||
|
||||
use ArrayIterator;
|
||||
use Cake\Core\Exception\CakeException;
|
||||
use Cake\Event\EventDispatcherInterface;
|
||||
use Cake\Event\EventListenerInterface;
|
||||
use Countable;
|
||||
use IteratorAggregate;
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
* Acts as a registry/factory for objects.
|
||||
*
|
||||
* Provides registry & factory functionality for object types. Used
|
||||
* as a super class for various composition based re-use features in CakePHP.
|
||||
*
|
||||
* Each subclass needs to implement the various abstract methods to complete
|
||||
* the template method load().
|
||||
*
|
||||
* The ObjectRegistry is EventManager aware, but each extending class will need to use
|
||||
* \Cake\Event\EventDispatcherTrait to attach and detach on set and bind
|
||||
*
|
||||
* @see \Cake\Controller\ComponentRegistry
|
||||
* @see \Cake\View\HelperRegistry
|
||||
* @see \Cake\Console\TaskRegistry
|
||||
* @template TObject of object
|
||||
* @template-implements \IteratorAggregate<string, TObject>
|
||||
*/
|
||||
abstract class ObjectRegistry implements Countable, IteratorAggregate
|
||||
{
|
||||
/**
|
||||
* Map of loaded objects.
|
||||
*
|
||||
* @var array<string, TObject>
|
||||
*/
|
||||
protected array $_loaded = [];
|
||||
|
||||
/**
|
||||
* Loads/constructs an object instance.
|
||||
*
|
||||
* Will return the instance in the registry if it already exists.
|
||||
* If a subclass provides event support, you can use `$config['enabled'] = false`
|
||||
* to exclude constructed objects from being registered for events.
|
||||
*
|
||||
* Using {@link \Cake\Controller\Component::$components} as an example. You can alias
|
||||
* an object by setting the 'className' key, i.e.,
|
||||
*
|
||||
* ```
|
||||
* protected $components = [
|
||||
* 'Email' => [
|
||||
* 'className' => 'App\Controller\Component\AliasedEmailComponent'
|
||||
* ];
|
||||
* ];
|
||||
* ```
|
||||
*
|
||||
* All calls to the `Email` component would use `AliasedEmail` instead.
|
||||
*
|
||||
* @param string $name The name/class of the object to load.
|
||||
* @param array<string, mixed> $config Additional settings to use when loading the object.
|
||||
* @return TObject
|
||||
* @throws \Exception If the class cannot be found.
|
||||
*/
|
||||
public function load(string $name, array $config = []): object
|
||||
{
|
||||
if (isset($config['className'])) {
|
||||
if ($name === $config['className']) {
|
||||
[, $objName] = pluginSplit($name);
|
||||
} else {
|
||||
$objName = $name;
|
||||
}
|
||||
$name = $config['className'];
|
||||
} else {
|
||||
[$plugin, $objName] = pluginSplit($name);
|
||||
if ($plugin) {
|
||||
$config['className'] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
$loaded = isset($this->_loaded[$objName]);
|
||||
if ($loaded && $config !== []) {
|
||||
$this->_checkDuplicate($objName, $config);
|
||||
}
|
||||
if ($loaded) {
|
||||
return $this->_loaded[$objName];
|
||||
}
|
||||
|
||||
$className = $name;
|
||||
if (is_string($name)) {
|
||||
$className = $this->_resolveClassName($name);
|
||||
if ($className === null) {
|
||||
[$plugin, $name] = pluginSplit($name);
|
||||
$this->_throwMissingClassError($name, $plugin);
|
||||
}
|
||||
}
|
||||
|
||||
$instance = $this->_create($className, $objName, $config);
|
||||
$this->_loaded[$objName] = $instance;
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for duplicate object loading.
|
||||
*
|
||||
* If a duplicate is being loaded and has different configuration, that is
|
||||
* bad and an exception will be raised.
|
||||
*
|
||||
* An exception is raised, as replacing the object will not update any
|
||||
* references other objects may have. Additionally, simply updating the runtime
|
||||
* configuration is not a good option as we may be missing important constructor
|
||||
* logic dependent on the configuration.
|
||||
*
|
||||
* @param string $name The name of the alias in the registry.
|
||||
* @param array<string, mixed> $config The config data for the new instance.
|
||||
* @return void
|
||||
* @throws \Cake\Core\Exception\CakeException When a duplicate is found.
|
||||
*/
|
||||
protected function _checkDuplicate(string $name, array $config): void
|
||||
{
|
||||
$existing = $this->_loaded[$name];
|
||||
$msg = sprintf('The `%s` alias has already been loaded.', $name);
|
||||
$hasConfig = method_exists($existing, 'getConfig');
|
||||
if (!$hasConfig) {
|
||||
throw new CakeException($msg);
|
||||
}
|
||||
if (!$config) {
|
||||
return;
|
||||
}
|
||||
$existingConfig = $existing->getConfig();
|
||||
unset($config['enabled'], $existingConfig['enabled']);
|
||||
|
||||
$failure = null;
|
||||
foreach ($config as $key => $value) {
|
||||
if (!array_key_exists($key, $existingConfig)) {
|
||||
$failure = " The `{$key}` was not defined in the previous configuration data.";
|
||||
break;
|
||||
}
|
||||
if (isset($existingConfig[$key]) && $existingConfig[$key] !== $value) {
|
||||
$failure = sprintf(
|
||||
' The `%s` key has a value of `%s` but previously had a value of `%s`',
|
||||
$key,
|
||||
json_encode($value, JSON_THROW_ON_ERROR),
|
||||
json_encode($existingConfig[$key], JSON_THROW_ON_ERROR),
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($failure) {
|
||||
throw new CakeException($msg . $failure);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Should resolve the classname for a given object type.
|
||||
*
|
||||
* @param string $class The class to resolve.
|
||||
* @return class-string<TObject>|null The resolved name or null for failure.
|
||||
*/
|
||||
abstract protected function _resolveClassName(string $class): ?string;
|
||||
|
||||
/**
|
||||
* Throw an exception when the requested object name is missing.
|
||||
*
|
||||
* @param string $class The class that is missing.
|
||||
* @param string|null $plugin The plugin $class is missing from.
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
abstract protected function _throwMissingClassError(string $class, ?string $plugin): void;
|
||||
|
||||
/**
|
||||
* Create an instance of a given classname.
|
||||
*
|
||||
* This method should construct and do any other initialization logic
|
||||
* required.
|
||||
*
|
||||
* @param TObject|class-string<TObject> $class The class to build.
|
||||
* @param string $alias The alias of the object.
|
||||
* @param array<string, mixed> $config The Configuration settings for construction
|
||||
* @return TObject
|
||||
*/
|
||||
abstract protected function _create(object|string $class, string $alias, array $config): object;
|
||||
|
||||
/**
|
||||
* Get the list of loaded objects.
|
||||
*
|
||||
* @return array<string> List of object names.
|
||||
*/
|
||||
public function loaded(): array
|
||||
{
|
||||
return array_keys($this->_loaded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a given object is loaded.
|
||||
*
|
||||
* @param string $name The object name to check for.
|
||||
* @return bool True is object is loaded else false.
|
||||
*/
|
||||
public function has(string $name): bool
|
||||
{
|
||||
return isset($this->_loaded[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get loaded object instance.
|
||||
*
|
||||
* @param string $name Name of object.
|
||||
* @return TObject Object instance.
|
||||
* @throws \Cake\Core\Exception\CakeException If not loaded or found.
|
||||
*/
|
||||
public function get(string $name): object
|
||||
{
|
||||
if (!isset($this->_loaded[$name])) {
|
||||
throw new CakeException(sprintf('Unknown object `%s`.', $name));
|
||||
}
|
||||
|
||||
return $this->_loaded[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide public read access to the loaded objects
|
||||
*
|
||||
* @param string $name Name of property to read
|
||||
* @return TObject|null
|
||||
*/
|
||||
public function __get(string $name): ?object
|
||||
{
|
||||
return $this->_loaded[$name] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide isset access to _loaded
|
||||
*
|
||||
* @param string $name Name of object being checked.
|
||||
* @return bool
|
||||
*/
|
||||
public function __isset(string $name): bool
|
||||
{
|
||||
return $this->has($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an object.
|
||||
*
|
||||
* @param string $name Name of a property to set.
|
||||
* @param TObject $object Object to set.
|
||||
* @return void
|
||||
*/
|
||||
public function __set(string $name, object $object): void
|
||||
{
|
||||
$this->set($name, $object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsets an object.
|
||||
*
|
||||
* @param string $name Name of a property to unset.
|
||||
* @return void
|
||||
*/
|
||||
public function __unset(string $name): void
|
||||
{
|
||||
$this->unload($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes an object configuration array into associative form for making
|
||||
* lazy loading easier.
|
||||
*
|
||||
* @param array $objects Array of child objects to normalize.
|
||||
* @return array<string, array> Array of normalized objects.
|
||||
*/
|
||||
public function normalizeArray(array $objects): array
|
||||
{
|
||||
$normal = [];
|
||||
foreach ($objects as $objectName => $config) {
|
||||
if (is_int($objectName)) {
|
||||
$objectName = $config;
|
||||
$config = [];
|
||||
}
|
||||
|
||||
[$plugin, $name] = pluginSplit($objectName);
|
||||
if ($plugin) {
|
||||
$config['className'] = $objectName;
|
||||
}
|
||||
|
||||
$normal[$name] = $config;
|
||||
}
|
||||
|
||||
return $normal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear loaded instances in the registry.
|
||||
*
|
||||
* If the registry subclass has an event manager, the objects will be detached from events as well.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
foreach (array_keys($this->_loaded) as $name) {
|
||||
$this->unload((string)$name);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an object directly into the registry by name.
|
||||
*
|
||||
* If this collection implements events, the passed object will
|
||||
* be attached into the event manager
|
||||
*
|
||||
* @param string $name The name of the object to set in the registry.
|
||||
* @param TObject $object instance to store in the registry
|
||||
* @return $this
|
||||
*/
|
||||
public function set(string $name, object $object)
|
||||
{
|
||||
// Just call unload if the object was loaded before
|
||||
if (array_key_exists($name, $this->_loaded)) {
|
||||
$this->unload($name);
|
||||
}
|
||||
if ($this instanceof EventDispatcherInterface && $object instanceof EventListenerInterface) {
|
||||
$this->getEventManager()->on($object);
|
||||
}
|
||||
$this->_loaded[$name] = $object;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an object from the registry.
|
||||
*
|
||||
* If this registry has an event manager, the object will be detached from any events as well.
|
||||
*
|
||||
* @param string $name The name of the object to remove from the registry.
|
||||
* @return $this
|
||||
*/
|
||||
public function unload(string $name)
|
||||
{
|
||||
if (!isset($this->_loaded[$name])) {
|
||||
throw new CakeException(sprintf('Object named `%s` is not loaded.', $name));
|
||||
}
|
||||
|
||||
$object = $this->_loaded[$name];
|
||||
if ($this instanceof EventDispatcherInterface && $object instanceof EventListenerInterface) {
|
||||
$this->getEventManager()->off($object);
|
||||
}
|
||||
unset($this->_loaded[$name]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array iterator.
|
||||
*
|
||||
* @return \Traversable<string, TObject>
|
||||
*/
|
||||
public function getIterator(): Traversable
|
||||
{
|
||||
return new ArrayIterator($this->_loaded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of loaded objects.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count(): int
|
||||
{
|
||||
return count($this->_loaded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug friendly object properties.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function __debugInfo(): array
|
||||
{
|
||||
$properties = get_object_vars($this);
|
||||
if (isset($properties['_loaded'])) {
|
||||
$properties['_loaded'] = array_keys($properties['_loaded']);
|
||||
}
|
||||
|
||||
return $properties;
|
||||
}
|
||||
}
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 2.0.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core;
|
||||
|
||||
/**
|
||||
* Plugin is used to load and locate plugins.
|
||||
*
|
||||
* It also can retrieve plugin paths and load their bootstrap and routes files.
|
||||
*
|
||||
* @link https://book.cakephp.org/5/en/plugins.html
|
||||
*/
|
||||
class Plugin
|
||||
{
|
||||
/**
|
||||
* Holds a list of all loaded plugins and their configuration
|
||||
*
|
||||
* @var \Cake\Core\PluginCollection|null
|
||||
*/
|
||||
protected static ?PluginCollection $plugins = null;
|
||||
|
||||
/**
|
||||
* Returns the filesystem path for a plugin
|
||||
*
|
||||
* @param string $name name of the plugin in CamelCase format
|
||||
* @return string path to the plugin folder
|
||||
* @throws \Cake\Core\Exception\MissingPluginException If the folder for plugin was not found
|
||||
* or plugin has not been loaded.
|
||||
*/
|
||||
public static function path(string $name): string
|
||||
{
|
||||
$plugin = static::getCollection()->get($name);
|
||||
|
||||
return $plugin->getPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the filesystem path for plugin's folder containing class files.
|
||||
*
|
||||
* @param string $name name of the plugin in CamelCase format.
|
||||
* @return string Path to the plugin folder containing class files.
|
||||
* @throws \Cake\Core\Exception\MissingPluginException If plugin has not been loaded.
|
||||
*/
|
||||
public static function classPath(string $name): string
|
||||
{
|
||||
$plugin = static::getCollection()->get($name);
|
||||
|
||||
return $plugin->getClassPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the filesystem path for plugin's folder containing config files.
|
||||
*
|
||||
* @param string $name name of the plugin in CamelCase format.
|
||||
* @return string Path to the plugin folder containing config files.
|
||||
* @throws \Cake\Core\Exception\MissingPluginException If plugin has not been loaded.
|
||||
*/
|
||||
public static function configPath(string $name): string
|
||||
{
|
||||
$plugin = static::getCollection()->get($name);
|
||||
|
||||
return $plugin->getConfigPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the filesystem path for plugin's folder containing template files.
|
||||
*
|
||||
* @param string $name name of the plugin in CamelCase format.
|
||||
* @return string Path to the plugin folder containing template files.
|
||||
* @throws \Cake\Core\Exception\MissingPluginException If plugin has not been loaded.
|
||||
*/
|
||||
public static function templatePath(string $name): string
|
||||
{
|
||||
$plugin = static::getCollection()->get($name);
|
||||
|
||||
return $plugin->getTemplatePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the plugin $plugin is already loaded.
|
||||
*
|
||||
* @param string $plugin Plugin name.
|
||||
* @return bool
|
||||
* @since 3.7.0
|
||||
*/
|
||||
public static function isLoaded(string $plugin): bool
|
||||
{
|
||||
return static::getCollection()->has($plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of loaded plugins.
|
||||
*
|
||||
* @return array<string> A list of plugins that have been loaded
|
||||
*/
|
||||
public static function loaded(): array
|
||||
{
|
||||
$names = [];
|
||||
foreach (static::getCollection() as $plugin) {
|
||||
$names[] = $plugin->getName();
|
||||
}
|
||||
sort($names);
|
||||
|
||||
return $names;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the shared plugin collection.
|
||||
*
|
||||
* This method should generally not be used during application
|
||||
* runtime as plugins should be set during Application startup.
|
||||
*
|
||||
* @return \Cake\Core\PluginCollection
|
||||
*/
|
||||
public static function getCollection(): PluginCollection
|
||||
{
|
||||
return static::$plugins ??= new PluginCollection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the shared plugin collection.
|
||||
*
|
||||
* @param \Cake\Core\PluginCollection $collection
|
||||
* @return void
|
||||
*/
|
||||
public static function setCollection(PluginCollection $collection): void
|
||||
{
|
||||
static::$plugins = $collection;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 3.6.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core;
|
||||
|
||||
use Cake\Console\CommandCollection;
|
||||
use Cake\Event\EventDispatcherInterface;
|
||||
use Cake\Http\MiddlewareQueue;
|
||||
use Cake\Routing\RouteBuilder;
|
||||
|
||||
/**
|
||||
* Interface for Applications that leverage plugins & events.
|
||||
*
|
||||
* Events can be bound to the application event manager during
|
||||
* the application's bootstrap and plugin bootstrap.
|
||||
*
|
||||
* @template TSubject
|
||||
* @extends \Cake\Event\EventDispatcherInterface<\Cake\Http\BaseApplication>
|
||||
*/
|
||||
interface PluginApplicationInterface extends EventDispatcherInterface
|
||||
{
|
||||
/**
|
||||
* Add a plugin to the loaded plugin set.
|
||||
*
|
||||
* If the named plugin does not exist, or does not define a Plugin class, an
|
||||
* instance of `Cake\Core\BasePlugin` will be used. This generated class will have
|
||||
* all plugin hooks enabled.
|
||||
*
|
||||
* @param \Cake\Core\PluginInterface|string $name The plugin name or plugin object.
|
||||
* @param array<string, mixed> $config The configuration data for the plugin if using a string for $name
|
||||
* @return $this
|
||||
*/
|
||||
public function addPlugin(PluginInterface|string $name, array $config = []);
|
||||
|
||||
/**
|
||||
* Run bootstrap logic for loaded plugins.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function pluginBootstrap(): void;
|
||||
|
||||
/**
|
||||
* Run routes hooks for loaded plugins
|
||||
*
|
||||
* @param \Cake\Routing\RouteBuilder $routes The route builder to use.
|
||||
* @return \Cake\Routing\RouteBuilder
|
||||
*/
|
||||
public function pluginRoutes(RouteBuilder $routes): RouteBuilder;
|
||||
|
||||
/**
|
||||
* Run middleware hooks for plugins
|
||||
*
|
||||
* @param \Cake\Http\MiddlewareQueue $middleware The MiddlewareQueue to use.
|
||||
* @return \Cake\Http\MiddlewareQueue
|
||||
*/
|
||||
public function pluginMiddleware(MiddlewareQueue $middleware): MiddlewareQueue;
|
||||
|
||||
/**
|
||||
* Run console hooks for plugins
|
||||
*
|
||||
* @param \Cake\Console\CommandCollection $commands The CommandCollection to use.
|
||||
* @return \Cake\Console\CommandCollection
|
||||
*/
|
||||
public function pluginConsole(CommandCollection $commands): CommandCollection;
|
||||
}
|
||||
+400
@@ -0,0 +1,400 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright 2005-2011, Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 3.6.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core;
|
||||
|
||||
use Cake\Core\Exception\CakeException;
|
||||
use Cake\Core\Exception\MissingPluginException;
|
||||
use Cake\Utility\Hash;
|
||||
use Countable;
|
||||
use Generator;
|
||||
use InvalidArgumentException;
|
||||
use Iterator;
|
||||
|
||||
/**
|
||||
* Plugin Collection
|
||||
*
|
||||
* Holds onto plugin objects loaded into an application, and
|
||||
* provides methods for iterating, and finding plugins based
|
||||
* on criteria.
|
||||
*
|
||||
* This class implements the Iterator interface to allow plugins
|
||||
* to be iterated, handling the situation where a plugin's hook
|
||||
* method (usually bootstrap) loads another plugin during iteration.
|
||||
*
|
||||
* While its implementation supported nested iteration it does not
|
||||
* support using `continue` or `break` inside loops.
|
||||
*
|
||||
* @template-implements \Iterator<string, \Cake\Core\PluginInterface>
|
||||
*/
|
||||
class PluginCollection implements Iterator, Countable
|
||||
{
|
||||
/**
|
||||
* Plugin list
|
||||
*
|
||||
* @var array<string, \Cake\Core\PluginInterface>
|
||||
*/
|
||||
protected array $plugins = [];
|
||||
|
||||
/**
|
||||
* Names of plugins
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected array $names = [];
|
||||
|
||||
/**
|
||||
* Iterator position stack.
|
||||
*
|
||||
* @var array<int>
|
||||
*/
|
||||
protected array $positions = [];
|
||||
|
||||
/**
|
||||
* Loop depth
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected int $loopDepth = -1;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array<\Cake\Core\PluginInterface> $plugins The map of plugins to add to the collection.
|
||||
*/
|
||||
public function __construct(array $plugins = [])
|
||||
{
|
||||
foreach ($plugins as $plugin) {
|
||||
$this->add($plugin);
|
||||
}
|
||||
PluginConfig::loadInstallerConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add plugins from config array.
|
||||
*
|
||||
* @param array $config Configuration array. For e.g.:
|
||||
* ```
|
||||
* [
|
||||
* 'Company/TestPluginThree',
|
||||
* 'TestPlugin' => ['onlyDebug' => true, 'onlyCli' => true],
|
||||
* 'Nope' => ['optional' => true],
|
||||
* 'Named' => ['routes' => false, 'bootstrap' => false],
|
||||
* ]
|
||||
* ```
|
||||
* @return void
|
||||
*/
|
||||
public function addFromConfig(array $config): void
|
||||
{
|
||||
$notDebug = !Configure::read('debug');
|
||||
$notCli = PHP_SAPI !== 'cli';
|
||||
|
||||
/** @var array{onlyDebug?: bool, onlyCli?: bool, optional?: bool} $options */
|
||||
foreach (Hash::normalize($config, default: []) as $name => $options) {
|
||||
$onlyDebug = $options['onlyDebug'] ?? false;
|
||||
$onlyCli = $options['onlyCli'] ?? false;
|
||||
$optional = $options['optional'] ?? false;
|
||||
|
||||
if (
|
||||
($onlyDebug && $notDebug)
|
||||
|| ($onlyCli && $notCli)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$plugin = $this->create($name, $options);
|
||||
$this->add($plugin);
|
||||
} catch (MissingPluginException $e) {
|
||||
if (!$optional) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate a plugin path by looking at configuration data.
|
||||
*
|
||||
* This will use the `plugins` Configure key, and fallback to enumerating `App::path('plugins')`
|
||||
*
|
||||
* This method is not part of the official public API as plugins with
|
||||
* no plugin class are being phased out.
|
||||
*
|
||||
* @param string $name The plugin name to locate a path for.
|
||||
* @return string
|
||||
* @throws \Cake\Core\Exception\MissingPluginException when a plugin path cannot be resolved.
|
||||
* @internal
|
||||
*/
|
||||
public function findPath(string $name): string
|
||||
{
|
||||
// Ensure plugin config is loaded each time. This is necessary primarily
|
||||
// for testing because the Configure::clear() call in TestCase::tearDown()
|
||||
// wipes out all configuration including plugin paths config.
|
||||
PluginConfig::loadInstallerConfig();
|
||||
|
||||
/** @var string|null $path */
|
||||
$path = Configure::read('plugins.' . $name);
|
||||
if ($path) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
$pluginPath = str_replace('/', DIRECTORY_SEPARATOR, $name);
|
||||
$paths = App::path('plugins');
|
||||
foreach ($paths as $path) {
|
||||
if (is_dir($path . $pluginPath)) {
|
||||
return $path . $pluginPath . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
}
|
||||
|
||||
throw new MissingPluginException(['plugin' => $name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a plugin to the collection
|
||||
*
|
||||
* Plugins will be keyed by their names.
|
||||
*
|
||||
* @param \Cake\Core\PluginInterface $plugin The plugin to load.
|
||||
* @return $this
|
||||
*/
|
||||
public function add(PluginInterface $plugin)
|
||||
{
|
||||
$name = $plugin->getName();
|
||||
if (isset($this->plugins[$name])) {
|
||||
throw new CakeException(sprintf('Plugin named `%s` is already loaded', $name));
|
||||
}
|
||||
|
||||
$this->plugins[$name] = $plugin;
|
||||
$this->names = array_keys($this->plugins);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a plugin from the collection if it exists.
|
||||
*
|
||||
* @param string $name The named plugin.
|
||||
* @return $this
|
||||
*/
|
||||
public function remove(string $name)
|
||||
{
|
||||
unset($this->plugins[$name]);
|
||||
$this->names = array_keys($this->plugins);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all plugins from the collection
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
$this->plugins = [];
|
||||
$this->names = [];
|
||||
$this->positions = [];
|
||||
$this->loopDepth = -1;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the named plugin exists in the collection.
|
||||
*
|
||||
* @param string $name The named plugin.
|
||||
* @return bool
|
||||
*/
|
||||
public function has(string $name): bool
|
||||
{
|
||||
return isset($this->plugins[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the a plugin by name.
|
||||
*
|
||||
* If a plugin isn't already loaded it will be autoloaded on first access
|
||||
* and that plugins loaded this way may miss some hook methods.
|
||||
*
|
||||
* @param string $name The plugin to get.
|
||||
* @return \Cake\Core\PluginInterface The plugin.
|
||||
* @throws \Cake\Core\Exception\MissingPluginException when unknown plugins are fetched.
|
||||
*/
|
||||
public function get(string $name): PluginInterface
|
||||
{
|
||||
if ($this->has($name)) {
|
||||
return $this->plugins[$name];
|
||||
}
|
||||
|
||||
$plugin = $this->create($name);
|
||||
$this->add($plugin);
|
||||
|
||||
return $plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a plugin instance from a name/classname and configuration.
|
||||
*
|
||||
* @param string $name The plugin name or classname
|
||||
* @param array<string, mixed> $config Configuration options for the plugin.
|
||||
* @return \Cake\Core\PluginInterface
|
||||
* @throws \Cake\Core\Exception\MissingPluginException When plugin instance could not be created.
|
||||
* @throws \InvalidArgumentException When class name cannot be found or an empty name is provided.
|
||||
* @phpstan-param class-string<\Cake\Core\PluginInterface>|string $name
|
||||
*/
|
||||
public function create(string $name, array $config = []): PluginInterface
|
||||
{
|
||||
if ($name === '') {
|
||||
throw new InvalidArgumentException('Plugin name cannot be empty.');
|
||||
}
|
||||
|
||||
if (str_contains($name, '\\')) {
|
||||
if (!class_exists($name)) {
|
||||
throw new InvalidArgumentException(sprintf('Class `%s` does not exist.', $name));
|
||||
}
|
||||
|
||||
/** @var \Cake\Core\PluginInterface */
|
||||
return new $name($config);
|
||||
}
|
||||
|
||||
$config += ['name' => $name];
|
||||
$namespace = str_replace('/', '\\', $name);
|
||||
|
||||
$pos = strpos($name, '/');
|
||||
$namePart = $pos === false ? $name : substr($name, $pos + 1);
|
||||
|
||||
// Check for [Vendor/]Foo/FooPlugin class
|
||||
$className = $namespace . '\\' . $namePart . 'Plugin';
|
||||
|
||||
if (!class_exists($className)) {
|
||||
// Check for [Vendor/]Foo/Plugin class
|
||||
$className = $namespace . '\\' . 'Plugin';
|
||||
|
||||
if (class_exists($className)) {
|
||||
deprecationWarning(
|
||||
'5.3.0',
|
||||
'Loading plugins with a plugin class named `Plugin` is deprecated.'
|
||||
. " Rename the class to `{$namePart}Plugin` instead.",
|
||||
);
|
||||
} else {
|
||||
$className = BasePlugin::class;
|
||||
if (empty($config['path'])) {
|
||||
$config['path'] = $this->findPath($name);
|
||||
}
|
||||
|
||||
deprecationWarning(
|
||||
'5.3.0',
|
||||
'Loading plugins without a plugin class is deprecated.'
|
||||
. " You can create the missing class using `bin/cake bake plugin {$name} --class-only`.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/** @var class-string<\Cake\Core\PluginInterface> $className */
|
||||
return new $className($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of Countable.
|
||||
*
|
||||
* Get the number of plugins in the collection.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count(): int
|
||||
{
|
||||
return count($this->plugins);
|
||||
}
|
||||
|
||||
/**
|
||||
* Part of Iterator Interface
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function next(): void
|
||||
{
|
||||
$this->positions[$this->loopDepth]++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Part of Iterator Interface
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function key(): string
|
||||
{
|
||||
return $this->names[$this->positions[$this->loopDepth]];
|
||||
}
|
||||
|
||||
/**
|
||||
* Part of Iterator Interface
|
||||
*
|
||||
* @return \Cake\Core\PluginInterface
|
||||
*/
|
||||
public function current(): PluginInterface
|
||||
{
|
||||
$position = $this->positions[$this->loopDepth];
|
||||
$name = $this->names[$position];
|
||||
|
||||
return $this->plugins[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Part of Iterator Interface
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function rewind(): void
|
||||
{
|
||||
$this->positions[] = 0;
|
||||
$this->loopDepth += 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Part of Iterator Interface
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function valid(): bool
|
||||
{
|
||||
$valid = isset($this->names[$this->positions[$this->loopDepth]]);
|
||||
if (!$valid) {
|
||||
array_pop($this->positions);
|
||||
$this->loopDepth -= 1;
|
||||
}
|
||||
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the plugins to those with the named hook enabled.
|
||||
*
|
||||
* @param string $hook The hook to filter plugins by
|
||||
* @return \Generator<\Cake\Core\PluginInterface> A generator containing matching plugins.
|
||||
* @throws \InvalidArgumentException on invalid hooks
|
||||
*/
|
||||
public function with(string $hook): Generator
|
||||
{
|
||||
if (!in_array($hook, PluginInterface::VALID_HOOKS, true)) {
|
||||
throw new InvalidArgumentException(sprintf('The `%s` hook is not a known plugin hook.', $hook));
|
||||
}
|
||||
foreach ($this as $plugin) {
|
||||
if ($plugin->isEnabled($hook)) {
|
||||
yield $plugin;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+187
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 5.1.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core;
|
||||
|
||||
use Cake\Core\Exception\CakeException;
|
||||
use Cake\Utility\Hash;
|
||||
|
||||
/**
|
||||
* PluginConfig contains all available plugins and their config if/how they should be loaded
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class PluginConfig
|
||||
{
|
||||
/**
|
||||
* Load the path information stored in vendor/cakephp-plugins.php
|
||||
*
|
||||
* This file is generated by the cakephp/plugin-installer package and used
|
||||
* to locate plugins on the filesystem as applications can use `extra.plugin-paths`
|
||||
* in their composer.json file to move plugin outside of vendor/
|
||||
*
|
||||
* @internal
|
||||
* @return void
|
||||
*/
|
||||
public static function loadInstallerConfig(): void
|
||||
{
|
||||
if (Configure::check('plugins')) {
|
||||
return;
|
||||
}
|
||||
$vendorFile = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'cakephp-plugins.php';
|
||||
if (!is_file($vendorFile)) {
|
||||
$vendorFile = dirname(__DIR__, 4) . DIRECTORY_SEPARATOR . 'cakephp-plugins.php';
|
||||
if (!is_file($vendorFile)) {
|
||||
Configure::write(['plugins' => []]);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$config = require $vendorFile;
|
||||
Configure::write($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the config how plugins should be loaded
|
||||
*
|
||||
* @param string|null $path The absolute path to the composer.lock file to retrieve the versions from
|
||||
* @return array
|
||||
*/
|
||||
public static function getAppConfig(?string $path = null): array
|
||||
{
|
||||
self::loadInstallerConfig();
|
||||
|
||||
// phpcs:ignore
|
||||
$pluginLoadConfig = @include CONFIG . 'plugins.php';
|
||||
if (is_array($pluginLoadConfig)) {
|
||||
$pluginLoadConfig = Hash::normalize($pluginLoadConfig);
|
||||
} else {
|
||||
$pluginLoadConfig = [];
|
||||
}
|
||||
|
||||
try {
|
||||
$composerVersions = self::getVersions($path);
|
||||
} catch (CakeException) {
|
||||
$composerVersions = [];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
$availablePlugins = Configure::read('plugins', []);
|
||||
if ($availablePlugins && is_array($availablePlugins)) {
|
||||
foreach ($availablePlugins as $pluginName => $pluginPath) {
|
||||
if ($pluginLoadConfig && array_key_exists($pluginName, $pluginLoadConfig)) {
|
||||
$options = $pluginLoadConfig[$pluginName];
|
||||
$hooks = PluginInterface::VALID_HOOKS;
|
||||
$mainConfig = [
|
||||
'isLoaded' => true,
|
||||
'onlyDebug' => $options['onlyDebug'] ?? false,
|
||||
'onlyCli' => $options['onlyCli'] ?? false,
|
||||
'optional' => $options['optional'] ?? false,
|
||||
];
|
||||
foreach ($hooks as $hook) {
|
||||
$mainConfig[$hook] = $options[$hook] ?? true;
|
||||
}
|
||||
$result[$pluginName] = $mainConfig;
|
||||
} else {
|
||||
$result[$pluginName]['isLoaded'] = false;
|
||||
}
|
||||
|
||||
try {
|
||||
$packageName = self::getPackageNameFromPath($pluginPath);
|
||||
$result[$pluginName]['packagePath'] = $pluginPath;
|
||||
$result[$pluginName]['package'] = $packageName;
|
||||
} catch (CakeException) {
|
||||
$packageName = null;
|
||||
}
|
||||
if ($composerVersions && $packageName) {
|
||||
if (array_key_exists($packageName, $composerVersions['packages'])) {
|
||||
$result[$pluginName]['version'] = $composerVersions['packages'][$packageName];
|
||||
$result[$pluginName]['isDevPackage'] = false;
|
||||
} elseif (array_key_exists($packageName, $composerVersions['devPackages'])) {
|
||||
$result[$pluginName]['version'] = $composerVersions['devPackages'][$packageName];
|
||||
$result[$pluginName]['isDevPackage'] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$diff = array_diff(array_keys($pluginLoadConfig), array_keys($availablePlugins));
|
||||
foreach ($diff as $unknownPlugin) {
|
||||
$result[$unknownPlugin]['isLoaded'] = false;
|
||||
$result[$unknownPlugin]['isUnknown'] = true;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $path The absolute path to the composer.lock file to retrieve the versions from
|
||||
* @return array
|
||||
*/
|
||||
public static function getVersions(?string $path = null): array
|
||||
{
|
||||
$lockFilePath = $path ?? ROOT . DIRECTORY_SEPARATOR . 'composer.lock';
|
||||
if (!file_exists($lockFilePath)) {
|
||||
throw new CakeException(sprintf('composer.lock does not exist in %s', $lockFilePath));
|
||||
}
|
||||
$lockFile = file_get_contents($lockFilePath);
|
||||
if ($lockFile === false) {
|
||||
throw new CakeException(sprintf('Could not read composer.lock: %s', $lockFilePath));
|
||||
}
|
||||
$lockFileJson = json_decode($lockFile, true);
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
throw new CakeException(sprintf(
|
||||
'Error parsing composer.lock: %s',
|
||||
json_last_error_msg(),
|
||||
));
|
||||
}
|
||||
|
||||
$packages = Hash::combine($lockFileJson['packages'], '{n}.name', '{n}.version');
|
||||
$devPackages = Hash::combine($lockFileJson['packages-dev'], '{n}.name', '{n}.version');
|
||||
|
||||
return [
|
||||
'packages' => $packages,
|
||||
'devPackages' => $devPackages,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
protected static function getPackageNameFromPath(string $path): string
|
||||
{
|
||||
$jsonPath = $path . DS . 'composer.json';
|
||||
if (!file_exists($jsonPath)) {
|
||||
throw new CakeException(sprintf('composer.json does not exist in %s', $jsonPath));
|
||||
}
|
||||
$jsonString = file_get_contents($jsonPath);
|
||||
if ($jsonString === false) {
|
||||
throw new CakeException(sprintf('Could not read composer.json: %s', $jsonPath));
|
||||
}
|
||||
$json = json_decode($jsonString, true);
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
throw new CakeException(sprintf(
|
||||
'Error parsing %ss: %s',
|
||||
$jsonPath,
|
||||
json_last_error_msg(),
|
||||
));
|
||||
}
|
||||
|
||||
return $json['name'];
|
||||
}
|
||||
}
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright 2005-2011, Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 3.6.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core;
|
||||
|
||||
use Cake\Console\CommandCollection;
|
||||
use Cake\Http\MiddlewareQueue;
|
||||
use Cake\Routing\RouteBuilder;
|
||||
|
||||
/**
|
||||
* Plugin Interface
|
||||
*
|
||||
* @method \Cake\Event\EventManagerInterface events(\Cake\Event\EventManagerInterface $eventManager)
|
||||
*/
|
||||
interface PluginInterface
|
||||
{
|
||||
/**
|
||||
* List of valid hooks.
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
public const VALID_HOOKS = ['bootstrap', 'console', 'middleware', 'routes', 'services', 'events'];
|
||||
|
||||
/**
|
||||
* Get the name of this plugin.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string;
|
||||
|
||||
/**
|
||||
* Get the filesystem path to this plugin
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPath(): string;
|
||||
|
||||
/**
|
||||
* Get the filesystem path to configuration for this plugin
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getConfigPath(): string;
|
||||
|
||||
/**
|
||||
* Get the filesystem path to configuration for this plugin
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getClassPath(): string;
|
||||
|
||||
/**
|
||||
* Get the filesystem path to templates for this plugin
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTemplatePath(): string;
|
||||
|
||||
/**
|
||||
* Load all the application configuration and bootstrap logic.
|
||||
*
|
||||
* The default implementation of this method will include the `config/bootstrap.php` in the plugin if it exist. You
|
||||
* can override this method to replace that behavior.
|
||||
*
|
||||
* The host application is provided as an argument. This allows you to load additional
|
||||
* plugin dependencies, or attach events.
|
||||
*
|
||||
* @param \Cake\Core\PluginApplicationInterface $app The host application
|
||||
* @return void
|
||||
*/
|
||||
public function bootstrap(PluginApplicationInterface $app): void;
|
||||
|
||||
/**
|
||||
* Add console commands for the plugin.
|
||||
*
|
||||
* @param \Cake\Console\CommandCollection $commands The command collection to update
|
||||
* @return \Cake\Console\CommandCollection
|
||||
*/
|
||||
public function console(CommandCollection $commands): CommandCollection;
|
||||
|
||||
/**
|
||||
* Add middleware for the plugin.
|
||||
*
|
||||
* @param \Cake\Http\MiddlewareQueue $middlewareQueue The middleware queue to update.
|
||||
* @return \Cake\Http\MiddlewareQueue
|
||||
*/
|
||||
public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue;
|
||||
|
||||
/**
|
||||
* Add routes for the plugin.
|
||||
*
|
||||
* The default implementation of this method will include the `config/routes.php` in the plugin if it exists. You
|
||||
* can override this method to replace that behavior.
|
||||
*
|
||||
* @param \Cake\Routing\RouteBuilder $routes The route builder to update.
|
||||
* @return void
|
||||
*/
|
||||
public function routes(RouteBuilder $routes): void;
|
||||
|
||||
/**
|
||||
* Register plugin services to the application's container
|
||||
*
|
||||
* @param \Cake\Core\ContainerInterface $container Container instance.
|
||||
* @return void
|
||||
*/
|
||||
public function services(ContainerInterface $container): void;
|
||||
|
||||
/**
|
||||
* Disables the named hook
|
||||
*
|
||||
* @param string $hook The hook to disable
|
||||
* @return $this
|
||||
*/
|
||||
public function disable(string $hook);
|
||||
|
||||
/**
|
||||
* Enables the named hook
|
||||
*
|
||||
* @param string $hook The hook to disable
|
||||
* @return $this
|
||||
*/
|
||||
public function enable(string $hook);
|
||||
|
||||
/**
|
||||
* Check if the named hook is enabled
|
||||
*
|
||||
* @param string $hook The hook to check
|
||||
* @return bool
|
||||
*/
|
||||
public function isEnabled(string $hook): bool;
|
||||
}
|
||||
Vendored
+37
@@ -0,0 +1,37 @@
|
||||
[](https://packagist.org/packages/cakephp/core)
|
||||
[](LICENSE.txt)
|
||||
|
||||
# CakePHP Core Classes
|
||||
|
||||
A set of classes used for configuration files reading and storing.
|
||||
This repository contains the classes that are used as glue for creating the CakePHP framework.
|
||||
|
||||
## Usage
|
||||
|
||||
You can use the `Configure` class to store arbitrary configuration data:
|
||||
|
||||
```php
|
||||
use Cake\Core\Configure;
|
||||
use Cake\Core\Configure\Engine\PhpConfig;
|
||||
|
||||
Configure::write('Company.name','Pizza, Inc.');
|
||||
Configure::read('Company.name'); // Returns: 'Pizza, Inc.'
|
||||
```
|
||||
|
||||
It also possible to load configuration from external files:
|
||||
|
||||
```php
|
||||
Configure::config('default', new PhpConfig('/path/to/config/folder'));
|
||||
Configure::load('app', 'default', false);
|
||||
Configure::load('other_config', 'default');
|
||||
```
|
||||
|
||||
And write the configuration back into files:
|
||||
|
||||
```php
|
||||
Configure::dump('my_config', 'default');
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
Please make sure you check the [official documentation](https://book.cakephp.org/5/en/development/configuration.html)
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 3.6.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core\Retry;
|
||||
|
||||
use Closure;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Allows any action to be retried in case of an exception.
|
||||
*
|
||||
* This class can be parametrized with a strategy, which will be followed
|
||||
* to determine whether the action should be retried.
|
||||
*/
|
||||
class CommandRetry
|
||||
{
|
||||
/**
|
||||
* The strategy to follow should the executed action fail.
|
||||
*
|
||||
* @var \Cake\Core\Retry\RetryStrategyInterface
|
||||
*/
|
||||
protected RetryStrategyInterface $strategy;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected int $maxRetries;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected int $numRetries;
|
||||
|
||||
/**
|
||||
* Creates the CommandRetry object with the given strategy and retry count
|
||||
*
|
||||
* @param \Cake\Core\Retry\RetryStrategyInterface $strategy The strategy to follow should the action fail
|
||||
* @param int $maxRetries The maximum number of retry attempts allowed
|
||||
*/
|
||||
public function __construct(RetryStrategyInterface $strategy, int $maxRetries = 1)
|
||||
{
|
||||
$this->strategy = $strategy;
|
||||
$this->maxRetries = $maxRetries;
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of retries to perform in case of failure
|
||||
*
|
||||
* @param \Closure $action Callback to run for each attempt
|
||||
* @return mixed The return value of the passed action callable
|
||||
* @throws \Exception Throws exception from last failure
|
||||
*/
|
||||
public function run(Closure $action): mixed
|
||||
{
|
||||
$this->numRetries = 0;
|
||||
while (true) {
|
||||
try {
|
||||
return $action();
|
||||
} catch (Exception $e) {
|
||||
if (
|
||||
$this->numRetries < $this->maxRetries &&
|
||||
$this->strategy->shouldRetry($e, $this->numRetries)
|
||||
) {
|
||||
$this->numRetries++;
|
||||
continue;
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last number of retry attempts.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getRetries(): int
|
||||
{
|
||||
return $this->numRetries;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 3.6.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core\Retry;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Used to instruct a CommandRetry object on whether a retry
|
||||
* for an action should be performed
|
||||
*/
|
||||
interface RetryStrategyInterface
|
||||
{
|
||||
/**
|
||||
* Returns true if the action can be retried, false otherwise.
|
||||
*
|
||||
* @param \Exception $exception The exception that caused the action to fail
|
||||
* @param int $retryCount The number of times action has been retried
|
||||
* @return bool Whether it is OK to retry the action
|
||||
*/
|
||||
public function shouldRetry(Exception $exception, int $retryCount): bool;
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 4.2.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core;
|
||||
|
||||
/**
|
||||
* Read-only wrapper for configuration data
|
||||
*
|
||||
* Intended for use with {@link \Cake\Core\Container} as
|
||||
* a typehintable way for services to have application
|
||||
* configuration injected as arrays cannot be typehinted.
|
||||
*/
|
||||
class ServiceConfig
|
||||
{
|
||||
/**
|
||||
* Read a configuration key
|
||||
*
|
||||
* @param string $path The path to read.
|
||||
* @param mixed $default The default value to use if $path does not exist.
|
||||
* @return mixed The configuration data or $default value.
|
||||
*/
|
||||
public function get(string $path, mixed $default = null): mixed
|
||||
{
|
||||
return Configure::read($path, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if $path exists and has a non-null value.
|
||||
*
|
||||
* @param string $path The path to check.
|
||||
* @return bool True if the configuration data exists.
|
||||
*/
|
||||
public function has(string $path): bool
|
||||
{
|
||||
return Configure::check($path);
|
||||
}
|
||||
}
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 4.2.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core;
|
||||
|
||||
use League\Container\DefinitionContainerInterface;
|
||||
use League\Container\ServiceProvider\AbstractServiceProvider;
|
||||
use League\Container\ServiceProvider\BootableServiceProviderInterface;
|
||||
use LogicException;
|
||||
|
||||
/**
|
||||
* Container ServiceProvider
|
||||
*
|
||||
* Service provider bundle related services together helping
|
||||
* to organize your application's dependencies. They also help
|
||||
* improve performance of applications with many services by
|
||||
* allowing service registration to be deferred until services are needed.
|
||||
*/
|
||||
abstract class ServiceProvider extends AbstractServiceProvider implements BootableServiceProviderInterface
|
||||
{
|
||||
/**
|
||||
* List of ids of services this provider provides.
|
||||
*
|
||||
* @var array<string>
|
||||
* @see ServiceProvider::provides()
|
||||
*/
|
||||
protected array $provides = [];
|
||||
|
||||
/**
|
||||
* Get the container.
|
||||
*
|
||||
* @return \Cake\Core\ContainerInterface
|
||||
*/
|
||||
public function getContainer(): DefinitionContainerInterface
|
||||
{
|
||||
$container = parent::getContainer();
|
||||
|
||||
assert(
|
||||
$container instanceof ContainerInterface,
|
||||
sprintf(
|
||||
'Unexpected container type. Expected `%s` got `%s` instead.',
|
||||
ContainerInterface::class,
|
||||
get_debug_type($container),
|
||||
),
|
||||
);
|
||||
|
||||
return $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate to the bootstrap() method
|
||||
*
|
||||
* This method wraps the league/container function so users
|
||||
* only need to use the CakePHP bootstrap() interface.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
$this->bootstrap($this->getContainer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap hook for ServiceProviders
|
||||
*
|
||||
* This hook should be implemented if your service provider
|
||||
* needs to register additional service providers, load configuration
|
||||
* files or do any other work when the service provider is added to the
|
||||
* container.
|
||||
*
|
||||
* @param \Cake\Core\ContainerInterface $container The container to add services to.
|
||||
* @return void
|
||||
*/
|
||||
public function bootstrap(ContainerInterface $container): void
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the abstract services() method.
|
||||
*
|
||||
* This method primarily exists as a shim between the interface
|
||||
* that league/container has and the one we want to offer in CakePHP.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
$this->services($this->getContainer());
|
||||
}
|
||||
|
||||
/**
|
||||
* The provides method is a way to let the container know that a service
|
||||
* is provided by this service provider.
|
||||
*
|
||||
* Every service registered via this service provider must have an
|
||||
* alias added to this array or it will be ignored.
|
||||
*
|
||||
* @param string $id Identifier.
|
||||
* @return bool
|
||||
*/
|
||||
public function provides(string $id): bool
|
||||
{
|
||||
if (!$this->provides) {
|
||||
throw new LogicException(
|
||||
'The property `$provides` should contain a list with service ids for this service provider',
|
||||
);
|
||||
}
|
||||
|
||||
return in_array($id, $this->provides, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the services in a provider.
|
||||
*
|
||||
* All services registered in this method should also be included in the $provides
|
||||
* property so that services can be located.
|
||||
*
|
||||
* @param \Cake\Core\ContainerInterface $container The container to add services to.
|
||||
* @return void
|
||||
*/
|
||||
abstract public function services(ContainerInterface $container): void;
|
||||
}
|
||||
+333
@@ -0,0 +1,333 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 3.0.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core;
|
||||
|
||||
use BadMethodCallException;
|
||||
use InvalidArgumentException;
|
||||
use LogicException;
|
||||
|
||||
/**
|
||||
* A trait that provides a set of static methods to manage configuration
|
||||
* for classes that provide an adapter facade or need to have sets of
|
||||
* configuration data registered and manipulated.
|
||||
*
|
||||
* Implementing objects are expected to declare a static `$_dsnClassMap` property.
|
||||
*/
|
||||
trait StaticConfigTrait
|
||||
{
|
||||
/**
|
||||
* Configuration sets.
|
||||
*
|
||||
* @var array<string|int, array<string, mixed>>
|
||||
*/
|
||||
protected static array $_config = [];
|
||||
|
||||
/**
|
||||
* This method can be used to define configuration adapters for an application.
|
||||
*
|
||||
* To change an adapter's configuration at runtime, first drop the adapter and then
|
||||
* reconfigure it.
|
||||
*
|
||||
* Adapters will not be constructed until the first operation is done.
|
||||
*
|
||||
* ### Usage
|
||||
*
|
||||
* Assuming that the class' name is `Cache` the following scenarios
|
||||
* are supported:
|
||||
*
|
||||
* Setting a cache engine up.
|
||||
*
|
||||
* ```
|
||||
* Cache::setConfig('default', $settings);
|
||||
* ```
|
||||
*
|
||||
* Injecting a constructed adapter in:
|
||||
*
|
||||
* ```
|
||||
* Cache::setConfig('default', $instance);
|
||||
* ```
|
||||
*
|
||||
* Configure multiple adapters at once:
|
||||
*
|
||||
* ```
|
||||
* Cache::setConfig($arrayOfConfig);
|
||||
* ```
|
||||
*
|
||||
* @param array<string, mixed>|string $key The name of the configuration, or an array of multiple configs.
|
||||
* @param mixed $config Configuration value. Generally an array of name => configuration data for adapter.
|
||||
* @throws \BadMethodCallException When trying to modify an existing config.
|
||||
* @throws \LogicException When trying to store an invalid structured config array.
|
||||
* @return void
|
||||
*/
|
||||
public static function setConfig(array|string $key, mixed $config = null): void
|
||||
{
|
||||
if ($config === null) {
|
||||
if (!is_array($key)) {
|
||||
throw new LogicException('If config is null, key must be an array.');
|
||||
}
|
||||
foreach ($key as $name => $settings) {
|
||||
static::setConfig((string)$name, $settings);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
if (!is_string($key)) {
|
||||
throw new LogicException('If config is not null, key must be a string.');
|
||||
}
|
||||
|
||||
if (isset(static::$_config[$key])) {
|
||||
throw new BadMethodCallException(sprintf('Cannot reconfigure existing key `%s`.', $key));
|
||||
}
|
||||
|
||||
if (is_object($config)) {
|
||||
$config = ['className' => $config];
|
||||
}
|
||||
|
||||
if (is_array($config) && isset($config['url'])) {
|
||||
$parsed = static::parseDsn($config['url']);
|
||||
unset($config['url']);
|
||||
$config = $parsed + $config;
|
||||
}
|
||||
|
||||
if (isset($config['engine']) && empty($config['className'])) {
|
||||
$config['className'] = $config['engine'];
|
||||
unset($config['engine']);
|
||||
}
|
||||
|
||||
static::$_config[$key] = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads existing configuration.
|
||||
*
|
||||
* @param string $key The name of the configuration.
|
||||
* @return mixed|null Configuration data at the named key or null if the key does not exist.
|
||||
*/
|
||||
public static function getConfig(string $key): mixed
|
||||
{
|
||||
return static::$_config[$key] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads existing configuration for a specific key.
|
||||
*
|
||||
* The config value for this key must exist, it can never be null.
|
||||
*
|
||||
* @param string $key The name of the configuration.
|
||||
* @return mixed Configuration data at the named key.
|
||||
* @throws \InvalidArgumentException If value does not exist.
|
||||
*/
|
||||
public static function getConfigOrFail(string $key): mixed
|
||||
{
|
||||
if (!isset(static::$_config[$key])) {
|
||||
throw new InvalidArgumentException(sprintf('Expected configuration `%s` not found.', $key));
|
||||
}
|
||||
|
||||
return static::$_config[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops a constructed adapter.
|
||||
*
|
||||
* If you wish to modify an existing configuration, you should drop it,
|
||||
* change configuration and then re-add it.
|
||||
*
|
||||
* If the implementing objects supports a `$_registry` object the named configuration
|
||||
* will also be unloaded from the registry.
|
||||
*
|
||||
* @param string $config An existing configuration you wish to remove.
|
||||
* @return bool Success of the removal, returns false when the config does not exist.
|
||||
*/
|
||||
public static function drop(string $config): bool
|
||||
{
|
||||
if (!isset(static::$_config[$config])) {
|
||||
return false;
|
||||
}
|
||||
/** @phpstan-ignore-next-line */
|
||||
if (isset(static::$_registry)) {
|
||||
static::$_registry->unload($config);
|
||||
}
|
||||
unset(static::$_config[$config]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing the named configurations
|
||||
*
|
||||
* @return array<string> Array of configurations.
|
||||
*/
|
||||
public static function configured(): array
|
||||
{
|
||||
$configurations = array_keys(static::$_config);
|
||||
|
||||
return array_map(function (int|string $key) {
|
||||
return (string)$key;
|
||||
}, $configurations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a DSN into a valid connection configuration
|
||||
*
|
||||
* This method allows setting a DSN using formatting similar to that used by PEAR::DB.
|
||||
* The following is an example of its usage:
|
||||
*
|
||||
* ```
|
||||
* $dsn = 'mysql://user:pass@localhost/database?';
|
||||
* $config = ConnectionManager::parseDsn($dsn);
|
||||
*
|
||||
* $dsn = 'Cake\Log\Engine\FileLog://?types=notice,info,debug&file=debug&path=LOGS';
|
||||
* $config = Log::parseDsn($dsn);
|
||||
*
|
||||
* $dsn = 'smtp://user:secret@localhost:25?timeout=30&client=null&tls=null';
|
||||
* $config = Email::parseDsn($dsn);
|
||||
*
|
||||
* $dsn = 'file:///?className=\My\Cache\Engine\FileEngine';
|
||||
* $config = Cache::parseDsn($dsn);
|
||||
*
|
||||
* $dsn = 'File://?prefix=myapp_cake_translations_&serialize=true&duration=+2 minutes&path=/tmp/persistent/';
|
||||
* $config = Cache::parseDsn($dsn);
|
||||
* ```
|
||||
*
|
||||
* For all classes, the value of `scheme` is set as the value of both the `className`
|
||||
* unless they have been otherwise specified.
|
||||
*
|
||||
* Note that querystring arguments are also parsed and set as values in the returned configuration.
|
||||
*
|
||||
* @param string $dsn The DSN string to convert to a configuration array
|
||||
* @return array<int|string, array|bool|string|null> The configuration array to be stored after parsing the DSN
|
||||
* @throws \InvalidArgumentException If not passed a string, or passed an invalid string
|
||||
*/
|
||||
public static function parseDsn(string $dsn): array
|
||||
{
|
||||
if (!$dsn) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$pattern = <<<'REGEXP'
|
||||
{
|
||||
^
|
||||
(?P<_scheme>
|
||||
(?P<scheme>[\w\\\\]+)://
|
||||
)
|
||||
(?P<_username>
|
||||
(?P<username>.*?)
|
||||
(?P<_password>
|
||||
:(?P<password>.*?)
|
||||
)?
|
||||
@
|
||||
)?
|
||||
(?P<_host>
|
||||
(?P<host>\[[^]]+]|[^?#/:@]+)
|
||||
(?P<_port>
|
||||
:(?P<port>\d+)
|
||||
)?
|
||||
)?
|
||||
(?P<_path>
|
||||
(?P<path>/[^?#]*)
|
||||
)?
|
||||
(?P<_query>
|
||||
\?(?P<query>[^#]*)
|
||||
)?
|
||||
(?P<_fragment>
|
||||
\#(?P<fragment>.*)
|
||||
)?
|
||||
$
|
||||
}x
|
||||
REGEXP;
|
||||
|
||||
preg_match($pattern, $dsn, $parsed);
|
||||
|
||||
if (!$parsed) {
|
||||
throw new InvalidArgumentException(sprintf('The DSN string `%s` could not be parsed.', $dsn));
|
||||
}
|
||||
|
||||
$exists = [];
|
||||
/**
|
||||
* @var string|int $k
|
||||
*/
|
||||
foreach ($parsed as $k => $v) {
|
||||
if (is_int($k)) {
|
||||
unset($parsed[$k]);
|
||||
} elseif (str_starts_with($k, '_')) {
|
||||
$exists[substr($k, 1)] = ($v !== '');
|
||||
unset($parsed[$k]);
|
||||
} elseif ($v === '' && !$exists[$k]) {
|
||||
unset($parsed[$k]);
|
||||
}
|
||||
}
|
||||
|
||||
$query = '';
|
||||
|
||||
if (isset($parsed['query'])) {
|
||||
$query = $parsed['query'];
|
||||
unset($parsed['query']);
|
||||
}
|
||||
|
||||
parse_str($query, $queryArgs);
|
||||
|
||||
/**
|
||||
* @var string $key
|
||||
*/
|
||||
foreach ($queryArgs as $key => $value) {
|
||||
if ($value === 'true') {
|
||||
$queryArgs[$key] = true;
|
||||
} elseif ($value === 'false') {
|
||||
$queryArgs[$key] = false;
|
||||
} elseif ($value === 'null') {
|
||||
$queryArgs[$key] = null;
|
||||
}
|
||||
}
|
||||
|
||||
$parsed = $queryArgs + $parsed;
|
||||
|
||||
if (empty($parsed['className'])) {
|
||||
$classMap = static::getDsnClassMap();
|
||||
|
||||
/** @var string $scheme */
|
||||
$scheme = $parsed['scheme'];
|
||||
$parsed['className'] = $scheme;
|
||||
if (isset($classMap[$scheme])) {
|
||||
$parsed['className'] = $classMap[$scheme];
|
||||
}
|
||||
}
|
||||
|
||||
return $parsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the DSN class map for this class.
|
||||
*
|
||||
* @param array<string, string> $map Additions/edits to the class map to apply.
|
||||
* @return void
|
||||
* @phpstan-param array<string, class-string> $map
|
||||
*/
|
||||
public static function setDsnClassMap(array $map): void
|
||||
{
|
||||
static::$_dsnClassMap = $map + static::$_dsnClassMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the DSN class map for this class.
|
||||
*
|
||||
* @return array<string, class-string>
|
||||
*/
|
||||
public static function getDsnClassMap(): array
|
||||
{
|
||||
return static::$_dsnClassMap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @since 4.2.0
|
||||
* @license https://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core\TestSuite;
|
||||
|
||||
use Cake\Core\Configure;
|
||||
use Cake\Core\ConsoleApplicationInterface;
|
||||
use Cake\Core\ContainerInterface;
|
||||
use Cake\Core\HttpApplicationInterface;
|
||||
use Cake\Event\EventInterface;
|
||||
use Cake\Routing\Router;
|
||||
use Closure;
|
||||
use League\Container\Exception\NotFoundException;
|
||||
use LogicException;
|
||||
use PHPUnit\Framework\Attributes\After;
|
||||
|
||||
/**
|
||||
* A set of methods used for defining container services
|
||||
* in test cases.
|
||||
*
|
||||
* This trait leverages the `Application.buildContainer` event
|
||||
* to inject the mocked services into the container that the
|
||||
* application uses.
|
||||
*/
|
||||
trait ContainerStubTrait
|
||||
{
|
||||
/**
|
||||
* The customized application class name.
|
||||
*
|
||||
* @phpstan-var class-string<\Cake\Core\HttpApplicationInterface>|class-string<\Cake\Core\ConsoleApplicationInterface>|null
|
||||
* @var string|null
|
||||
*/
|
||||
protected ?string $_appClass = null;
|
||||
|
||||
/**
|
||||
* The customized application constructor arguments.
|
||||
*
|
||||
* @var array|null
|
||||
*/
|
||||
protected ?array $_appArgs = null;
|
||||
|
||||
/**
|
||||
* The collection of container services.
|
||||
*
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
private array $containerServices = [];
|
||||
|
||||
/**
|
||||
* Configure the application class to use in integration tests.
|
||||
*
|
||||
* @param string $class The application class name.
|
||||
* @param array|null $constructorArgs The constructor arguments for your application class.
|
||||
* @return void
|
||||
* @phpstan-param class-string<\Cake\Core\HttpApplicationInterface>|class-string<\Cake\Core\ConsoleApplicationInterface> $class
|
||||
*/
|
||||
public function configApplication(string $class, ?array $constructorArgs): void
|
||||
{
|
||||
$this->_appClass = $class;
|
||||
$this->_appArgs = $constructorArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an application instance.
|
||||
*
|
||||
* Uses the configuration set in `configApplication()`.
|
||||
*
|
||||
* @return \Cake\Core\HttpApplicationInterface|\Cake\Core\ConsoleApplicationInterface
|
||||
*/
|
||||
protected function createApp(): HttpApplicationInterface|ConsoleApplicationInterface
|
||||
{
|
||||
if (class_exists(Router::class)) {
|
||||
Router::resetRoutes();
|
||||
}
|
||||
|
||||
if ($this->_appClass) {
|
||||
$appClass = $this->_appClass;
|
||||
} else {
|
||||
/** @var class-string<\Cake\Http\BaseApplication> $appClass */
|
||||
$appClass = Configure::read('App.namespace') . '\Application';
|
||||
}
|
||||
if (!class_exists($appClass)) {
|
||||
throw new LogicException(sprintf('Cannot load `%s` for use in integration testing.', $appClass));
|
||||
}
|
||||
$appArgs = $this->_appArgs ?: [CONFIG];
|
||||
|
||||
$app = new $appClass(...$appArgs);
|
||||
if ($this->containerServices && method_exists($app, 'getEventManager')) {
|
||||
$app->getEventManager()->on('Application.buildContainer', [$this, 'modifyContainer']);
|
||||
}
|
||||
|
||||
foreach ($this->appPluginsToLoad as $pluginName => $config) {
|
||||
if (is_array($config)) {
|
||||
$app->addPlugin($pluginName, $config);
|
||||
} else {
|
||||
$app->addPlugin($config);
|
||||
}
|
||||
}
|
||||
|
||||
return $app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a mocked service to the container.
|
||||
*
|
||||
* When the container is created the provided classname
|
||||
* will be mapped to the factory function. The factory
|
||||
* function will be used to create mocked services.
|
||||
*
|
||||
* @param string $class The class or interface you want to define.
|
||||
* @param \Closure $factory The factory function for mocked services.
|
||||
* @return $this
|
||||
*/
|
||||
public function mockService(string $class, Closure $factory)
|
||||
{
|
||||
$this->containerServices[$class] = $factory;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a mocked service to the container.
|
||||
*
|
||||
* @param string $class The class or interface you want to remove.
|
||||
* @return $this
|
||||
*/
|
||||
public function removeMockService(string $class)
|
||||
{
|
||||
unset($this->containerServices[$class]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the application's container with one containing mocks.
|
||||
*
|
||||
* If any mocked services are defined, the application's container
|
||||
* will be replaced with one containing mocks. The original
|
||||
* container will be set as a delegate to the mock container.
|
||||
*
|
||||
* @param \Cake\Event\EventInterface $event The event
|
||||
* @param \Cake\Core\ContainerInterface $container The container to wrap.
|
||||
* @return void
|
||||
*/
|
||||
public function modifyContainer(EventInterface $event, ContainerInterface $container): void
|
||||
{
|
||||
if (!$this->containerServices) {
|
||||
return;
|
||||
}
|
||||
foreach ($this->containerServices as $key => $factory) {
|
||||
if ($container->has($key)) {
|
||||
try {
|
||||
$container->extend($key)->setConcrete($factory);
|
||||
} catch (NotFoundException) {
|
||||
$container->add($key, $factory);
|
||||
}
|
||||
} else {
|
||||
$container->add($key, $factory);
|
||||
}
|
||||
}
|
||||
|
||||
$event->setResult($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears any mocks that were defined and cleans
|
||||
* up application class configuration.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[After]
|
||||
public function cleanupContainer(): void
|
||||
{
|
||||
$this->_appArgs = null;
|
||||
$this->_appClass = null;
|
||||
$this->containerServices = [];
|
||||
}
|
||||
}
|
||||
|
||||
// phpcs:disable
|
||||
class_alias(
|
||||
'Cake\Core\TestSuite\ContainerStubTrait',
|
||||
'Cake\TestSuite\ContainerStubTrait'
|
||||
);
|
||||
// phpcs:enable
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"name": "cakephp/core",
|
||||
"description": "CakePHP Framework Core classes",
|
||||
"type": "library",
|
||||
"keywords": [
|
||||
"cakephp",
|
||||
"framework",
|
||||
"core"
|
||||
],
|
||||
"homepage": "https://cakephp.org",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "CakePHP Community",
|
||||
"homepage": "https://github.com/cakephp/core/graphs/contributors"
|
||||
}
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/cakephp/cakephp/issues",
|
||||
"forum": "https://stackoverflow.com/tags/cakephp",
|
||||
"irc": "irc://irc.freenode.org/cakephp",
|
||||
"source": "https://github.com/cakephp/core"
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.2",
|
||||
"cakephp/utility": "^5.3.0",
|
||||
"league/container": "^5.1",
|
||||
"psr/container": "^1.1 || ^2.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Cake\\Core\\": "."
|
||||
},
|
||||
"files": [
|
||||
"functions.php"
|
||||
]
|
||||
},
|
||||
"provide": {
|
||||
"psr/container-implementation": "^2.0"
|
||||
},
|
||||
"suggest": {
|
||||
"cakephp/event": "To use PluginApplicationInterface or plugin applications.",
|
||||
"cakephp/cache": "To use Configure::store() and restore().",
|
||||
"league/container": "To use Container and ServiceProvider classes"
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-5.next": "5.3.x-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
+539
@@ -0,0 +1,539 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 3.0.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Cake\Core;
|
||||
|
||||
use JsonException;
|
||||
use Stringable;
|
||||
|
||||
if (!defined('DS')) {
|
||||
/**
|
||||
* Defines DS as short form of DIRECTORY_SEPARATOR.
|
||||
*/
|
||||
define('DS', DIRECTORY_SEPARATOR);
|
||||
}
|
||||
|
||||
if (!defined('CAKE_DATE_RFC7231')) {
|
||||
define('CAKE_DATE_RFC7231', 'D, d M Y H:i:s \G\M\T');
|
||||
}
|
||||
|
||||
if (!function_exists('Cake\Core\pathCombine')) {
|
||||
/**
|
||||
* Combines parts with a forward-slash `/`.
|
||||
*
|
||||
* Skips adding a forward-slash if either `/` or `\` already exists.
|
||||
*
|
||||
* @param array<string> $parts
|
||||
* @param bool|null $trailing Determines how trailing slashes are handled
|
||||
* - If true, ensures a trailing forward-slash is added if one doesn't exist
|
||||
* - If false, ensures any trailing slash is removed
|
||||
* - if null, ignores trailing slashes
|
||||
* @return string
|
||||
*/
|
||||
function pathCombine(array $parts, ?bool $trailing = null): string
|
||||
{
|
||||
$numParts = count($parts);
|
||||
if ($numParts === 0) {
|
||||
if ($trailing === true) {
|
||||
return '/';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
$path = $parts[0];
|
||||
for ($i = 1; $i < $numParts; ++$i) {
|
||||
$part = $parts[$i];
|
||||
if ($part === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($path[-1] === '/' || $path[-1] === '\\') {
|
||||
if ($part[0] === '/' || $part[0] === '\\') {
|
||||
$path .= substr($part, 1);
|
||||
} else {
|
||||
$path .= $part;
|
||||
}
|
||||
} elseif ($part[0] === '/' || $part[0] === '\\') {
|
||||
$path .= $part;
|
||||
} else {
|
||||
$path .= '/' . $part;
|
||||
}
|
||||
}
|
||||
|
||||
if ($trailing === true) {
|
||||
if ($path === '' || ($path[-1] !== '/' && $path[-1] !== '\\')) {
|
||||
$path .= '/';
|
||||
}
|
||||
} elseif ($trailing === false) {
|
||||
if ($path !== '' && ($path[-1] === '/' || $path[-1] === '\\')) {
|
||||
$path = substr($path, 0, -1);
|
||||
}
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('Cake\Core\h')) {
|
||||
/**
|
||||
* Convenience method for htmlspecialchars.
|
||||
*
|
||||
* @param mixed $text Text to wrap through htmlspecialchars. Also works with arrays, and objects.
|
||||
* Arrays will be mapped and have all their elements escaped. Objects will be string cast if they
|
||||
* implement a `__toString` method. Otherwise, the class name will be used.
|
||||
* Other scalar types will be returned unchanged.
|
||||
* @param bool $double Encode existing html entities.
|
||||
* @param string|null $charset Character set to use when escaping.
|
||||
* Defaults to config value in `mb_internal_encoding()` or 'UTF-8'.
|
||||
* @return mixed Wrapped text.
|
||||
* @link https://book.cakephp.org/5/en/core-libraries/global-constants-and-functions.html#h
|
||||
*/
|
||||
function h(mixed $text, bool $double = true, ?string $charset = null): mixed
|
||||
{
|
||||
if (is_string($text)) {
|
||||
//optimize for strings
|
||||
} elseif (is_array($text)) {
|
||||
$texts = [];
|
||||
foreach ($text as $k => $t) {
|
||||
$texts[$k] = h($t, $double, $charset);
|
||||
}
|
||||
|
||||
return $texts;
|
||||
} elseif (is_object($text)) {
|
||||
if ($text instanceof Stringable) {
|
||||
$text = (string)$text;
|
||||
} else {
|
||||
$text = '(object)' . $text::class;
|
||||
}
|
||||
} elseif ($text === null || is_scalar($text)) {
|
||||
return $text;
|
||||
}
|
||||
|
||||
static $defaultCharset = false;
|
||||
if ($defaultCharset === false) {
|
||||
$defaultCharset = mb_internal_encoding() ?: 'UTF-8';
|
||||
}
|
||||
|
||||
return htmlspecialchars($text, ENT_QUOTES | ENT_SUBSTITUTE, $charset ?: $defaultCharset, $double);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('Cake\Core\pluginSplit')) {
|
||||
/**
|
||||
* Splits a dot syntax plugin name into its plugin and class name.
|
||||
* If $name does not have a dot, then index 0 will be null.
|
||||
*
|
||||
* Commonly used like
|
||||
* ```
|
||||
* list($plugin, $name) = pluginSplit($name);
|
||||
* ```
|
||||
*
|
||||
* @param string $name The name you want to plugin split.
|
||||
* @param bool $dotAppend Set to true if you want the plugin to have a '.' appended to it.
|
||||
* @param string|null $plugin Optional default plugin to use if no plugin is found. Defaults to null.
|
||||
* @return array Array with 2 indexes. 0 => plugin name, 1 => class name.
|
||||
* @link https://book.cakephp.org/5/en/core-libraries/global-constants-and-functions.html#pluginSplit
|
||||
* @phpstan-return array{string|null, string}
|
||||
*/
|
||||
function pluginSplit(string $name, bool $dotAppend = false, ?string $plugin = null): array
|
||||
{
|
||||
if (str_contains($name, '.')) {
|
||||
$parts = explode('.', $name, 2);
|
||||
if ($dotAppend) {
|
||||
$parts[0] .= '.';
|
||||
}
|
||||
|
||||
/** @phpstan-var array{string, string} */
|
||||
return $parts;
|
||||
}
|
||||
|
||||
return [$plugin, $name];
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('Cake\Core\namespaceSplit')) {
|
||||
/**
|
||||
* Split the namespace from the classname.
|
||||
*
|
||||
* Commonly used like `list($namespace, $className) = namespaceSplit($class);`.
|
||||
*
|
||||
* @param string $class The full class name, ie `Cake\Core\App`.
|
||||
* @return array{0: string, 1: string} Array with 2 indexes. 0 => namespace, 1 => classname.
|
||||
*/
|
||||
function namespaceSplit(string $class): array
|
||||
{
|
||||
$pos = strrpos($class, '\\');
|
||||
if ($pos === false) {
|
||||
return ['', $class];
|
||||
}
|
||||
|
||||
return [substr($class, 0, $pos), substr($class, $pos + 1)];
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('Cake\Core\pr')) {
|
||||
/**
|
||||
* print_r() convenience function.
|
||||
*
|
||||
* In terminals this will act similar to using print_r() directly, when not run on CLI
|
||||
* print_r() will also wrap `<pre>` tags around the output of given variable. Similar to debug().
|
||||
*
|
||||
* This function returns the same variable that was passed.
|
||||
*
|
||||
* @param mixed $var Variable to print out.
|
||||
* @return mixed the same $var that was passed to this function
|
||||
* @link https://book.cakephp.org/5/en/core-libraries/global-constants-and-functions.html#pr
|
||||
* @see debug()
|
||||
*/
|
||||
function pr(mixed $var): mixed
|
||||
{
|
||||
if (!Configure::read('debug')) {
|
||||
return $var;
|
||||
}
|
||||
|
||||
$template = PHP_SAPI !== 'cli' && PHP_SAPI !== 'phpdbg' ? '<pre class="pr">%s</pre>' : "\n%s\n\n";
|
||||
printf($template, trim(print_r($var, true)));
|
||||
|
||||
return $var;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('Cake\Core\pj')) {
|
||||
/**
|
||||
* JSON pretty print convenience function.
|
||||
*
|
||||
* In terminals this will act similar to using json_encode() with JSON_PRETTY_PRINT directly, when not run on CLI
|
||||
* will also wrap `<pre>` tags around the output of given variable. Similar to pr().
|
||||
*
|
||||
* This function returns the same variable that was passed.
|
||||
*
|
||||
* @param mixed $var Variable to print out.
|
||||
* @return mixed the same $var that was passed to this function
|
||||
* @see pr()
|
||||
* @link https://book.cakephp.org/5/en/core-libraries/global-constants-and-functions.html#pj
|
||||
*/
|
||||
function pj(mixed $var): mixed
|
||||
{
|
||||
if (!Configure::read('debug')) {
|
||||
return $var;
|
||||
}
|
||||
|
||||
$template = PHP_SAPI !== 'cli' && PHP_SAPI !== 'phpdbg' ? '<pre class="pj">%s</pre>' : "\n%s\n\n";
|
||||
$flags = JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES;
|
||||
printf($template, trim((string)json_encode($var, $flags)));
|
||||
|
||||
return $var;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('Cake\Core\env')) {
|
||||
/**
|
||||
* Gets an environment variable from available sources, and provides emulation
|
||||
* for unsupported or inconsistent environment variables (i.e. DOCUMENT_ROOT on
|
||||
* IIS, or SCRIPT_NAME in CGI mode). Also exposes some additional custom
|
||||
* environment information.
|
||||
*
|
||||
* @param string $key Environment variable name.
|
||||
* @param string|bool|null $default Specify a default value in case the environment variable is not defined.
|
||||
* @return string|float|int|bool|null Environment variable setting.
|
||||
* @link https://book.cakephp.org/5/en/core-libraries/global-constants-and-functions.html#env
|
||||
*/
|
||||
function env(string $key, string|float|int|bool|null $default = null): string|float|int|bool|null
|
||||
{
|
||||
if ($key === 'HTTPS') {
|
||||
if (isset($_SERVER['HTTPS'])) {
|
||||
return !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off';
|
||||
}
|
||||
|
||||
return str_starts_with((string)env('SCRIPT_URI'), 'https://');
|
||||
}
|
||||
|
||||
if ($key === 'SCRIPT_NAME' && env('CGI_MODE') && isset($_ENV['SCRIPT_URL'])) {
|
||||
$key = 'SCRIPT_URL';
|
||||
}
|
||||
|
||||
$val = $_SERVER[$key] ?? $_ENV[$key] ?? null;
|
||||
assert($val === null || is_scalar($val));
|
||||
if ($val == null && getenv($key) !== false) {
|
||||
$val = (string)getenv($key);
|
||||
}
|
||||
|
||||
if ($key === 'REMOTE_ADDR' && $val === env('SERVER_ADDR')) {
|
||||
$addr = env('HTTP_PC_REMOTE_ADDR');
|
||||
if ($addr !== null) {
|
||||
$val = $addr;
|
||||
}
|
||||
}
|
||||
|
||||
if ($val !== null) {
|
||||
return $val;
|
||||
}
|
||||
|
||||
switch ($key) {
|
||||
case 'DOCUMENT_ROOT':
|
||||
$name = (string)env('SCRIPT_NAME');
|
||||
$filename = (string)env('SCRIPT_FILENAME');
|
||||
$offset = 0;
|
||||
if (!str_ends_with($name, '.php')) {
|
||||
$offset = 4;
|
||||
}
|
||||
|
||||
return substr($filename, 0, -(strlen($name) + $offset));
|
||||
case 'PHP_SELF':
|
||||
return str_replace((string)env('DOCUMENT_ROOT'), '', (string)env('SCRIPT_FILENAME'));
|
||||
case 'CGI_MODE':
|
||||
return PHP_SAPI === 'cgi';
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('Cake\Core\triggerWarning')) {
|
||||
/**
|
||||
* Triggers an E_USER_WARNING.
|
||||
*
|
||||
* @param string $message The warning message.
|
||||
* @return void
|
||||
*/
|
||||
function triggerWarning(string $message): void
|
||||
{
|
||||
trigger_error($message, E_USER_WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('Cake\Core\deprecationWarning')) {
|
||||
/**
|
||||
* Helper method for outputting deprecation warnings
|
||||
*
|
||||
* @param string $version The version that added this deprecation warning.
|
||||
* @param string $message The message to output as a deprecation warning.
|
||||
* @param int $stackFrame The stack frame to include in the error. Defaults to 1
|
||||
* as that should point to application/plugin code.
|
||||
* @return void
|
||||
*/
|
||||
function deprecationWarning(string $version, string $message, int $stackFrame = 1): void
|
||||
{
|
||||
if (!(error_reporting() & E_USER_DEPRECATED)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$trace = debug_backtrace();
|
||||
if (isset($trace[$stackFrame])) {
|
||||
$frame = $trace[$stackFrame];
|
||||
$frame += ['file' => '[internal]', 'line' => '??'];
|
||||
|
||||
// Assuming we're installed in vendor/cakephp/cakephp/src/Core/functions.php
|
||||
$root = dirname(__DIR__, 5);
|
||||
if (defined('ROOT')) {
|
||||
$root = ROOT;
|
||||
}
|
||||
$relative = str_replace(DIRECTORY_SEPARATOR, '/', substr($frame['file'], strlen($root) + 1));
|
||||
$patterns = (array)Configure::read('Error.ignoredDeprecationPaths');
|
||||
foreach ($patterns as $pattern) {
|
||||
$pattern = str_replace(DIRECTORY_SEPARATOR, '/', $pattern);
|
||||
if (fnmatch($pattern, $relative)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$message = sprintf(
|
||||
"Since %s: %s\n%s, line: %s\n" .
|
||||
'You can disable all deprecation warnings by setting `Error.errorLevel` to ' .
|
||||
'`E_ALL & ~E_USER_DEPRECATED`. Adding `%s` to `Error.ignoredDeprecationPaths` ' .
|
||||
'in your `config/app.php` config will mute deprecations from that file only.',
|
||||
$version,
|
||||
$message,
|
||||
$frame['file'],
|
||||
$frame['line'],
|
||||
$relative,
|
||||
);
|
||||
}
|
||||
|
||||
static $errors = [];
|
||||
$checksum = hash('xxh128', $message);
|
||||
$duplicate = (bool)Configure::read('Error.allowDuplicateDeprecations', false);
|
||||
if (isset($errors[$checksum]) && !$duplicate) {
|
||||
return;
|
||||
}
|
||||
if (!$duplicate) {
|
||||
$errors[$checksum] = true;
|
||||
}
|
||||
|
||||
trigger_error($message, E_USER_DEPRECATED);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('Cake\Core\toString')) {
|
||||
/**
|
||||
* Converts the given value to a string.
|
||||
*
|
||||
* This method attempts to convert the given value to a string.
|
||||
* If the value is already a string, it returns the value as it is.
|
||||
* ``null`` is returned if the conversion is not possible.
|
||||
*
|
||||
* @param mixed $value The value to be converted.
|
||||
* @return ?string Returns the string representation of the value, or null if the value is not a string.
|
||||
* @since 5.1.0
|
||||
*/
|
||||
function toString(mixed $value): ?string
|
||||
{
|
||||
if (is_string($value)) {
|
||||
return $value;
|
||||
}
|
||||
if (is_int($value)) {
|
||||
return (string)$value;
|
||||
}
|
||||
if (is_bool($value)) {
|
||||
return $value ? '1' : '0';
|
||||
}
|
||||
if (is_float($value)) {
|
||||
if (is_nan($value) || is_infinite($value)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
$return = json_encode($value, JSON_THROW_ON_ERROR);
|
||||
} catch (JsonException) {
|
||||
$return = null;
|
||||
}
|
||||
|
||||
if ($return === null || str_contains($return, 'e')) {
|
||||
return rtrim(sprintf('%.' . (PHP_FLOAT_DIG + 3) . 'F', $value), '.0');
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
if ($value instanceof Stringable) {
|
||||
return (string)$value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('Cake\Core\toInt')) {
|
||||
/**
|
||||
* Converts a value to an integer.
|
||||
*
|
||||
* This method attempts to convert the given value to an integer.
|
||||
* If the conversion is successful, it returns the value as an integer.
|
||||
* If the conversion fails, it returns NULL.
|
||||
*
|
||||
* String values are trimmed using trim().
|
||||
*
|
||||
* @param mixed $value The value to be converted to an integer.
|
||||
* @return int|null Returns the converted integer value or null if the conversion fails.
|
||||
* @since 5.1.0
|
||||
*/
|
||||
function toInt(mixed $value): ?int
|
||||
{
|
||||
if (is_int($value)) {
|
||||
return $value;
|
||||
}
|
||||
if (is_string($value)) {
|
||||
$value = trim($value);
|
||||
if (preg_match('/^0+[^0]{1}/', $value)) {
|
||||
$value = ltrim($value, '0');
|
||||
}
|
||||
|
||||
$value = filter_var($value, FILTER_VALIDATE_INT, FILTER_NULL_ON_FAILURE);
|
||||
|
||||
return $value === PHP_INT_MIN ? null : $value;
|
||||
}
|
||||
if (is_float($value)) {
|
||||
if (is_nan($value) || is_infinite($value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (int)$value;
|
||||
}
|
||||
if (is_bool($value)) {
|
||||
return (int)$value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('Cake\Core\toFloat')) {
|
||||
/**
|
||||
* Converts a value to a float.
|
||||
*
|
||||
* This method attempts to convert the given value to a float.
|
||||
* If the conversion is successful, it returns the value as an float.
|
||||
* If the conversion fails, it returns NULL.
|
||||
*
|
||||
* String values are trimmed using trim().
|
||||
*
|
||||
* @param mixed $value The value to be converted to a float.
|
||||
* @return float|null Returns the converted float value or null if the conversion fails.
|
||||
* @since 5.1.0
|
||||
*/
|
||||
function toFloat(mixed $value): ?float
|
||||
{
|
||||
if (is_string($value)) {
|
||||
$value = trim($value);
|
||||
if (preg_match('/^0+[^0]{1}/', $value)) {
|
||||
$value = ltrim($value, '0');
|
||||
}
|
||||
|
||||
$value = filter_var($value, FILTER_VALIDATE_FLOAT, FILTER_NULL_ON_FAILURE);
|
||||
|
||||
return $value === PHP_FLOAT_MIN ? null : $value;
|
||||
}
|
||||
if (is_float($value)) {
|
||||
if (is_nan($value) || is_infinite($value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
if (is_int($value)) {
|
||||
return (float)$value;
|
||||
}
|
||||
if (is_bool($value)) {
|
||||
return (float)$value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('Cake\Core\toBool')) {
|
||||
/**
|
||||
* Converts a value to boolean.
|
||||
*
|
||||
* 1 | '1' | 1.0 | true - values returns as true
|
||||
* 0 | '0' | 0.0 | false - values returns as false
|
||||
* Other values returns as null.
|
||||
*
|
||||
* @param mixed $value The value to convert to boolean.
|
||||
* @return bool|null Returns true if the value is truthy, false if it's falsy, or NULL otherwise.
|
||||
* @since 5.1.0
|
||||
*/
|
||||
function toBool(mixed $value): ?bool
|
||||
{
|
||||
if (in_array($value, ['1', 1, 1.0, true], true)) {
|
||||
return true;
|
||||
}
|
||||
if (in_array($value, ['0', 0, 0.0, false], true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+271
@@ -0,0 +1,271 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||
* @link https://cakephp.org CakePHP(tm) Project
|
||||
* @since 3.0.0
|
||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
|
||||
use function Cake\Core\deprecationWarning as cakeDeprecationWarning;
|
||||
use function Cake\Core\env as cakeEnv;
|
||||
use function Cake\Core\h as cakeH;
|
||||
use function Cake\Core\namespaceSplit as cakeNamespaceSplit;
|
||||
use function Cake\Core\pathCombine as cakePathCombine;
|
||||
use function Cake\Core\pj as cakePj;
|
||||
use function Cake\Core\pluginSplit as cakePluginSplit;
|
||||
use function Cake\Core\pr as cakePr;
|
||||
use function Cake\Core\toBool as cakeToBool;
|
||||
use function Cake\Core\toFloat as cakeToFloat;
|
||||
use function Cake\Core\toInt as cakeToInt;
|
||||
use function Cake\Core\toString as cakeToString;
|
||||
use function Cake\Core\triggerWarning as cakeTriggerWarning;
|
||||
|
||||
if (!function_exists('pathCombine')) {
|
||||
/**
|
||||
* Combines parts with a forward-slash `/`.
|
||||
*
|
||||
* Skips adding a forward-slash if either `/` or `\` already exists.
|
||||
*
|
||||
* @param array<string> $parts
|
||||
* @param bool|null $trailing Determines how trailing slashes are handled
|
||||
* - If true, ensures a trailing forward-slash is added if one doesn't exist
|
||||
* - If false, ensures any trailing slash is removed
|
||||
* - if null, ignores trailing slashes
|
||||
* @return string
|
||||
*/
|
||||
function pathCombine(array $parts, ?bool $trailing = null): string
|
||||
{
|
||||
return cakePathCombine($parts, $trailing);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('h')) {
|
||||
/**
|
||||
* Convenience method for htmlspecialchars.
|
||||
*
|
||||
* @param mixed $text Text to wrap through htmlspecialchars. Also works with arrays, and objects.
|
||||
* Arrays will be mapped and have all their elements escaped. Objects will be string cast if they
|
||||
* implement a `__toString` method. Otherwise, the class name will be used.
|
||||
* Other scalar types will be returned unchanged.
|
||||
* @param bool $double Encode existing html entities.
|
||||
* @param string|null $charset Character set to use when escaping.
|
||||
* Defaults to config value in `mb_internal_encoding()` or 'UTF-8'.
|
||||
* @return mixed Wrapped text.
|
||||
* @link https://book.cakephp.org/5/en/core-libraries/global-constants-and-functions.html#h
|
||||
*/
|
||||
function h(mixed $text, bool $double = true, ?string $charset = null): mixed
|
||||
{
|
||||
return cakeH($text, $double, $charset);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('pluginSplit')) {
|
||||
/**
|
||||
* Splits a dot syntax plugin name into its plugin and class name.
|
||||
* If $name does not have a dot, then index 0 will be null.
|
||||
*
|
||||
* Commonly used like
|
||||
* ```
|
||||
* list($plugin, $name) = pluginSplit($name);
|
||||
* ```
|
||||
*
|
||||
* @param string $name The name you want to plugin split.
|
||||
* @param bool $dotAppend Set to true if you want the plugin to have a '.' appended to it.
|
||||
* @param string|null $plugin Optional default plugin to use if no plugin is found. Defaults to null.
|
||||
* @return array Array with 2 indexes. 0 => plugin name, 1 => class name.
|
||||
* @link https://book.cakephp.org/5/en/core-libraries/global-constants-and-functions.html#pluginSplit
|
||||
* @phpstan-return array{string|null, string}
|
||||
*/
|
||||
function pluginSplit(string $name, bool $dotAppend = false, ?string $plugin = null): array
|
||||
{
|
||||
return cakePluginSplit($name, $dotAppend, $plugin);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('namespaceSplit')) {
|
||||
/**
|
||||
* Split the namespace from the classname.
|
||||
*
|
||||
* Commonly used like `list($namespace, $className) = namespaceSplit($class);`.
|
||||
*
|
||||
* @param string $class The full class name, ie `Cake\Core\App`.
|
||||
* @return array{0: string, 1: string} Array with 2 indexes. 0 => namespace, 1 => classname.
|
||||
*/
|
||||
function namespaceSplit(string $class): array
|
||||
{
|
||||
return cakeNamespaceSplit($class);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('pr')) {
|
||||
/**
|
||||
* print_r() convenience function.
|
||||
*
|
||||
* In terminals this will act similar to using print_r() directly, when not run on CLI
|
||||
* print_r() will also wrap `<pre>` tags around the output of given variable. Similar to debug().
|
||||
*
|
||||
* This function returns the same variable that was passed.
|
||||
*
|
||||
* @param mixed $var Variable to print out.
|
||||
* @return mixed the same $var that was passed to this function
|
||||
* @link https://book.cakephp.org/5/en/core-libraries/global-constants-and-functions.html#pr
|
||||
* @see debug()
|
||||
*/
|
||||
function pr(mixed $var): mixed
|
||||
{
|
||||
return cakePr($var);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('pj')) {
|
||||
/**
|
||||
* JSON pretty print convenience function.
|
||||
*
|
||||
* In terminals this will act similar to using json_encode() with JSON_PRETTY_PRINT directly, when not run on CLI
|
||||
* will also wrap `<pre>` tags around the output of given variable. Similar to pr().
|
||||
*
|
||||
* This function returns the same variable that was passed.
|
||||
*
|
||||
* @param mixed $var Variable to print out.
|
||||
* @return mixed the same $var that was passed to this function
|
||||
* @see pr()
|
||||
* @link https://book.cakephp.org/5/en/core-libraries/global-constants-and-functions.html#pj
|
||||
*/
|
||||
function pj(mixed $var): mixed
|
||||
{
|
||||
return cakePj($var);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('env')) {
|
||||
/**
|
||||
* Gets an environment variable from available sources, and provides emulation
|
||||
* for unsupported or inconsistent environment variables (i.e. DOCUMENT_ROOT on
|
||||
* IIS, or SCRIPT_NAME in CGI mode). Also exposes some additional custom
|
||||
* environment information.
|
||||
*
|
||||
* @param string $key Environment variable name.
|
||||
* @param string|bool|null $default Specify a default value in case the environment variable is not defined.
|
||||
* @return string|float|int|bool|null Environment variable setting.
|
||||
* @link https://book.cakephp.org/5/en/core-libraries/global-constants-and-functions.html#env
|
||||
*/
|
||||
function env(string $key, string|float|int|bool|null $default = null): string|float|int|bool|null
|
||||
{
|
||||
return cakeEnv($key, $default);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('triggerWarning')) {
|
||||
/**
|
||||
* Triggers an E_USER_WARNING.
|
||||
*
|
||||
* @param string $message The warning message.
|
||||
* @return void
|
||||
*/
|
||||
function triggerWarning(string $message): void
|
||||
{
|
||||
cakeTriggerWarning($message);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('deprecationWarning')) {
|
||||
/**
|
||||
* Helper method for outputting deprecation warnings
|
||||
*
|
||||
* @param string $version The version that added this deprecation warning.
|
||||
* @param string $message The message to output as a deprecation warning.
|
||||
* @param int $stackFrame The stack frame to include in the error. Defaults to 1
|
||||
* as that should point to application/plugin code.
|
||||
* @return void
|
||||
*/
|
||||
function deprecationWarning(string $version, string $message, int $stackFrame = 1): void
|
||||
{
|
||||
cakeDeprecationWarning($version, $message, $stackFrame + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('toString')) {
|
||||
/**
|
||||
* Converts the given value to a string.
|
||||
*
|
||||
* This method attempts to convert the given value to a string.
|
||||
* If the value is already a string, it returns the value as it is.
|
||||
* ``null`` is returned if the conversion is not possible.
|
||||
*
|
||||
* @param mixed $value The value to be converted.
|
||||
* @return ?string Returns the string representation of the value, or null if the value is not a string.
|
||||
* @since 5.1.1
|
||||
*/
|
||||
function toString(mixed $value): ?string
|
||||
{
|
||||
return cakeToString($value);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('toInt')) {
|
||||
/**
|
||||
* Converts a value to an integer.
|
||||
*
|
||||
* This method attempts to convert the given value to an integer.
|
||||
* If the conversion is successful, it returns the value as an integer.
|
||||
* If the conversion fails, it returns NULL.
|
||||
*
|
||||
* String values are trimmed using trim().
|
||||
*
|
||||
* @param mixed $value The value to be converted to an integer.
|
||||
* @return int|null Returns the converted integer value or null if the conversion fails.
|
||||
* @since 5.1.1
|
||||
*/
|
||||
function toInt(mixed $value): ?int
|
||||
{
|
||||
return cakeToInt($value);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('toFloat')) {
|
||||
/**
|
||||
* Converts a value to a float.
|
||||
*
|
||||
* This method attempts to convert the given value to a float.
|
||||
* If the conversion is successful, it returns the value as an float.
|
||||
* If the conversion fails, it returns NULL.
|
||||
*
|
||||
* String values are trimmed using trim().
|
||||
*
|
||||
* @param mixed $value The value to be converted to a float.
|
||||
* @return float|null Returns the converted float value or null if the conversion fails.
|
||||
* @since 5.1.1
|
||||
*/
|
||||
function toFloat(mixed $value): ?float
|
||||
{
|
||||
return cakeToFloat($value);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('toBool')) {
|
||||
/**
|
||||
* Converts a value to boolean.
|
||||
*
|
||||
* 1 | '1' | 1.0 | true - values returns as true
|
||||
* 0 | '0' | 0.0 | false - values returns as false
|
||||
* Other values returns as null.
|
||||
*
|
||||
* @param mixed $value The value to convert to boolean.
|
||||
* @return bool|null Returns true if the value is truthy, false if it's falsy, or NULL otherwise.
|
||||
* @since 5.1.1
|
||||
*/
|
||||
function toBool(mixed $value): ?bool
|
||||
{
|
||||
return cakeToBool($value);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user