Laravel多态关联的应用案例

多对多 多态

需求如图用户关注不同的实体
用户表
专家表
主播表
作者表
关注中间表
//用户模型
class User extends Authenticatable
{
    use HasFactory, Notifiable, HasApiTokens, DateFormat, Filterable;

    protected $table = 'users';
    
    //关注的用户
    public function followUser()
    {
        return $this->morphedByMany($this, 'followable', 'followable', 'user_id', 'followable_id')
            ->withTimestamps();
    }
    //关注的专家
    public function followExpert()
    {
        return $this->morphedByMany('App\Models\Expert', 'followable', 'followable', 'user_id', 'followable_id')
            ->withTimestamps();
    }
    //关注的主播
    public function followAnchors()
    {
        return $this->morphedByMany('App\Models\Anchors', 'followable', 'followable', 'user_id', 'followable_id')
            ->withTimestamps();
    }
    //关注的作者
    public function followAuthors()
    {
        return $this->morphedByMany('App\Models\Authors', 'followable', 'followable', 'user_id', 'followable_id')
            ->withTimestamps();
    }
    //关注者,即主动关注用户的人
    public function followerUser()
    {
        return $this->morphToMany($this, 'followable', 'followable', 'followable_id', 'user_id')
            ->withTimestamps();
    }
}
//专家模型
class Expert extends BaseModel
{
    protected $table = 'expert';
    //关注者,即主动关注专家的人
    public function followerUser()
    {
        return $this->morphToMany('App\Models\User', 'followable', 'followable', 'followable_id', 'user_id')
            ->withTimestamps();
    }
}
//主播模型
class Anchors extends BaseModel
{
    protected $table = 'anchors';
    //关注者,即主动关注主播的人
    public function followerUser()
    {
        return $this->morphToMany('App\Models\User', 'followable', 'followable', 'followable_id', 'user_id')
            ->withTimestamps();
    }
}
//作者模型
class Authors extends BaseModel
{
    protected $table = 'authors';
    //关注者,即主动关注作者的人
    public function followerUser()
    {
        return $this->morphToMany('App\Models\User', 'followable', 'followable', 'followable_id', 'user_id')
            ->withTimestamps();
    }
}
//控制器代码
class FollowController extends Controller
{
  //关注/取消
  public function toggle(Request $request)
 {
    $request->validate([
         'followable_id'=>'bail|required|integer',
        'followable_type'=>'bail|required|string|in:user,expert,authors,anchors'
    ]);
    //利用可变方法动态创建模型对象
    $type_model = "\App\Models\\".ucfirst($request->input('followable_type'));
    $follow = $type_model::findOrFail($request->input('followable_id'));
    //调用关注人关联和toggle方法动态切换关注和取消关注
    $result = $follow->followerUser()->toggle($request->user()->id);

    if ($result['attached']) {
        $status = 1;
    } else {
        $status = 0;
    }

    return response()->json(compact('status'));
 }

//关注列表
public function index(Request $request)
 {
    $request->validate([
      'followable_type'=>'bail|required|string|in:user,expert,authors,anchors'
    ]);
    //根据类型可变方法动态加载我的关注关联,实现4个类型列表
    $followable_funname = 'follow'.ucfirst($request->input('followable_type'));
    $builder = $request->user()->$followable_funname();

    if ($request->input('followable_type') == 'user') {
        $builder->select('users.id', 'name', 'avatar');
    } elseif ($request->input('followable_type') == 'expert') {
        $builder->select('expert.id', 'name', 'nickname', 'photo', 'tags')
                ->where('is_show', 1);
    } elseif ($request->input('followable_type') == 'authors') {
        $builder->select('authors.id', 'authors.user_id', 'introduction')
                ->with([
                    'user'=>function ($query) {
                        $query->select('id', 'name', 'avatar');
                    }
                ])
                ->where('status', 1);
    } elseif ($request->input('followable_type') == 'anchors') {
        $builder->select('anchors.id', 'anchors.user_id', 'games_type')
                ->with([
                    'user'=>function ($query) {
                        $query->select('id', 'name', 'avatar');
                    }
                ])
                ->where('status', 1);
   }
   //按关注时间排序
   $followed = $builder->orderBy('followable.created_at', 'desc')
           ->forPage($request->input('page', 1), $request->input('per_page', 1))
           ->get();

   return $followed;
}

}

这种抽象的写法可以减少接口数量,要看具体需求是否合适

Linux安装PHP FAQ

离线安装

很多国企和大型企业的自建机房不允许访问公网,流量只能进开发固定端口,造成安装LNMP环境时缺少各种依赖和报错。以centos系统为例

1.上传和服务器版本一致的操作系统镜像,(例:CentOS-7-x86_64-Everything-2009.iso,一定要使用everything版本包含软件包) 到服务器

2.挂载光盘镜像

mkdir /mnt/dvd //创建挂载目录
mount -o loop /xxx/CentOS-7-x86_64-Everything-2009.iso /mnt/dvd  //挂载,xxx为镜像所在目录
df -h  //查看 /mnt/dvd 挂载点是否挂载成功

3.配置yum本地源

mkdir /etc/yum.repos.d/bk //创建备份目录
mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/bk //备份源文件

vim /etc/yum.repos.d/CentOS-Media.repo  //编辑本地源
//centos6/7内容如下,file路径为上一步的镜像挂载
[local-media]
name=CentOS-$releasever-Media
baseurl=file:///mnt/dvd/
gpgcheck=1
enabled=1
gpgkey=file:///mnt/dvd/RPM-GPG-KEY-CentOS-7

//CentOS 8本地源配置文件写法与CentOS6和7不同,配置文件内容如下:
[LocalRepo_BaseOS]
name=LocalRepository_BaseOS
baseurl=file:///mnt/dvd/BaseOS
enabled=1
gpgcheck=0

[LocalRepo_AppStream]
name=LocalRepository_AppStream
baseurl=file:///mnt/dvd/AppStream
enabled=1
gpgcheck=0

//保存然后执行
yum clean all && yum makecache

//测试一下是否可用
yum install git

4 执行离线安装

使用oneinstack

一台服务器(可以使用系统版本系统的虚拟机替代)联网使用oneinstack安装后,src目录里会有相应的包,打包oneinstack 放到需要离线安装的服务器(配置好内网yum源)就是离线了。

使用lnmp一键安装包,需要下载完整包

执行CheckMirror=n ./install.sh lnmp

5 其它参考

https://blog.51cto.com/u_1836630/2417675

Linux编译安装相关知识

linux查看某个库是否安装

https://blog.csdn.net/vantian/article/details/76636327

ldconfig -p | grep pcap

Nginx常用功能配置

缓存静态资源

location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|flv|mp4|ico)$ {
    expires 30d;
    access_log off;
}
location ~ .*\.(js|css)?$ {
    expires 7d;
    access_log off;
}

开启SSL

SSL http2

listen 443 http2;
ssl_certificate /usr/local/nginx/conf/ssl/xxx.pem;
ssl_certificate_key /usr/local/nginx/conf/ssl/xxx.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_timeout 10m;
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_buffer_size 1400;
add_header Strict-Transport-Security max-age=15768000;
ssl_stapling on;
ssl_stapling_verify on;

开启GZIP

gzip_module ngx_http_gzip_static_module

#Gzip                          Compression
gzip on;
gzip_buffers 16 8k;
gzip_comp_level 6;
gzip_http_version 1.1;
gzip_min_length 256;
gzip_proxied any;
gzip_vary on;
gzip_types
text/xml application/xml application/atom+xml application/rss+xml application/xhtml+xml image/svg+xml
text/javascript application/javascript application/x-javascript
text/x-json application/json application/x-web-app-manifest+json
text/css text/plain text/x-component
font/opentype application/x-font-ttf application/vnd.ms-fontobject
image/x-icon;
gzip_disable "MSIE [1-6]\.(?!.*SV1)";

重定向

http 跳转 https

if ($ssl_protocol = "") { return 301 https://$host$request_uri; }

非www 重定向到 www

if ($host != 'www.xxxx.com' ) {
   rewrite ^/(.*)$ https://www.xxxx.com/$1 permanent;
}

防盗链

ngx_http_referer_module ngx_http_secure_link_module

location ~ .*\.(wma|wmv|asf|mp3|mmf|zip|rar|jpg|gif|png|swf|flv|mp4)$ {
    valid_referers none blocked *.nginx.stu nginx.stu;
    if ($invalid_referer) {
        return 403;
    }
}

PHP知识框架

安装

编译安装php

安装php扩展

php运行模式

php优化配置指南

第三方脚本

oneinstack安装脚本

宝塔运维面板

lnmp一键安装包

phpbrew

语言参考

基础语法 变量 常量 数据类型 表达式 运算符

流程控制 自定义函数

面向对象相关 命名空间 枚举

错误和异常

纤程和生成器

注解

预定义变量 异常 接口

上下文(Context)选项和参数 支持协议和封装协议

安全和特点

session cookie

文件上传处理

连接处理 数据库持久连接

命令型模式

引用的解释 垃圾回收机制

内置函数和pecl扩展API

扩展函数参考文档

PHP调试

PHP debug 笔记

PHP开发生态

PHP开发生态 常用笔记

vscode 常用插件及配置

左下角齿轮图标 >> Extension 打开扩展商品搜索即可安装

主题图标

vscode-icons 图标

Atom One Dark Theme 主题

语言包

Chinese (Simplified) Language Pack for Visual Studio Code

修改侧边栏样式

CSS文件目录:/usr/share/code/resources/app/out/vs/workbench/workbench.desktop.main.css

查找 .part>.content 如图修改字体

配置文件

MySQL Syntax 语法高亮显示

NGINX Configuration Language Support 语法高亮和自动补全

Apache Conf 语法高亮

Linux Desktop File support 桌面配置语法高亮

EditorConfig for VS Code 编码风格统一配置 editorconfig文档

DotENV .env格式配置文件 高亮显示 node php的部分框架都可以用

远程插件

Remote Development 远程开发插件

Remote – Containers 链接远程docker容器

Remote – SSH ssh远程终端工具

Remote – SSH: Editing Configuration Filesms 便捷ssh配置文件

其它插件

TODO Highlight TODO 标注功能的,如你写到某一部分的代码时,其中部分的功能需要稍后再来实现,这是就可以在对应的代码处添加一个 TODO 类型的注释

search-online 在线翻译和搜索插件

GitLens — Git supercharged git可视化工具,显示代码作者和提交历史

Project Manager ctrl + shift + p 如图使用

PHP插件

PHP Intelephense 代码提示,语法检测,psr12格式化,点击自动跳转追赠方法,显示内置API的官方文档,点击直接跳转官方文档提升查手册效率

可以免费使用,有付费功能,购买后输入key

设置PHP版本

出现未定义 undefined 错误 需要到如下选项配置支持。laravel框架需要 安装laravel ide help扩展包 swoole 也需要安装swoole ide help

php-cs-fixer 代码格式化插件 ,也可以项目中使用通过composer安装

    "php-cs-fixer.executablePath": "php-cs-fixer",
    "php-cs-fixer.onsave": false,
    "php-cs-fixer.rules": "@PSR1,@PSR1,@Symfony",
    "php-cs-fixer.config": ".php_cs;.php_cs.dist",
    "php-cs-fixer.allowRisky": false,
    "php-cs-fixer.pathMode": "override",
    "php-cs-fixer.exclude": [],
    "php-cs-fixer.autoFixByBracket": true,
    "php-cs-fixer.autoFixBySemicolon": false,
    "php-cs-fixer.formatHtml": false,
    "php-cs-fixer.documentFormattingProvider": true,

多个格式化插件冲突时 通过如下配置,设置默认格式化插件

"[php]": {
        "editor.defaultFormatter": "junstyle.php-cs-fixer"
 },

PHP DocBlocker PHP注释插件

配置作者和邮箱,@author触发

"php-docblocker.author": {
    "name": "yangliuan",
    "email": "yangliuancn@foxmail.com"
 },

laravel框架插件

laravel goto view 点击跳转 视图

laravel-goto-controller 点击跳转到控制器

Laravel Snippets laravel语句提示

Laravel Blade Snippets Blade模板语法提示

laravel8.x版本如下方式写路由时可以不使用此插件

Javascript

Vetur

ESLint

    "eslint.validate": [
        "javascript",
        "javascriptreact",
        "vue"
    ],
    "eslint.options": {
        "plugins": [
            "html"
        ]
    },

搜索时包含指定目录

点击替换下的…按钮可以输入要包含和排出的文件

shell

shellcheck

详细配置见扩展详情页或github

ubuntu简单美化

首先更新系统

sudo apt update && sudo apt upgrade

软件中心安装显卡驱动

Software && updates => Additional Drivers 一般N

如果没有合适的去官网下载,出现卡顿等问题也可以装一下显卡驱动试试

AMD Linux驱动 官方地址

NVIDIA官方驱动 NVIDIA安装驱动英文教程

sudo apt install nvidia-utils-530

安装N卡显示设置

sudo apt install nvidia-settings

切换显卡

更新驱动后可能会丢失这个选项 解决参考

可以通过指令切换 nvidia|intel|on-demand|query

sudo prime-select nvidia # select nvidia gpu
sudo prime-select intel  # select intel gpu
sudo prime-select on-demand  # on-demand 按需

安装tweaks

sudo apt install gnome-tweak-tool
#ubuntu22.04
sudo apt install gnome-tweaks
sudo apt install chrome-gnome-shell #需要安装chrome浏览器
sudo apt install gnome-shell-extensions

开启关闭gnome-shell-extensions

安装chrome-gnome-shell成功后

ubuntu20.04+ 已更新版本

安装dash to dock 和 TopIcons Plus 和 Drop Down Terminal

版本未更新时替代品

Dash to Dock for COSMIC (替代 dash to dock ) ddterm (替代Drop Down Terminal ) TopIconsFix (替代 TopIcons Plus)

https://extensions.gnome.org/

打开上述网站,搜索并安装扩展

设置为打开即可,如上图

dash to dock 配置截图

启用Dash To Dock 后 禁用ubuntu dock,否则会导致indicator-sysmonitor插件报错

dock尺寸

图标尺寸

isloate workspace 隔离工作空间 isloate monitors 隔离显示器

ddterm

Panel Icon : none 隐藏顶部栏图标

TopiconsFix

Tray horizontal alignment (托盘图标水平对齐) right

Ubuntu AppIndicators

Tray horizontal alignment left (托盘水平左对齐)可以解决一些应用菜单无法推出的情况

FAQ

gnome出现问题,可以尝试重新安装

sudo apt-get install --reinstall ubuntu-desktop

gnome控制中心设置失效可以重新安装

sudo apt install gnome-control-center