在开发符合聚会的束缚时,我们可能需要根据某些条件创建服务。在这种情况下,我们必须使用我们的捆绑扩展类类实现它,而不是在服务文件上定义服务。
让我们看看一个简单的示例。想象一下,我们正在创建一个可以根据其配置的多种方式连接到Redis的捆绑包:
- 案例1 :捆绑配置定义主机和端口
- 案例2 :捆绑配置定义URI Connection
- 案例3 :捆绑配置定义了redis袜子路径
按照我们刚刚定义的情况,我们将创建一项服务,该服务将连接到REDIS,将其考虑在内。我们的服务看起来像这样:
class RedisWrapper {
public function __construct(
public readonly Predis\Client $client
){ }
// .......
}
配置类
配置类使用 symfony \ component \ config \ definition \ builder \ treebuilder 类定义捆绑配置参数。它保留在de depentencyIndoction 文件夹中,该文件夹必须位于您的束根dir中。
让我们看看它的外观:
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
class MyBundleConfiguration implements ConfigurationInterface
{
public function getConfigTreeBuilder(): TreeBuilder
{
$tb = new TreeBuilder('ict_api_one_endpoint');
$tb
->getRootNode()
->children()
->scalarNode('host')
->defaultNull()
->end()
->scalarNode('port')
->defaultValue(6379)
->end()
->scalarNode('uri')
->defaultNull()
->end()
->scalarNode('sock_path')
->defaultNull()
->end()
;
return $tb;
}
}
方法 getConfigtreeBuilder 将捆绑配置返回为 treebuilder 对象。如我们所见,所有参数都是可选的。每种情况的配置将为以下:
情况1
my_bundle_name:
host: 195.230.65.145
port: 6379
案例2
my_bundle_name:
uri: 'tcp://195.230.65.145:6379'
案例3
my_bundle_name:
sock_path: '/path/to/my.sock'
您可以探索有关配置的更多信息here
现在,是时候根据最后可能的配置来创建服务。
扩展文件
扩展文件将加载捆绑到安装项目的服务和参数。作为配置类,扩展类也保留在 depentencyInjection 文件夹中。
通常,它首先使用Bundle Services文件加载容器(通常位于 Resources/config 文件夹下),然后根据配置的参数值加载配置。
让我们看看它的外观
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\Reference;
class IctApiOneEndpointExtension extends Extension
{
/**
* @throws \Exception
*/
public function load(array $configs, ContainerBuilder $container): void
{
$loader = new XmlFileLoader($container, new FileLocator(dirname(__DIR__).'/Resources/config'));
$loader->load('services.xml');
$configuration = new IctApiOneEndpointConfiguration();
$config = $this->processConfiguration($configuration, $configs);
if(!empty($config['host']) && !empty($config['port'])) {
$container
->register('my.redis_client', Predis\Client::class)
->addArgument(['scheme' => 'tcp', 'host' => $config['host'], 'port' => $config['port']])
;
}
else if(!empty($config['uri'])) {
$container
->register('my.redis_client', Predis\Client::class)
->addArgument($config['uri'])
;
}
else{
if(empty($config['sock_path'])) {
throw new \RuntimeException('Missing arguments for loading bundle');
}
$container
->register('my.redis_client', Predis\Client::class)
->addArgument(['scheme' => 'unix', 'host' => $config['sock_path']])
;
}
$container
->register('my.redis_wrapper', RedisWrapper::class)
->addArgument(new Reference('my.redis_client'))
;
}
}
让我们逐步探索扩展代码:
$loader = new XmlFileLoader($container, new FileLocator(dirname(__DIR__).'/Resources/config'));
$loader->load('services.xml');
$configuration = new IctApiOneEndpointConfiguration();
$config = $this->processConfiguration($configuration, $configs);
这是所有扩展类通常开始的。它只需从XML或YAML服务文件加载容器即可。然后,它从项目安装程序配置的值处理捆绑配置。
if(!empty($config['host']) && !empty($config['port'])) {
$container
->register('my.redis_client', Predis\Client::class)
->addArgument(['scheme' => 'tcp', 'host' => $config['host'], 'port' => $config['port']])
;
}
如果 host 和 port 参数不是空的,它会从 predis \ client \ client 类中登录服务,以:
- 方案:通常TCP
- 主机:主机配置参数的值
- 端口:端口配置参数的值
else if(!empty($config['uri'])) {
$container
->register('my.redis_client', Predis\Client::class)
->addArgument($config['uri'])
;
}
如果 uri 参数不是空的,则我们注册相同的服务,但作为参数通过REDIS URI连接。
else{
if(empty($config['sock_path'])) {
throw new \RuntimeException('Missing arguments for loading bundle');
}
$container
->register('my.redis_client', Predis\Client::class)
->addArgument(['scheme' => 'unix', 'host' => $config['sock_path']])
;
}
作为最后一个选项,如果 sock_path 参数为空A \ runtimeTimeExeption ,因为没有更多选项登记连接。否则,我们注册服务,但通过以下方式将其作为参数作为参数。
- 方案:unix
- 主机: sock_path 值
$container
->register('my.redis_wrapper', RedisWrapper::class)
->addArgument(new Reference('my.redis_client'))
;
最后,我们注册 rediswrapper 服务添加为参数a 参考 my.redis_client
因此,我们允许开发人员配置此捆绑包,然后给出3个选项:
- 使用主机和端口
- 使用URI连接
- 使用袜子路径
如果您阅读了predis docs,您将在“ 连接到redis ”部分上看到 predis \ client \ client class可以作为参数接受我们刚刚看到的三种情况。这篇文章。
您可以在我的secrets bundle
中看到类似的情况