基于CodeIgniter在控制器内实现新增与编辑表单的技术问询
优化CodeIgniter控制器内直接拼接表单的实现方案
我看到你在CodeIgniter控制器里直接拼接HTML字符串来实现新增/编辑表单功能,这种写法虽然能快速跑通功能,但后续维护、修改和扩展都会非常麻烦,完全违背了MVC框架的职责分离原则。下面给你拆解问题并给出具体的优化方案:
1. 修复控制器职责混乱问题(核心优化)
控制器的核心职责应该是处理请求、调用模型获取数据、传递数据给视图,而不是直接拼接HTML。我们把HTML渲染逻辑完全移到视图文件中:
优化后的控制器代码
function get_master() { // 获取POST参数 $store_id = $this->input->post('store_id'); if (empty($store_id)) { // 处理参数缺失的情况,比如跳转回店铺选择页 redirect('store_selection'); } // 获取店铺信息并设置会话 $get_store = $this->common->get_row(['store_id' => $store_id], DBPREFIX . "store"); if (!$get_store) { show_error('店铺不存在'); } $this->session->set_userdata([ 'store' => $get_store->store_state_id, 'company' => $get_store->store_company_id ]); // 获取主数据列表(用于渲染表单) $data['masters'] = $this->common->get_whereresult( DBPREFIX . 'apimaster', [ 'master_status' => 1, 'master_state' => $get_store->store_state_id ], 'master_name' ); // 加载视图,传递数据 $this->load->view('metrc_settings/master_form', $data); }
对应的视图文件(application/views/metrc_settings/master_form.php)
用CodeIgniter的视图语法渲染HTML,支持语法高亮,修改更方便:
<div class="container"> <?php foreach ($masters as $master): ?> <div class="row"> <div class="form-group col-md-12 col-sm-12 col-xs-12"> <div class="panel panel-default"> <div class="panel-heading" role="tab" id="headingOne-<?= $master->master_id ?>"> <h4 class="panel-title" style="height:18px;"> <!-- 使用CodeIgniter的form_open辅助函数,自动处理CSRF(如果开启) --> <?= form_open("add_metrcsettingmaster/{$master->master_id}") ?> <div class="form-group col-md-2 col-sm-2 col-xs-12"> <a data-toggle="collapse" data-parent="#accordion" href="#collapseOne-<?= $master->master_id ?>" aria-expanded="true" aria-controls="collapseOne-<?= $master->master_id ?>" > <?= html_escape($master->master_name) ?> </a> <input type="hidden" name="master_id" value="<?= $master->master_id ?>"> </div> <!-- 开始日期字段 --> <div class="form-group col-md-2 col-sm-2 col-xs-12 start_date" style="margin-top:-8px;"> <input placeholder="Start Date" type="text" class="form-control hasDatepicker" name="start_date" value="" > <span class="start_datetext">Sync Active</span> </div> <!-- 结束日期字段 --> <div class="form-group col-md-2 col-sm-2 col-xs-12 end_date" style="margin-top:-8px;"> <input placeholder="End Date" type="text" class="form-control hasDatepicker" name="end_date" value="" > <span class="end_datetext">Sync Expire</span> </div> <!-- 同步时间字段 --> <div class="form-group col-md-2 col-lg-2 col-sm-2 col-xs-12 time" style="margin-top:-5px;"> <input type="time" name="time" class="form-control" value=""> <span class="timetext">Sync Time</span> </div> <!-- 重复日期多选框 --> <div class="form-group col-md-2 col-sm-2 col-xs-12" style="margin-top: -5px"> <select name="days[]" class="form-control status chosen-select" multiple="multiple"> <option value="Monday">Monday</option> <option value="Tuesday">Tuesday</option> <option value="Wednesday">Wednesday</option> <option value="Thursday">Thursday</option> <option value="Friday">Friday</option> <option value="Saturday">Saturday</option> <option value="Sunday">Sunday</option> </select> </div> <!-- 手动/自动开关 --> <div class="form-group col-md-2 col-lg-2 col-sm-2 col-xs-12" style="margin-top:-8px;text-align:center;"> <label class="switch"> <p style="margin-top:10px;margin-left:-60px;"> Manual </p> <p style="margin-top:-27px;margin-left:60px;"> Auto </p> <input type="checkbox" name="manauto" id="chkPassportt-<?= $master->master_id ?>" value=""> <span class="slider round"></span> </label> </div> <!-- 提交按钮 --> <div class="col-md-2 col-lg-2 col-sm-2 col-xs-12 pull-right" style="margin-top:-8px;"> <input class="btn btn-danger" type="submit" name="submit" value="Submit"> </div> <?= form_close() ?> </h4> </div> <!-- 子项折叠面板 --> <div id="collapseOne-<?= $master->master_id ?>" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingOne-<?= $master->master_id ?>"> <div class="panel-body"> <div id="childdata-<?= $master->master_id ?>"> <?php // 预加载当前主项的子数据(推荐在控制器中提前查询后传递,这里为了演示直接在视图调用) $children = $this->common->get_whereresult( DBPREFIX . 'apichild', [ 'child_status' => 1, 'child_master' => $master->master_id ], 'child_apiname' ); foreach ($children as $child): ?> <div class="row"> <div class="form-group col-md-12 col-sm-12 col-xs-12"> <!-- 子项表单内容,可参考主项的写法拆分到局部视图 --> <?= html_escape($child->child_apiname) ?> </div> </div> <?php endforeach; ?> </div> </div> </div> </div> </div> </div> <?php endforeach; ?> </div>
2. 新增编辑功能的支持
当前代码只有新增逻辑,我们可以扩展支持编辑:
- 在控制器中判断是否存在编辑ID,查询对应数据传递给视图
- 在视图中为表单字段赋值,实现数据回显
控制器新增编辑逻辑
function add_metrcsettingmaster($master_id = null) { // 判断是否为编辑模式 $is_edit = false; $edit_data = []; if ($master_id && $this->input->server('REQUEST_METHOD') == 'GET') { $is_edit = true; $edit_data = $this->common->get_row( [ 'metrcsettingconf_master_id' => $master_id, 'metrcsettingconf_company_id' => $this->session->userdata('company'), 'metrcsettingconf_store_id' => $this->session->userdata('store') ], DBPREFIX . 'metrcsetting_conf' ); } // 处理表单提交(新增/编辑) if ($this->input->server('REQUEST_METHOD') == 'POST') { // 验证表单数据 $this->form_validation->set_rules('start_date', 'Start Date', 'required'); // 其他验证规则... if ($this->form_validation->run()) { $post_data = $this->input->post(); if ($is_edit) { // 执行更新逻辑 $this->common->update(DBPREFIX . 'metrcsetting_conf', $post_data, ['metrcsettingconf_id' => $edit_data->metrcsettingconf_id]); } else { // 执行新增逻辑 $this->common->insert(DBPREFIX . 'metrcsetting_conf', $post_data); } redirect('get_master'); } } // 传递编辑数据到视图 $data['is_edit'] = $is_edit; $data['edit_data'] = $edit_data; $data['master_id'] = $master_id; $this->load->view('metrc_settings/master_edit_form', $data); }
视图中回显编辑数据
<input placeholder="Start Date" type="text" class="form-control hasDatepicker" name="start_date" value="<?= $is_edit ? html_escape($edit_data->start_date) : '' ?>" >
3. 其他优化建议
- XSS安全防护:所有输出到HTML的动态内容都用
html_escape()包裹,防止XSS攻击 - 表单验证:使用CodeIgniter的
form_validation类对用户输入进行验证,确保数据合法性 - 代码复用:把重复的表单字段(比如日期选择器、开关组件)拆分成局部视图,通过
$this->load->view('partials/_date_picker')复用 - CSRF保护:开启CodeIgniter的CSRF防护,
form_open()会自动生成CSRF令牌字段,防止跨站请求伪造
内容的提问来源于stack exchange,提问作者Amod Kumar
相关产品推荐
相关产品推荐

