新建話題 upload
==================================================
http://larabbs.test/topics/create
==================================================
*route:
/*
| GET|HEAD | topics | topics.index | App\Http\Controllers\TopicsController@index | web
| POST | topics | topics.store | App\Http\Controllers\TopicsController@store | web
| GET|HEAD | topics/create | topics.create | App\Http\Controllers\TopicsController@create | web
| PUT|PATCH | topics/{topic} | topics.update | App\Http\Controllers\TopicsController@update | web
| DELETE | topics/{topic} | topics.destroy | App\Http\Controllers\TopicsController@destroy | web
| GET|HEAD | topics/{topic}/edit | topics.edit | App\Http\Controllers\TopicsController@edit | web
*/
Route::resource('topics', 'TopicsController', ['only' => ['index', 'create', 'store', 'update', 'edit', 'destroy']]);
Route::post('upload_image', 'TopicsController@uploadImage')->name('topics.upload_image');
==================================================
*controller:
app\Http\Controllers\TopicsController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests\TopicRequest;
use App\Models\Topic;
use App\Models\Category;
use App\Models\User;
use App\Models\Link;
use Auth;
use App\Handlers\ImageUploadHandler;
class TopicsController extends Controller
{
public function __construct()
{
$this->middleware('auth', ['except' => ['index', 'show']]);
}
//新建話題:view
public function create(Topic $topic)
{
$categories = Category::all();
return view('topics.create_and_edit', compact('topic', 'categories'));
}
//新建話題:儲存資料
public function store(TopicRequest $request, Topic $topic)
{
$topic->fill($request->all());
$topic->user_id = Auth::id();
$topic->save();
return redirect()->to($topic->link())->with('success', '建立話題成功!');
}
//新建話題:上傳圖片
public function uploadImage(Request $request, ImageUploadHandler $uploader)
{
//初始化返回資料,默認是失敗的
$data = [
'success' => false,
'msg' => '上傳失敗!',
'file_path' => '',
];
//判斷是否有上傳檔案,並賦值給 $file
if($file = $request->upload_file){
//保存圖片到主機(本地端)
$result = $uploader->save($request->upload_file, 'topics', \Auth::id(), 1024);
//圖片保存成功
if($result){
$data['file_path'] = $result['path'];
$data['msg'] = '上傳成功!';
$data['success'] = true;
}
}
return $data;
}
}
---------------------------
app\Http\Requests\TopicRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class TopicRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
switch($this->method())
{
//CREATE
case 'POST':
//UPDATE
case 'PUT':
case 'PATCH':
{
return [
'title' => 'required|min:2',
'body' => 'required|min:3',
'category_id' => 'required|numeric',
];
}
case 'GET':
case 'DELETE':
default:
{
return [];
};
}
}
public function messages()
{
return [
'title.min' => '標題必須填寫最少2個字',
'body.min' => '文章內容必須填寫最少3個字',
];
}
}
---------------------------
app\Handlers\ImageUploadHandler.php
<?php
namespace App\Handlers;
use Image;
use Str;
class ImageUploadHandler
{
protected $allowed_ext = ["png", "jpg", "gif", "jpeg"];
public function save($file, $folder, $file_prefix, $max_width = false)
{
//建立儲存圖片的資料夾規則,例如:uploads/images/avatars/202010/22/
//資料夾切割可讓找尋圖片的效率更高
$folder_name = "uploads/images/$folder/" . date('Ym/d', time());
//儲存圖片的實際路徑( public_path() 是 public資料夾 的路徑 )
//例如: /home/vagrant/code/larabbs/public/uploads/images/avatars/202010/22/
$upload_path = public_path() . '/' . $folder_name;
//獲取圖檔的副檔名 (若圖檔沒有副檔名,此處確保副檔名一直存在)
//若圖檔有副檔名,則取其副檔名 ( $file->getClientOriginalExtension() )
//若圖檔沒有副檔名,則設定為png
$extension = strtolower($file->getClientOriginalExtension()) ?: 'png';
// dd($extension);
//連接檔案名稱,加前綴是為了增加辨識度,前綴可以是相關數據模型的 ID
//例如:1_1493521050_7BVc9v9ujP.png
$filename = $file_prefix . '_' . time() . '_' . Str::random(10) . '.' . $extension;
//如果上傳的不是圖片,則終止操作
if(! in_array($extension, $this->allowed_ext)){
return false;
}
//把圖片移到自己設定的路徑
$file->move($upload_path, $filename);
//如果限制了圖片寬度,就執行圖片裁剪
if($max_width && $extension != 'gif'){
//此類別封裝的函數,用於執行圖片裁剪
$this->reduceSize($upload_path . '/' . $filename, $max_width);
}
return [
'path' => config('app.url') . "/$folder_name/$filename"
];
}
public function reduceSize($file_path, $max_width)
{
//先實例化,參數是圖片的路徑
$image =Image::make($file_path);
//調整圖片尺寸
$image->resize($max_width, null, function($constraint){
//設定寬度為 $max_width,高度為等比例縮放
$constraint->aspectRatio();
//防止裁圖時圖片尺寸變大
$constraint->upsize();
});
//儲存已經調整完成的圖片
$image->save();
}
}
==================================================
*view:
resources\views\topics\create_and_edit.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<div class="col-md-10 offset-md-1">
<div class="card">
<div class="card-body">
<h2 class="">
<i class="far fa-edit"></i>
@if($topic->id)
編輯話題
@else
新建話題
@endif
</h2>
<hr>
@if($topic->id)
<form action="{{ route('topics.update', $topic->id) }}" method="POST" accept-charset="UTF-8">
<input type="hidden" name="_method" value="PUT">
@else
<form action="{{ route('topics.store') }}" method="POST" accept-charset="UTF-8">
@endif
<input type="hidden" name="_token" value="{{ csrf_token() }}">
@include('shared._error')
<div class="form-group">
<input class="form-control" type="text" name="title" value="{{ old('title', $topic->title) }}" placeholder="請填寫標題" required>
</div>
<div class="form-group">
<select class="form-control" name="category_id" required>
<option value="" hidden disabled {{ $topic->id ? '' : 'selected' }}>請選擇分類</option>
@foreach($categories as $value)
<option value="{{ $value->id }}" {{ $topic->category_id == $value->id ? 'selected' : '' }}>
{{ $value->name }}
</option>
@endforeach
</select>
</div>
<div class="form-group">
<textarea name="body" class="form-control" id="editor" rows="6" placeholder="請填寫至少3個字的內容" required>{{ old('body', $topic->body) }}</textarea>
</div>
<div class="well well-sm">
<button type="submit" class="btn btn-primary"><i class="far fa-save mr-2" aria-hidden="true"></i> 儲存</button>
</div>
</form>
</div>
</div>
</div>
</div>
@endsection
@section('styles')
<link rel="stylesheet" type="text/css" href="{{ asset('css/simditor.css') }}">
@stop
@section('scripts')
<script type="text/javascript" src="{{ asset('js/module.js') }}"></script>
<script type="text/javascript" src="{{ asset('js/hotkeys.js') }}"></script>
<script type="text/javascript" src="{{ asset('js/uploader.js') }}"></script>
<script type="text/javascript" src="{{ asset('js/simditor.js') }}"></script>
<script>
$(document).ready(function(){
var editor = new Simditor({
textarea: $('#editor'),
upload: {
url: '{{ route('topics.upload_image') }}',
params: {
_token: '{{ csrf_token() }}'
},
fileKey: 'upload_file',
connectionCount: 3,
leaveConfirm: '檔案上傳中,關閉此頁面將取消上傳!'
},
pasteImage: true,
});
});
</script>
@stop
------------------------
Route::post('upload_image', 'TopicsController@uploadImage')->name('topics.upload_image');
==================================================
*model:
app\Models\Topic.php
<?php
namespace App\Models;
class Topic extends Model
{
protected $fillable = [
'title', 'body', 'category_id', 'excerpt', 'slug'
];
public function replies()
{
return $this->hasMany(Reply::class);
}
public function category()
{
return $this->belongsTo(Category::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
public function scopeWithOrder($query, $order)
{
//不同的排序,使用不同的數據讀取邏輯
switch($order) {
case 'recent':
$query->recent();
break;
default:
$query->recentReplied();
break;
}
}
public function scopeRecentReplied($query)
{
/*
當話題有新回覆時,我們將編寫邏輯來更新話題模型的 reply_count 屬性,
此時會自動觸發框架對數據模型 updated_at 時間戳的更新
*/
return $query->orderBy('updated_at', 'desc');
}
public function scopeRecent($query)
{
//依照建立時間排序
return $query->orderBy('created_at', 'desc');
}
public function link($params = [])
{
return route('topics.show', array_merge([$this->id, $this->slug], $params));
}
public function updateReplyCount()
{
$this->reply_count = $this->replies->count();
$this->save();
}
}
==================================================
*migration:
database\migrations\2020_11_02_165250_create_topics_table.php
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateTopicsTable extends Migration
{
public function up()
{
Schema::create('topics', function(Blueprint $table) {
$table->increments('id');
$table->string('title')->index();
$table->text('body');
$table->bigInteger('user_id')->unsigned()->index();
$table->integer('category_id')->unsigned()->index();
$table->integer('reply_count')->unsigned()->default(0);
$table->integer('view_count')->unsigned()->default(0);
$table->integer('last_reply_user_id')->unsigned()->default(0);
$table->integer('order')->unsigned()->default(0);
$table->text('excerpt')->nullable();
$table->string('slug')->nullable();
$table->timestamps();
});
}
public function down()
{
Schema::drop('topics');
}
}
==================================================
https://ithelp.ithome.com.tw/articles/10203820
沒有留言:
張貼留言