fadion/validator-assistant

此包已被废弃,不再维护。未建议替代包。

使用ValidatorAssistant从Laravel控制器中解耦验证

1.0.2 2015-01-28 13:27 UTC

This package is not auto-updated.

Last update: 2020-01-24 15:17:51 UTC


README

Laravel的FormRequest大致做了与该包相同的工作,但与框架集成得更好。对于所有使用Laravel 5的用户,我强烈推荐使用FormRequests。您不会错过任何功能,并且从5.2版本开始,它还支持输入数组。

ValidatorAssistant

通过将验证规则和消息组织到专用类中,使Laravel控制器保持精简并重用代码。ValidatorAssistant是一个小型库,旨在由这些类扩展,以便它们可以轻松使用Laravel的验证系统以及一些附加功能,如子规则、作用域和绑定。

目录

安装

  • 将包添加到您的composer.json文件中,并运行composer update
{
    "require": {
        "fadion/validator-assistant": "~1.0"
    }
}
  • (可选) 将新别名'ValidatorAssistant' => 'Fadion\ValidatorAssistant\ValidatorAssistant'添加到您的app/config/app.php文件中的aliases数组。

使用方法

ValidatorAssistant可以由任何遵循几个简单规则的PHP类扩展。作为个人偏好,我将验证类存储在app/validators文件夹中,并将其添加到composer.json的classmap选项中,以实现简单自动加载。可能给它们命名空间也是个好主意。

以下是一个实际操作的验证类示例。请注意$rules和$messages属性。为了使它们被ValidatorAssistant“看到”,它们的可见性需要是protectedpublic,但不能是private

class UserValidator extends ValidatorAssistant {

    // Validation rules, as you'd define them
    // for Laravel's Validator class.
    protected $rules = array(
        'username' => 'required',
        'email' => 'required|email'
    );

    // Error messages.
    protected $messages = array(
        'username.required' => "Username is required",
        'email.required' => "Email is required",
        'email.email' => "Email is invalid"
    );

}

如果使用命名空间,您将这样编写

namespace MyApp\Validators;

// If the alias was added
use ValidatorAssistant;

// Without alias
use Fadion\ValidatorAssistant\ValidatorAssistant;

class UserValidator extends ValidatorAssistant {}

在验证类中定义了规则和消息后,控制器中的典型工作流程如下

$userValidator = UserValidator::make(Input::all());

if ($userValidator->fails()) {
    return Redirect::back()->withInput()->withErrors($userValidator->instance());
}

您甚至可以省略Input::all()调用,因为它将由ValidatorAssistant默认调用

$userValidator = UserValidator::make();

// is the sames as
$userValidator = UserValidator::make(Input::all());

非常简洁,对吧?!每当您需要验证模型或表单时,只需调用相应的验证类,您就可以用几行代码完成。

子规则

数组输入对于组织大型表单、本地化字段等非常有帮助。不幸的是,目前Laravel验证器不支持子规则,因此如果您遇到难题,ValidatorAssistant将非常有帮助。

假设您需要创建一些多语言输入,其中某个字段将被视为数组,HTML代码如下

<input type="text" name="title[sq]">
<input type="text" name="title[en]">
<input type="text" name="title[it]">

为每个输入设置规则就像编写数组键一样简单。

protected $rules = array(
    'title[sq]' => 'required',
    'title[en]' => 'max:15',
    'title[it]' => 'required|alpha'
);

消息也是如此。

protected $messages = array(
    'title[sq].required' => 'Albanian title is required.',
    'title[en].required' => 'English title is required.',
    'title[it].required' => 'Italian title is required.'
);

ValidatorAssistant在后台执行的操作是遍历所有规则、消息和输入,以便修改它们,以便它们可以被Laravel的验证器处理。一个title[en]规则在规则和输入中都被翻译为title_en,在消息中为title_en.required

还有一个方便的、通用的修饰符,可以验证输入的所有子规则,这在键是程序性构建且每个键都有相同的验证规则时非常有用。在语言的情况下,上面的例子可以写成:

protected $rules = array(
    'title[*]' => 'required'
);

protected $messages = array(
    'title[*].required' => 'The title is required.'
);

属性名称

Laravel支持为字段自定义属性名称,这是一种轻松地为输入别名并生成有用错误信息的方法。ValidatorAssistant也支持它们!

只需将一个$attribute数组作为验证类的一个类成员即可

protected $rules = array(
    'username' => 'required',
    'email' => 'email'
);

// Custom attributes
protected $attributes = array(
    'username' => 'Your name',
    'email' => 'Your email'
);

protected $messages = array(
    'username.required' => ':attribute is required.',
    'email.email' => ':attribute is not valid.'
);

子规则以与规则和消息相同的方式应用于属性名称

protected $attributes = array(
    'title[sq]' => 'Titulli',
    'title[en]' => 'Title'
);

// or with the catch-all modifier

protected $attributes = array(
    'title[*]' => 'The title'
);

过滤器

有时需要在验证之前以某种方式转换或清理输入数据。您可以手动完成,或者更简单,使用过滤器。ValidatorAssistant的过滤器定义得与规则一样,但每个过滤器都有一些特定的关键字。

以下是一个例子

protected $rules = array(
    'title' => 'required',
    'body' => 'required'
);

protected $filters = array(
    'title' => 'trim|ucwords',
    'body' => 'strip_tags'
);

"title"输入将通过PHP的trim()ucwords()函数进行过滤,而"body"输入将通过strip_tags()进行过滤。除了少数几个之外,大多数过滤器都是PHP函数的等效项。

还有一些过滤器可以接受参数。例如,rtrim接受一个字符串参数,指定要删除的字符,而limit接受一个参数,指定字符串必须限制的字符数。

protected $filters = array(
    'title' => 'rtrim:abc',
    'body' => 'trim|limit:255'
);

对于其他任何内容,子规则也可以设置在过滤器上

protected $filters = array(
    'title[sq]' => 'trim|ucfirst',
    'title[en]' => 'trim|ucwords'
);

// or with the catch-all modifier

protected $filters = array(
    'title[*]' => 'trim|upper'
);

最后,如果您想使用转换后的值(例如数据库条目或其他用途),甚至可以获取过滤后的输入。只需在验证运行后,在验证器对象上运行inputs()方法即可。

$userValidator = UserValidator::make(Input::all());

if ($userValidator->fails()) {
    return Redirect::back()->withInput()->withErrors($userValidator->instance());
}

// Will return the filtered input data
$inputs = $userValidator->inputs();

以下列出了可用的过滤器

trim:[可选要删除的字符] => trim($input, $chars)

ltrim:[可选要删除的字符] => ltrim($input, $chars)

rtrim:[可选要删除的字符] => rtrim($input, $chars)

md5 => md5($input)

sha1 => sha1($input)

url_encode => url_encode($input)

url_decode => url_decode($input)

strip_tags => strip_tags($input)

htmlentities => htmlentities($input)

base64_encode => base64_encode($input)

base64_decode => base64_decode($input)

lcfirst => lcfirst($input)

ucfirst => ucfirst($input)

ucwords => ucwords($input)

upper => strtoupper($input)

lower => strtolower($input)

nl2br => nl2br($input)

date:[日期格式] => date($format, strtotime($input))

number_format:[小数位数] => number_format($input, $decimals)

sanitize_email => filter_var($input, FILTER_SANITIZE_EMAIL)

sanitize_encoded => filter_var($input, FILTER_SANITIZE_ENCODED)

sanitize_string => filter_var($input, FILTER_SANITIZE_STRING)

sanitize_url => filter_var($input, FILTER_SANITIZE_URL)

limit:[字符数] => 限制字符串长度为指定字符数

mask:[可选掩码字符] => 使用掩码字符对字符串进行掩码(默认:*)

alpha => 将字符串转换为仅字母字符

alphanumeric => 将字符串转换为仅字母数字字符

numeric => 将字符串转换为仅数字字符

intval => intval($input, $base)

floatval => floatval($input)

boolval => boolval($input)

作用域规则

对于相同的模型或表单,您可能需要应用新的规则或删除不必要的规则。比如说,在注册过程中,您只需要用户名和电子邮件字段,而在个人资料表单中还有许多其他字段。当然,您可以构建两个不同的验证类,但有一个更好的方法:作用域!

您可以使用简单的PHP类属性定义任意数量的作用域。看以下例子

// Default rules
protected $rules = array(
    'username' => 'required',
    'email' => 'required|email'
);

// Profile rules
protected $rulesProfile => array(
    'name' => 'required',
    'age' => 'required|numeric|min:13'
);

// Registration rules
protected $rulesRegister => array(
    'terms' => 'accepted'
);

考虑“默认”范围(类属性$rules)作为一个共享的规则集,它将与您调用的任何其他范围合并。按照惯例,范围名称应采用“rulesName”格式(驼峰式),否则将无法找到类属性。例如:rulesLogin、rulesEdit或rulesDelete。

现在我们将初始化验证类

// Validates the 'default' and 'profile' rules combined,
// with the 'profile' ruleset taking precedence
$userValidator = UserValidator::make(Input::all())->scope('profile');

// Validates the 'default' and 'register' rules
$userValidator = UserValidator::make(Input::all())->scope('register');

// Validates the 'default', 'profile' and 'register' rules
$userValidator = UserValidator::make(Input::all())->scope(['profile', 'register']);

// Validates the 'default' rules only
$userValidator = UserValidator::make(Input::all());

默认行为是通过替换键来合并规则,以便范围具有优先级。这允许更灵活和更安全的合并,因为您可以轻松预测哪些规则将被计算。

以下规则集

protected $rules = [
    'username' => 'required'
];

protected $rulesProfile = [
    'username' => 'unique:users'
];

当选择“profile”范围时,将产生以下规则,因为范围将替换之前的规则。

[
    'username' => 'unique:users'
]

然而,可能存在您需要保留规则而不是替换规则的场景。为此,只需在验证类中添加一个类属性

class UserValidator extends ValidatorAssistant {

    protected $preserveScopeValues = true;

}

之前的规则将被计算为

[
    'username' => 'required|unique:users'
]

动态规则和消息

除了定义的规则和消息外,您还可以使用addRuleaddMessage方法轻松添加动态规则。这对于规则需要包含动态参数或需要根据某些动作动态添加时非常方便。

$userValidator = UserValidator::make(Input::all());

// New rules or messages will be added or overwrite existing ones
$userValidator->addRule('email', 'required|email|unique:users,email,10');
$userValidator->addMessage('email.unique', "Cmon!");

还有一个append方法,它不会重写规则集,而是将其新规则附加到它。它仅适用于现有规则集,但会静默失败。此外,它将用新规则覆盖相同类型的规则。考虑到之前的示例,假设“email”字段已经有一个“required”规则,我们可以按如下方式向其添加规则

// The combined rules will be: required|email|unique:users
$userValidator->append('email', 'email|unique:users');

参数绑定

作为一种完全不同且[可能]更优雅的方法,除了addRule()append()方法外,您还可以使用参数绑定。这对于需要分配变量的动态规则非常有用。让我们先编写一些规则,并为它们分配一些参数。

protected $rules = array(
    'username' => 'required|alpha|between:{min},{max}',
    'email' => 'required|unique:{table}',
    'birthday' => 'before:{date}'
);

这很简单!参数的名称没有任何限制,只要它们在花括号内且唯一,否则它们将被前面的规则覆盖。现在您已经弄清楚这一点,让我们将这些参数绑定到一些真实值上。

有三种方法可以绑定参数,我们将在以下示例中探讨它们

$userValidator = UserValidator::make(Input::all());

// One by one
$userValidator->bind('min', 5);
$userValidator->bind('max', 15);
$userValidator->bind('table', 'users')
$userValidator->bind('date', '2012-12-12');

// As an array
$userValidator->bind([
    'min' => 5,
    'max' => 15,
    'table' => 'users',
    'date' => '2012-12-12'
]);

// Overloading
$userValidator->bindMin(5);
$userValidator->bindMax(15);
$userValidator->bindTable('users');
$userValidator->bindDate('2012-12-12');

每种方法都会得到相同的结果,因此请使用您更舒适的方法。

之前和之后方法

您可以将两个方法添加到验证类中,并由ValidatorAssistant调用。before方法将在验证类初始化后运行,输入和规则设置之后。after方法将在验证完成后运行,作为ValidatorAssistant的最后一件事。您可以在其中编写任何代码,但显然如果它们包含一些任意代码就没有意义。它们最好用于在规则上执行操作、根据某些条件添加消息等。

添加它们非常简单

class UserValidator extends ValidatorAssistant {

    protected $rules = array(/* some rules */);

    protected function before()
    {
        // Rules, inputs, filters, attributes and
        // messages can be manipulated.
        $this->rules['username'] = 'required|alpha';
        $this->inputs['username'] = strtoupper($this->inputs['username']);
        $this->filters['username'] = 'trim';
        $this->attributes['username'] = 'Your name';
        $this->messages['username.required'] = "Username can't be empty.";
    }

    protected function after($validator)
    {
        if ($validator->fails()) {
            // run some code
        }
    }

}

如您所见,before方法是一个执行一些操作逻辑或条件的好地方。而after方法,它接收验证器实例作为参数,可以用来根据验证的状态运行代码。

自定义规则

Laravel通过Validator的extend()方法支持自定义规则。为了使过程尽可能简单,自定义规则可以作为验证器类中的方法创建。这些方法只需以“custom”前缀加上自定义规则的名称,其行为与Laravel文档中描述的闭包完全相同。

class UserValidator extends ValidatorAssistant {

    protected $rules = array(
        'username' => 'required|foo',
        'email' => 'foo_bar'
    );

    protected function customFoo($attribute, $value, $parameters)
    {
        return $value == 'foo';
    }

    protected function customFooBar($attribute, $value, $parameters)
    {
        return filter_var($value, FILTER_VALIDATE_EMAIL);
    }

}

唯一的约定是方法名称应以“custom”前缀开头,并且规则名称使用驼峰式命名法。例如,“my_rule”应写作“customMyRule()”。

集成 Fadion/Rule

Rule 是我开发的另一个包,它允许使用方法而不是数组,以表达性方式构建验证规则和消息。去看看吧!

使用 before() 方法将 Rule 与 ValidatorAssistant 集成非常简单,因为可以在实际运行验证器之前构建规则和消息。

class UserValidator extends ValidatorAssistant {

    protected function before()
    {
        Rule::add('username')->required()->alpha();
        Rule::add('email')->required()->email();

        // Rules with custom messages
        Rule::add('password')
            ->required()->message("Password is required.")
            ->between(5, 15)->message("Password must be between 5 to 15 characters.");

        $this->rules = Rule::get();
        $this->messages = RuleMessage::getMessages();
    }

}

可以使用 Rule 构建作用域规则

protected function before()
{
    Rule::add('username')->required()->alpha();
    Rule::add('email')->required()->email();

    $this->rules = Rule::get();

    Rule::add('username')->required();
    Rule::add('email')->email();

    // Add a 'profile' scope
    $this->rulesProfile = Rule::get();
}

最后,绑定

protected function before()
{
    Rule::add('age')->min('{min}');
    Rule::add('date')->date('{date}');

    $this->rules = Rule::get();
}