Laravel 5项目结构分析及中文文档阅读摘要
HTTP路由 1
中间件 5
控制器 5
HTTP请求 7
HTTP 响应 8
视图 9
Service Providers 11
Service Container 12
Contracts 13
Facades 14
请求的生命周期 15
应用程序结构 16
认证 20
缓存 24
集合 26
Artisan Console 26
扩展框架* 27
Laravel Elixir* 27
加密 27
错误与日志 28
事件 28
文件系统 / 云存储 30
哈希 31
辅助方法 31
本地化* 31
邮件* 31
扩展包开发* 31
分页* 31
队列* 31
会话 32
Blade模板 33
单元测试* 35
数据验证 35
数据库使用基础 36
查询构造器 38
结构生成器 41
迁移和数据填充 41
Eloquent ORM 41
基本路由
定义针对不同Http Method的路由,如:
Route::get('/', function(){
Route::post('foo/bar', function(){
Route::match(['get', 'post'], '/', function(){ # 多个方法
Route::any('foo', function(){ # 所有方法
使用url方法生成url:$url = url('foo');
CSRF保护
Laravel会自动在每一位用户的session中放置随机的token。VerifyCsrfToken 中间件将保存在session中的请求和输入的token配对来验证token。除了寻找CSRF token 作为「POST」参数,中间件也检查X-XSRF-TOKEN请求头。
插入CSRF Token到表单:
_token" value="csrf_token(); ?>">
在Blade模板引擎使用:
_token" value="{ { csrf_token() }}">
添加到X-XSRF-TOKEN请求头中:
csrf-token" content="{ { csrf_token() }}" />
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
...
# 这样所有ajax请求中将会带上该头信息:
$.ajax({
url: "/foo/bar",
})
方法欺骗
_method" value="PUT">
">
路由参数
Route::get('user/{id}', function($id){ # 基础参数
Route::get('user/{name?}', function($name = null){ # 可选参数
Route::get('user/{name?}', function($name = 'John'){ # 带默认值的参数
可以定义参数的全局模式,在RouteServiceProvider的boot方法里定义模式:
$router->pattern('id', '[0-9]+');
之后,会作用在所有使用这个特定参数的路由上:
Route::get('user/{id}', function($id)
if ($route->input('id') == 1){ # 在路由外部取得参数
也可以通过依赖注入来取得参数:
use Illuminate\Http\Request;
Route::get('user/{id}', function(Request $request, $id){
if ($request->route('id')){
路由命名
Route::get('user/profile', ['as' => 'profile', function(){
# 为控制器动作指定路由名称
Route::get('user/profile', [
'as' => 'profile',
'uses' => 'UserController@showProfile'
]);
# 使用命名路由进行重定向
$url = route('profile');
$redirect = redirect()->route('profile');
# 返回当前路由请求的名称
$name = Route::currentRouteName();
路由群组
将共享属性作为一个数组当做Route::group第一个参数:
# 共享中间件
Route::group(['middleware' => ['foo', 'bar']], function()
{
Route::get('/', function()
{
// Has Foo And Bar Middleware
});
Route::get('user/profile', function()
{
// Has Foo And Bar Middleware
});
});
# 上例中foo和bar为中间件键名。自定义的中间件的键名与类名映射关系需要在Kernel.php中添加。
# 共享命名空间
Route::group(['namespace' => 'Admin'], function()
{
// Controllers Within The "App\Http\Controllers\Admin" Namespace
Route::group(['namespace' => 'User'], function()
{
// Controllers Within The "App\Http\Controllers\Admin\User" Namespace
});
});
子域名路由
Route::group(['domain' => '{account}.myapp.com'], function()
{
Route::get('user/{id}', function($account, $id)
{
//
});
});
路由前缀
Route::group(['prefix' => 'admin'], function()
{
Route::get('users', function()
{
// Matches The "/admin/users" URL
});
});
# 在路由前缀中定义参数
Route::group(['prefix' => 'accounts/{account_id}'], function()
{
Route::get('detail', function($account_id)
{
//
});
});
路由模型绑定
模型绑定提供方便的方式将模型实体注入到路由中:比起注入User ID,你可以选择注入符合给定ID的User类实体。在RouteServiceProvider::boot方法定义模型绑定:
public function boot(Router $router)
{
parent::boot($router);
$router->model('user', 'App\User');
}
然后定义一个有 {user} 参数的路由:
Route::get('profile/{user}', function(App\User $user){
//
});
请求至profile/1将注入ID为1的User实体。若实体不存在,则抛出404。可以传给第三个参数一个闭包,定义找不到时的行为。
抛出404错误
两种方法:
abort(404); # 本质上是抛出了一个带有特定状态码的Symfony\Component\HttpKernel\Exception\HttpException 。
或者:手工抛出HttpException
新建中间件
php artisan make:middleware OldMiddleware # 新建一个中间件
中间件的主要功能在handle()方法中实现:
class OldMiddleware {
public function handle($request, Closure $next){
if (xxx){
return redirect('xx');
}
return $next($request);
}
}
分析其结构可以发现,基本上就是执行一个判断,然后依次进行重定向或者继续向前。
全局中间件
若是希望中间件被所有的 HTTP 请求给执行,只要将中间件的类加入到app/Http/Kernel.php的$middleware 属性清单列表中。
指派中间件给路由
新建中间件后,在app/Http/Kernel.php的$routeMiddleware中添加中间件键名与类名的映射关系,然后就可以在路由中使用这个键名来指派路由:
Route::get('admin/profile', ['middleware' => 'auth', function(){
可终止中间件
可终止中间件需要继承自TerminableMiddleware,并实现terminate()方法。其用处是在HTTP响应已经被发送到用户端后再执行。可终止中间件需要添加到app/Http/Kernel.php的全局中间件清单中。
基础控制器
所有的控制器都应该扩展基础控制器类
use App\Http\Controllers\Controller;
class UserController extends Controller { # 继承Controller
public function showProfile($id) # 动作
{
App\Http\Controllers\Controller的定义如下:
namespace Borogadi\Http\Controllers;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
abstract class Controller extends BaseController
{
use DispatchesJobs, ValidatesRequests;
}
可见最终是继承自Illuminate\Routing\Controller类。
# 命名控制器路由
Route::get('foo', ['uses' => 'FooController@method', 'as' => 'name']);
# 指向控制器的URL
$url = action('App\Http\Controllers\FooController@method');
或者:
URL::setRootControllerNamespace('App\Http\Controllers');
$url = action('FooController@method');
# 获取正在执行的控制器动作名称
$action = Route::currentRouteAction();
控制器中间件
两种方式,一是在控制器路由中指定:
Route::get('profile', [
'middleware' => 'auth',
'uses' => 'UserController@showProfile'
]);
另一种是直接在控制器构造器中指定:
class UserController extends Controller {
public function __construct(){
$this->middleware('auth');
$this->middleware('log', ['only' => ['fooAction', 'barAction']]);
隐式控制器
隐式控制器实现定义单一路由来处理控制器中的每一项行为:
定义一个路由:
Route::controller('users', 'UserController');
定义控制器类的实现:
class UserController extends BaseController {
public function getIndex(){ # 响应user
public function postProfile(){ # 响应post方式的user/profile
public function anyLogin(){ # 响应所有方式的user/login
可以通过使用“-”来支持多个字词的控制器行为:
public function getAdminProfile() {} # 响应users/admin-profile,不是user/adminprofile。注意动作名中使用的驼峰命名方法
RESTful资源控制器
其实就是隐式控制器的一个具体应用。
路由缓存
如果应用中只使用了控制器路由,则可以利用路由缓存来提高性能。
php artisan route:cache
缓存路由文件将会被用来代替app/Http/routes.php文件
取得请求
两种方式,一是通过Request facade:
use Request;
$name = Request::input('name');
或者通过依赖注入:在控制器中的构造函数或方法对该类使用类型提示。当前请求的实例将会自动由服务容器注入:
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
class UserController extends Controller {
public function store(Request $request){
$name = $request->input('name');
若同时还有使用路由参数输入的数据,只需将路由参数置于其他依赖之后:
public function update(Request $request, $id){
取得输入数据
$name = Request::input('name'); # 取得特定输入数据
$name = Request::input('name', 'Sally'); # 取得特定输入数据,若没有则取得默认值
if (Request::has('name')){ # 确认是否有输入数据
$input = Request::all(); # 取得所有输入数据
$input = Request::only('username', 'password'); # 取得部分输入数据
$input = Request::except('credit_card'); # 取得部分输入数据排除法
$input = Request::input('products.0.name'); # 取得数组形式的数据
旧输入数据
Request::flash(); # 将当前的输入数据存进 session中
Request::flashOnly('username', 'email'); # 将部分数据存成session
Request::flashExcept('password'); # 将部分数据存成session,排除法
return redirect('form')->withInput(); # 重定向,同时将当期输入数据缓存到session
return redirect('form')->withInput(Request::except('password')); # 重定向,同时将当期输入的部分数据缓存到session
$username = Request::old('username'); # 取得前一次请求所保存的一次性Session
{ { old('username') }} # 在blade模板中显示旧输入数据
Cookies
Laravel 所建立的 cookie 会加密并且加上认证记号。
$value = Request::cookie('name'); # 取得Cookie值
# 在响应中添加Cookies
$response = new Illuminate\Http\Response('Hello World');
$response->withCookie(cookie('name', 'value', $minutes));
$response->withCookie(cookie()->forever('name', 'value')); # 添加永久有效的Cookie
# 以队列方式添加Cookie,即在实际发送响应之前设置Cookie
Cookie::queue('name', 'value');
return response('Hello World');
上传文件
$file = Request::file('photo'); # 取得上传文件
if (Request::hasFile('photo')) # 确认文件是否有上传
if (Request::file('photo')->isValid()) # 确认上传的文件是否有效
Request::file('photo')->move($destinationPath); # 移动上传的文件
Request::file('photo')->move($destinationPath, $fileName); # 移动上传的文件,并重命名
其他的请求信息
$uri = Request::path(); # 取得请求 URI
if (Request::ajax()) # 判断一个请求是否使用了 AJAX
# 判断请求的方法
$method = Request::method();
if (Request::isMethod('post'))
if (Request::is('admin/*')) # 确认请求路径是否符合特定格式
$url = Request::url(); # 取得请求URL
基本响应
Route::get('/', function(){ # 返回字符串
return 'Hello World';
# 返回完整的Responses实例,有两种方法
返回Responses对象:
use Illuminate\Http\Response;
return (new Response($content, $status))
->header('Content-Type', $value);
或者使用response辅助方法:
return response($content, $status)->header('Content-Type', $value);
# 返回视图
return response()->view('hello')->header('Content-Type', $type);
# 添加Cookies
return response($content)->withCookie(cookie('name', 'value'));
重定向
return redirect('user/login'); # 使用redirect重定向方法
return redirect('user/login')->with('message', 'Login Failed'); # 重定向,并将当前数据保存至Session
return redirect()->back(); # 重定向至前一个位置
return redirect()->route('login'); # 重定向到特定路由
# 重定向到特定路由,并带参数
return redirect()->route('profile', [1]); # 路由的 URI 为:profile/{id}
return redirect()->route('profile', ['user' => 1]); # 路由的 URI 为:profile/{user}
# 根据控制器动作的重定向
return redirect()->action('App\Http\Controllers\HomeController@index');
return redirect()->action('App\Http\Controllers\UserController@profile', ['user' => 1]); # 带参数
其他响应
# 返回json
return response()->json(['name' => 'Abigail', 'state' => 'CA']);
# 返回jsonp
return response()->json(['name' => 'Abigail', 'state' => 'CA'])
->setCallback($request->input('callback'));
# 文件下载
return response()->download($pathToFile, $name, $headers);
响应宏
# 定义响应宏,通常定义在Provider的boot方法内
Response::macro('caps', function($value) use ($response){ # PHP在默认情况下,匿名函数不能调用所在代码块的上下文变量,而需要通过使用use关键字。use会复制一份变量到闭包内,也支持引用形式,如use ( &$rmb )
return $response->make(strtoupper($value));
});
# 调用响应宏
return response()->caps('foo');
基本视图
# 视图定义 文件路径及文件名:resources/views/