MVC服务层内的限制

时间:2015-06-30 08:37:39

标签: php oop model-view-controller

我最近潜入了OOP& PHP MVC应用程序设计。目前我正在学习很多,但我有一件事情目前困扰着我。

我阅读并理解为什么在服务层中放置http重定向是不明智的。我们不知道服务完成后控制器需要做什么等等。我还读到服务不应该在其目的之外做任何事情。示例:用户注册只应使用控制器传递的输入创建新用户,但我想知道在服务层中设置Flash消息是否也可以。

我的应用程序显示了大量Flash消息session based notifications for users。所有这些都基于与服务相关的输入验证检查,并产生类似于以下的警报

用户名xxxxxx已在使用中

用户名应该是> 5个字符

应该/可以在服务类中定义/设置,还是有问题?我有一个Alert帮助函数来处理警报的设置。我可以轻松地使用我的依赖注入器使其可用我只是想知道这样做是否存在问题。

我犯了在服务中实现所有重定向的错误,我刚刚完成删除所有重定向并将它们放在控制器中,我不想同时消耗错误,所以我在这里寻找建议。

提前感谢您的帮助。

编辑 - 代码示例

<?php

/**
 *-----------------------------------------------------------------
 * 
 *  LOGIN CONTROLLER
 * 
 */
namespace Controller\www;
use \Helper\Controller;

class Login extends Controller {
    public $dependencies = ['arena', 'login', 'site'];

    /**
     *  Login
     * 
     *  Login Runs Through Various Checks Including If User is Banned, Account is Locked, 
     *  or Forgot Password Request Is Active. Then the Entered Password is Matched & if Valid
     *  User is Logged In
     */
    public function index() {

        // Define Default
        $username = '';                                                                     


        /** 
         *  User Login
         * 
         *  If      Successful, Login User, Redirect Home
         *  Else    Set Error Alerts 
         */
        if ($this->form->post('login')) { 

            // Define and Sanitize Post Data
            $username = $this->input->get('username');
            $password = $this->input->get('password');


            // Login Service Layer
            $login = $this->factory->make('user/login');

            // If Successful Redirect Home - Else Set Errors
            if ($login->user($username, $password) === true) {
                $this->redirect->home();
            }
            $this->alert->error($login->get('errors'));
        }


        /**
         *  Define Site Title & Display Page
         */
        $this->view->sitetitle('login');
        $this->view->display('www/login', [
            'video'     => $this->arena->video(),
            'username'  => $this->input->set($username)
        ], ['notifications' => 'user/forgotpassword']);
    }
}

服务层     

/**
 *-----------------------------------------------------------------
 * 
 *  USER LOGIN SERVICE LAYER
 * 
 */
namespace Service\User;
use \Helper\Service;

class Login extends Service {
    public $dependencies = ['login', 'mail', 'time', 'user', 'vars'];

    /**
     *  Handles Entire Login Process For Site Users
     *  
     *  @params all         User Submitted Form Data
     */
    public function user($username = '', $password = '') {

        // Validate $_POST Form Data
        $this->validateInput($username, $password);


        /**
         *  No Errors Produced - Complete Form Submission
         * 
         *  We Are Not Using `elseif` Between Forgot Password & Normal Login
         *  After a Forgot Password Code is Generated User May Remember Old Passwords
         *  We Need to Ensure Users Can Still Login Using Account Password As Well
         */
        if (!$this->errors()) {


            /** 
             *  User Input Password Matches Account Password
             */
            if ($this->input->verifyhash($password, $this->user->get('info.password'))) {
                $this->login->user();
                return true;                                                                    
            }


            /** 
             *  If We Have Not Been Redirected Login Was Unsuccessful
             */
            $message = $forgotPW ? 'Forgot Password Code Invalid - Login Lost Incorrect' : 'Login Unsuccessful - Incorrect Username or Password';
            $this->log->error($message, ['Username' => $username, 'Password' => $password]);

            $this->error('Incorrect Username or Password');
        }

        /** 
         *  If We Have Made It This Far Login Was Unsuccessful - Log Unsuccessful Attempt
         */
        $this->login->logAttempt();


        return false;
    }


    /**
     *  Validate $_POST Data
     * 
     *  @params all         User Submitted Form Data
     */
    private function validateInput($username = '', $password = '') {

        // Display Error if Username is Empty 
        if (!$username) {                                                                                           
            $this->error('Please enter a username');                                        
        }
        // Display Error if Password is Empty
        elseif (!$password) {                                                                                       
            $this->error('Please enter a password');                                        
        } 
        // Search DB For User With Matching Username - If User Not Found Display/Log Error, Else Set User
        else {
            $user = $this->user->info($username, 'username', '', '`userid`');
            if (!$user) {
                $this->error('The username ' . $username . ' does not exist'); 
                $this->log->error('User Not Found When Attempting to Login', ['username' => $username]);   
            } else {
                $this->user->set('user', $user['userid']);
            } 
        }
    }
}

2 个答案:

答案 0 :(得分:0)

为了回答你的问题,我认为最好将MVC的概念分解为一个非常基本的形式及其各个部分。如果出现这种情况有点居高临下,我会提前道歉。

查看
应用程序的视图显示任何内容。如果要显示某些内容,则应在此图层中完成

<强>控制器
控制器是视图和模型之间的中介。它从视图中获取输入,对其应用逻辑/规则(如果需要),并与模型交互,然后将数据传递回视图。

<强>模型
这是完成数据加载和保存的地方。大多数验证应该作为控制器中规则的一部分完成,并且这应该仅在加载期间传递任何错误的细节或者在出现时保存回控制器。如果没有错误,它应该将相关数据或成功状态返回给控制器。

考虑到这些要点,模型不应该向会话设置flash消息,这应该在控制器内完成,具体取决于模型的结果。

答案 1 :(得分:0)

将重定向和警报视为特定于某种特定形式的UI,并且显而易见的是,模型中没有它们的位置。只需总是尝试为您的应用程序描绘替代界面;例如用于管理任务或REST API的命令行界面。重定向显然在这些替代方案中都没有位置。警报是值得商榷的......至少警报的形式会有很大不同。您的模型需要能够将一些状态代码传递给您的Controller或View,然后控制器的工作就是对“负面”事件和View的工作做出反应,以便可视化任何必要时提醒。

例如,您的模型可能会执行以下操作:

public function registerUser(User $user) {
    ...

    if (!$successful) {
        throw new EmailAlreadyRegisteredException;
    }
    return true;
}

控制器可能如下所示:

public function userRegistration(Request $request) {
    try {
        $user = User::fromRequest($request);
        $this->services->get('Users')->registerUser($user);
        $this->view->render('registration_successful', $user);
    } catch (InvalidUserData $e) {
        $this->view->render('registration_form', $request, $e);
    } catch (EmailAlreadyRegisteredException $e) {
        $this->view->render('registration_failed', $user, $e);
    }
}

“警报”作为例外传递。这只是模型向其呼叫者发出信号的方法。接下来由呼叫者对这些事件做出反应并将其可视化。您当然不应期望模型中存在任何特定类型的可视化。所以你不想硬编码特定的HTML编码消息等。你根本不想触摸人类语言,这就是视图的全部工作。