# 系统配置

Testing Is Documentation

tests/Option/OptionTest.php

QueryPHP 为系统提供了灵活的配置,通常来说通过服务提供者将配置打包到服务容器中,可以很方便地使用。

# 使用方式

使用容器 option 服务

\App::make('option')->set($name, $value = null): void;
\App::make('option')->get(string $name = 'app\\', $defaults = null);

依赖注入

class Demo
{
    private \Leevel\Option\IOption $option;

    public function __construct(\Leevel\Option\IOption $option)
    {
        $this->option = $option;
    }
}

使用静态代理

\Leevel\Option\Proxy\Option::set($name, $value = null): void;
\Leevel\Option\Proxy\Option::get(string $name = 'app\\', $defaults = null);

# 配置目录

系统配置文件为 option 目录,每个配置文件对应不同的组件,当然你也可以增加自定义的配置文件。

  • 配置位于 option,可以定义配置文件。
  • 主要配置文件包含应用、数据库、缓存、日志、Session 等等。
  • 扩展配置 common/ui/option/test.php 目录,在 composer.json 中定义。

composer.json 可以扩展目录

{
    "extra": {
        "leevel": {
            "@options": "The extend options",
            "options": {
                "test": "common/ui/option/test.php"
            }
        }
    }
}

WARNING

注意,其它软件包也可以采用这种方式自动注入扩展默认配置。

系统默认常见配置:

配置项 配置描述
app 应用配置
auth 登陆验证
cache 缓存配置
console 控制台配置
cookie Cookie 配置
database 数据库配置
debug 调试配置
filesystem 文件系统配置
i18n 国际化配置
log 日志配置
session Session 配置
view 视图配置

# 配置缓存

配置支持生成缓存,通过内置的命令即可实现。

php leevel option:cache

返回结果

Start to cache option.
Option cache file /data/codes/queryphp/bootstrap/option.php cache successed.

清理配置缓存

php leevel option:clear

返回结果

Start to clear cache option.
Option cache file /data/codes/queryphp/bootstrap/option.php cache clear successed.

# 配置定义

可以直接在相应的配置文件已数组的方式定义,新的配置文件直接放入目录即可。

TIP

配置参数名严格区分大小写,建议是使用小写定义配置参数的规范。

app 应用配置中几个核心的配置项,这是整个系统关键的配置。

配置项 配置值 描述
environment development 运行环境,可以为 production : 生产环境 testing : 测试环境 development : 开发环境
debug true 是否打开调试模式,可以为 true : 开启调试 false 关闭调试,打开调试模式可以显示更多精确的错误信息。
auth_key 7becb888f518b20224a988906df51e05 安全 key,请妥善保管此安全 key,防止密码被人破解。

# 环境变量定义

可以在应用的根目录下定义一个特殊的 .env 环境变量文件,一般用于平时开发使用。

# 自定义环境变量

可以通过 RUNTIME_ENVIRONMENT 来定义自定义的环境变量文件,比如定义 .test 的环境变量。

putenv('RUNTIME_ENVIRONMENT=test');

环境变量配置格式

# Environment production、testing and development
ENVIRONMENT = development

# Debug
DEBUG = true
DEBUG_JSON = true
DEBUG_CONSOLE = true
DEBUG_JAVASCRIPT = true

...

获取环境配置

\env('environment');
\Leevel::env('environment');
\App::env('environment');

Uses

<?php

use Leevel\Option\Option;

# all 返回所有配置

public function testAll(): void
{
    $data = [
        'hello'       => 'world',
        'test\\child' => ['foo' => 'bar'],
    ];

    $option = new Option($data);

    $this->assertSame($option->all(), $data);
}

# get 获取配置

public function testGet(): void
{
    $data = [
        'app' => [
            'environment' => 'testing',
            'debug'       => true,
        ],
        'cache' => [
            'expire'      => 86400,
            'time_preset' => [
                'foo' => 'bar',
            ],
        ],
        'hello' => 'world',
    ];

    $option = new Option($data);

    $this->assertSame('testing', $option->get('app\\environment'));
    $this->assertSame('testing', $option->get('environment'), 'Default namespace is app, so it equal app\\testing.');
    $this->assertNull($option->get('hello'), 'The default namespace is app, so it equal app\\hello');
    $this->assertNull($option->get('app\\hello'), 'The default namespace is app, so it equal app\\hello');
    $this->assertSame($option->get('hello\\'), 'world');
    $this->assertSame($option->get('hello\\*'), 'world');

    $this->assertSame([
        'environment' => 'testing',
        'debug'       => true,
    ], $option->get('app\\'));

    $this->assertSame([
        'environment' => 'testing',
        'debug'       => true,
    ], $option->get('app\\*'));

    $this->assertFalse([
        'environment' => 'testing',
        'debug'       => true,
    ] === $option->get('app'), 'The default namespace is app, so it equal app\\app');

    // namespace\sub.sub1.sub2
    $this->assertSame($option->get('cache\\time_preset.foo'), 'bar');
    $this->assertNull($option->get('cache\\time_preset.foo2'));
}

# has 是否存在配置

public function testHas(): void
{
    $data = [
        'app' => [
            'environment' => 'testing',
            'debug'       => true,
        ],
        'cache' => [
            'expire'      => 86400,
            'time_preset' => [
                'foo' => 'bar',
            ],
        ],
        'hello' => 'world',
    ];

    $option = new Option($data);

    $this->assertTrue($option->has('app\\environment'));
    $this->assertTrue($option->has('environment'), 'Default namespace is app, so it equal app\\testing.');
    $this->assertFalse($option->has('hello'), 'The default namespace is app, so it equal app\\hello');
    $this->assertFalse($option->has('app\\hello'), 'The default namespace is app, so it equal app\\hello');
    $this->assertTrue($option->has('hello\\'));
    $this->assertTrue($option->has('hello\\*'));
    $this->assertTrue($option->has('app\\'));
    $this->assertTrue($option->has('app\\*'));
    $this->assertFalse($option->has('app'), 'The default namespace is app, so it equal app\\app');

    // namespace\sub.sub1.sub2
    $this->assertTrue($option->has('cache\\time_preset.foo'));
    $this->assertFalse($option->has('cache\\time_preset.foo2'));
}

# set 设置配置

public function testSet(): void
{
    $data = [];

    $option = new Option($data);

    // set app\environment value
    $option->set('environment', 'testing');
    $this->assertSame('testing', $option->get('app\\environment'));
    $this->assertSame('testing', $option->get('environment'), 'Default namespace is app, so it equal app\\testing.');

    $this->assertNull($option->get('hello'), 'The default namespace is app, so it equal app\\hello');
    $option->set('hello', 'i am hello');
    $this->assertSame($option->get('hello'), 'i am hello', 'The default namespace is app, so it equal app\\hello');

    $this->assertSame($option->all(), [
        'app' => [
            'environment' => 'testing',
            'hello'       => 'i am hello',
        ],
    ]);

    // 当我们获取一个不存在的配置命名空间时,返回一个初始化的空数组
    // hello namespace not app\hello
    $this->assertSame($option->get('hello\\'), []);
    $this->assertSame($option->get('hello\\*'), []);

    $option->set('hello\\', ['foo' => ['sub' => 'bar']]);

    $this->assertSame($option->get('hello\\foo.sub'), 'bar');

    // namespace\sub.sub1.sub2
    $option->set('cache\\time_preset.foo', 'bar');
    $this->assertSame($option->get('cache\\time_preset.foo'), 'bar');
    $this->assertNull($option->get('cache\\time_preset.foo2'));
}

# delete 删除配置

public function testDelete(): void
{
    $data = [
        'app' => [
            'environment' => 'testing',
            'debug'       => true,
        ],
        'cache' => [
            'expire'      => 86400,
            'time_preset' => [
                'foo' => 'bar',
            ],
        ],
        'hello' => 'world',
    ];

    $option = new Option($data);
    $option->delete('debug');

    $this->assertSame($option->all(), [
        'app' => [
            'environment' => 'testing',
        ],
        'cache' => [
            'expire'      => 86400,
            'time_preset' => [
                'foo' => 'bar',
            ],
        ],
        'hello' => 'world',
    ]);

    $option->delete('cache\\time_preset.foo');

    $this->assertSame($option->all(), [
        'app' => [
            'environment' => 'testing',
        ],
        'cache' => [
            'expire'      => 86400,
            'time_preset' => [
            ],
        ],
        'hello' => 'world',
    ]);

    // 删除命令空间会初始化该命名空间为空数组,不存在会创建一个空数组
    $option->delete('hello\\');

    $this->assertSame($option->all(), [
        'app' => [
            'environment' => 'testing',
        ],
        'cache' => [
            'expire'      => 86400,
            'time_preset' => [
            ],
        ],
        'hello' => [],
    ]);

    $option->delete('world\\');

    $this->assertSame($option->all(), [
        'app' => [
            'environment' => 'testing',
        ],
        'cache' => [
            'expire'      => 86400,
            'time_preset' => [
            ],
        ],
        'hello' => [],
        'world' => [],
    ]);
}

# reset 重置配置

危险操作,一般没有必要调用。

public function testReset(): void
{
    $data = [
        'hello' => 'world',
    ];

    $option = new Option($data);

    $this->assertSame($option->all(), [
        'hello' => 'world',
    ]);

    // array
    $option->reset(['foo' => 'bar']);
    $this->assertSame($option->all(), [
        'foo' => 'bar',
    ]);

    // set a namespace
    $option->reset('foo');
    $this->assertSame($option->all(), [
        'foo' => [],
    ]);

    $option->reset('foo2');
    $this->assertSame($option->all(), [
        'foo'  => [],
        'foo2' => [],
    ]);

    // reset all
    $option->reset();
    $this->assertSame($option->all(), []);
}

# 数组访问配置对象

配置实现了 \ArrayAccess,可以通过以数组的方式访问配置对象,在服务提供者中经常运用。

public function testArrayAccess(): void
{
    $data = [
        'app' => [
            'environment' => 'testing',
            'debug'       => true,
        ],
        'cache' => [
            'expire'      => 86400,
            'time_preset' => [
                'foo' => 'bar',
            ],
        ],
        'hello' => 'world',
    ];

    $option = new Option($data);

    // get
    $this->assertSame($option['cache\\time_preset.foo'], 'bar');

    // remove
    unset($option['cache\\time_preset.foo']);
    $this->assertNull($option['cache\\time_preset.foo']);

    // set
    $option['cache\\foo'] = 'bar';
    $this->assertSame($option['cache\\foo'], 'bar');

    // has
    $this->assertTrue(isset($option['hello\\']));
}