Zend Framework 2将变量传递给模型

Mpk*_*pk1 5 php multilingual models zend-framework2

我目前正在开发一个多语言网站.对于多语言部分,我使用翻译器/ poedit.我将所选语言存储在会话中.它工作正常.

Module.php:

public function onBootstrap(MvcEvent $e)
{
    // ...

    $session = new Container('base');

    if ($session->language !== NULL) {
        $e->getApplication()->getServiceManager()->get('translator')->setLocale($session->language);
    }
}
Run Code Online (Sandbox Code Playgroud)

在控制器中设置语言的操作:

public function setLanguageAction()
{
    $language = $this->params()->fromRoute('language');

    if (isset($this->languages[$language])) {

        $session = new Container('base');

        if ($language == 'en') {
            $session->language = NULL;
        } else {
            $session->language = $language;
        }
    }

    return $this->redirect()->toRoute('home');
}
Run Code Online (Sandbox Code Playgroud)

在module.config.php中,默认语言环境设置为en.

正如我说的一切正常,除了一件事.

我也在DB中存储了一些与语言相关的数据,所以在我的模型中我需要知道当前的语言是什么.模型中的其他用途也需要当前语言.

所以我在每个模型的构造函数中包含以下代码:

$session = new Container('base');

if ($session->language !== NULL) {
    $this->language = $session->language;
} else {
    $this->language = 'default';
}
Run Code Online (Sandbox Code Playgroud)

我认为这不是最好的解决方案.我有太多的模型总是包含这个代码.

我想知道是否有一个解决方案可以自动将$ language变量传递给我的所有模型,例如Module.php/getServiceConfig函数:

public function getServiceConfig()
{        
    $session = new Container('base');

    return array(
        'factories' => array(
            'Application\Model\SomeThing' => function($sm) {
                $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
                $c = new SomeThing($dbAdapter);
                $c->language = $session->language;
                return $c;
            }
        )
    );
}
Run Code Online (Sandbox Code Playgroud)

当然这不起作用,但是能够做类似这样的事情或更通用的解决方案会很棒,因为没有必要将当前语言的值分配给工厂数组中的每个模型的语言变量(例如,模型的通用引导程序,可以在一个地方为所有模型完成此分配).

我的问题有解决方案吗?

谢谢您的帮助!

中号

And*_*708 4

如果您不想将语言注入到所有模型中,那么我至少可以想到另一种方法。

您可以使用初始化程序。初始化程序基本上允许您对通过服务管理器获取的服务执行初始化任务。因此,要使用这种方法,您必须通过服务管理器获取模型(至少是需要该语言的模型)。如果您需要注入任何依赖项,这就像将它们添加为可调用或工厂一样简单。有关初始化程序的更多信息,您可以阅读我撰写的有关服务管理器的文章(向下滚动到有关初始化程序的部分)。

因此,您可以做的是让您的模型实现一个接口,例如LanguageAwareInterface

namespace User\Model;

interface LanguageAwareInterface {
    /**
    * Gets the language
    *
    * @return string
    */
    public function getLanguage();

    /**
    * Sets the language
    *
    * @param string $language
    */
    public function setLanguage($language);
}
Run Code Online (Sandbox Code Playgroud)

然后您可以在模型中执行以下操作。

namespace User\Model;

class MyModel implements \User\Model\LanguageAwareInterface {
    /**
    * @var string $language The current language
    */
    protected $language;

    /**
    * Gets the language
    *
    * @return string
    */
    public function getLanguage() {
        return $this->language;
    }

    /**
    * Sets the language
    *
    * @param string $language
    */
    public function setLanguage($language) {
        $this->language = $language;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您愿意,您甚至可以创建一个具有上述代码的抽象基模型类,或者如果您想避免扩展类,则可以编写一个简单的特征。然后,每个模型都可以扩展这个基类,但这取决于有多少模型实际上需要使用当前语言。

现在是初始化程序。在我的文章中,我有一个如何通过方法调用添加它的示例,但您很可能希望在配置文件中执行此操作(Application如果您使用的是 Zend Skeleton 应用程序,则可能在模块中)。Module您可以在方法中从模块的类返回一个数组(或指向配置文件)getServiceConfig(),也可以将其添加到该键YourModule/config/module.config.php下的文件中service_manager。官方文档没有给出任何这方面的例子;事实上,初始化器是唯一缺少的东西。然而,它应该有效。

return array(
    /* Other configuration here */

    'service_manager' => array(
        'initializers' => array(
            'language' => function($service, $sm) {
                // $service is the service that is being fetched from the service manager
                // $sm is the service manager instance
                if ($service instanceof \User\Model\LanguageAwareInterface) {
                    $session = new \Zend\Session\Container('base');

                    if ($session->language === null) {
                        // Fetch default language from configuration
                        $config = $sm->get('Config');

                        $session->language = $config['translator']['locale'];
                    }

                    $service->setLanguage($session->language);
                }
            },
        ),
    ),
);
Run Code Online (Sandbox Code Playgroud)

上面的初始化程序检查从服务管理器获取的每个对象,看看它是否实现了我们上面创建的接口。如果是,则可以注入语言。在我的示例中,我检查会话中是否设置了它,如果没有,则从配置中获取它。您可能需要根据您的具体需求调整逻辑。请注意,每次从服务管理器获取对象时都会运行初始化程序,因此它确实增加了一点开销。然而,这并不重要,因为当服务未实现该接口时,我们只是进行简单的类型检查。另外,服务默认是共享的,这意味着一个服务只会被实例化一次;对同一服务的后续请求将重用先前实例化的服务。这有助于进一步限制开销。