Php 利用Zend_Controller_Action_Helper_FlashMessenger将Zend_View_Helper_Action小部件重构为模型

Php 利用Zend_Controller_Action_Helper_FlashMessenger将Zend_View_Helper_Action小部件重构为模型,php,zend-framework,zend-form,zend-db-table,Php,Zend Framework,Zend Form,Zend Db Table,我试图创建一个登录小部件,它可以随意包含在需要登录的应用程序内容之外的任何操作中。我的想法是,我想要一种干燥的方法来呈现登录框,其中包含来自上一次登录尝试的任何错误消息。为了启用此功能,我使用保存登录尝试失败的结果。该小部件还使用,以避免在使用浏览器后退按钮时多次发布数据的问题 现在的问题是,我宁愿不使用,因为该助手克隆了请求并创建了另一个调度循环运行,这是相当资源密集型的。因此,通过查看下面的代码,您能给我一些关于如何重构代码的建议吗 小部件可以包含在任意视图脚本中 呈现先前登录尝试的结果 小

我试图创建一个登录小部件,它可以随意包含在需要登录的应用程序内容之外的任何操作中。我的想法是,我想要一种干燥的方法来呈现登录框,其中包含来自上一次登录尝试的任何错误消息。为了启用此功能,我使用保存登录尝试失败的结果。该小部件还使用,以避免在使用浏览器后退按钮时多次发布数据的问题

现在的问题是,我宁愿不使用,因为该助手克隆了请求并创建了另一个调度循环运行,这是相当资源密集型的。因此,通过查看下面的代码,您能给我一些关于如何重构代码的建议吗

  • 小部件可以包含在任意视图脚本中
  • 呈现先前登录尝试的结果
  • 小部件不调用分派循环中的运行
  • 当前,登录小部件通过在视图脚本中调用来呈现:

    echo $this->action('auth', 'login-widget');
    
    AuthController.php:

    class AuthController extends Zend_Controller_Action {    
        // This method is invoked by Zend_View_Helper_Action to render the
        // login widget
        public function loginWidgetAction () {
            $flashMessenger = $this->_helper->flashMessenger->setNamespace('login');
            $this->view->messages = $flashMessenger->getMessages();
        }
    
        public function loginAction () {
            if($this->getRequest()->isPost()) {
                $result = Auth::doLogin($this->getRequest()->getPost());
                if($result->isValid()) {
                    $this->_redirect('user');
                } 
                else {
                    $flashMessenger = $this->_helper->flashMessenger->
                                                      setNamespace('login');
                    foreach($result->getMessages() as $message) {
                        $flashMessenger->addMessage($message);    
                    }
                }
            }
            // This will be changed to redirect either to the index page,
            // or the page the request originated from if available.
            $this->_redirect('');
        }
        [...]
    }
    
    /models/Auth.php:

    /**
     * Model for encapsulating the actions that deals with authentication,
     * such as registering and activating users, as well as logging in and
     * logging out.
     * @todo: Refactor this to remove static methods
     */
    class Auth {
    
        /**
         * 
         * @return Zend_Auth_Result
         */
        public static function doLogin ($credentials) {
            $authAdapter = new Auth_Adapter_DbTable(
                Zend_Db_Table::getDefaultAdapter(),
                'Users',
                'username',
                'pwdHash',
                'SHA1(CONCAT(?, salt))'
            );
            $authAdapter->setIdentity($credentials['username']);
            $authAdapter->setCredential($credentials['password']);
            $auth = Zend_Auth::getInstance();
            return $auth->authenticate($authAdapter);
    }
    [...]
    }
    
    /models/Auth/Adapter/DbTable.php:

    class Auth_Adapter_DbTable extends Zend_Auth_Adapter_DbTable {    
    
        /**
         * authenticate() - defined by Zend_Auth_Adapter_Interface.  This method 
         * is called to attempt an authenication.  Previous to this call, this
         * adapter would have already been configured with all necessary 
         * information to successfully connect to a database table and attempt
         * to find a record matching the provided identity.
         *
         * @throws Zend_Auth_Adapter_Exception if answering the authentication 
         * query is impossible
         * @see library/Zend/Auth/Adapter/Zend_Auth_Adapter_DbTable#authenticate()
         * @return MedU_Auth_Result
         */
        public function authenticate() {
            return parent::authenticate();
        }
    
        /**
         * _authenticateValidateResult() - This method attempts to validate that
         * the record in the result set is indeed a record that matched the 
         * identity provided to this adapter.
         * 
         * Additionally it checks that the user account is activated. 
         *
         * @param array $resultIdentity
         * @return MedU_Auth_Result
         */
        protected function _authenticateValidateResult($resultIdentity)
        {
            $result = parent::_authenticateValidateResult($resultIdentity);
            if(!$result->isValid()) { return $result; }
    
            $this->_checkAccountIsActivated($resultIdentity);
            $this->_checkAccountIsSuspended($resultIdentity);
    
            // Overwrite the username supplied by the user and instead
            // use the name supplied upon registration, i.e if the
            // user signs in as uSERNAME and registered as Username,
            // the identity is Username
            $this->_authenticateResultInfo['identity'] = 
                $resultIdentity[$this->_identityColumn]; 
    
            return $this->_authenticateCreateAuthResult();
        }
    
        protected function _checkAccountIsActivated ($resultIdentity) {
            if(!$resultIdentity['activated']) {
                $this->_authenticateResultInfo['code'] = 
                    MedU_Auth_Result::FAILURE_NOT_ACTIVATED;
                $this->_authenticateResultInfo['messages'] = 
                    array('The account has not yet been activated. 
                           Please click on the link provided in the 
                           activation email.');
            }
        }
    
        protected function _checkAccountIsSuspended ($resultIdentity) {
            if($resultIdentity['suspended']) {
                $this->_authenticateResultInfo['code'] = 
                    MedU_Auth_Result::FAILURE_SUSPENDED;
                $this->_authenticateResultInfo['messages'] = 
                      array('The account has been suspended. 
                             If you feel this is a mistake, 
                             please contact our support: support@meduniverse.com');
            }
        }
    
        /**
         * _authenticateCreateAuthResult() - This method creates a 
         * MedU_Auth_Result object from the information that has 
         * been collected during the authenticate() attempt.
         *
         * @return MedU_Auth_Result
         */
        protected function _authenticateCreateAuthResult()
        {
            return new MedU_Auth_Result(
                $this->_authenticateResultInfo['code'],
                $this->_authenticateResultInfo['identity'],
                $this->_authenticateResultInfo['messages']
               );
        }
    }
    
    /视图/脚本/auth/partials/login-widget.phtml

    // The fetchForm-view helper returns a Zend_Form object. 
    // The form definition (xml) is attached below in the
    // code box below this one.
    <div class="box">
        <h3>Login</h3>
        <?php if($this->messages) : ?>
                <ul class="errors">
                    <?php foreach($this->messages as $message) : ?>
                        <li><?php echo $message ?></li>
    
                    <?php endforeach; ?>
                </ul>
        <?php endif; ?>
        <div>
            <?php echo $this->fetchForm('user', 'login') ?>
        </div>
    </div>
    
    //fetchForm视图帮助程序返回Zend_表单对象。
    //表单定义(xml)附在下面的
    //下面的代码框。
    登录
    
    /application/configs/forms.xml

    // Configuration of the Login form. 'user' and 'login' are 
    // just keys for the view helper to return the correct form
    <forms>
        <user>
            <login>
                <action value="/auth/login" />
                <method value="post" />
                <elements>
                    <username>
                        <type value="text"></type>
                        <options>
                            <label value="Username" />
                            <required value="true" />
                            <validators>
                                <alnum validator="alnum" />
                                <strlen validator="StringLength">
                                    <options min="6" max="45" />
                                </strlen>
                            </validators>
                        </options>
                    </username>
    
                    <password>
                        <type value="password" />
                        <options>
                            <label value="Password" />
                            <required value="true" />
                            <validators>
                                <strlen validator="StringLength">
                                    <options min="6" max="20" />
                                </strlen>
                            </validators>
                        </options>
                    </password>
    
                    <submit>
                        <type value="submit" />
                        <options>
                            <label value="Log in" />
                        </options>
                    </submit>
                </elements>
        </login>
    
    //登录表单的配置。'“用户”和“登录”是
    //只需按查看帮助器的键即可返回正确的表单
    
    也许您应该使用ViewHelper来呈现表单和ActionController以进行身份验证? 这将使您从第二个分派循环中解脱出来。 如果你愿意,我可以给你举一些小例子


    另外,你确定表单需要验证器吗?我看不出在您的示例中有任何用处。

    据我所知,您当前对
    Zend\u View\u Helper\u操作的调用只不过是呈现登录表单而已。为什么不编写查看帮助程序,从flash messenger中检索与登录相关的消息并呈现登录表单

    编辑:

  • 您可以从其静态代理检索flash messenger:

    $flashMessenger = Zend_Controller_Action_HelperBroker::getStaticHelper('FlashMessenger');
    $flashMessenger->setNamespace('login');
    $messages = $flashMessenger->getMessages();
    
  • 您不需要在view helper中安装新的flash messenger,只需检索它的当前实例(请参见1)。从设计的角度来看,在视图助手中检索应用程序组件是绝对可行的(例如,
    Zend\u view\u Helper\u Url
    从静态前端控制器检索路由器)。为了减少耦合并实现setter依赖注入模式,我建议如下(
    Zend\u View\u Helper\u Translate
    使用类似的模式检索转换器):

  • 当flash messenger提供您所需的功能时,情况并非如此。如果您需要区分错误消息、信息消息和成功消息,例如,一个自主开发的解决方案可能是更好的方法


  • 另外,您可以使用FlashMessenger存储任何数据。所以你可以

    $flash->addMessage(array('status'=>'error','message'=> 'oops'));
    
    然后在每一次使用中

    foreach($messages as $message){
    echo '<div class="message '. $message['status'] .'">' . $message['message'] . '</div>'
    }
    
    foreach($messages作为$message){
    回显“”。$message['message'].'
    }
    
    +1,一个有趣的问题,但是当一个未登录的用户试图访问受保护的内容时,为什么不发出一个简单的重定向,比如说,AuthController->loginAction?有什么特别的原因吗?当然,我仍然需要这样做,但我希望能够让用户在他喜欢的时候登录,而不必强迫他先单击需要登录的链接。例如,当用户未登录时,在侧栏中有一个登录框。我可能不需要任何验证器,目前也不使用它们。我只是在配置表单时添加了它们,但你是对的。如果我觉得它们没用的话,我可能应该把它们拿出来。它的作用还不止这些。它还获取错误消息并将其推送到视图中。我曾想过使用视图辅助对象而不是控制器操作,但在以下几点上我犹豫不决:*在视图辅助对象中实例化Zend_controller_action_辅助对象是否正确?(闪光信使)。*如何以适当的方式实例化它?*我应该建立自己的错误传递机制而不是使用flash messenger吗?我想你也忘了!或者在getFlashMessenger中为空($this->\u flash)。除此之外,此解决方案与使用“动作视图”辅助对象一样有效。我喜欢您关于依赖注入模式的想法,尽管在这种情况下可能有些过分。谢谢你的帮助和想法!
    foreach($messages as $message){
    echo '<div class="message '. $message['status'] .'">' . $message['message'] . '</div>'
    }