0

我目前正在“胖控制器”中验证输入并返回错误,如下所示:

class SomeController
{
    public function register()
    {
        // validate input
        $username = isset($_POST['username']) && strlen($_POST['username']) <= 20 ? $_POST['username'] : null;

        // proceed if validation passed
        if (isset($username)) {
            $user = $this->model->build('user');
            if ($user->insert($username)) {
                $_SESSION['success'] = 'User created!';
            } else {
                $_SESSION['error'] = 'Could not register user.';
            }
        } else {
            $_SESSION['failed']['username'] = 'Your username cannot be greater than 20 characters.';
        }

        // load appropriate view here
    }
}

class SomeModel
{
    public function insert($username)
    {
        // sql for insertion
        // ...

        return $result;
    }
}

虽然这很有效并且对我来说很容易实现,但我知道这是不正确的,因为验证属于模型,我试图使用“胖模型”来纠正它,如下所示:

class SomeController
{
    public function register()
    {
        $user = $this->model->build('user');
        $user->insert($_POST['username']);

        // load appropriate view here
        // ...
    }
}

class SomeModel
{
    public function insert($username)
    {
        // validate input
        $error = false;
        $username = trim($username) != '' && strlen($username) <= 20 ? $username : null;

        // proceed if validation passed
        if (isset($username)) {
            // sql for insertion
            // ...

            $_SESSION['success'] = 'User created!';
        } else {
            // store error in session
            $error = true;
            $_SESSION['error']['username'] = 'Your username cannot be greater than 20 characters ';
        }

        return $error ? false : true;
    }
}

我在这里看到的问题是模型应该是可移植的,因为它永远不需要更改。但是如果对长度的要求$username发生变化,那么显然我将不得不改变我的模型。

我觉得这可能是一个非常普遍的问题,但我还没有找到一个直截了当的答案。如果不实现任何额外的“层”、“映射器”或任何其他令人困惑的术语,如何修改提供的示例伪代码以正确处理此事务?(例如,验证输入,如果验证失败则返回错误)?

4

2 回答 2

6

无需实现任何额外的“层”、“映射器”或其他任何东西

您应该将“模型”视为应用而不是单个类。术语“层”可以被认为是一种简单的方式来引用 MVC 三明治的 M 切片。因此,要实现您想要的灵活性,您需要创建它。

可以进行许多清晰的分离。我会考虑拥有三个抽象:服务、数据映射器和实体。

服务将暴露给控制器并执行所请求的服务。

// some controller
function register() {
  $service = $this->getUserService();
  $user = $service->register($_POST['first_name'], $_POST['last_name']);
  if ($user instanceof \My\Entity\User) {
    // set user in view
  } else {
    // redirect to error
  }
}

所以任务一完成,控制器现在对寄存器内发生的任何事情都一无所知,它只想知道如何解决适当的结果。如果有用户对象,则成功,否则为假出错。

服务类本身将封装所提供的服务:

// class UserService.php
function register($firstname, $lastname) {
  // validate arguments
  if ($this->isValidUsername(....
    $userMapper = $this->getUserMapper();
    $user = new My\Entity\User();
    $user->setFirstName($firstname);
    $user->setLastName($lastname);
    return $userMapper->save($user);
  }
  return false;
}

我们处理参数的验证并创建新用户,将其传递给数据映射器,后者将执行抽象数据库操作的“实际保存”。

// UserMapper
function save($user) {
  // save $user to db
  $sql = 'INSERT INTO ....

 return true;
}
于 2013-10-14T01:03:08.197 回答
1

我不确定你会认为什么是不受欢迎的“图层”或“映射器”。这是一个有趣的问题,我的第一个问题是您可以只包含一个为您的用户名长度定义一个常量的配置文件。我的第二个想法是你可以让 someModel 扩展一个类或实现一个接口,其中你的值将被设置为属性或常量。我怀疑你已经想到了这些,并且正在回避它们;这就是避免“层”和“映射器”的意思。在这段代码中,您似乎受到这些原则的指导:

  • 避免“幻数”
  • 组合优于继承
  • 瘦控制器/胖模型

那么,你在运行 php5.4+ 吗?也许定义一个可以在这个模型和其他模型中使用的特征,它定义了应用程序中的用户名长度和其他可变值。或者也许这也是一个“层”?

于 2013-10-14T00:22:55.103 回答