我在我的parameters.yml
文件中创建了一个参数:
parameters:
category:
var: test
如何在我的config.yml
? 例如,我想将此参数作为全局 twig 变量传递给我的所有 twig 文件:
twig:
globals:
my_var: %category.var% # throws ParameterNotFoundException
我在我的parameters.yml
文件中创建了一个参数:
parameters:
category:
var: test
如何在我的config.yml
? 例如,我想将此参数作为全局 twig 变量传递给我的所有 twig 文件:
twig:
globals:
my_var: %category.var% # throws ParameterNotFoundException
在我见过的所有 symfony 配置文件中,'parameters:' 下的条目总是完全限定的。我不完全理解为什么会这样,但它可以帮助您在 parameters.yml 中编写条目,如下所示:
category1.var1: xxx
category1.var2: yyy
category1.var3. zzz
category2.subcategory1.var1: 5
category2.subcategory1.var2: 10
category2.subcategory2.var1: foo
category2.subcategory2.var2: bar
... 等等。
我尝试将问题中的嵌套参数粘贴到我的一个项目中的 parameters.local.yml 中,并运行一个简单的单元测试来检索该参数和容器中的完全限定参数,例如
$testUserEmail = $container->getParameter('test.user.email');
$this->assertEquals('dahlia.flower@randomtest.com', $testUserEmail);
$testParam = $container->getParameter('category.var');
$this->assertEquals('test', $testParam);
完全限定参数很好,尝试获取嵌套参数导致InvalidArgumentException
:category.var
必须定义参数。我不认为参数可以用嵌套来定义。
$this->container->getParameter('category')['var']
我已经在 symfony 2.8 上测试过了,它对我有用。
或者您可以编写简单的 ParameterBag 可以动态实现嵌套参数(没有配置值重复):
<?php
namespace Your\Namespace;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
class ParameterBagNested extends ParameterBag
{
/**
* wire $this->set() logic into add() too
*
* @param array $parameters
*/
public function add( array $parameters )
{
foreach ( $parameters as $name => $value ) {
$this->set( $name, $value );
}
}
/**
* sets all levels of nested array parameters with dot notation
* - loggly[host: loggly.com] will be translated this way:
* - loggly: [host: loggly.com] - standard array parameter will be left as is
* - loggly.host: loggly.com - nested variables ar translated so you can access them directly too as parent.variable
*
* @param string $name
* @param mixed $value
*/
public function set( $name, $value )
{
if ( $this->has( $name ) ) {
// this is required because of array values
// we can have arrays defined there, so we need to remove them first
// otherwise some subvalues would to remain in the system and as a result, arrays would be merged, not overwriten by set()
$this->remove( $name );
}
$this->setNested( $name, $value );
}
/**
* remove checks even if name is not array
*
* @param string $name
*/
public function remove( $name )
{
$value = $this->get( $name );
if ( is_array( $value ) ) {
foreach ( $value as $k => $v ) {
$this->remove( $name . '.' . $k, $v );
}
}
if ( strpos( $name, '.' ) !== FALSE ) {
$parts = explode( '.', $name );
$nameTopLevel = reset( $parts );
array_shift( $parts );
$topLevelData = $this->removeKeyByAddress( $this->get( $nameTopLevel ), $parts );
ksort( $topLevelData );
$this->setNested( $nameTopLevel, $topLevelData );
}
parent::remove( $name );
}
/**
* @param array $data
* @param array $addressParts
*
* @return array
*/
private function removeKeyByAddress( $data, $addressParts )
{
$updatedLevel = & $data;
$i = 1;
foreach ( $addressParts as $part ) {
if ( $i === count( $addressParts ) ) {
unset( $updatedLevel[$part] );
} else {
$updatedLevel = & $updatedLevel[$part];
$i++;
}
}
return $data;
}
/**
* @see set()
*
* @param string $name
* @param mixed $value
*/
private function setNested( $name, $value )
{
if ( is_array( $value ) ) {
foreach ( $value as $k => $v ) {
$this->setNested( $name . '.' . $k, $v );
}
}
parent::set( $name, $value );
}
}
phpunit 测试:
<?php
namespace Your\Namespace;
use Symfony\Component\DependencyInjection\Tests\ParameterBag\ParameterBagTest;
/**
* its essential to use ParameterBagNested as ParameterBag because this way we run even parent class tests upon it
* parent class is part of Symfony DIC standard test suite and we use it here just for check if our parameter bag is still ok
*/
use SBKS\DependencyInjection\ParameterBag\ParameterBagNested as ParameterBag;
/**
* testing basic and even added ParameterBag functionality
*/
class ParameterBagNestedTest extends ParameterBagTest
{
public function testConstructorNested()
{
$bag = new ParameterBag(
array(
'foo' => array( 'foo1' => 'foo' ),
'bar' => 'bar',
)
);
$this->assertEquals(
array(
'foo.foo1' => 'foo',
'foo' => array(
'foo1' => 'foo',
),
'bar' => 'bar',
),
$bag->all(),
'__construct() takes an array of parameters as its first argument'
);
}
public function testRemoveNested()
{
$bag = new ParameterBag(
array(
'foo' => array(
'foo1' => array(
'foo11' => 'foo',
'foo12' => 'foo',
),
'foo2' => 'foo',
),
'bar' => 'bar',
)
);
$bag->remove( 'foo.foo1.foo11' );
$this->assertEquals(
array(
'foo' => array(
'foo1' => array(
'foo12' => 'foo',
),
'foo2' => 'foo',
),
'foo.foo1' => array( 'foo12' => 'foo' ),
'foo.foo1.foo12' => 'foo',
'foo.foo2' => 'foo',
'bar' => 'bar',
),
$bag->all(),
'->remove() removes a parameter'
);
$bag->remove( 'foo' );
$this->assertEquals(
array(
'bar' => 'bar',
),
$bag->all(),
'->remove() removes a parameter'
);
}
public function testSetNested()
{
$bag = new ParameterBag(
array(
'foo' => array(
'foo1' => array(
'foo11' => 'foo',
'foo12' => 'foo',
),
'foo2' => 'foo',
),
)
);
$bag->set( 'foo', 'foo' );
$this->assertEquals( array( 'foo' => 'foo' ), $bag->all(), '->set() sets the value of a new parameter' );
}
public function testHasNested()
{
$bag = new ParameterBag(
array(
'foo' => array(
'foo1' => array(
'foo11' => 'foo',
'foo12' => 'foo',
),
'foo2' => 'foo',
),
)
);
$this->assertTrue( $bag->has( 'foo' ), '->has() returns true if a parameter is defined' );
$this->assertTrue( $bag->has( 'foo.foo1' ), '->has() returns true if a parameter is defined' );
$this->assertTrue( $bag->has( 'foo.foo1.foo12' ), '->has() returns true if a parameter is defined' );
$this->assertTrue( $bag->has( 'foo.foo2' ), '->has() returns true if a parameter is defined' );
}
}
然后您可以通过将 Parameter bag 注入 ContainerBuilder来使用它:
$parameterBag = new \Your\Namespace\ParameterBagNested();
$container = new ContainerBuilder($parameterBag);
就是这样,您现在可以在 Symfony DI 容器中使用带有点符号的嵌套参数。
如果您在 phpstorm 中使用 Symfony 插件,它也会使用点符号自动完成您的嵌套属性。
有点晚了,但这是一个对我有用的解决方案。
# app/config/config.yml
twig:
globals:
my_var: category['var']
当您将参数文件导入app/config/config.yml
文件时,您可以自动访问参数文件中定义的所有变量。
请记住,当您使用该结构时:
# app/config/parameters.yml
parameters:
category:
var: test
您正在定义一个category
使用值调用的参数,该值本身又是一个键值对数组,包含var
键和test
值。
在较新版本的 symfony (3.4 - 4.2) 中,您现在可以执行以下操作:
# app/config/config.yml
twig:
globals:
custom_categories: '%categories%'
通过设置此参数:
# app/config/parameters.yml
parameters:
categories:
- category_A
- category_B
这里要注意的事情: - 在 parameters.yml 类别中是一个数组
所以要在树枝模板中使用它,您应该能够执行以下操作:
<ul>
{% for category in categories %}
<li> {{ category }} </li>
{% endfor %}
</ul>
另一个对象示例:
# app/config/parameters.yml
parameters:
marketplace:
name: 'My Store'
address: '...'
配置树枝变量:
# app/config/config.yml
twig:
globals:
marketplace: '%marketplace%'
在树枝中使用它:
...
<p>{{marketplace.name}}</p>
<p>{{marketplace.address}}</p>
...
希望这可以帮助!:)
Symfony 的表达式语言语法来救援!试一试:
twig:
globals:
my_var: '@=parameter("category")["var"]'
为了提供一种不需要从 setter 中删除值的替代方法,我重写了 getter 方法。
namespace NameSpaceFor\ParameterBags;
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
class ParameterBagParser extends ParameterBag
{
/**
* {@inheritDoc}
*/
public function get($name, $parent = null)
{
if (null === $parent) {
$parent = $this->parameters;
}
$name = strtolower($name);
if (!array_key_exists($name, $parent)) {
if (!$name) {
throw new ParameterNotFoundException($name);
}
if (false !== strpos($name, '.')) {
$parts = explode('.', $name);
$key = array_shift($parts);
if (isset($parent[$key])) {
return $this->get(implode('.', $parts), $parent[$key]);
}
}
$alternatives = [];
foreach ($parent as $key => $parameterValue) {
$lev = levenshtein($name, $key);
if ($lev <= strlen($name) / 3 || false !== strpos($key, $name)) {
$alternatives[] = $key;
}
}
throw new ParameterNotFoundException($name, null, null, null, $alternatives);
}
return $parent[$name];
}
}
它递归地遍历名称,直到检查完所有点符号。
所以它将适用于数组和标量值。
配置.yml:
parameters:
my_param:
- test
my_inherited: '%my_param.0%' #test
容器感知:
$container->getParameter('my_param')[0]; //test
模拟嵌套参数的技巧,在 yaml 文件中访问:
parameters:
crawler:
urls:
a: '%crawler.urls.a%' # here the root of the rest of the tree/array
crawler.urls.a:
cat1:
- aa
- bb
cat2:
- cc
services:
xx:
class: myclass
arguments:
$urls: '%crawler.urls.a%'
在 Symfony 中,我现在将参数('crawler')作为完整树访问,在服务 xx 中,子树/数组是可访问的。