title: Best Practice for Related Model Validation in Laravel 4?
body: <p>I would like to be able to validate a create form with related models before I initiate a save. I am saving an organization which has a number of related models. Since I have a number of many-to-many relationships I have to create the primary model first then go through a laborious process of separately creating each related model from the input data. I call a 'createRelated' method within the Organization repository after the initial organization is created.</p>
  
  <pre><code>public function createRelated($input)
  {
      $this-&gt;orgtypes()-&gt;attach(1, ['objectstate_id' =&gt; ORGANIZATION_STARTED]);
      $this-&gt;addresses()-&gt;create(array_only($input, ['street1', 'zip', 'city', 'state_code']));
      for ($i=0; $i &lt; 2; $i++) 
      { 
          if($input['phone_numbers_'.$i.'_number'])
          {
              $this-&gt;phoneNumbers()-&gt;create(['phone_number_type_id' =&gt; $input['phone_numbers_'.$i.'_phone_number_type_id'], 'number' =&gt; $input['phone_numbers_'.$i.'_number']]);
          }
      }  
      $this-&gt;procedures()-&gt;attach($input['procedures']);     
      $input['objectstate_id'] = USER_STARTED;
      $input['password'] = $this-&gt;encryptPassword($input['password']);
      $this-&gt;users()-&gt;create(array_only($input, ['first_name', 'last_name', 'email', 'password', 'objectstate_id']));
      $this-&gt;profileElements()-&gt;create(['type' =&gt; 'short_description', 'content' =&gt; $input['short_description']]);
  }
  </code></pre>
  
  <p>Having to call out each input and sending it to its appropriate model does NOT seem right to me, but that is what I heard on IRC as the 'right' way. But now I come to validation and currently there is no validation on create for these models even though the input may violate the validation rules. I am surprised that there is no naming convention (that I have seen) that clearly identifies related model input so that it can all be validated and created without manual processing like the above.  Any ideas on how to validate related input data before I start the above save transaction?</p>
  
  <p>My validator for Organization looks like:</p>
  
  <pre><code>&lt;?php namespace Acme\Validators\Organizations;
  
  use Acme\Validators\ValidatorAbstract;
  
  class Validator extends ValidatorAbstract {
  
     /**
      * Validation rules
      */
     protected $rules = array(
         'organization_name' =&gt; 'required'
     );
  
     /**
      * Custom Validation Messages
      */
     protected $messages = array(
     );
  
  }
  
  &lt;?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-&gt;input = $input ?: \Input::all();
  
         $this-&gt;validator = \Validator::make($this-&gt;input, $this-&gt;rules, $this-&gt;messages);
         $this-&gt;errors = $bag;
     }
  
     /**
      * Run validation on input.
      *
      * @return boolean
      */
     public function passes()
     {
         if($this-&gt;validator-&gt;passes())
         {
             return true;
         }
         $this-&gt;errors = $this-&gt;validator-&gt;messages();
  
         return false;
     }
  
     /**
      * Get all errors stored.
      *
      * @return MessageBag
      */
     public function getErrors()
     {
         return $this-&gt;errors;
     }
  
     /**
      * Add new error.
      *
      * @return MessageBag
      */
     public function addError($key, $message)
     {
        return $this-&gt;errors-&gt;add($key, $message);
     }
  
  }
  </code></pre>
  
  <p>My Abstract Repository class where I bring in Ardent</p>
  
  <pre><code>&lt;?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
  …
  </code></pre>
  
  <p>My controller:</p>
  
  <pre><code>&lt;?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-&gt;repository = $repository;
         $this-&gt;validator = $validator;
         $this-&gt;users_validator = $usersValidator;
     }
  </code></pre>
  
  <p>[…] Vanilla eloquent style store method:</p>
  
  <pre><code>   public function store()
     {
         $input = Input::all();
         $opasses = $this-&gt;validator-&gt;passes();
         $ppasses = $this-&gt;repository-&gt;validateProcedure($input);
         $upasses = $this-&gt;users_validator-&gt;passes();
         if($opasses &amp;&amp; $ppasses['status'] &amp;&amp; $upasses)
         {
             $new_organization = $this-&gt;repository-&gt;create(['organization_name' =&gt; $input['organization_name']]);  
             if($input['logo_url'])
             {
                 $new_organization-&gt;processImage($input, Request::root());             
             }
             if($new_organization-&gt;saveRelated($input, 'create'))
             {
                 return Redirect::route('home')
                     -&gt;with('message', 'Organization Created.');               
             }
             else
             {
                 return Redirect::route('organizations.create')
                     -&gt;withInput()
                     -&gt;with('message', 'There were errors in the creation of this Organization');              
             }
         }
         return Redirect::route('organizations.create')
             -&gt;withInput()
             -&gt;withErrors(array_merge($this-&gt;validator-&gt;getErrors()-&gt;toArray(), $this-&gt;users_validator-&gt;getErrors()-&gt;toArray(), $ppasses))
             -&gt;with('message', 'There were validation errors.');
  
     }
  </code></pre>
  
  <p>This all seems overly complex and brittle.</p>