文章评论表设计参考
评论表
id | article_id | parent_id(string) |
---|---|---|
1 | 3 | 0 |
2 | 3 | 1 |
3 | 3 | 1_2 |
4 | 3 | 2 |
5 | 3 | 1_2_3 |
模型操作
删除 id = 1 的1 级文章及下级所有文章
Article::where('id', 1)->delete();
Article::where('parent_id', 'like', '1%')->delete();
这样和 id = 1 的所有相关文章就删除了
删除这些文章下的评论就用观察者就行了
id | article_id | parent_id(string) |
---|---|---|
1 | 3 | 0 |
2 | 3 | 1 |
3 | 3 | 1_2 |
4 | 3 | 2 |
5 | 3 | 1_2_3 |
删除 id = 1 的1 级文章及下级所有文章
Article::where('id', 1)->delete();
Article::where('parent_id', 'like', '1%')->delete();
这样和 id = 1 的所有相关文章就删除了
删除这些文章下的评论就用观察者就行了
习惯将CDN文件下载到本地,保存至静态目录中,注意保留版本号。
<!-- 引入 css -->
<link href="https://cdn.jsdelivr.net/npm/@wangeditor/editor@latest/dist/css/style.css" rel="stylesheet">
<!-- 引入 js -->
<script src="https://cdn.jsdelivr.net/npm/@wangeditor/editor@latest/dist/index.min.js"></script>
直接上 HTML
代码吧:
<div class="layui-row">
<div class="layui-col-md12">
<div class="layui-form-item">
<label class="layui-form-label">正文:</label>
<div class="layui-input-block">
<textarea name="content" id="content" style="display: none"></textarea>
<div id="toolbar-container"></div>
<div id="editor-container" style="height: 300px;border:1px solid #dddddd"></div>
</div>
</div>
</div>
</div>
注意从官方拷贝js
代码时,要注意javascript与typescript的修改。
直接上 JS
代码。
// 渲染富文本编辑器
const { createEditor, createToolbar } = window.wangEditor;
// 编辑器配置
const editorConfig = {MENU_CONF: {}};
// 图片上传
editorConfig.MENU_CONF['uploadImage'] = {
// 表单字段名称
fieldName: 'file',
// 单个文件的最大体积限制,默认为 2M
maxFileSize: 5 * 1024 * 1024, // 5M
// 最多可上传几个文件,默认为 100
maxNumberOfFiles: 5,
// 选择文件时的类型限制,默认为 ['image/*'] 。如不想限制,则设置为 []
allowedFileTypes: ['image/*'],
// 小于该值就插入 base64 格式(而不上传),默认为 0
base64LimitSize: 5 * 1024, // 5kb
// 自定义参数
meta: {
from: 'editor', //标志是从编辑器上传
},
// 上传图片的配置
server: '<?=route("upload.image")?>',
};
// 默认提示文字
editorConfig.placeholder = '请输入内容'
editorConfig.onChange = (editor) => {
// 当编辑器选区、内容变化时,即触发
//console.log('content', editor.children)
//console.log('html', editor.getHtml())
document.getElementById('content').value = editor.getHtml();
}
// 工具栏配置
const toolbarConfig = {}
// 创建编辑器
const editor = createEditor({
html: document.getElementById('content').value,
selector: '#editor-container',
config: editorConfig,
mode: 'simple' // 或 'simple' 参考下文
})
// 创建工具栏
const toolbar = createToolbar({
editor,
selector: '#toolbar-container',
config: toolbarConfig,
mode: 'simple' // 或 'simple' 参考下文
})
截图如下。
composer require aliyuncs/oss-sdk-php
use OSS\Core\OssException;
use OSS\OssClient;
use OSS\Core\OssUtil;
// 接收文件数据
$file = request()->file('img');
// 取出文件名截取后缀
$name = $file->getOriginalName();
$suffix = strchr($name,'.');
// 阿里云配置
$accessKeyId = "LTAI5t88SfZ5yhH4Sgu1u3gt";
$accessKeySecret = "vbLBZWvzazGZvJpPap20ZyKDoBbdq2";
// Endpoint以杭州为例,其它Region请按实际情况填写。
$endpoint = "oss-cn-shanghai.aliyuncs.com";
// 设置存储空间名称。
$bucket= "*";
// 设置文件名称。
//这里是由sha1加密生成文件名 之后连接上文件后缀
$object = sha1(date('YmdHis', time()) . uniqid()) . $suffix;
$url = 'http://test.caotengfei.xyz/'.$object;
// <yourLocalFile>由本地文件路径加文件名包括后缀组成,例如/users/local/myfile.txt。
$filePath = $file->getPathname();
$options = array(
OssClient::OSS_CHECK_MD5 => true,
OssClient::OSS_PART_SIZE => 1,
);
try{
$ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint);
//返回uploadId。uploadId是分片上传事件的唯一标识,您可以根据uploadId发起相关的操作,如取消分片上传、查询分片上传等。
$uploadId = $ossClient->initiateMultipartUpload($bucket, $object);
} catch(OssException $e) {
printf(__FUNCTION__ . ": initiateMultipartUpload FAILED\n");
printf($e->getMessage() . "\n");
return ;
}
print(__FUNCTION__ . ": initiateMultipartUpload OK" . "\n");
$partSize = 10 * 1024 * 1024;
$uploadFileSize = filesize($filePath);
$pieces = $ossClient->generateMultiuploadParts($uploadFileSize, $partSize);
$responseUploadPart = array();
$uploadPosition = 0;
$isCheckMd5 = true;
foreach ($pieces as $i => $piece) {
$fromPos = $uploadPosition + (integer)$piece[$ossClient::OSS_SEEK_TO];
$toPos = (integer)$piece[$ossClient::OSS_LENGTH] + $fromPos - 1;
$upOptions = array(
// 上传文件。
$ossClient::OSS_FILE_UPLOAD => $filePath,
// 设置分片号。
$ossClient::OSS_PART_NUM => ($i + 1),
// 指定分片上传起始位置。
$ossClient::OSS_SEEK_TO => $fromPos,
// 指定文件长度。
$ossClient::OSS_LENGTH => $toPos - $fromPos + 1,
// 是否开启MD5校验,true为开启。
$ossClient::OSS_CHECK_MD5 => $isCheckMd5,
);
// 开启MD5校验。
if ($isCheckMd5) {
$contentMd5 = OssUtil::getMd5SumForFile($filePath, $fromPos, $toPos);
$upOptions[$ossClient::OSS_CONTENT_MD5] = $contentMd5;
}
try {
// 上传分片。
$responseUploadPart[] = $ossClient->uploadPart($bucket, $object, $uploadId, $upOptions);
} catch(OssException $e) {
printf(__FUNCTION__ . ": initiateMultipartUpload, uploadPart - part#{$i} FAILED\n");
printf($e->getMessage() . "\n");
return;
}
printf(__FUNCTION__ . ": initiateMultipartUpload, uploadPart - part#{$i} OK\n");
}
// $uploadParts是由每个分片的ETag和分片号(PartNumber)组成的数组。
$uploadParts = array();
foreach ($responseUploadPart as $i => $eTag) {
$uploadParts[] = array(
'PartNumber' => ($i + 1),
'ETag' => $eTag,
);
}
try {
// 执行completeMultipartUpload操作时,需要提供所有有效的$uploadParts。OSS收到提交的$uploadParts后,会逐一验证每个分片的有效性。当所有的数据分片验证通过后,OSS将把这些分片组合成一个完整的文件。
$ossClient->completeMultipartUpload($bucket, $object, $uploadId, $uploadParts);
} catch(OssException $e) {
printf(__FUNCTION__ . ": completeMultipartUpload FAILED\n");
printf($e->getMessage() . "\n");
return;
}
return json(['code'=>200,'msg'=>'成功','url'=>$url]);
Deprecated: Method ReflectionParameter::getClass() is deprecated in /vendor/topthink/think-container/src/Container.php on line 450
Script @php think service:discover handling the post-autoload-dump event returned with error code 255
这是因为在PHP8.0
以后反射类ReflectionParameter::getClass()
已弃用,变更为getType()
。
只要找到文件vendor/topthink/think-container/src/Container.php
修改替换即可。
如下图:
详情见:https://github.com/top-think/framework/commit/df4a07d2f51307a6fabdf75dc5b4b7f8b0ad8af8
1、xls
application/vnd.ms-excel
2、xlsx
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
3、ppt
application/vnd.ms-powerpoint
4、pptx
application/vnd.openxmlformats-officedocument.presentationml.presentation
5、doc
application/msword
6、docx
application/vnd.openxmlformats-officedocument.wordprocessingml.document
7、zip
application/x-zip-compressed
8、rar
application/x-zip-compressed
9、wmv
video/x-ms-wmv
10、mp3
audio/mpeg
11、mp4
video/mp4
12、gif
image/gif
13、jpg
image/jpeg
14、png
image/png
15、bmp
image/bmp
16、psd
application/octet-stream
17、ico
image/x-icon
18、7z
application/octet-stream
19、exe
application/octet-stream
20、avi
video/avi
21、rmvb
application/vnd.rn-realmedia-vbr
22、3gp
application/octet-stream
23、flv
application/octet-stream
24、wav
audio/wav
25、krc
application/octet-stream
26、lrc
application/octet-stream
27、txt
text/plain
28、pdf
application/pdf
29、chm
application/octet-stream
30、mdb
application/msaccess
31、sql
application/octet-stream
32、con
application/octet-stream
33、log
text/plain
34、dat
application/octet-stream
35、ini
application/octet-stream
36、php
application/octet-stream
37、html 和 htmhtm
text/html
38、ttf
application/octet-stream
39、fon
application/octet-stream
40、js
application/x-javascript
41、xml
text/xml
42、dll
application/octet-stream
转自:https://learnku.com/articles/60802
products
商品表字段名称 | 描述 | 类型 | 加索引缘由 |
---|---|---|---|
id | 自增长ID | unsigned big int | 主键 |
title | SKU 名称 | varchar | 无 |
description | SKU 描述 | varchar | 无 |
price | SKU 价格 | decimal | 无 |
stock | 库存 | unsigne int | 无 |
product_id | 所属商品 id | unsigne big int | 外键 |
orders
订单表字段名称 | 描述 | 类型 | 加索引缘由 |
---|---|---|---|
id | 自增长ID | unsigned big int | 主键 |
no | 订单流水号 | varchar | 唯一 |
user_id | 下单的用户ID | unsigned big int | 外键 |
address | JSON格式的收货地址 | text | 无 |
total_amount | 订单总金额 | decimal | 无 |
remark | 订单备注 | text | 无 |
paid_at | 支付时间 | datetime, null | 无 |
payment_method | 支付方式 | varchar, null | 无 |
payment_no | 支付平台订单号 | varchar, null | 无 |
refund_status | 退款状态 | varchar | 无 |
refund_no | 退款单号 | varchar, null | 唯一 |
closed | 订单是否已关闭 | tinyint, default 0 | 无 |
reviewed | 订单是否已评价 | tinyint, default 0 | 无 |
ship_status | 物流状态 | varchar | 无 |
ship_data | 物流数据 | text, null | 无 |
extra | 其他额外的数据 | text, null | 无 |
order_sku
订单项目名字段名称 | 描述 | 类型 | 加索引缘由 |
---|---|---|---|
id | 自增长ID | unsigned big int | 主键 |
order_id | 所属订单ID | unsigned big int | 外键 |
product_id | 对应商品ID | unsigned big int | 外键 |
product_sku_id | 对应商品SKU ID | unsigned big int | 外键 |
amount | 数量 | unsigned int | 无 |
price | 单价 | decimal | 无 |
rating | 用户打分 | unsigned int, null | 无 |
review | 用户评价 | text | 无 |
reviewed_at | 评价时间 | timestamp, null | 无 |
附:面向切面编程(AOP是Aspect Oriented Program的首字母缩写) ,我们知道,面向对象的特点是继承、多态和封装。而封装就要求将功能分散到不同的对象中去,这在软件设计中往往称为职责分配。实际上也就是说,让不同的类设计不同的方法。这样代码就分散到一个个的类中去了。这样做的好处是降低了代码的复杂程度,使类可重用。
但是人们也发现,在分散代码的同时,也增加了代码的重复性。什么意思呢?比如说,我们在两个类中,可能都需要在每个方法中做日志。按面向对象的设计方法,我们就必须在两个类的方法中都加入日志的内容。也许他们是完全相同的,但就是因为面向对象的设计让类与类之间无法联系,而不能将这些重复的代码统一起来。
也许有人会说,那好办啊,我们可以将这段代码写在一个独立的类独立的方法里,然后再在这两个类中调用。但是,这样一来,这两个类跟我们上面提到的独立的类就有耦合了,它的改变会影响这两个类。那么,有没有什么办法,能让我们在需要的时候,随意地加入代码呢?这种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。
一般而言,我们管切入到指定类指定方法的代码片段称为切面,而切入到哪些类、哪些方法则叫切入点。有了AOP,我们就可以把几个类共有的代码,抽取到一个切片中,等到需要时再切入对象中去,从而改变其原有的行为。
这样看来,AOP其实只是OOP的补充而已。OOP从横向上区分出一个个的类来,而AOP则从纵向上向对象中加入特定的代码。有了AOP,OOP变得立体了。如果加上时间维度,AOP使OOP由原来的二维变为三维了,由平面变成立体了。从技术上来说,AOP基本上是通过代理机制实现的。
AOP在编程历史上可以说是里程碑式的,对OOP编程是一种十分有益的补充。
https://www.iteye.com/blog/hejiajunsh-1776569
http://open-doc.dingtalk.com/microapp/serverapi2/vzzrkv
中下载PHP
版本SDK
。解压后文件目录如图:dingtalk
中的文件,删除aliyun、QimenCloud
目录,保留top
目录Autoloader.php
和TopSdk.php
文件。composer.json
中:"autoload": {
"classmap": [
"database"
],
"files":[
"app/Packages/taobao/TopSdk.php"
],
"psr-4": {
"App\\": "app/"
}
}
composer dump-autoload
Controller
中就可以直接使用DingTalk SDK
了。测试结果如下(注意要加‘ \ ’):object(DingTalkClient)#276 (9) { ["gatewayUrl"]=> string(34) "http://eco.taobao.com/router/rest" ["format"]=> string(4) "json" ["connectTimeout"]=> NULL ["readTimeout"]=> NULL ["apiCallType"]=> string(4) "oapi" ["httpMethod"]=> string(4) "POST" ["checkRequest"]=> bool(true) ["apiVersion":protected]=> string(3) "2.0" ["sdkVersion":protected]=> string(25) "dingtalk-sdk-php-20161214" }
本文转载:https://blog.csdn.net/xiaoweite1/article/details/106175892
<IfModule mod_rewrite.c>
Options +FollowSymlinks -Multiviews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [L,E=PATH_INFO:$1]
</IfModule>