Laravel 学习笔记
Laravel学习笔记
一、简介
1. 安装
composer create-project laravel/laravel=6.0.* --prefer-dist blog
二、路由的使用
1. 文件位置
/routes/web.php
web网页的路由/routes/api.php
api接口的路由/routes/console.php
终端的路由,php artisan inspire
/routes/channels
待补充
2. 基本使用
2.1 根路由
<?php
Route::get('/', function () { return 'this is root route'; });
2.2 请求方式
<?php
Route::get('/users', function () {});
Route::post('/users', function () {});
Route::put('/users', function () {});
Route::patch('/users', function () {});
Route::delete('/users/1', function () {});
Route::options('/users', function () {});
2.3 match
和 any
的使用
<?php
// 匹配指定规则路由
Route::match(['get', 'post'], '/users', function () {});
// 匹配任何路由规则
Route::any('foo', function () {});
2.4 资源路由
<?php
Route::resource('/users', UsersController::class);
3. 参数
3.1 必选参数
-
格式:
{param}
-
举例
<?php Route::get('/users/{id}', 'UsersController@edit');
3.2 可选参数
-
格式:
{param?}
-
举例
<?php Route::get('/users/{id?}', 'UsersController@edit');
3.3 别名
-
格式:
->name('alias name')
-
举例
<?php Route::get('/aaa/bbb/ccc/ddd/eee/fff', 'XxxController@xxx')->name('abcdef');
-
调用方式:
route('abcedf')
3.4 使用 artisan
查看路由列表
- 命令:
php artisan route:list
3.5路由群组
-
格式:
group
-
举例
<?php Route::group(['prefix' => 'admin'], function () { Route::get('menus', function () {}); // 匹配路由:/admin/menus });
三、控制器
1. 文件位置
/app/Http/Controllers
2. 命名格式
- 格式:
大写驼峰+Controller.php
- 举例:商品控制器:
GoodsController.php
- 使用
artisan
创建:php artisan make:controller GoodsController
3. 接收用户参数
- 使用的类路径:
Illuminate\Support\Facades\Request
- 获取方式:
Request::get('参数名称', '默认值');
Request::all(); // 获取用户的所有参数
Request::get(''); // 获取 get 参数
Request::only([]); // 获取指定的几个参数
Request::except([]); // 排除指定的几个参数
Request::has('name'); // 判断参数是否存在
四、DB
类操作数据库
1. 文件所在位置
Illuminate\Support\Facades\DB::class
2. 基本操作
2.1 增加
-
insert
-
使用
table('表名')
再进行插入,返回bool
类型<?php $db = DB::table('user'); $db->insert(['nickname' => 'xfjpeter', 'email' => 'fsyzxz@163.com']); // 返回布尔类型的值
-
直接使用
::insert('sql语句')
插入,返回bool
类型<?php DB::insert('insert into user(nickname, email) values("xfjpeter", "fsyzxz@163.com")'); // 也是返回布尔类型值
-
批量插入,返回
bool
类型<?php $db = DB::table('user'); $data = [ ['nickname' => 'xfjpeter', 'email' => 'fsyzxz@163.com'], ['nickname' => 'alice', 'email' => 'alice@163.com'] ], $db->insert($data); // 返回布尔类型的值
-
-
insertGetId
,返回 插入的自增 id<?php $db = DB::table('user'); $db->insertGetId(['nickname' => 'tom', 'email' => 'tom@163.com']);
2.2 删除
-
delete
返回受影响的行数-
配合
where
进行删除<?php DB::table('user')->where('id', 1)->delete();
-
直接在
delete
传id
值<?php DB::table('user')->delete(3);
-
-
truncate
清空整张表<?php DB::table('user')->truncate();
2.3 修改
-
update
返回受影响的行数<?php $db->where('nickname', '杨幂')->update(['nickname' => '刘诗诗']);
-
increment
自增操作,返回受影响的行数<?php $db->where('id', '100')->increment('vote', 5);
-
decrement
自减操作,返回受影响行数<?php $db->where('id', 1)->decrement(1);
2.4 查询
-
取出基本数据
-
get
取出所有数据,返回的是一个Collection
<?php $res = DB::table('user')->where('id', 111)->get(); dd($res->toArray());
1、通过
foreach
循环时候,每一行的记录是一个 对象,不是数组2、如果查询没有结果,返回一个空
Collection
-
first
取出单行数据,返回一个对象<?php DB::table('user')->first();
1、如果查询没有结果,返回
null
-
value
取出某个值<?php DB::table('user')->value('nickname');
1、如果查询没有结果,返回
null
-
select
查询指定字段<?php DB::table('user')->select('nickname')->get();
-
select
执行sql
语句,返回一个二维数据<?php DB::select("select * from user");
-
orderBy
按指定字段排序<?php DB::table('user')->orderBy('id', 'desc')->get();
-
limit
和offset
配合进行分页操作<?php DB::table('user')->limit(3)->offset(0)->get();
-
五、本地和线上环境部署
1. 设置
-
设置
php.ini
文件env="dev" ; 开发环境 env="production" ; 生产环境
-
设置
/bootstrap/app.php
<?php // 新增一下内容 $envs = ['dev', 'production']; $app->loadEnvironmentFrom('.env.' . get_cfg_var('env'));
-
在根目录创建
.env.dev
和.env.production
分别表示开发和线上环境
六、视图操作
1. 文件位置
/resources/views
2. 文件命名方式
-
*.blade.php
.php
和.blade.php
两个文件同时存在,.blade.php
会优先显示
3. 控制器视图渲染
3.1 控制器、视图、路由
-
控制器:
app/Http/Controllers/TestController.php
<?php namespace App\Http\Controllers; class TestController { public function index() { return view('test.index'); } }
-
视图:
resources/views/test/index.blade.php
<h1>文件所在位置:resources/views/test/index.blade.php</h1>
-
路由:
routes/web.php
<?php Route::get('test.index', 'TestController@index')->name('test.index');
3.2 控制器传参
-
view('视图文件', 参数数组)
. . . return view('test.index', ['nickname' => 'xfjpeter', 'email' => 'fsyzxz@163.com']); . . .
-
with('键', '值')
传参return view('test.index')->with('nickname', 'xfjpeter')->with('email', 'fsyzxz@163.com');
-
with(数组)
传参return view('test.index')->with(['nickname' => 'xfjpeter', 'email' => 'fsyzxz@163.com']);
模板中使用的时候,只能用数组的方式
3.3 标签
3.3.1 循环
-
@foreach
@foreach($users as $key => $user) <div>key:{{$key}},昵称:{{$user->nickname}},邮箱:{{$user->email}}</div> @endforeach
3.3.2 判断语句
-
@if
@elseif
@foreach($users as $key => $user) @if($key % 2 == 0) <div style="color: red;">key:{{$key}},昵称:{{$user->nickname}},邮箱:{{$user->email}}</div> @else <div style="color: orange;">key:{{$key}},昵称:{{$user->nickname}},邮箱:{{$user->email}}</div> @endif @endforeach
3.4 模板继承
@yield('名称')
父级模板占位符@extends('父级模板')
继承父级模板@section
替换yield
占位的内容区域@include('文件名')
包含文件
3.5 引入资源文件
{{asset('css/app.css')}}
引入不带域名和版本号的 css 文件{{mix('css/app.css')}}
引入带域名和版本号的 css 文件
3.6 引入 csrf
3.6.1 基本使用
{{csrf_token()}}
引入 csrf 码{{csrf_field()}}
引入带 input 的csrf- 放在 meta 中,
<meta name="csrf-token" content="{{ csrf_token() }}">
3.6.2 排除不需要验证的路由
- 路径:
app/Http/Middleware/VerifyCsrfToken.php
中$except
中填写
七、validate 验证器
1. 基本使用
-
required
必填项$this->validate($request, [ 'name' => 'required' ], [ 'name.required' => '姓名不能为空' ])
-
unique
表字段唯一$this->validate($request, [ 'name' => 'required|unique:users,name' ], [ 'name.unique' => '姓名已经存在' ])
-
regex
正则验证$this->validate($request, [ 'name' => 'required|regex:\w{4,16}' ])
其他
1、添加自定义文件,如 bootstrap/helpers.php
-
创建文件
helpers.php
-
在文件中写入以下内容
<?php function test_helper() { return 'OK'; }
-
在
composer.json
中写入以下内容{ ... "autoload": { "files": [ "bootstrap/helpers.php" ] } }
-
在命令行执行
composer dumpautoload
-
测试文件是否导入成功,执行下面命令后输出 OK 表示导入成功
$ php artisan tinker >>>test_helper()
2、引入 bootstrap vue
- 引入
laravel/ui
包,composer require laravel/ui:"^1.0" --dev
- 上一步之行成功,引入 bootstrap,
php artisan ui vue
npm install
安装依赖模块- 监视文件变化,
npm run watch-poll
,如果这一步执行错误,可能是sass-loader
版本号太高,卸载sass-loader
重新安装一下:npm install --save-dev sass-loader@7.1.0
3、工厂类的使用
-
使用命令创建一个 factory 和 migration ,
php artisan make:model UserAddress -fm
-
在生成的
database/migrations
下找到刚刚创建的表类,写入以下内容... public function up() { Schema::create('user_addresses', function (Blueprint $table) { $table->bigIncrements('id'); $table->unsignedBigInteger('user_id'); $table->foreign('user_id')->on('users')->references('id')->onDelete('cascade'); $table->string('province'); $table->string('city'); $table->string('district'); $table->string('address'); $table->unsignedInteger('zip'); $table->string('concat_name'); $table->string('concat_phone'); $table->dateTime('last_used_at')->nullable(); $table->timestamps(); }); } ...
-
使用迁移命令,生成表,
php artisan migrate
-
在
database/factories/UserAddressFactory
中书写以下内容<?php /** @var \Illuminate\Database\Eloquent\Factory $factory */ use App\Models\UserAddress; use Faker\Generator as Faker; $factory->define(UserAddress::class, function (Faker $faker) { $addresses = [ ["北京市", "市辖区", "东城区"], ["河北省", "石家庄市", "长安区"], ["江苏省", "南京市", "浦口区"], ["江苏省", "苏州市", "相城区"], ["广东省", "深圳市", "福田区"], ]; $address = $faker->randomElement($addresses); return [ 'province' => $address[0], 'city' => $addresses[1], 'district' => $address[2], 'address' => sprintf('第%d条街道第%d号', $faker->randomNumber(2), $faker->randomNumber(3)), 'zip' => $faker->postcode, 'concat_name' => $faker->name, 'concat_phone' => $faker->phoneNumber, ]; });
$faker->randomElement($addresses)
是从$addresses
中随机出一个元素$faker->randomNumber()
是随机生成指定位数的数字$faker->postcode
是随机获取邮编号码$faker->name
随机生成用户姓名$faker->phoneNumber
随机生成手机号码
-
测试刚刚创建的工厂文件
$ php artisan tinker >>> factory(App\Models\UserAddress::class)->make()
-
factory()->make()
只是生成了数据,并未保存到数据库中,保存数据需要用到create
命令>>> factory(App\Models\UserAddress::class, 3)->create(['user_id' => 1])
-
4、使用 policy
控制权限
-
创建一个
policy
,php artisan make:policy UserAddressPolicy
-
在创建的文件中新增以下内容
public function own(User $user, UserAddress $address) { return $address->user_id == $user->id; }
-
接下来需要在
AuthServiceProvider
注册这个授权策略,app/Providers/AuthServiceProvider.php
,写入以下内容public function boot() { $this->registerPolicies(); // 使用 Gate::guessPolicyNamesUsing 方法来自定义策略文件的寻找逻辑 Gate::guessPolicyNamesUsing(function ($class) { // class_basename 是 Laravel 提供的一个辅助函数,可以获取类的简短名称 // 例如传入 \App\Models\User 会返回 User return '\\App\\Policies\\'.class_basename($class).'Policy'; }); }
-
在控制器中使用,例如以下代码
class UserAddressesController { public function edit(UserAddress $userAddress) { // 以下这行代码是触发策略机制 $this->authorize('own', $userAddress); } }
5、seeder
的使用
-
先创建
factory
类 -
使用命令创建
seeder
文件,php artisan make:seeder ProductsSeeder
-
在创建的文件中写入代码,如:
public function run() { $products = factory(\App\Models\Product::class, 30)->create(); foreach ($products as $product) { // 创建 3 个 sku $skus = factory(\App\Models\ProductSku::class, 3)->create(['product_id' => $product->id]); // 找出最低的价格 $product->update(['price' => $skus->min('price')]); } }
-
执行,
php artisan db:seed --class=ProductsSeeder
6、Exception
的使用
6.1 用户错误行为触发的异常
-
创建一个
exception
类,php artisan make:exception InvalidRequestException
-
在刚刚创建的
InvalidRequestException
中写入以下内容<?php namespace App\Exceptions; use Exception; use Illuminate\Http\Request; class InvalidRequestException extends Exception { public function __construct(string $message = "", int $code = 400) { parent::__construct($message, $code); } public function render(Request $request) { if ($request->expectsJson()) { // json() 方法第二个参数就是 Http 返回码 return response()->json(['msg' => $this->message], $this->code); } return view('pages.error', ['msg' => $this->message]); } }
$request->expectsJson()
判断当前是否ajax
请求,如果是返回json
格式的数据,否则在页面在返回错误信息
-
创建
resource/views/pages/error.blade.php
文件,写入以下内容@extends('layouts.app') @section('title', '错误') @section('content') <div class="card"> <div class="card-header">错误</div> <div class="card-body text-center"> <h1>{{ $msg }}</h1> <a class="btn btn-primary" href="{{ route('root') }}">返回首页</a> </div> </div> @endsection
-
如果不期望把这个日志写入栈内,在
app/Exceptions/Handler.php
文件中,把刚刚创建的类,写入进入protected $dontReport = [ InvalidRequestException::class, ];
6.2 创建系统内部异常,开发者须知
-
先创建异常类,
php artisan make:exception InternalException
-
在
app/Exceptions/InternalException
中写入<?php namespace App\Exceptions; use Exception; use Illuminate\Http\Request; class InternalException extends Exception { protected $msgForUser; public function __construct(string $message, string $msgForUser = '系统内部错误', int $code = 500) { parent::__construct($message, $code); $this->msgForUser = $msgForUser; } public function render(Request $request) { if ($request->expectsJson()) { return response()->json(['msg' => $this->msgForUser], $this->code); } return view('pages.error', ['msg' => $this->msgForUser]); } }
-
使用,在需要抛出异常的地方
... throw new InvalidRequestException('这是抛出的异常提示信息'); ...
7、任务队列的使用
-
创建一个任务队列,
php artisan make:job OrderClose
-
在刚刚创建的类中写入:
<?php namespace App\Jobs; use Illuminate\Bus\Queueable; use Illuminate\Queue\SerializesModels; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use App\Models\Order; // 代表这个类需要被放到队列中执行,而不是触发时立即执行 class CloseOrder implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; protected $order; public function __construct(Order $order, $delay) { $this->order = $order; // 设置延迟的时间,delay() 方法的参数代表多少秒之后执行 $this->delay($delay); } // 定义这个任务类具体的执行逻辑 // 当队列处理器从队列中取出任务时,会调用 handle() 方法 public function handle() { // 判断对应的订单是否已经被支付 // 如果已经支付则不需要关闭订单,直接退出 if ($this->order->paid_at) { return; } // 通过事务执行 sql \DB::transaction(function() { // 将订单的 closed 字段标记为 true,即关闭订单 $this->order->update(['closed' => true]); // 循环遍历订单中的商品 SKU,将订单中的数量加回到 SKU 的库存中去 foreach ($this->order->items as $item) { $item->productSku->addStock($item->amount); } }); } }
-
触发任务
use App\Jobs\CloseOrder; . . . public function store(OrderRequest $request) { . . . $this->dispatch(new CloseOrder($order, config('app.order_ttl'))); // 也可以使用函数:dispatch(new CloseOrder($order, config('app.order_ttl'))) return $order; }
-
启动任务队列,
php artisan queue:work
写在最后,持续更新中…