欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 时评 > laravel学习之Eloquent和Collect

laravel学习之Eloquent和Collect

2024/10/25 23:24:28 来源:https://blog.csdn.net/qq_39962403/article/details/141266566  浏览:    关键词:laravel学习之Eloquent和Collect

兜兜转转,又拿起了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 管道对象,可以在管道中批量添加命令。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com