selene/config

此包已被废弃,不再维护。未建议替代包。

Selene 配置组件

dev-development 2014-08-22 17:46 UTC

This package is not auto-updated.

Last update: 2015-12-05 10:10:40 UTC


README

Build Status Code Climate Coverage Status

License

安装

可以通过composer安装此组件。

{
    "require":{
        "selene/config":"dev-development"
    }
}

然后运行

$ composer install

加载器

配置包包含三种不同的基础加载器:PhpFileLoaderXmlFileLoaderCallableLoader。两者都扩展了FileLoader,并需要一个资源定位器实例。

加载实现取决于你。例如,假设你有一个名为Config的类,它将所有配置值存储为一个关联数组。

<?php

namespace Acme\Config;

class Config
{
    protected $config;

    public function __construct(array $config = [])
    {
        $this->config = $config;
    }

    public function addValues(array $values)
    {
        $this->config = array_merge((array)$this->config, $values);
    }

    public function get($key, $default = null)
    {
        if (…) {
            return $value;
        }

        return $default;
    }

    public function all()
    {
        return $this->config;
    }
}

你的PHP加载器可能看起来像这样

<?php

namespace Acme\Config;

use \Selene\Components\Config\Loader\PhpFileLoader;
use \Selene\Components\Config\Resource\LocatorInterface;

class PhpLoader extends PhpFileLoader
{
    public function __construct(Config $config, LocatorInterface $locator)
    {
        $this->config = $config;
        parent__construct($locator);
    }

    protected function doLoad($file)
    {
        $values = parent::doLoad($file);

        $this->config->addValues($values);
    }
}

加载文件

使用你的新加载器,你现在可以像这样加载配置文件

<?php

use \Acme\Config\Config;
use \Acme\Config\PhpLoader;
use \Selene\Components\Config\Resource\Locator;

$config  = new Config;
$locator = new Locator(['path/config/a', 'path/config/b']);
$loader  = new PhpLoader($config, $locator;

$loader->load('config.php');

注意,定位器接受一个路径数组,用于定位配置文件。默认情况下,使用第一个结果,其余路径被丢弃。然而,如果你将布尔值(true)传递给load()方法的第二个参数,将定位和加载所有路径中的文件。

<?php

$loader->load('config.php', PhpLoader::LOAD_ALL);

加载不同类型的资源

可以使用DelegatingLoader类加载不同类型的配置。

<?php

use \Acme\Config\PhpLoader;
use \Acme\Config\JsonLoader;
use \Selene\Components\Config\Loader\Resolver;
use \Selene\Components\Config\Loader\DelegatingLoader;

$loader = new DelegatingLoader(new Resolver(
    new PhpLoader($config, $locator),   
    new JsonLoader($config, $locator)  
));

$loader->load('config.php', PhpLoader::LOAD_ALL);
$loader->load('config.json', PhpLoader::LOAD_ALL);

自定义加载器

理论上,你可以创建各种加载器,例如JSON加载器。

<?php

namespace Acme\Config;

use \Selene\Components\Config\Loader\FileLoader;

class JsonFileLoader extends FileLoader
{
    protected $extension = 'json';

    /**
     * {@inheritdoc}
     */
    protected function doLoad($file)
    {
        $contents = json_decode(file_get_contents($file), true);

        // setter logic goes here.
    }
}

监听加载器事件

每次加载资源时,加载器将通知已注册在加载器上的监听器。监听器必须实现Selene\Components\Config\Loader\LoaderListener

例如,你可能想要将加载事件记录到你的应用程序日志文件中。

<?php

namespace Acme\Config;

use \Psr\Log;
use \Selene\Components\Config\Loader\LoaderListener;

class ConfigLoaderLogger extends LoaderListener
{
    public function __construct(Log $logger)
    {
        $this->logger = $logger;
    }

    public function onLoaded($resource)
    {
        $this->logger->info(sprintf('Loaded resource "%s"',  $resource));
    }
}

只需使用addListener()方法将监听器添加到你的配置加载器中。

<?php

$configLoaderLogger = new ConfigLoaderLogger($logger);

$loader->addListener($configLoaderLogger);

如果你需要删除监听器,可以使用removeListener方法。

<?php

$loader->removeListener($configLoaderLogger);

缓存

根据情况,缓存配置可能很有用,例如,每次请求都解析xml文件将影响性能。相反,你可能会解析配置文件一次,并将内容存储在PHP数组中。

<?php

use \Acme\Config\Config;
use \Acme\Config\XmlLoader;
use \Selene\Components\Config\Cache;
use \Selene\Components\Config\Resource\Locator;

$cache = new Cache($file);

if ($cache->isValid()) {
    $config = new Config(include $file);
} else {
    $config = new Config;
    $loader = new XmlLoader($config, new Locator($paths));
    $loader->load('config.xml');

    // …

    $cache->write("<?php\n    return ".var_export($config->all()).';');
}

上述解决方案适用于加载单个文件。如果给定的缓存文件自上次请求以来已修改,则Cache::isValid()将报告false。然而,实际配置文件不会被考虑。

缓存能够进行资源检查。只需将true传递给构造函数作为第二个参数,并在写入缓存时提供要跟踪的资源列表。

这就是加载器的事件能力发挥作用的地方。让我们通过实现LoaderListener接口来修改Acme\Config\Config类。

<?php

namespace Acme\Config;

use \Selene\Components\Config\Loader\PhpFileLoader;
use \Selene\Components\Config\Loader\LoaderListener;
use \Selene\Components\Config\Resource\FileResource;
use \Selene\Components\Config\Resource\ObjectResource;
use \Selene\Components\Config\Resource\LocatorInterface;

class PhpLoader extends PhpFileLoader implements LoaderListener
{
    private $resources;

    //…

    public function onLoaded($resource)
    {
        if (is_object($resource)) {
            $this->resources[] = new ObjectResource($resource); 
        } elseif(is_string($file)) {
            $this->resources[] = new FileResource($resource);   
        }
    }

    public function getResources()
    {
        return $this->resources;
    }
}

现在,正在加载的每个资源都将推送到一个数组中,我们可以将其用作缓存将用于跟踪更改的文件列表。

<?php

$cache = new Cache($file, true);

// do the loading proceedure. 

// write the cache file content and pass in the resources to be tracked.
$cache->write(
    "<?php\n    return ".var_export($config->all()).';',
    $config->getResources()
);

验证

验证器允许您验证关联数组。在加载之前验证用户定义的配置非常有用。

验证器附带一个Builder类,允许您将配置结构定义为树。然后树将与输入数组进行验证。

<?php

use \Selene\Components\Config\Validator\Builder;

$builder = new Builder('config');
$builder
    ->getRoot()
    // build the tree


$validator = $builder->getValidator();
$validator->load($config);
$validator->validate();

节点类型

有两种不同的节点类型。标量节点数组节点

它们都共享用于在验证时定义其行为的公共方法。

  • optional()
    标记节点为必填。

  • notEmpty()
    标记节点为空。空值的定义取决于节点类型。例如,在字符串节点中,空字符串是空值。

  • defaultValue($value)
    如果节点是可选的且缺失或为空,则使用此值。

  • condition()
    开始一个条件块。请参阅下文中的条件

  • end()
    在构建器上下文中,end()将返回当前节点的父节点。

标量节点

标量节点表示标量值,如字符串、布尔值、整数等。

与数组节点不同,标量节点不能有子节点。

布尔值

表示布尔值。

<?php

$builder
    ->getRoot()
    ->boolean('required')
    ->end();
字符串

表示字符串值。

<?php

$builder
    ->getRoot()
    ->string('name')
    ->end();
整数

表示整数。

<?php

$builder
    ->getRoot()
    ->integer('port')
    ->end();
浮点数

表示浮点值。

<?php

$builder
    ->getRoot()
    ->float('precission')
    ->end();
数组节点

数组节点可以包含类型为标量和数组的子节点。

字典

表示关联数组。

<?php

$builder
    ->getRoot()
    ->dict('memcached_server')
        ->string('host')->end()
        ->integer('port')->end()
        ->integer('weight')->end()
    ->end();

表示索引数组。

注意,你只能在值节点上定义一个子节点。
子节点表示应该在索引数组中存在的值类型。

<?php

$builder
    ->getRoot()
    ->values('paths')
        ->string('path')->end()
    ->end();
节点条件

节点条件作为简单的if/then块。只有当“if”部分返回true时,“then”部分才会执行。

<?php

$root
    ->string()
        ->condition()
            ->when(function ($value) {…})
            ->then(function ($value) {…})
        ->end()
    ->end();

有几个预定义的“if”条件。

  • always()
    总是执行。

  • when(Closure $expression)
    评估闭包中的表达式以返回true或false。

  • ifTrue(Closure $expression)
    when相同。

  • ifMissing()
    只有当值(指输入的键)缺失时才会触发。

  • ifEmpty()
    只有当值为空时才会触发。

  • ifNull()
    只有当值为null时才会触发。

  • ifArray()
    when相同。只有当输入值是数组时才会触发。

  • ifNotArray()
    只有当输入值不是数组时才会触发。

  • ifInArray(array $values)
    只有当输入值在$values数组中时才会触发。

  • ifNotInArray()
    when相同。只有当输入值不在$values数组中时才会触发。

  • ifString()
    只有当输入值是字符串时才会触发。

还有几个预定义的“then”结果。

  • ifInt()
    只有当输入值是整数时才会触发。

  • ifFloat()
    只有当输入值是浮点值时才会触发。

  • thenMarkInvalid
    标记节点无效。

  • thenRemove
    取消设置当前节点并将其从父节点中删除。