jelix / profiles
管理访问和凭证数据的API
Requires
- php: >=7.2
Requires (Dev)
- phpunit/phpunit: 8.5.*
This package is auto-updated.
Last update: 2024-09-05 10:07:44 UTC
README
管理包含访问和凭证数据的配置文件的API。
一个配置文件包含访问服务的必要信息。服务可以是数据库,例如一个Web API。在一个应用程序内部,您可以针对同一类型的服务有多个配置文件。
JelixProfiles 允许在ini文件中指定这些配置文件。所有的凭证都将存储在单个文件中。当您的应用程序的一个组件(让我们称它为“连接器”)需要有关配置文件的信息时,它将使用JelixProfiles。
安装
您可以使用Composer进行安装。在您的项目中
composer require "jelix/profiles"
配置
配置文件数据应存储在ini文件中。此文件包含应用程序组件所需连接参数:SQL和NoSQL数据库、SOAP Web服务、缓存等。
配置文件参数
每个部分对应一个配置文件。一个配置文件是一个连接参数集。部分名称由两个名称组成,用“:”分隔。
- 第一个名称是连接类型的名称,(通常对应组件名称)
- 第二个名称是您选择的名称。然而,有两个名称具有特殊含义:
default
表示在未提供配置文件名称时使用默认配置文件。还有__common__
,如下所述。
连接参数部分的内部内容。
以下是一个JelixDatabase组件的示例(它允许访问SQL数据库)
[jdb:default] driver=mysqli host=localhost login= mylogin password=mypassword
配置文件别名
您可以为某些配置文件定义一些别名,即对配置文件有多个名称。这在两个库使用不同的配置文件名称,但您希望这些库使用相同的连接参数时很有用。
别名在仅包含连接类型名称的章节中定义。以下是一个使用JelixDatabase的示例,为默认配置文件定义了别名“jacl2_profile”
[jdb] jacl2_profile = default [jdb:default] driver=mysqli host=localhost login= mylogin password=mypassword
别名不应链接到另一个别名。
通用参数
您可以定义适用于同一类型所有配置文件的通用参数。这避免了在每个配置文件中重复它们。为此,您必须在特殊的配置文件 __common__
中声明它们。
例如,如果所有SQL数据库的连接都必须持久且都在同一服务器上
[jdb:__common__] host=my.server.example.com persistant=on
您当然可以在配置文件中重新定义这些参数。
使用环境变量
ini文件由 parse_ini_file
函数读取,因此有特定的语法来指示来自ini文件外部的值。
- 您可以使用PHP常量
# somewhere in a file included by your index.php define("SOMETHING", "hello world");
在您的某个ini文件中
foo = SOMETHING
然后 foo 将具有值 "hello world"
。
- 您可以使用环境变量
# variables set in the environment of PHP-FPM, PHP-CLI, or Apache (with the PHP module) MYAPP_MYSQL_LOGIN=admin MYAPP_MYSQL_PASSWORD=Sup3Rp4ssw0rd!
例如,在您的ini文件中,您必须使用此语法 ${VARIABLE_NAME}
[jdb:default] driver=mysqli login= ${MYAPP_MYSQL_LOGIN} password= ${MYAPP_MYSQL_PASSWORD}
使用方法
您应使用 ProfilesReader
对象,该对象将读取ini文件,并将结果存储到 ProfilesContainer
对象中。使用此对象,您将能够获取配置文件的数据。
如果您有这种类型的 profiles.ini 文件
[jdb:default] driver=mysqli host=localhost login= mylogin password=mypassword
在使用JelixProfiles的组件代码中
$iniFile = '/somewhere/profiles.ini'; $cacheFile = '/somewhere/profiles.cache.json'; $reader = new \Jelix\Profiles\ProfilesReader(); /** @var \Jelix\Profiles\ProfilesContainer $profiles */ $profiles = $reader->readFromFile($iniFile, $cacheFile); // get the profile named 'foo' for the type 'jdb' $profile = $profiles->get('jdb', 'default'); $myDatabaseConnection = new Database( $profile['driver'], $profile['host'], $profile['login'], $profile['password'] );
请注意,您必须向 readFromFile
提供一个缓存文件。这允许JelixProfiles在加载ini文件期间保存额外的计算参数。
虚拟配置文件
您可以使用未在ini文件中声明的配置文件。因此,您可以使用只在执行期间知道的信息的连接。
虚拟配置文件必须在使用您的组件之前创建。使用 createVirtualProfile()
方法的对象 ProfilesContainer
并传递连接类型的名称、一个名称和参数数组。
示例
// let's retrieve a profiles container $iniFile = '/somewhere/profiles.ini'; $cacheFile = '/somewhere/profiles.cache.json'; $reader = new \Jelix\Profiles\ProfilesReader(); /** @var \Jelix\Profiles\ProfilesContainer $profiles */ $profiles = $reader->readFromFile($iniFile, $cacheFile); // now create our virtual profile $params = array( 'driver'=>'mysqli', 'host'=>'localhost', 'database'=>'jelix', 'user'=>'toto', 'password'=>'blabla', 'persistent'=>false, 'force_encoding'=>true ); $profiles->createVirtualProfile('jdb', 'my_profil', $params); // somewhere else $profile = $profiles->get('jdb', 'my_profil'); //...
当然,在__common__
配置文件中定义的所有参数都适用于虚拟配置文件。
使用插件检查参数
连接器,使用配置文件的对象,可能期望有特定的参数。在使用参数之前,它可能需要检查参数是否正确。它甚至可能需要根据在给定参数中找到的值“计算”一些其他参数。
为了避免每次连接器实例化时都执行这些检查或计算,JelixProfiles提供了一个解决方案,在首次读取配置文件时处理这些事情,然后最终参数存储在配置文件的缓存文件中。
您可以提供一个插件,用于为特定类别的配置文件执行这些检查和计算。这是一个应该继承自Jelix\Profiles\ReaderPlugin
的类,并实现了接收参数数组作为参数的consolidate
方法,并返回完整的配置文件。
示例
// example of a plugin that process a profile containing access parameters to an SQL database class myDbPlugin extends \Jelix\Profiles\ReaderPlugin { protected function consolidate($profile) { $newProfile = $profile; // Check that the `host` parameter does exist if (!isset($profile['driver']) || $profile['driver'] == '' || !isset($profile['host']) || $profile['host'] == '' || !isset($profile['database']) || $profile['database'] == '' ) { throw new \Exception('host or database are missing from the profile'); } // check if port is present, if not, let's set a default value if (!isset($profile['port']) { $profile['port'] = 1234; } if ($driver == 'pgsql') { // let's generate a connection string $newProfile['connectionstr'] = 'host='.$profile['host'].';port='.$profile['port'].'database='.$profile['database']; } // here you probably want to do more checks etc, but for the example, it is enough. // return a new profile, that is ready to be used by your database connection object without checking // parameters or calculate connectionstr, at each http requests, because all these parameters will be stored // into a cache by ProfilesReader return $newProfile; } }
接下来,您必须通过给出每个类别的插件列表来指示配置文件读取器。
$reader = new \Jelix\Profiles\ProfilesReader([ // category name => plugin class name 'db' => 'myDbPlugin' ]);
另一种方法是提供一个回调函数,该函数将返回给定类别的插件。如果您的插件具有特定的构造函数,或者类以特定的方式加载,这很有用。
class myDbPlugin extends \Jelix\Profiles\ReaderPlugin { // for the example, let's redefine the constructor to have a different constructor than ReaderPlugin... public function __construct() {} // ... } $reader = new \Jelix\Profiles\ProfilesReader(function($category) { if ($category == 'db') { return new myDbPlugin(); } return null; });
使用插件自动实例化连接器
我们看到了您可以检索配置文件,然后您必须将其提供给您的连接器对象。
$profile = $profiles->get('jdb', 'default'); $myDatabaseConnection = new Database( $profile['driver'], $profile['host'], $profile['login'], $profile['password'] );
ProfilesContainer
有一个方法可以自动实例化与配置文件对应的连接器,并且它还允许在整个HTTP请求过程中使用相同的连接器对象。这使得您的代码更轻量。
$myDatabaseConnection = $profiles->getConnector('jdb', 'default');
为了使用此方法,插件必须实现Jelix\Profiles\ProfileInstancePluginInterface
。它有两个方法,getInstanceForPool($name, $profile)
和closeInstanceForPool($name, $instance)
。
第一个方法是实例化连接器对象。它由getConnector
调用。第二个方法应该终止连接器对象。例如,如果连接器对象维护到数据库的连接,closeInstanceForPool()
应调用其关闭连接的方法。
class myDbPlugin extends \Jelix\Profiles\ReaderPlugin implements { protected function consolidate($profile) { // ... } public function getInstanceForPool($name, $profile) { return new Database( $profile['driver'], $profile['host'], $profile['login'], $profile['password'] ); } /** * @param string $name * @param Database $instance * @return void */ public function closeInstanceForPool($name, $instance) { $instance->close() } }