Zend_Form_Element_Captcha でデコレータ毎にレンダリングする。

Zend_Form はマジックメソッド __toString() が実装されており、インスタンスを echo すると、フォームが dl タグで整形されて出力されます。
また、要素毎に細かく出力を調整しながらレンダリングしていくことも可能です。

Zend_Form に登録された username 要素のラベルだけを出力する場合は、以下のようになります。

<form action="" method="POST">
<?php echo $this->form->username->renderLabel(); ?>
</form>

このように、登録したデコレータで出力出来るような機能が実装されています。
Zend_Form_Element の実装部分を以下に記載いたします。

<?php
// Zend/Form/Element.php

    /**
     * Overloading: allow rendering specific decorators
     *
     * Call renderDecoratorName() to render a specific decorator.
     *
     * @param  string $method
     * @param  array $args
     * @return string
     * @throws Zend_Form_Exception for invalid decorator or invalid method call
     */
    public function __call($method, $args)
    {
        if ('render' == substr($method, 0, 6)) {
            $this->_isPartialRendering = true;
            $this->render();
            $this->_isPartialRendering = false;
            $decoratorName = substr($method, 6);
            if (false !== ($decorator = $this->getDecorator($decoratorName))) {
                $decorator->setElement($this);
                $seed = '';
                if (0 < count($args)) {
                    $seed = array_shift($args);
                }
                return $decorator->render($seed);
            }

            require_once 'Zend/Form/Element/Exception.php';
            throw new Zend_Form_Element_Exception(sprintf('Decorator by name %s does not exist', $decoratorName));
        }

        require_once 'Zend/Form/Element/Exception.php';
        throw new Zend_Form_Element_Exception(sprintf('Method %s does not exist', $method));
    }

マジックメソッド __call() を利用して、render{デコレータ名}() として呼び出してやることが可能となっています。
しかし、この方法で利用できるのは登録されたデコレータのみとなります。

続きを読む

Zend_Form でバリデーション時に表示されるエラーメッセージを設定する。

Zend_Form を利用してフォームを作成する場合、エレメント毎にバリデーションやフィルタ等のオプションを設定するだけで、dl タグで装飾されたフォームが自動で生成されます。*1
今回はタイトルの通り、バリデーションのエラーメッセージの設定方法を説明します。

<?php
class Form_Login extends Zend_Form
{
    public function init()
    {
        $this->addElement('text', 'username', array(
            'label'         => 'Username',
            'validators'    => array(
                array('StringLength', false, array(3, 255, 'messages' => array(
                    Zend_Validate_StringLength::TOO_SHORT   => 'Usernameは%min%〜%max%文字で入力して下さい。',
                    Zend_Validate_StringLength::TOO_LONG    => 'Usernameは%min%〜%max%文字で入力して下さい。',
                ))),
            ),
        ));
    }
}

※説明に不要な設定は省いておりますので、ご了承下さい。
上記のコードは Zend_Form の init() メソッドから各要素を登録する方法で実装しておりますが、他にも、Zend_Form をインスタンス化してから addElement() メソッドで登録しても構いません。
さて、肝心のバリデータ設定の説明に移ります、上記コードで addElement() メソッドの第三引数に連想配列として要素のオプションを渡しておりますが、ここの 'validators' というキーに割り当てられてる配列値が、複数のバリデータの設定郡となります。
入れ子構造になっており、読解しづらいですが、一つ一つの階層を見ていけば、そう難しくない事が分かるかと思います。

*1:ul タグにしたい場合もデコレーションの設定等で調整可能

続きを読む

application.ini と独自アクションヘルパーでモジュール毎のレイアウトを実装する。

ZendFramework にはモジュール毎にレイアウトを変更する機能が備わっておりません。*1
ですので、アクションヘルパーを自作し、実装することにします。
尚、自作したクラスは独自ライブラリとしてパッケージングしておくことにします。

application.ini にオートロードするネームスペース*2を記述します。
任意のネームスペースを記述して下さい。※ここでは Peta としています。

; Namespaces
autoloaderNamespaces[]                        = "Peta"

次にモジュールを利用出来るように以下を記述します。
Front Controller の項目の一行目はデフォルトで呼ばれるモジュールも他のモジュールと同じ階層に設置する為の記述です。

; Front Controller
resources.frontController.controllerDirectory = APPLICATION_PATH "/modules/default/controllers"
resources.frontController.moduleDirectory     = APPLICATION_PATH "/modules"

; Module
resources.modules[]                           =

そして、レイアウトを各モジュール毎に設定します。
以下の例は、「default」「hoge」「fuga」のモジュールに設定しています。

; Layout
resources.layout.layout                       = "layout"
default.resources.layout.layoutPath           = APPLICATION_PATH "/modules/default/layouts/scripts"
hoge.resources.layout.layoutPath              = APPLICATION_PATH "/modules/hoge/layouts/scripts"
fuga.resources.layout.layoutPath              = APPLICATION_PATH "/modules/fuga/layouts/scripts"

application.ini の設定はここまで。次に独自クラスを実装していきます。
先の説明でネームスペースを設定しましたので、次のようなディレクトリ構造になるようにファイルを作成します。

/library/Peta/Controller/Action/Helper/LayoutLoader.php

ファイルの内容は以下の通り。

<?php
require_once 'Zend/Controller/Action/Helper/Abstract.php' ;
class Peta_Controller_Action_Helper_LayoutLoader extends Zend_Controller_Action_Helper_Abstract
{
    public function preDispatch()
    {
        $bootstrap  = $this->getActionController()->getInvokeArg('bootstrap');
        $config     = $bootstrap->getOptions();
        $module     = $this->getRequest()->getModuleName();
        if (isset($config[$module]['resources']['layout'])) {
            $this->getActionController()
                 ->getHelper('layout')
                 ->setOptions($config[$module]['resources']['layout']);
        }
    }
}

どのように動作するかですが、コントローラが preDispatch されたタイミングでレイアウトを設定しなおします。*3

最後に作成したアクションヘルパーを Bootstrap で登録して完成です。

<?php
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
    protected function _initLayoutHelper()
    {
        $this->bootstrap('frontController');
        Zend_Controller_Action_HelperBroker::addHelper(new Peta_Controller_Action_Helper_LayoutLoader());
    }
}

*1:ひょっとしたら私の知識不足なだけかもしれませんが・・・。

*2:ここで言うネームスペースはPHPが提供するネームスペースの機能とは異なり、ZendFrameworkが提供しておる擬似ネームスペースの事を指します。

*3:preDispatch 前に一度設定されるので、しなおすという表現にしてます。

続きを読む

コントローラからアクションヘルパーを実行する

例えば、 Redirector ヘルパーを利用したい場合、例えばコントローラ内から以下のように使用します。

<?php
$this->_helper->redirector($action, $controller, $module, $params);

このように、 $this->_helper-> に続けて使用したいヘルパー名を続ける事で使用可能です。
さらに、 Redirector ヘルパーのもつその他のメソッドを使用したい場合は、以下のように、メンバとして呼び出して、使用したいメソッドを使用する事で実現可能です。

<?php
$this->_helper->redirector->gotoRoute($urlOptions, $name, $reset, $encode);
続きを読む