我正在构建一个基于REST的API,其中一个API具有以下请求
{ "categories_id" :"1", "product_name" : "Pen", "product_description" : "this is pen", "tags" : "pen,write", "image_count" : "4", "skus": { "is_shippable":"n", "actual_price":"100.55", "selling_price":"200.45", "quantity_type":"bucket", "quantity_total":"10", "bucket_value":"instock", "sort_order":"1" } }
这些是我的验证规则
protected $rules = [ ValidatorInterface::RULE_CREATE => [ 'users_id' => 'required', 'user_profiles_id' => 'required', 'categories_id' => 'required', 'product_name' => 'required|max:100', 'product_description' => 'required|max:1000', 'tags' => 'required', 'image_count'=>'required|integer', 'creation_mode'=>'required|integer', 'skus.is_shippable'=>'in:y,n', 'skus.actual_price'=>'regex:/^\s*(?=.*[1-9])\d*(?:\.\d{1,2})?\s*$/', 'skus.selling_price' => 'regex:/^\s*(?=.*[1-9])\d*(?:\.\d{1,2})?\s*$/', 'skus.quantity_type' => 'sometimes|required|in:finite,infinite,bucket', 'skus.quantity_total' => 'integer|required_if:skus.quantity_type,finite', 'skus.bucket_value'=>'in:instock,soldout,limited|required_if:skus.quantity_type,bucket', 'skus.sort_order'=> 'required|integer' ], ValidatorInterface::RULE_UPDATE => [ ] ];
上述请求已正确验证.但是skus可以在下面请求中包含多个实体
{ "categories_id" :"1", "product_name" : "Pen", "product_description" : "this is pen", "tags" : "pen,write", "image_count" : "4", "skus": [{ "is_shippable":"n", "actual_price":"100.55", "selling_price":"200.45", "quantity_type":"bucket", "quantity_total":"10", "bucket_value":"instock", "sort_order":"1" }, { "is_shippable":"n", "actual_price":"100.55", "selling_price":"200.45", "quantity_type":"bucket", "quantity_total":"10", "bucket_value":"instock", "sort_order":"1" }] }
如何验证是否存在多个嵌套实体?
您使用的是什么版本的Laravel?如果您使用的是Laravel 5.2,或者如果您不介意更新它,那么就有了开箱即用的解决方案.
数组验证
在Laravel 5.2中,验证数组表单输入字段要容易得多.例如,要验证给定数组输入字段中的每个电子邮件是否唯一,您可以执行以下操作:
$validator = Validator::make($request->all(), [ 'person.*.email' => 'email|unique:users' ]);
同样,您可以在语言文件中指定验证消息时使用*字符,从而可以轻松地为基于数组的字段使用单个验证消息:
'custom' => [ 'person.*.email' => [ 'unique' => 'Each person must have a unique e-mail address', ] ],
Laravel新闻的另一个例子:
假装你有一个包含输入字段数组的表单,如下所示:
在Laravel 5.1中添加验证规则,它需要循环并单独添加规则.而不是必须做所有这些"Laravelized"到这个:
$v = Validator::make($request->all(), [ 'person.*.id' => 'exists:users.id', 'person.*.name' => 'required:string', ]);
因此,如果您不想使用Laravel 5.2,则必须手动执行,如果您更新到Laravel 5.2,则可以使用新的数组验证,它将是这样的:
protected $rules = [ ValidatorInterface::RULE_CREATE => [ 'users_id' => 'required', 'user_profiles_id' => 'required', 'categories_id' => 'required', 'product_name' => 'required|max:100', 'product_description' => 'required|max:1000', 'tags' => 'required', 'image_count'=>'required|integer', 'creation_mode'=>'required|integer', 'skus.*.is_shippable'=>'in:y,n', 'skus.*.actual_price'=>'regex:/^\s*(?=.*[1-9])\d*(?:\.\d{1,2})?\s*$/', 'skus.*.selling_price' => 'regex:/^\s*(?=.*[1-9])\d*(?:\.\d{1,2})?\s*$/', 'skus.*.quantity_type' => 'sometimes|required|in:finite,infinite,bucket', 'skus.*.quantity_total' => 'integer|required_if:skus.quantity_type,finite', 'skus.*.bucket_value'=>'in:instock,soldout,limited|required_if:skus.quantity_type,bucket', 'skus.*.sort_order'=> 'required|integer' ], ValidatorInterface::RULE_UPDATE => [ ] ];编辑
Ihmo添加这个额外验证逻辑的最好方法是扩展Validator类创建你的CustomValidator类,它可能有点矫枉过正,但是当Laravel 5.2发布时你可以删除你的CustomValidator并继续使用Laravel的5.2 Validator而不做任何修改你的代码.
怎么样?首先,我们在我们下面创建一个文件夹,app/
我决定将此文件夹命名为Validator,您可以根据需要为其命名,只需记住更新以下类的命名空间即可.接下来,我们将在此文件夹CustomValidator.php,CustomValidatorServiceProvider.php和Factory.php中创建3个.php文件.
translator = $translator; $this->customMessages = $messages; $this->data = $this->parseData($data); $this->customAttributes = $customAttributes; // Explode the rules first so that the implicit ->each calls are made... $rules = $this->explodeRules($rules); $this->rules = array_merge((array) $this->rules, $rules); } /** * Explode the rules into an array of rules. * * @param string|array $rules * @return array */ protected function explodeRules($rules) { foreach ($rules as $key => $rule) { if (Str::contains($key, '*')) { $this->each($key, $rule); unset($rules[$key]); } else { $rules[$key] = (is_string($rule)) ? explode('|', $rule) : $rule; } } return $rules; } /** * Define a set of rules that apply to each element in an array attribute. * * @param string $attribute * @param string|array $rules * @return void * * @throws \InvalidArgumentException */ public function each($attribute, $rules) { $data = Arr::dot($this->data); foreach ($data as $key => $value) { if (Str::startsWith($key, $attribute) || Str::is($attribute, $key)) { foreach ((array) $rules as $ruleKey => $ruleValue) { if (! is_string($ruleKey) || Str::endsWith($key, $ruleKey)) { $this->mergeRules($key, $ruleValue); } } } } } /** * Get the inline message for a rule if it exists. * * @param string $attribute * @param string $lowerRule * @param array $source * @return string|null */ protected function getInlineMessage($attribute, $lowerRule, $source = null) { $source = $source ?: $this->customMessages; $keys = ["{$attribute}.{$lowerRule}", $lowerRule]; // First we will check for a custom message for an attribute specific rule // message for the fields, then we will check for a general custom line // that is not attribute specific. If we find either we'll return it. foreach ($keys as $key) { foreach (array_keys($source) as $sourceKey) { if (Str::is($sourceKey, $key)) { return $source[$sourceKey]; } } } } /** * Get the custom error message from translator. * * @param string $customKey * @return string */ protected function getCustomMessageFromTranslator($customKey) { $shortKey = str_replace('validation.custom.', '', $customKey); $customMessages = Arr::dot( (array) $this->translator->trans('validation.custom') ); foreach ($customMessages as $key => $message) { if ($key === $shortKey || (Str::contains($key, ['*']) && Str::is($key, $shortKey))) { return $message; } } return $customKey; } }
此自定义验证器具有在Laravel 5.2上进行的所有更改,您可以在此处进行检查
现在我们有了一个新的CustomValidator类,我们必须找到一种使用它的方法,因为我们必须扩展ValidatorServiceProvider和Validator工厂.
app->singleton('validator', function ($app) { $validator = new Factory($app['translator'], $app); // The validation presence verifier is responsible for determining the existence // of values in a given data collection, typically a relational database or // other persistent data stores. And it is used to check for uniqueness. if (isset($app['validation.presence'])) { $validator->setPresenceVerifier($app['validation.presence']); } return $validator; }); } }
resolver)) { return new Validator($this->translator, $data, $rules, $messages, $customAttributes); } return call_user_func($this->resolver, $this->translator, $data, $rules, $messages, $customAttributes); } }
现在我们已经扩展了验证以支持嵌套语法 sku.*.id
我们只需将Validator交换到CustomValidator,最后一步是更改文件config/app.php,在ServiceProviders数组中寻找ValidatorServiceProvider,只需注释该行并添加我们的扩展服务提供者,如下所示:
.... // Illuminate\Validation\ValidationServiceProvider::class, App\Validator\CustomValidatorServiceProvider::class, ....
我们评论它的原因是因为每当你将Laravel 5.1更新到5.2时你只想取消注释它,从列表中删除我们的CustomValidatorServiceProvider然后你删除我们的app/Validator文件夹,因为我们不再需要它了.