Laravel中JSON列操作:CV表多联系方式存储与视图回显
嘿,刚好我之前做过类似的多联系方式存储场景,给你一步步捋清楚怎么实现,分控制器处理提交和视图展示两部分来说:
一、控制器处理表单提交数据
首先,你需要先处理前端提交的phone[]和email[]数组,这里要注意过滤空值(避免用户留空输入框导致存空字符串到JSON里),然后直接存入JSON字段就行——Laravel对JSON列的支持很友好,直接传数组就会自动序列化,不用手动json_encode。
1. 先给模型加字段映射(关键!)
在你的Cv模型里添加$casts属性,这样从数据库取出数据时,JSON列会自动转成数组,不用每次手动解码:
// app/Models/Cv.php class Cv extends Model { use HasFactory; protected $fillable = [ // 其他可填充字段... 'phone', 'email' ]; protected $casts = [ 'phone' => 'array', // 自动把JSON转成数组 'email' => 'array' ]; }
2. 控制器的存储/更新逻辑
以store方法为例,先做验证,再过滤空值,最后存入数据库:
// app/Http/Controllers/CvController.php public function store(Request $request) { // 验证提交的数据,手机号的正则可以根据你的需求调整 $validated = $request->validate([ 'phone.*' => 'nullable|string|regex:/^1[3-9]\d{9}$/', // 国内手机号示例 'email.*' => 'nullable|email', // 其他CV字段的验证规则... ]); // 过滤掉空的手机号和邮箱,只保留有内容的项 $phones = array_filter($validated['phone'] ?? []); $emails = array_filter($validated['email'] ?? []); // 创建CV记录,直接传数组给JSON字段即可 Cv::create([ // 其他字段赋值... 'phone' => $phones, 'email' => $emails ]); return redirect()->route('cvs.index')->with('success', '简历创建成功'); }
如果是update方法,逻辑类似,把create换成update就行。
二、视图中检索展示数据
分两种场景:详情页展示,和编辑页回显并支持新增/删除输入框。
1. 详情页展示联系方式
因为模型加了$casts,$cv->phone和$cv->email直接是数组,循环展示即可:
<!-- resources/views/cvs/show.blade.php --> <div class="contact-info"> <h3>联系方式</h3> <div class="phones"> <h4>手机号</h4> @if(count($cv->phone) > 0) <ul> @foreach($cv->phone as $phone) <li>{{ $phone }}</li> @endforeach </ul> @else <p>暂无手机号</p> @endif </div> <div class="emails"> <h4>邮箱</h4> @if(count($cv->email) > 0) <ul> @foreach($cv->email as $email) <li>{{ $email }}</li> @endforeach </ul> @else <p>暂无邮箱</p> @endif </div> </div>
2. 编辑页回显并支持动态添加/删除
这里要把已有的联系方式渲染成输入框,同时支持用户新增或删除输入框,用简单的JS就能实现:
<!-- resources/views/cvs/edit.blade.php --> <div class="form-group"> <label for="phones">手机号</label> <div class="phone-inputs"> <!-- 回显已有的手机号 --> @foreach($cv->phone as $index => $phone) <div class="input-row"> <input type="text" name="phone[]" value="{{ old('phone.'.$index, $phone) }}" class="form-control"> <button type="button" class="btn btn-danger remove-btn">删除</button> </div> @endforeach <!-- 如果没有手机号,默认显示一个空输入框 --> @if(empty($cv->phone)) <div class="input-row"> <input type="text" name="phone[]" value="{{ old('phone.0') }}" class="form-control"> </div> @endif </div> <button type="button" class="btn btn-secondary mt-2" id="add-phone">添加手机号</button> </div> <div class="form-group mt-4"> <label for="emails">邮箱</label> <div class="email-inputs"> @foreach($cv->email as $index => $email) <div class="input-row"> <input type="text" name="email[]" value="{{ old('email.'.$index, $email) }}" class="form-control"> <button type="button" class="btn btn-danger remove-btn">删除</button> </div> @endforeach @if(empty($cv->email)) <div class="input-row"> <input type="text" name="email[]" value="{{ old('email.0') }}" class="form-control"> </div> @endif </div> <button type="button" class="btn btn-secondary mt-2" id="add-email">添加邮箱</button> </div> <!-- 动态添加/删除输入框的JS --> <script> // 通用的删除按钮逻辑 document.querySelectorAll('.remove-btn').forEach(btn => { btn.addEventListener('click', function() { this.parentElement.remove(); }); }); // 添加手机号输入框 document.getElementById('add-phone').addEventListener('click', function() { const container = document.querySelector('.phone-inputs'); const inputRow = document.createElement('div'); inputRow.className = 'input-row mt-2'; inputRow.innerHTML = ` <input type="text" name="phone[]" class="form-control"> <button type="button" class="btn btn-danger remove-btn ml-2">删除</button> `; container.appendChild(inputRow); // 给新添加的删除按钮绑定事件 inputRow.querySelector('.remove-btn').addEventListener('click', function() { this.parentElement.remove(); }); }); // 添加邮箱输入框(逻辑和手机号一致) document.getElementById('add-email').addEventListener('click', function() { const container = document.querySelector('.email-inputs'); const inputRow = document.createElement('div'); inputRow.className = 'input-row mt-2'; inputRow.innerHTML = ` <input type="text" name="email[]" class="form-control"> <button type="button" class="btn btn-danger remove-btn ml-2">删除</button> `; container.appendChild(inputRow); inputRow.querySelector('.remove-btn').addEventListener('click', function() { this.parentElement.remove(); }); }); </script>
一些额外的小提示
- 过滤空值的
array_filter很重要,不然用户提交空输入框的话,JSON里会存空字符串,影响数据整洁 - 如果需要对JSON列里的手机号/邮箱做查询,Laravel也支持,比如
Cv::whereJsonContains('phone', '138xxxx1234')->get() - 验证规则里的
nullable是必须的,因为允许单个输入框为空,但提交后会被过滤掉
内容的提问来源于stack exchange,提问作者priMo-ex3m
相关产品推荐
相关产品推荐

