title: CakePHP 2.3: Save multiple forms in multiple tables all at once in 1 page
body: <p>I'm trying to set up a commercial proposal system using CakePHP 2.3.</p>
  
  <p>It has 5 tables which are associated (see details below).
  This system will have 1 page on which are 5 forms for each table. (see details below).</p>
  
  <p>Form 1: table proposals<br/>
  Form 2: table clients FK proposal_id<br/>
  Form 3: table products FK client_id<br/>
  Form 4: table specifications FK product_id (of the product)<br/>
  Form 5: table appendices  FK product_id (of the product)<br/></p>
  
  <p>WHERE:</p>
  
  <p>proposals <strong>hasOne</strong> clients.<br/>
  ----------v----------<br/>
  clients <strong>beongsTo</strong> proposals AND <strong>hasMany</strong> products.<br/>
  ----------v----------<br/>
  products <strong>belongsTo</strong> clients AND <strong>hasMany</strong> specifications &amp; appendices.<br/>
  ----------v----------<br/>
  specifications <strong>belongsTo</strong> products.<br/>
  appendices <strong>belongsTo</strong> products.<br/></p>
  
  <p>The form 4 can have multiple row so it's inside a foreach loop to generate more input. Same for the form 5. Because 1 product can have multiple specifications and appendices.</p>
  
  <p>I admit, it's pretty tricky :)</p>
  
  <p>This is the solution I finally chose, but maybe there is better. For exemple, I could make a multi-step form but it seems quite difficult to put in place. Anyway, i'm open to suggestion.</p>
  
  <p>Meanwhile, I'm sure we can make this work so here are the details. For each table, I have created a model and made the appropriated connections. In each model I have enable the containable behaviour: <code>public $actsAs = array('Containable');</code>.</p>
  
  <p>Now here is the ProposalsController.php:</p>
  
  <pre><code>function admin_edit($id=null){
          $this-&gt;loadModel('Proposal','Client','Product', 'Specification', 'Appendice');
          $this-&gt;Proposal-&gt;contain('Proposal','Client','Product', 'Specification', 'Appendice');
  
          if ($this-&gt;request-&gt;is('put') || $this-&gt;request-&gt;is('Post')) {
              $data = $this-&gt;request-&gt;data;
              if (!empty($data)) {
                  // Use the following to avoid validation errors:
                  // unset($this-&gt;Proposal-&gt;Client-&gt;validate['proposal_id']);
                  // $this-&gt;Proposal-&gt;saveAssociated($data);
                  // $this-&gt;Session-&gt;setFlash("Le contenu a bien été édité");
                  // $this-&gt;redirect(array('action' =&gt; 'index', $data['Product']['id']));
                  debug($data);
              }
          }
          elseif($id){
              $this-&gt;Proposal-&gt;id = $id;
              $this-&gt;request-&gt;data = $this-&gt;Proposal-&gt;read(null,$id);
          }
      }
  </code></pre>
  
  <p>This edit action has many errors because I don't know how to set it up correctly in that case. So forgive me but I give you a raw code :). I would like this admin_function to add or edit, but again, in this case I don't know how to handle it.</p>
  
  <p>And the view admin_edit.ctp :</p>
  
  <pre><code>&lt;hr/&gt;
  &lt;h1&gt;Proposition&lt;/h1&gt;
  &lt;hr/&gt;
  
  &lt;?php echo $this-&gt;Form-&gt;create('Product'); ?&gt;
  
  &lt;?php echo $this-&gt;Form-&gt;input('Proposal.name', array('label' =&gt; "Nom de la proposition")); ?&gt;
  &lt;?php echo $this-&gt;Form-&gt;input('Proposal.created', array('label' =&gt; "Date de création")); ?&gt;
  &lt;?php echo $this-&gt;Form-&gt;input('Proposal.due', array('label' =&gt; "Date d'échéance")); ?&gt;
  &lt;?php echo $this-&gt;Form-&gt;input('Proposal.content', array('label' =&gt; "Termes &amp; conditions")); ?&gt;
  
  &lt;hr/&gt;
  &lt;h1&gt;Client&lt;/h1&gt;
  &lt;hr/&gt;
  
  &lt;?php echo $this-&gt;Form-&gt;input('Client.name', array('label' =&gt; "Nom du client")); ?&gt;
  &lt;?php echo $this-&gt;Form-&gt;input('Client.project', array('label' =&gt; "Nom du projet")); ?&gt;
  &lt;?php echo $this-&gt;Form-&gt;input('Client.address', array('label' =&gt; "Adresse")); ?&gt;
  &lt;?php echo $this-&gt;Form-&gt;input('Client.phone', array('label' =&gt; "Téléphone")); ?&gt;
  &lt;?php echo $this-&gt;Form-&gt;input('Client.email', array('label' =&gt; "Email")); ?&gt;
  &lt;?php echo $this-&gt;Form-&gt;hidden('Client.proposal_id'); ?&gt;
  
  &lt;hr/&gt;
  &lt;h1&gt;Produit&lt;/h1&gt;
  &lt;hr/&gt;
  
  &lt;?php echo $this-&gt;Form-&gt;input('Product.0.name', array('label' =&gt; "Nom du produit")); ?&gt;
  &lt;?php echo $this-&gt;Form-&gt;input('Product.0.reference', array('label' =&gt; "Référence")); ?&gt;
  &lt;?php echo $this-&gt;Form-&gt;input('Product.0.image', array('label' =&gt; "Image")); ?&gt;
  &lt;?php echo $this-&gt;Form-&gt;input('Product.0.pu', array('label' =&gt; "Prix Unitaire")); ?&gt;
  &lt;?php echo $this-&gt;Form-&gt;input('Product.0.quantity', array('label' =&gt; "Quantité")); ?&gt;
  &lt;?php echo $this-&gt;Form-&gt;input('Product.0.ce', array('label' =&gt; "CE")); ?&gt;
  &lt;?php echo $this-&gt;Form-&gt;input('Product.0.nf', array('label' =&gt; "NF")); ?&gt;
  &lt;?php echo $this-&gt;Form-&gt;input('Product.0.rohs', array('label' =&gt; "RoHS")); ?&gt;
  &lt;?php echo $this-&gt;Form-&gt;hidden('Product.0.client_id'); ?&gt;
  
  &lt;hr/&gt;
  &lt;h1&gt;Spécifications :&lt;/h1&gt;
  &lt;hr/&gt;
  
  &lt;?php
  foreach (range(0,1) as $i):
      $a=$i+1;
      echo '&lt;p&gt;Spécification '.$a.'&lt;/p&gt;';
      echo $this-&gt;Form-&gt;input('Specification.'.$i.'.name', array('label' =&gt; "Nom de la spécification"));
      echo $this-&gt;Form-&gt;input('Specification.'.$i.'.value', array('label' =&gt; "Valeur de la spécification"));
      echo $this-&gt;Form-&gt;hidden('Specification.'.$i.'.product_id');
  endforeach;
  ?&gt;
  
  &lt;hr/&gt;
  &lt;h1&gt;Annexes :&lt;/h1&gt;
  &lt;hr/&gt;
  
  &lt;?php
  foreach (range(0,1) as $j):
      $b=$j+1;
      echo '&lt;p&gt;Annexe '.$b.'&lt;/p&gt;';
      echo $this-&gt;Form-&gt;input('Appendice.'.$j.'.name', array('label' =&gt; "Image"));
      echo $this-&gt;Form-&gt;input('Appendice.'.$j.'.content', array('label' =&gt; "Description de l'annexe"));
      echo $this-&gt;Form-&gt;hidden('Appendice.'.$j.'.product_id');
  endforeach;
  ?&gt;
  
  &lt;?php echo $this-&gt;Form-&gt;end('valider'); ?&gt;
  </code></pre>
  
  <p>And finally, here is the array result of the debug($data):</p>
  
  <pre><code>array(
      'Proposal' =&gt; array(
          'name' =&gt; 'Proposition 3',
          'created' =&gt; array(
              'month' =&gt; '02',
              'day' =&gt; '19',
              'year' =&gt; '2013',
              'hour' =&gt; '08',
              'min' =&gt; '27',
              'meridian' =&gt; 'am'
          ),
          'due' =&gt; array(
              'month' =&gt; '02',
              'day' =&gt; '19',
              'year' =&gt; '2013',
              'hour' =&gt; '08',
              'min' =&gt; '27',
              'meridian' =&gt; 'am'
          ),
          'content' =&gt; 'Termes &amp; conditions'
      ),
      'Client' =&gt; array(
          'name' =&gt; 'Client 3',
          'project' =&gt; 'Projet Client 3',
          'address' =&gt; 'Adresse Client 3',
          'phone' =&gt; 'Téléphone Client 3',
          'email' =&gt; 'Email@test.com',
          'proposal_id' =&gt; ''
      ),
      'Product' =&gt; array(
          (int) 0 =&gt; array(
              'name' =&gt; 'Produit 3',
              'reference' =&gt; 'Référence Produit 3',
              'image' =&gt; 'Image Produit 3',
              'pu' =&gt; '100.77',
              'quantity' =&gt; '1000',
              'ce' =&gt; '1',
              'nf' =&gt; '0',
              'rohs' =&gt; '0',
              'client_id' =&gt; ''
          )
      ),
      'Specification' =&gt; array(
          (int) 0 =&gt; array(
              'name' =&gt; 'Specification 1',
              'value' =&gt; 'Valeur 1',
              'product_id' =&gt; ''
          ),
          (int) 1 =&gt; array(
              'name' =&gt; 'Specification 2',
              'value' =&gt; 'Valeur 2',
              'product_id' =&gt; ''
          )
      ),
      'Appendice' =&gt; array(
          (int) 0 =&gt; array(
              'name' =&gt; 'Image annexe 1',
              'content' =&gt; 'Description de l'annexe',
              'product_id' =&gt; ''
          ),
          (int) 1 =&gt; array(
              'name' =&gt; 'Image annexe 2',
              'content' =&gt; 'Description de l'annexe',
              'product_id' =&gt; ''
          )
      )
  )
  </code></pre>
  
  <p>So in this array, everything is there. I just need to take these data and save them all in the corresponding tables. The first problem is to manage with the table's associations. Then the 2 foreach loops that generate multiple row.</p>
  
  <p>I would like to save it all at once but is it even possible?</p>
  
  <p>After trying many ways to get it work, I've gone completely crazy and I just lost myself. I'm really desperate on that one, i mix up everything between the saving method and the request->data that contains everything but cannot get it saved. Anyway, i'm desperately in need for help!</p>
  
  <p>Thank you very much in advance for all the help you can give me, I really appreciate!</p>
  
  <hr>
  
  <h2>[EDIT]</h2>
  
  <p>I add my model to the present post for more detail.</p>
  
  <p><strong>Proposal.php:</strong></p>
  
  <pre><code>&lt;?php
  class Proposal extends AppModel {
  
      public $actsAs = array('Containable');
  
      public $validate = array(
          'name' =&gt; array(
              'rule'       =&gt; 'notEmpty',
              'message'    =&gt; "Veuillez préciser un titre"
          )
      ) ;
  
      public $hasOne = array(
          'Client' =&gt; array(
              'className'    =&gt; 'Client',
              'foreignKey'   =&gt; 'proposal_id',
              'dependent'    =&gt; true
              )
          );
  }
  </code></pre>
  
  <p><strong>Client.php:</strong></p>
  
  <pre><code>&lt;?php
  class Client extends AppModel {
  
      public $actsAs = array('Containable');
  
      public $belongsTo = array(
          'Proposal' =&gt; array(
              'className'    =&gt; 'Proposal',
              'foreignKey'   =&gt; 'proposal_id'
              )
          );
  
      public $hasMany = array(
          'Product' =&gt; array(
              'className'     =&gt; 'Product',
              'foreignKey'    =&gt; 'client_id',
              'conditions'    =&gt; '',
              'order'         =&gt; '',
              'limit'         =&gt; '',
              'dependent'     =&gt; true
              )
          );
  }
  </code></pre>
  
  <p><strong>Product.php:</strong></p>
  
  <pre><code>&lt;?php
  class Product extends AppModel {
  
      public $actsAs = array('Containable');
  
      public $belongsTo = array(
          'Client' =&gt; array(
              'className'    =&gt; 'Client',
              'foreignKey'   =&gt; 'client_id'
              )
          );
  
      public $hasMany = array(
          'Specification' =&gt; array(
              'className'     =&gt; 'Specification',
              'foreignKey'    =&gt; 'product_id',
              'conditions'    =&gt; '',
              'order'         =&gt; '',
              'limit'         =&gt; '',
              'dependent'     =&gt; true
              ),
          'Appendice' =&gt; array(
              'className'     =&gt; 'Appendice',
              'foreignKey'    =&gt; 'product_id',
              'conditions'    =&gt; '',
              'order'         =&gt; '',
              'limit'         =&gt; '',
              'dependent'     =&gt; true
              )
          );
  }
  </code></pre>
  
  <p><strong>Specification.php:</strong></p>
  
  <pre><code>&lt;?php
  class Specification extends AppModel {
  
      public $actsAs = array('Containable');
  
      public $belongsTo = array(
          'Product' =&gt; array(
              'className'    =&gt; 'Product',
              'foreignKey'   =&gt; 'product_id'
              )
          );
  }
  </code></pre>
  
  <p><strong>Appendice.php:</strong></p>
  
  <pre><code>&lt;?php
  class Appendice extends AppModel {
  
      public $actsAs = array('Containable');
  
      public $belongsTo = array(
          'ProductAppend' =&gt; array(
              'className'    =&gt; 'Product',
              'foreignKey'   =&gt; 'product_id'
              )
          );
  }
  </code></pre>