# Nested add forms of multiple tables via form buttons

**URL:** <https://discourse.cakephp.org/t/nested-add-forms-of-multiple-tables-via-form-buttons/7806>\
**Category:** Need Help\
**Created:** [May 11, 2020, 3:48pm UTC](https://discourse.cakephp.org/t/nested-add-forms-of-multiple-tables-via-form-buttons/7806 "2020-05-11T15:48:03Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![HypJ3U50N](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.cakephp.org/hypj3u50n/32/1803_2.png) [@HypJ3U50N](https://discourse.cakephp.org/u/HypJ3U50N)\
**Post date:** [May 11, 2020, 3:48pm UTC](https://discourse.cakephp.org/t/nested-add-forms-of-multiple-tables-via-form-buttons/7806/1 "2020-05-11T15:48:04Z")

</div>

I would like to implement add entities in one View, for example add a new song (unknown in DB) in a new song request. I don’t know how to access and implement multiple model’s data in one template.  
`songs` have id, title, artist, album etc.  
`song requests` have request\_id, song\_id (foreign key), date of request, user\_id etc.

One way would be to make multiple hasOne relations and foreignKeys to add Form-\>control() for unknown song.title, song.artist etc.( [Creating Inputs for Associated Data](https://book.cakephp.org/4/en/views/helpers/form.html#creating-inputs-for-associated-data)).

The other way (the correct one I guess) would be to implement the add() form of Songs if the user clicks on an “add new song” button.

In pseudo-code for add.php of song requests:

```
 <?= $this->Form->create($order) ?>
            <fieldset>
                <legend><?= __('Add Order') ?></legend>
                <?php ... echo $this->Form->button('add new song',  

```

**echoing the actual add() template code of Songs**  
$this-\>Form-\>button(‘confirm new song’, [‘controller’=\>‘Songs’, ‘action’=\>‘add’, **new song data fields (are no possible direct arguments for the add function)**]);  
…  
?\>   
  
\<?= $this-\>Form-\>button(\_\_('Submit')) ?\>  
\<?= $this-\>Form-\>end() ?\>

The problem is that I want to retrieve the actual add form of Songs, while staying at the same page and same location (song request add template). Is it even possible to have form elements for successive models within the fieldset and before the submit button of the first model form?

I could also implement the add() controller code of songs into add() of song requests controller and retrieve data fields of one form. I don’t know which solution is DRYer, especially since it would not automatically take validation of the fields for songs into account.

---

<div class="post-metadata">

**Author:** ![HypJ3U50N](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.cakephp.org/hypj3u50n/32/1803_2.png) [@HypJ3U50N](https://discourse.cakephp.org/u/HypJ3U50N)\
**Post date:** [May 11, 2020, 6:36pm UTC](https://discourse.cakephp.org/t/nested-add-forms-of-multiple-tables-via-form-buttons/7806/2 "2020-05-11T18:36:48Z")

</div>

The last option seems most feasible for me, so I want to implement the following form code after clicking a button:

 \<?= $this-\>Form-\>create($product) ?\> 

```
            <?php
                echo $this->Form->control('song_name');
               ...
            ?>
        </fieldset>
        <?= $this->Form->button(__('Submit')) ?>
        <?= $this->Form->end() ?>
    </div>

```

I did not find a direct way to run code from a button (even though I thought onclick would work as an HTML attribute?), so I implemented like this in the add.php of song request:

echo $this-\>Form-\>postButton(‘add new song’, ‘nested\_song\_form.php’);

with the former code in nested\_song\_form. However, clicking the button leads to no execution of this code, but staying on the same page with the error that the song request could not be saved.

---

<div class="post-metadata">

**Author:** ![dreamingmind](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.cakephp.org/dreamingmind/32/1857_2.png) [@dreamingmind](https://discourse.cakephp.org/u/dreamingmind)\
**Post date:** [May 12, 2020, 1:57am UTC](https://discourse.cakephp.org/t/nested-add-forms-of-multiple-tables-via-form-buttons/7806/3 "2020-05-12T01:57:37Z")

</div>

Here are some very general principals to keep in mind.

Any entity with its associated data as returned from a query can be converted to an array like this:

```auto
//example query
$result = $this->Tenants->find('all')
    ->where(['Tenants.id' => $id])
    ->contain(['Warehouses', 'TenantWorkers'])
    ->toArray();

//pick off one entity
$entity = $result[0];

$array = $entity->toArray();

```

This ‘native structure’ for your data can guide you when trying to save posted data.

If you follow Cake’s conventions in naming, querying, and creating your forms, the data that posts back to your actions will match this structure. If it does, it will almost always save directly with no further fiddling (including associated data).

I don’t know that this will work 100% of the time, but as a general principle, if you are having trouble getting form data to save, just do a query to get a result matching the kind of data you want to save and compare the result structure to your posted data structure. Then correct your form helper calls to match the structure of the query result. Typically this will be a matter of ‘naming’ the fields correctly in the Form-\>control() calls.

Perhaps this will guide you to a solution.

---

<div class="post-metadata">

**Author:** ![HypJ3U50N](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.cakephp.org/hypj3u50n/32/1803_2.png) [@HypJ3U50N](https://discourse.cakephp.org/u/HypJ3U50N)\
**Post date:** [May 12, 2020, 8:18am UTC](https://discourse.cakephp.org/t/nested-add-forms-of-multiple-tables-via-form-buttons/7806/4 "2020-05-12T08:18:02Z")

</div>

I think I am not looking for any (existing) entity in this problem. These are my issues as I can currently indicate:

**accessing non associated table requirements /options**

1. echo’ing Form-\>controls of non-associated DB fields can’t be checked whether the value is valid in a “foreign” form.  
1.1) echo’ing Form-\>controls of non-associated DB fields can’t list options that belong to the non-associated DB. For example, in the add order form I would like to add a new product and list available product.categories (equivalent to `'options' => $categories` in the add form of products.).

**insight in the controller**  
2) So far `debug($this->request->getData());` in the (e.g. song requests / order) controller doesn’t give output. The song request / order is stored in the DB, but not shown in the index since song / product ID is missing (which I first need to assign by a new song / product Entity in the song request / order controller).

**non-form button to add non-associated data fields on pressing**  
3) I am looking for a NON-Form button that simply executes the echo’ing code for non-associated fields within the form, without executing a form submit/post yet.

---

<div class="post-metadata">

**Author:** ![dreamingmind](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.cakephp.org/dreamingmind/32/1857_2.png) [@dreamingmind](https://discourse.cakephp.org/u/dreamingmind)\
**Post date:** [May 13, 2020, 3:38am UTC](https://discourse.cakephp.org/t/nested-add-forms-of-multiple-tables-via-form-buttons/7806/5 "2020-05-13T03:38:15Z")

</div>

> [@HypJ3U50N](#):
>
> echo’ing Form-\>controls of non-associated DB fields can’t be checked whether the value is valid in a “foreign” form.

You can use [Cake’s Modeless Forms](https://book.cakephp.org/4/en/core-libraries/form.html) to create any non-model schema and validation process you want.

> [@HypJ3U50N](#):
>
> For example, in the add order form I would like to add a new product and list available product.categories (equivalent to `'options' => $categories` in the add form of products.).

If you make the values you want available on a variable and set the [‘options’ key in the control properly](https://book.cakephp.org/4/en/views/helpers/form.html#creating-select-pickers), you can accomplish this.

> [@HypJ3U50N](#):
>
> So far `debug($this->request->getData())`

There won’t be any value here until you arrive with POST data from some form.

> [@HypJ3U50N](#):
>
> **non-form button to add non-associated data fields on pressing**

This sounds like something you could do with javascript and an ajax call.

---

<div class="post-metadata">

**Author:** ![HypJ3U50N](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.cakephp.org/hypj3u50n/32/1803_2.png) [@HypJ3U50N](https://discourse.cakephp.org/u/HypJ3U50N)\
**Post date:** [May 13, 2020, 10:55am UTC](https://discourse.cakephp.org/t/nested-add-forms-of-multiple-tables-via-form-buttons/7806/6 "2020-05-13T10:55:35Z")

</div>

Okay, so I have to create a form from scratch instead of implementing the baked forms.

In the example of Modeless Forms a new class is made for the custom form. I want to implement the new wholistic form in an existing controller, namely OrderController. In here, use Cake\Form\OneBigForm; still gives Class ‘App\Form\OneForm’ not found. Is this since I did not create a OneBigController, and therefore necessary to work with a custom form?

And are the explicit schemas of baked forms located somewhere? Such that I can copy these fields to the schema of OneBigForm and copy the validators from the Tables.

And to be sure, I really need Javascript and Ajax? What about the onClick HTML attribute? I was hoping for a local solution to add more Form-\>control fields with e.g. [onclick - Run PHP code with click on Button - Stack Overflow](https://stackoverflow.com/questions/46837067/run-php-code-with-click-on-button) .

PS

> [@dreamingmind](#):
>
> There won’t be any value here until you arrive with POST data from some form.

I was aware of this, but it didn’t show even after succesfully redirecting after the add form submission.

---

<div class="post-metadata">

**Author:** ![dreamingmind](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.cakephp.org/dreamingmind/32/1857_2.png) [@dreamingmind](https://discourse.cakephp.org/u/dreamingmind)\
**Post date:** [May 13, 2020, 2:33pm UTC](https://discourse.cakephp.org/t/nested-add-forms-of-multiple-tables-via-form-buttons/7806/7 "2020-05-13T14:33:23Z")

</div>

> [@HypJ3U50N](#):
>
> so I have to create a form from scratch instead of implementing the baked forms.

Yes. The baked forms are just a standard scaffold to get you rolling.

> [@HypJ3U50N](#):
>
> Cake\Form\OneBigForm; still gives Class ‘App\Form\OneForm’ not found

Is the fact that you use two different names here a typo in this message or your code? Did you include a `use` statement before your class declaration? And was your OneBigForm class properly namespaced?

> [@HypJ3U50N](#):
>
> And are the explicit schemas of baked forms located somewhere?

Yes. If you want to change them I think [these are the details](https://book.cakephp.org/bake/2/en/development.html#creating-a-bake-theme)

> [@HypJ3U50N](#):
>
> I was hoping for a local solution to add more Form-\>control fields with e.g. [onclick - Run PHP code with click on Button - Stack Overflow](https://stackoverflow.com/questions/46837067/run-php-code-with-click-on-button) .

That might work. I have no specific knowledge here.

> [@HypJ3U50N](#):
>
> but it didn’t show even after succesfully redirecting after the add form submission.

I think you would have to add the data to your new redirected request since I think redirect will truly make a new request (not forward the current one)

---

<div class="post-metadata">

**Author:** ![HypJ3U50N](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.cakephp.org/hypj3u50n/32/1803_2.png) [@HypJ3U50N](https://discourse.cakephp.org/u/HypJ3U50N)\
**Post date:** [May 14, 2020, 9:18pm UTC](https://discourse.cakephp.org/t/nested-add-forms-of-multiple-tables-via-form-buttons/7806/8 "2020-05-14T21:18:07Z")

</div>

> [@dreamingmind](#):
>
> Is the fact that you use two different names here a typo in this message or your code? Did you include a `use` statement before your class declaration? And was your OneBigForm class properly namespaced?

Yes sorry that’s a typo. I have set the class like:

```
<?php

namespace App\Form;

use Cake\Form\Form;
use Cake\Form\Schema;
use Cake\Validation\Validator;

class OneForm extends Form

```

and in OrdersController:

```
<?php
declare(strict_types=1);

namespace App\Controller;

use App\Form\OneForm;

...
public function add()
    {
		$oneBigForm=new OneForm();

```

---

<div class="post-metadata">

**Author:** ![dreamingmind](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.cakephp.org/dreamingmind/32/1857_2.png) [@dreamingmind](https://discourse.cakephp.org/u/dreamingmind)\
**Post date:** [May 15, 2020, 1:19am UTC](https://discourse.cakephp.org/t/nested-add-forms-of-multiple-tables-via-form-buttons/7806/9 "2020-05-15T01:19:09Z")

</div>

that looks right. Does it work now?

---

<div class="post-metadata">

**Author:** ![HypJ3U50N](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.cakephp.org/hypj3u50n/32/1803_2.png) [@HypJ3U50N](https://discourse.cakephp.org/u/HypJ3U50N)\
**Post date:** [May 15, 2020, 9:55am UTC](https://discourse.cakephp.org/t/nested-add-forms-of-multiple-tables-via-form-buttons/7806/10 "2020-05-15T09:55:39Z")

</div>

No, I hadn’t changed anything before responding, it is the same code as two days ago to which you responded 🙂

---

<div class="post-metadata">

**Author:** ![HypJ3U50N](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.cakephp.org/hypj3u50n/32/1803_2.png) [@HypJ3U50N](https://discourse.cakephp.org/u/HypJ3U50N)\
**Post date:** [May 15, 2020, 11:23am UTC](https://discourse.cakephp.org/t/nested-add-forms-of-multiple-tables-via-form-buttons/7806/11 "2020-05-15T11:23:54Z")

</div>

> [@dreamingmind](#):
>
> I think you would have to add the data to your new redirected request since I think redirect will truly make a new request (not forward the current one)

I probably misused the word redirection, I meant the routing from add() to index(). However, the data was actually requested and debug() was indeed not showing output. I created a new post for this specific issue here [Debug() visibility depending on following debug(e.g. $this)](https://discourse.cakephp.org/t/debug-visibility-depending-on-following-debug-e-g-this/7821)

---

<div class="post-metadata">

**Author:** ![Zuluru](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.cakephp.org/zuluru/32/1230_2.png) [@Zuluru](https://discourse.cakephp.org/u/Zuluru)\
**Post date:** [May 15, 2020, 3:15pm UTC](https://discourse.cakephp.org/t/nested-add-forms-of-multiple-tables-via-form-buttons/7806/12 "2020-05-15T15:15:09Z")

</div>

You may have correctly used the word redirection, and are now misusing “routing”. 🙂 Routing is basically what figures out which controller action to call for a particular URL; redirection is the act of sending the visitor to a new URL after completing some process.

Redirecting to `index` is normal after `add`, but you haven’t shown any code that includes a `redirect` call. And this may explain your other “bug”: if you’re calling `debug` and then `redirect`, then the output from the `debug` call will be lost forever. Debug output is not like `flash` text, which persists in the session between page loads.
