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;
}

}

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

电商商品模块,关于规格问题的研究

基础概念

商品规格 商品属性 SKU

没有规格

最简单的商品规格设计,就是没有规格直接展示SKU

只需要两张表 商品表 (products) 和 商品sku表(product_skus)

product_skus 包含 库存和价格

多规格

有赞的设计方式

实现逻辑

对规格值进行笛卡尔积计算,生成SKU

1.规格不变,规格值发生变化时

添加规格值,重新生成添加值对应的笛卡尔积,删除规格值,删除删除值对应的笛卡尔积

2.规格变动,重新生成笛卡尔积覆盖原有数据

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