避免两个模块中的实体之间的循环依赖关系

时间:2013-02-07 10:39:08

标签: doctrine-orm zend-framework2

如果我有相互引用的doctrine2实体,我现在想知道将ZF2模块可复制从一个项目到另一个项目的好方法。

我目前的情况是这样的:我有一个实体User,我希望能够访问该用户所说的所有语言。

当然,Language不是Authentication模块的一个组件,因为我可能也想将它用于其他目的。

namespace Authentication\Entity;

class User {
    public function getSpokenLanguages();
}

namespace Application\Entity;

class Language {
    public function getUsersWhoSpeakThisLanguage();
}

问题是,我希望我的Authentication模块完全独立于项目特定的模块Application

是否有一种很好的方法可以将这些关系从我的实体中删除,或者可能从Application模块注入它们?也许UserService(在Application模块中)为我提供特定Language[]的语言User会是一个好主意吗?我可以这样称呼它:

$userService->getUsersLanguages($user);

我认为,特别是注入可能是一个ZF2解决方案,但我不知道,如何从另一个模块扩展Doctrine2实体。

1 个答案:

答案 0 :(得分:1)

我认为你说的是​​更多的语义问题而不是特定于ZF2的语义问题。阅读你的问题,我认为你的语言变得更像是一个托管层,你可以轻松地与工厂和DI一起促进 - 幸运的是ZF2拥有所有合适的工具。考虑这样的事情作为解决方案的潜在草案:

创建 LanguageAbstractFactory

namespace Your\Namespace;

use Zend\ServiceManager\AbstractFactoryInterface,
    Zend\ServiceManager\ServiceLocatorInterface;

class LanguageAbstractFactory implements AbstractFactoryInterface
{
    /**
     * Determine if we can create a service with name
     *
     * @param ServiceLocatorInterface $serviceLocator
     * @param                         $name
     * @param                         $requestedName
     * @return bool
     */
    public function canCreateServiceWithName( ServiceLocatorInterface $serviceLocator, $name, $requestedName )
    {
        return stristr( $requestedName, 'Namespace\Language' ) !== false;
    }


    public function createServiceWithName(ServiceLocatorInterface $locator, $name, $requestedName)
    {
        $filter = new $requestedName();
        $filter->setServiceLocator( $locator );
        return $filter;
    }

}

然后,在同一名称空间中创建语言,作为语言的子类,实现 ServiceLocatorAwareInterface (以便为您提供数据库访问等)。上面工厂中的代码注入了服务定位器(在那里你调整它以注入其他优点以满足你的语言架构):

namespace Your\Namespace;

use Zend\ServiceManager\ServiceLocatorAwareInterface,
    Zend\ServiceManager\ServiceLocatorInterface;


class Language implements ServiceLocatorAwareInterface
{

    protected $serviceLocator;


    public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
    {
        $this->serviceLocator = $serviceLocator;
    }

    public function getServiceLocator()
    {
        return $this->serviceLocator;
    }

    // ... other things your factory knows, that this class may not go here
}

语言实现可能如下所示:

namespace Your\Namespace\Language;

class English extends \Your\Namespace\Language
{

    public function getUsersWhoSpeakThisLanguage()
    {
        $sm = $this->getServiceManager();
        // get your entities or w/e using the SM
    }
}

通过在getServiceConfig上调整模块的Module.php来连接工厂:

public function getServiceConfig(){         返回数组(

        'abstract_factories' => array(
            // this one generates all of the mass email filters
            'Your\Namespace\LanguageAbstractFactory',
        ),

    );
}

这使您能够使用服务管理器轻松获取服务感知语言。例如,来自服务感知类:

$sm->getServiceManager()->get( '\Your\Namespace\Language\English' );

由于配置以及Factory可以满足请求,您的工厂将以非常便携的方式使用您构建的任何逻辑自动配置英语实例。

这是对Factories的一种入门 - 如果您使用了服务可以用来与您的用户类对话的接口类,您可以将控制权从用户转换为语言服务。让用户实现LanguageAware(例如)包含语言服务可以使用的类应该只需几步之遥。

希望这会有所帮助。这种猫可能有15种方法可以去皮;这种方法是我用来解决类似问题的方法,例如“过滤”数据。过滤器可以过滤信息,并且过滤器可以过滤信息。

祝你好运!