Hello!
I’m going to make form like this:
6614
And I have the following table schema (model relations):
6615
How can I implement it in ActiveForm style?
I tried to make it but I couldn’t due to lack of docs.
Any suggestions, please?
Hello!
I’m going to make form like this:
6614
And I have the following table schema (model relations):
6615
How can I implement it in ActiveForm style?
I tried to make it but I couldn’t due to lack of docs.
Any suggestions, please?
I’m afraid there wouldn’t be any out-of-the-box solution for this. Perhaps somebody would have a code for a similar form to share with you. Making the form will be the easy part if you have a good model.
You may also look at some existing projects for the inspiration. For example: http://easyiicms.com
Or some time ago I’ve posted a solution for a different type of form using many-to-many data. It’s not exactly what you need but it may give you some ideas:
I understand that there’s no any out-of-the-box solutions. I just need some reference, some kind of starting point.
Most of available open source projects on Yii2 are trivial and it’s hard to learn how to build a real-world application.
Okay, I’ll try to dig into Easyii CMS. Thank you, Vojtech!
Since skworden addressed only how to handle the form I’ll post here how I would handle the dynamic attributes.
I would generate Survey, Indicator, Response and Answer model using Gii and then proceed with following modifications:
<?php
namespace frontend\models;
use Yii;
use common\models\Response;
use common\models\Survey;
use common\models\Answer;
use yii\base\Model;
class ResponseForm extends Response
{
/**
* Overrides parent method. Populates the Response model and related Answer models.
*
* @inheritdoc
*/
public function load($data, $formName = null)
{
if (!parent::load($data, $formName)) {
return false;
}
return Model::loadMultiple($this->answers, $data, $formName);
}
/**
* Overrides parent method. Saves the Response model and related Answer models.
*
* @inheritdoc
*/
public function save($runValidation = true, $attributeNames = null)
{
$transaction = Yii::$app->db->beginTransaction();
try {
if (!parent::save($runValidation, $attributeNames) || !$this->saveAnswers()) {
$transaction->rollBack();
return false;
}
$transaction->commit();
} catch (\Exception $e) {
$transaction->rollBack();
throw $e;
}
return true;
}
/**
* Binds the Survey model and creates empty answers for a new response
*
* @param Survey $survey Related Survey model
*/
public function bindSurvey($survey)
{
$this->survey_id = $survey->id;
$answers = [];
foreach ($survey->indicators as $indicator) {
$answers[$indicator->id] = new Answer(['indicator_id' => $indicator->id]);
}
$this->setAnswers($answers);
}
/**
* Overrides parent method. Indexes answers by ID.
*
* @inheritdoc
*/
public function getAnswers()
{
return parent::getAnswers()->indexBy('indicator_id');
}
/**
* Setter for Answers
*
* @param Answers[] $answers
*/
protected function setAnswers($answers)
{
$this->answers = $answers;
}
/**
* Saves all answers. Sets the response_id for new records.
*
* @return boolean whether the saving succeeds
*/
protected function saveAnswers()
{
foreach ($this->answers as $answer) {
if ($answer->isNewRecord) {
$answer->response_id = $this->id;
}
if (!$answer->save()) {
return false;
}
}
return true;
}
}
/**
* @inheritdoc
*/
public function attributeLabels()
{
return [
'response_id' => Yii::t('app', 'Response ID'),
'indicator_id' => Yii::t('app', 'Indicator ID'),
'value' => $this->indicator->text,
];
}
/**
* Creates a new Response model.
* If creation is successful, the browser will be redirected to the 'view' page.
* @param integer $surveyID Related Survey ID
* @return mixed
*/
public function actionCreate($surveyID)
{
if (($survey = Survey::findOne($surveyID)) === null) {
throw new NotFoundHttpException('The requested page does not exist.');
}
$model = new ResponseForm();
$model->bindSurvey($survey);
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('create', [
'model' => $model,
]);
}
}
<div class="response-form">
<?php $form = ActiveForm::begin(); ?>
<?php foreach ($model->answers as $id => $answer): ?>
<?= $form->field($answer, "[$id]value")->textInput() ?>
<?php endforeach; ?>
<?= $form->field($model, 'name')->textInput(['maxlength' => true]) ?>
<?= $form->field($model, 'email')->textInput(['maxlength' => true]) ?>
<?= $form->field($model, 'comment')->textInput(['maxlength' => true]) ?>
<div class="form-group">
<?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
What a good answer, Vojtech! Thank you a lot!
I bet that someday you’ll be able to just submit your answers from this forum to a publishing house and make the best Yii book ever.
I’m not really sure how you mean it. There is a standard validation of loaded data performed by the save() method of the Response and Answer models and there is also a client side validation of the ActiveForm. But perhaps you mean something else.
I’m glad you found my answer useful. I wouldn’t dare to assume it would be worthy a book. There are surely other approaches and some could be even more elegant. Perhaps it could be used as a contribution to samdark’s Yii 2.0 Cookbook - https://github.com/samdark/yii2-cookbook. I’ll ask samdark about that.