安装:
composer create-project --prefer-dist laravel/laravel blog
入口文件:
public/index.php
缓存目录写入权限:
storage, /bootstrap/cache
环境配置:
.evn文件
获取配置值:
evn()
evn('APP_DEBUG',false),后面为默认值
访问配置值:
config()
config('app.timezone'); //获取配置值
config(['app.timezone'=>'Asia/Shanghai']); //设置配置值
缓存配置文件:
缓存后存放在/bootstrap/cache文件夹中,提高访问速度,但是evn函数将失效。所以一般线上部署才使用
php artisan config:cache
取消config:clear
维护模式:
php artisan down --message="Upgrading Database" --retry=60
php artisan up
查看可用make命令:
php artisan list make
核心概念:
服务容器
服务提供者
门面
契约
路由(Route)
Route::get('hello', function () {
return 'Hello, Welcome to LaravelAcademy.org';
});
可用的请求方法有:
get/post/put/patch/delete/options
match
any
Route::match(['get', 'post'], 'foo', function () {
return 'This is a request from get or post';
});
Route::any('bar', function () {
return 'This is a request from any HTTP verb';
});
重定向
Route::redirect('/here', '/there', 301);
视图
Route::view($uri, $view, $params);
例:
Route::view('/welcome', 'welcome', ['name' => '学院君']);
路由参数
必选参数
Route::get('posts/{post}/comments/{comment}', function ($postId, $commentId) {
return $postId . '-' . $commentId;
});
路由参数被注入到路由回调/控制器取决于它们的顺序,与回调/控制器名称无关
可选参数
Route::get('user/{name?}', function ($name = 'John') {
return $name;
});
参数约束
Route::get('user/{id}/{name}', function ($id, $name) {
// 同时指定 id 和 name 的数据格式
})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);
全局约束
如果想要路由参数在全局范围内被给定正则表达式约束,可以使用 pattern 方法。需要在 RouteServiceProvider 类的 boot 方法中定义这种约束模式:
public function boot()
{
Route::pattern('id', '[0-9]+');
parent::boot();
}
命名路由
name方法命名,route方法使用
命名路由为生成 URL 或重定向提供了方便,实现起来也很简单,在路由定义之后使用 name 方法链的方式来定义该路由的名称:
Route::get('user/profile', function () {
// 通过路由名称生成 URL
return 'my url: ' . route('profile');
})->name('profile');
Route::get('redirect', function() {
// 通过路由名称进行重定向
return redirect()->route('profile');
});
//带参数的url
Route::get('user/{id}/profile', function ($id) {
$url = route('profile', ['id' => 1]);
return $url;
})->name('profile');
//检查当前路由
if ($request->route()->named('profile')) {
//
}
路由分组
//给分组中的所有路由使用中间件
Route::middleware(['first', 'second'])->group(function () {
Route::get('/', function () {
// Uses first & second Middleware
});
Route::get('user/profile', function () {
// Uses first & second Middleware
});
});
或者
Route::prefix('apply-for')
->middleware('auth:api')
->group(base_path('routes/api/apply-for.php')); //分组的路由单独写成一个文件引入,这样就可以避免闭包让路由支持缓存
//给分组中的所有路由分配同一个命名空间
Route::namespace('Admin')->group(function () {
// Controllers Within The "App\Http\Controllers\Admin" Namespace
});
//给分组中的所有路由添加前缀
Route::prefix('admin')->group(function () {
Route::get('users', function () {
// Matches The "/admin/users" URL
});
});
路由模型绑定
隐式绑定
用ID将整个user模型载入。变量声明为user模型
用哪个字段做KEY可以在模型中用getRouteKeyName方法定义
Route::get('users/{user}', function (App\User $user) {
return $user->email;
});
显式绑定
为给定参数指定绑定类
在 RouteServiceProvider 类的 boot 方法中定义显式模型绑定
public function boot()
{
parent::boot();
Route::model('user_model', App\User::class);
}
在routes/web.php中定义路由
$router->get('profile/{user_model}', function(App\User $user) {
dd($user);
});
自定义解析逻辑
public function boot()
{
parent::boot();
Route::bind('user', function($value) {
return App\User::where('name', $value)->first() ?? abort(404);
});
}
频率限制:throttle
// 获取当前路由实例
$route = Route::current();
// 获取当前路由名称
$name = Route::currentRouteName();
// 获取当前路由action属性
$action = Route::currentRouteAction();
中间件(middleware)
作用:过滤进入应用的 HTTP 请求
新建一个中间件:php artisan make:middleware CheckToken
请求之前/请求之后执行
class BeforeMiddleware
{
public function handle($request, Closure $next)
{
// 执行动作
return $next($request);
}
}
class AfterMiddleware
{
public function handle($request, Closure $next)
{
$response = $next($request);
// 执行动作
return $response;
}
}
中间件分三类,分别是全局中间件、中间件组和指定路由中间件:
全局中间件
定义的中间件在每一个 HTTP 请求时都被执行,只需要将相应的中间件类添加到 app/Http/Kernel.php 的数组属性 $middleware 中
指定路由中间件
首先应该在 app/Http/Kernel.php 文件中的数组属性$routeMiddleware 分配给该中间件一个 key,这个key用在路由中
//分配
protected $routeMiddleware = [
...
'token' => CheckToken::class
];
//使用
Route::get('/', function () {
//
})->middleware('token');
中间件组
系统默认有api和web两个组在$middlewareGroups属性中
Route::get('/', function () {
//
})->middleware('web');
中间件参数
额外的中间件参数会在 $next 参数之后传入中间件
public function handle($request, Closure $next, $role)
{
if (! $request->user()->hasRole($role)) {
// Redirect...
}
return $next($request);
}
中间件参数可以在定义路由时通过 : 分隔中间件名和参数名来指定,多个中间件参数可以通过逗号分隔:
Route::put('post/{id}', function ($id) {
//
})->middleware('role:editor');
终端中间件
终端中间件,可以理解为一个善后的后台处理中间件。有时候中间件可能需要在 HTTP 响应发送到浏览器之后做一些工作
需要定义一个终止中间件并添加 terminate 方法到这个中间件,同时添加到kernel.php文件的全局中间件中
class StartSession
{
public function handle($request, Closure $next)
{
return $next($request);
}
//接收请求和响应作为参数
public function terminate($request, $response)
{
// 存储session数据...
}
}
控制器
控制器用于将相关的 HTTP 请求封装到一个类中进行处理
php artisan make:controller UserController
指定控制器路由
Route::get('user/{id}', 'UserController@show');
命名空间
默认在RouteServiceProvider有指定namespace
App\Http\Controllers\Photos\AdminController,则可以像这样注册路由:
Route::get('foo', 'Photos\AdminController@method');
控制器中间件
路由中分配
Route::get('profile', 'UserController@show')->middleware('auth');
构造函数中指定
public function __construct()
{
$this->middleware('token');
}
$this->middleware('auth')->only(['show', 'index']); // 只对指定方法生效
$this->middleware('auth')->except(['show', 'index']); // 对指定方法以外的方法生效
资源控制器
类似yii2的gii生成crud
生成一个操作资源的控制器,包含了index,create,store,show,edit,update,destory几个方法(具体功能要自己实现)
php artisan make:controller UserController --resource
注册路由,就可以通过/posts/action来访问控制器里的方法了
Route::resource('posts', 'PostController');
Route::resource('post', 'PostController', ['only' =>
['index', 'show']
]);
Route::resource('post', 'PostController', ['except' =>
['create', 'store', 'update', 'destroy']
]);
本地化url
在 AppServiceProvider 的 boot 方法中实现
public function boot()
{
Route::resourceVerbs([
'create' => 'xinzeng',
'edit' => 'bianji',
]);
}
路由缓存
只有控制器的路由可以缓存,闭包的路由不会缓存
php artisan route:cache
php artisan route:clear
HTTP请求
在控制器中获取当前 HTTP 请求实例,需要在构造函数或方法中对 Illuminate\Http\Request 类进行依赖注入
protected $request;
public function __construct(Request $request)
{
$this->request = $request;
}
或
public function store(Request $request)
{
$name = $request->input('name');
}
如果还期望在控制器方法中获取路由参数,只需要将路由参数置于其它依赖之后即可,例如,如果你的路由定义如下:
Route::put('user/{id}','UserController@update');
你仍然可以对 Illuminate\Http\Request 进行依赖注入并通过如下方式定义控制器方法来访问路由参数 id:
public function update(Request $request, $id)
{
//
}
request常用方法
$request->path() //请求路径
$request->is('/user/*') //正则匹配判断
$request->url() //完整路径,不包含参数
$request->fullUrl() //完整路径,包含参数
$request->method() //请求方法
自带的TrimStrings和ConvertEmptyStringsToNull两个中间件,会处理传入的参数,进行trim和空转null操作
获取请求输入
$request->all();
$request->input();
$request->input('name','default');
$request->input('products.0.name'); //数组形式的参数获取
$request->query(); //只获取url查询字符串中的参数
$request->query('name','default');
$name = $request->name; //通过动态属性获取输入
$request->only(['name','email']) //获取部分数据
$request->except(['password']) //获取部分数据
$request->has(['password']) //判断参数是否存在
$request->filled(['password']) //判断参数是否存在且不为空
//获取上一次请求输入
$request->flash();
$request->flashOnly('username', 'email');
$request->flashExcept('password');
//获取输入并重定向
return redirect('form')->withInput();
//获取旧输入
$username = $request->old('username');
//模板中也可以使用
<input type="text" name="username" value="{{ old('username') }}">
//获取cookie
$request->cookie('name');
Cookie::get('name');
添加cookie到响应
- 直接添加到response
return response('欢迎来到 Laravel 学院')->cookie(
'name', '学院君', $minutes, $path, $domain, $secure, $httpOnly
);
- 使用 Cookie 门面将应用于附件的 Cookie 推送到输出响应队列。queue 方法接收一个 Cookie 实例或者创建一个 Cookie 实例的必要参数。这些 Cookie 会在响应发送到浏览器之前添加上
Cookie::queue(Cookie::make('name', 'value', $minutes));
Cookie::queue('name', 'value', $minutes);
生成 Cookie 实例的全局辅助函数
$cookie = cookie('name', '学院君', $minutes);
return response('欢迎来到 Laravel 学院')->cookie($cookie);
文件上传
$file = $request->file('photo');
$file = $request->photo;
返回Illuminate\Http\UploadedFile类的一个实例(文档:http://api.symfony.com/4.0/Symfony/Component/HttpFoundation/File/UploadedFile.html)
$request->hasFile('photo'); //判断是否存在
基本的保存图片用uploadedFile的store或storeAs方法
$file->store('images','public');
第一个参数为path,第二个参数对应config/filesystems.php中的disks,默认为local
如果参数为public,则对应的存储路径为storage/public,该目录可以通过php artisan storage:link 命令生成一个外链,这样就可以外部访问了。
HTTP响应
直接return的字符串也会处理为一个完整的http响应
return数组会转化为一个json响应
response对象
return response($content);
添加响应头
->header('Content-Type', $type)
或
->withHeaders([
'X-Header-One' => 'Header Value',
'X-Header-Two' => 'Header Value',
]);
添加cookies
->cookie($name, $value, $minutes, $path, $domain, $secure, $httpOnly)
或者用门面的queue方法
Cookie::queue('author', '学院君', 1);
cookie加密
App\Http\Middleware\EncryptCookies
可以添加例外或直接注释掉
重定向
全局辅助函数 redirect
return redirect('home/dashboard');
返回到前一个url
return back()->withInput();
重定向到命名路由
return redirect()->route('login');
重定向到控制器动作
return redirect()->action('HomeController@index');
重定向到外部域名
return redirect()->away('http://laravelacademy.org');
带一次性 Session 数据的重定向(类似yii的setflash + redirect)
return redirect('dashboard')->with('status', 'Profile updated!');
视图(view)响应
return view('hello');
json响应
return response()->json([
'name' => 'Abigail',
'state' => 'CA'
]);
jsonp响应
return response()
->json(['name' => 'Abigail', 'state' => 'CA'])
->withCallback($request->input('callback'));
或者直接使用 jsonp 方法:
return response()
->jsonp($request->input('callback'), ['name' => 'Abigail', 'state' => 'CA']);
文件下载响应
return response()->download($pathToFile);
return response()->download($pathToFile, $name, $headers);
return response()->download($pathToFile)->deleteFileAfterSend(true);
文件响应
在浏览器中展示文件而不下载
return response()->file($pathToFile);
return response()->file($pathToFile, $headers);
流式下载
streamDownload
响应宏
在serviceProvider的boot方法中定义
public function boot()
{
Response::macro('caps', function ($value) {
return Response::make(strtoupper($value));
});
}
使用:用上面定义的caps方法来响应
Route::get('macro/response', function() {
return response()->caps('LaravelAcademy');
});
Blade模板引擎
用.blade.php文件扩展存放在resources/views文件夹下
http://laravelacademy.org/post/8773.html
SESSION
-
自成一套,用$_SESSION获取不到
-
在控制器的构造函数中无法获取到session,因为session是通过中间件启动的,解决办法是获取session逻辑后置或者在构造函数中引入在startSession之后执行的中间件
配置
config/session.php
使用redis存储session:
composer安装predis/predis包
配置文件修改
在 config/database.php 中为 Redis 配置了一个 Session 连接
config/session.php 中配置 Session 驱动为 redis,对应的 connection 项指向 database 中的 redis.session 配置
获取session
- 全局辅助函数session
$value = session('key', 'default');
- request实例
$value = $request->session()->get('key');
存储session数据
- 全局辅助函数session
session(['key' => 'value']);
- request实例
$request->session()->put('key', 'value');
删除session数据
$request->session()->forget('key');
$request->session()->flush(); //删除所有数据
获取&删除session数据
$value = $request->session()->pull('key', 'default');
一次性数据
通过 flash 方法来实现。使用该方法存储的 Session 数据只在随后的 HTTP 请求中有效,然后将会被删除
$request->session()->flash('status', '登录Laravel学院成功!');
如果你需要在更多请求中保持该一次性数据,可以使用 reflash 方法,该方法将所有一次性数据保留到下一个请求,如果你只是想要保存特定一次性数据,可以使用 keep 方法:
$request->session()->reflash();
$request->session()->keep(['username', 'email']);
表单验证
注意可选字段最好加上nullable规则,因为自带了trimStrings和ConvertEmptyStringsToNull中间件。
1\ 使用request对象的validate方法,只要传入验证规则,会自动处理。验证通过代码继续执行,不通过会抛异常。web请求会重定向,ajax请求会返回一个json响应
public function store(Request $request){
$validatedData = $request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
// 验证通过,存储到数据库...
}
- php artisan make:request StoreBlogPost命令创建表单请求
生成的类位于 app/Http/Requests 目录下
规则添加到rules方法中
还有一个authorize方法,可以控制请求权限。不想限制直接return true
该类继承自request基类,所以可以使用request对象的任意方法,比如可以用$request->user()获取用户信息。
在控制器方法中注入该请求
public function store(StoreBlogPost $request) {}
- 手动创建验证器
通过Validator门面创建
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
if ($validator->fails()) {
return redirect('post/create')
->withErrors($validator)
->withInput();
}
// 存储博客文章...
}
自定义错误消息
public function messages(){
return [
'same' => 'The :attribute and :other must match.'
'title.required' => 'A title is required',
'body.required' => 'A message is required',
];
}
语言文件中指定:attribute替换(多语言) resources/lang/xx/validation.php
'attributes' => [
'email' => '邮箱地址',
],
字段存在时才验证:添加sometimes规则
复杂条件验证
$v = Validator::make($data, [
'email' => 'required|email',
'games' => 'required|numeric',
]);
传递给 sometimes 方法的第一个参数是我们需要有条件验证的名称字段,第二个参数是我们想要添加的规则,如果作为第三个参数的闭包返回 true,规则被添加。该方法让构建复杂条件验证变得简单,你甚至可以一次为多个字段添加条件验证:
$v->sometimes(['reason', 'cost'], 'required', function($input) {
return $input->games >= 100;
});
验证规则大全
http://laravelacademy.org/post/8798.html#toc_17
Accepted
Active URL
After (Date)
After Or Equal(Date)
Alpha
Alpha Dash
Alpha Numeric
Array
Before (Date)
Before Or Equal(Date)
Between
Boolean
Confirmed
Date
Date Equals
Date Format
Different
Digits
Digits Between
Dimensions(图片文件)
Distinct
Exists (Database)
File
Filled
Image (File)
In
In Array
Integer
IP Address
JSON
Max
MIME Types (File)
MIME Type By File Extension
Min
Nullable
Not In
Numeric
Present
Regular Expression
Required
Required If
Required Unless
Required With
Required With All
Required Without
Required Without All
Same
Size
String
Timezone
Unique (Database)
URL
自定义验证规则
- php artisan make:rule TestRule
在passes方法中写规则,返回布尔值,在message方法中写错误提示
'name' => ['required', new TestRule],
- 闭包函数
'title' => [
'required',
'max:255',
function($attribute, $value, $fail) {
if ($value === 'foo') {
return $fail($attribute.' is invalid.');
}
},
],
错误处理
App\Exceptions\Handler
abort辅助函数,相当于throw Exception
Log日志
config/logging.php
Log门面
Log::emergency($error);
Log::alert($error);
Log::critical($error);
Log::error($error);
Log::warning($error);
Log::notice($error);
Log::info($error);
Log::debug($error);
多语言
config/app.php的locale选项配置默认语言
App::setLocale($locale); //通过App门面动态设置
你还可以配置一个“备用语言”,当当前语言不包含给定语言行时备用语言被返回。和默认语言一样,备用语言也在配置文件 config/app.php 中配置:
'fallback_locale' => 'en',
$locale = App::getLocale(); //获取
App::isLocale('en'); //判断
resource/lang文件夹存放语言翻译文件
获取翻译字符串
echo __('messages.welcome')
数据库操作
数据库相关配置文件:
.env
config/database.php
migrate迁移
新建一个migrate文件:
php artisan make:migration create_users_table
默认在/databse/migrations目录下,用--path=参数可以指定路径
中间users是默认的表名,可以用--table=table_name或者--create=table_name来指定表明或者是否要新建一个表
运行迁移
php artisan migrate
回滚
php artisan migrate:rollback --step=5 //回滚最近的5个迁移
php artisan migrate:reset //回滚所有迁移
migrate:refresh //先回滚后执行,相当于重建
各种方法参照:
http://laravelacademy.org/post/8845.html
DB门面
运行原生SQL
DB::select("select * from user where id = :id",['id'=>1]);
同理还有以下操作
DB::insert($sql);
DB::update($sql);
DB::delete($sql);
DB::statement($sql); //通用操作,比如drop等
事务
闭包方法
DB::transaction(function () {
DB::table('users')->update(['votes' => 1]);
DB::table('posts')->delete();
},5); //此处的参数5为死锁发生时事务的最大重试次数,可选
手动方法
DB::beginTransaction();
DB::rollBack();
DB::commit();
查询构建器
DB::table('table_name')
获取结果集
->get() 获取表中所有记录
->first() 获取一行记录
->value('name') 获取一行中的某个记录
->pluck('title','name') 获取单列记录,后面的参数为前者指定的键名,必须是数据库中的另外一个字段
->chunk(100,function($data){
}) 闭包函数获取组块的结果集
例:
DB::table('users')->orderBy('id')->chunk(100, function($users) { //一次取出100条数据进行处理
foreach ($users as $user) {
//
}
return false; //满足条件终止运行
});
->count()
->max()
->min()
->avg()
->sum()
->exists()
->doesntExists()
查询(select)
->select('name','email as user_email') 自定义想要获取的字段
->addSelect('nickname') 已有select可以添加更多的字段
->distinct() 去重
原生表达式
DB::raw()
$users = DB::table('users')->select(DB::raw('count(*) as user_count, status'))->get();
表连接
->join(表名,条件) //inner join
->leftJoin(表名,条件)
例:DB::table('users')->join('contacts', 'users.id', '=', 'contacts.user_id')->select('users.*', 'contacts.phone')->all();
更高级的连接条件,在闭包中添加连接条件
DB::table('users')
->join('contacts', function ($join) {
$join->on('users.id', '=', 'contacts.user_id')
->where('contacts.user_id', '>', 5);
})->get();
where子句
->where('votes', '=', 100) //中间操作符可以是>,<,>=,<=,like,<>等,是=的时候可以省略
->where([ //多个条件
['status', '=', '1'],
['subscribed', '<>', '1'],
])
orWhere() or语句
>whereBetween('votes', [1, 100]) //还有whereNotBetween
->whereIn('id', [1, 2, 3]) //还有whereNotIn
->whereNull('updated_at') //判断是否是null值,还有whereNotNull
whereDate / whereMonth / whereDay / whereYear / whereTime //比较时间
migrate里面的timestamps方法在mysql中的字段类型是timestamp
->whereDate('created_at', '2016-10-10')
->whereColumn('first_name','>','last_name') //比较两个字段
->whereExists(function ($query) { //where exists 子句
$query->select(DB::raw(1))
->from('orders')
->whereRaw('orders.user_id = users.id');
})
->orderBy('name', 'desc')
->latest() / ->oldest() //根据created_at字段排序
->inRandomOrder() //随机排序
->groupBy() / ->having()
->offset(0) / ->skip(0) //等价
->limit(5) / ->take(5) //等价
条件子句(相当于yii的filterWhere())
$role = $request->input('role');
$users = DB::table('users')
->when($role, function ($query) use ($role) { //当$role为true的时候才会执行
return $query->where('role_id', $role);
})
->get();
你可以传递另一个闭包作为 when 方法的第三个参数,该闭包会在第一个参数为 false 的情况下执行
$sortBy = null;
$users = DB::table('users')
->when($sortBy, function ($query) use ($sortBy) {
return $query->orderBy($sortBy);
}, function ($query) {
return $query->orderBy('name');
})
->get();
插入
DB::table('users')->insert([
['email' => 'taylor@example.com', 'votes' => 0],
['email' => 'dayle@example.com', 'votes' => 0]
]);
insertGetId:如果有自增ID则返回插入记录的自增ID值
更新
DB::table('users')
->where('id', 1)
->update(['votes' => 1]);
递增/递减
->increment('votes'); //+1
->decrement('votes', 5); //-5
->increment('votes', 1, ['name' => 'John']); //指定额外的字段更新
删除
->delete();
->truncate(); //清空记录
悲观锁使用
Laravel 查询构建器提供了一些方法帮助你在 select 语句中实现“悲观锁”。可以在查询中使用 sharedLock 方法从而在运行语句时带一把”共享锁“。共享锁可以避免被选择的行被修改直到事务提交:
DB::table('users')->where('votes', '>', 100)->sharedLock()->get();
上面这个查询等价于下面这条 SQL 语句:
select * from `users` where `votes` > '100' lock in share mode
此外你还可以使用 lockForUpdate 方法。“for update”锁避免选择行被其它共享锁修改或删除:
DB::table('users')->where('votes', '>', 100)->lockForUpdate()->get();
上面这个查询等价于下面这条 SQL 语句:
select * from `users` where `votes` > '100' for update
for update 与 lock in share mode 都是用于确保被选中的记录值不能被其它事务更新(上锁),两者的区别在于 lock in share mode 不会阻塞其它事务读取被锁定行记录的值,而 for update 会阻塞其他锁定性读对锁定行的读取(非锁定性读仍然可以读取这些记录,lock in share mode 和 for update 都是锁定性读)。
这么说比较抽象,我们举个计数器的例子:在一条语句中读取一个值,然后在另一条语句中更新这个值。使用 lock in share mode 的话可以允许两个事务读取相同的初始化值,所以执行两个事务之后最终计数器的值+1;而如果使用 for update 的话,会锁定第二个事务对记录值的读取直到第一个事务执行完成,这样计数器的最终结果就是+2了。
ORM模型
php artisan make:model User
指定表名
protected $table = 'my_flights';
指定数据库连接名
protected $connection = 'connection-name';
主键
Eloquent 默认每张表的主键名为 id,你可以在模型类中定义一个 $primaryKey 属性来覆盖该约定。
此外,Eloquent 默认主键字段是自增的整型数据,这意味着主键将会被自动转化为 int 类型,如果你想要使用非自增或非数字类型主键,必须在对应模型中设置 keyType 属性值为 string。
时间戳填充
默认自动填充created_at和updated_at
不想使用可以设置
public $timestamps = false;
自定义时间戳字段名称
const CREATED_AT = 'creation_date';
const UPDATED_AT = 'last_update';
自定义格式
protected $dateFormat = 'U';
save()保存模型数据
App\Flight::where('active', 1)
->where('destination', 'San Diego')
->update(['delayed' => 1]); //批量更新
批量赋值
需要设置guarded属性,设置允许/禁止通过批量赋值写入的字段名称
$flight = App\Flight::create(['name' => 'Flight 10','price'=>100]); //create方法会载入参数并保存到数据库
firstOrCreate/firstOrNew/updateOrCreate //先查找数据库中有没有对应记录,然后进行create或new或update操作。new只返回对象,不会写入数据库
delete() 删除模型
通过主键删除模型
App\Flight::destroy([1, 2, 3]);
软删除
数据表中加入deleted_at字段
class Flight extends Model
{
use SoftDeletes;
protected $dates = ['deleted_at'];
}
此时调用delete()方法会进行软删除。可以用trashed()方法判断实例是否被软删除
查询时软删除的模型会被自动排除,可以加上withTrashed()方法来包含结果
onlyTrashed() 只获取软删除的模型
restore() 恢复软删除的模型
->forceDelete() 强制永久删除
全局作用域
在模型的boot方法中使用addGlobalScope方法添加
protected static function boot()
{
parent::boot();
static::addGlobalScope('age', function(Builder $builder) {
$builder->where('age', '>', 200);
});
}
这样这个查询条件会附加到每个查询中。想要不使用,则在查询时使用withoutGlobalScope('age')
推荐闭包实现,还有一种另定义方法实现,可以参考文档
局部作用域
在模型中定义以scope开头的方法
public function scopePopular($query)
{
return $query->where('votes', '>', 100);
}
使用时加上->popular()即可,可以多个同时使用。
动态作用域
接收传参的scope方法
public function scopeOfType($query, $type)
{
return $query->where('type', $type);
}
使用时传入参数->ofType('admin')
事件
retrieved, creating, created, updating, updated, saving, saved, deleting, deleted, restoring, restored
映射模型生命周期中多个时间点与对应事件类
protected $dispatchesEvents = [
'saved' => UserSaved::class,
'deleted' => UserDeleted::class,
];
观察者
- 新建一个观察者类
<?php
namespace App\Observers;
use App\User;
class UserObserver
{
/**
* 监听用户创建事件.
*
* @param User $user
* @return void
*/
public function created(User $user)
{
//
}
/**
* 监听用户删除事件.
*
* @param User $user
* @return void
*/
public function deleting(User $user)
{
//
}
}
- 在 AppServiceProvider 中注册观察者
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
User::observe(UserObserver::class);
}
}
关联关系
一对一
public function phone()
{
return $this->hasOne('App\Phone', 'user_id', 'id');
}
编译前端资源
步骤:
-
安装node.js
-
npm install 安装前端依赖。依赖声明在packages.json文件中,安装完成后会生成一个lock文件。windows环境加上参数--no-bin-links
-
npm run dev 将自带的默认webpack.mix.js文件中引入的scss,js等文件进行编译。
laravel mix工具(基于webpack开发)
webpack.mix.js文件包含需要编译的文件
mix.sass('resources/assets/sass/app.scss', 'public/css'); //编译scss文件
mix.styles([ //编译原生CSS文件
'public/css/vendor/normalize.css',
'public/css/vendor/videojs.css'
], 'public/css/all.css');
mix.js('resources/assets/js/app.js', 'public/js'); //编译js文件,.vue文件
mix.copy('node_modules/foo/bar.css', 'public/css/bar.css'); //拷贝文件
css文件中的url处理:默认会把图片拷贝到public/images目录下,然后修改css文件中对应的url指向。想要禁用该功能:
mix.sass('resources/assets/app/app.scss', 'public/css')
.options({
processCssUrls: false
});
版本号/刷新缓存
mix.js('resources/assets/js/app.js', 'public/js')
.version(); //附带唯一哈希到文件名,方便缓存刷新。
视图中用laravel的全局函数mix来加载
<link rel="stylesheet" href="{{ mix('css/app.css') }}">
网友评论