【问题标题】:Laravel 4 Repository Validation and TestsLaravel 4 存储库验证和测试
【发布时间】:2013-07-31 06:42:01
【问题描述】:

我正在尝试编写一个可测试的 Laravel 4 应用程序。在 Taylor Otwells 关于 Laravel https://leanpub.com/laravel 的书中,他写道,我们应该考虑在 Validation 命名空间中创建一个 UserValidator 类,并将该验证器注入到您的存储库中。您能否提供一个代码示例,该代码在控制器、存储库和测试中看起来像。如果用户输入不满意,我应该在存储库中抛出验证异常并在控制器中捕获错误吗? http://jasonlewis.me/article/laravel-advanced-validation

【问题讨论】:

  • 注意,最后提供的link与Laravel 3有关,与Laravel 4无关。

标签: phpunit laravel laravel-4


【解决方案1】:

我最近编写了类似的代码,这是 laracasts (http://laracasts.com) 推荐的(参考了 Taylor Otwell 的书)。请注意,您不必遵循所使用的应用程序结构。

<?php namespace ACME\Services\Validation;

use Validator as V;

abstract class Validator {

    protected $errormessages;
    protected $rules;

    public function validate($input, $rules)
    {

        $validator = V::make($input, $rules);
        $this->rules = $rules;

        if ($validator->fails()) {

            $this->errormessages = $validator->messages();

            return false;
        }

        return true;

    }

    public function getErrorMessages()
    {
        return $this->errormessages;
    }

    public function getValidationRules()
    {
        return $this->rules;
    }
}

这是应为各种验证目的而扩展的类,如下面的示例代码 sn-p 所示。

<?php namespace ACME\Services\Validation;

use Auth;

class UserValidator extends Validator {

    protected $create_rules = [
        'firstname' => 'required|min:3|max:64|alpha-dash',
        'lastname' => 'required|min:2|max:64|alpha-dash',
        'account' => 'required|min:4|max:15|alpha_num',
        'email' => 'required|between:3,254|email|unique:users',
        'description' => 'max:500'
    ];

    protected $edit_rules = [
        'firstname' => 'required|min:3|max:64|alpha-dash',
        'lastname' => 'required|min:2|max:64|alpha-dash',
        'description' => 'max:500'
    ];

    protected $pass_edit_rules = [
        'oldpassword' => 'required',
        'password'  => 'required|min:5|confirmed',
        'password_confirmation'=> 'required|min:5'
    ];

    public function validateCreate($input)
    {


        return parent::validate($input, $this->create_rules);
    }

    public function validateEdit($input)
    {
        $newRules = $this->edit_rules;

        if ($this->validatePasswordChanged($input))
            $newRules = array_merge($newRules, $this->pass_edit_rules);

        return parent::validate($input, $newRules);
    }

    public function validatePasswordChanged($input)
    {
        return $input['password'] != '' || $input['oldpassword'] != '' || $input['password_confirmation'] != '' ? true : false;
    }

}

$this->validate 可以像在类中使用 parent::validate 一样简单。

另一个例子,由于 laracasts 提供课程,他们可能有一个 LessonValidator.php 文件,其中包含 class LessonValidator extends Validator {} 和一组不同的规则。

在存储库中使用? 存储库接口和服务提供者被排除在外

<?php namespace ACME\Repositories;

use User;
use UserController;
use ACME\Services\Validation\UserValidator;

class DatabaseUserRepository extendes UserRepositoryInterface {
    protected $validator;

    public function __construct(UserValidator $validator, UserController $listener)
    {
        $this->validator = $validator;
        $this->listener = $listener;
    }

    public function createUser(User $user)
    {
        if ($this->validator->validateCreate($input))
            return $this->listener->withErrors('/',$this->validator->getErrorMessages());

        /* Validation passed, create user with User::create() */

        $this->listener->withView('usercreatedview');
    }
}

您的控制器将包含类似以下内容的内容。

<?php

use ACME\Repositories\UserRepositoryInterface;

class UserController extends BaseController {

    protected $repository;

    public function __construct(UserRepositoryInterface $repository)
    {
        $this->repository = $repository;
    }

    public function withErrors($path, MessageBag $errors)
    {
        return Redirect::to($path)->withErrors($errors);
    }

    public function withView($view)
    {
        return View::make($view);
    }

    /* Other controller stuff... */
}

请注意,如果您不将 DatabaseUserRepository 绑定到 UserRepositoryInterface(以及我可能犯的任何错字),这将出错。您可以将验证类注入控制器,但我相信您想合并一个存储库。我倾向于在事件处理程序内部进行验证和存储库调用。

我会阅读 psr 自动加载、依赖注入和创建自定义服务提供程序。

【讨论】:

  • 控制器应该调用存储库,而不是相反。 Repository 封装了持久化在数据存储中的一组对象以及对它们执行的操作,提供了持久层的更加面向对象的视图。 请参阅Martin Fowler's P of EAA Catalog
  • 存储库不调用控制器,它只是将其结果通知监听器,而监听器恰好是控制器。 Matt Wynne 在 Gotham Ruby 大会上演示了它,而 Jeffrey Way 在他的“Controller Cleanup”截屏中做了某种对 Laravel 的翻译。
  • 如果 Matt Wynne 只是遵循“应该”做的事情,他就不会坚持他的被动控制器想法。参考:vimeo.com/44807822 - laracasts.com/lessons/controller-cleanup
  • @VerronKnowles ,我喜欢这个答案。这是一种委托方法。忽略托基尔。
【解决方案2】:

就个人而言,我更喜欢直接在模型中进行验证。也就是说,我将为每个模型设置一个 getValidator() 方法,如下所示:

class User extends Eloquent
{
    public function getValidator()
    {
        $params = array(
            'username' => $this->username,
            'password' => $this->password,
        );

        $rules = array(
            'username' => ['required', 'unique:users'],
            'password' => ['required', 'min:6'],
        );

        return Validator::make($params, $rules);
    }
}

然后在我的控制器、命令或测试中,我只需调用该方法以获得一个验证器实例,然后我会调用我需要的方法,可以是 passes()fails()

下面说明了我是如何在控制器中实际使用它的。

class UserController extends BaseController
{
    public function processCreateUser()
    {
        // Retrieve user input.
        $user = new User(Input::all());

        // Validate input.
        $validator = $user->getValidator();

        if ($validator->passes()) 
        {
            // Hash the password.
            $user->password = Hash::make($user->password);

            // Save the new user.
            $user->save();

            return Redirect::to('users')
                ->with('success', 'User created!');
        }

        return Redirect::route('users.create')
            ->withInput()
            ->with('error', 'Cannot create user, please double check the form.')
            ->withErrors($validator);
    }
}

【讨论】:

  • 绝对没有这个答案,触及了原始问题所要求的任何内容!
  • @JasonMortonNZ,我同意你的看法。但是 OP 提供的最后一个链接谈到了直接在模型中实现验证,而不是使用存储库。所以我坚持认为这个基于我个人经验的答案可能会引起 OP 的兴趣。
猜你喜欢
  • 2015-06-15
  • 2021-03-16
  • 1970-01-01
  • 2013-07-28
  • 2017-03-24
  • 1970-01-01
  • 1970-01-01
  • 2017-05-23
  • 2013-05-07
相关资源
最近更新 更多