问题
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)
- Entity (with fields)
回答1:
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!
回答2:
I got the code to work with a few edits. I'm only showing the People entity for brevity, but it applies to the Organizations block also. The edit is where the filter saves the People model to the database.
From:
if(isset($record->person_data)) {
$person = People::create($record->person_data);
if($person->save()) {
$record->person_id = $person->id;
}
}
To:
if(isset($record->person_data)) {
//added this to make an array out of the $record->person_data(mongo doc)
//$person_data = array();
//foreach($record->person_data as $key => $value) {
//$person_data[$key] = $value;
//}
//replaced the mongo doc with the array
//Edited: accessing the data() method on an object will return an array of the properties, doing exactly what I put up there initially.
$person = People::create($record->person_data->data());
if($person->save()) {
//replaced the "id" with "_id"
$record->person_id = $person->_id;
}
//removed the person_data embedded doc from the entity doc
unset($record->person_data);
}
来源:https://stackoverflow.com/questions/8599991/lithium-fill-multiple-models-from-view