5

私は現在、多言語ウェブサイトを開発しています。多言語部分については、translator / poedit を使用します。選択した言語をセッションに保存します。それは正常に動作します。

Module.php:

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

    $session = new Container('base');

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

コントローラーで言語を設定するためのアクション:

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');
}

module.config.php では、デフォルトのロケールは en に設定されています。

私が言ったように、1つのことを除いて、すべてが正常に機能します。

言語に依存するデータをDBにも保存しているため、モデルでは現在の言語が何であるかを知る必要があります。現在の言語は、モデルの他の目的にも必要です。

したがって、すべてのモデルの構築関数に次のコードを含めます。

$session = new Container('base');

if ($session->language !== NULL) {
    $this->language = $session->language;
} else {
    $this->language = 'default';
}

最善の解決策ではないと思います。モデルが多すぎて、常にこのコードを含めることができません。

たとえば Module.php / getServiceConfig 関数から、すべてのモデルに $language 変数を自動的に渡すソリューションがあるかどうかを知りたいです。

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;
            }
        )
    );
}

もちろん、これは機能していませんが、このような類似のこと、またはファクトリ配列内のすべてのモデルの言語変数に現在の言語の値を割り当てる必要がない、より一般的な解決策を実行できれば素晴らしいことです。 (たとえば、この割り当てをすべてのモデルに対して 1 か所で実行できる、モデルの一般的なブートストラップ)。

私の問題の解決策はありますか?

ご協力ありがとうございました!

M

4

2 に答える 2

4

すべてのモデルに言語を注入したくない場合は、頭のてっぺんから少なくとも 1 つの別の方法を考えることができます。

イニシャライザを使用できます。基本的に、初期化子を使用すると、サービス マネージャーを介してフェッチされたサービスに対して初期化タスクを実行できます。したがって、このアプローチを使用するには、サービス マネージャーを介してモデル (少なくとも言語を必要とするモデル) をフェッチする必要があります。これは、依存関係を注入する必要がある場合に、それらを呼び出し可能オブジェクトまたはおそらくファクトリとして追加するのと同じくらい簡単です。初期化子の詳細については、私がサービス マネージャーについて書いた記事を参照してください(初期化子に関するセクションまでスクロールしてください)。

したがって、できることは、モデルにインターフェースを実装させることですLanguageAwareInterface

namespace User\Model;

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

    /**
    * Sets the language
    *
    * @param string $language
    */
    public function setLanguage($language);
}

次に、モデルで次のようにすることができます。

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;
    }
}

必要に応じて、上記のコードを持つ抽象基本モデル クラスを作成したり、クラスの拡張を避けたい場合は単純なトレイトを記述したりすることもできます。次に、モデルはそれぞれこの基本クラスを拡張できますが、それは現在の言語で実際に動作する必要があるモデルの数によって異なります。

次にイニシャライザです。私の記事では、メソッド呼び出しでそれを追加する方法の例を示していますが、設定ファイル ( ApplicationZend Skeleton アプリケーションを使用している場合はモジュール内) でそれを行う可能性があります。Moduleメソッドでモジュールのクラスから配列を返す (または構成ファイルを指す)か、キーの下のファイルにgetServiceConfig()追加することができます。公式ドキュメントには、この例はありません。実際、欠けているのはイニシャライザだけです。ただし、機能するはずです。YourModule/config/module.config.phpservice_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);
                }
            },
        ),
    ),
);

上記のイニシャライザは、サービス マネージャからフェッチされたすべてのオブジェクトをチェックして、上で作成したインターフェイスを実装しているかどうかを確認します。もしそうなら、言語を注入することができます。私の例では、セッションで設定されているかどうかを確認し、設定されていない場合は構成からフェッチします。正確なニーズに応じて、ロジックを微調整する必要がある場合があります。初期化子は毎回実行されることに注意してくださいサービス マネージャーからオブジェクトを取得する時間にかかるため、多少のオーバーヘッドが追加されます。ただし、サービスがインターフェイスを実装していない場合に単純な型チェックを行うだけなので、これは重要ではありません。また、サービスはデフォルトで共有されます。つまり、サービスは一度だけインスタンス化されます。同じサービスに対する後続のリクエストは、以前にインスタンス化されたものを再利用します。これは、オーバーヘッドをさらに制限するのに役立ちます。

于 2013-03-31T19:08:40.200 に答える
0

最初に、必要なモジュールの Module.php のサービス マネージャーにセッション モデルを登録して、グローバルに利用できるようにし、セッションにアクセスする必要があるときはいつでもこのサービスを使用できると思います。

public function getServiceConfig()
{        
    return array(
        'factories' => array(
            'AppSession' => function($sm) {
                  $session = new \Path\To\Session();
                  $session->doSomething();
                  return $session;
            }
        )
    );
}

アプリケーション全体でさまざまなモデルをサービス マネージャーに登録するときに、セッション サービスを挿入します。

public function getServiceConfig()
{        
    return array(
        'factories' => array(
            'Application\Model\SomeThing' => function($sm) {
                $c = new SomeThing();
                // You will have to create the set and get functions.
                $c->setDbAdapterService($sm->get('Zend\Db\Adapter\Adapter'));
                $c->setSessionService($sm->get('AppSession'));
                return $c;
            }
        )
    );
}

また、コントローラーでも、最初からセッションを挿入して、セッションの準備が整い、あなたを待っている方が理にかなっている場合があります。

あなたのmodule.config.phpで...

return array(
    'controllers' => array(
        'factories' => array(
            'Application\Controller\Something' => function ($sm) {
                $locator = $sm->getServiceLocator();
                $c = new Application\Controller\SomethingController();
                $c->setSessionService($locator->get('AppSession'));
                return $c;
            },
        ),
    ),
    'router' => array(
        'routes' => array(
            'myroute' => array(
                'type' => 'Zend\Mvc\Router\Http\Segment',
                'options' => array(
                    'route' => '[/:action]',
                    'defaults' => array(
                        'controller' => 'Application\Controller\Something',
                        'action'     => 'index',
                    ),
                ),
            ),
        ),
    ),
);
于 2013-04-05T00:12:58.097 に答える