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 Article
    public 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 映射到的数据表字段是title
    public 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");//1234
        echo PHP_EOL.$article->title;//111
        echo 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'); // 20
        var_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操作

        // 管道批量写入Redis
        Redis::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 管道对象,可以在管道中批量添加命令。

  • 7
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老A技术联盟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值