一、安装
1:安装php
PHP >= 7.1.3
PHP Extension
OpenSSL 、PDO、Mbstring、Tokenizer 、XML 、Ctype 、JSON 、BCMath
2:安装composer
中文网链接
3:加载安装项目、初始化框架
//https://packagist.org/packages/laravel/installer
composer global require laravel/installer
laravel new blog
4:简单指令
php artisan serve 启动服务
php artisan list 查看指令列表
二、目录结构
app 项目主要业务逻辑
bootstrap 引导
config 配置文件
database
public 入口文件目录
resources 前端资源包括视图
routes 路由
storage 项目临时文件存储目录
tests 单元测试
vendor composer安装依赖目录
三、配置文件
1:.env文件,不要纳入版本控制,不同环境采用不同配置
2:程序获取、设置配置文件
$value = config('app.timezone');
config(['app.timezone' => 'America/Chicago']);
3:设置、清理配置缓存
php artisan config:cache
php artisan config:clear
4:维护模式
php artisan down
php artisan down --message="Upgrading Database" --retry=60
php artisan down --allow=127.0.0.1 --allow=192.168.0.0/16
php artisan up
维护模式模板:resources/views/errors/503.blade.php
四、上线优化
1:自动加载优化
composer install --optimize-autoloader --no-dev
2:配置文件缓存
php artisan config:cache
3:路由规则缓存
php artisan route:cache
五、路由规则
1:简单返回
Route::get('foo', function () {
return 'Hello World';
});
2:调用具体Controller Action
Route::get('/user', 'UserController@index');
3:HTTP六种请求方式
Route::get($uri, $callback);
Route::post($uri, $callback);
Route::put($uri, $callback);
Route::patch($uri, $callback);
Route::delete($uri, $callback);
Route::options($uri, $callback);
4:同时支持 get和post
Route::match(['get', 'post'], '/', function () {
//
});
5:支持任一一种方式
Route::any('foo', function () {
//
});
6:跳转
默认302跳转
Route::redirect('/here', '/there');
指定跳转状态码
Route::redirect('/here', '/there', 301);
7:调用模板
Route::view('/welcome', 'welcome');
Route::view('/welcome', 'welcome', ['name' => 'Taylor']);
8:路由参数
参数由{}包围,不能有-中划线,中划线用_下划线代替
Route::get('user/{id}', function ($id) {
return 'User '.$id;
});
可选参数
Route::get('user/{name?}', function ($name = null) {
return $name;
});
正则校验
Route::get('user/{name}', function ($name) {
//
})->where('name', '[A-Za-z]+');
Route::get('user/{id}', function ($id) {
//
})->where('id', '[0-9]+');
Route::get('user/{id}/{name}', function ($id, $name) {
//
})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);
匹配任一字符 包括斜杠
Route::get('search/{search}', function ($search) {
return $search;
})->where('search', '.*');
全局校验
/app/Providers/RouteServiceProvider.php
9:路由命名
Route::get('user/profile', 'UserProfileController@show')->name('profile');
$url = route('profile');
简单跳转
return redirect()->route('profile');
判断当前路由名称
if ($request->route()->named('profile')) {
//
}
10:路由分组
1:中间件
Route::middleware(['first', 'second'])->group(function () {
Route::get('/', function () {
// Uses first & second Middleware
});
Route::get('user/profile', function () {
// Uses first & second Middleware
});
});
2:命名空间
Route::namespace('Admin')->group(function () {
// Controllers Within The "App\Http\Controllers\Admin" Namespace
});
3:子域名
Route::domain('{account}.myapp.com')->group(function () {
Route::get('user/{id}', function ($account, $id) {
//
});
});
11:路由前缀
Route::prefix('admin')->group(function () {
Route::get('users', function () {
// Matches The "/admin/users" URL
});
});
12:路由命名前缀
Route::name('admin.')->group(function () {
Route::get('users', function () {
// Route assigned name "admin.users"...
})->name('users');
});
13:路由和model绑定
隐式绑定
Route::get('api/users/{user}', function (App\User $user) {
return $user->email;
});
如果不是主键ID,model文件方法
public function getRouteKeyName()
{
return 'slug';
}
显式绑定
RouteServiceProvider
public function boot()
{
parent::boot();
Route::model('user', App\User::class);
}
Route::get('profile/{user}', function (App\User $user) {
//
});
14:无法匹配
Route::fallback(function () {
//
});
15:限制访问频率
每分钟允许访问60次
Route::middleware('auth:api', 'throttle:60,1')->group(function () {
Route::get('/user', function () {
//
});
});
动态设置限制
Route::middleware('auth:api', 'throttle:rate_limit,1')->group(function () {
Route::get('/user', function () {
//
});
});
16:获取Route信息
$route = Route::current();
$name = Route::currentRouteName();
$action = Route::currentRouteAction();
六、控制器
1:唯一Action
public function __invoke($id)
{
return view('user.profile', ['user' => User::findOrFail($id)]);
}
对应路由规则
Route::get('user/{id}', 'ShowProfile');
创建指令
php artisan make:controller ShowProfile --invokable
2:中间件
class UserController extends Controller
{
/**
* Instantiate a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
$this->middleware('log')->only('index');
$this->middleware('subscribed')->except('store');
}
}
3:资源型Controller
php artisan make:controller /Test/PhotoController --resource
配合route
Route::resource('photos', 'PhotoController');
一次添加多个
Route::resources([
'photos' => 'PhotoController',
'posts' => 'PostController'
]);
所有Action
Verb URI Action Route Name
GET /photos index photos.index
GET /photos/create create photos.create
POST /photos store photos.store
GET /photos/{photo} show photos.show
GET /photos/{photo}/edit edit photos.edit
PUT/PATCH /photos/{photo} update photos.update
DELETE /photos/{photo} destroy photos.destroy
开放部分请求方式
Route::resource('photos', 'PhotoController')->only([
'index', 'show'
]);
Route::resource('photos', 'PhotoController')->except([
'create', 'store', 'update', 'destroy'
]);
api型
Route::apiResource('photos', 'PhotoController');
php artisan make:controller API/PhotoController --api
依赖注入
构造函数注入
public function __construct(UserRepository $users)
{
$this->users = $users;
}
方法注入
public function store(Request $request)
{
$name = $request->name;
//
}
请求处理
默认参数经过 App\Http\Kernel 加载的中间件处理,过滤了前后空格和将空数据转为null
接收参数
$name = $request->input('name');
获取路径 不含域名部分
$uri = $request->path();
获取url,不含参数部分
$url = $request->url();
$url = $request->fullUrl();
判断url
if ($request->is('admin/*')) {
//
}
//获取请求方法
$method = $request->method();
if ($request->isMethod('post')) {
//
}
//获取全部请求数据
$input = $request->all();
$input = $request->input();
赋予默认参数
$name = $request->input('name', 'Sally');
数组型参数
$name = $request->input('products.0.name');
$names = $request->input('products.*.name');
get请求
$name = $request->query('name');
$name = $request->query('name', 'Helen');
$query = $request->query();
通过获取属性,获取请求参数
$name = $request->name;
获取json格式请求参数
$name = $request->input('user.name');
参数例外
$input = $request->only(['username', 'password']);
$input = $request->only('username', 'password');
$input = $request->except(['credit_card']);
$input = $request->except('credit_card');
判断请求参数是否存在
if ($request->has('name')) {
//
}
接收非空请求参数,参数必须要有值
if ($request->filled('name')) {
//
}
将请求参数写入session保留
$request->flash();
获取保留的旧参数
$username = $request->old('username');
模板中使用旧参数
<input type="text" name="username" value="{{ old('username') }}">
cookies相关
$value = $request->cookie('name');
$value = Cookie::get('name');
给返回添加cookie
return response('Hello World')->cookie(
'name', 'value', $minutes
);
文件
$file = $request->file('photo');
$file = $request->photo;
if ($request->hasFile('photo')) {
//
}
if ($request->file('photo')->isValid()) {
//
}
$path = $request->photo->path();
$extension = $request->photo->extension();
$path = $request->photo->store('images');
$path = $request->photo->store('images', 's3');
$path = $request->photo->storeAs('images', 'filename.jpg');
$path = $request->photo->storeAs('images', 'filename.jpg', 's3');
配置受信任的代理
当负载均衡服务器TLS / SSL证书过期,应用可能不会生成安全连接
使用中间件 App\Http\Middleware\TrustProxies
使用视图和传值
return view('admin.profile', $data);
return view('greeting')->with('name', 'Victoria');
七、视图
1:判断视图是否存在
if (View::exists('emails.customer')) {
//
}
2:使用第一个视图
return view()->first(['custom.admin', 'admin'], $data);
use Illuminate\Support\Facades\View;
return View::first(['custom.admin', 'admin'], $data);
3:数据共用
AppServiceProvider
public function boot()
{
View::share('key', 'value');
}
4:表单CSRF(跨站请求伪造)校验
<form method="POST" action="/profile">
@csrf
...
</form>
5:HTML的form表单不支持 PUT、PATCH、DELETE
<form action="/foo/bar" method="POST">
<input type="hidden" name="_method" value="PUT">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
</form>
<form action="/foo/bar" method="POST">
@method('PUT')
@csrf
</form>
6:布局
<!-- Stored in resources/views/layouts/app.blade.php -->
<html>
<head>
<title>App Name - @yield('title')</title>
</head>
<body>
@section('sidebar')
This is the master sidebar.
@show
<div class="container">
@yield('content')
</div>
</body>
</html>
<!-- Stored in resources/views/child.blade.php -->
@extends('layouts.app')
@section('title', 'Page Title')
@section('sidebar')
@parent
<p>This is appended to the master sidebar.</p>
@endsection
@section('content')
<p>This is my body content.</p>
@endsection
@endsection闭合标签,@show除了有@endsection的功能,还会立即生成内容
组件
弹窗
<!-- /resources/views/alert.blade.php -->
<div class="alert alert-danger">
{{ $slot }}
</div>
@component('alert')
<strong>Whoops!</strong> Something went wrong!
@endcomponent
带标题
<div class="alert alert-danger">
<div class="alert-title">{{ $title }}</div>
{{ $slot }}
</div>
@component('alert')
@slot('title')
Forbidden
@endslot
You are not allowed to access this resource!
@endcomponent
或者如下传递参数
@component('alert', ['foo' => 'bar'])
...
@endcomponent
关联组件路径,方便组件未在模板同目录下
use Illuminate\Support\Facades\Blade;
Blade::component('components.alert', 'alert');
@alert(['type' => 'danger'])
You are not allowed to access this resource!
@endalert
展示数据
Route::get('greeting', function () {
return view('welcome', ['name' => 'Samantha']);
});
Hello, {{ $name }}.
使用php函数
The current UNIX timestamp is {{ time() }}.
强制不转义数据,默认 htmlspecialchars转义
Hello, {!! $name !!}.
输出JSON
<script>
var app = <?php echo json_encode($array); ?>;
</script> 等同如下:
<script>
var app = @json($array);
</script>
流程控制
@if (count($records) === 1)
I have one record!
@elseif (count($records) > 1)
I have multiple records!
@else
I don't have any records!
@endif
@unless (Auth::check())
You are not signed in.
@endunless
@isset($records)
// $records is defined and is not null...
@endisset
@empty($records)
// $records is "empty"...
@endempty
判断组件是否有内容
@hasSection('navigation')
<div class="pull-right">
@yield('navigation')
</div>
<div class="clearfix"></div>
@endif
分支语法
@switch($i)
@case(1)
First case...
@break
@case(2)
Second case...
@break
@default
Default case...
@endswitch
循环
@for ($i = 0; $i < 10; $i++)
The current value is {{ $i }}
@endfor
@foreach ($users as $user)
<p>This is user {{ $user->id }}</p>
@endforeach
@forelse ($users as $user)
<li>{{ $user->name }}</li>
@empty
<p>No users</p>
@endforelse
@while (true)
<p>I'm looping forever.</p>
@endwhile
@foreach ($users as $user)
@if ($user->type == 1)
@continue
@endif
@continue($user->type == 1)
<li>{{ $user->name }}</li>
@if ($user->number == 5)
@break
@endif
@endforeach
@foreach ($users as $user)
@if ($loop->first)
This is the first iteration.
@endif
@if ($loop->last)
This is the last iteration.
@endif
@endforeach
循环嵌套,获取上一级循环数据
@foreach ($users as $user)
@foreach ($user->posts as $post)
@if ($loop->parent->first)
This is first iteration of the parent loop.
@endif
@endforeach
@endforeach
$loop->index The index of the current loop iteration (starts at 0).
$loop->iteration The current loop iteration (starts at 1).
$loop->remaining The iterations remaining in the loop.
$loop->count The total number of items in the array being iterated.
$loop->first Whether this is the first iteration through the loop.
$loop->last Whether this is the last iteration through the loop.
$loop->depth The nesting level of the current loop.
$loop->parent When in a nested loop, the parent's loop variable.
注释
{{-- This comment will not be present in the rendered HTML --}}
PHP代码
@php
//
@endphp
引入子页面
<div>
@include('shared.errors')
<form>
<!-- Form Contents -->
</form>
</div>
@include('view.name', ['some' => 'data'])
@includeIf('view.name', ['some' => 'data']) 不确定模板是否存在
@includeWhen($boolean, 'view.name', ['some' => 'data']) 根据判断是否加载
@includeFirst(['custom.admin', 'admin'], ['some' => 'data'])
八、模型
1:数据库配置
主从
'mysql' => [
'read' => [
'host' => ['192.168.1.1'],
],
'write' => [
'host' => ['196.168.1.2'],
],
'sticky' => true,
'driver' => 'mysql',
'database' => 'database',
'username' => 'root',
'password' => '',
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
],
2:执行sql
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
class UserController extends Controller
{
/**
* Show a list of all of the application's users.
*
* @return Response
*/
public function index()
{
$users = DB::select('select * from users where active = ?', [1]);
$results = DB::select('select * from users where id = :id', ['id' => 1]);
DB::insert('insert into users (id, name) values (?, ?)', [1, 'Dayle']);
$affected = DB::update('update users set votes = 100 where name = ?', ['John']);
$deleted = DB::delete('delete from users');
$deleted = DB::delete('delete from users');
return view('user.index', ['users' => $users]);
}
}
3:事物
DB::transaction(function () {
DB::table('users')->update(['votes' => 1]);
DB::table('posts')->delete();
});
处理死锁问题,五秒后抛异常
DB::transaction(function () {
DB::table('users')->update(['votes' => 1]);
DB::table('posts')->delete();
}, 5);
自定义事物流程
DB::beginTransaction();
DB::rollBack();
DB::commit();
4:查询
返回一条数据
$user = DB::table('users')->where('name', 'John')->first();
返回一条记录的某个字段
$email = DB::table('users')->where('name', 'John')->value('email');
返回指定列
$titles = DB::table('roles')->pluck('title');
foreach ($titles as $title) {
echo $title;
}
5:创建model文件指令
php artisan make:model Model/Test
php artisan make:model Model/Test -m(表结构创建脚本)
所在目录:/app/database/migrate
php artisan migrate(执行全部的表结构脚本)
php artisan migrate:reset 取消执行
基本方法:
use App\Model\Test AS Test;
//根据主键查询
$obj = Test::find(2);
$obj = Test::find([1, 2]);
//查询第一条
$obj = Test::first();
//查询所有
$all = Test::all();
//统计总数 count, sum, max, min
$num = Test::count();
$maxId = Test::max('id');
//条件查询
$resArrr = Test::where('state', '=', 1)
// '=', '<', '>', '<=', '>=', '<>', '!=', '<=>',
// 'like', 'like binary', 'not like', 'ilike',
// '&', '|', '^', '<<', '>>',
// 'rlike', 'regexp', 'not regexp',
// '~', '~*', '!~', '!~*', 'similar to',
// 'not similar to', 'not ilike', '~~*', '!~~*',
->orderBy('id', 'desc')
->skip(1)//offset
->take(2)//limit
->get();
//大批量数据处理 每次处理200条
Test::chunk(200, function ($all) {
foreach ($all as $item) {
//
}
});
//上千条sql合并为一个sql处理
foreach (Test::cursor() as $item) {
//
}
//新增
$model = new Test;
$model->name = 'test';
$model->state = 1;
$model->save();
$model = Test::create(['name' => 'create', 'state' => 1]);
// 加上对应的字段
protected $fillable = ['name', 'state'];
//修改
$model = Test::find(1);
$model->name = 'update';
$model->state = 1;
$model->save();
//多条修改
Test::where('state', 1)->update(['state' => 1]);
//删除
$obj = Test::find(1)->delete();
//软删除
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Flight extends Model
{
use SoftDeletes;
/**
* The attributes that should be mutated to dates.
*
* @var array
*/
protected $dates = ['deleted_at'];
}
Schema::table('flights', function (Blueprint $table) {
$table->softDeletes();
});
//判断是否已删除
if (Test::withTrashed()->find(1)->trashed()) {
//
}
//只获取软删除的数据
Test::onlyTrashed()->get()
//获取包含软删除的数据
Test::withTrashed()->get()
//恢复软删除数据
Test::onlyTrashed()->restore();
//结果集处理
转为数组
Test::all()->toArray();
常见支持方法:
all、get、first、last、toArray、search、max、min、avg、sum、toJson
详情:https://laravel.com/docs/5.7/eloquent-collections
九、返回
基本
Route::get('/', function () {
return 'Hello World';
});
数据会自动JSON
Route::get('/', function () {
return [1, 2, 3];
});
返回对象
Route::get('home', function () {
return response('Hello World', 200)
->header('Content-Type', 'text/plain');
});
return response($content)
->withHeaders([
'Content-Type' => $type,
'X-Header-One' => 'Header Value',
'X-Header-Two' => 'Header Value',
])
->cookie('name', 'value', $minutes);
重定向
Route::get('dashboard', function () {
return redirect('home/dashboard');
});
返回,附带请求参数
Route::post('user/profile', function () {
// Validate the request...
return back()->withInput();
});
重定向到login名称的路由
return redirect()->route('login');
return redirect()->route('profile', ['id' => 1]);
重定向到指定页面
return redirect()->action('HomeController@index');
return redirect()->action(
'UserController@profile', ['id' => 1]
);
return redirect()->away('https://www.google.com');
文件下载
return response()->download($pathToFile);
return response()->download($pathToFile, $name, $headers);
return response()->download($pathToFile)->deleteFileAfterSend();
流媒体下载
return response()->streamDownload(function () {
echo GitHub::api('repo')
->contents()
->readme('laravel', 'laravel')['contents'];
}, 'laravel-readme.md');
文件返回
return response()->file($pathToFile);
return response()->file($pathToFile, $headers);
十、命令行
1:添加命令
php artisan make:command SendEmails
2:执行命令
protected $signature = 'test';
php artisan test
protected $signature = 'test:user {user}';
php artisan test:user lvxiaohu
protected $signature = 'test:user {user*}';
php artisan test:user lvxiaohu sunyin
3:获取参数
$userId = $this->argument('user');
$arguments = $this->arguments();
4:选项(非必须)
protected $signature = 'test:user {user} {--id=*}';
php artisan test:user lvxiaohu --id=1 --id=2
5:提示输入
$name = $this->ask('What is your name?');
$password = $this->secret('What is the password?');
$name = $this->anticipate('What is your name?', ['Taylor', 'Dayle']);
$name = $this->choice('What is your name?', ['Taylor', 'Dayle'], 0);
6:信息输出
$this->info('Display this on the screen');
$this->error('Something went wrong!');
$this->line('Display this on the screen');
7:进度
$users = TestModel::all();
$bar = $this->output->createProgressBar(count($users));
$bar->start();
foreach ($users as $user) {
$this->performTask($user);
$bar->advance();
}
$bar->finish();