兜兜转转,又拿起了PHP写项目,大部分用的是laravel和lumen,那么我就来研究研究有没有什么好玩的东西
前期准备
我使用php artisan 来生成一个Commands文件来方便测试。
php artisan make:command LinxiDemo
执行完命令之后会生成一个LinxiDemo.php的文件
- 同时生成model和controller,指定model目录
php artisan make:model Models/Company -cr
依赖注入
/*** Date: 2024/8/16 18:24* @desc 使用依赖注入让容器来实例化对* @param Article $article*/public function handle(Article $article){$article=$article::where("auto_id",">",0)->orderByDesc("auto_id")->first();}
app方法返回单例对象
我们先看下面一段代码
public function handle(){$model=$this->getModel();$article=$model::where("auto_id",">",0)->orderByDesc("auto_id")->first();}// @return Articlepublic function getModel(){//app方法返回单例对象return app(Article::class);}
为什么说app是单例模式的,我们可以追一下里面的代码,一个妥妥的单例
function app($abstract = null, array $parameters = []){if (is_null($abstract)) {return Container::getInstance();}return Container::getInstance()->make($abstract, $parameters);}
Eloquent
model的相关属性
/*** @Class Article* @package App\Models* @version V1.0* @note 我们可以在这里定义类的一些属性,比如定义数据表字段的熟悉* @property $id ID* @property $catid 栏目ID* @property $title 标题* @property $title_style 标题样式* @property $thumb 缩略图* @property $keywords 关键词*/
class Article extends ModelAbstract
{
}
- 别名
在model里面设置Attribute
class Article extends ModelAbstract
{protected $table = "cms_blog";// 定义访问器 注意OtherTitle 对外的属性名是other_title 映射到的数据表字段是titlepublic function getOtherTitleAttribute(){return $this->attributes['title'];}// 定义修改器public function setOtherTitleAttribute($value){$this->attributes['title'] = $value;}
}
读取
public function handle(Article $article){$quey = $article::query();$res= $quey->where("status",1)->first();echo $res->other_title;}
复制行数据的副本快速插入
public function handle(Article $article){//复制行数据的副本$article=$article::where("auto_id",">",0)->orderByDesc("auto_id")->first();$newArticle=$article->replicate();$newArticle->auto_id=$article->auto_id+1;$newArticle->title="1234";//插入一条新的数据$newArticle->save();;}
我们看到replicate是Eloquent提供给我们的,那么Eloquent还提供了哪些有意思的方法呢
getOriginal
getOriginal看名字就知道了,获取初始数据值,比如我下面一个操作
$article=$article::where("auto_id",">",0)->orderByDesc("auto_id")->first();$article->title="1111";echo PHP_EOL.$article->getOriginal("title");//1234echo PHP_EOL.$article->title;//111echo PHP_EOL.$article->isDirty();//1 被修改过echo PHP_EOL.$article->isDirty("title");//1 title被修改过
基于ModelAbstract基类的字段标识
下面这些字段都会追加到sql的后面作为过滤条件,当然,也可以给它注释掉
const DELETED = 1;const NOT_DELETED = 0;const DELETED_AT = 'status';
注释之后
protected static function boot(){parent::boot();self::addGlobalScope(static::DELETED_AT, function(Builder $builder) {
// $builder->where(static::DELETED_AT, static::NOT_DELETED);});}
https://juejin.cn/post/7026979304755953700
分页和total
当我执行一个列表查询的时候,我们看你一下SQL的执行情况
public function handle(Article $article){//列表查询$article=$article::where("auto_id",">",0)->orderByDesc("auto_id")->paginate();var_dump($article->perPage());var_dump($article->total());die;}
[2024-08-17 10:18:05] TraceId: SQL:select count(*) as aggregate from `cms_blog` where `auto_id` > '0' 耗时:110.18ms
[2024-08-17 10:18:05] TraceId: SQL:select * from `cms_blog` where `auto_id` > '0' order by `auto_id` desc limit 15 offset 0 耗时:12.82ms//paginate接收更多参数如下
//Parameters:
//int|null $perPage array $columns string $pageName int|null $page$query=$article::where("auto_id",">","300")->paginate(20, ["*"], "page", 2);
我们看到,SQL先执行了count查询,如果count是有值的,再去查询列表,这个count的值我们可以通过total方法获取。
query
query是数据库查询构造器,构造器让我们更方便的进行复杂的查询,举个例子
if($status && $type) {$users = User::where('status', $status)->where('type', $type)->latest()->get();} else if ($status) {$users = User::where('status', $status)->latest()->get(); } else if ($type) {$users = User::where('status', $type)->latest()->get();} else {$users = User::latest()->get(); }
这种写法经过改造就可以改写为
$query = User::query();if ($status) {$query->where('status', $status);}if ($type) {$query->where('type', $type);} $users = $query->latest()->get();
在 Laravel 的 Eloquent 模型中,常用的查询方法主要包括以下几类:基本查询、条件查询、聚合函数、关系查询等。以下是一些常用的查询方法及其功能:
1. 基本查询方法
all()
: 获取模型的所有记录。$users = User::all();
find($id)
: 根据主键查找记录。$user = User::find(1);
first()
: 获取查询结果中的第一条记录。$user = User::where('email', 'example@example.com')->first();
get()
: 获取查询的所有结果集。$users = User::where('active', 1)->get();
pluck($column)
: 获取结果集中某一列的值。$emails = User::pluck('email');
count()
: 获取查询结果的总条数。$count = User::count();
2. 条件查询方法
where($column, $operator, $value)
: 添加一个基本的查询条件。$users = User::where('status', '=', 'active')->get();
orWhere($column, $operator, $value)
: 添加一个 OR 条件。$users = User::where('status', 'active')->orWhere('role', 'admin')->get();
whereIn($column, array $values)
: 查询列的值在指定数组中的记录。$users = User::whereIn('id', [1, 2, 3])->get();
whereNull($column)
: 查询列的值为空的记录。$users = User::whereNull('email_verified_at')->get();
whereNotNull($column)
: 查询列的值不为空的记录。$users = User::whereNotNull('email_verified_at')->get();
3. 排序与分页方法
orderBy($column, $direction)
: 按指定列排序。$users = User::orderBy('created_at', 'desc')->get();
skip($value)
: 跳过指定数量的记录。$users = User::skip(10)->take(5)->get(); // 跳过10条记录后获取5条记录
take($value)
: 获取指定数量的记录。$users = User::take(5)->get(); // 获取前5条记录
paginate($perPage)
: 分页获取记录。$users = User::paginate(15); // 每页15条记录
4. 聚合方法
count()
: 计算总数。$count = User::where('status', 'active')->count();
sum($column)
: 求某列的总和。$total = Order::sum('amount');
avg($column)
: 求某列的平均值。$average = Order::avg('amount');
min($column)
: 求某列的最小值。$min = Order::min('amount');
max($column)
: 求某列的最大值。$max = Order::max('amount');
5. 关系查询方法
with($relations)
: 预加载关联关系。$users = User::with('posts')->get();
has($relation)
: 查询具有指定关系的记录。$users = User::has('posts')->get();
whereHas($relation, $callback)
: 查询满足关联关系条件的记录。$users = User::whereHas('posts', function ($query) {$query->where('title', 'like', '%Laravel%'); })->get();
6. 更新与删除方法
update($attributes)
: 批量更新记录。User::where('active', 0)->update(['active' => 1]);
delete()
: 删除记录。User::where('last_login', '<', now()->subYear())->delete();
7. 查询作用域
- 预定义好的查询条件,可以在模型中定义。
public function scopeActive($query) {return $query->where('status', 'active'); }$activeUsers = User::active()->get();
这些是 Laravel 中一些最常用的 Eloquent 查询方法。通过这些方法,开发者可以高效地进行数据库查询,且代码可读性强。
8 一对多和一对一的关系
我这里以两张表为例子,一个是文章表,一个是作者表,一个文章只对应一个作者,一个作者对应多个文章。我们以此举例来看一下
hasOne
model文件
class Article extends ModelAbstract
{protected $table = "cms_blog";public function authorInfo(){// foreign key 对应表的字段, local key 当前表的字段return $this->hasOne('App\Models\Admin', 'id', 'author_id');}
}
调用文件
public function handle(Article $article){//列表查询$res=$article::where("auto_id","=","322")->first();$author=$res->authorInfo;dd($author);}//相关日志[2024-08-17 11:21:59] TraceId: SQL:select * from `cms_blog` where `auto_id` = '322' limit 1 耗时:8.31ms
[2024-08-17 11:21:59] TraceId: SQL:select * from `cms_admin` where `cms_admin`.`id` = '3' and `cms_admin`.`id` is not null limit 1 耗时:2.12ms
但是当我批量获取到文章后,想要获取作者,比如下面这段代码,会导致我在循环内不停的调用数据库,这明显是不可取的,那么此时我们可以使用with预加载来优化这种情况,比如
$res=$article::where("auto_id",">","322")->get();if ($res->isEmpty()){dd("没有数据");}foreach ($res as $item){echo $item->authorInfo->username;}
- 优化后
$res=$article::with("authorInfo")->where("auto_id",">","322")->get();[2024-08-17 11:44:26] TraceId: SQL:select * from `cms_blog` where `auto_id` > '322' 耗时:37.58ms
[2024-08-17 11:44:26] TraceId: SQL:select * from `cms_admin` where `cms_admin`.`id` in ('3', '4', '5') 耗时:8.83ms
hasMany
model
class Admin extends Model
{//protected $table = "cms_admin";public function articleList(){return $this->hasMany(Article::class, 'author_id', 'id');}}
- 调用
public function handle(){$user=Admin::where("id","=","1")->first();$articleList=$user->articleList;dd($articleList);}[2024-08-17 11:34:32] TraceId: SQL:select * from `cms_admin` where `id` = '1' limit 1 耗时:29.8ms
[2024-08-17 11:34:32] TraceId: SQL:select * from `cms_blog` where `cms_blog`.`author_id` = '1' and `cms_blog`.`author_id` is not null 耗时:21.58ms
belongto
即这篇文章的所有者
model
class Article extends ModelAbstract
{protected $table = "cms_blog";public function belongAuthorInfo(){// foreign key当前表的字段, ownerKey 隶属表(admin)的字段return $this->belongsTo('App\Models\Admin', 'author_id', 'id');}
}
调用
public function handle(Article $article){//列表查询$res = $article::where("auto_id", ">", "322")->first();echo $res->belongAuthorInfo->username;}
9.query的克隆
query确实给我们带来了方便,但是有时候query有很多分支,比如,前面的where都是通用的,后面根据Source来源要有不同的过滤,这个时候我们不能再重复写一遍query了吧
$quey = $article::query();$quey->where("status",1);$quey->where("status",2);//这个query啥也查不到 等价与where status = 1 and startus = 2
那么怎么办呢,我们可以使用query克隆
public function handle(Article $article){$quey = $article::query();$quey->where("id",">",0);//使用clone 不会影响到原来的query$statusList= (clone $quey)->where("status",1)->get();$statusListNew=(clone $quey)->where("status",2)->get();}
collect
集合是Laravel 中提供的最强大的功能之一,集合本质上是由功能强大的数组组成。
把类似数组的对象应用到方法中是很有用的,通过链式编程,用极短的代码,就可以达到预期的效果。
一般来说,集合是不可改变的,这意味着大部分 Collection 方法都会返回一个全新的 Collection 实例。
创建集合
前面我们说了,集合的本质是数组组成的,那么一个数组我们怎么转换为集合呢
$arr=[1,5,10];$collection=collect($arr);var_dump($collection);//object
那么怎么返回集合内的数组呢,一般有两种方法,一种是all,一种是toArray,
$arr=[1,5,10];$collection=collect($arr);$res=$collection->toArray();var_dump($res);$res=$collection->all();var_dump($res);
但是注意,model里面对这两种方法进行了二次封装,如果是null的话会导致报错。
Call to a member function all() on null
avg count min max求值
//对某列进行求值$res=collect([['foo' => 10], ['foo' => 10], ['foo' => 20], ['foo' => 40]])->avg('foo'); // 20var_dump($res);
chunk 分割集合
collapse合并多个集合
$collection = collect([[1, 2, 3], [4, 5, 6], [7, 8, 9]]);
// 注意这里返回了一个新的集合
$collapsed = $collection->collapse();
$collapsed->all();
// [1, 2, 3, 4, 5, 6, 7, 8, 9]
combine
将一个集合的值作为「键」,再将另一个数组或者集合的值作为「值」合并成一个集合。
$collection = collect(['name', 'age']);
$combined = $collection->combine(['boo', 25]);
$combined->all();
// ['name' => 'boo', 'age' => 25]
isEmpty() , isNotEmpty()
判断是否非空
迭代函数
- each() filter() map() 注意,map会返回运算后的结果。如果想直接修改原集合,可以使用transform
$res->transform(function ($value, $key) {if ($value['foo']>20){$value['name']="aaa";}return $value;});var_dump($res->all());
排序
sort() , sortBy() , sortKeys() , reverse() , *Desc()
转型
toArray() , toJson()
where
$res=collect([['foo' => 10], ['foo' => 10], ['foo' => 20], ['foo' => 40]]);$new=$res->where("foo",">",20);var_dump($new->all());
取值
get 获取指定的键,并返回对应的结果
$res=collect(["name"=>"jimy","age"=>20]);$name=$res->get("name");var_dump($name);
keyBy 这个可能用的比较多一点,比如,获取用户之后,以用户id作为key,用户信息作为value
collect相关操作
collect相关操作2
laravel和lumen的区别
- Laravel注重开发人员的开发效率和舒适性,提供了大量的工具和功能来简化常见任务,如数据库操作、表单验证、身份验证等。
- Lumen是基于Laravel开发的微框架,专注于提供高性能和精简的API服务。去除了一些在大型应用中可能不需要的功能,如模板引擎和Session管理,使其更轻量级。虽然Lumen提供了大部分Laravel的核心特性,但它对某些功能进行了简化或者限制,如不包含Session和Cookie支持,默认配置下也不包含Eloquent ORM。
redis的pipe操作
// 管道批量写入RedisRedis::pipeline(function ($pipe) use ($insertCache) {foreach ($insertCache as $courseUnitId => $value) {$key = self::getCourseUnitInfoKey($courseUnitId);$pipe->del($key);//先删if( empty($value) ){//空结果 重新赋值 缓存起来 从缓存取的时候再转换回去$pipe->hmset($key, [self::EMPTY_SIGN => 1]);$pipe->expire($key, self::KEY_COURSE_UNIT_INFO_EMPTY_EXPIRE);continue;}$pipe->hmset($key, $value);$pipe->expire($key, self::KEY_COURSE_UNIT_INFO_EXPIRE);}});
解读:
使用 Redis 的管道功能,允许在一次网络往返中批量发送多个命令,从而减少网络延迟。代表 Redis 管道对象,可以在管道中批量添加命令。