(29/03/2564)
หน้า Desgin / Ui - พี่กร
Document ต่างๆ - ทุกคน
- https://www.postman.com : สำหรับเทสค่า API และทำ Document
- https://github.com : สำหรับการทำงานร่วมกัน
- https://stackoverflow.com : ครูที่ดี หาไรไม่เจอ มาหาที่นี่
- shorturl.asia/ZGyIE : วิธีการใช้งาน Github
- https://cookiewow.com : เว็บสำหรับทำ Cookie
- https://www.xml-sitemaps.com/ : Sitemap เอา link url เว็บไซต์ไปใส่ รอ Gen 10 นาที
เป็นการ Insert Update ปกติ แต่ว่าลดขั้นตอนลงมา จากเดิมที่ต้องสร้าง 2 Function เราก็ยุบเหลือ Function เดียว
ซึ่งจะสังเกตุเห็นได้ใน Code ว่าใน Function 'Insert' และ 'Update' จะเรียก Function 'store_system' โดยแต่ละตัวจะส่งค่า
ไปสองค่าเหมือนกัน คือ $request และ $id แต่ถ้าหากเป็นการ Insert จะส่งค่า null ของ id ไปแทน
// Function Insert และ Update
public function insert(Request $request)
{
return $this->store_system($request,$id=null);
}
public function update(Request $request, $id=null)
{
return $this->store_system($request,$id);
}
//Store System
public function store_system($request, $id=null)
{
try
{
if($id==null)
{
//กรณีที่เป็น การ Insert เข้ามาใหม่
$data = new mNews;
$data->created = date('Y-m-d H:i:s');
}
else
{
//กรณีที่เป็น การ Update
$data = mNews::find($id);
$data->updated = date('Y-m-d H:i:s');
}
$data->name_th = $request->name_th;
if($data->save())
{
// Return หน้าที่สำเร็จ
}else
{
// Return หน้าที่ไม่สำเร็จ
}
}
catch(\Exception $e)
{
//กรณีที่หน้ามีปัญหา Error
$error_log = $e->getMessage();
$error_line = $e->getLine();
$type_status = 'error';
$error_url = url()->current();
}
}
// Style ส่วนนี้ทำสำหรับรูปภาพที่ยังไม่ได้อัพ โหลดเป็นภาพ Preview
<style>
.img-preview {
width: 100%;
max-height: 145px;
overflow: hidden;
}
.img-preview>img {
height: 100%;
}
#tree {
width: auto;
height: 350px;
overflow-x: auto;
overflow-y: auto;
border-radius: .25rem;
}
#tree>ul {
padding-top: 10px;
}
#preview {
display: inline-block;
font-style: normal;
font-variant: normal;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
}
#preview:after {
font-family: 'Font Awesome 5 Free';
font-size: 9em !important;
content: "\f03e";
color: #999;
display: block;
margin: 30px;
}
.img-thumbnail {
text-align: center;
}
</style>
//== ส่วนนี้สำหรับ การแสดงผลช่อง Input
<form method="post" action="" enctype="multipart/form-data">
<div class="row">
<div class="form-group col-12 col-xs-12 col-md-12 col-xl-12">
<small class="help-block">*รองรับไฟล์ <strong class="text-danger">(jpg, jpeg, png)</strong> เท่านั้น</small>
<small class="text-danger">แนะนำขนาดรูปภาพ : 100 x 100 Pixel</small>
<div class="custom-file">
<input type="file" class="custom-file-input" name="image" id="image">
<label class="custom-file-label" for="image">Choose file</label>
</div>
</div>
</div>
</form>
//=== ส่วนนี้คือ Script ที่เอาไว้ทำงานให้เวลากดเลือกรูป รูปจะนำไปแสดงผลด้านบน เป็นการ Preview รูปภาพ
<script>
$("#image").on('change',function(){
var $this = $(this);
const input = $this[0];
const fileName = $this.val().split("\\").pop();
$this.siblings(".custom-file-label").addClass("selected").html(fileName);
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$('#preview').attr('src', e.target.result).fadeIn('slow');
}
reader.readAsDataURL(input.files[0]);
}
});
</script>
เป็นการอัพโหลดที่จะนำไปลง public path ซึ่งในตรงนี้เราจะต้องไปตั้งค่า ใน 'config/filesystem.php' ก่อน เพื่อให้รูปภาพที่อัพโหลดไปเข้าไปอยู่ใน folder 'public' 'public' => ['driver' => 'local','root' => public_path(),'visibility' => 'public',], เมื่อมีการอัพโหลดรูปภาพ ฐานข้อมูลในการเก็บรูปจะ เซฟเป็น Path ของรูปภาพนั้นๆ สามารถเอามาใช้ได้โดยการเรียกมาตรงๆ ไม่ต้องกำหนด Path
// เรียกใช้งานด้านบนของ Controller
use Illuminate\Support\Facades\Storage;
use Intervention\Image\ImageManagerStatic as Image;
// Image upload ส่วนนี้นำไปลงใน Function Insert , Update ของแต่ละคน
$filename = 'news_' . date('dmY-His');
$file = $request->image;
if ($file)
{
$lg = Image::make($file->getRealPath());
$height = Image::make($file)->height();
$width = Image::make($file)->width();
$ext = explode("/", $lg->mime())[1];
$lg->resize($width, $height)->stream(); // กรณีนี้จะดึงภาพขนาดจริงของรูปมาเลย
// $lg->resize(ขนาดไซส์รูป(กว้าง), ขนาดไซส์รูป(ยาว))->stream();
$newLG = 'upload/news/' . $filename . '.' . $ext;
$store = Storage::disk('public')->put($newLG, $lg);
if($store)
{
//== เมื่อ Upload สำเร็จค่อยนำ ไป Insert ลงฐานข้อมูล
$data->image = $newLG;
}
}
เป็น Function สำหรับแปลงตัวเลข ให้เป็นตัวอักษร เช่น "125" แปลงเป็น "หนึ่งร้อยยี่สิบห้า"
วิธีใช้คือ นำ Function ไปวางไว้ที่ Controller ที่ต้องการใช้งานหรือสร้างเป็น Helper เอาไว้ เพื่อสะดวกต่อการเรียกใช้
เวลาใช้ให้ทำการเรียก Function เช่น
$number = 200;
m2t($number); -> สองร้อย
function m2t($number)
{
$number = number_format($number, 2, '.', '');
$numberx = $number;
$txtnum1 = array('ศูนย์','หนึ่ง','สอง','สาม','สี่','ห้า','หก','เจ็ด','แปด','เก้า','สิบ');
$txtnum2 = array('','สิบ','ร้อย','พัน','หมื่น','แสน','ล้าน','สิบ','ร้อย','พัน','หมื่น','แสน','ล้าน');
$number = str_replace(",","",$number);
$number = str_replace(" ","",$number);
$number = str_replace("บาท","",$number);
$number = explode(".",$number);
if(sizeof($number)>2){
return 'ทศนิยมหลายตัวนะจ๊ะ';
exit;
}
$strlen = strlen($number[0]);
$convert = '';
for($i=0;$i<$strlen;$i++){
$n = substr($number[0], $i,1);
if($n!=0){
if($i==($strlen-1) AND $n==1){ $convert .= 'เอ็ด'; }
elseif($i==($strlen-2) AND $n==2){ $convert .= 'ยี่'; }
elseif($i==($strlen-2) AND $n==1){ $convert .= ''; }
else{ $convert .= $txtnum1[$n]; }
$convert .= $txtnum2[$strlen-$i-1];
}
}
$convert .= 'บาท';
if($number[1]=='0' OR $number[1]=='00' OR
$number[1]==''){
$convert .= 'ถ้วน';
}else{
$strlen = strlen($number[1]);
for($i=0;$i<$strlen;$i++){
$n = substr($number[1], $i,1);
if($n!=0){
if($i==($strlen-1) AND $n==1){$convert
.= 'เอ็ด';}
elseif($i==($strlen-2) AND
$n==2){$convert .= 'ยี่';}
elseif($i==($strlen-2) AND
$n==1){$convert .= '';}
else{ $convert .= $txtnum1[$n];}
$convert .= $txtnum2[$strlen-$i-1];
}
}
$convert .= 'สตางค์';
}
//แก้ต่ำกว่า 1 บาท ให้แสดงคำว่าศูนย์ แก้ ศูนย์บาท
if($numberx < 1)
{
if($numberx == 0)
{
$convert = "ศูนย์" . $convert;
} else {
$convert = "ลบ" . $convert;
}
}
//แก้เอ็ดสตางค์
$len = strlen($numberx);
$lendot1 = $len - 2;
$lendot2 = $len - 1;
if(($numberx[$lendot1] == 0) && ($numberx[$lendot2] == 1))
{
$convert = mb_substr($convert,0,-10);
$convert = $convert . "หนึ่งสตางค์";
}
//แก้เอ็ดบาท สำหรับค่า 1-1.99
if($numberx >= 1)
{
if($numberx < 2)
{
$convert = substr($convert,4);
$convert = "หนึ่ง" . $convert;
}
}
return $convert;
}
เรียกใช้งานผ่าน CDN ซึ่ง Ckedtior เป็นตัวฟรีจะมีทั้งหมด 5 ระดับในการใช้งาน โดยแต่ละระดับจะมีการเปิด Function ใช้งานที่ต่างกัน เช่น
basic - the Basic preset
standard - the Standard preset
standard-all - the Standard preset together with all other plugins created by CKSource*
full - the Full preset
full-all - the Full preset together with all other plugins created by CKSource*
อ้างอิงข้อมูลจาก https://cdn.ckeditor.com/
<script src="https://cdn.ckeditor.com/4.12.1/standard/ckeditor.js''> </script>
<textarea id="detail_kr" name="detail_kr" placeholder=""></textarea>
//=== ตัวนี้อยู่ตรง Footer สำหรับ Replace id นั้นๆให้เปลี่ยนเป็น Editor
<script>
CKEDITOR.config.allowedContent = true;
CKEDITOR.replace('detail_kr', {
language: 'th',
});
</script>
1.เข้า Direct admin
2.เลือกที่ Mysql Management
3.เลือก Database ที่ต้องการจะทำให้ Localhost เข้ามา Connect ได้
4.สังเกตุด้านล่างที่เป็น Input ให้ใส่ % เข้าไปและเลือก Add host จะทำให้ Localhost เข้ามา connect ได้
* % หมายถึงโฮสใดๆ
การใช้งาน Text ตัวนี้จะเป็นการบังคับให้กรอกได้เฉพาะ ที่เรากำหนดไว้ จะสังเกตุได้ว่า โค้ดด้านล่างจะให้ใช้ได้เฉพาะ
เลข '0 - 9 . -' เท่านั้น โดยการใช้ทำการเรียก input ออกมาและนำ onkeypress ไปใส่เช่น
<input OnKeyPress="return chkNumber(this)">
OnKeyPress="return chkNumber(this)" // เอาไปใส่ไว้ใน input
<script language="JavaScript">
function chkNumber(ele)
{
var vchar = String.fromCharCode(event.keyCode);
if ((vchar<'0' || vchar>'9') && (vchar != '.') && (vchar != '-')) return false;
ele.onKeyPress=vchar;
}
</script>
1.ติดต่อให้พี่กรเปิด Cronjob ก่อน ถึงจะจัดการ Cronjob ใน Directadmin ของ orangeworkshop ได้
2.ให้เข้าไปที่เมนู Cronjob
3.ตั้งค่าเวลา(ดูในเน็ต) ส่วนของช่อง Command ให้ใส่ตามลิงค์ด้านล่าง
(curl -L -k --request GET 'ลิงค์เว็บ') เช่น
curl -L -k --request GET 'www.google.com' เป็นต้น ลักษณะการทำงานคือ เหมือนกับว่าให้ Server เปิดเว็บหน้านั้นของเรา
Paginate กรณีทำ Searching และกด เปลี่ยน Page ตัว Search ไม่ส่งค่า Get ตามมา ให้ใช้
appends [ $rows->appends(request()->input())->links() ]
เป็นการทำงานร่วมกับ การใช้ try catch เมื่อเวลามีการทำงานที่ผิดพลาดของ
ระบบหรือเข้า Catch ระบบจะทำการส่งค่าไป Controller 'LogbackendController'
เพื่อนำไปเข้า function send_line และส่งค่าแจ้งเข้าไปที่ Line
//Function สำหรับการส่งค่าไปหาไลน์
public static function send_line($message, $token)
{
$ch = curl_init();
curl_setopt( $ch, CURLOPT_URL, "https://notify-api.line.me/api/notify");
curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt( $ch, CURLOPT_POST, 1);
curl_setopt( $ch, CURLOPT_POSTFIELDS, "message=$message");
curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, 1);
$headers = array( "Content-type: application/x-www-form-urlencoded", "Authorization: Bearer $token", );
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec( $ch );
curl_close( $ch );
return $result;
}
//ในส่วนของการทำงานโปรแกรม ที่นำ try catch ไปแทรก
try{
}
catch(\Exception $e)
{
$error_log = $e->getMessage();
$error_line = $e->getLine();
$type_status = 'error';
$error_url = url()->current();
$message = "
เกิดข้อผิดพลาดทางด้านโปรแกรม
Log ที่ได้รับแจ้ง : $error_log
Website Link : $error_url
บรรทัดที่มีปัญหา : $error_line
";
$token = 'สำหรับ Linenoti ที่ไปขอ token มา';
Log_backendController::send_line($message, $token);
}
ini_set('max_execution_time', '3000');
ini_set('memory_limit','3072M');
นำโค้ดด้านบนไปใส่ใน Controller หรือที่ต้องการปรับเพิ่ม Memory
"app/Helpers/" และทำการสร้าง Helper.php ไว้
"app/Helpers/"
namespace App\Helpers;
class Helper{
public static function SayHello()
{
return "SayHello";
}
}
'aliases' => [
/*Defaults...*/
'Helper' => App\Helpers\Helper::class,
],
use Helper; // สำหรับเรียกใช้ Helper ตามชื่อที่เราตั้งใใน config/app.php Helper::SayHello(); // เรียกใช้ Function ใน Helper ที่เราสร้าง
tb_gallery โดยมีการเก็บ Field คือid(int) PK
_id(int) -> เก็บ ID FK ของตารางที่เป็นตารางที่เราอัพโหลดรูป
type(varchar) -> เก็บประเภทของรูปภาพเช่น (product,blog,news)
image(varchar)
created(datetime)
updated(datetime)
เวลาเรียกใช้ 'gallerys' => GalleryModel::where(['type'=>'product', '_id'=>$id])->get(),//=== หน้าแสดงผล ===
<div class="row">
<div class="col-lg-12">
<div class="row">
<div class="col-lg-12">
<div class="border"><br>
<div class="header">
<div class="col-lg-12">
<strong style="font-size:18px">Gallery :</strong>
<a class="btn btn-primary btn-sm" href="javascript:" id="add_gallery">Add</a></div>
</div>
<div id="gallery" class="form-group col-lg-6 col-md-6 col-xs-12" style="display:none;">
<br>
<div class="clearfix"></div>
<small class="help-block">*รองรับไฟล์ <strong class="text-danger">(jpg, jpeg, png)</strong> เท่านั้น</small>
<small class="text-danger">ขนาดรูปภาพแนะนำ</small>
<div class="input-group">
<div class="custom-file">
<input type="file" class="custom-file-input" name="gallery[]" id="galleryUpload" multiple="" onchange="readGallery()" accept="image/jpg,image/jpeg,image/png">
<label class="custom-file-label" for="image">Choose file</label>
</div>
<span class="input-group-append">
<button class="btn btn-danger reset-upload" type="button">Reset</button>
</span>
</div>
</div>
<div class="text-right pr-2 action-gallery" style="display:none;">
<button type="button" class="btn btn-secondary btn-sm cancel" data-toggle="gallerImg" role="button" disabled>Cancel</button>
<button type="button" class="btn btn-secondary btn-sm deleteGallerys" role="button" disabled>Delete</button>
</div>
<div class="col-lg-12">
<div class="row" id="galleryPreview"> <!-- ส่วนนี้เมิ่อมีการกด Input file รูปภาพ จะทำการโชว์รูปภาพ -->
</div>
</div>
<br>
</div>
</div>
</div>
</div>
</div>
<script>
<!-- ส่วนนี้เป็นไฟล์ script -->
/* ================================================= */
/* ==================== Gallery ==================== */
/* ================================================= */
$('#add_gallery').click(function(){
const text = $(this).html();
if(text=='Add'){
$(this).html('Cancel');
$("#gallery").slideDown('fast');
}else{
$(this).html('Add');
$("#gallery").slideUp('fast');
}
});
$('.reset-upload').click(function(){
$(this).parent().find('input[type="file"]').val(null);
$(this).parent().find('input[type="text"]').val(null);
$('#galleryPreview').find('.preview-item').remove();
$(this).parent().parent().find(".custom-file-label").removeClass('selected').html('');
})
$('input[name="gallery[]"]').on('change',function(){
var $this = $(this);
const fileName = [];
const files = $this[0].files;
for(let i = 0; i<files.length; i++)
{
fileName.push(files[i].name);
}
$this.siblings(".custom-file-label").addClass("selected").html(fileName.toString());
});
function readGallery()
{
const target = $('#galleryPreview');
var total_file=document.getElementById("galleryUpload").files.length;
target.find('.new-pre').remove();
for(var i=0;i<total_file;i++)
{
target.append("<div class='col-lg-2 col-md-2 col-xs-6 p-2 preview-item'><div class='img-thumbnail'><div class='img-preview'><img class='img-fluid' style='width:127px; height:127px;' src='"+URL.createObjectURL(event.target.files[i])+"'/></div><div class='caption' style='margin-top:5px;'><i class='fas fa-upload'></i></div></div></div>");
}
}
$('input[name="gallerImg"]').click(function(){
selectGallery()
})
$('.cancel').on('click',function(){
const toggle = $(this).data('toggle');
$('input[name^="'+toggle+'"]').prop('checked',false);
selectGallery()
})
$('.deleteGallerys').click(function(){
const id = $('input[name="gallerImg"]:checked').map(function(){ return $(this).val() }).get(), row = $(this).data('row');
if(id.length>0){ deleteGallery(id,row); }
})
$('.deleteGallery').click(function(){
const id = [$(this).data('id')], row = $(this).data('row');
deleteGallery(id,row);
})
function selectGallery()
{
const checked = $('input[name="gallerImg"]:checked').map(function(){ return $(this).val() }).get();
const action = $('.action-gallery');
const btnC = $('.action-gallery').find('.cancel');
const btnD = $('.action-gallery').find('.deleteGallerys');
// console.log(btnC)
if(checked.length>0){
action.slideDown('fast');
btnC.removeAttr('disabled');
btnD.removeAttr('disabled');
if(!btnD.hasClass('btn-danger'))
{
btnD.toggleClass('btn-secondary btn-danger');
}
}else{
action.slideUp('fast');
btnC.attr('disabled','');
btnD.attr('disabled','');
if(btnD.hasClass('btn-danger'))
{
btnD.toggleClass('btn-secondary btn-danger');
}
}
}
function deleteGallery(id,row)
{
Swal.fire({
title:"ยืนยันลบ",text:"คุณแน่ใจใช่หรือไม่?",icon:"warning",showCancelButton:true,confirmButtonColor:"#DD6B55",showLoaderOnConfirm: true,
preConfirm: () => {
return fetch(fullUrl+'/gallery/destroy?id='+id)
.then(response => response.json())
.then(data => {
// if(data===true){location.reload()}
$.each(id,function(i,v){$('#gallery'+v).remove()})
})
.catch(error => { Swal.showValidationMessage(`Request failed: ${error}`)})
}
});
}
</script>
//=== หน้า Controller ===
if ($request->gallery)
{
$gallery = $request->gallery;
$gfilename = 'gallery-' . date('dmY-His');
for ($i = 0; $i < count($gallery); $i++) {
$lg = Image::make($gallery[$i]->getRealPath());
$ext = explode("/", $lg->mime())[1];
$size = $this->ImageSize('gallery');
$lg->resize('ขนาดรูปภาพกว้าง', 'ขนาดรูปภาพสูง')->stream();
$newLg = 'uploads/product/gallery/' . $gfilename . '-' . $i . '.' . $ext;
Storage::disk('public')->put($newLg, $lg);
GalleryModel::insert(['_id' => $data->id, 'type' => 'product', 'image' => $newLg, 'created' => date('Y-m-d H:i:s')]);
}
}
//=== หน้าแสดงผล ===
<div class="row">
<div class="col-lg-12">
<div class="row">
<div class="col-lg-12">
<div class="border"><br>
<div class="header">
<div class="col-lg-12">
<strong style="font-size:18px">Gallery :</strong>
<a class="btn btn-primary btn-sm" href="javascript:" id="add_gallery">Add</a></div>
</div>
<div id="gallery" class="form-group col-lg-6 col-md-6 col-xs-12" style="display:none;">
<br>
<div class="clearfix"></div>
<small class="help-block">*รองรับไฟล์ <strong class="text-danger">(jpg, jpeg, png)</strong> เท่านั้น</small>
<small class="text-danger">ขนาดรูปภาพที่แนะนำ</small>
<div class="input-group">
<div class="custom-file">
<input type="file" class="custom-file-input" name="gallery[]" id="galleryUpload" multiple="" onchange="readGallery()" accept="image/jpg,image/jpeg,image/png">
<label class="custom-file-label" for="image">Choose file</label>
</div>
<span class="input-group-append">
<button class="btn btn-danger reset-upload" type="button">Reset</button>
</span>
</div>
</div>
<div class="text-right pr-2 action-gallery" style="display:none;">
<button type="button" class="btn btn-secondary btn-sm cancel" data-toggle="gallerImg" role="button" disabled>Cancel</button>
<button type="button" class="btn btn-secondary btn-sm deleteGallerys" role="button" disabled>Delete</button>
</div>
<div class="col-lg-12">
<div class="row" id="galleryPreview">
@if($gallerys)
@foreach($gallerys as $i => $v)
<div class='col-lg-2 col-md-3 col-xs-6 p-2' id="gallery{{$v->id}}">
<div class='img-thumbnail p-2'>
<a href="javascript:" class="float-right btn-link" style="margin-bottom:5px;">
<i class="fas fa-times fa-lg deleteGallery" data-id="{{$v->id}}"></i>
</a>
<div class="float-left custom-control custom-checkbox">
<input type="checkbox" name="gallerImg" class="custom-control-input" id="gall{{$v->id}}" value="{{$v->id}}">
<label class="custom-control-label" for="gall{{$v->id}}"></label>
</div>
<div class="img-preview">
<a href="{{url("$v->image")}}" target="_blank"><img class="img-fluid" src="{{url("$v->image")}}" style="width:127px; height:127px;"></a>
</div>
</div>
</div>
@endforeach
@endif
</div>
</div>
<br>
</div>
</div>
</div>
</div>
</div>
Controller สำหรับลบรูปภาพ Gallery
public function gallery_destroy(Request $request)
{
$datas = GalleryModel::find(explode(',', $request->id));
if (@$datas) {
foreach ($datas as $data)
{
if($data->image != null)
{
Storage::disk('public')->delete($data->image);
}
//destroy
$query = GalleryModel::destroy($data->id);
}
}
if (@$query) {
return response()->json(true);
} else {
return response()->json(false);
}
}