我正在尝试在Yii2中为DynamicFormWidget小部件添加自定义验证。有一个DynamicFormWidget小部件'百分比'以及所有'百分比'的总和动态创建的值应为100.我添加了验证规则
public function checkPercentageTotal($attribute, $params){
foreach (Yii::$app->request->post()['Category'] as $percentage){
$percentage_values[]=$percentage['percentage'];
}
if( array_sum($percentage_values)<>100){
$this->addError($attribute, 'Total percentage should be 100');return false;
}
}
并添加了
public function rules()
{
return [
[['percentage'] ,'checkPercentageTotal'],
];
}
但是没有显示错误。代码在function checkPercentageTotal()
这是我的视图文件中的代码:
<?php
use yii\helpers\Html;
use yii\bootstrap\ActiveForm;
use wbraganca\dynamicform\DynamicFormWidget;
use kartik\date\DatePicker;
use kartik\select2\Select2;
use dosamigos\tinymce\TinyMce;
use yii\helpers\ArrayHelper;
use backend\models\Department;
$script = <<< JS
$(".dynamicform_wrapper").on("afterInsert", function(e, item) {
console.log("afterInsert");
var row = $(this).closest('td');
var row=jQuery(item).find('select:eq(1)');
row.val('5')
});
JS;
$this->registerJs($script);
?>
<br>
<div class="dynamicform_wrapper">
<?php $form = ActiveForm::begin(['id' => 'dynamic-form', ]); ?>
<div class="box box-primary box-solid">
<div class="box-header with-border">
<h3 class="box-title">Create Survey Form</h3>
</div><br>
<div class="col-sm-12">
<div class="row">
<div class="col-sm-2">
<?= $form->field($modelSurvey, 'form_id')->textInput(['maxlength' => true]) ?>
</div>
<div class="col-sm-6">
<?= $form->field($modelSurvey, 'title')->textInput(['maxlength' => true]) ?>
</div>
<div class="col-sm-2">
<?php
$data=ArrayHelper::map(Department::find()->all(), 'id', 'department');
echo '<label class="control-label">Department</label>';
echo Select2::widget([
'name' => 'depart',
'id' => 'department',
'theme' =>Select2::THEME_BOOTSTRAP,
'value' => isset($modelSurvey->depart) ? $modelSurvey->depart : [],
'data' => $data,
// 'initValueText' => isset($model->dept) ? $model->dept : [],
'options' => [
'placeholder' => Yii::t('app', 'Choose Department...'),
'multiple' => true,
],
'pluginOptions' => [
'tags' => true,
'allowClear' => true,
'width' => '100%'
],]);
?>
</div>
<div class="col-sm-2">
<?php
$data=array('1'=>'Staff','2'=>'Student');
echo '<label class="control-label">Type</label>';
echo Select2::widget([
'name' => 'type_id',
'id' => 'type_id',
'theme' =>Select2::THEME_BOOTSTRAP,
'value' => isset($modelSurvey->type_id) ? $modelSurvey->type_id : [],
'data' => $data,
// 'initValueText' => isset($model->dept) ? $model->dept : [],
'options' => [
'placeholder' => Yii::t('app', 'Choose Type...'),
// 'multiple' => true,
],
'pluginOptions' => [
'tags' => true,
'allowClear' => true,
'width' => '100%'
],]);
?>
</div>
</div>
<div class="row">
<div class="col-sm-6">
<?= $form->field($modelSurvey, 'abstract')->widget(TinyMce::className(), [
'options' => ['rows' => 6],
'language' => 'en',
'clientOptions' => [
'plugins' => [
"advlist autolink lists link charmap print preview anchor",
"searchreplace visualblocks code fullscreen",
"insertdatetime media table contextmenu paste"
],
'toolbar' => "undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image"
]
]); ?>
</div>
<div class="col-sm-6">
<?= $form->field($modelSurvey, 'ledger')->widget(TinyMce::className(), [
'options' => ['rows' => 6],
'language' => 'en',
'clientOptions' => [
'plugins' => [
"advlist autolink lists link charmap print preview anchor",
"searchreplace visualblocks code fullscreen",
"insertdatetime media table contextmenu paste"
],
'toolbar' => "undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image"
]
]); ?>
</div>
</div>
</div>
<div class="padding-v-md">
<div class="line line-dashed"></div>
</div>
<div class="col-md-12">
<table class="table table-bordered table-striped">
<tbody class="container-items">
<?php foreach ($modelsCategory as $indexCategory => $modelCategory): ?>
<tr class="house-item" >
<?php
// necessary for update action.
if (! $modelCategory->isNewRecord) {
echo Html::activeHiddenInput($modelCategory, "[{$indexCategory}]id");
}
?>
<th colspan="5" bgcolor="#EC7063" style="display: inline-grid; width: 100%;">Categories</th>
<td style="display: inline-grid; width: 8%;"><?= $form->field($modelCategory, "[{$indexCategory}]percentage")->label(true)->textInput(['maxlength' => true]) ?></td>
<td style="display: inline-block; width: 10%;">
<button type="button" class="add-house btn btn-success btn-xs"><span class="glyphicon glyphicon-plus"></span></button>
<button type="button" class="remove-house btn btn-danger btn-xs"><span class="glyphicon glyphicon-minus"></span></button>
</td>
<td style="display: block;" >
<?= $this->render('_form-rooms', [
'form' => $form,
'indexCategory' => $indexCategory,
'modelsQuestion' => $modelsQuestion[$indexCategory],
]) ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php DynamicFormWidget::end(); ?>
<div class="form-group">
<div style="padding-left: 1%;">
<?= Html::submitButton($modelSurvey->isNewRecord ? 'Create' : 'Update', ['class' => 'btn btn-lg btn-danger']) ?>
</div></div>
<?php ActiveForm::end(); ?>
CategoryModel中的代码是
<?php
namespace backend\models;
use Yii;
/**
* This is the model class for table "category".
*
* @property int $id
* @property string $survey_id
*/
class Category extends \yii\db\ActiveRecord
{
/**
* @inheritdoc
*/
public static function tableName()
{
return 'category';
}
/**
* @inheritdoc
*/
public function rules()
{
return [
[['survey_id', 'percentage'], 'required'],
[['survey_id' ], 'string', 'max' => 250],
[['percentage'] ,'checkPercentageTotal'],
];
}
/**
* @inheritdoc
*/
public function attributeLabels()
{
return [
'id' => Yii::t('app', 'ID'),
'survey_id' => Yii::t('app', 'Survey ID'),
'percentage' => Yii::t('app', 'Percent'),
];
}
public function getQuestions()
{
return $this->hasMany(Question::className(), ['cat_id' => 'id']);
}
public function checkPercentageTotal($attribute, $params){
foreach (Yii::$app->request->post()['Category'] as $percentage){
$percentage_values[]=$percentage['percentage'];
}
if( array_sum($percentage_values)<>100){
$this->addError($attribute, 'Total percentage should be 100');return false;
}
}
}
和SurveyModel的代码是
<?php
namespace backend\models;
use Yii;
/**
* This is the model class for table "survey".
*
* @property int $id
* @property string $form_id
* @property string $dept
* @property string $title
* @property string $period
* @property string $abstract
* @property string $ledger
* @property string $apr_name
* @property string $apr_desg
* @property string $sem
* @property string $acad_yr
* @property string $sec
* @property string $qualification
*/
class Survey extends \yii\db\ActiveRecord
{
/**
* @inheritdoc
*/
/**===============================
* floated variable for survey form
*/
/**
* end here =====================
*/
public static function tableName()
{
return 'survey';
}
/**
* @inheritdoc
*/
public function rules()
{
return [
[['form_id', 'title', 'abstract', 'ledger','date_created'], 'required'],
[['form_id'], 'string', 'max' => 1250],
];
}
/**
* @inheritdoc
*/
public function attributeLabels()
{
return [
'id' => Yii::t('app', 'ID'),
'form_id' => Yii::t('app', 'Form ID'),
'title' => Yii::t('app', 'Title'),
'abstract' => Yii::t('app', 'Abstract'),
'ledger' => Yii::t('app', 'Ledger'),
'date_created' =>Yii::t('app', 'Date Created'),
'depart' =>Yii::t('app', 'Department'),
];
}
}
创建活动控制器的代码是
public function actionCreate()
{
$modelSurvey = new Survey;
$modelsCategory = [new Category];
$modelsQuestion = [[new Question]];
if ($modelSurvey->load(Yii::$app->request->post())) {
foreach($_POST['depart'] as $departindex => $departvalue){
$department[]=$departvalue;
}
$dep=implode(',',$department);
$modelsCategory = Model::createMultiple(Category::classname());
Model::loadMultiple($modelsCategory, Yii::$app->request->post());
// validate survey and category models
$valid[] = $modelSurvey->validate();
$valid[] = Model::validateMultiple($modelsCategory) && $valid;
if (isset($_POST['Question'][0][0])) {
foreach ($_POST['Question'] as $indexCategory => $questions) {
foreach ($questions as $indexQuestion => $question) {
$data['Question'] = $question;
$modelQuestion = new Question;
$modelQuestion->load($data);
$modelsQuestion[$indexCategory][$indexQuestion] = $modelQuestion;
$valid[] = $modelQuestion->validate();
}
}
}
if ($valid) {
$transaction = Yii::$app->db->beginTransaction();
try {
$today = date("Y-m-d H:i:s");
$modelSurvey->date_created=$today;
$modelSurvey->depart=$dep;
$modelSurvey->type_id=$_POST['type_id'];
if ($flag = $modelSurvey->save(false)) {
foreach ($modelsCategory as $indexCategory => $modelCategory) {
if ($flag === false) {
break;
}
$modelCategory->survey_id = $modelSurvey->id;
if (!($flag = $modelCategory->save(false))) {
break;
}
if (isset($modelsQuestion[$indexCategory]) && is_array($modelsQuestion[$indexCategory])) {
foreach ($modelsQuestion[$indexCategory] as $indexQuestion => $modelQuestion) {
$modelQuestion->cat_id = $modelCategory->id;
if (!($flag = $modelQuestion->save(false))) {
break;
}
}
}
}
}
if ($flag) {
$transaction->commit();
return $this->redirect(['view', 'id' => $modelSurvey->id]);
} else {
$transaction->rollBack();
}
} catch (Exception $e) {
$transaction->rollBack();
}
}
}
return $this->render('create', [
'modelSurvey' => $modelSurvey,
'modelsCategory' => (empty($modelsCategory)) ? [new Category] : $modelsCategory,
'modelsQuestion' => (empty($modelsQuestion)) ? [[new Question]] : $modelsQuestion,
]);
}
我认为自定义验证规则对动态表单小部件元素没有任何影响
答案 0 :(得分:1)
我想这是主要问题:
$valid[] = $modelSurvey->validate();
$valid[] = Model::validateMultiple($modelsCategory) && $valid;
// ...
if ($valid) {
即使您的所有验证都返回false
,您也会获得false
个数组,这些数组将被视为true
(非空数组=== true)。您可以尝试使用以下内容更改此代码:
$valid = Model::validateMultiple($modelsCategory) && $valid;
但老实说,你的代码非常混乱,需要一些严肃的重构。您不应直接在模型内部访问GET或POST数据,此操作和验证过于复杂。
对于这种情况,您应该创建单独的SurveyForm
,并且所有验证和保存都应该在其中。 checkPercentageTotal
验证程序并不真正适合Category
模型 - 现在您多次执行相同的验证(分别针对每个类别)。此验证可能应该在SurveyForm
模型上完成,只需执行一次。