Xem xét mối quan hệ giữa table cusc_sanpham
và cusc_hinhanh
Thiết kế của table cusc_hinhanh
Do table cusc_hinhanh
sử dụng cặp khóa chính gồm 2 cột (columns) là sp_ma
và ha_stt
nên chúng ta cần hiệu chỉnh model HinhAnh
để có thể đáp ứng được việc lưu trữ cặp khóa chính thông qua Laravel như sau:
Step 1: Hiệu chỉnh file model app\HinhAnh.php
, bổ sung các hàm xử lý với trường hợp sử dụng cặp khóa chính (Multi PrimaryKey) model HinhAnh:
<?php namespace App; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; class HinhAnh extends Model { public $timestamps = false; //created_at, updated_at protected $table = 'cusc_hinhanh'; protected $fillable = ['ha_ten']; protected $guarded = ['sp_ma', 'ha_stt']; protected $primaryKey = ['sp_ma', 'ha_stt']; public $incrementing = false; /** * Set the keys for a save update query. * * @param \Illuminate\Database\Eloquent\Builder $query * @return \Illuminate\Database\Eloquent\Builder */ protected function setKeysForSaveQuery(Builder $query) { $keys = $this->getKeyName(); if(!is_array($keys)){ return parent::setKeysForSaveQuery($query); } foreach($keys as $keyName){ $query->where($keyName, '=', $this->getKeyForSaveQuery($keyName)); } return $query; } /** * Get the primary key value for a save query. * * @param mixed $keyName * @return mixed */ protected function getKeyForSaveQuery($keyName = null) { if(is_null($keyName)){ $keyName = $this->getKeyName(); } if (isset($this->original[$keyName])) { return $this->original[$keyName]; } return $this->getAttribute($keyName); } }
Step 2: Thêm các hàm lấy danh sách Hình ảnh liên quan trong Model:
<?php namespace App; use Illuminate\Database\Eloquent\Model; use Carbon\Carbon; class SanPham extends Model { const CREATED_AT = 'sp_taoMoi'; const UPDATED_AT = 'sp_capNhat'; protected $table = 'cusc_sanpham'; protected $fillable = ['sp_ten', 'sp_giaGoc', 'sp_giaBan', 'sp_hinh', 'sp_thongTin', 'sp_danhGia', 'sp_taoMoi', 'sp_capNhat', 'sp_trangThai', 'l_ma']; protected $guarded = ['sp_ma']; protected $primaryKey = 'sp_ma'; protected $dates = ['sp_taoMoi', 'sp_capNhat']; protected $dateFormat = 'Y-m-d H:i:s'; public function loaisanpham() { return $this->belongsTo('App\Loai', 'l_ma', 'l_ma'); } public function hinhanhlienquan() { return $this->hasMany('App\HinhAnh', 'sp_ma', 'sp_ma'); } }
Step 3: Hiệu chỉnh chức năng Thêm mới Sản phẩm (create), bổ sung thêm ô chọn file cho phép người dùng upload cùng lúc nhiều hình ảnh
- Hiệu chỉnh view:
resources/views/backend/sanpham/create.blade.php
@extends('backend.layouts.master') @section('title') Thêm mới sản phẩm @endsection @section('custom-css') <!-- Các css dành cho thư viện bootstrap-fileinput --> <link href="{{ asset('vendor/bootstrap-fileinput/css/fileinput.css') }}" media="all" rel="stylesheet" type="text/css" /> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" crossorigin="anonymous"> <link href="{{ asset('vendor/bootstrap-fileinput/themes/explorer-fas/theme.css') }}" media="all" rel="stylesheet" type="text/css" /> @endsection @section('content') @if ($errors->any()) <div class="alert alert-danger"> <ul> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> </div> @endif <form method="post" action="{{ route('admin.sanpham.store') }}" enctype="multipart/form-data"> {{ csrf_field() }} <div class="form-group"> <label for="l_ma">Loại sản phẩm</label> <select name="l_ma" class="form-control"> @foreach($danhsachloai as $loai) @if(old('l_ma') == $loai->l_ma) <option value="{{ $loai->l_ma }}" selected>{{ $loai->l_ten }}</option> @else <option value="{{ $loai->l_ma }}">{{ $loai->l_ten }}</option> @endif @endforeach </select> </div> <div class="form-group"> <label for="sp_ten">Tên sản phẩm</label> <input type="text" class="form-control" id="sp_ten" name="sp_ten" value="{{ old('sp_ten') }}"> </div> <div class="form-group"> <label for="sp_giaGoc">Giá gốc</label> <input type="text" class="form-control" id="sp_giaGoc" name="sp_giaGoc" value="{{ old('sp_giaGoc') }}"> </div> <div class="form-group"> <label for="sp_giaGoc">Giá bán</label> <input type="text" class="form-control" id="sp_giaBan" name="sp_giaBan" value="{{ old('sp_giaBan') }}"> </div> <div class="form-group"> <div class="file-loading"> <label>Hình đại diện</label> <input id="sp_hinh" type="file" name="sp_hinh"> </div> </div> <div class="form-group"> <label for="sp_thongTin">Thông tin</label> <input type="text" class="form-control" id="sp_thongTin" name="sp_thongTin" value="{{ old('sp_thongTin') }}"> </div> <div class="form-group"> <label for="sp_danhGia">Đánh giá</label> <input type="text" class="form-control" id="sp_danhGia" name="sp_danhGia" value="{{ old('sp_danhGia') }}"> </div> <div class="form-group"> <label for="sp_taoMoi">Ngày tạo mới</label> <input type="text" class="form-control" id="sp_taoMoi" name="sp_taoMoi" value="{{ old('sp_taoMoi') }}"> </div> <div class="form-group"> <label for="sp_capNhat">Ngày cập nhật</label> <input type="text" class="form-control" id="sp_capNhat" name="sp_capNhat" value="{{ old('sp_capNhat') }}"> </div> <div class="form-group"> <label for="sp_trangThai">Trạng thái</label> <select name="sp_trangThai" class="form-control"> <option value="1" {{ old('sp_trangThai') == 1 ? "selected" : "" }}>Khóa</option> <option value="2" {{ old('sp_trangThai') == 2 ? "selected" : "" }}>Khả dụng</option> </select> </div> <div class="form-group"> <div class="file-loading"> <label>Hình ảnh liên quan sản phẩm</label> <input id="sp_hinhanhlienquan" type="file" name="sp_hinhanhlienquan[]" multiple> </div> </div> <button type="submit" class="btn btn-primary">Lưu</button> </form> @endsection @section('custom-scripts') <!-- Các script dành cho thư viện bootstrap-fileinput --> <script src="{{ asset('vendor/bootstrap-fileinput/js/plugins/sortable.js') }}" type="text/javascript"></script> <script src="{{ asset('vendor/bootstrap-fileinput/js/fileinput.js') }}" type="text/javascript"></script> <script src="{{ asset('vendor/bootstrap-fileinput/js/locales/fr.js') }}" type="text/javascript"></script> <script src="{{ asset('vendor/bootstrap-fileinput/themes/fas/theme.js') }}" type="text/javascript"></script> <script src="{{ asset('vendor/bootstrap-fileinput/themes/explorer-fas/theme.js') }}" type="text/javascript"></script> <script> $(document).ready(function() { $("#sp_hinh").fileinput({ theme: 'fas', showUpload: false, showCaption: false, browseClass: "btn btn-primary btn-lg", fileType: "any", previewFileIcon: "<i class='glyphicon glyphicon-king'></i>", overwriteInitial: false }); // Ô nhập liệu cho phép chọn nhiều hình ảnh cùng lúc (các hình ảnh liên quan đến sản phẩm) $("#sp_hinhanhlienquan").fileinput({ theme: 'fas', showUpload: false, showCaption: false, browseClass: "btn btn-primary btn-lg", fileType: "any", previewFileIcon: "<i class='glyphicon glyphicon-king'></i>", overwriteInitial: false, allowedFileExtensions: ["jpg", "gif", "png", "txt"] }); }); </script> <!-- Các script dành cho thư viện Mặt nạ nhập liệu InputMask --> <script src="{{ asset('vendor/input-mask/jquery.inputmask.min.js') }}"></script> <script src="{{ asset('vendor/input-mask/bindings/inputmask.binding.js') }}"></script> <script> $(document).ready(function() { // Gắn mặt nạ nhập liệu cho các ô nhập liệu Giá gốc $('#sp_giaGoc').inputmask({ alias: 'currency', positionCaretOnClick: "radixFocus", radixPoint: ".", _radixDance: true, numericInput: true, groupSeparator: ",", suffix: ' vnđ', min: 0, // 0 ngàn max: 100000000, // 1 trăm triệu autoUnmask: true, removeMaskOnSubmit: true, unmaskAsNumber: true, inputtype: 'text', placeholder: "0", definitions: { "0": { validator: "[0-9\uFF11-\uFF19]" } } }); // Gắn mặt nạ nhập liệu cho các ô nhập liệu Giá bán $('#sp_giaBan').inputmask({ alias: 'currency', positionCaretOnClick: "radixFocus", radixPoint: ".", _radixDance: true, numericInput: true, groupSeparator: ",", suffix: ' vnđ', min: 0, // 0 ngàn max: 100000000, // 1 trăm triệu autoUnmask: true, removeMaskOnSubmit: true, unmaskAsNumber: true, inputtype: 'text', placeholder: "0", definitions: { "0": { validator: "[0-9\uFF11-\uFF19]" } } }); // Gắn mặt nạ nhập liệu cho các ô nhập liệu Ngày tạo mới $('#sp_taoMoi').inputmask({ alias: 'datetime', inputFormat: 'yyyy-mm-dd' // Định dạng Năm-Tháng-Ngày }); // Gắn mặt nạ nhập liệu cho các ô nhập liệu Ngày cập nhật $('#sp_capNhat').inputmask({ alias: 'datetime', inputFormat: 'yyyy-mm-dd' // Định dạng Năm-Tháng-Ngày }); }); </script> @endsection
Step 4: hiệu chỉnh action store
của Backend\SanPhamController
Bổ sung chức năng Lưu trữ cùng lúc nhiều hình ảnh
use App\HinhAnh; // Chúng ta cần sử dụng model HinhAnh để truy vấn dữ liệu /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { // Bổ sung ràng buộc Validate $validation = $request->validate([ 'sp_hinh' => 'required|file|image|mimes:jpeg,png,gif,webp|max:2048', // Cú pháp dùng upload nhiều file 'sp_hinhanhlienquan.*' => 'file|image|mimes:jpeg,png,gif,webp|max:2048' ]); // Tạo mới object SanPham $sp = new SanPham(); $sp->sp_ten = $request->sp_ten; $sp->sp_giaGoc = $request->sp_giaGoc; $sp->sp_giaBan = $request->sp_giaBan; $sp->sp_thongTin = $request->sp_thongTin; $sp->sp_danhGia = $request->sp_danhGia; $sp->sp_taoMoi = $request->sp_taoMoi; $sp->sp_capNhat = $request->sp_capNhat; $sp->sp_trangThai = $request->sp_trangThai; $sp->l_ma = $request->l_ma; // Kiểm tra xem người dùng có upload hình ảnh Đại diện hay không? if ($request->hasFile('sp_hinh')) { $file = $request->sp_hinh; // Lưu tên hình vào column sp_hinh $sp->sp_hinh = $file->getClientOriginalName(); // Chép file vào thư mục "storate/public/photos" $fileSaved = $file->storeAs('public/photos', $sp->sp_hinh); } $sp->save(); // Lưu hình ảnh liên quan if($request->hasFile('sp_hinhanhlienquan')) { $files = $request->sp_hinhanhlienquan; // duyệt từng ảnh và thực hiện lưu foreach ($request->sp_hinhanhlienquan as $index => $file) { $file->storeAs('public/photos', $file->getClientOriginalName()); // Tạo đối tưọng HinhAnh $hinhAnh = new HinhAnh(); $hinhAnh->sp_ma = $sp->sp_ma; $hinhAnh->ha_stt = ($index + 1); $hinhAnh->ha_ten = $file->getClientOriginalName(); $hinhAnh->save(); } } // Hiển thị câu thông báo 1 lần (Flash session) Session::flash('alert-info', 'Them moi thanh cong ^^~!!!'); // Điều hướng về route index return redirect()->route('admin.sanpham.index'); }
Step 5: Hiệu chỉnh chức năng Sửa Sản phẩm (edit), bổ sung thêm ô chọn file cho phép người dùng upload cùng lúc nhiều hình ảnh
- Hiệu chỉnh view:
resources/views/backend/sanpham/edit.blade.php
@extends('backend.layouts.master') @section('title') Hiệu chỉnh sản phẩm @endsection @section('custom-css') <!-- Các css dành cho thư viện bootstrap-fileinput --> <link href="{{ asset('vendor/bootstrap-fileinput/css/fileinput.css') }}" media="all" rel="stylesheet" type="text/css"/> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" crossorigin="anonymous"> <link href="{{ asset('vendor/bootstrap-fileinput/themes/explorer-fas/theme.css') }}" media="all" rel="stylesheet" type="text/css"/> @endsection @section('content') @if ($errors->any()) <div class="alert alert-danger"> <ul> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> </div> @endif <form method="post" action="{{ route('admin.sanpham.update', ['id' => $sp->sp_ma]) }}" enctype="multipart/form-data"> <input type="hidden" name="_method" value="PUT" /> {{ csrf_field() }} <div class="form-group"> <label for="l_ma">Loại sản phẩm</label> <select name="l_ma" class="form-control"> @foreach($danhsachloai as $loai) @if($loai->l_ma == $sp->l_ma) <option value="{{ $loai->l_ma }}" selected>{{ $loai->l_ten }}</option> @else <option value="{{ $loai->l_ma }}">{{ $loai->l_ten }}</option> @endif @endforeach </select> </div> <div class="form-group"> <label for="sp_ten">Tên sản phẩm</label> <input type="text" class="form-control" id="sp_ten" name="sp_ten" value="{{ old('sp_ten', $sp->sp_ten) }}"> </div> <div class="form-group"> <label for="sp_giaGoc">Giá gốc</label> <input type="text" class="form-control" id="sp_giaGoc" name="sp_giaGoc" value="{{ old('sp_giaGoc', $sp->sp_giaGoc) }}"> </div> <div class="form-group"> <label for="sp_giaGoc">Giá bán</label> <input type="text" class="form-control" id="sp_giaBan" name="sp_giaBan" value="{{ old('sp_giaBan', $sp->sp_giaBan) }}"> </div> <div class="form-group"> <div class="file-loading"> <label>Hình đại diện</label> <input id="sp_hinh" type="file" name="sp_hinh"> </div> </div> <div class="form-group"> <label for="sp_thongTin">Thông tin</label> <input type="text" class="form-control" id="sp_thongTin" name="sp_thongTin" value="{{ old('sp_thongTin', $sp->sp_thongTin) }}"> </div> <div class="form-group"> <label for="sp_danhGia">Đánh giá</label> <input type="text" class="form-control" id="sp_danhGia" name="sp_danhGia" value="{{ old('sp_danhGia', $sp->sp_danhGia) }}"> </div> <div class="form-group"> <label for="sp_taoMoi">Ngày tạo mới</label> <input type="text" class="form-control" id="sp_taoMoi" name="sp_taoMoi" value="{{ old('sp_taoMoi', $sp->sp_taoMoi) }}" data-mask-datetime> </div> <div class="form-group"> <label for="sp_capNhat">Ngày cập nhật</label> <input type="text" class="form-control" id="sp_capNhat" name="sp_capNhat" value="{{ old('sp_capNhat', $sp->sp_capNhat) }}" data-mask-datetime> </div> <div class="form-group"> <label for="sp_trangThai">Trạng thái</label> <select name="sp_trangThai" class="form-control"> <option value="1" {{ old('sp_trangThai', $sp->sp_trangThai) == 1 ? "selected" : "" }}>Khóa</option> <option value="2" {{ old('sp_trangThai', $sp->sp_trangThai) == 2 ? "selected" : "" }}>Khả dụng</option> </select> </div> <div class="form-group"> <div class="file-loading"> <label>Hình ảnh liên quan sản phẩm</label> <input id="sp_hinhanhlienquan" type="file" name="sp_hinhanhlienquan[]" multiple> </div> </div> <button type="submit" class="btn btn-primary">Lưu</button> </form> @endsection @section('custom-scripts') <!-- Các script dành cho thư viện bootstrap-fileinput --> <script src="{{ asset('vendor/bootstrap-fileinput/js/plugins/sortable.js') }}" type="text/javascript"></script> <script src="{{ asset('vendor/bootstrap-fileinput/js/fileinput.js') }}" type="text/javascript"></script> <script src="{{ asset('vendor/bootstrap-fileinput/js/locales/fr.js') }}" type="text/javascript"></script> <script src="{{ asset('vendor/bootstrap-fileinput/themes/fas/theme.js') }}" type="text/javascript"></script> <script src="{{ asset('vendor/bootstrap-fileinput/themes/explorer-fas/theme.js') }}" type="text/javascript"></script> <script> $(document).ready(function() { $("#sp_hinh").fileinput({ theme: 'fas', showUpload: false, showCaption: false, browseClass: "btn btn-primary btn-lg", fileType: "any", append: false, showRemove: false, autoReplace: true, previewFileIcon: "<i class='glyphicon glyphicon-king'></i>", overwriteInitial: false, initialPreviewShowDelete: false, initialPreviewAsData: true, initialPreview: [ "{{ asset('storage/photos/' . $sp->sp_hinh) }}" ], initialPreviewConfig: [ { caption: "{{ $sp->sp_hinh }}", size: {{ Storage::exists('public/photos/' . $sp->sp_hinh) ? Storage::size('public/photos/' . $sp->sp_hinh) : 0 }}, width: "120px", url: "{$url}", key: 1 }, ] }); // Ô nhập liệu cho phép chọn nhiều hình ảnh cùng lúc (các hình ảnh liên quan đến sản phẩm) $("#sp_hinhanhlienquan").fileinput({ theme: 'fas', showUpload: false, showCaption: false, browseClass: "btn btn-primary btn-lg", fileType: "any", append: false, showRemove: false, autoReplace: true, previewFileIcon: "<i class='glyphicon glyphicon-king'></i>", overwriteInitial: false, allowedFileExtensions: ["jpg", "gif", "png", "txt"], initialPreviewShowDelete: false, initialPreviewAsData: true, initialPreview: [ @foreach($sp->hinhanhlienquan()->get() as $hinhAnh) "{{ asset('storage/photos/' . $hinhAnh->ha_ten) }}", @endforeach ], initialPreviewConfig: [ @foreach($sp->hinhanhlienquan()->get() as $index=>$hinhAnh) { caption: "{{ $hinhAnh->ha_ten }}", size: {{ Storage::exists('public/photos/' . $hinhAnh->ha_ten) ? Storage::size('public/photos/' . $hinhAnh->ha_ten) : 0 }}, width: "120px", url: "{$url}", key: {{ ($index + 1) }} }, @endforeach ] }); }); </script> <!-- Các script dành cho thư viện Mặt nạ nhập liệu InputMask --> <script src="{{ asset('vendor/input-mask/jquery.inputmask.min.js') }}"></script> <script src="{{ asset('vendor/input-mask/bindings/inputmask.binding.js') }}"></script> <script> $(document).ready(function() { // Gắn mặt nạ nhập liệu cho các ô nhập liệu Giá gốc $('#sp_giaGoc').inputmask({ alias: 'currency', positionCaretOnClick: "radixFocus", radixPoint: ".", _radixDance: true, numericInput: true, groupSeparator: ",", suffix: ' vnđ', min: 0, // 0 ngàn max: 100000000, // 1 trăm triệu autoUnmask: true, removeMaskOnSubmit: true, unmaskAsNumber: true, inputtype: 'text', placeholder: "0", definitions: { "0": { validator: "[0-9\uFF11-\uFF19]" } } }); // Gắn mặt nạ nhập liệu cho các ô nhập liệu Giá bán $('#sp_giaBan').inputmask({ alias: 'currency', positionCaretOnClick: "radixFocus", radixPoint: ".", _radixDance: true, numericInput: true, groupSeparator: ",", suffix: ' vnđ', min: 0, // 0 ngàn max: 100000000, // 1 trăm triệu autoUnmask: true, removeMaskOnSubmit: true, unmaskAsNumber: true, inputtype: 'text', placeholder: "0", definitions: { "0": { validator: "[0-9\uFF11-\uFF19]" } } }); // Gắn mặt nạ nhập liệu cho các ô nhập liệu Ngày tạo mới $('#sp_taoMoi').inputmask({ alias: 'datetime', inputFormat: 'yyyy-mm-dd' // Định dạng Năm-Tháng-Ngày }); // Gắn mặt nạ nhập liệu cho các ô nhập liệu Ngày cập nhật $('#sp_capNhat').inputmask({ alias: 'datetime', inputFormat: 'yyyy-mm-dd' // Định dạng Năm-Tháng-Ngày }); }); </script> @endsection
Step 6: hiệu chỉnh action update
của Backend\SanPhamController
Bổ sung chức năng Lưu trữ cùng lúc nhiều hình ảnh
/** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param int $id * @return \Illuminate\Http\Response */ public function update(Request $request, $id) { // Bổ sung ràng buộc Validate $validation = $request->validate([ 'sp_hinh' => 'file|image|mimes:jpeg,png,gif,webp|max:2048', // Cú pháp dùng upload nhiều file 'sp_hinhanhlienquan.*' => 'image|mimes:jpeg,png,gif,webp|max:2048' ]); // Tìm object Sản phẩm theo khóa chính $sp = SanPham::where("sp_ma", $id)->first(); $sp->sp_ten = $request->sp_ten; $sp->sp_giaGoc = $request->sp_giaGoc; $sp->sp_giaBan = $request->sp_giaBan; $sp->sp_thongTin = $request->sp_thongTin; $sp->sp_danhGia = $request->sp_danhGia; $sp->sp_taoMoi = $request->sp_taoMoi; $sp->sp_capNhat = $request->sp_capNhat; $sp->sp_trangThai = $request->sp_trangThai; $sp->l_ma = $request->l_ma; // Kiểm tra xem người dùng có upload hình ảnh Đại diện hay không? if ($request->hasFile('sp_hinh')) { // Xóa hình cũ để tránh rác Storage::delete('public/photos/' . $sp->sp_hinh); // Upload hình mới // Lưu tên hình vào column sp_hinh $file = $request->sp_hinh; $sp->sp_hinh = $file->getClientOriginalName(); // Chép file vào thư mục "photos" $fileSaved = $file->storeAs('public/photos', $sp->sp_hinh); } // Lưu hình ảnh liên quan if ($request->hasFile('sp_hinhanhlienquan')) { // DELETE các dòng liên quan trong table `HinhAnh` foreach ($sp->hinhanhlienquan()->get() as $hinhAnh) { // Xóa hình cũ để tránh rác Storage::delete('public/photos/' . $hinhAnh->ha_ten); // Xóa record $hinhAnh->delete(); } $files = $request->sp_hinhanhlienquan; // duyệt từng ảnh và thực hiện lưu foreach ($request->sp_hinhanhlienquan as $index => $file) { $file->storeAs('public/photos', $file->getClientOriginalName()); // Tạo đối tưọng HinhAnh $hinhAnh = new HinhAnh(); $hinhAnh->sp_ma = $sp->sp_ma; $hinhAnh->ha_stt = ($index + 1); $hinhAnh->ha_ten = $file->getClientOriginalName(); $hinhAnh->save(); } } $sp->save(); // Hiển thị câu thông báo 1 lần (Flash session) Session::flash('alert-info', 'Cập nhật thành công ^^~!!!'); // Điều hướng về trang index return redirect()->route('admin.sanpham.index'); }
Step 7: hiệu chỉnh action despoy
của Backend\SanPhamController
Bổ sung chức năng Xóa cùng lúc nhiều hình ảnh
/** * Remove the specified resource from storage. * * @param int $id * @return \Illuminate\Http\Response */ public function destroy($id) { // Tìm object Sản phẩm theo khóa chính $sp = SanPham::where("sp_ma", $id)->first(); // Nếu tìm thấy được sản phẩm thì tiến hành thao tác DELETE if (empty($sp) == false) { // DELETE các dòng liên quan trong table `HinhAnh` foreach ($sp->hinhanhlienquan()->get() as $hinhAnh) { // Xóa hình cũ để tránh rác Storage::delete('public/photos/' . $hinhAnh->ha_ten); // Xóa record $hinhAnh->delete(); } // Xóa hình cũ để tránh rác Storage::delete('public/photos/' . $sp->sp_hinh); } $sp->delete(); // Hiển thị câu thông báo 1 lần (Flash session) Session::flash('alert-info', 'Xóa sản phẩm thành công ^^~!!!'); // Điều hướng về trang index return redirect()->route('admin.sanpham.index'); }
Chương trình học
Các bài học
Bài học trước Bài học tiếp theo
Chương trình học
Bao gồm Module, Chương, Bài học, Bài tập, Kiểm tra...Chương trình học
Bài học trước Bài học tiếp theo