Laravel 5文档阅读摘要

WBOY
Freigeben: 2016-08-10 08:48:38
Original
810 Leute haben es durchsucht

Laravel 5项目结构分析及中文文档阅读摘要

 

HTTP路由1

中间件5

控制器5

HTTP请求7

HTTP 响应8

视图9

Service Providers11

Service Container12

Contracts13

Facades14

请求的生命周期15

应用程序结构16

认证20

缓存24

集合26

Artisan Console26

扩展框架*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 ORM41

 

 

 

 

HTTP路由

基本路由

定义针对不同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中放置随机的tokenVerifyCsrfToken 中间件将保存在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" c/span>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'){  #  带默认值的参数

 

可以定义参数的全局模式,在RouteServiceProviderboot方法里定义模式:

$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

    });

 

});

上例中foobar为中间件键名。自定义的中间件的键名与类名映射关系需要在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,你可以选择注入符合给定IDUser类实体。在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将注入ID1User实体。若实体不存在,则抛出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文件

 

 

HTTP请求

取得请求

两种方式,一是通过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

 

HTTP 响应

基本响应

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);

 

响应宏

#  定义响应宏,通常定义在Providerboot方法内

Response::macro('caps', function($value) use ($response){  # PHP在默认情况下,匿名函数不能调用所在代码块的上下文变量,而需要通过使用use关键字。use会复制一份变量到闭包内,也支持引用形式,如use ( &$rmb )

   return $response->make(strtoupper($value));

 });

 

#  调用响应宏

return response()->caps('foo');

 

视图

基本视图

#  视图定义  文件路径及文件名:resources/views/greeting.php

    

        

Hello, name; ?>

    

 

#  视图调用

Route::get('/', function()

{

    return view('greeting', ['name' => 'James']);  #  传给视图的参数为一个键值对数组

});

 

#  子文件夹视图调用  定义位置:resources/views/admin/profile.php

return view('admin.profile', $data);

 

传递数据到视图的其他方法

$view = view('greeting')->with('name', 'Victoria');  #  传统方法

$view = view('greeting')->withName('Victoria');  #  魔术方法

$view = view('greetings', $data);  #直接传数组  $data为一个键值对数组

 

共享数据给所有视图

自定义一个Provider,或者直接在AppServiceProviderboot方法内添加:

view()->share('data', [1, 2, 3]);

或者:

View::share('data', [1, 2, 3]);

 

#  确认视图是否存在

if (view()->exists('emails.customer'))

 

#  从一个文件路径产生视图

return view()->file($pathToFile, $data);

 

视图组件

视图组件就是在视图被渲染前,会调用的闭包或类方法。

 

#  定义视图组件

use View;

use Illuminate\Support\ServiceProvider;

 

class ComposerServiceProvider extends ServiceProvider {

    public function boot(){

        View::composer('profile', 'App\Http\ViewComposers\ProfileComposer');  #  使用类来指定视图组件

        View::composer('dashboard', function($view){  #  使用闭包来指定视图组件

...

        });

}

...

}

使用类来指定视图组件,在视图被渲染之前将调用所指定类的名为compose的方法。如上例中,ProfileComposer'类的定义为:

 

use Illuminate\Contracts\View\View;

use Illuminate\Users\Repository as UserRepository;

 

class ProfileComposer {

    protected $users;

    public function __construct(UserRepository $users){  #  service container 会自动解析所需的参数

         $this->users = $users;

    }

 

    public function compose(View $view){ #  compose方法被传入了一个View的实例,在此可以传参给View

        $view->with('count', $this->users->count());

    }

}

 

#  在视图组件内使用通配符 

View::composer('*', function($view){  #  相当于定义给所有视图

 

#  同时对多个视图附加视图组件

View::composer(['profile', 'dashboard'], 'App\Http\ViewComposers\MyViewComposer');

 

#  定义多个视图组件

View::composers([

    'App\Http\ViewComposers\AdminComposer' => ['admin.index', 'admin.profile'],

    'App\Http\ViewComposers\UserComposer' => 'user',

    'App\Http\ViewComposers\ProductComposer' => 'product'

]);

 

Service Providers

每个自定义的Provider都必须继承自Illuminate\Support\ServiceProvider,并在config/app.php中的Providers数组中注册。自定义的Provider必须定义register()方法,用于定义注册时的行为。此外还有两个可选方法和一个可选属性:boot()方法在所有的Provider都被加载后才会调用,而provides()方法用来和$defer可选属性配合,提供缓载功能。

通过服务提供者的方式来提供服务的思路:实现一个完成实际工作的类,定义一个Provider,并在Providerregister()方法中往系统容器注册实际工作类以及获取实际工作类实例的方法。然后再在应用配置中注册这个Provider。这样,应用初始化时会调用所有Providerregister()方法来间接注册获取实际工作类实例的方式。

 

定义一个基本Provider

use Riak\Connection;

use Illuminate\Support\ServiceProvider;

 

class RiakServiceProvider extends ServiceProvider {

public function register(){

#  往容器中注册一个类及获取其实例的方法

        $this->app->singleton('Riak\Contracts\Connection', function($app){  

            return new Connection($app['config']['riak']);

        });

    }

}

 

 

Service Container

基本用法

Provider内部,可以通过$this->app来访问服务容器。

注册依赖主要有两种方式:回调接口方式和绑定实例接口。

 

#  闭包回调的方式

$this->app->bind('FooBar', function($app){

    return new FooBar($app['SomethingElse']);

});

 

#  以单例方式注册,之后的调用都返回相同的实例

$this->app->singleton('FooBar', function($app){

    return new FooBar($app['SomethingElse']);

});

 

#  绑定为一个已经存在的实例

$fooBar = new FooBar(new SomethingElse);

$this->app->instance('FooBar', $fooBar);

 

从容器解析出实例也有两种方式:

$fooBar = $this->app->make('FooBar');  #  使用make()方法解析

$fooBar = $this->app['FooBar'];  #  因为容器实现了ArrayAccess接口,所以可以用数组访问形式

 

在定义好注册、解析信息后,就可以直接在类的构造函数中通过type-hint的方式指定所需要的依赖,容器将自动注入所需要的所有依赖

 

use Illuminate\Routing\Controller;

use App\Users\Repository as UserRepository;

 

class UserController extends Controller {

    protected $users;

    public function __construct(UserRepository $users){  #  type-hint

        $this->users = $users;

    }

    public function show($id){

    }

 

}

 

绑定接口

interface EventPusher {

    public function push($event, array $data);

}

 

class PusherEventPusher implements EventPusher {

...

}

因为PusherEventPusher类实现了EventPusher接口,所以可以直接注册这个接口并绑定为某个实现了该接口的类:

$this->app->bind('App\Contracts\EventPusher', 'App\Services\PusherEventPusher');

当有类需要EventPusher接口时,会告诉容器应该注入PusherEventPusher

 

上下文绑定

$this->app->when('App\Handlers\Commands\CreateOrderHandler')

          ->needs('App\Contracts\EventPusher')

          ->give('App\Services\PubNubEventPusher');

 

标签

$this->app->bind('SpeedReport', function(){

});

 

$this->app->bind('MemoryReport', function(){

});

 

$this->app->tag(['SpeedReport', 'MemoryReport'], 'reports');  #  将上两步注册的类打成一个标签‘reports

 

一旦服务打上标签,可以通过 tagged 方法轻易地解析它们:

$this->app->bind('ReportAggregator', function($app){

    return new ReportAggregator($app->tagged('reports'));

});

 

容器事件

容器在解析每一个对象时就会触发一个事件。可以用resolving方法来监听此事件(被解析的对象将被传入到闭包方法中):

$this->app->resolving(function($object, $app){  #  当容器解析任意类型的依赖时被调用

...

});

$this->app->resolving(function(FooBar $fooBar, $app){  #  当容器解析FooBar类型的依赖时被调用

...

});

 

Contracts

Contracts是所有Laravel主要组件实现所用的接口,可以看到Contracts目录下的目录结构和Illuminate中的一样。Contracts中为接口定义,Illuminate为具体实现。Illuminate中每个具体实现的类都扩展了其在Contracts中对应的接口。这样将接口和实现相分离,可以使依赖注入变得低耦合

/laravel

/framework

/src

/Illuminate

/Auth

/Broadcasting

/Bus

...

/Contracts  

/Auth

/Broadcasting

/Bus

...

 

Facades

基本用法

Facades提供一个静态接口给在应用程序的服务容器中可以取用的类。(设计模式中“装饰模式”的一个应用,主要是使用class_alias来创建类别名,另外使用__callStatic()来提供一个静态代理,其最终是使用模拟对象的方式模拟PHP对象并调用对象的方法)

 

Laravelfacades和你建立的任何自定义facades,将会继承基类Facade,并只需要去实现一个方法:getFacadeAccessor()

 

Cache这个facade的调用:$value = Cache::get('key');

看一下类的实现:

class Cache extends Facade {

    protected static function getFacadeAccessor() { return 'cache'; }  #  该方法的作用就是返回服务容器绑定的名称

}

当用户在Cachefacade上执行任何的静态方法,Laravel从服务容器解析被绑定的cache ,并对该对象执行被请求的方法 (在这个例子中,get)

 

所有的facades存在于全局命名空间,当在有嵌套的命名空间中使用时,需要导入facade类进入命名空间:

use Cache;  #  导入Cache facade

class PhotosController extends Controller {

    public function index(){

        $photos = Cache::get('photos');

    }

}

 

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!