Laravel 4中相关模型验证的最佳实践?

时间:2014-01-17 15:48:55

标签: php validation laravel-4

我希望能够在启动保存之前验证具有相关模型的创建表单。我正在保存一个拥有许多相关模型的组织。由于我有许多多对多的关系,我必须首先创建主要模型,然后经历一个费力的过程,从输入数据中单独创建每个相关的模型。在创建初始组织后,我在组织存储库中调用“createRelated”方法。

public function createRelated($input)
{
    $this->orgtypes()->attach(1, ['objectstate_id' => ORGANIZATION_STARTED]);
    $this->addresses()->create(array_only($input, ['street1', 'zip', 'city', 'state_code']));
    for ($i=0; $i < 2; $i++) 
    { 
        if($input['phone_numbers_'.$i.'_number'])
        {
            $this->phoneNumbers()->create(['phone_number_type_id' => $input['phone_numbers_'.$i.'_phone_number_type_id'], 'number' => $input['phone_numbers_'.$i.'_number']]);
        }
    }  
    $this->procedures()->attach($input['procedures']);     
    $input['objectstate_id'] = USER_STARTED;
    $input['password'] = $this->encryptPassword($input['password']);
    $this->users()->create(array_only($input, ['first_name', 'last_name', 'email', 'password', 'objectstate_id']));
    $this->profileElements()->create(['type' => 'short_description', 'content' => $input['short_description']]);
}

不得不调出每个输入并将其发送到适当的模型对我来说似乎不对,但这就是我在IRC上听到的“正确”方式。但现在我来验证,目前没有验证这些模型的创建,即使输入可能违反验证规则。令我感到惊讶的是,没有命名约定(我已经看到),它清楚地标识了相关的模型输入,因此可以在不进行上述手动处理的情况下对其进行验证和创建。在开始上述保存事务之前,有关如何验证相关输入数据的任何想法吗?

我的组织验证器如下:

<?php namespace Acme\Validators\Organizations;

use Acme\Validators\ValidatorAbstract;

class Validator extends ValidatorAbstract {

   /**
    * Validation rules
    */
   protected $rules = array(
       'organization_name' => 'required'
   );

   /**
    * Custom Validation Messages
    */
   protected $messages = array(
   );

}

<?php namespace Acme\Validators;

use Illuminate\Support\MessageBag as MessageBag;


/*
* This class defines abstract Validator methods
*/

abstract class ValidatorAbstract implements ValidatorInterface {
   protected $validator;

   protected $input;

   protected $errors;

   /**
    * @param array $input
    *
    */
   public function __construct($input = NULL, MessageBag $bag)
   {
       $this->input = $input ?: \Input::all();

       $this->validator = \Validator::make($this->input, $this->rules, $this->messages);
       $this->errors = $bag;
   }

   /**
    * Run validation on input.
    *
    * @return boolean
    */
   public function passes()
   {
       if($this->validator->passes())
       {
           return true;
       }
       $this->errors = $this->validator->messages();

       return false;
   }

   /**
    * Get all errors stored.
    *
    * @return MessageBag
    */
   public function getErrors()
   {
       return $this->errors;
   }

   /**
    * Add new error.
    *
    * @return MessageBag
    */
   public function addError($key, $message)
   {
      return $this->errors->add($key, $message);
   }

}

我的抽象存储库类,我引入了Ardent

<?php namespace Acme\Repositories;

// use Eloquent;
use LaravelBook\Ardent\Ardent;

/*
* This class defines Eloquent methods
*/

abstract class EloquentRepositoryAbstract extends Ardent implements RepositoryInterface {

   protected $guarded = [];

   public $timestamps = false;
   public $autoHydrateEntityFromInput = true;    // Ardent hydrates on new entries' validation
   public $forceEntityHydrationFromInput = true; // Ardent hydrates whenever validation is called
…

我的控制器:

<?php

use \Acme\Repositories\Organizations\OrganizationRepositoryInterface;
use \Acme\Validators\Organizations\Validator;
use \Acme\Validators\Users\EditValidator as UsersValidator;

class OrganizationsController extends BaseController {

   /**
    * Organization Repository
    *
    * @var repository
    * @var validator
    * @var usersValidator
    */
   protected $repository;
   protected $validator;
   protected $usersValidator;

   public function __construct(OrganizationRepositoryInterface $repository, 
                               Validator $validator,
                               UsersValidator $usersValidator)
   {
       $this->repository = $repository;
       $this->validator = $validator;
       $this->users_validator = $usersValidator;
   }

[...] Vanilla雄辩的风格商店方法:

   public function store()
   {
       $input = Input::all();
       $opasses = $this->validator->passes();
       $ppasses = $this->repository->validateProcedure($input);
       $upasses = $this->users_validator->passes();
       if($opasses && $ppasses['status'] && $upasses)
       {
           $new_organization = $this->repository->create(['organization_name' => $input['organization_name']]);  
           if($input['logo_url'])
           {
               $new_organization->processImage($input, Request::root());             
           }
           if($new_organization->saveRelated($input, 'create'))
           {
               return Redirect::route('home')
                   ->with('message', 'Organization Created.');               
           }
           else
           {
               return Redirect::route('organizations.create')
                   ->withInput()
                   ->with('message', 'There were errors in the creation of this Organization');              
           }
       }
       return Redirect::route('organizations.create')
           ->withInput()
           ->withErrors(array_merge($this->validator->getErrors()->toArray(), $this->users_validator->getErrors()->toArray(), $ppasses))
           ->with('message', 'There were validation errors.');

   }

这一切似乎过于复杂和脆弱。

1 个答案:

答案 0 :(得分:0)

我认为最棘手的决定是在调用验证方法之前放置验证规则。这是一个有用的链接:http://laravel.com/docs/validation#available-validation-rules

以下是我的做法,但我仍在决定将验证规则/错误消息放在何处。

Laravel 4的内置验证类有一种方法可以使验证变得简单:

Validator::make($input, $rules=array(), $errors=array())

(第三个参数是可选的)

在您的情况下,在调用create方法之前(假设用于保存元素),您可以这样做:

$rules = array(
    "first_name" : "required",
    "second_name" : "required",
     and so on...
);

我给你的链接会给你可能的规则。最后,您还可以创建自己的自定义错误消息,如下所示:

$messages = array(
    "required" => "This :attribute field is required"
    and so on...
);

:属性将填写自动验证失败的字段。

然后,要验证您只是传入这些数组并调用pass()方法或fail()方法:

Validator::make($input, $rules, $messages)->passes() (如果传递则返回true,如果失败则返回false) 我认为这样做会更加清晰:

$validation = Validator::make($input, $rules, $messages);
if ($validation->passes()) {
      // save data
}

作为奖励,您可以访问此阵列中的错误消息:

$errors = $validation->messages();

所以,我希望能回答你的问题。我认为最大的问题是在哪里放置这些验证规则,因为我认为还没有一个约定。如果您有任何意见,请分享您的见解和意见。感谢。