composer create-project --prefer-dist laravel/laravel projectname
chmod -R a+w storage bootstrap/cache # 设定目录权限
php artisan key:generate # 生成加密秘钥
confit/app.php配置timezone=>Asia/Shanghai, locale=>zh
* 服务器解析到`public`目录上 *
.env
配置文件、phpunit.xml env
变量设定 会被加载至两处
phpunit.xml env
配置失效)PHP $_ENV
变量env()
读取的是系统环境变量.env
文件在Docker
容器启动时被加载到容器的系统环境变量App::environment()
App\Exceptions\Handler
处理
report()
(默认是记录日志)render()
HTTP异常
abort(404 [,'error msg'])
resources/views/errors/404.blade.php
APP_DEBUG=true
Monolog
日志
配置
APP_LOG=single
(single、daily、syslog、errorlog
)APP_LOG_LEVEL=debug
\Log::debug|info|notice|warning|error|critical|alert|emergency('xxx', Array $context)
(错误级别降序)php artisan make:provider XxxServiceProvider
(自动注册于 config/app.php
)Provider
的register
完毕后才调用boot
延迟加载Provider
protected $defer = true;
provides
方法返回延迟加载服务的类名绑定
* 仅当需要修改容器中绑定的对象时才进行手工绑定 *
$this->app->bind(类名, 闭包); # 简单绑定
$this->app->bind(接口名, 类名); # 接口实现绑定
$this->app->singleton(类名, 闭包); # 单例绑定
$this->app->instance(类名, 对象); # 实例绑定
$this->app->when(类名)->needs(类名)->give(闭包); # 场景绑定
$this->app->when(类名)->needs('$变量名')->give(变量值); # 数据绑定
解析
* $this->app->make(类名);
* app(类名)
* resolve(类名);
* 自动依赖注入
容器事件
* 每当服务容器解析一个对象前就会触发一个事件 - 前置回调 *
$this->app->resolving(function ($object, $app) {
// 解析任何类型的对象时都会调用该方法...
});
$this->app->resolving(HelpSpot\API::class, function ($api, $app) {
// 解析「HelpSpot\API」类型的对象时调用...
});
使用模式
\Cache
\Illuminate\Support\Facades\Cache
Illuminate\Support\Facades\Facade
类,并实现getFacadeAccessor
方法返回容器绑定key路由方法
get、post、put、patch、delete、options
- 匹配基本请求类型 Route::get(路径, 控制器@方法, ['except'=>[..], 'only'=>[..]])
->where(正则约束)
->middleware('')
->name('')
match
- 匹配多个请求类型any
- 匹配所有请求类型resource
- 处理Rest请求
index、create、store、show、edit、update、destroy
Route::resource(路径, 控制器, ['except'=>[..], 'only'=>[..]])
$url = route('profile', Array $context) # 从命名路由生成url
return redirect()->route('profile'); # 重定向到命名路由
## 当前路由信息 ##
$route = Route::current();
$name = Route::currentRouteName();
$action = Route::currentRouteAction();
## 控制器中调用路由参数 ##
$this->route('ParaName')
## 表单方法伪造 ##
{{ method_field('PUT') }}
# 生成路由缓存(仅对基于控制器实现的路由有效)
php artisan route:clear
php artisan route:cache
中间件注册
app/Http/Kernel.php
bootstrap/app.php
中间件类型
BeforeMiddleware
BeforeMiddleware
$router->middleware('xxx', ...)
(别名或全名)Route::group(['middleware' => ['xxx', ...]], Closure);
$this->middleware('xxx')->only()->except()
terminate($request, $response)
方法(响应被发送到浏览器之后才运行)$middlewareGroups
属性->middleware('中间件名:参数1,参数2,...');
{{ csrf_field() }}
自动触发 VerifyCsrfToken
中间件meta标签X-CSRF-TOKEN头部类型
<meta name="csrf-token" content="{{ csrf_token() }}">
$.ajaxSetup({headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')}});
public function __invoke
方法(路由不指定Action
)php artisan make:controller XxxController --resource
请求数据
$request->get|input(xxx)
$request->all()
_method
指定HTTP类型 {{ method_field('PUT') }}
return response()->json(array $data)[->withCallback($jsonpCallbackName)]
return response()->download($pathToFile [, $name, $headers])->deleteFileAfterSend(true) #文件名必须ascii
return response()->file($pathToFile [, $headers])
# 嵌套视图路径用点隔开
- 常规视图:return view($viewName, $data)[->with($key, $value)](或者View::make())
- 定制头部:return response()->view($viewName, $data, $statuCode)->header($field, $value)
View::exists($viewName) #检查视图是否存在
View::share($key, $value) #设定全部视图共享的数据,AppServiceProvider::boot()中
## 视图编排ViewComposers(在视图输出前做修饰)##
# 定义composer类
class MyComposer
{
public function compose(View $view)
{
$view->....
}
}
# 视图绑定composer
View::composer($viewName|$viewNames|*, $composer::Class|function($view){})
## ViewCreator(视图一创建就执行修饰) ##
View::creator($viewName|$viewNames|*, $creator::Class|function($view){})
$response = response($content, $statusCode)
$response->header($field, $value)->withHeaders(array $headers)
$response->cookies($name, $value, $minutes [, $path, $domain, $secure, $httpOnly]) #中间件EncryptCookies::$except中配置不加密签名的cookie项
- 常规跳转:return redirect($url)
- 带session闪存跳转:return redirect($url)->with($name, $value)
- 跳至命名路由:return redirect()->route($routeName [, array $routeParams])
- 回到上一页:return back()->withInput(); #基于session实现的
- 跳至控制器方法:return redirect()->action('Controller@action' [, array $params])
细节
blade
注释不会html
输出{{-- 注释内容 --}}
@php xxx @endphp
@push(栈名) xxx @endpush
,调用@stack(栈名)
@inject('varName', My::class)
,调用{{ $varName }}
布局和区块
@extends(区块名)
定义区块内容
@section(区块名, 'content')
@section(区块名) @parent xxx @endsection
#@parant
指令引入继承区块的内容@yield(区块名)
组件和插槽
用于视图组件的重用
定义视图组件,设定插槽注入动态数据
{{ $slot }}
{{ $varname }}
component(组件视图名 [, array $data])
@slot('varname')
命名插槽数据
@endslot
默认插槽数据
endcomponent
子视图
@include(视图名 [, $data])
@includeif(视图名 [, $data])
@each(视图名, $collection, 'itemName', 集合空的候选视图)
数据输出
{{ $var }}
{!! $var !!}
{{ func() }}
@{{ $var }}
(最终结果双括号保留,@符剔除)@verbatim xxx @endverbatim
控制流
条件语句
@if (bool) xxx @elseif (bool) xxx @else xxx @endif
@unless (bool) xxx @endunless
@isset(bool) xxx @endisset
@empty(bool) xxx @endempty
循环语句
@for ($i = 0; $i < 10; $i++) xxx @endfor
@foreach () xxx @endforeach
@forelse () xxx @empty yyy @endforelse
@while (bool) xxx @endwhile
循环控制
@continue
@continue(bool)
@break
@break(bool)
*循环变量$loop->index
$loop->first
$loop->last
$loop->count
$loop->parent
自定义指令
php artisan view:clear
Blade::directive('directName', function ($expression) {
return "<?php echo xxx; ?>";
});
resources/lang/zh/file.php
语言配置
config/app.php
App::setLocale($locale)
App::getLocale(); App::isLocale('en');
读取(不存在则返回键名)
__('[filename.]lanKey' [, array $data])
($data
可替换翻译中的:xxx
占位符)@lang('[filename.]lanKey')
翻译复数
|
隔开{0}xxx|[1,10]yyy|[11,*]zzz
trans_choice('[filename.]lanKey', $num)
resources/lang/vendor/{package}/{locale}
前端移除 可选移除前端脚手架 php artisan preset none
Mix运行
npm install #安装package.json中的依赖
# 执行构建任务
npm run dev
npm run production
# 监控文件变动自动重新构建
npm run watch
npm run watch-poll #自动监控无效可用这个命令
Mix构建定义 - 基于webpack
定义构建任务(webpack.mix.js
)
# 构建基础
mix.webpackConfig({}) #部分调整webpack配置(亦可整个重置webpack.config.js)
.less|sass|js($from, $to, {$settings})
.options({processCssUrls:false})
.extract(['vue', ...]) #将指定依赖库导出到vendor.js文件
.version() #version后变名资源加载可通过 `mix(资源路径)`
.disableNotifications() #关闭编译通知
.sourceMaps()
# css|js文件合并
mix.styles|scripts([$fromPaths], $targetPath)
# 文件|目录拷贝
mix.copy|copyDirectory($from, $to)
# 使用编译的js(顺序加载)
<script src="/js/manifest.js"></script>
<script src="/js/vendor.js"></script>
<script src="/js/app.js"></script>
# `npm run环境`的检测
mix.inProduction()
browserSync支持
1. mix.browserSync(域名|{详细配置}) #浏览器:3000 -> browserSyn -> WebServer -> 文件监控
2. npm run watch
环境变量
.env
中MIX_
打头的变量process.env.变量名
验证失败后
redirect
至先前位置ajax
请求返回json错误信息
及422状态码flash
至 session
MessageBag $errors
自动被 ShareErrorsFromSession
中间件绑定到视图字段的特殊校验
bail
先决规则(任意规则校验失败后,该字段后续规则不再进行)sometimes
规则(有则校验)校验方式
$this->validate($request, array $rules)
$validator = Validator::make($request->all(), array $rules);
$validator->validate(); # 校验失败将自动跳转
$validator->fails();
$validator->after(function($validator){}); #验证后钩子
表单请求验证
Request
php artisan make:request MyRequest
- 路径app/Http/Requests
MyRequet
实现rules()+messages()、authorize()
逻辑MyRequest
后会自动在方法执行前进行验证错误消息
/** $return Illuminate\Support\MessageBag */
$errors = $validator->errors();
$errors->has('FieldName'); # 检查指定字段时候出错
$errors->first('FieldName'); # 指定字段第一个错误提示
$errors->get('FieldName'); # 指定字段所有错误提示
$errors->all(); # 全部错误
底层
# 读写分离配置
database连接配置下新增read、write键并配置相应db集群
DB::connection(连接名)->select(...); # 数据库切换
DB::connection()->getPdo(); # 获得底层pdo实例
## 数据库事务 ##
- 自动模式 DB::transaction(Closure);
- 手动模式 DB::beginTransaction(); DB::rollBack(); DB::commit();
## 数据库锁 ##
$builder->sharedLock(); # 共享锁(锁住写入)
$builder->lockForUpdate(); # 悲观所(锁住读写)
QueryBuilder
* 查询结果`Illuminate\Support\Collection`集合中的每个实例都是`StdClass`类型 *
DB::get|first|select|insert|update|delete|statement($sql, array $params); # 原生sql查询
$builder = DB::table('tableName'); # 查询构造器
$builder->insert($row | $rows); # 批量插入
$builder->chunk($perPage, function($records){...}); # 查询结果分块,闭包若返回false则将停止处理后续结果
$builder->distinct(); # 去重
$builder->->increment('field' [, $step]; # 递增
$builder->whereColumn('field1', '=', 'field2'); # 列比较
# 字段值
$builder->value(FieldName); # 获取一行记录的字段值
$builder->pluck(FieldName); # 获取集合的一列字段字段值
$builder->pluck(KeyField, $ValueField); # 获取集合的两列键值字段
# 字段选取
$builder->select('field1', 'xxx as filed2');
$builder->select(DB::raw('field1, xxx as filed2'));
# 参数分组(通过where的闭包进行)
$builder->where(function($query){
$query->where ...
});
# exist查询
$builder->whereExists(function($query){
$query->select('xx')->from('xx')->where('child.parent_id = parent.id')...
});
## 子查询构建
$builder = DB::table(DB::raw("({$childQuery->toSql()}) as tmp"))->->mergeBindings($childQuery->getQuery());
分页
# 系统默认当前页码?page=参数
# 直接返回分页器, 将被框架自动转成JSON
# 创建分页
$builder|Model->paginate($perPage) // Illuminate\Pagination\LengthAwarePaginator 带完整分页信息
$builder|Model->simplePaginate($perPage) // Illuminate\Pagination\Paginator 不查询分页情况(仅知道前后页的简单分页)
# 内部集合数据
$paginator->getCollection()
$paginator->setCollection($collection)
# 分页助手方法
->links(【'view.自定义分页模板'】) # 分页链接(php artisan vendor:publish --tag=laravel-pagination)
->setPath($uri) # 设定基础uri
->appends(Array) # 分页链接加参数
Migration
php artisan make:migration create_xxxs_table --create|table=xxxs # migration建表
php artisan migrate:rollback 【--step=num】 # 回滚上次数据库变动涉及的migration操作
php artisan migrate:reset # 回滚所有migration
php artisan migrate:refresh 【--step=num】 # 先重置后重载migration
Schema::hasTable($tableName) # 结构检查
Schema::hasColumn($colName1, ...)
Schema::connection('foo') # 切换链接
Schema::rename($from, $to) # 重命名
Schema::drop|dropIfExists($tableName) # 删除
# 表定义
$table->increments('id');
$table->字段类型(字段名)->unsigned()->nullable()->default(默认值)->after(列名)->comment(注释); #字段定义
$table->timestamps(); #created_at & updated_at
$table->softDeletes(); #软删除deleted_at
$table->索引类型(字段名 [, 索引名称]); #索引定义(复合索引则传入字段数组)
# 杂项表处理
$table->engine = 'InnoDB';
$table->....->change(); #更新已有字段
$table->renameColumn('from', 'to'); #重命名字段
$table->dropColumn($colName); #删除字段
$table->dropIndex($index); #删除索引
# !注意事项! #
SQLite 在单个Schema下只支持处理一个Column
基础查询
php artisan make:model Models/ModelName -m
# 查
$builder = Model::query() | $model->newQuery()
$builder->get()
$builder->first|firstOrFail()
$builder->chunk($num, function($rows{ });
Model::all() #表中所有记录
Model::find|findOrFail($id | $ids)
# 游标查询
foreach($builder->cursor() as $item) # 一次查一条,节约内存
# 增
$model=new MyModel;$model->save();
Model::create($data);
Model::firstOrCreate($data);
Model::firstOrNew($data);
# 删
$builder->delete(); # 批量删除
$model->delete();
Model::destroy($ids);
# 改
$model->save();
$builder->update($data); # 批量更新
模型定制属性
protected $connection = 'connectionName'; # 重定向连接名
protected $table = 'tableName'; # 重定向表名(默认使用模型的SnakeCase复数形式为表名)
protected $primaryKey = 'fieldName'; # 重定向主键名(默认为整型id)
public $incrementing = false; # 声明主键为非递增、非数字
# 默认的created_at、updated_at字段被转换成Carbon
protected $dates = [created_at', 'updated_at', 'deleted_at']; # 指定哪些字段被自动Carbon转换
protected $dateFormat = 'Y-m-d H:i:s'; # 设定日期字段存储或序列化的格式
const CREATED_AT = 'createtimeName'; # 重指定默认创建时间字段
const UPDATED_AT = 'updatetimeName'; # 重指定默认ge时间字段
public $timestamps = false; # 禁止自动维护时间字段(默认的单个模型save()方法调用时自动更新两个时间字段)
# 调用create()批量赋值前配置下面属性之一(Mass-Assignment批量赋值保护)
protected $guarded = []; # 黑名单,空数组则所有属性可被批量赋值
protected $fillable = []; # 白名单
# belongsTo、belongsToMany关系 更新父级时间戳
protected $touches = [关联名];
# 属性类型转换,支持integer,real,float,double,string,boolean,object,array,collection,date,datetime,timestamp
protected $casts = [字段 => 目标数据类型];
# 特色使用:json字段array类型转换为数组
# 字段显示与隐藏(影响toArray、toJson方法)
protected $hidden = ['password'];
protected $visible = ['id', 'name'];
# 临时修改字段可见性
$model->makeVisible/makeHidden('field')->toArray();
# array/json输出追加访问器字段
protected $appends = ['is_admin'];
public function getIsAdminAttribute()
{
return (bool)this->attributes['admin'];
}
# 动态重定向连接名
public function getConnectionName()
{
return app()->environment('testing') ?
'DatabaseName' : config('database.default');
}
# 字段值修饰器
- 区别于`eloquence`中的`Mappable, Mutable`
- accessor —— 修饰器方法取名为 “get字段驼峰式Attribute($value)”
- mutator —— 修饰器方法取名为 “get字段驼峰式Attribute($value)”
软删除
# migration创建软删除字段
$table->softDeletes();
# 模型声明软删除(deleted_at非空时认定为记录已被删除)
use SoftDeletes;
protected $dates = ['deleted_at'];
$model->trashed(); # 判断是否被软删除
$model->forceDelete(); # 强制完全删除
# 恢复被软删除的数据
$model->restore(); # 单个恢复
$builder->restore(); # 批量恢复
# 默认软删除数据不在查询结果中
Model::withTrashed() # 声明包含软删除数据
Model::onlyTrashed() # 声明只查询软删除数据
查询作用域(增加查询约束条件)
## 全局作用域 ##
class CustomScope implenments Scope
{
public function apply(Builder $builder, Model $model)
{
return $builder->where...
}
}
class CustomModel extends Model
{
protected static function boot()
{
parent::boot();
# 模型绑定全局作用域类
static::addGlobalScope(new AgeScope);
# 模型绑定全局域闭包
static::addGlobalScope('age', function(Builder $builder) {
$builder->where...
});
}
}
# 临时解除全局作用域
Model::withoutGlobalScope(...)
## 本地作用域 ##
class CustomModel extends Model
{
public function scopeXxx($query【, $params】)
{
return $query->where...
}
}
# 本地作用域(临时作用)
$builder->Xxx([$params])...
CustomModel::Xxx([$params])
打印SQL
/* @var \Illuminate\Database\Eloquent\Builder $query */
$query->toSql();
\DB::enableQueryLog();
# SQL查询
dd(\DB::getQueryLog());
模型事件
# 模型生命周期事件
creating, created, updating, updated, saving, saved, deleting, deleted, restoring, restored
# 监听模型事件
AppServiceProvider->boot()
{
# 监听sql查询事件
\DB::listen(function ($query) {
dump($query->sql, $query->bindings);
});
# 注册模型单一事件监听器
XxxModel::creating(function ($xxxModel) {
# 返回false将取消 save / update 操作
return boolean;
});
# 用observer管理模型一组事件监听器
XxxModel::observe(XxxObserver::class);
}
class XxxObserver
{
public function created(XxxModel $Xxx){ ... }
}
关联定义
多对多关联是个绑定关系 & 其他关联是个衍生关系
## 正向关系 ##
- 子模型外键参考为“snake父模型名_主键”
- 父模型本地键参考为“主键”
$this->hasOne(子模型, 外键, 本地键) #一对一
$this->hasMany(子模型, 外键, 本地键) #一对多
## 反向关系 ##
- 子模型外键参考为“snake关联方法名_主键”
- 父模型其他键参考为“主键”
$this->belongsTo(父模型, 外键, 其他键) #一对一
$this->belongsTo(父模型, 外键, 其他键) #多对一
## 多对多 ##
- 中间表名参考为“字母顺序排列组合的下划线表名”
- 中间表上的外键:
* 当前模型外键参考为“snake当前模型名_主键”
* 关联模型外键参考为“snake关联模型名_主键”
$this->belongsToMany(关联模型, 中间表, 当前模型外键, 关联模型外键)
->using(中间表模型) #可选,自定义中间表模型(继承Illuminate\Database\Eloquent\Relations\Pivot)
->wherePivot|wherePivotIn() #可选,过滤中间表字段
->withPivot($field1, ...) #可选,声明中间表包含的外键以外的字段
## 远程一对多 ##
一对多两级放大
- 中间模型外键参考为“snake模型名_主键”
- 远程模型外键参考为“snake模型名_主键”
- 当前模型本地键参考为“snake模型名_主键”
$this->hasManyThrough(远程模型, 中间模型, 中建模型外键, 远程模型外键, 本地键)
## 一对多morph多态 ##
多个一衍生针对同组多
- 可选关联名参考为“关联方法名”,必选关联名建议为“子模型名able”
- type字段名参考为“关联名_type”
- id字段名参考为“关联名_id”
- 本地键参考为“主键”
正向s: $this->morphMany(子模型, 必选关联名, [type字段名, id字段名, 本地键])
反向able:$this->morphTo([可选关联名, type字段名, id字段名])
- 默认“type字段值”参考为“完整命名空间指定模型名”
- 自定义type字段值需注册多态映射到AppServiceProvider::boot
use Illuminate\Database\Eloquent\Relations\Relation;
Relation::morphMap([type => 模型]);
## 多对多morph多态 ##
多个一跨中间表绑定共享同一组多
多对多关联基础上,其中一端多进行多态化
正向s: $this->morphToMany(父模型, 必选关联名)
多个反向s: $this->morphedByMany(子模型, 必选关联名)
查询关联
################ 查询关联数据 - 懒加载 ################
直接通过动态属性访问关联是“懒加载”,在访问关联数据属性时才加载关联
查询:
- $model->$relation #直接动态属性访问关联
- $model->$relation->pivot #pivot属性访问中间表(多对多关联场景,且默认只能访问到外键字段)
################ 查询关联数据 - 预加载 ################
使用with方法“EagerLoad预加载”,在查询父数据时即加载关联(其`WhereIn`机制解决了`N+1`问题,减少总查询至2次)
声明:
- 模型::with($relation1, ...) #加载多个关联
- 模型::with($relation1.$relation1_a, ...) #加载嵌套关联
- 模型::with([$relation => function($query){ $query->关联数据约束、排序等 }])->... #约束关联数据
- $collection|$model->load($relation1, ... | [$relation1 => function])#延迟预加载(手动预加载)
查询:
- $model->$relation #with声明后动态属性访问关联
################ 查询关联计数 ################
只统计不加载数据
声明:
- 单个关联计数 模型::withCount(关联名)->...
- 别名关联计数 模型::withCount('关联名 AS 别名')->...
- 多个关联计数 模型::withCount([关联1, 关联2])->...
- 约束关联计数 模型::withCount([关联 => function($query){ $query->where(关联数据约束) }])->...
查询:
- $model->$relation_count #动态属性访问计数
######## 关联过滤(过滤条件施加到关联数据上) ########
## 查询结果 - 关联数据 ##
- 模型::with([$relation => function($query){ $query->关联数据约束、排序等 }])->... #with声明时关联过滤
- $model->$relation()->where #关联结果进一步过滤
## 查询结果 - 主对象 ##
#1. 关联数据存在性 约束
- 模型::has(关联名 [,比较符, 数量])->... #关联名中可进一步使用点语法来声明关联数据下属数据的存在性
- 模型::whereHas|orWhereHas(关联名, function($query){ $query->where(关联数据约束) })->...
#2. 关联数据不存在性 约束
- 模型::doesntHave(关联名)->...
- 模型::whereDoesntHave(关联名, function($query){ $query->where(关联数据约束) })->...
插入/更新 关联数据
## 正向关系 ###
$parent->relations()->save($child)
$parent->relations()->saveMany(array $childs)
$parent->relations()->create(array $child1_data)
## 反向关系 ##
$child->relation()->associate($parent) && $child->save()
$child->relation()->dissociate($parent) && $child->save()
## 多对多关联 ##
--通过id处理--
- $modelA->relations()->attach($modelB_ID | $modelB_IDS [, array 中间表更新]) #中间表追加绑定关系
- $modelA->relations()->detach($modelB_ID | $modelB_IDS) #中间表解除绑定关系
- $modelA->relations()->detach() #中间表解除A的所有绑定
- $modelA->relations()->sync($modelB_IDS) #中间表重置绑定关系
- $modelA->relations()->syncWithoutDetaching($modelB_IDS) #中间表重置绑定关系(但是不解除已有绑定)
- $modelA->relations()->toggle($modelB_IDS) #中间表切换绑定关系(已绑的解绑, 未绑的绑定)
--通过对象处理--
- 使用正向关系里的所有方法
- $modelA->relations()->save($modelB [, array 中间表更新]) #中间表追加绑定关系
- $modelA->relations()->updateExistingPivot($modelB_ID , array 中间表更新) #更新中间表某条绑定关系的数据
普通集合 - Illuminate\Support\Collection
类
递归序列化
$collection|$model->toArray()
$collection|$model->toJson()
collect($array)
动态属性方式 调用 高阶信息方法
contains,each,every,filter,first,map,partition,reject,sortBy,sortByDesc,sum
ORM集合 - Illuminate\Database\Eloquent\Collection
Cache::store($storeType)->...;# 切换缓存的store驱动
Cache->get($key【, $default】);
Cache->put($key, $value, $minutes|$expiresAt);
Cache::forget($key); //删除缓存
Cache::flush(); //清空所有缓存
Cache->add($key, $value, $minutes|$expiresAt); //不存在时才更新,实际写入时返回true
Cache->forever($key【, $default】); //永久缓存
Cache::has($key);
Cache::increment|decrement($key【, $step】);
Cache::remember($key, $minutes, Closure); //获取值,不存在则闭包更新
Cache::pull($key); // 一次性获取然后删除
# 缓存标签
Cache::tags(array $tags)->put($key, $value, $minutes);
Cache::tags(array $tags)->get($key);
Cache::tags(array $tags)->flush();
# EventServiceProvider中可注册监听缓存事件
绑定
EventServiceProvider->listen
中注册绑定 * 根据绑定配置自动创建 `php artisan event:generate` *
protected $listen = [
事件类 => [
监听器类1,
....
],
];
EventServiceProvider::boot()
中注册public function boot()
{
parent::boot();
# 单一事件监听
Event::listen('event.事件名', function($data){});
# 全局事件监听
Event::listen('event.*', function($eventName, array $eventData){});
}
单事件监听器
handle
中返回false
将会队列化监听器
ShouldQueue
接口public $connection|$queue
定制 连接&队列public function failed(OrderShipped $event, $exception)
中处理FailedJob
多事件订阅者 EventServiceProvider $subscribe
中注册
namespace App\Listeners;
class MyEventSubscriber
{
public function onMyAction($event){...}
# 处理订阅逻辑
public function subscribe($events)
{
$events->listen(事件类, 'MyEventSubscriber@onMyAction');
}
}
派发事件 event(new MyEvent())
快速搭建
php artisan make:auth
生成认证相关的路由、视图、home示例php artisan migrate
数据表准备config/auth.php
配置
web session、api token
两种)providers - 持久层账号读取模式(内置Eloquent、Database
两种)
remember_token
字段(用于记住我)框架已预置4个Auth控制器
LoginController
username()
(默认email
字段)use ThrottlesLogins
(认证字段+IP限流试登次数/Min)Auth控制器定制
$redirectTo | redirectTo()
(默认/home
)Guard
认证模式guard()
登录检查
Auth::check()
auth
路由中间件检查
guard
:->middleware('auth')
guard
:->middleware('auth:api')
获取用户
$request->user();
Auth::user();
Auth::id();
自主认证
$credentials = ['email' => $email, 'password' => $password, ...] #凭据
Auth::[guard('web')]->attempt($credentials [, $boolRememberMe]) #登录(返回bool,登录成功则启动认证session)
Auth::logout() #登出(清除session登录信息)
Auth::once($credentials) #仅认证一次当前请求(no session)
return redirect()->intended(备用地址) #跳至被认证中间件截断的原先意向页面
Auth::viaRemember() #检查用户是否通过`RememberMe cookie`登录(返回bool)
模拟身份
# 登入为指定用户
Auth::[guard('web')]->login($user [, $boolRemember])
Auth::[guard('web')]->loginUsingId($userId [, $boolRememberMe])
自定义Guard
# 定义
Illuminate\Contracts\Auth\Guard
# AuthServiceProvider::boot()下注册
Auth::extend('my_guard_driver', function($app, $name, array $config){
return new MyGuard(Auth::createUserProvider($config['provider']));
});
# config('auth.guards')下配置
'guards' => [
'my_guard' => [
'driver' => 'my_guard_driver',
'provider' => 'users',
],
],
自定义Providor
# 定义
Illuminate\Contracts\Auth\UserProvider
# AuthServiceProvider::boot()下注册
Auth::provider('my_provider_dirver', function($app, array $config) {
return new MyProvider($app->make('riak.connection'));
});
# config('auth.guards')下配置
'providers' => [
'my_provider' => [
'driver' => 'my_provider_dirver',
],
],
认证事件
# Illuminate\Auth\Events空间下事件
- Registered
- Attempting
- Authenticated
- Login
- Failed
- Logout
- Lockout
密码重置
内建账户系统的重置机制
User
模型配置
use Notifiable
implement CanResetPassword
(use CanResetPassword
来实现)reset token
表定制处理
ForgotPasswordController|ResetPasswordController::broker()
定制Password Broker
User::sendPasswordResetNotification()
定制重置邮件的通知类加密解密
加解密(加密前准备APP_KEY
)
encrypt|decrypt()
(支持字符串、对象、数组)\Crypt::encryptString|decryptString()
(支持字符串)HASH
Hash
提供Bcrypt
散列处理(默认用于内建账户系统的密码存储)散列使用
\Hash::make($str);
\Hash::check($str, $hashedStr);
Gate鉴权 简易、闭包式、资源无关的 鉴权(定义在AuthServiceProvider::boot())
## 定义 ##
Gate::define(权限名, function ($user [, $model]) {
return bool
});
Gate::define(权限名, '策略类@操作')
Gate::resource(资源名, 策略类名) #资源式Gate(默认 资源.view、create、update、delete)
## 鉴权 ##
Gate::allows|denies(权限名 [, $model]) #默认当前用户
Gate::forUser($user)->allows|denies(权限名 [, $model]) #明确指定用户
Policy鉴权 鉴权特定资源的几个操作
## 定义 ##
php artisan make:policy MyPolicy [--model=My]
AuthServiceProvider::$policies #注册以关联 策略&资源
MyPolicy::before($user, $ability) #策略过滤以预鉴权(返回null才进入policy鉴权)
## 鉴权 ##
$user->can|cant(权限名, $model|Model::class) #未通过则返回false
Controller->authorize(权限名, $model|Model::class) #未通过则抛出AuthorizationException
## Blade模板鉴权 ##
can|cannot(权限名, $model|Model::class)
xxx
elsecan|elsecannot(权限名, $model|Model::class)
xxx
endcan|endcannot
创建命令
php artisan make:command 命令名
(默认目录app/Console/Commands
)参数
{name=default}
{name?}
{name*}
选项
{--opt}
(选项简写{--O|opt}
){--opt=default}
{--opt*}
: description
读取数据(无则返回null
)
$this->argument('name')
、所有参数$this->arguments()
$this->option('name')
、所有选项$this->options()
交互
提示输入
$answer = $this->ask('question?');
$answer = $this->secret('question?');
if ($this->confirm('Are you sure?'))
$name = $this->anticipate('Whats your name?', ['Tom', 'Jim']);
$name = $this->choice('Whats your name?', ['Tom', 'Jim'], 'defaultName');
输出
文字输出
$this->line()
$this->info()
$this->error()
$this->question()
$this->comment()
$this->table([$field1...], [$value1...])
$bar = $this->output->createProgressBar($num);
$bar->advance();
$bar->finish();
注册命令
$this->load(__DIR__.'/Commands');
Kernel::$commands
编程调用命令
Artisan::call($command, array $args);
Artisan::queue($command, array $args)->onConnection(连接名)->onQueue(队列名);
命令中调用命令
$this->call($command, array $args);
$this->callSilent($command, array $args);
其他命令
routes/console.php
Artisan::command('sig:nature {arg}' function($arg){...})->describe(命令描述);
php artisan serve # 启动本地开发服务器localhost:8000
php artisan down --message='系统升级中' # 进入维护模式:关闭服务、队列(默认视图resources/views/errors/503.blade.php)
php artisan up # 服务重启
App\Console\Kernel::schedule(Schedule $schedule)
* * * * * php 项目路径/artisan schedule:run >> /dev/null 2>&1
调度模式
$schedule->call(function(){. . .})->daily();
$schedule->command('xxx:yyy --force')->daily();
$schedule->command(XxxCommand::class, ['--force'])->daily();
$schedule->exec('echo HelloWorld')->daily();
调度频率
->cron('* * * * * *') #自定义频率
->everyMinute()
->hourly() | ->hourlyAt(20)
->daily() | ->dailyAt('13:00')
->weekly()
->monthly() | ->monthlyOn(4, '15:00')
->quarterly()
->yearly()
额外约束
->when(闭包)
->at('13:00')
->between('8:00', '17:00')
->>mondays|weekdays|sundays|...()
->timezone('America/New_York') #设置时区
任务输出
# 只适用于 $schedule->command() 方法
->appendOutputTo|sendOutputTo|emailOutputTo($filePath)
任务钩子
->before|after(闭包)
Ping
钩子 ->pingBefore|thenPing(闭包)
(依赖Guzzle
)特殊设定
避免任务重叠 ->withoutOverlapping()
->evenInMaintenanceMode()
覆盖面:
# mock数据(视情况可选)
$mock = \Mockery::mock(XxxRepository::class);
$mock->shouldReceive($methodName)->andReturn($model);
$this->app->instance(XxxRepository::class, $mock); #容器针对某类绑定到mock实例
# 发起请求
$this->get/post($api [, array $headers]);
# 测试响应
$this->seeStatusCode(200);
$this->seeHeader($headName【, $headVal】);
$this->seeJsonStructure(array $structure);
$this->seeJsonContains(array $structure);
$this->seeJsonEquals(array $structure); # 要求完整数据结构
$this->seeInDatabase($tableName, array $data);
$this->assertCount($num, array $testData);
config/filesystems.php
中配置文件系统连接及其相应驱动
Public文件系统 - 公共访问磁盘
local
驱动(根路径storage/app
)public/storage->storage/app/public
(php artisan storage:link
)asset('storage/myfile.txt')
FTP文件系统
'ftp' => [
'driver' => 'ftp',
'host' => 'ftp.example.com',
'username' => 'your-username',
'password' => 'your-password',
// 'port' => 21,
// 'root' => '',
// 'passive' => true,
// 'ssl' => true,
// 'timeout' => 30,
],
文件系统操作
$storage = Storage::disk(文件系统连接);
->url|get|exists|size|lastModified|getVisibility($path)
->copy|move($fromPath, $toPath)
->delete($filePath|$files)
->put|prepend|append($path, $content|$resource) //大文件建议使用资源句柄
# 自动流式处理,返回完整文件名路径
* ->putFile($saveDir, Illuminate\Http\File|Illuminate\Http\UploadedFile) #自动生成文件名
* ->putFileAs($saveDir, Illuminate\Http\File|Illuminate\Http\UploadedFile,$saveName) #指定文件存储名
# 上传文件处理,返回完整文件名路径
* Illuminate\Http\UploadedFile $request->file($name)->store($saveDir [, 文件系统连接]) #自动生成文件名
* Illuminate\Http\UploadedFile $request->file($name)->storeAs($saveDir, $saveName [, 文件系统连接]) #指定文件存储名
# 目录
->files|directories($dir) #不含子目录
->allFiles|allDirectories($dir) #包含子目录
->makeDirectory|deleteDirectory($dir) #目录增删
增加文件系统驱动
1. composer 安装驱动包
2. 新建ServiceProvidor,boot方法中拓展文件系统驱动
public function boot()
{
Storage::extend($fileDriverName, function ($app, $config) {
$client = new XxxClient();
return new Filesystem(new XxxAdapter($client));
});
}、
3. 基于新驱动配置新文件系统连接
国内云存储驱动
composer require yangyifan/upload:v0.2.1
php artisan cache:clear
(注意把redis
缓存库 和 队列、session
库分离开)php artisan config:cache
php artisan route:cache
classmap
生成php artisan optimize --force
composer dumpautoload --optimize
Redis
存储Session
OpCache
Original url: Access
Created at: 2018-10-10 17:19:40
Category: default
Tags: none
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
最新评论