Yii2中如何通过Select2将选中值传递至控制器
问题:Kartik Select2多选值无法传递到下载控制器
初始代码(无法获取选中值)
视图代码
<?= $form->field($model, 'msn')->widget(Select2::classname(), [ 'options' => [ 'id' => 'msn-select', // 添加ID属性 'placeholder' => '选择仪表...', 'multiple' => true, ], 'pluginOptions' => [ 'allowClear' => true, 'minimumInputLength' => 1, 'ajax' => [ 'url' => Url::to(['taskconfig/list']), 'dataType' => 'json', 'data' => new JsExpression('function(params) { return {q:params.term}; }'), 'processResults' => new JsExpression('function(data) { return { results: $.map(data.results, function(item) { return { id: item.id, text: item.text }; }) }; }'), ], ], ])->label('仪表'); ?> <div class="form-group"> <?= Html::a('下载Excel', ['download'], ['class' => 'btn btn-primary','id' => 'download-btn']) ?> </div>
控制器代码
public function actionDownload() { var_dump($_REQUEST); die(0); }
点击「下载Excel」按钮时,控制器返回NULL或array(0) { },无法获取选中的多个值。
更新后的代码
视图代码(改为表单提交)
<div class="task-config-form"> <?php $form = ActiveForm::begin(['id' => 'task','method'=>'post']); ?> <?= $form->field($model, 'msn')->widget(Select2::classname(), [ 'options' => [ 'id' => 'msn-select', // 添加ID属性 'placeholder' => '选择仪表...', 'multiple' => true, ], 'pluginOptions' => [ 'allowClear' => true, 'minimumInputLength' => 1, 'ajax' => [ 'url' => Url::to(['taskconfig/list']), 'dataType' => 'json', 'data' => new JsExpression('function(params) { return {q:params.term}; }'), 'processResults' => new JsExpression('function(data) { return { results: $.map(data.results, function(item) { return { id: item.id, text: item.text }; }) }; }'), ], ], ])->label('仪表'); ?> <div class="form-group"> <?= Html::submitButton('下载Excel', ['class' => 'btn btn-primary', 'id' => 'download-btn', 'name' => 'download']) ?> </div> <?php ActiveForm::end(); ?>
控制器代码
public function actionDownload() { $postData = Yii::$app->request->post(); $msnArray = $postData['TaskConfig']['msn']; // 移除数组中的空值 $msnArrayFilter = array_filter($msnArray); if (empty($msnArrayFilter)) { Yii::$app->session->setFlash('error', '未选择任何仪表。'); return $this->redirect(Yii::$app->request->referrer ?: Yii::$app->homeUrl); } $dataProvider = new ActiveDataProvider([ 'query' => TaskConfig::find()->select(['msn', 'ak', 'ek', 'utility'])->where(['msn' => $msnArrayFilter]), 'pagination' => false, ]); $models = $dataProvider->getModels(); // 创建Excel文件 $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); // 设置表头 $sheet->setCellValue('A1', 'Msn'); $sheet->setCellValue('B1', 'Ak'); $sheet->setCellValue('C1', 'Ek'); $sheet->setCellValue('D1', 'Utility'); // 填充数据 $row = 2; foreach ($msnArray as $msn) { // 假设TaskConfig::find()返回的模型包含Excel列对应的属性 $model = TaskConfig::find()->where(['msn' => $msn])->one(); if ($model !== null) { $sheet->setCellValue('A' . $row, $model->msn); $sheet->setCellValue('B' . $row, $model->ak); $sheet->setCellValue('C' . $row, $model->ek); $sheet->setCellValue('D' . $row, $model->utility); $row++; } } // 将Excel文件内容保存到临时文件 $microseconds = microtime(true); // 获取带微秒的当前时间戳 $microseconds = str_replace('.', '', $microseconds); // 移除微秒中的点 $filename = 'task_config_' . date('YmdHis') . '_' . $microseconds . '.xlsx'; try { // 将Excel文件保存到临时位置 $tempFilePath = sys_get_temp_dir() . '/' . $filename; $writer = IOFactory::createWriter($spreadsheet, 'Xlsx'); $writer->save($tempFilePath); // 将文件内容发送给用户下载 Yii::$app->response->sendFile($tempFilePath, $filename)->send(); return; } catch (\Throwable $e) { // 处理异常 Yii::error('生成Excel文件出错: ' . $e->getMessage()); Yii::$app->session->setFlash('error', '生成Excel文件时发生错误。'); return $this->redirect(Yii::$app->request->referrer ?: Yii::$app->homeUrl); } }
问题解决与优化建议
1. 确保多选值正确传递的关键配置
因为是多选场景,表单字段名必须以[]结尾,PHP才能将多个选中值解析为数组。如果ActiveForm没有自动生成正确的名称,可以手动指定:
'options' => [ 'id' => 'msn-select', 'placeholder' => '选择仪表...', 'multiple' => true, 'name' => 'TaskConfig[msn][]' // 手动指定数组格式的字段名 ],
2. 控制器取值的安全优化
直接访问$postData['TaskConfig']['msn']存在数组键不存在的风险,建议用更安全的写法:
$taskConfigData = Yii::$app->request->post('TaskConfig', []); $msnArray = $taskConfigData['msn'] ?? [];
3. 数据查询优化
原代码在foreach循环里逐个查询模型,会产生N+1查询问题,性能低下。可以直接用已获取的$models数组填充Excel:
// 填充数据(优化后) $row = 2; foreach ($models as $model) { $sheet->setCellValue('A' . $row, $model->msn); $sheet->setCellValue('B' . $row, $model->ak); $sheet->setCellValue('C' . $row, $model->ek); $sheet->setCellValue('D' . $row, $model->utility); $row++; }
4. 临时文件清理(可选)
生成的临时文件不会自动删除,可在发送文件后添加清理逻辑:
// 发送文件后删除临时文件 register_shutdown_function(function() use ($tempFilePath) { if (file_exists($tempFilePath)) { unlink($tempFilePath); } });
内容的提问来源于stack exchange,提问作者Moeez
相关产品推荐
相关产品推荐

