lavarel5.2官方文檔閱讀——架構基礎

《目錄》php

1.請求的生命週期前端

2.應用的架構laravel

3.服務提供者redis

4.服務容器數據庫

5.Facades外立面(從這節起,看中文版的:https://phphub.org/topics/1783)bootstrap

6.用戶認證api

1.請求的生命週期數組

全部的請求都會被服務器導向public/index.php文件,它是整個框架的入口點。首先載入Composer提供的類自動加載器,而後獲取lavarel應用的一個實例(從bootstrap/app.php中)。
進來的全部請求,根據類型不一樣,要麼送進HTTP kernel,要麼就送進console kernel。kernel位於app/Http/Kernel.php中,它是Illuminate\Foundation\Http\Kernel類的子類,其中定義有bootstrappers數組,該操做在處理請求前首先被執行,對錯誤、日誌等不少方面進行配置。其中,也定義了不少中間件,對session、CSRF驗證、維護模式等進行處理。kernel中的handle方法能夠看作是一個黑盒,輸入爲請求對象,輸出爲響應對象。
另外一個重要的操做是載入service provider,它位於config/app.php的providers數組中,首先將執行全部provider的register函數,而後執行他們的boot函數。service provider能夠提供database, queue, validation, 和routing方面的各類組件,它是lavar啓動過程當中最重要的一環。
這些都創建起來之後,請求將送至router,根據路由規則進行分發處理。
總而言之,service provider是laravel啓動的關鍵,app實例被建立、service被註冊、而後請求就交給app處理,如此簡單!理解service provider是關鍵、它位於app/Providers中,默認地,能夠在AppServiceProvider中添加自定義的啓動代碼、容器的綁定方式等;也能夠建立單獨的幾個文件以負責更細粒度的provider。

2.應用的架構緩存

lavarel並不會限制將類放在哪一個目錄下,只要是composer能夠自動加載就能夠。
目錄結構以下:
app保存應用的核心代碼
bootstrap保存啓動框架的代碼和一些自動加載配置等,cache是爲了優化啓動速度文件夾。
config包含全部的配置文件
database包含數據庫的migration和seeds
public包含前端控制和靜態文件
resources包含視圖文件、本地化文件、和raw assets (LESS, SASS, CoffeeScript)等
storage包含編譯好的blade模板、基於文件的session、緩存和其餘一些由框架生成的文件。分爲app文件夾(能夠保存任何被框架使用的文件)、framework文件夾(保存生成的文件和緩存)、logs文件夾(保存全部的日誌文件)。
tests文件夾包含測試代碼
vendor文件夾包含composer依賴包

app文件夾詳解(該文件夾中的許多類均可以經過artisan make命令生成):
Console和Http文件夾至關因而提供了框架核心功能的api,http和cli是兩種與框架交互的方式,可是並無功能性的代碼,他們只會對應用發起一些命令。console中包含了artisan命令,http中包含了中間件、控制器、請求等。
Events文件夾是event類所在地,它提供了靈活和解耦的方式,以通知應用的其餘部分某事件已發生。
Exceptions包含了異常處理類。
Jobs是隊列任務的所在地,能夠執行隊列任務,也能夠與現有的請求生命週期同步執行。
Listeners文件夾中是事件的handler所在地,例如UserRegistered事件就有多是被SendWelcomeEmail監聽器所處理的。
Policies文件夾是保存認證策略的地方,它決定登陸用戶能夠對哪些資源進行哪些操做。

3.服務提供者Service Provider服務器

// config/app.php中的providers數組是全部provider的列表,可是它們中的許多都是延遲加載,意味着只有在請求體須要時,它才進行載入。
// 全部的provider都繼承Illuminate\Support\ServiceProvider抽象類,惟一必須實現的方法是register,其中只能寫將起綁定到service container的代碼。由下列命令生成一個provider:
php artisan make:provider RiakServiceProvider

//下列是一個provider示例:
<?php

namespace App\Providers;

use Riak\Connection;
use Illuminate\Support\ServiceProvider;

class RiakServiceProvider extends ServiceProvider
{
    /**
     * Register bindings in the container.
     *
     * @return void
     */
    public function register()//此處使用register方法在服務容器中定義了一個Riak\Connection類的實例,並且是「單例」
    {
        $this->app->singleton(Connection::class, function ($app) {
            return new Connection(config('riak'));
        });
    }
}

//當咱們想要註冊一個view composer時,須要在boot方法中。boot方法的調用是在全部其餘的provider都已經被註冊後,因此在函數中可使用框架提供的任何service。下面展現了boot的使用:
<?php

namespace App\Providers;

use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;

class EventServiceProvider extends ServiceProvider
{
    // Other Service Provider Properties...

    /**
     * Register any other events for your application.
     *
     * @param  \Illuminate\Contracts\Events\Dispatcher  $events
     * @return void
     */
    public function boot(DispatcherContract $events)
    {
        parent::boot($events);

        view()->composer('view', function () {
            //
        });
    }
}

//能夠在boot方法中type-hint任何類,服務容器能夠幫你完成依賴注入:
use Illuminate\Contracts\Routing\ResponseFactory;

public function boot(ResponseFactory $factory)
{
    $factory->macro('caps', function ($value) {
        //
    });
}

//註冊本身的provider,位於config/app.php中providers數組:
'providers' => [
    // Other Service Providers

    App\Providers\AppServiceProvider::class,
],

//經過設置provider的defer屬性爲true,而且定義一個provides方法,能夠避免該provider每次請求時,都從文件系統中加載,只有在實際須要時,才真正加載進來。Lavarel會保存這些延遲加載的provider,還有他們對應的類名,僅當實際須要時,就能夠加載進來:
<?php

namespace App\Providers;

use Riak\Connection;
use Illuminate\Support\ServiceProvider;

class RiakServiceProvider extends ServiceProvider
{
    /**
     * Indicates if loading of the provider is deferred.
     *
     * @var bool
     */
    protected $defer = true;

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton(Connection::class, function ($app) {
            return new Connection($app['config']['riak']);
        });
    }

    /**
     * Get the services provided by the provider.
     *
     * @return array
     */
    public function provides()//該方法只用返回註冊到服務容器中的服務綁定名便可
    {
        return [Connection::class];
    }

}

4.服務容器Service Container

//首先,請參考https://phphub.org/topics/789以瞭解什麼是服務容器、依賴注入等

//第一個示例:
//由於每購買一個podcast,就會發送郵件,這裏將mailer做爲依賴注入
<?php

namespace App\Jobs;

use App\User;
use Illuminate\Contracts\Mail\Mailer;
use Illuminate\Contracts\Bus\SelfHandling;

class PurchasePodcast implements SelfHandling
{
    /**
     * The mailer implementation.
     */
    protected $mailer;

    /**
     * Create a new instance.
     *
     * @param  Mailer  $mailer
     * @return void
     */
    public function __construct(Mailer $mailer)
    {
        $this->mailer = $mailer;
    }

    /**
     * Purchase a podcast.
     *
     * @return void
     */
    public function handle()
    {
        //
    }
}

//幾乎全部的容器綁定都是在provider中的,在provider中,能夠經過$this->app實例來訪問container對象:
$this->app->bind('HelpSpot\API', function ($app) {//這裏接受了app做爲參數,以便咱們能夠經過app對象獲取子依賴
    return new HelpSpot\API($app['HttpClient']);
});

//單例模式
$this->app->singleton('FooBar', function ($app) {
    return new FooBar($app['SomethingElse']);
});

//綁定一個具體對象
$fooBar = new FooBar(new SomethingElse);
$this->app->instance('FooBar', $fooBar);

//將接口綁定到一個特定實現
//第一個參數是接口,第二個參數是實現類
$this->app->bind('App\Contracts\EventPusher', 'App\Services\RedisEventPusher');
//在使用該接口的地方,就會自動注入該實現:
use App\Contracts\EventPusher;

/**
 * Create a new class instance.
 *
 * @param  EventPusher  $pusher
 * @return void
 */
public function __construct(EventPusher $pusher)
{
    $this->pusher = $pusher;
}

//上下文綁定Contextual Binding
$this->app->when('App\Handlers\Commands\CreateOrderHandler')
          ->needs('App\Contracts\EventPusher')
          ->give('App\Services\PubNubEventPusher');
//綁定一個特定整數
$this->app->when('App\Handlers\Commands\CreateOrderHandler')
          ->needs('$maxOrderCount')
          ->give(10);

//經過標籤管理
//當構建一個report集成器時,須要不一樣類型的report,此時將他們標註同一個標籤,以實現一次性綁定所有
$this->app->bind('SpeedReport', function () {
    //
});
$this->app->bind('MemoryReport', function () {
    //
});
$this->app->tag(['SpeedReport', 'MemoryReport'], 'reports');
//使用時:
$this->app->bind('ReportAggregator', function ($app) {
    return new ReportAggregator($app->tagged('reports'));
});

//解析:
$fooBar = $this->app->make('FooBar');
$fooBar = $this->app['FooBar'];
//更經常使用的方式是在controller、listener、jobs、middleware等類的構造對象中進行type-hint,laravel能夠自動解析依賴

//監聽解析事件,使用resolving方法:
$this->app->resolving(function ($object, $app) {
    // Called when container resolves object of any type...
});
//這種監聽使得該類在解析時,進行監聽函數調用,好比添加一些額外屬性啥的,而後才返回給consumer
$this->app->resolving(FooBar::class, function (FooBar $fooBar, $app) {
    // Called when container resolves objects of type "FooBar"...
});

5.Facades外立面

// 門面爲應用的服務容器中的綁定類提供了一個「靜態」接口。Laravel 內置了不少門面,你可能在不知道的狀況下正在使用它們。Laravel 的門面做爲服務容器中的底層類的「靜態代理」
// 在 Laravel 應用的上下文中,門面就是一個提供訪問容器中對象的類。該機制原理由 Facade 類實現
// 門面類只須要實現一個方法:getFacadeAccessor。正是 getFacadeAccessor 方法定義了從容器中解析什麼(而後 Facade 基類使用魔術方法 __callStatic() 從你的門面中調用解析對象)
// Cache 門面繼承 Facade 基類並定義了 getFacadeAccessor 方法,該方法的工做就是返回服務容器綁定類的別名,當用戶引用 Cache 類的任何靜態方法時,Laravel 從服務容器中解析 cache 綁定,而後在解析出的對象上調用全部請求方法(本例中是 get):
<?php

namespace App\Http\Controllers;

use Cache;
//注意咱們在頂部位置引入了 Cache 門面。該門面做爲代理訪問底層 Illuminate\Contracts\Cache\Factory 接口的實現。咱們對門面的全部調用都會被傳遞給 Laravel 緩存服務的底層實例。
use App\Http\Controllers\Controller;

class UserController extends Controller{
    /**
     * 爲指定用戶顯示屬性
     *
     * @param  int  $id
     * @return Response
     */
    public function showProfile($id)
    {
        $user = Cache::get('user:'.$id);

        return view('profile', ['user' => $user]);
    }
}
// Cache類的實如今Illuminate\Support\Facades\Cache
class Cache extends Facade{
    /**
     * 獲取組件註冊名稱
     *
     * @return string
     */
    protected static function getFacadeAccessor() { 
        return 'cache'; 
    }
}
//下表列出了facade、底層類和container中的綁定名之間的關係:
Facade    Class    Service Container Binding
App    Illuminate\Foundation\Application    app
Artisan    Illuminate\Contracts\Console\Kernel    artisan
Auth    Illuminate\Auth\AuthManager    auth
Blade    Illuminate\View\Compilers\BladeCompiler    blade.compiler
Bus    Illuminate\Contracts\Bus\Dispatcher
Cache    Illuminate\Cache\Repository    cache
Config    Illuminate\Config\Repository    config
Cookie    Illuminate\Cookie\CookieJar    cookie
Crypt    Illuminate\Encryption\Encrypter    encrypter
DB    Illuminate\Database\DatabaseManager    db
DB (Instance)    Illuminate\Database\Connection
Event    Illuminate\Events\Dispatcher    events
File    Illuminate\Filesystem\Filesystem    files
Gate    Illuminate\Contracts\Auth\Access\Gate
Hash    Illuminate\Contracts\Hashing\Hasher    hash
Lang    Illuminate\Translation\Translator    translator
Log    Illuminate\Log\Writer    log
Mail    Illuminate\Mail\Mailer    mailer
Password    Illuminate\Auth\Passwords\PasswordBroker    auth.password
Queue    Illuminate\Queue\QueueManager    queue
Queue (Instance)    Illuminate\Contracts\Queue\Queue    queue
Queue (Base Class)    Illuminate\Queue\Queue
Redirect    Illuminate\Routing\Redirector    redirect
Redis    Illuminate\Redis\Database    redis
Request    Illuminate\Http\Request    request
Response    Illuminate\Contracts\Routing\ResponseFactory
Route    Illuminate\Routing\Router    router
Schema    Illuminate\Database\Schema\Blueprint
Session    Illuminate\Session\SessionManager    session
Session (Instance)    Illuminate\Session\Store
Storage    Illuminate\Contracts\Filesystem\Factory    filesystem
URL    Illuminate\Routing\UrlGenerator    url
Validator    Illuminate\Validation\Factory    validator
Validator (Instance)    Illuminate\Validation\Validator
View    Illuminate\View\Factory    view
View (Instance)    Illuminate\View\View

6.用戶認證

// 配置文件位於config/auth.php
// 在底層代碼中,Laravel 的認證組件由「guards」和「providers」組成,Guard 定義了用戶在每一個請求中如何實現認證,例如,Laravel 經過 session guard來維護 Session 存儲的狀態、Cookie 以及 token guard,token guard 是認證用戶發送請求時帶的「API token」。
// Provider 定義瞭如何從持久化存儲中獲取用戶信息
// 對應的數據表模型位於App\User,還有其對應的migration,位於database中
// Laravel 開箱提供了兩個認證控制器,位於 App\Http\Controllers\Auth 命名空間下,AuthController 處理新用戶註冊和登陸,PasswordController 用於幫助用戶找回密碼。每一個控制器都使用 trait 來引入它們須要的方法。
use AuthenticatesAndRegistersUsers, ThrottlesLogins;

// AuthController 中的自定義操做
// 自定義路徑:
protected $redirectTo = '/home';
// 自定義Guard,該屬性的值對應認證配置文件 auth.php 中的相應 guard 配置
protected $guard = 'admin';
// 自定義驗證/存儲
AuthController 的 validator 方法包含了新用戶的驗證規則,你能夠按須要自定義該方法。
AuthController 的 create 方法負責使用 Eloquent ORM 在數據庫中建立新的 App\User 記錄。固然,你也能夠基於本身的須要自定義該方法。

// 獲取認證用戶
$user = Auth::user();
// 或經過Illuminate\Http\Request實例訪問
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Routing\Controller;

class ProfileController extends Controller{
    /**
     * 更新用戶屬性.
     *
     * @param  Request  $request
     * @return Response
     */
    public function updateProfile(Request $request)
    {
        if ($request->user()) {
            // $request->user() 返回認證用戶實例...
        }
    }
}

// 判斷當前用戶是否經過認證
if (Auth::check()) {
    // The user is logged in...
}

// auth中間件的使用,只容許經過認證的用戶訪問給定路由
// 使用路由閉包...
Route::get('profile', ['middleware' => 'auth', function() {
    // 只有認證用戶能夠進入...
}]);
// 使用控制器...
Route::get('profile', [
    'middleware' => 'auth',
    'uses' => 'ProfileController@show'
]);
// 在Controller中使用:
public function __construct(){
    $this->middleware('auth');
}

// 指定一個Guard,在指定auth中間件時,也能夠指定一個guard,肯定其使用哪一個(列表參見auth.php中的guards數組)
Route::get('profile', [
    'middleware' => 'auth:api',
    'uses' => 'ProfileController@show'
]);

// 登陸失敗次數限制
若是你使用了 Laravel 內置的 AuthController 類, 可使用 Illuminate\Foundation\Auth\ThrottlesLogins trait 來限制用戶登陸失敗次數。默認狀況下,用戶在幾回登陸失敗後將在一分鐘內不能登陸,這種限制基於用戶的用戶名/郵箱地址+IP地址。(這裏如何設定次數???)
// 這個類中,設爲5次,應該也能夠重寫這個值 vendor/laravel/framework/src/Illuminate/Foundation/Auth/ThrottlesLogins.php

// 經過ID認證用戶,要經過用戶ID登陸到應用,可使用 loginUsingId 方法,該方法接收你想要認證用戶的主鍵做爲參數(用於測試):
Auth::loginUsingId(1);

//一次性認證用戶。你可使用 once 方法只在單個請求中將用戶登陸到應用,而不存儲任何 Session 和 Cookie,這在構建無狀態的 API 時頗有用。once方法和attempt方法用法差很少:
if (Auth::once($credentials)) {
    //
}

【下面的內容不看了,都是具體的接口函數、等等,用的時候再看】

相關文章
相關標籤/搜索