请问可有:Model模型使用规范,或最佳实践 ?

1. 运行环境

1). 当前使用的 Laravel 版本?

Lavavel 9

2). 当前使用的 php/php-fpm 版本?

PHP 版本: PHP8.1

3). 当前系统

Ubuntu 20.4

2. 问题描述?

如题所述,哪里有大佬关于Model的最佳使用实践博文吗?
或者一定基础的情况入门laravel的教程推荐
深感内网百度查询不靠谱。。。
读过社区一些很好的文章,比如:
Laravel 项目开发规范
Laravel Eloquent 提示和技巧
Laravel 的十八个最佳实践
我相信,有不少phper欠缺对设计模式、底层源码的理解深度
比如说我。。。
以下是我在使用Model时,一些纠结的地方,请各位大佬指点,感谢。
疑问详见评论

PS:入门艰辛,感谢愿意指点的大佬们,如果有些问题过于浅显,也请体谅。
后续有时间,我会整理一个初学者杂录,回馈社区的帮助。

《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 34
// 查询 A
public function getUserList(){
    return User::get();
}
//还是 B
public function getUserList(User $user){
    return $user->get();
}

哪一种更好

1年前 评论
Rache1 1年前
largezhou 1年前
____Laravel (作者) (楼主) 1年前

组装查询条件

//A方法,自行组装$where,当查询参数特别多的时候很方便,
可以直接从请求中取出参数,生成where条件,但是复杂一些的逻辑就难以处理
$where = [
    ['name','like','xxx'],['tel','like','xxx'],['short_name','like','xxx'],
];
$list = User::where($where)->get();
// 还是 B 
$list = User::when($name,function($query,$name){
    $query->where('name','like','xxx');
})->when($tel,function($query,$tel){
    $query->where('tel','like','xxx');
})->when($short_name,function($query,$short_name){
    $query->where('short_name','like','xxx');
})->get();
//当然,可以把B方法写到模型,scope
public function scopeName($query,$key){
    return $key ? $query->where('name','like',$key):$query;
}
...
...
//然后
$list = (new User)->name('xx')->tel('xx')->shortName('xxx')->get();
//B方法可读性更强,但是参数很多的时候怎么办?

如何更好?

1年前 评论
jatdung 1年前
Rache1 1年前
____Laravel (作者) (楼主) 1年前
随波逐流 1年前
随波逐流 1年前
____Laravel (作者) (楼主) 1年前
____Laravel (作者) (楼主) 1年前
//3 这样的写法有问题吗?
$user = User::where('xxx','aaa')->where('aaax','xxxx')...;
$avgAge = $user->avg('age');
$count = $user->count();
//有问题的话,有什么好的写法吗
1年前 评论
//4 在模型添加自定义方法,是添加static的还是正常的?A
public function getLowAndPoorCoder(){
    return $this->low()->poor()->get();
}
//还是 B
public static function getLowAndPoorCoder(){
    return self::low()->poor()->get();
}

A,B适用什么场景?

1年前 评论
Rache1 1年前
//5 如果不用国际化,那么模型中的字段字典如何处理
//例如有个状态$status 
$statusDict = ['A'=>'等待','B'=>'已处理''C'=>'已拒绝','D'=>'已同意'];
public function getStatusText(){
    return $statusDict[$this->attributes['status']]?? '';
}
//这个$statusDict会被查询界面,新增和修改界面使用,还需要用在查询结果中转化状态
//如何放置它比较好?最好是使用国际化的哪一套吗?
//还是在config里面放一个dict或者在数据库里建一个dict
1年前 评论
largezhou 1年前
____Laravel (作者) (楼主) 1年前
Rache1 1年前
____Laravel (作者) (楼主) 1年前
// 6 用过tp,喜欢在控制器中初始化时定义模型
class UserController extends Controller
{
    protected Request $request ;
    protected User $model ;
    public function __construct(Request $request)
    {
        $this->request = $request;
        $this->model = new User;
    }
}
//然后在crud中使用$this->model;
$list = $this->model->where('xx','xxx')->get();
$user = $this->model->find($id);
...
$user->save();

这样的写法有什么问题没?

1年前 评论
Rache1 1年前
// 7 tp有个where('name|code','like','xxx')的写法,lavavel的话
User::where('status',$status)->when($name,function($query,$name){
    $query->where('name','like','xxx')->whereOr('code','like','xxx');
});
//laravel 对这样的有什么便捷写法么,如果用数组的话,怎么组装?
$where = [
    ['status','=',$status],
    //$query->where('name','like','xxx')->whereOr('code','like','xxx');
    //这个怎么处理
];
1年前 评论

可以自己封装一个解析where数组的方法,
在AppServiceProvider的boot方法中添加下面代码

use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Query\Builder as QueryBuilder;

QueryBuilder::macro('queryBuilder', function (array $where) {
            $withoutParseWhere = [];
            foreach ($where as $key => $value) {
                if ($key === 'RAW_SQL' || $key === 'RAW_SQL:or') {
                    $operators = explode(':', $key);
                    if (count($operators) > 1) {
                        $boolean = $operators[1];
                    } else {
                        $boolean = 'and';
                    }
                    if (is_array($value)) {
                        list($sql, $binds) = $value;
                        $this->whereRaw($sql, $binds, $boolean);
                    } else {
                        $this->whereRaw($value, [], $boolean);
                    }
                } elseif (Str::contains($key, '|')) {
                    $arr = explode('|', $key);
                    list($column, $operators) = $arr;
                    $list = explode(':', $operators);
                    if (count($list) == 1) {
                        $operator = $list[0];
                        $boolean = 'and';
                    } else {
                        list($operator, $boolean) = $list;
                    }
                    switch ($operator) {
                        case 'in':
                            $this->whereIn($column, $value, $boolean);
                            break;
                        case 'notIn':
                            $this->whereNotIn($column, $value, $boolean);
                            break;
                        case 'between':
                            $this->whereBetween($column, $value, $boolean);
                            break;
                        case 'notBetween':
                            $this->whereNotBetween($column, $value, $boolean);
                            break;
                        case 'isNull':
                            $this->whereNull($column, $boolean);
                            break;
                        case 'isNotNull':
                            $this->whereNotNull($column, $boolean);
                            break;
                    }
                } elseif ($value instanceof Closure) {
                    $this->where($value);
                } else {
                    $withoutParseWhere[$key] = $value;
                }
            }
            if ($withoutParseWhere) {
                $this->where($withoutParseWhere);
            }
            return $this;
        });
        EloquentBuilder::macro('queryBuilder', function (array $where) {
            $this->getQuery()->queryBuilder($where);
            return $this;
        });


//用法示例
$where = [
    'id|in' => [1, 3],
    function($query) {
        $query->where('name', '张三')->orWhere('code', '李四');
    }
];
User::queryBuilder($where)->get();
1年前 评论
____Laravel (楼主) 1年前
____Laravel (楼主) 1年前

@huchao399 感谢,以下是我实现源码

Builder::macro('extWhere', function ($where) {
            foreach ($where as $item) {
                list($fields, $operator, $value) = $item;
                if (Str::contains($fields, '|')) {
                    $filedList = explode('|', $fields);
                    $this->where(function ($query) use ($filedList, $operator, $value) {
                        $query->where(array_shift($filedList), $operator, $value);
                        foreach ($filedList as $field) {
                            $query->orWhere($field, $operator, $value);
                        }
                    });
                }elseif (Str::contains($fields, '&')) {
                    $filedList = explode('|', $fields);
                    foreach ($filedList as $field) {
                            $this->where($field, $operator, $value);
                    }
                }else{
                        $this->where($fields, $operator, $value);
                }
            }
        });

        EloquentBuilder::macro('extWhere', function ($where) {
            $this->getQuery()->extWhere($where);
            return $this;
        });
        $where = [
            ['id|name', 'like', '%123%'] ,
            ['sex|love', '=', '456'] ,
            ['status','=','1'],
        ];
        $list = User::extWhere($where)->select(['id','name'])->get();
1年前 评论

基础查询方法
file

构建实体参数类进行查询

$hourFilter = app(AnalyseApiStatsHourFilter::class)
    ->setOrganizationId($project->organization_id)
    ->setProjectId($project->id);
$maxMinuteRequestData = $this->analyseApiStatsMinuteRepository->getMaxMinuteTotalCountData($minuteFilter);

参数类调用基础查询,然后写格子独立的条件

    public function getMaxMinuteTotalCountData(AnalyseApiStatsMinuteFilter $filter): AnalyseApiStatsMinute|null
    {
        return $this->baseQuery($filter)
            ->groupBy('date_minute')
            ->orderByRaw("sum(total_count) desc")
            ->select([
                'date_minute',
                DB::raw('any_value(organization_id) as organization_id'),
                DB::raw('any_value(project_id) as project_id'),
                DB::raw("sum(total_count) as total_count"),
                DB::raw("sum(total_millisecond) as total_millisecond"),
                DB::raw("max(max_millisecond) as max_millisecond"),
                DB::raw("min(min_millisecond) as min_millisecond"),
            ])
            ->first();
    }

参数实体类

<?php

namespace App\QueryFilter;

use App\Abstracts\QueryFilterAbstract;
use App\Traits\Filter\FilterOrganizationTrait;
use App\Traits\Filter\FilterProjectTrait;

class AnalyseApiStatsMinuteFilter extends QueryFilterAbstract
{
    use FilterOrganizationTrait, FilterProjectTrait;

    private ?bool $isEffective = null;

    /**
     * @return bool|null
     */
    public function getIsEffective(): ?bool
    {
        return $this->isEffective;
    }

    /**
     * @param bool|null $isEffective
     * @return AnalyseApiStatsMinuteFilter
     */
    public function setIsEffective(?bool $isEffective): AnalyseApiStatsMinuteFilter
    {
        $this->isEffective = $isEffective;
        return $this;
    }
}
1年前 评论
____Laravel (楼主) 1年前

不喜歡模型 :grin:

$bind = [];
$name = '1=1';
$code = '1=1';
if(!empty($post['name'])){
    $name = 'name=?';
    $bind[] = $post['name'];
}
if(!empty($post['code '])){
    $code = 'code =?';
    $bind[] = $post['code '];
}
$where = "{$name} and {$code}";
1年前 评论
____Laravel (楼主) 1年前

之前大佬推荐过一个包,很好用l3aro/pipeline-query-collection

Admin::filter([
            new RelativeFilter('name'),    // like查询
            new TrashFilter(),    // 软删除
            new ExactFilter('status'),    // =查询
            new DateFromFilter('last_login'),    // >=
            new DateToFilter('last_login', \Baro\PipelineQueryCollection\Enums\MotionEnum::TILL),    // <
            new Sort()    // 排序
        ])->paginate($request->page_size);

类似与 when where还有when order之类的用法

1年前 评论
____Laravel (楼主) 1年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!