Php 在非';一捆
我正在为Symfony应用程序构建一个捆绑包,该应用程序使用了我编写的几个不同组件。我将把这个包称为MyAppBundle 我的bundle使用的组件本身并不依赖于Symfony,但我希望能够为每个组件定义一组Symfony服务,这些服务将在每个单独包的services.yml文件中定义,但我不希望这些包成为完整的bundle 为什么??因为我不希望软件包依赖于Symfony框架,我不想将软件包结构化为Symfony捆绑包,我希望能够通过注册单个MyAppBundle来注册我的应用程序所需的所有服务,同时,如果我愿意,我可以灵活地在一个无关的Symfony应用程序中使用这些组件提供的服务。如果我将这些包制作成完整的包,那么我必须在我的AppKernel中单独加载每个包,这是我不想要的 这应该很容易-根据文档,我只需要构建一个容器扩展: 因此,我为我的组件创建了一个容器扩展以加载其服务定义:Php 在非';一捆,php,symfony,Php,Symfony,我正在为Symfony应用程序构建一个捆绑包,该应用程序使用了我编写的几个不同组件。我将把这个包称为MyAppBundle 我的bundle使用的组件本身并不依赖于Symfony,但我希望能够为每个组件定义一组Symfony服务,这些服务将在每个单独包的services.yml文件中定义,但我不希望这些包成为完整的bundle 为什么??因为我不希望软件包依赖于Symfony框架,我不想将软件包结构化为Symfony捆绑包,我希望能够通过注册单个MyAppBundle来注册我的应用程序所需的所有
namespace MyComponent;
class MyComponentExtension extends \Symfony\Component\DependencyInjection\Extension\Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader->load('services.yml');
}
}
我只是不确定如何从MyAppBundle加载此扩展?关于如何从另一个bundle加载扩展的信息似乎很少。也许这不是推荐的做事方式,但出于上述原因,我认为我的用例是合理的
到目前为止,我从MyAppBundle加载MyComponentExtension的最佳尝试是:
namespace MyAppBundle;
class MyAppBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
$extensions = array(
new MyComponentExtension(),
new MyOtherComponentExtension()
);
$aliases = array();
foreach($extensions as $extension) {
$container->registerExtension($extension);
$aliases[] = $extension->getAlias();
}
$container->addCompilerPass(new MergeExtensionConfigurationPass($aliases));
}
}
“addCompilerPass”是从我能找到的一些小信息中收集到的,我敢肯定它是错的。执行此操作时,我无法访问MyComponentExtension提供的服务。我非常确定我只需要确保定义被正确地编译到容器中,但我不确定如何做到这一点 有两种类型的耦合:硬耦合和软耦合。 那么你就有了脱钩 解耦 当您将组件从捆绑包中解耦时,您可以使每个部分依赖于一个公共接口() 或者您可以具有单向依赖关系。在这种情况下,捆绑包将依赖于组件。一个示例是依赖于Symfony组件的Symfony框架包 对于第一个示例,您将使用配置来定义要使用的类。 然后,在第二个示例中,您将为组件的类定义捆绑包中的服务。同样,这就是Symfony框架包的作用 软耦合 这是指一个库引用另一个库(或另一个库的抽象),但不需要它(除非您尝试使用它,之后它间接成为硬依赖)。例如,如果缺少提供附加功能的资源,则会忽略这些附加功能 例如,将依赖项注入放在组件中,提供对Symfony的支持,但不需要它 例如,请查看
Symfony\Bridge\doctor\DependencyInjection\AbstractDoctrineExtension
常见的策略是创建一个抽象扩展,然后在bundle中重写它。
如果需要进一步集成,则捆绑包可以覆盖组件的部分()
任意一种方式
理想的情况是组件可以自己使用(),并且只使用Symfony将它们作为服务引导
解耦
Bundle => depends on => Component
Component depends on nothing
软依赖
Bundle => depends on => Component
Component -> supports -> Symfony
但是,您永远不应该创建一个双向依赖项。也就是说,每个部分静态地相互依赖
根据以下方式进行编辑:
你可以,尽管你为什么要这么做对我来说仍然是个谜
class MyAppBundle extends Bundle
{
/**
* Override extension getter.
*/
public function getContainerExtension()
{
if(null === $this->extension) {
$this->extension = new My\Component\Extension();
}
return $this->extension;
}
}
你可能会让事情变得更难。MyAppExtension可以轻松地从组件库加载services.yml。不需要组件扩展
class MyAppBundleExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$loader = new Loader\YamlFileLoader($container,
new FileLocator('path_to_component_library'));
$loader->load('services.yml');
}
获取组件库的路径是唯一的小挑战,但即使是硬编码,也不会太糟糕
说到这里,你真的应该考虑把桥牌捆绑到你的图书馆里去。它真正需要的只是一个Bundle类、扩展类和services.yml文件。您的库本身可以保持原样
桥是Symfony 2框架用来访问诸如Twig和Doctrine之类的库的东西。很肯定它们也会为你的图书馆工作。以:vendor/symfony/monolog bundle为例。下面是我最后选择的解决方案。我使用静态buildContainer方法在MyComponent中创建了一个loader类:
<?php
namespace MyComponent;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
class MyComponentLoader
{
/**
* Loads component services into a container.
*
* @param ContainerBuilder $container
*/
public static function buildContainer(ContainerBuilder $container)
{
$loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/Resources/config'));
$loader->load('services.yml');
}
}
感谢您提供了信息丰富的答案。事实上,我希望MyComponentExtension只对Symfony具有软依赖性,但您的回答没有告诉我如何从MyAppBundle正确注册我的ComponentExtension!在您给出的AbstractDoctrineExtension示例中,您仍然需要一个DoctrineBundle,它必须从AppKernel类中单独加载-这是我希望避免的情况,因为MyAppBundle应该加载MyComponentExtension本身。是的,但是Doctrine\Bundle\DoctrineBundle\DependencyInjection\DoctrineExtension
在bridge中扩展了AbstractDoctrineExtension
。我理解,但是DoctrineExtension是DoctrineBundle的一部分,只能通过注册DoctrineBundle来加载。我的问题是-我可以在我的应用程序中注册一个扩展,而不将该扩展作为捆绑包的一部分吗?更新以显示如何做到这一点。我先前的回答是试图让你们回到忠诚的道路上:这与我最终选择的方法有些相似。通过在我的组件中使用静态加载程序方法,我避免了硬编码路径。不制作桥接捆绑包的原因是我只想在AppKernel中加载一个捆绑包,而不需要单独加载其他依赖捆绑包
<?php
namespace MyAppBundle\DependencyInjection;
use MyComponent\MyComponentLoader;
use MyOtherComponent\MyOtherComponentLoader;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
class SmartCloneExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
MyComponentLoader::buildContainer($container);
MyOtherComponentLoader::buildContainer($container);
}
}