在Symfony 3中整个应用程序中可重用值的最佳方法是什么?

时间:2017-01-22 19:30:56

标签: model-view-controller twig symfony

我希望有一个文件或列表,我可以使用可能在整个应用程序中更改的值轻松更新。

我真的不想将文本值硬编码到模板中。我更喜欢将所有这些值放在一个地方并正确标记。

可能会更新的值的示例包括:

  • 页面标题
  • 徽标文字
  • 品牌或公司名称

我考虑过两个选择:

  1. 将它们添加到config.yml中的twig配置中。这有点乱,如果我决定把很多价值放在那里,那似乎没有组织。
  2. 为这些创建数据库表,并在每个需要使用值的控制器中包含实体。这可能会造成太多的工作。
  3. 还有其他选择还是其中一种更适合?

    谢谢。

1 个答案:

答案 0 :(得分:2)

您需要创建一个twig函数并使用它来返回所需的值。例如:

namespace AppBundle\Twig;

use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
use Symfony\Component\DependencyInjection\ContainerInterface;

class TwigExtension extends \Twig_Extension implements ContainerAwareInterface
{

    use ContainerAwareTrait;

    /**
     * @var ContainerInterface
     */
    protected $container;

    public function getFunctions()
    {
        return array(
            new \Twig_SimpleFunction('parameter', function($name)
            {
                try {
                    return $this->container->getParameter($name);
                } catch(\Exception $exception) {
                    return "";
                }
            })
        );
    }

    /**
     * Returns the name of the extension.
     *
     * @return string The extension name
     */
    public function getName()
    {
        return 'app.twig.extension';
    }
}

这将创建一个名为parameter的函数,一旦你在twig {{ parameter('my.parameter') }}中调用它,它将返回参数。您需要将其作为服务加载,您可以通过将以下内容添加到services.yml文件来执行此操作:

app.twig.extension:
    class: AppBundle\Twig\TwigExtension
    calls:
        - [setContainer, ["@service_container"]]
    tags:
        - { name: twig.extension }

从个人经验来看,人们通常希望能够改变一些参数。这就是为什么我通常更喜欢创建一个SettingParameter实体,它看起来像这样:

/**
 * Setting
 *
 * @ORM\Table(name="my_parameters")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\ParameterRepository")
 */
class Parameter
{
    /**
     * @var integer
     *
     * @ORM\Id
     * @ORM\Column(name="parameter_id", type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255)
     */
    private $name;

    /**
     * @var string
     *
     * @ORM\Column(name="value", type="text", nullable=true)
     */
    private $value;

    /**
     * @param string|null $name
     * @param string|null $value
     */
    public function __construct($name = null, $value = null)
    {
        $this->setName($name);
        $this->setValue($value);
    }

    /**
     * Get id
     *
     * @return integer
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     *
     * @return Parameter
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Set value
     *
     * @param string $value
     *
     * @return Parameter
     */
    public function setValue($value = null)
    {
        $this->value = serialize($value);

        return $this;
    }

    /**
     * Get value
     *
     * @return string
     */
    public function getValue()
    {
        $data = @unserialize($this->value);

        return $this->value === 'b:0;' || $data !== false ? $this->value = $data : null;
    }
}

然后我会添加一个CompilerPass,它将帮助从数据库中获取所有参数并缓存它们,以便您的应用程序不会对数据库进行不必要的SQL查询。这可能看起来类似于以下类:

// AppBundle/DependencyInjection/Compiler/ParamsCompilerPass.php
namespace AppBundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

class ParamsCompilerPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        $em       = $container->get('doctrine.orm.default_entity_manager');
        $settings = $em->getRepository('AppBundle:Parameter')->findAll();

        foreach($settings as $setting) {
            // I like to prefix the parameters with "app." 
            // to avoid any collision with existing parameters.
            $container->setParameter('app.'.strtolower($setting->getName()), $setting->getValue());
        }
    }
}

最后,在您的bundle类(即src/AppBundle/AppBundle.php)中添加编译器传递:

namespace AppBundle;

use AppBundle\DependencyInjection\Compiler\ParamsCompilerPass;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;

class AppBundle extends Bundle
{
    public function build(ContainerBuilder $builder)
    {
        parent::build($builder);
        $builder->addCompilerPass(new ParamsCompilerPass(), , PassConfig::TYPE_AFTER_REMOVING);
    }
}

现在,您可以创建DoctrineFixture模板来加载您一直使用的参数。使用TwigExtension,您仍然可以从树枝模板调用参数,并且可以创建Web UI来更改某些参数/设置。