Yii Composite Form Extension
Extension that can greatly simplify complex forms processing that have multiple relations.
Weavora's Git Repo - https://github.com/weavora/wform
Features:
1) Download and unpack source into protected/extensions/ folder.
2) Below you can see config settings for import:
// main.php return array( ... 'import' => array( ... 'ext.wform.*', ), ... );
3) Extension require changing of CActiveRecord::onUnsafeAttribute. Here are few options for that:
a) Extend all your models/forms from WActiveRecord instead of CActiveRecord
b) If you already has modified class for active record, then extend it from WActiveRecord or add onUnsafeAttribute method:
// protected/components/ActiveRecord.php // extend from WActiveRecord class ActiveRecord extends WActiveRecord { // you custom code here (if reqired) } // or add onUnsafeAttribute method class ActiveRecord extends CActiveRecord { // you custom code here (if required) /** * Raise onUnsafeAttribute event for active record * Required for wform extension * * @param $name unsafe attribute name * @param $value unsafe attribute value */ public function onUnsafeAttribute($name, $value) { $event = new CEvent($this, array('name' => $name, 'value' => $value)); $this->raiseEvent('onUnsafeAttribute', $event); return parent::onUnsafeAttribute($name, $value); } }
1) Modify model: define relations and attach behavior. You can also create separate class for the form extended from your model.
class MyModel extends WActiveRecord { ... public function relations() { return array( 'hasOneRelation' => array(self::HAS_ONE, 'HasOneModel', 'my_model_fk_into_related_model'), 'belongsToRelation' => array(self::BELONGS_TO, 'BelongsToModel', 'related_model_fk_into_my_model'), 'hasManyRelation' => array(self::HAS_MANY, 'HasManyModel', 'my_model_fk_into_related_model'), 'manyManyRelation' => array(self::MANY_MANY, 'ManyManyModel', 'linker(my_model_id,related_model_id)'), ); } ... public function behaviors() { return array( // attach wform behavior 'wform' => array( 'class' => 'ext.wform.WFormBehavior', // define relations which would be processed 'relations' => array('hasOneRelation', 'belongsToRelation', 'hasManyRelation', 'manyManyRelation'), ), // or you could allow to skip some relation saving if it was submitted empty 'wform' => array( 'class' => 'ext.wform.WFormBehavior', 'relations' => array( 'hasOneRelation' => array('required' => true), // default for HAS_ONE: false 'belongsToRelation' => array('required' => true), // default for BELONGS_TO: false 'hasManyRelation' => array('required' => false), // default for HAS_MANY: true 'manyManyRelation' => array('required' => false), // default for MANY_MANY: true ), ), ); } ... }
2) Create action to process form.
class MyController extends Controller { ... // form create & edit processed by single action public function actionEdit($id = null) { $myModel = $id ? MyModel::model()->with('hasManyRelation','manyManyRelation')->findByPk($id) : new MyModel(); if(Yii::app()->request->isPostRequest) { $myModel->attributes = Yii::app()->request->getPost('MyModel'); if ($myModel->save()) { $this->redirect('some/page'); } } $this->render('edit', array( 'model' => $myModel )); } }
3) Include js/jquery.multiplyforms.js jquery plugin into your layout
4) Define form using WForm instead of CActiveForm
// protected/views/my/edit.php <h1><?php echo ($model->isNewRecord ? "Create" : "Update " . $model->name);</h1> <?php $form = $this->beginWidget('WForm'); <!-- MyModel form fields --> <div class="row"> <?php echo $form->labelEx($model, 'name'); <?php echo $form->textField($model, 'name'); <?php echo $form->error($model, 'name'); </div> <!-- fields of embeded forms --> <!-- has_one relation --> <div class="row"> <?php echo $form->labelEx($model, 'hasOneRelation.name'); <?php echo $form->textField($model, 'hasOneRelation.name'); <?php echo $form->error($model, 'hasOneRelation.name'); </div> <!-- belongs_to relation --> <div class="row"> <?php echo $form->labelEx($model, 'belongsToRelation.name'); <?php echo $form->textField($model, 'belongsToRelation.name'); <?php echo $form->error($model, 'belongsToRelation.name'); </div> <!-- has_many relation --> <div class="row hasManyRelation"> <!-- exists items --> <?php if ($model->hasManyRelation): <?php foreach ($model->hasManyRelation as $index => $item): <div class="has-many-item"> <?php if (!$item->isNewRecord): <?php echo $form->hiddenField($model, "hasManyRelation.$index.id"); <?php endif; <?php echo $form->labelEx($model, "hasManyRelation.$index.text"); <?php echo $form->textField($model, "hasManyRelation.$index.text"); <?php echo $form->error($model, "hasManyRelation.$index.text"); <a href="#" class="delete">Delete</a> </div> <?php endforeach <?php endif; <!-- create new items --> <div class="has-many-item just-empty-form-template-hasManyRelation"> <?php echo $form->labelEx($model, "hasManyRelation..text"); <?php echo $form->textField($model, "hasManyRelation..text"); <?php echo $form->error($model, "hasManyRelation..text"); <a href="#" class="delete">Delete</a> </div> <a href="#" class="add">Add more</a> </div> <!-- many_many relation --> <div class="row manyManyRelation"> <!-- exists items --> <?php if ($model->manyManyRelation): <?php foreach ($model->manyManyRelation as $index => $item): <div class="many-many-item"> <?php if (!$item->isNewRecord): <?php echo $form->hiddenField($model, "manyManyRelation.$index.id"); <?php endif; <?php echo $form->labelEx($model, "manyManyRelation.$index.note"); <?php echo $form->textField($model, "manyManyRelation.$index.note"); <?php echo $form->error($model, "manyManyRelation.$index.note"); <a href="#" class="delete">Delete</a> </div> <?php endforeach <?php endif; <!-- create new items --> <div class="many-many-item just-empty-form-template-manyManyRelation"> <?php echo $form->labelEx($model, "manyManyRelation..note"); <?php echo $form->textField($model, "manyManyRelation..note"); <?php echo $form->error($model, "manyManyRelation..note"); <a href="#" class="delete">Delete</a> </div> <a href="#" class="add">Add more</a> </div> <div class="row buttons"> <?php echo CHtml::submitButton($model->isNewRecord ? 'Create' : 'Save'); </div> <?php $this->endWidget(); <script type="text/javascript"> $(document).ready(function(){ // init controls for multiply form $('.hasManyRelation').multiplyForms({ embedClass: 'has-many-item', templateClass: 'just-empty-form-template-hasManyRelation' }); $('.manyManyRelation').multiplyForms({ embedClass: 'many-many-item', templateClass: 'just-empty-form-template-manyManyRelation', addLink: '.add', deleteLink: '.delete', afterAdd: function(embedForm, multiplyFormInstance){}, beforeDelete: function(embedForm, multiplyFormInstance){} }); }); </script>
0.2
0.1
Total 3 comments
Guys this is an amazing extension, I was working in something like this, but it handles the AR relations really beautiful, just some cuestions, can it handle HAS_MANY|HAS_ONE with the "through" parameter? and how many levels of relations(depth) can I go?, again, GREAT extension.
Thank you.
There is one small problem with many relations if you want to get the ID of the input field via CHtml::activeId($model, "manyManyRelation.$index.note"); you will get a wrong id back. You will have to use CHtml::activeId($model, "manyManyRelation[$index][note]"); to get the correct id back.
I Just onder one thing, the first inputfield for a manymanyrelation shows up disabled? But when I press Add, the new ones that appear works. Also works perfectly fine to save it even if the first field is disabled and empty.. how do i fix this?:)
Leave a comment
Please login to leave your comment.