当前位置: 首页 > news >正文

Laravel基础

Laravel 基础

01.Laravel入门和安装

Composer安装Laravel步骤

要使用 Composer 安装 Laravel,请按照以下步骤操作:

  1. 确保已经安装了 Composer。如果还没有安装,请访问 https://getcomposer.org/download/ 下载并安装。

  2. 打开命令行或终端。

  3. 使用 cd 命令导航到你的项目目录,例如:

    cd /path/to/your/project
    
  4. 在项目目录中,运行以下命令创建一个新的Laravel项目:

    composer create-project --prefer-dist laravel/laravel your_project_name
    

    其中,your_project_name 是你的项目名称。这将下载 Laravel 的最新版本并创建一个新的项目。

  5. 安装完成之后进入项目

    cd your_project_name
    
  6. .env.example 文件复制并重命名为 .env

    cp .env.example .env
    
  7. .env 文件中配置数据库连接信息。例如:

    DB_CONNECTION=mysql
    DB_HOST=127.0.0.1
    DB_PORT=3306
    DB_DATABASE=your_database_name
    DB_USERNAME=your_database_username
    DB_PASSWORD=your_database_password
    
  8. 生成应用密钥:

    php artisan key:generate
    
  9. 运行数据库迁移和数据填充(如果有):

    php artisan migrate
    php artisan db:seed
    
  10. 最后,启动开发服务器:

    php artisan serve
    

这将在本地启动一个 HTTP 服务器,通常在 http://localhost:8000 上运行。现在你可以开始构建你的 Laravel 应用了。

02.路由的定义和控制器

一.路由的定义
  1. 什么是路由?路由就是提供接受 HTTP 请求的路径,并和程序交互的功能;

  2. 简单点理解,就是为了提供访问程序的 URL 地址,所做的一些设置工作;

  3. phpstorm 支持 cmd 操作,左下角 Terminal 按钮展开,调整字体即可;

  4. 输入 php artisan serve 命令后,即支持 localhost:8000 内置服务器;

  5. 路由的定义文件在根目录 routes/web.php 中,可以看到welcome 页面;

  6. 我们创建一个路由,让它返回一段信息,并设置响应的 url 地址;

    Route::get('index', function () {return "<h1>Hello World</h1>";
    });
    
  7. 在路由定义上,我们采用了::get()这个方法,它接受的就是GET 提交;

  8. ::post()、::put()、::delete()是表单和 Ajax 的提交接受方式;

  9. ::any()表示不管你是哪种提交方式,我智能的全部接收响应;

  10. ::match()表示接收你指定的提交方式,用数组作为参数传递;

    // 使用 match 必须有三个参数, any 是两个参数
    Route::match(['get', 'post'], 'match', function () {return "Matched";
    });
    
  11. 在路由的规则和闭包区域,我们可以设置和传递路由参数;

    Route::get('index/{id}', function ($id) {return "<h1>Hello World $id</h1>";
    });
    // http://localhost:8000/index/5
    
  12. 上面例子中{id}表示在 url 的动态参数,比如数字 5;

  13. 那么闭包的$id,可以接受 url 传递过来的 5,最终输出 5;

二.创建控制器
  1. MVC 模式中 C 代表控制器,用于接收 HTTP 请求,从而进行逻辑处理;

  2. 有两种方式可以创建控制器,IDE 直接创建,或使用命令生成一个;

    php artisan make:controller TaskController

  3. 控制器目录在 app\Http\Controllers 下,使用 IED 会自动生成命名空间;

    <?php
    namespace App\Http\Controllers;class TaskConterollers extends Controller
    {public function index(){return "task index";}public function read($id){return "id is $id";}
    }
    
  4. 通过设置路由来访问创建好的控制器,参数二:控制器@方法名;

    use App\Http\Controllers\TaskConterollers;Route::get("/task/read/{id}", [TaskConterollers::class, 'read'])->where(['id' => '[0-9]+', 'name' => '[a-z]+']);
    

03.路由参数.重定向.视图

一.路由参数
  1. 上一节课,我们已经学习了部分路由参数的功能,比如动态传递{id}

  2. 那么,有时这个参数需要进行约束,我们可以使用正则来限定必须是数字;

    //单个参数
    Route::get("/task/read/{id}", [TaskConterollers::class, 'read'])->where('id', '[0-9]+');// 多个参数
    Route::get("/task/read/{id}", [TaskConterollers::class, 'read'])->where(['id' => '[0-9]+', 'name' => '[a-z]+']);
    
  3. 如果想让约束 id 只能是 0-9 之间作用域全局范围,可以在模型绑定器里设置;

  4. 模型绑定器路径为:app\Providers\RouteServiceProvider 的boot()方法;

    public function boot()
    {$this->pattern('id', '[0-9]+'); // 全局都有效
    }
    
  5. 如果 id 已经被全局约束,在某个局部你想让它脱离约束,可以如下操作:

    // 全局范围的约束解除
    Route::get("/task/read/{id}", [TaskConterollers::class, 'read'])->where('id', '.*');
    
二.路由重定向
  1. 可以设置访问一个路由的 URI,跳转到另一个路由的 URI,具体如下:

    Route::redirect('index', 'task');
    Route::redirect('index', 'task', 301);  // 状态码
    
  2. 还有一个方法,可以直接让路由跳转返回 301 状态码而不用设置:

    Route::permanentRedirect('index', 'task');
    
三.视图路由
  1. 在使用视图路由之前,我们先要创建一个视图(MVC)中的 V 部分;

  2. 使用视图路由,有三个参数:1.URI(必);2.名称(必);3.参数(选);

    //参数 1:URI,localhost:8000/task
    //参数 2:view,resources/views/task.blade.php
    //参数 3:传参,{{$id}}
    Route::view('task', 'task', ['id'=>10]);
    
  3. 对于视图页面的创建,在 resources/views 下创建 task.blade.php;

    {{--静态页面--}}
    task{{$id}}
    
  4. 当然,也可以使用助手函数 view()方法来实现这个功能;

    //这里 view()的参数 1 是视图名称
    //参数 2 传参,可选;
    Route::get('task', function () {return view('task', ['id'=>10]);
    });
    
  5. 也可以将路由直接指向控制器的方法,通过方法实现 view()引入视图;

    public function index()
    {return view('task', ['id'=>10]);
    }
    

04.路由命名和分组

一.路由命名
  1. 给一个制定好的路由进行命名,可以生成 URL 地址或进行重定向;

    Route::get('task', 'TaskController@index')->name('task.index');
    
  2. 在控制器区域,使用助手函数 route()来获取路由生成的 URL 地址;

    //生成 url 地址,http://localhost:8000/task
    route('task.index'); PSURLURI 的子集,更多区别请百度;
    
  3. route()助手的第二参数为参数,第三参数为是否包含域名URL;

    // http://localhost:8000/task?id=10
    route('task.index', ['id'=>10]);
    // /task?id=10
    $url = route('task.index', ['id'=>10], false);
    // PS:如果需要更改成/task/10 模式,路由需要相应更改 task/{id}
    
  4. 使用 redirect()助手结合 route()生成一个重定向跳转,注意不要自我死跳;

    //生成重定向
    return redirect()->route('task.index', ['id'=>10]);
    
二.路由分组
  1. 路由分组功能是为了让大量路由共享路由属性,包括中间件、命名空间等;

    //一个空的分组路由
    Route::group([], function () {Route::get('index/{id}', function ($id) {return 'index'.$id;});Route::get('task/{id}', function ($id) {return 'task'.$id;});
    });
    
  2. 可以将中间件作用域路由分组中,有两种写法,至于中间件?后续章节讲解;

    //引入中间件,方法一
    Route::group(['middleware'=>'中间名'], function () {});
    //引入中间件,方法二
    Route::middleware(['中间件'])->group(function () {});
    
  3. 可以设置路由路径前缀,通过 prefix 来设置,也有两种方法,具体如下:

    //引入路由前缀,方法一
    Route::group(['prefix'=>'api'],function () {});
    //引入路由前缀,方法二
    Route::prefix('api')->group(function () {});
    
  4. 可以设置子域名,从而限定路由可执行的域名,有两种方法,具体如下:

    //引入子域名,方法一
    Route::group(['domain'=>'127.0.0.1'], function () {});
    //引入子域名,方法二
    Route::domain('127.0.0.1')->group(function () {});
    
  5. 可以设置命名空间,让命名空间分配给控制器,让其得以访问,具体如下:

    //命名空间,方法一
    Route::group(['namespace'=>'Admin'],function () {});
    //命名空间,方法二
    Route::namespace('Admin')->group(function () {});
    PS:在 Controller 目录下创建 Admin 目录,再其目录下创建的控制器命名空间如下:namespace App\Http\Controllers\Admin;
    
  6. 可以设置名称前缀,方式两种,也可以嵌套,具体如下:

    //名称前缀,方式一
    Route::group(['as'=>'task.'], function () {Route::get('task', 'TaskController@index')->name('index');Route::get('task/url', 'TaskController@url');
    });
    //名称前缀,方式二
    Route::name('task.')->group( function () {});
    //生成 URL
    $url = route('task.index');
    return $url;
    //嵌套方式命名前缀
    Route::name('task.')->group(function () {Route::name('abc.')->group(function () {Route::get('task', 'TaskController@index')->name('index');});Route::get('task/url', 'TaskController@url');
    });
    //生成 URL
    $url = route('task.abc.index');
    return $url;
    

05.回退.当前路由.单行为

一.单行为控制器
  1. 之前的课程,我们简单的创建和定义了控制器,并继承了控制器基类;

  2. 为何要继承基类?因为继承基类后,可以使用基类的方法,比如中间件等;

  3. 继承基类后除了支持中间件快捷使用,还支持验证、列队等快捷方法;

    public function __construct()
    {$this->middleware('中间件');
    }
    
  4. 如果你想要定义一个只执行一个方法的控制器,可以使用单行为控制器;

  5. 单行为控制器使用__invoke()方法,可以使用命令行创建;

    命令:php artisan make:controller OneController --invokable

    //手工创建
    class OneController extends Controller
    {public function __invoke(){return '单行为控制器';}
    }
    
  6. 单行为控制器,路由定义就不需要指定特定的方法,指定控制器即可

  7. 单行为控制器只是语义上的单行为,并没有限制创建更多方法访问;

    Route::get('one', 'OneController');
    
二.路由回退
  1. 如果我们跳转到了一个不存在路由时,会产生 404 错误,体验不佳;

  2. 可以使用回退路由,让不存在的路由自动跳转到你指定的页面去;

  3. 注意:由于执行顺序问题,必须把回退路由放在所有路由的最底部;

    Route::fallback(function () {return redirect('/');
    });
    
  4. 当然,你也可以制作一个自己的 404 页面,用回退路由加载这个页面;

    Route::fallback(function () {return view('404');
    });
    
三.当前路由
  1. 我们可以通过使用::current()系列方法,来获取当前路由的访问信息;

    Route::get('index', function () {//当前路由信息dump(Route::current());//返回当前路由的名称return Route::currentRouteName();//返回当前路由指向的方法return Route::currentRouteAction();
    })->name('localhost.index');
    

06.响应设置和重定向

一.响应设置
  1. 路由和控制器处理完业务都会返回一个发送到浏览器的响应:return;

  2. 比如字符串会直接输出,而数组则会输出 json 格式,本身是Response 对象;

    return [1, 2, 3]; //输出 json 格式
    return response([1, 2, 3]); //同上
    return response()->json([1, 2, 3]); //同上
    
  3. 如果使用 response()输出的话,可以设置状态码和响应头信息;

    return response('index', 201); //可以设置 HTTP 请求状态码
    
  4. 也可以给 HTTP 添加或修改标头,比如将 html 解析模式改成文本plain 模式;

    return response('<b>index</b>')->header('Content-Type', 'text/plain'); //文本解析模式
    
  5. 结合上面的响应操作,再结合 view()视图功能,显示纯 HTML 代码页面;

    return response()->view('task', ['id'=>10], 201)->header('Content-Type', 'text/plain');
    
二.路由重定向
  1. 重定向使用助手函数 redirect()的 to()方法,注意需要return 才能跳转

    return redirect()->to('/'); //跳到首页
    return redirect()->to('task'); //跳转到 task
    return redirect()->to('task/url'); //跳转到 task/url
    
  2. 也可以直接使用快捷方式直接进行跳转; 常用

return redirect('/'); //跳到首页
return redirect('task'); //跳转到 task
return redirect('task/url'); //跳转到 task/url
  1. redirect()助手有一个对应的 facade 模式对象;

    return Redirect::to('/'); //facade 模式,但需要 use 引入
    
  2. 使用 redirect()的 route()方法,可以跳转到指定的命名路由URI;

    return redirect()->route('task.index'); //注意和 route()方法区别
    
  3. 使用 redirect()back()方法,可以重定向到上一个页面中;常用

    return redirect()->back();
    return back(); //快捷方式
    
  4. 使用 redirect()的 action()方法,可以直接重定向到控制器方法;

    return redirect()->action('TaskController@index'); //需注册路由
    return redirect()->action('TaskController@index', ['id'=>10]);
    
  5. 使用 redirect()的 away()方法,跳转到外部链接;

    return redirect()->away('http://www.baidu.com'); //不带任何编码
    

07.资源控制器

一.资源控制器
  1. 声明:资源控制器是某个特定场景下的产物,完全理解需要PHP项目基础;

  2. 比如开发过博客系统,留言帖子系统之类,具有类似思维,否则你懂的…;

  3. 只是学习了PHP基础,就立刻学习框架的同学,可以过一遍即可(不影响后续)…;

  4. 有一种控制器专门处理CURD(增删改查),方法很多且方法名基本固定;

  5. 对于这种控制器,我们可以将它设置为资源型控制器,不要大量设置路由;

  6. 这里推荐直接使用命令行生成资源路由,比如:BlogController

    php artisan make:controller BlogController --resource
    
  7. 生成了的资源控制器会产生 7 个方法,配置好路由后会自动生成相关内容

    Route::resource('blogs', BlogController::class); //单个资源路由//批量定义资源路由
    // 多个路由
    Route::resources(["blogs" => BlogController::class,"tasks" => TaskController::class
    ]); 
    
    HTTP类型路由URI控制器方法路由命名描述
    GETblogsindex()blogs.index获得数据列表
    GETblogs/createcreate()blogs.create创建页面(表单页)
    POSTblogsstore()blogs.store创建页的接受处理
    GETblogs/{blog}show()blogs.show获得一条数据
    GETblogs/{blog}/editedit()blogs.edit编辑(表单页)
    PUT/PATCHblogs/{blog}update()blogs.update从编辑页中接受处理
    DELETEblogs/{blog}destroy()blogs.destroy删除一条数据
  8. 如果我们注册了资源路由,那么如上图的资源路由 URI 和名称均自动创建生效;

    http://localhost:8000/blogs/10/edit
    //可以访问到edit方法return route('blogs.store');
    //可以通过助手route()了解是否注册
    
  9. 还有一条命令可以直接查看目前可用的路由以及命名; 常用

    php artisan route:list

  10. 我们也可以限制资源路由只开放部分方法或排除部分方法,可以用命令查看;

    // 只有 index 和 show 可以访问
    Route::resource('blogs', BlogController::class)->only(['index', 'show']); // index 和 show 不可访问,剩下的都可以 
    Route::resource('blogs', BlogController::class)->except(['index', 'show']); 
    
  11. 资源控制器还有一种不需要HTML页面方法的API路由,只提供数据接口

    //API资源,并不需要HTML页面(create,edit),会排除
    Route::apiResource('blogs', 'BlogController');//批量方式
    Route::apiResources(['blogs' => 'BlogController'
    ]);
    
  12. 当然,也支持一开始就生成一个不包含HTML页面方法的资源控制器;

  13. 要注意的是,对应的资源路由,直接使用api资源路由即可;创建时就说是API

    php artisan make:controller CommentController --api
    
    Route::apiResource('comments', CommentController::class);
    

08.资源嵌套.浅嵌套.自定义

  1. 声明:资源控制器是某个特定场景下的产物,完全理解需要PHP项目基础;

  2. 比如开发过博客系统、留言帖子系统之类,具有类似思维,否则你懂的…;

  3. 只是学习了PHP基础就立刻学习框架的同学,可以过一遍即可(不影响后续);

  4. 在一篇博文(Blog)下有多条评论(Comment),编辑某条博文下的一条评论;

  5. 以上需求,可以通过嵌套资源路由来实现这个功能:

    php artisan make:controller CommentController --resource
    
    //嵌套资源路由
    Route::resource('blogs.comments', CommentController::class);
    
    HTTP类型路由URI控制器方法路由命名
    GETblogs/{blog}/commentsindex()blogs.comments.index
    GETblogs/{blog}/comments/createcreate()blogs.comments.create
    POSTblogs/{blog}/commentsstore()blogs.comments.store
    GETblogs/{blog}/comments/{comment}show()blogs.comments.show
    GETblogs/{blog}/comments/{comment}/editedit()blogs.comments.edit
    PUT/PATCHblogs/{blog}/comments/{comment}update()blogs.comments.update
    DELETEblogs/{blog}/comments/{comment}destroy()blogs.comments.destroy
  6. 以上需求,可以通过嵌套资源路由来实现这个功能,编辑方法以及传参如下:

    public function edit($blog_id, $comment_id) {return '编辑博文下的评论,博文id: ' . $blog_id . ',评论id: ' . $comment_id;
    }
    
  7. 而实际上,每个 id 都是独立唯一的,并不需要父 id 和子id 同时存在;

  8. 为了优化资源嵌套,通过路由方法->shallow()实现浅层嵌套方法; 取消父级

    // 浅层嵌套
    Route::resource('blogs.comments', 'CommentController')->shallow();
    
  9. 实现后的路由及参数传递更精准:

    HTTP类型路由URI控制器方法路由命名
    GETblogs/{blog}/commentsindex()blogs.comments.index
    GETblogs/{blog}/comments/createcreate()blogs.comments.create
    POSTblogs/{blog}/commentsstore()blogs.comments.store
    GETcomments/{comment}show()blogs.comments.show
    GETcomments/{comment}/editedit()blogs.comments.edit
    PUT/PATCHcomments/{comment}update()blogs.comments.update
    DELETEcomments/{comment}destroy()blogs.comments.destroy
    public function edit($id) {return '评论id: ' . $id;
    }
    
  10. 如果觉得资源路由命名过长,可以自己自定义,有两种方式:

    ->name('index', 'b.c.i');
    ->names(['index' => 'b.c.i']);
    
  11. 如果觉得资源路由的参数不符合你的心意,也可以改变:

    ->parameter('blogs', 'id');
    ->parameters(['blogs' => 'blog_id', 'comments' => 'comment_id'
    ]);
    

09.表单伪造和CSRF保护

一.表单伪造

  1. 之前一直用的 GET 请求方式,而表单可以实现 POST 方式,我们来实验下:

  2. 先在 TaskController 创建两个方法,一个表单页,一个接受表单数据路由;

    public function form()
    {return view('form');
    }
    //表单页
    Route::get('task/form', 'TaskController@form');
    //接受表单数据
    Route::any('task/getform', function () {return \Illuminate\Support\Facades\Request::method();
    });
    
  3. 表单页以 post 发送,路由也使用 post 接受,以下表单提交会出现419 错误;

    <form action="/task/getform" method="post">用户名:<input type="text" name="user"><button type="submit">提交</button>
    </form>
    
  4. 这是为了避免被跨站请求伪造攻击,框架提供了 CSRF 令牌保护,请求时验证;

    <input type="hidden" name="_token" value="{{csrf_token()}}">
    
  5. 表单可以实现 POST 提交方式,那其它提交方式该如何实现呢?可以采用伪造技术;

    <input type="hidden" name="_method" value="PUT">
    
  6. 对于 CSRF 令牌保护和表单伪造提交方式,也支持快捷方式的声明,如下:

    @csrf
    @method('PUT')
    
  7. 如果我们想让某些 URL 关闭 csrf 验证,可以设置 csrf 白名单;

  8. 白名单具体设置位置在:中间件目录下的 VerifyCsrfToken.php 文件;

  9. 当然,不建议直接注释掉这个验证 csrf 功能的中间件;

    protected $except = ['api/*',
    ];
    

10.数据库配置入门

一.配置数据库
  1. 框架支持原生、查询构造器和 Eloquent ORM(关系型对象映射器)来操作数据库;

  2. 数据库的配置在 config/database.php,如果是本地可以直接配置.env 文件;

  3. 我们通过.env 文件配置数据库连接的相关信息,以提供给database 读取;

    DB_CONNECTION=mysql //.env
    DB_HOST=127.0.0.1
    DB_PORT=3306
    DB_DATABASE=grade
    DB_USERNAME=root
    DB_PASSWORD=123456
    'mysql' => [ //.database.php'driver' => 'mysql',...
    ]
  4. 我们可以直接创建一个新的控制器 DataController 来测试数据库部分;

  5. 数据库有一个专用类 DB,可以用它来实现原生查询和构造器查询;

    //使用 DB 类的 select()方法执行原生 SQL
    $user = DB::select('select * from laravel_user');
    return $user;
    
  6. 查询构造器主要通过 DB 类的各种数据库操作方法来实现,比如选定一条;

    //这里省去了 laravel_,需要在 database.php 配置
    $user = DB::table('user')->find(19);
    return [$user];
    
  7. 由于火狐浏览器自动将 JSON 显示的很美化,而 find()只返回对象;

    return response()->json($user);
    
  8. 使用 Eloquent ORM 模型来操作数据库,使用命令在 Http 目录下创建模型;

    php artisan make:model Http/Models/User

    //使用 Eloquent ORM 构建
    $user = User::all();
    return $user;
    

上面使用模型来操作数据后,报错提示数据表是复数:users;

而我们真实的数据库表为:laravel_user,为何会这样???

前缀可以在 database.php 修改添加:laravel_,最终变为:laravel_users;

由于模型编码规范要求数据表是复数,这里的复数并不是单纯加s;

可能会加 es,可能会加 ies,也可能是 child 编程 children 之类的;

可以使用字符串助手:Str::plural()来判断英文单词的复数情况:

return Str::plural('bus'); //buses
return Str::plural('user'); //users
return Str::plural('child'); //children

你可以根据规范去更改数据表名称,或者强制使用现有的数据表名;

protected $table = 'user';

11.构造器的查询.分块.聚合

一.构造器查询
  1. table()方法引入相应的表,get()方法可以查询当前表的所有数据;

    //获取全部结果
    $users = DB::table('users')->get();
    
  2. first()方法,可以获取到第一条数据;

    //获取第一条数据
    $users = DB::table('users')->first();
    
  3. value(字段名)方法,可以获取到第一条数据的指定字段的值;

    //获取第一条数据的 email 字段值
    $users = DB::table('users')->value('email');
    
  4. find(id)方法,可以获取指定 id 的一条数据;

    //通过 id 获取指定一条数据
    $users = DB::table('users')->find(20);
    
  5. pluck(字段名)可以获取所有数据单列值的集合;

    //获取单列值的集合
    $users = DB::table('users')->pluck('username');
    $users = DB::table('users')->pluck('username', 'email');
    
二.分块.聚合
  1. 如果你一次性处理成千上万条记录,防止读取出错,可以使用chunk()方法;

    //切割分块执行,每次读取 3 条,id 排序;
    DB::table('users')->orderBy('id')->chunk(3, function ($users) {foreach ($users as $user) {echo $user->username;}echo '------<br>';
    });
    
  2. 构造器查询提供了:count()、max()、min()、avg()和 sum()聚合查询;

    //聚合查询
    return DB::table('users')->count();
    return DB::table('users')->max('price');
    return DB::table('users')->avg('price');
    
  3. 构造器查询两个判断记录是否存在的方法:exists()和 doesntexists()方法;

    //判断是否存在
    return DB::table('users')->where('id', 19)->exists();
    return DB::table('users')->where('id', 18)->doesntExist();
    

PS:这里 DB::第一个使用静态,返回查询对象,然后使用->where 等各种查询方法,这些查询方法返回的还是查询对象,所以可以继续连缀操作。最后当遇到比如get()返回结果等方法时,停止连缀。所以,返回结果必须放在最后。

12.构造器的查询表达式

一.select 查询
  1. select()方法可以制定你想要的列,而不是所有列;

    //设置显示的列,设置列别名
    $users = DB::table('users')->select('username as name', 'email')->get();
    
  2. addSelect()方法,可以在你基础的查询构造器上再增加想要显示的字段;

    //给已经构建好的查询添加更多字段
    $base = DB::table('users')->select('username as name', 'email');
    $users = $base->addSelect('gender')->get();
    
  3. DB::raw()方法可以在 select()内部实现原生表达式,否则解析错误;

    //结合原生 SQL 实现复杂查询
    $users = DB::table('users')->select(DB::raw('COUNT(*) AS id, gender'))->groupBy('gender')->get();
    
  4. 也可以直接使用 selectRaw()方法实现内部原生;

    //或者直接使用 selectRaw()方法实现原生
    $users = DB::table('users')->selectRaw('COUNT(*) AS count, gender')->groupBy('gender')->get();
    
  5. 还可以通过 havingRaw()方法实现更精准的分组筛选;

    //使用 havingRaw 方法实现分组筛选
    $users = DB::table('users')->selectRaw('COUNT(*) AS count, gender')->groupBy('gender')->havingRaw('count>5')->get();
    
二.where 查询
  1. where()查询,即条件查询,完整形式需要字段表达式和值三个;

    //where 查询完整形式
    $users = DB::table('users')->where('id', '=', 19)->get();
    
  2. 大部分情况下,是等于用的比较多,就可以省略掉=号参数;

    //where 查询完整形式
    $users = DB::table('users')->where('id', 19)->get();
    
  3. 当然,还有>、<、>=、<=、<>、like 等操作符;

    users = DB::table('users')->where('price', '>=', 95)->get();
    $users = DB::table('users')->where('username', 'like', '%小%')->get();
    
  4. 如果条件较多,可以用数组来分别添加条件,具体如下:

    //如果条件都是等于,查看 SQL 语句用->toSql()替换->get()
    $users = DB::table('users')->where(['price' => 90,'gender' => '男'
    ])->get();
    //如果条件非等于
    $users = DB::table('users')->where([['price', '>=', 90],['gender', '=', '男']
    ])->get();
    

13.构造器的where派生查询

一.where 派生查询
  1. orWhere()方法,可以通过连缀实现两个或以上的 or 条件查询;

    //where() + orWhere 实现 or 条件查询
    $users = DB::table('users')->where('price', '>', 95)->orWhere('gender', '女')->toSql();
    
  2. 通过闭包,我们还可以构建更加复杂的 orWhere 查询;

    //orWhere()结合闭包查询
    $users = DB::table('users')
    ->where('price', '>', '95')
    ->orWhere(function ($query) {$query->where('gender', '女')->where('username', 'like', '%小%');
    })->toSql();
    
  3. whereBetween()可以实现区间查询,比如价格在一个区间内的用户;

    //whereBetween 查询区间价格 60~90 之间
    $users = DB::table('users')->whereBetween('price', [60, 90])->toSql();
    // PS:这里还支持相关三种:whereNotBetween/orWhereBetween/orWhereNotBetween;
    
  4. whereIn()可以实现数组匹配查询,比如匹配出数组里指定的数据;

    //whereIn 查询数组里匹配的数值
    $users = DB::table('users')->whereIn('id', [20,30,50])->toSql();
    
  5. whereNull()可以查询字段为 Null 的记录;

    //whereNull 查询字段值为 Null 的记录
    $users = DB::table('users')->whereNull('uid')->toSql();
    

    PS:这里还支持相关三种:whereNotNull/orWhereNull/orWhereNotNull;

  6. whereDate()可以查询指定日期的记录;

    //whereYear 查询指定日期的记录,或大于
    $users = DB::table('users')->whereDate('create_time', '2018-12-11')->toSql();

    // PS:这里还支持相关四种:whereYear/whereMonth/whereDay/whereTime,支持or 前缀

// PS:三个参数支持大于小于之类的操作 orWhereDate(‘create_time’,‘>’, ‘2018-12-11’)

14.构造器的排序分组.子查询

一.排序分组
  1. 使用 whereColumn()方法实现两个字段相等的查询结果;

    //判断两个相等的字段,同样支持 orWhereColumn()
    //支持符号'create_time','>', 'update_time'
    //支持符号支持数组多个字段格式['create_time','>', 'update_time']
    $users = DB::table('users')->whereColumn('create_time', 'update_time')->get();
    
  2. 使用 orderBy()方法实现 desc 或 asc 排序功能。

    //支持 orderByRaw 和 orderByDesc 倒序方法
    $users = DB::table('users')->orderBy('id', 'desc')->get();
    
  3. 使用 latest()方法设置时间倒序来排,默认时间字段是 created_at;

    //按照创建时间倒序排,默认字段 created_at
    $users = DB::table('users')->latest('create_time')->toSql();
    
  4. 使用 inRandomOrder()方法来随机排序,得到一个随机列表;

    //随机排序
    $users = DB::table('users')->inRandomOrder()->get();
    
  5. 使用 skip()和 take()限制结果集,或使用 offset()和 limit();

    //从第 3 条开始,显示 3 条
    $users = DB::table('users')->skip(2)->take(3)->toSql();
    $users = DB::table('users')->offset(2)->limit(3)->get();
    
  6. 使用 when()方法可以设置条件选择,执行相应的 SQL 语句;

    //when 实现条件选择
    $users = DB::table('users')->when(true, function ($query) {$query->where('id', 19);
    }, function ($query) {$query->where('username', '辉夜');
    })->get();
    
  7. 如果 MySQL 在 5.7+,有支持 JSON 数据的新特性;

    $users = DB::table('users')->where('list->id', 19)->first();

二.子查询
  1. 使用 whereExists()方法实现一个子查询结果,返回相应的主查询;

    //通过 books 表数据,查询到 users 表关联的所有用户
    $users = DB::table('users')->whereExists(function ($query) {$query->selectRaw(1)->from('books')->whereRaw('laravel_books.user_id = laravel_users.id');
    })->toSql();// whereRaw 这句也可以替代为:whereColumn('books.user_id','users.id');
    // PS:select 1 from,一般用于子查询的手段,目的是减少开销,提升效率,深入请搜索;
    
  2. 也可以使用 where(字段,function())闭包,来实现一个子查询;

    //id=子查询返回的 user_id
    $users = DB::table('users')->where('id', function ($query) {$query->select('user_id')->from('books')->whereColumn('books.user_id','users.id');
    })->toSql();
    

15.构造器的join查询

一.join 查询
  1. 使用 join 实现内联接的多表查询,比如三张表进行 inner join 查询;

    $users = DB::table('users')->join('books', 'users.id', '=', 'books.user_id')->join('profiles', 'users.id', '=', 'profiles.user_id')->select('users.id', 'users.username', 'users.email','books.title', 'profiles.hobby')->get();
    
  2. 也可以使用 leftjoin 左连接或 rightjoin 右连接实现多表查询;

    $users = DB::table('users')->leftJoin('books', 'users.id', '=', 'books.user_id')->rightjoin('profiles', 'users.id', '=', 'profiles.user_id')->get();
    
  3. 使用 crossjoin 交叉连接查询,会生成笛卡尔积,再用 distinct()取消重复;

    $users = DB::table('users')->crossJoin('books')->select('username', 'email')->distinct()->get();
    
  4. 如果你想要实现闭包查询,和 where 类似,只不过要用 on 和orOn 方法;

    $users = DB::table('users')->join('books', function ($join) {//支持 orOn 连缀$join->on('users.id', '=', 'books.user_id');})->toSql();
    // PS:on()方法后面如果想要再增加筛选条件,可以追加 where();
    
  5. 使用 joinSub 实现子连接查询,将对应的内容合并在一起输出;

    //子连接查询
    $query = DB::table('books')->selectRaw('user_id,title');
    $users = DB::table('users')->joinSub($query,'books', function ($join) {$join->on('users.id', '=', 'books.user_id');
    })->get();
    
  6. 使用 union()或 unionAll()方法实现两个查询的合并操作;

    //union 取消重复,unionAll 不取消重复
    $query = DB::table('users');
    $users = DB::table('users')->union($query)->get();
    

16.构造器的增删改

一.增删改操作
  1. 使用 insert()方法可以新增一条或多条记录;

    //新增一条记录
    DB::table('users')->insert(['username' => '李白','password' => '123456','email' => 'libai@163.com','details' => '123'
    ]);
    //新增多条记录
    DB::table('users')->insert([[...],[...]
    ]);
    
  2. 使用 insertOrIgnore()方法,可以忽略重复插入数据的错误;

    //忽略重复新增数据的错误
    DB::table('users')->insertOrIgnore(['id' => 304,'username' => '李白','password' => '123456','email' => 'libai@163.com','details' => '123'
    ]);
    
  3. 使用 insertGetId()方法,获取新增后的自增 ID;

    //获取新增后返回的 ID
    $id = DB::table('users')->insertGetId(['username' => '李白','password' => '123456','email' => 'libai@163.com','details' => '123'
    ]);
    return $id;
    
  4. 使用 update()方法,可以通过条件更新一条数据内容;

    //更新修改一条数据
    DB::table('users')->where('id', 304)->update(['username' => '李红','email' => 'lihong@163.com']);
    
  5. 使用 updateOrInsert()方法,可以先进行查找修改,如不存在,则新增;

    //参数 1:修改的条件
    //参数 2:修改的内容(新增的内容)
    DB::table('users')->updateOrInsert(['id'=>307],['username'=>'李黑', 'password'=>'654321', 'details'=>'123']
    );
    
  6. 对于 json 数据,新增和修改的方法和正常数据类似;

    //新增时,转换为 json 数据
    'list' => json_encode(['id'=>19])
    //修改时,使用 list->id 指定
    DB::table('users')->where('id', 306)->update(['list->id' => 20]);
    
  7. 更新数据时,可以使用自增 increment()和自减 decrement()方法;

    //默认自增/自减为 1,可设置
    DB::table('users')->where('id', 306)->increment('price');
    DB::table('users')->where('id', 306)->increment('price', 2);
    
  8. 使用 delete()删除数据,一般来说要加上 where 条件,否则清空;

    //删除一条数据
    DB::table('users')->delete(307);
    DB::table('users')->where('id', 307)->delete();
    //清空
    DB::table('users')->delete();
    DB::table('users')->truncate();
    

17.模型的定义

一.默认设置
  1. 框架可以使用 Eloquent ORM 进行数据库交互,也就是关系对象模型;

  2. 在数据库入门阶段,我们已经创建了一个 User.php 模型,如下:

    php artisan make:model Http/Models/User 默认在 app 目录

  3. 而调用的时候,我们也知道表名要遵循它默认规则,修改为复数,或特定;

    class User extends Model
    {protected $table = 'user';
    }
    
  4. 系统假定你的主键为 id,如果你要修改默认主键,可以特定;

    protected $primaryKey = 'xid';

  5. 系统假定你的主键 id 为自增性,意味着是主键会自动转换int 类型;

  6. 如果你希望不是非自增,非数值类型主键,可以设置取消;

    public $incrementing = false;

  7. 如果你主键不是一个整数,那么需要$keyType 设置为 string;

    protected $keyType = 'string';

  8. 系统默认情况下会接管 created_at 和 updated_at 两个时间戳列;

  9. 如果不想让系统干涉这两个列,可以设置 false 取消;

    public $timestamps = false;

  10. 如果你想自定义时间戳的格式,可以设置;

    protected $dateFormat = 'U';

  11. 可以更改创建时间 created_at 和更新时间 updated_at 字段名;

    const CREATED_AT = 'create_time';
    const UPDATED_AT = 'update_time';
    
  12. 默认读取 database.php 配置的数据库连接,也可以在模型端局部更改;

    protected $connection = 'mysql';

二.模型定义
  1. 之前在查询构造器部分,把常用的数据库操作基本讲完,模型大体相同;

  2. 比如,我们要查询所有数据,直接使用模型::all()即可;

    //查询所有记录
    $users = User::get(); //或 all()
    return [$users];
    
  3. 也可以像查询构造器一样,添加各种各样的条件,写法一样;

    //查询性别为男,价格大于 90,限制显示 2 条
    $users = User::where([['gender', '=', '男'],['price', '>', 95]
    ])->limit(2)->get();
    
  4. 虽然安装了插件,但模型还是没有代码提示,可以通过安装插件解决;

    composer require barryvdh/laravel-ide-helperphp artisan ide-helper:generate – 为 Facades 生成注释
    php artisan ide-helper:models – 为数据模型生成注释
    php artisan ide-helper:meta – 生成 PhpStorm Meta file
    
  5. 其它查询方法基本和查询构造器一样,如果有不一样,参考错误提示;

  6. 这里列出官网给出示例的方法,对照实验(结合详细文档,重复较多);

    (1) .find(1) //通过主键查找
    (2) .first() //查找第一个
    (3) .firstWhere() //找到查询中的首个
    (4) .find([1,2,3]) //通过数组查找
    (5) .firstOr() //查找首个返回,支持闭包
    (6) .firstOrFail() //找不到时返回异常
    (7) .count()max()等集合 //集合操作
    

    PS:还有很多在查询构造器中的方法,比如排序、分组子查询等等都可以使用(并未一一验证)。

18.模型的增删改

一.增删改操作
  1. 新增方法如下,注意:默认模型接管 created_at 和 updated_at;

    $users = new User();
    $users->username = '辉夜';
    $users->password = '123';
    $users->email = 'huiye@163.com';
    $users->details = '123';
    $users->save();
    
  2. 更新,只要是查找到一条数据的情况下使用 save()就是更新;

    $users = User::find(321);
    $users->username = '夜辉';
    $users->save();
    
  3. 使用 update()方法实现批量更新;

    User::where('username', '夜辉')->update(['username' => '辉夜']);
    
  4. 使用 create()方法实现新增,但需要在模型端设置批量赋值的许可;

    User::create(['username' => '辉夜','password' => '123','email' => 'huiye@163.com','details' => '123',
    ]);
    //许可批量赋值,默认不可
    protected $fillable = ['username','password','email','details'
    ];
    //不许可的批量赋值,不可和$fillable 同时使用
    //protected $guarded = ['uid'];
    //如果取消批量赋值限制,直接如下
    protected $guarded = [];
    

    PS:必须在模型中定义批量赋值的可填充字段,否则无法生效;防止用户不小心设置新值;

  5. 使用 delete()方法,可以删除数据;

    $users = User::find(332);
    $users->delete();
    //批量删除
    $users = User::where('username', '夜辉');
    $users->delete();
    
  6. 如果你是通过主键 id 删除,那使用 destroy(id)方法,免去查询操作;

    //通过主键删除
    User::destroy(328);
    

19.批量赋值和软删除

一.批量赋值
  1. 上一节增删改中,新增中我们发现需要进行批量赋值的许可;
  2. 一般情况下,是为了防止提交过来的字段在部分场景中不需要或不能;
  3. 所以,我们需要通过黑白名单机制进行过滤掉必要的字段;
//通过提交过来的数据一次性新增
User::create(\Request::all());
二.软删除
  1. 什么叫软删除?它相对于真实的删除,而并非真正的删除,只是隐藏了;

  2. 首先,需要在数据库创建一个字段 deleted_at(默认),用于判断是否被软删除;

  3. 默认设置这个字段为空(null),如果写入数据,成为非空状态,则说明被删除;

  4. 开启软删除的功能,需要在模型端设置一下:

    use SoftDeletes; //开启软删除功能

  5. 当开启了软删除功能,之前的删除操作,都会变成更新操作,给deleted_at 赋值;

    //删除一
    $users = User::find(82);
    $users->delete();
    //删除二
    User::destroy(81);
    
  6. 而当我们开启了软删除的功能后,此时通过正常的数据获取列表,会自动隐藏;

    //软删除的数据不可见
    $users = User::get();
    return [$users];
    //单独获取被软删除的数据不行
    $users = User::find(82);
    return [$users];
    
  7. 如果需要查询包含软删除的数据,通过 withTrashed()方法实现;

    //获取包含软删除的数据
    $users = User::withTrashed()->get();
    return [$users];
    //获取某个被软删除的数据(即使不是软删除的也可以搜索到)
    $users = User::withTrashed()->find(82);
    return [$users];
    
  8. 如果只想搜索出被软删除的数据,通过 onlyTrashed()方法实现;

    //获取所有软删除的数据
    $users = User::onlyTrashed()->get();
    return [$users];
    //获取某个被软删除的数据(只有软删除的数据才可以被搜索到)
    $users = User::onlyTrashed()->find(82);
    return [$users];
    
  9. 如果要对这个数据进行软删除的判断,是否是被软删除的,可以使用trashed();

    //判断是否是被软删除的数据
    $users = User::withTrashed()->find(81);
    return $users->trashed();
    
  10. 如果想将软删除的数据恢复正常(类似从回收站还原),使用restore()方法;

    //将被软删除的数据回复正常
    $users = User::onlyTrashed()->find(82);
    $users->restore();
    
  11. 如果开启了软删除,还需要强行真实的永久删除,可以使用forceDelete()方法;

    //开启软删除时的真实永久删除
    $users = User::onlyTrashed()->find(82);
    $users->forceDelete();
    

20.模型的作用域

一.本地作用域
  1. 很多情况下,我们在数据查找时有一部分条件会被重复且大量使用;

  2. 而这个条件,可能只是在这个模型对应的数据表使用,别的表并不使用;

  3. 那么这种情况,可以使用本地作用域的方式,将常用的 SQL 封装起来;

  4. 比如:用户模块中,我们大量查询需要查询性别为男,且其它条件的SQL;

    $users = User::where('gender', '男')->where('price', '>', 90)->get();
    

    PS:我们可以将性别为男这个片段,封装成一个单独的方法,然后统一在这个模型下调用;

    //App\Http\Models;
    //本地作用域,搜索自动添加为“男”的条件
    //语法:scope 开头,后面名称尽可能包含语义
    public function scopeGenderMale($query)
    {return $query->where('gender', '男');
    }
    //当然,如果感觉单词太长,直接 gm()也行
    $users = User::genderMale()->where('price', '>', 90)->get();
    
  5. 上面的方法比较死板,适合简单粗暴,如果想要灵活多变,支持传递参数;

    //参数可以是 1 个或多个
    $users = User::gender('女', -3)->where('price', '>', 90)->get();
    //参数 2 和 3,接受控制器传递过来的 1,2
    public function scopeGender($query, $value, $value2)
    {return $query->where('gender', $value)->where('status', $value2);
    }
    
二.全局作用域
  1. 全局作用域,顾名思义就是在任意地方都可以有效的封装条件;

  2. 比如有个需求,不管在哪里操作,总是显示 status 为 1 的用户;

  3. 首先在 app 目录下创建一个用于全局作用域的目录:Scopes;

  4. 创建一个用于设置 status 为 1 的全局作用域的类,它需要实现scope 接口;

    namespace App\Scopes;
    //这里引用代码自动生成
    use Illuminate\Database\Eloquent\Builder;
    use Illuminate\Database\Eloquent\Model;
    use Illuminate\Database\Eloquent\Scope;
    class StatusScope implements Scope
    {/*** @inheritDoc*/public function apply(Builder $builder, Model $model){// TODO: Implement apply() method.return $builder->where('status', 1);}
    }
    
  5. 此时,还不能实现全局,因为需要在模型设置个开关,让其富有灵活性;

    //启用全局作用域
    protected static function booted()
    {parent::booted(); // TODO: Change the autogenerated stubstatic::addGlobalScope(new StatusScope());
    }
    

    PS:而在控制器端,并不需要做任何设置,即可自动添加 status=1 的条件;

  6. 当然,如果这个全局只是针对某个模块,并不需要创建一个全局类,直接闭包即可;

    static::addGlobalScope('status', function (Builder $builder) {return $builder->where('status', 1);
    });
    

    PS:注意 Builder 引入的文件和全局类引入的文件一致,如果引入别的同名类会错;

  7. 如果某个查询,并不需要这个全局条件,可以单独移出掉;

    //取消名称为 status 的全局
    $users = User::withoutGlobalScope('status')->get();
    //取消全局类的条件
    $users = User::withoutGlobalScope(StatusScope::class)->get();
    

    PS:还有 withoutGlobalScopes([])方法,传递参数取消多个全局;

21.模型的访问器和修改器

一.访问器
  1. 访问器:就是在获取数据列表时,拦截属性并对属性进行修改的过程;

  2. 比如,我们在输出性别时,在性别左右加上括号,或给邮件转换为大写;

    //访问器,前固定 get,后固定 Attribute,Gender 是字段名
    //参数$value 是源字段值,可修改返回
    public function getGenderAttribute($value)
    {return '【'.$value.'】';
    }
    

    PS:如果字段名是两个单词中间是下划线:user_name,那么方法名:getUserNameAttribute()

  3. 我们也可以创建一个虚拟字段,用已有的数据字段进行整合,不过要进行数据追加;

    //将虚拟字段追加到数据对象列表里去
    protected $appends = ['info'];
    //创建一个虚拟字段
    public function getInfoAttribute()
    {return $this->username.'-'.$this->gender;
    }
    

    PS:注意,如果 gender 之前已经有访问器修改过,上面的方法会得到修改过的结果;

    PS:如果要使用源字段进行创建虚拟字段,需要使用下面这种:

    return $this->attributes['username'].'-'.$this->attributes['gender'];

二.修改器
  1. 修改器,相对于访问器,是在写入的时候拦截,进行修改再写入;

    //修改器,写入数据时,将邮箱转换为大写
    public function setEmailAttribute($value)
    {$this->attributes['email'] = strtoupper($value);
    }
    
  2. 可以添加默认的日期列,默认 created_at 和 updated_at;

    //设置可以自动写入日期的列
    protected $dates = ['details'
    ];
    
  3. 可以设置字段输出的类型,比如设置一个布尔型,输出时就是true 和false;

    //设置字段类型
    protected $casts = ['details' => 'boolean'
    ];
    

22.集合的使用

一.创建集合
  1. 什么是集合?即:它是一种更具读取性和处理能力的数组封装;

  2. 比如,我们从数据库得到的数据列表,它就是一种集合;

  3. 数据集合,提供了大量的方法方便我们进行各种操作;

  4. 除了数据库对象返回的数据集合之外,我们还可以自行创建数据集合;

    //创建一个数据集合
    $collection = collect(['张三', '李四', '王五', null]);
    //使用 dd 查看它的类型
    dd($collection);
    //直接 return 可以返回
    return $collection;
    
  5. 数据集合提供了大概有三十多个(31?)处理数据集合的方法,可链式调用;

  6. 这里我们把最常用的演示一遍,剩下的所有,可以自行参考手册方法列表;

    //以底层数组形式输出
    return $collection->all();
    //map 方法,类似访问器,可修改输出
    return $collection->map(function ($value, $key) {return $key.'['.$value.']';
    });
    //支持链式,reject 移出非 true 的值
    return $collection->reject(function ($value, $key) {return $value === null;
    })->map(function ($value, $key) {return $key.'['.$value.']';
    });
    //filter 筛选为 true 的值,和 reject 相反
    return $collection->filter(function ($value, $key) {return $value === null;
    });//search 找到后返回 key,找不到返回 false
    return $collection->search('王五');
    //集合的分割
    return $collection->chunk(2);
    //迭代输出
    $collection->each(function ($item, $key) {echo $item;
    });
    

    PS:这里就介绍这么多,更多的我们去手册扫一遍。做项目时,凭着记忆回头查,慢慢就熟了;PS:下一节,我们会花一节课,把最常用的方法再运行一遍加深印象;

  7. 如果三十多个方法都没有你要的,还可以自定义方法,比如说所有英文大写;

    $collection = collect(['Mr.Zhang', '李四', '王五', null]);
    Collection::macro('toUpper', function () {//dd($this);return $this->map(function ($value) {return strtoupper($value);});
    });
    return $collection->toUpper();
    

23.集合的常用方法

一.常用方法
  1. all()方法,转换为属性形式输出,使用 dd 方法看类型;

    $collection = collect([1, 2, 2, 3, 4, 4, 4]);
    dd($collection->all());
    // PS:$collection->dd()方法可以以 dd()模式输出,还有 dump()模式;
    
  2. avg()方法返回平均值;

    //返回平均值
    $collection = collect([1, 2, 3, 4]);
    return $collection->avg();
    //返回分组平均值
    $collection = collect([['男'=>1], ['女'=>1], ['男'=>3]]);
    return $collection->avg('男');
    
  3. count()方法返回集合总数;

    return $collection->count();
    // PS:相关的还有 sum()、min()、max()等统计;
    
  4. countBy()方法返回数值出现的次数或回调函数指定值出现的次数;

    $collection = collect([1, 2, 2, 3, 4, 4, 4]);
    return $collection->countBy();
    //回调搜索相同指定片段的值的次数
    $collection = collect(['xiaoxin@163.com', 'yihu@163.com', 'xiaoying@qq.com']);return $collection->countBy(function ($value) {return substr(strrchr($value, '@'), 1);
    });
    // PS:相关的还有 groupBy()、keyBy()方法;
    
  5. diff()方法返回集合数组之间不相同的部分,组合新的集合;

    //diff 返回两个集合中不相同的
    $collection = collect([1, 2, 3, 4, 5]);
    return $collection->diff([3, 5]);
    // PS:其中还有 diffAssoc()、diffKeys()派生方法;
    
  6. duplicates()返回重复的值;

    $collection = collect([1, 2, 2, 3, 4, 5, 5, 6]);
    return $collection->duplicates(); //严格派生方法:duplicatesStrict()
    
  7. first()返回成立后的第一个值;

    //返回判断成立的第一条数值
    $collection = collect([1, 2, 3, 4]);
    return $collection->first(function ($value) {
    return $value > 2;
    });
    // PS:相关的还有 every()、except()、only()、firstWhere()、last()等方法;
    
  8. flatten()将多维数组转换为一维;

    $collection = collect(['name'=>'Mr.Lee', 'details'=>['gender'=>'男', 'age'=>100]]);
    return $collection->flatten();
    
  9. get()通过键名找值;

    $collection = collect(['name'=>'Mr.Lee', 'gender'=>'男']);
    return $collection->get('name');
    // PS:相关的还有 pluck()等;
    
  10. has()判断集合中是否存在指定键;

    return $collection->has('name');
    
  11. pop()移出集合中最后一个值;

    $collection = collect([1, 2, 3, 4, 5]);
    //$collection->pop();
    return $collection;
    // PS:相关的还有 pull()、push()、put()方法
    
  12. slice()返回指定值后续的集合;

    $collection = collect([1, 2, 3, 4, 5]);
    return $collection->slice(3);
    

    PS:相关的还有 splice()等方法;

  13. sort()返回指定值后续的集合;

    $collection = collect([3, 1 , 5, 2, 7]);
    return $collection->sort()->values(); //需要配合 values()方法
    

    PS:相关的有 sortBy()、sortByDesc()、sortKeys()等;

  14. where()系列方法,和数据库条件一样;

    $collection = collect([['name'=>'Mr.Lee', 'gender'=>'男'],['name'=>'Miss.Zhang', 'gender'=>'女']
    ]);
    return $collection->where('name', 'Mr.Lee');
    

24.模型的数据集合

一.数据集合
  1. 数据集合,就是已经将模型方法 get()获取到的数据再进行处理;

  2. 比如:map()方法,通过它可以实现类似访问器一样对字段进行处理的效果;

    $users = User::get();
    //使用集合方法 map 可以对输出的字段进行过滤
    $women = $users->map(function ($user) {$user->email = strtoupper($user->email);return $user;
    });
    return [$women]
    

    PS:数据集合支持连缀操作,和数据库连缀一样;

  3. 使用 reject()方法,可以获取条件之外的数据内容;

    $women = $users->reject(function ($user) {return $user->gender != '女';
    })->map(function ($user) {return $user;
    });
    
  4. 下面列出常用的集合方法列表:

    //判断集合中是否包含指定的模型实例
    return $users->contains(19);
    return $users->contains(User::find(19));
    //返回不在集合中的所有模型
    return $users->diff(User::whereIn('id', [19,20,21])->get());
    //返回给定主键外的所有模型
    return $users->except([19,20,21]);
    //集合也有 find 方法
    return $users->find(19);
    //返回集合的数量
    return $users->count();
    //返回所有模型的主键
    return $users->modelKeys();
    //返回主键的所有模型
    return $users->only([19,20,21]);
    //返回集合中的唯一模型
    return $users->unique();
    

25.模型的一对一关联

一.关联概念
  1. 关联模型,即:两张或以上的表进行一定规则的绑定关联;
  2. 比如:一个学生(学生表)对应一张个人信息卡(信息表),这种就是一对一;
  3. 再比如:一篇博文(帖子表)对应多个评论(评论表),这种就是一对多;
  4. 再再比如:一个用户(用户表)对应多个职位(权限表), 而一个职位又可以有多个用户;那么,这种就是多对多关联;
  5. 自然,还有更多更复杂的关联,都是基于此的,我们只探讨这三种;
  6. 既然是关联,当然会有绑定的概念,当有数据库操作,关联表也会跟着变动;
  7. 这就是关联模型的意义;
二.一对一关联
  1. 一对一关联,我们选择两张表来做演示,首先看下两张表的结果对比;

  2. 由于之前 Models 下的 User.php 模型代码很多了,改成.bak 后重建;

  3. 创建两个 model,User.php 和 Profile.php,并使用命令实现提示;

    php artisan ide-helper:models

    //User.php,一对一关联 Profile 表
    public function profile()
    {//参数 1 或:'App\Http\Models\Profile'//参数 2:默认为 user_id,如不是需要指明//参数 3:默认 id,如不是需要指明return $this->hasOne(Profile::class, 'user_id', 'id');
    }
    
  4. 注意:Profile.php 只要建立空类即可,不需要其它,一对一调用如下:

    //注意:->profile 不要加括号,以属性方式访问
    $profiles = User::find(19)->profile;
    return $profiles;
    
  5. 一对一也支持反向关联:定向反向关联;具体通过在 Profile 设置即可;

    //profile.php
    //参数 1 为主表类
    //参数 2,3 和正向一致,默认对应可以不写
    public function user()
    {return $this->belongsTo(User::class, 'user_id', 'id');
    }
    $users = Profile::find(1)->user;
    return $users;
    

26.模型的一对多关联

27.模型的多对多关联

28.模型的关联查询

29.Debugbar调试器

30.模型的预加载

31.模型的关联写入

32.多对多的关联写入

33.请求和依赖注入

34.请求的常用方法

35.生成URL

36.Cookie

37.Session

38.理解中间件

39.中间件进阶

40.Blade模板入门

41.模版的流程控制

42.模板的继承布局

43.表单快速验证

44.验证类的使用

45.创建手动验证

46.验证规则大全

47.数据分页

http://www.xdnf.cn/news/221545.html

相关文章:

  • 基于PLC的图书管理识别系统设计
  • 修复典籍知识问答典籍管理界面典籍不能正确加载的问题
  • IAP远程升级入门讲解
  • 第十五章-PHP文件编程
  • Docker与Vmware网络模式的对别
  • softlockup_panic=1配置方法及区别
  • 天猫店铺代运营公司推荐与服务内容解析
  • 【进程与线程】
  • Linux权限管理进阶:文件归属、特殊权限与ACL详解
  • 力扣面试150题--删除链表的倒数第 N 个结点
  • 代发考试战报:4月份 思科认证,华为认证,考试战报分享
  • 不同类型插槽的声明方法和对应的调用方式
  • 题目:胖达的山头
  • 关于php-fpm的调优和配置
  • 2025年渗透测试面试题总结-拷打题库26(题目+回答)
  • AXPA17388: 4x45W 车用AB类四通道桥式输出音频功率放大器
  • MLOps全链路能力:模型监控、版本回滚与持续训练
  • 欧拉计划 Project Euler60(素数对集合)题解
  • LeetCode 2302 统计得分小于K的子数组数目(滑动窗口)
  • Mysql存储引擎、锁机制
  • (2)python之虚拟环境管理工具venv和anaconda
  • Lucene中不同搜索类型的使用方法、基本概念、应用场景、差异对比,并通过表格进行总结
  • JavaScript 作用域全面总结
  • 夜族觉醒 服务搭建 异地联机 保姆教程 流畅不卡顿
  • 【Science】强耦合手性准BIC驱动动量空间可编程高Q圆偏振激光——哈工大突破拓扑光子学新维度
  • GTC Taipei 2025 医疗域前瞻:从AI代理到医疗生态,解码医疗健康与生命科学的未来图景
  • 分享一款免费的 AI 工作流平台
  • Golang 并发编程
  • 从遍历序列构造二叉树:前序+中序与中序+后序的递归解法详解
  • USB 网卡——RNDIS 介绍