Forms which reference multiple models - smart way in ATK?


#1

Hi,

I will have several form which display and store thier content into several models. Have a look at this form:
formwithmultiplemodels1

This form mostly displays values of Group model, but also has one or more fields which represent values of Email model. So one Guest can have several Emails. Same will follow for Phone numbers and Addresses.

So, is there a smart way to do this in ATK? My solution at the moment works, but is raw: Each field representing an Email is referenced by putting the ID into the input name.

Adding a field for each referenced Email to group form:

//Go trough all referenced Emails
foreach($group->getAllEmails() as $e_id => $email) {
	$middle_form->addField('emails'.$e_id);
	$middle_form->model->getElement('emails'.$e_id)->never_persist = true;
	$middle_form->model->getElement('emails'.$e_id)->set($email);
	$middle_form->fields['emails'.$e_id]->on('focusout',               $middle_form->js()->form('submit'));

//Link to add a new Email
$t = new \atk4\ui\Label('+ weitere Email-Adresse hinzufügen', 'pmg-selectable');
$middle_form->layout->add($t, 'Emails');
$t->on('click', function () use ($app, $group) {
	$e = new \Pmg\Email($app->db);
	$e['group_id'] = $group['id'];
	$e->save();
	return (new \atk4\ui\jQuery('.pmgreloaditemchange'))->trigger('pmgreloaditemchange')
});

On Submit: Check all fields if ones name matches ‘emailsXX’. Then check if value changed, if so save.

  //define submit function
 $middle_form->onSubmit(function($middle_form) use ($group, $lcl, $app, $emails) {

	//check for all Address, Email and Tel fields
	foreach($middle_form->fields as $name => $field) {
		//if its an Email field
		if(substr($name, 0, 6) == 'emails') {
			$email_id = substr($name, 6);
			//if field is empty, delete Email
			if(empty(trim($field->getValue())) && isset($emails[$email_id])) {
				$email = new \Pmg\Email($app->db);
				$email->tryLoad($email_id);
				if($email->loaded()) {
					$email->delete();
				}
			}
			//compare if changes were made if so load, change and save Email.
			elseif($emails[$email_id] != $field->getValue()) {
				$email = new \Pmg\Email($app->db);
				$email->tryLoad($email_id);
				if($email->loaded()) {
					$email['email'] = $field->getValue();
					$email->save();
				}
			}
		}
  ...

As you can see, raw…
2 Ideas I had for making this nicer:

  1. Can several models be assigned to a form? So each form field points to modelA->field1 or modelB->field1 and so on.
  2. Any way to do this sensibly with joins, as one group can have several Emails?

Thanks and best regards
Philipp


#2

I’ll share my ideas about form and multiple models.

  1. I think it’s theoretically possible to link up model with multiple fields, but it is confusing.
  2. It would be more proper if this was done in Agile Data (https://github.com/atk4/data/issues/276)
  3. Another possibility is to implement JoinModel that can join multiple models with extended logic (even cross-persistence)

Either way this require more thinking before proposing anything further, I believe.