PHP持久化存储管理Laravel config配置 - Zanealancy博客

PHP持久化存储管理Laravel config配置

47185924

这个扩展为Laravel引入了持久配置存储库。

它的使用特别支持应用程序运行时配置,从数据库加载配置。

For license information check the LICENSE-file.

Latest Stable Version Total Downloads Build Status

安装

The preferred way to install this extension is through composer.

任一次运行

php composer.phar require --prefer-dist illuminatech/config

或加入

"illuminatech/config": "*"

到你的composer.json的require部分。

用法

这个扩展允许使用外部存储(如关系数据库)中的数据重新配置已经创建的配置存储库。

它提供了特殊的配置存储库类Illuminatech config PersistentRepository,它包装了任何给定的配置存储库,

添加一个层来保存和恢复来自持久存储的数据。

<?php

use IlluminateConfigRepository;
use IlluminatechConfigStorageDb;
use IlluminateSupportFacadesApp;
use IlluminatechConfigPersistentRepository;

$sourceConfigRepository = new Repository([
    'foo' => [
        'name' => 'Foo',
    ],
    'bar' => [
        'enabled' => false,
    ],
    'other' => [
        'value' => 'Some',
    ],
]);

$storage = new StorageDb(App::make('db.connection'));

$persistentConfigRepository = (new PersistentRepository($sourceConfigRepository, $storage))
    ->setItems([
        'foo.name',
        'bar.enabled',
    ]);

echo $persistentConfigRepository->get('foo.name'); // 如果存在则从数据库中返回值,否则从源存储库中返回值,在这个例子中- ` Foo `如果存在则从数据库中返回值,否则从源存储库中返回值,在这个例子中- ` Foo `

echo $persistentConfigRepository->get('other.value'); // 没有指定为“items”的键始终保持完整,在这种情况下-始终返回` Some `

没有指定为“items”的键始终保持完整,在这种情况下-始终返回“Some”配置数据,这些数据应该保存在通过IlluminatechConfigPersistentRepository::setItems()定义的持久存储中。

只有显式定义为“项”的键才会被存储或从持久存储中检索。其他数据

源配置存储库中的内容将保持原样。

PersistentRepository完全装饰任何配置存储库,匹配IlluminateContracts config repository,并可以替换Illuminate config repository实例。

特别是,它允许你用Illuminatech config persistentpository实例替换常规的Laravel配置,

将数据库配置应用到整个应用程序。你可以在AppServiceProvider类中执行此操作。 例如:

<?php

namespace AppProviders;

use IlluminatechConfigStorageDb;
use IlluminateSupportServiceProvider;
use IlluminateContractsConfigRepository;
use IlluminatechConfigPersistentRepository;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        $this->app->extend('config', function (Repository $originConfig) {
            $storage = new StorageDb($this->app->make('db.connection'));

            $newConfig = (new PersistentRepository($originConfig, $storage))
                ->setItems([
                    'mail.contact.address' => [
                        'label' => __('Email address receiving contact messages'),
                        'rules' => ['sometimes', 'required', 'email'],
                    ],
                    // ...
                ]);

            return $newConfig;
        });

        // ...
    }
}

注意:此扩展不提供应用程序配置替代的内置服务提供者,因为它可能不需要 对于特定的应用程序,而IlluminatechConfig persistentpository的使用不受此任务的限制。

您还可以为每个特定的应用程序实体管理持久配置。例如:假设我们需要允许

应用程序用户自定义其资料页面的外观,如更改颜色模式或启用/禁用侧边栏等。

这些设置可以通过绑定到用户Eloquent模型的IlluminatechConfigPersistentRepository来管理。这样的模型类

可能看起来像下面这样:

<?php

namespace AppModels;

use IlluminateConfigRepository;
use IlluminatechConfigStorageDb;
use IlluminateDatabaseEloquentModel;
use IlluminatechConfigPersistentRepository;

class User extends Model
{
    /**
     * @var IlluminatechConfigPersistentRepository 特定于此模型的配置存储库。
     */
    private $config;

    /**
     * 返回与此特定模型关联的配置。
     *
     * @return IlluminatechConfigPersistentRepository 配置存储库。
     */
    public function getConfig(): PersistentRepository
    {
        if ($this->config === null) {
            if (empty($this->id)) {
                throw new InvalidArgumentException('Unable to get config for model without ID.');
            }

            $repository = new Repository($this->defaultConfigData());

            $storage = (new StorageDb($this->getConnection()))
                ->setFilter(['user_id' => $this->id]); // 确保每个模型的配置不同

            $this->config = (new PersistentRepository($repository, $storage))
                ->setItems($this->persistentConfigItems());
        }

        return $this->config;
    }

    /**
     * 定义模型实例的默认配置。
     *
     * @return array config.
     */
    private function defaultConfigData()
    {
        return [
            'sidebar' => [
                'enabled' => true,
            ],
            'color' => [
                'primary' => '#4099de',
                'sidebar' => '#b3c1d1',
            ],
        ];
    }

    /**
     * 定义配置项,这些配置项应该可以从web界面管理并存储在数据库中。
     *
     * @return array 配置项。
     */
    private function persistentConfigItems(): array
    {
        return [
            'sidebar.enabled' => [
                'label' => 'Sidebar enabled',
                'rules' => ['sometimes', 'required', 'boolean'],
            ],
            'color.primary' => [
                'label' => 'Primary color',
                'rules' => ['sometimes', 'required', 'string'],
            ],
            'color.sidebar' => [
                'label' => 'Sidebar color',
                'rules' => ['sometimes', 'required', 'string'],
            ],
        ];
    }
}

它将允许您对每个用户记录分别操作持久配置,因此配置文件页面组合可以

如下图所示:

@php
/* @var $user AppModelsUser */ 
@endphp
@extends('layouts.main')

@section('content')
@if ($user->getConfig()->get('sidebar.enabled'))
    @include('includes.sidebar', ['color' => $user->getConfig()->get('color.sidebar')])
@endif
<div style="background-color:{{ $user->getConfig()->get('color.primary') }};">
    ...
</div>
@endsection

配置项规范

应该保存在持久存储中的配置部分由' IlluminatechConfigPersistentRepository::setItems() '定义,

它接受一个“IlluminatechConfigItem”列表或它的配置数组。

每个配置项都应该定义一个键,该键指向源存储库中的目标值。

配置项也有几个属性,它支持创建web界面进行配置设置。

这些都是:

  • 'id' - string,列表中项目的唯一id,该值将用于请求字段和表单输入。

  • 'label' -字符串,配置值输入的详细标签。

  • 'hint' -字符串,配置值或输入提示的详细描述。

  • 'rules' -数组,值验证规则。

  • 'cast' -字符串,要转换到的值的本机类型。

  • 'encrypt' - bool,是否加密存储的值。

  • 'options' -数组,项目的额外描述性选项,可以在你认为合适的时候使用。

由于只有'key'是必选项,项目可以通过定义该键的单个字符串指定。

以下是一些项目规格的例子:

<?php

use IlluminatechConfigItem;
use IlluminatechConfigPersistentRepository;

$persistentConfigRepository = (new PersistentRepository(...))
    ->setItems([
        'some.config.value',
        'another.config.value' => [
            'label' => 'Custom label',
            'rules' => ['required', 'numeric'],
        ],
        [
            'key' => 'array.config.value',
            'rules' => ['required', 'array'],
            'cast' => 'array',
        ],
        new Item(['key' => 'explicit.object']),
    ]);

配置存储

声明的配置项可以保存到持久存储中,然后从中检索。

实际的项目存储可以是任何匹配IlluminatechConfigStorageContract接口的类。

Following storages are available within this extension:

  • IlluminatechConfigStorageDb—将配置存储在关系数据库中;

  • IlluminatechConfigStorageEloquent -使用Eloquent模型存储配置;

  • IlluminatechConfigStoragePhp -将配置存储在本地PHP文件中;

  • IlluminatechConfigStorageArray -将配置存储在运行时内存中;

有关更多细节,请参阅特定的存储类。

保存和恢复数据

IlluminatechConfig persistentpository将自动从持久存储中检索配置项值

第一次尝试从中获取配置值。

<?php

use IlluminatechConfigPersistentRepository;

$persistentConfigRepository = (new PersistentRepository(...))
    ->setItems([
        'some.config',
    ]);

$value = $persistentConfigRepository->get('some.config'); // 自动从持久存储加载数据。

你也可以使用restore()方法手动从持久化存储中获取数据:

<?php

use IlluminatechConfigPersistentRepository;

$persistentConfigRepository = (new PersistentRepository(...))
    ->setItems([
        'some.config',
    ]);

$persistentConfigRepository->restore(); // loads/re-loads data from persistent storage

小心! 在值恢复过程中出现的任何错误或异常都会被自动抑制。这是 在存储还没有准备好使用的情况下避免应用程序阻塞,例如:数据库表还不存在。 存储失败错误只会出现在应用程序日志中。您应该手动测试恢复的值 您的应用程序以避免意外行为。 要将配置数据保存到持久存储中,请使用save()方法:

<?php

use IlluminatechConfigPersistentRepository;

$persistentConfigRepository = (new PersistentRepository(...))
    ->setItems([
        'some.config',
        'another.config',
    ]);

$persistentConfigRepository->save([
    'some.config' => 'some persistent value',
    'another.config' => 'another persistent value',
]);

通过常规配置库接口(例如通过方法set()push()等)进行的更改不会自动执行

保存到持久存储中。但是,你可以使用synchronize()方法将当前配置项的值保存到其中。

<?php

use IlluminatechConfigPersistentRepository;

$persistentConfigRepository = (new PersistentRepository(...))
    ->setItems([
        'some.config',
        'another.config',
    ]);

$persistentConfigRepository->set('some.config', 'new value'); // 在这一点上,持久存储没有更改

$persistentConfigRepository->synchronize(); // 将值保存到持久存储

提示:您可以在应用程序终止阶段调用synchronize(),以确保所做的所有更改 在应用程序运行期间保存。

方法reset()清除保存到持久存储的所有数据,恢复原始(例如默认)配置存储库的值。

<?php

use IlluminateConfigRepository;
use IlluminatechConfigPersistentRepository;

$sourceConfigRepository = new Repository([
    'some' => [
        'config' => 'original value',
    ],
]);

$persistentConfigRepository = (new PersistentRepository($sourceConfigRepository, ...))
    ->setItems([
        'some.config',
    ]);

$persistentConfigRepository->save([
    'some.config' => 'new value',
]);

echo $persistentConfigRepository->get('some.config'); // outputs 'new value'

$persistentConfigRepository->reset(); // clears data in the persistent storage

echo $persistentConfigRepository->get('some.config'); // outputs 'original value'

你也可以使用resetValue()方法来重置特定的配置键。

缓存

您可以使用PSR-16兼容缓存存储来提高配置项的性能

从持久存储中检索。例如:

<?php

use IlluminateConfigRepository;
use IlluminateSupportFacadesApp;
use IlluminatechConfigPersistentRepository;

$sourceConfigRepository = new Repository([
    'some' => [
        'config' => 'original value',
    ],
]);

$persistentConfigRepository = (new PersistentRepository($sourceConfigRepository, ...))
    ->setItems([
        'some.config',
    ])
    ->setCache(App::make('cache.store'))
    ->setCacheKey('global-config')
    ->setCacheTtl(3600 * 24);

验证

每个配置项都有验证规则,默认匹配[ sometimes required ]。你可以很容易地

在保存配置之前,使用这些规则或使用Illuminatech config PersistentRepository::validate()为用户输入创建一个验证。

例如:

<?php

/* @var $request IlluminateHttpRequest */
/* @var $config IlluminatechConfigPersistentRepository */

$validatedData = $config->validate($request->all()); // throws IlluminateValidationValidationException if validation fails.
// ...

你也可以使用IlluminatechConfig persistentpository::makeValidator()方法来创建一个手动处理的验证器实例。

小心! 如果你没有使用IlluminatechConfigPersistentRepository::validate()方法,请注意输入框中句点符号(.)的用法。

默认情况下,Laravel将验证规则中的dots视为数组嵌套键分隔符。你要么换掉它们

通过->字符串或手动定义IlluminatechConfigItem::$id,以使其不包含句点。

创建配置web界面

这个扩展最常见的用例之一是创建一个web界面,允许控制应用程序

运行时配置。

IlluminatechConfig persistentpository不仅用于应用配置-它还有助于创建一个

配置编辑界面。

用于配置管理的web控制器可能如下所示:

<?php

namespace AppHttpControllers;

use IlluminateHttpRequest;
use IlluminateContractsContainerContainer;

class ConfigController extends Controller
{
    /**
     * @var IlluminatechConfigPersistentRepository 持久化配置存储库,设置在`AppServiceProvider`。
     */
    private $config;

    public function __construct(Container $app)
    {
        $this->config = $app->get('config');
    }

    public function index()
    {
        $this->config->restore(); // 确保从数据库中恢复配置值

        return view('config.form', ['items' => $this->config->getItems()]);
    }

    public function update(Request $request)
    {
        $validatedData = $this->config->validate($request->all());

        $this->config->save($validatedData);

        return back()->with('status', 'success');
    }

    public function restoreDefaults()
    {
        $this->config->reset();

        return back()->with('status', 'success');
    }
}

你可以在HTML表单输入组合中操作IlluminatechConfigItem界面。例如:

...
<form ...>
...
@foreach ($items as $item)
    <label>{{ $item->label }}</label>
    <input type="text" name="{{ $item->id }}" value="{{ $item->getValue() }}">
    <p>{{ $item->hint }}</p>
@endforeach
...
</form>
...

提示:你可以使用IlluminatechConfigItem::$options来设置动态表单输入的配置,指定 输入类型,CSS类等等。

小心! 请记住,PHP会自动替换非字母数字字符,如点(.),破折号(-)等 在原生POST解析过程中,对config. conf等键进行收集和验证。一些关键的是不可能的。 你需要为每个持久配置项手动设置IlluminatechConfigItem::$id值,以防万一

<?php

use IlluminatechConfigPersistentRepository;

$persistentConfigRepository = (new PersistentRepository(...))
    ->setItems([
        'some.config.value' => [
            'id' => 'some_config_value',
        ],
        'another-config-value' => [
            'id' => 'another_config_value',
        ],
        // ...
    ]);

提示:如果您使用JSON通过REST API接口提交配置项值,则不会面临此问题

格式化或通过原生(不是伪造的)“把”的要求。

型态转换

可以将数组等复杂类型的值作为持久化值进行操作。为此,你应该指定config item

通过IlluminatechConfigItem::$cast进行类型转换。例如:

<?php

use IlluminateConfigRepository;
use IlluminatechConfigPersistentRepository;

$sourceConfigRepository = new Repository([
    'some' => [
        'array' => ['one', 'two', 'three'],
    ],
]);

$persistentConfigRepository = (new PersistentRepository($sourceConfigRepository, ...))
    ->setItems([
        'some.array' => [
            'cast' => 'array', // cast value from persistent storage to array
            'rules' => ['sometimes', 'required', 'array'],
        ],
    ]);

$persistentConfigRepository->save([
    'some.array' => ['five', 'six'],
]);

$persistentConfigRepository->restore();

var_dump($persistentConfigRepository->get('some.array') === ['five', 'six']); // outputs 'true'

加密

如果你打算操作敏感数据,如密码、API密钥等,你可能希望将它们存储为

加密字符串而不是普通字符串。这可以通过启用IlluminatechConfigItem::$encrypt来实现。

例如:

<?php

use IlluminateConfigRepository;
use IlluminatechConfigPersistentRepository;

$sourceConfigRepository = new Repository([
    'some' => [
        'apiKey' => 'secret',
    ],
]);

$persistentConfigRepository = (new PersistentRepository($sourceConfigRepository, ...))
    ->setItems([
        'some.apiKey' => [
            'encrypt' => true, // encrypt value before placing it into the persistent storage
        ],
    ]);

注意,数据加密会影响配置存储库的性能。

垃圾回收

随着项目的发展,可能会出现新的配置项,也可能会出现冗余的配置项。

IlluminatechConfigPersistentRepository自动忽略持久存储中的任何值,如果它没有

匹配由setItems()设置的配置项。因此,存储的废弃值无论如何不会影响配置库

它们仍然可能消耗额外的存储空间。您可以手动从存储中删除所有废弃的值,

使用gc()方法:

<?php

use IlluminateConfigRepository;
use IlluminatechConfigStorageDb;
use IlluminatechConfigPersistentRepository;

$sourceConfigRepository = new Repository([
    'some' => [
        'config' => 'original value',
    ],
]);

$storage = new StorageDb(...);
$storage->save([
    'some.config' => 'some value',
    'obsolete.config' => 'obsolete value',
]);

$persistentConfigRepository = (new PersistentRepository($sourceConfigRepository, $storage))
    ->setItems([
        'some.config',
    ]);

$persistentConfigRepository->gc(); // 删除过时的。从存储配置

如果启用了IlluminatechConfig persistentpository::$gcEnabled,垃圾回收将自动执行

每次配置值都通过save()synchronize()方法保存。

阿里云安全可靠、弹性可伸缩的云计算服务。百款产品直降,平均降幅20%,下方点击直达: