Search code examples
lithium

lithium fill multiple models from view


So lets say I have an Entities Model which is the base for a People and Organizations Model.

I've three empty collections, one for Entities, one for People, one for Organization.

Lets assume that the relationships between People and Organization will be ignored for the purpose of this question.

Finally, I have a view, with fields for all three models.

My question: Do I create a model class as a DTO (data transfer object) just to hold the data for all three models and save them to their respective collections in the controller?

The DTO hierarchy would be like this:

  • AddClientDTO
    • Entity (with fields)
      • Organization (with fields)
      • Person (with fields)

Solution

  • It sounds like you're trying to create records for 3 different models using a single form and controller action. Here's a simple way to do it that should at least get you started.

    First, create Entities, People, and Organization models in app/models.

    Then, create an entities controller containing the following action:

    public function add() {
       $entity = Entities::create(); 
       if($this->request->data && $entity->save($this->request->data)) {
          echo 'Success!';
          exit;
       }
       return compact('entity');
    }
    

    Next, create /app/views/entities/add.html.php:

    <?=$this->form->create($entity); ?>
    <?=$this->form->label('name', 'Entity Name');?>
    <?=$this->form->text('name');?>
    <?=$this->form->label('person_data[name]', 'Person Name');?>
    <?=$this->form->text('person_data[name]');?>
    <?=$this->form->label('organization_data[title]', 'Organization Title');?>
    <?=$this->form->text('organization_data[title]');?>
    <?=$this->form->submit('Save');?>
    <?=$this->form->end(); ?>
    

    Finally, describe your relationships and add a filter in app/models/Entities.php to save the person and organization when the data is saved:

    <?php
    
    namespace app\models;
    use \app\models\People;
    use \app\models\Organizations;
    
    class Entities extends \lithium\data\Model {
    
        public $belongsTo = array(
            'Organizations' => array(
                'class' => '\app\models\Organizations',
                'key' => 'organization_id',
            ),
            'People' => array(
                'class' => '\app\models\People',
                'key' => 'person_id',
            ),
        );
    
        public static function __init() {
            parent::__init();
    
            static::applyFilter('save', function($self, $params, $chain) {
    
                // If data is passed to the save function, set it in the record
                if ($params['data']) {
                    $params['entity']->set($params['data']);
                   $params['data'] = array();
                }
    
                $record = $params['entity'];
    
                if(isset($record->person_data)) {
                    $person = People::create($record->person_data);
                    if($person->save()) {
                        $record->person_id = $person->id;
                    }
                }
    
                if(isset($record->organization_data)) {
                    $org = Organizations::create($record->organization_data);
                    if($org->save()) {
                        $record->organization_id = $org->id;
                    }
                }
    
                $params['entity'] = $record;
                return $chain->next($self, $params, $chain);
    
            });
        }
    
    }
    
    ?>
    

    If I made too many assumptions about what you're trying do to, leave a comment and I'll adjust the code accordingly. Hope this helps!