lavarel5.2官方文檔閱讀——基本概念

《目錄》php

1.安裝html

2.配置laravel

3.基本操做git

4.中級操做github

5.路由web

6.中間件express

7.控制器json

8.請求對象api

9.響應對象數組

10.views視圖

11.blade模板引擎

 

1.安裝

若經過Composer 或 the Laravel installer 進行項目建立,會使用php artisan key:generate自動生成一個app_key,保存在.env文件中。該key的做用是保證session等加密數據的安全。

config/app.php中的配置通常不用改,其中的timezone和locale能夠根據實際狀況配置一下。

2.配置

在代碼中,配置的使用:

$value = config('app.timezone');//讀取配置值
config(['app.timezone' => 'America/Chicago']);//運行中設置配置值

環境配置,位於.env.php中,使用方法,第二個參數是默認值:

'debug' => env('APP_DEBUG', false),

在生產環境下,開啓配置文件的緩存:

php artisan config:cache

上述方式使得配置融合進一個文件當中,能夠加快配置的載入。

開啓維護模式,在維護模式下,網站將使用resources/views/errors/503.blade.php做爲響應

php artisan down//啓動維護模式
php artisan up//關閉維護模式

官方提供了homestead虛擬機,用於構建lavarel開發環境。

3.基本操做

建立新項目:

composer create-project laravel/laravel quickstart --prefer-dist
git clone https://github.com/laravel/quickstart-basic quickstart cd quickstart composer install php artisan migrate

新建數據表:

php artisan make:migration create_tasks_table --create=tasks
//在database文件夾中新生成的文件中添加name字段
<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateTasksTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('tasks', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('tasks');
    }
}

新建model:

php artisan make:model Task

//新生成的文件以下:
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Task extends Model
{
    //
}

新建route,使用web中間件,使得他們具備session state 和 CSRF protection:

(帳號項目中好像沒用到這個)

//文件位於app/Http/routes.php
<?php

use App\Task;
use Illuminate\Http\Request;

Route::group(['middleware' => 'web'], function () {

    /**
     * Show Task Dashboard
     */
    Route::get('/', function () {
        //
    });

    /**
     * Add New Task
     */
    Route::post('/task', function (Request $request) {
        //
    });

    /**
     * Delete Task
     */
    Route::delete('/task/{task}', function (Task $task) {
        //
    });
});

網頁視圖位於resources/views中,調用方式:

Route::get('/', function () {
    return view('tasks'); //該視圖文件位於resources/views/tasks.blade.php中
});

佈局layout文件,通常地,應該建立到resources/views/layouts/app.blade.php

<!-- resources/views/layouts/app.blade.php -->

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Laravel Quickstart - Basic</title>

        <!-- CSS And JavaScript -->
    </head>

    <body>
        <div class="container">
            <nav class="navbar navbar-default">
                <!-- Navbar Contents -->
            </nav>
        </div>

        @yield('content') //這是section的名稱,能夠被子視圖繼承
    </body>
</html>

添加tasks子視圖,並繼承上述的layouts:

<!-- resources/views/tasks.blade.php -->

@extends('layouts.app') //繼承layouts視圖

@section('content')//擴展其中的content section

    <!-- Bootstrap Boilerplate... -->

    <div class="panel-body">
        <!-- Display Validation Errors -->
        @include('common.errors') //直接載入另外一個視圖文件,該文件位於resources/views/common/errors.blade.php

        <!-- New Task Form -->
        <form action="{{ url('task') }}" method="POST" class="form-horizontal">
            {!! csrf_field() !!}

            <!-- Task Name -->
            <div class="form-group">
                <label for="task" class="col-sm-3 control-label">Task</label>

                <div class="col-sm-6">
                    <input type="text" name="name" id="task-name" class="form-control">
                </div>
            </div>

            <!-- Add Task Button -->
            <div class="form-group">
                <div class="col-sm-offset-3 col-sm-6">
                    <button type="submit" class="btn btn-default">
                        <i class="fa fa-plus"></i> Add Task
                    </button>
                </div>
            </div>
        </form>
    </div>

    <!-- TODO: Current Tasks -->
@endsection

完成建立任務的表單:

//路由以下設置:
Route::post('/task', function (Request $request) {
    $validator = Validator::make($request->all(), [
        'name' => 'required|max:255',
    ]);

    if ($validator->fails()) {
        return redirect('/')
            ->withInput()
            ->withErrors($validator); //這裏將flash錯誤到session中。視圖中使用$errors變量
    }

    // Create The Task...
    $task = new Task;
    $task->name = $request->name;
    $task->save();

    return redirect('/');
});

//處理錯誤的視圖
<!-- resources/views/common/errors.blade.php -->

@if (count($errors) > 0) //$errors是ViewErrorBag類的實例
    <!-- Form Error List -->
    <div class="alert alert-danger">
        <strong>Whoops! Something went wrong!</strong>

        <br><br>

        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif

展現已有的tasks:

//routes.php中
Route::get('/', function () {
    $tasks = Task::orderBy('created_at', 'asc')->get();

    return view('tasks', [
        'tasks' => $tasks
    ]);
});

//對應的views中:
@extends('layouts.app')

@section('content')
    <!-- Create Task Form... -->

    <!-- Current Tasks -->
    @if (count($tasks) > 0)
        <div class="panel panel-default">
            <div class="panel-heading">
                Current Tasks
            </div>

            <div class="panel-body">
                <table class="table table-striped task-table">

                    <!-- Table Headings -->
                    <thead>
                        <th>Task</th>
                        <th>&nbsp;</th>
                    </thead>

                    <!-- Table Body -->
                    <tbody>
                        @foreach ($tasks as $task)
                            <tr>
                                <!-- Task Name -->
                                <td class="table-text">
                                    <div>{{ $task->name }}</div>
                                </td>

                                <td>
                                     <form action="{{ url('task/'.$task->id) }}" method="POST">
                                         {!! csrf_field() !!}
                                         {!! method_field('DELETE') !!}

                                         <button type="submit" class="btn btn-danger">
                                             <i class="fa fa-trash"></i> Delete
                                         </button>
                                     </form>
                                </td>
                            </tr>
                        @endforeach
                    </tbody>
                </table>
            </div>
        </div>
    @endif
@endsection

用於刪除task的路由:

//這裏使用了隱式對象綁定:https://laravel.com/docs/5.2/routing#route-model-binding
Route::delete('/task/{task}', function (Task $task) {
    $task->delete();

    return redirect('/');
});

4.中級操做

laravel自帶了users表。

增長string類型的字段$table->string('name');

增長int類型的字段$table->integer('user_id')->index(); //這個是用來設置索引的?

創建用戶、任務之間的1對多關係,能夠直接使用$user->tasks進行調用

//在User類中:
public function tasks() { return $this->hasMany(Task::class); }
//在Task類中:
public function user() { return $this->belongsTo(User::class); }

全部的TaskController中的方法都須要登錄的用戶才能執行,使用auth中間件進行指定:

class TaskController extends Controller
{
    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth');
    }
}

對輸入數據進行validate:

/**
 * Create a new task.
 *
 * @param  Request  $request
 * @return Response
 */
public function store(Request $request)
{
    $this->validate($request, [
        'name' => 'required|max:255',
    ]); //此處若是驗證失敗了,就自動重定向回/tasks,包含舊的input和遇到的errors

    // Create The Task...
}

建立新Task:

/**
 * Create a new task.
 *
 * @param  Request  $request
 * @return Response
 */
public function store(Request $request)
{
    $this->validate($request, [
        'name' => 'required|max:255',
    ]);

    $request->user()->tasks()->create([//自動填充了task表的user_id字段
        'name' => $request->name,
    ]);

    return redirect('/tasks');
}

依賴注入。建立app/Repositories文件夾,而且建立TaskRepository類(repository的做用是將一些共有的查詢代碼進行共享)

<?php

namespace App\Repositories;

use App\User;
use App\Task;

class TaskRepository
{
    /**
     * Get all of the tasks for a given user.
     *
     * @param  User  $user
     * @return Collection
     */
    public function forUser(User $user)
    {
        return Task::where('user_id', $user->id)
                    ->orderBy('created_at', 'asc')
                    ->get();
    }
}

注入這個Repository。使用type-hint,在Task控制器的構造方法中注入,Lavarel使用容器解析全部的controller類,因此這個依賴能夠被自動注入到控制器的實例當中:

<?php

namespace App\Http\Controllers;

use App\Task;
use App\Http\Requests;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Repositories\TaskRepository;

class TaskController extends Controller
{
    /**
     * The task repository instance.
     *
     * @var TaskRepository
     */
    protected $tasks;

    /**
     * Create a new controller instance.
     *
     * @param  TaskRepository  $tasks
     * @return void
     */
    public function __construct(TaskRepository $tasks)
    {
        $this->middleware('auth');

        $this->tasks = $tasks;
    }

    /**
     * Display a list of all of the user's task.
     *
     * @param  Request  $request
     * @return Response
     */
    public function index(Request $request)
    {
        return view('tasks.index', [
            'tasks' => $this->tasks->forUser($request->user()),
        ]);
    }
}

刪除Task時的驗證,只容許用戶刪除本身的Task,不容許刪除他人的。這裏使用policy:

php artisan make:policy TaskPolicy
//在新生成的TaskPolicy中添加代碼
<?php

namespace App\Policies;

use App\User;
use App\Task;
use Illuminate\Auth\Access\HandlesAuthorization;

class TaskPolicy
{
    use HandlesAuthorization;

    /**
     * Determine if the given user can delete the given task.
     *
     * @param  User  $user
     * @param  Task  $task
     * @return bool
     */
    public function destroy(User $user, Task $task)
    {
        return $user->id === $task->user_id;
    }
}

而後,將Model和Policy聯繫起來:

//文件位於app/Providers/AuthServiceProvider.php
//增長一行鍵值對:

/**
 * The policy mappings for the application.
 *
 * @var array
 */
protected $policies = [
    'App\Task' => 'App\Policies\TaskPolicy',
];

在Model中應用該驗證。說明:這裏運用authorize方法,指定policy名稱爲destroy,傳入實例$task,驗證若是失敗,會自動返回403錯誤頁面:

/**
 * Destroy the given task.
 *
 * @param  Request  $request
 * @param  Task  $task
 * @return Response
 */
public function destroy(Request $request, Task $task)
{
    $this->authorize('destroy', $task);

    $task->delete();

    return redirect('/tasks');
}

5.路由Routing

位於app/Http/routes.php中,基本的路由寫法爲url加一個閉包構成:

Route::get('foo', function () {
    return 'Hello World';
});

路由規則位於web中間件的group中,以使用sessions和CSRF保護(實踐中發現,若是不位於此,將沒法使用$errors變量):

Route::group(['middleware' => ['web']], function () {
    //
});

路由接受的請求的類型:

Route::match(['get', 'post'], '/', function () {
    //接受多種請求類型的路由
});

Route::any('foo', function () {
    //接受全部請求類型的路由
});

路由能夠接受參數,用大括號括起來。參數後面帶一個問號,標明該參數是可選的(這種狀況下,須要在函數傳參時,給它一個默認值):

Route::get('user/{id}', function ($id) {
    return 'User '.$id;
});
Route::get('posts/{post}/comments/{comment}', function ($postId, $commentId) {
    //
});
Route::get('user/{name?}', function ($name = null) {
    return $name;
});

Route::get('user/{name?}', function ($name = 'John') {
    return $name;
});

 

能夠對某個路由規則進行命名,指定其name,這樣在重定向時將十分方便:

Route::get('profile', ['as' => 'profile', function () {
    //
}]);

Route::get('profile', [
    'as' => 'profile', 'uses' => 'UserController@showProfile'
]);

Route::get('user/profile', 'UserController@showProfile')->name('profile');

其餘幾種命名路由的使用方式:

Route::group(['as' => 'admin::'], function () {
    Route::get('dashboard', ['as' => 'dashboard', function () {
        // Route named "admin::dashboard"
    }]);
});

// Generating URLs...
$url = route('profile');

// Generating Redirects...
return redirect()->route('profile');

Route::get('user/{id}/profile', ['as' => 'profile', function ($id) {
    //
}]);
$url = route('profile', ['id' => 1]);//route函數的第二個參數做爲路由規則的對應參數傳入

路由組Route groups的概念,容許設定多個路由的共同屬性,這些共有屬性做爲Route::group方法的第一個參數,以數組形式傳入。如下爲使用的幾種方式:

//(1)指定路由規則使用的中間件,中間件的執行順序與此處定義順序相同
Route::group(['middleware' => ['auth']], function () {
    Route::get('/', function ()    {
        // Uses Auth Middleware
    });

    Route::get('user/profile', function () {
        // Uses Auth Middleware
    });
});

//(2)指定控制器的命名空間,這裏只須要指定App\Http\Controllers\後面路徑名便可
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
    });
});

//(3)指定子域的路由規則:
//這個試了下,要指定hosts文件中IP qxxx.myapp.com條目,那麼在訪問qxxx.myapp.com:端口號/user/{id}時,便可匹配到此路由。
Route::group(['domain' => '{account}.myapp.com'], function () {
    Route::get('user/{id}', function ($account, $id) {
        //
    });
});
//(4)指定路由url的前綴:
Route::group(['prefix' => 'accounts/{account_id}'], function () {
    Route::get('detail', function ($accountId)    {
        // Matches The "/accounts/{account_id}/detail" URL
    });
});

CSRF跨站請求僞造的防範:

//在表單內部提供csrf token隱藏域
// Vanilla PHP
<?php echo csrf_field(); ?>

// Blade Template Syntax
{{ csrf_field() }}

//生成了以下標籤:
<input type="hidden" name="_token" value="<?php echo csrf_token(); ?>">

web中間件中的VerifyCsrfToken中間件將自動的驗證這類token是否與session中存儲的token一致(這裏是怎麼個原理呢?爲何就能防範)

若是不想使某些url進行這種防範,第一種方法是將路由規則寫在web中間件以外,第二種是修改VerifyCsrfToken類的except數組變量:

<?php

namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;

class VerifyCsrfToken extends BaseVerifier
{
    /**
     * The URIs that should be excluded from CSRF verification.
     *
     * @var array
     */
    protected $except = [//再也不驗證此數組中指定的url的csrf token
        'stripe/*',
    ];
}

路由與模型的自動綁定,若是路由的action函數的參數中包含type-hint的類,lavarel自動使用url中的參數獲取到對應的類型:

//默認地,獲取的類型實例是以ID字段查出來的
Route::get('api/users/{user}', function (App\User $user) {
    return $user->email;
});

//經過重寫model類的getRouteKeyName方法,能夠改變對應的字段
/**
 * Get the route key for the model.
 *
 * @return string
 */
public function getRouteKeyName()
{
    return 'slug';
}

上述爲隱式綁定,也能夠進行顯示綁定,即人工指定綁定的方式:

//在RouteServiceProvider::boot方法中,指明這種綁定
public function boot(Router $router)
{
    parent::boot($router);
    $router->model('user', 'App\User');
}
//如下這些都是寫在上述的方法中的。
//還能夠自定義這種解析邏輯:
$router->bind('user', function($value) {
    return App\User::where('name', $value)->first();
});
//當這種綁定失敗時,即查詢不到參數對應的數據時,默認的返回404,也能夠對這種行爲進行定製:
$router->model('user', 'App\User', function() {
    throw new NotFoundHttpException;
});

表單的提交方式指定:

//指定爲PUT方式提交:
{{ method_field('PUT') }}
//生成的html以下:
<input type="hidden" name="_method" value="PUT">

獲取當前路由的name和Action(路由請求類型):

$route = Route::current();
$name = $route->getName();
$actionName = $route->getActionName();
//或使用如下方法:
$name = Route::currentRouteName();
$action = Route::currentRouteAction();

6.中間件Middleware

中間件提供了一種方便的過濾http請求的機制,例如,中間件能夠驗證用戶,若用戶未登陸,則重定向至login,不然,就會繼續容許用戶的訪問。其餘中間件也能夠完成各類各樣的任務,CORS負責爲全部的響應添加合適的Headers、LOGGing會記錄下全部的請求狀況。Laravel中包含了maintenance、authentication、CSRF等多種中間件。

建立一個新中間件,中間件位於app/Http/Middleware中

php artisan make:middleware AgeMiddleware

下列的中間件限定了只有在輸入的age大於200時,才能夠繼續訪問應用(將中間件想象成一個層,http請求須要通過一個個這樣的層,以到達應用的核心處理函數。其中的$next方法意味着將該請求繼續向深層傳遞):

<?php

namespace App\Http\Middleware;
use Closure;

class AgeMiddleware
{
    /**
     * Run the request filter.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if ($request->input('age') <= 200) {
            return redirect('home');
        }

        return $next($request);
    }

}

中間件被調用的時機,包括在請求處理前請求處理後兩種:

//在請求被處理前使用,對$request對象進行處理
<?php
namespace App\Http\Middleware;
use Closure;

class BeforeMiddleware
{
    public function handle($request, Closure $next)
    {
        // Perform action

        return $next($request);
    }
}

//在請求處理後使用的中間件,此處對$response對象進行處理
<?php
namespace App\Http\Middleware;
use Closure;

class AfterMiddleware
{
    public function handle($request, Closure $next)
    {
        $response = $next($request);

        // Perform action

        return $response;
    }
}

中間件的使用,註冊並使用中間件:

//(1)若想要對全部的請求使用中間件,請更改app/Http/Kernel.php中的$middleware變量
//(2)若想要在路由規則中使用中間件,須要首先在app/Http/Kernel.php中修改$routeMiddleware變量,加入本身的中間件、而且命名:
protected $routeMiddleware = [
    'auth' => \App\Http\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
];
// 其次,在路由規則中進行指定:
Route::get('/', ['middleware' => ['first', 'second'], function () {
    //中間件傳入一個變量,或一個數組
}]);
// 或使用:
Route::get('/', function () {
    //
})->middleware(['first', 'second']);
// 甚至也能夠直接使用類名:
use App\Http\Middleware\FooMiddleware;
Route::get('admin/profile', ['middleware' => FooMiddleware::class, function () {
    //
}]);
//(3)中間件組:爲了方便將多箇中間件「集合」到一箇中,方便進行使用和分配,依舊是更改app/Http/Kernel.php中的以下變量:
/**
 * The application's route middleware groups.
 *
 * @var array
 */
protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
    ],

    'api' => [
        'throttle:60,1',
        'auth:api',
    ],
];
// 在進行分配時,方法是同樣的。

中間件也能夠接收參數,從第三個變量以後,爲傳入的參數:

//中間件的定義,使用了$role參數,限定用戶的角色
<?php

namespace App\Http\Middleware;
use Closure;

class RoleMiddleware
{
    /**
     * Run the request filter.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  string  $role
     * @return mixed
     */
    public function handle($request, Closure $next, $role)
    {
        if (! $request->user()->hasRole($role)) {
            // Redirect...
        }

        return $next($request);
    }

}

//在進行分配使用時,中間件名稱與參數經過冒號分割,多個參數使用逗號進行分割:
Route::put('post/{id}', ['middleware' => 'role:editor', function ($id) {
    //
}]);

收尾中間件,Terminable Middleware,在響應被返回到瀏覽器後,作一些收尾工做,好比說lavarel的session中間件將會把會話數據寫入存儲中。要實現收尾中間件,須要在中間件中定義terminate方法,並且,這種中間件必須被定義爲全局中間件:

<?php

namespace Illuminate\Session\Middleware;
use Closure;

class StartSession
{
    public function handle($request, Closure $next)
    {
        return $next($request);
    }

    public function terminate($request, $response)
    {
        // Store the session data...
    }
}

//深層次地,當調用terminate中間件方法時,laravel從service container中從新實例化一箇中間件類。若想要在使用handle和terminate時使用同一個實例,則須要在註冊該中間件到container中時,使用container的singleton方法。(具體如何操做這裏還沒講到)

7.控制器Controllers

先看一個例子:

<?php

namespace App\Http\Controllers;

use App\User;
use App\Http\Controllers\Controller;

class UserController extends Controller
{
    /**
     * Show the profile for the given user.
     *
     * @param  int  $id
     * @return Response
     */
    public function showProfile($id)
    {
        return view('user.profile', ['user' => User::findOrFail($id)]);
    }
}

控制器的命名空間,在指定route對應的控制器動做時,只需指定App\Http\Controllers以後的路徑名,由於默認地,RouteServiceProvider將會把routes文件載入到一個包含上述命名空間的路由組中。

在controller中分配中間件(這種方式比在路由中指定要更方便):

class UserController extends Controller
{
    /**
     * Instantiate a new UserController instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth'); //全部方法均適用

        $this->middleware('log', ['only' => [//只限於下列方法適用
            'fooAction',
            'barAction',
        ]]);

        $this->middleware('subscribed', ['except' => [//排除如下方法
            'fooAction',
            'barAction',
        ]]);
    }
}

RESTful資源訪問控制器,使用命令php artisan make:controller PhotoController --resource新建一個控制器:

//向該類控制器指定路由規則
Route::resource('photo', 'PhotoController');
//另外可使用下列方法限定該種路由表的範圍:
Route::resource('photo', 'PhotoController', ['only' => [ 'index', 'show' ]]); Route::resource('photo', 'PhotoController', ['except' => [ 'create', 'store', 'update', 'destroy' ]]);
Route::resource('photo', 'PhotoController', ['names' => [ 'create' => 'photo.build'//能夠經過names數組從新定義路由規則的名稱 ]]);
 
//這條路由規則默認地創建一下路由表:

對資源路由規則的參數的命名:

//默認地,lavarel將根據resource第一個參數,即資源名對參數進行命名
//好比資源名叫作user,那麼參數名就叫作user
//若是想更改這種行爲,使用如下方式:
Route::resource('user', 'AdminUserController', ['parameters' => [
    'user' => 'admin_user'
]]);
//下面這個方式將參數名改成單數形式,而非資源名的複數形式
Route::resource('users.photos', 'PhotoController', [
    'parameters' => 'singular'
]);
//或者用如下的方法,全局地設定參數名規則:
Route::singularResourceParameters();
Route::resourceParameters([
    'user' => 'person', 'photo' => 'image'
]);
//注意以上幾種方式的優先級:
//1.顯示地傳入resource的參數。2.全局設定的參數名。3.singular設置。4.默認值

注意:請將自定義的路由規則放於resource規則之上,由於可能會被resource規則覆蓋掉。

對控制器的依賴注入,服務容器service container被用來解析全部的controller,因此在controller中可使用type-hint方式指定方法所需的依賴類實例,這個依賴會自動被解析,而且注入到控制器類的實例中:

<?php

namespace App\Http\Controllers;

use App\Repositories\UserRepository;

class UserController extends Controller
{
    /**
     * The user repository instance.
     */
    protected $users;

    /**
     * Create a new controller instance.
     *
     * @param  UserRepository  $users
     * @return void
     */
    public function __construct(UserRepository $users)//在構造函數中的依賴注入,repository參見:這裏
    {
        $this->users = $users;
    }

    **
     * Store a new user.
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)//在方法中的依賴注入
    {
        $name = $request->input('name');

        //
    }

    /**
     * Update the specified user.
     *
     * @param  Request  $request
     * @param  string  $id
     * @return Response
     */
    public function update(Request $request, $id)//依賴注入的同時,還能夠接收路由規則傳進來的參數
    {
        //
    }
}

路由規則的緩存,請使用命令php artisan route:cache,將極快的提升註冊應用路由的速度(可是開發中若是更改了路由規則,請從新運行這個命令。若想刪除路由緩存,使用php artisan route:clear

8.請求對象Request

Request類的基本方法:

//對於http://domain.com/foo/bar,返回foo/bar
$uri = $request->path();
//url()和fullUrl()返回徹底的網址:
// Without Query String...
$url = $request->url();
// With Query String...
$url = $request->fullUrl();
$url = $request->fullUrlWithQuery(['bar' => 'baz']);
//對於http://domain.com/foo返回http://domain.com/foo?bar=baz

//is方法返回是否匹配某個uri模式:
if ($request->is('admin/*')) {
    //
}

//取請求的method:
$method = $request->method();
if ($request->isMethod('post')) {
    //
}

//取用戶的表單輸入:
$name = $request->input('name');
$name = $request->input('name', 'Sally');//第二個參數爲默認值
$name = $request->input('products.0.name');//這個和下面那個適用於forms with array inputs,這是什麼???
$names = $request->input('products.*.name');
//取json格式的輸入(請求頭必須有Content-Type:application/json):
$name = $request->input('user.name');//點號能夠取json的下層結構
if ($request->has('name')) {//判斷是否存在某輸入字段
    //
}
$input = $request->all();//取出全部的輸入參數,返回一個數組
$input = $request->only(['username', 'password']);//下面這四個是取輸入的一部分參數
$input = $request->only('username', 'password');
$input = $request->except(['credit_card']);
$input = $request->except('credit_card');
$name = $request->name;//也能夠這麼取name字段,順序是先以route規則中的參數,其次以請求體中的參數

//舊有的輸入,在表單出錯時,復如今用戶頁面上
$request->flash();//將輸入flash到session裏,在用戶下一次的請求中仍可訪問
$request->flashOnly(['username', 'email']);
$request->flashExcept('password');
//重定向加flash:
return redirect('form')->withInput();
return redirect('form')->withInput($request->except('password'));
//使用上一個請求中的old輸入:
$username = $request->old('username');//代碼裏使用
<input type="text" name="username" value="{{ old('username') }}">//blade模板中使用

//cookie:全部的lavarel的cookie都是加密的,而且用受權碼簽名
$value = $request->cookie('name');
$response = new Illuminate\Http\Response('Hello World');//新建一個cookie
$response->withCookie('name', 'value', $minutes);
return $response;
$response->withCookie(cookie()->forever('name', 'value'));//新建一個永久cookie,五年

//文件類操做
$file = $request->file('photo');//獲取一個上傳的文件對象UploadedFile的實例
if ($request->hasFile('photo')) {//判斷請求對象中是否包含一個文件
    //
}
if ($request->file('photo')->isValid()) {//判斷是否已經成功上傳該文件
    //
}
$request->file('photo')->move($destinationPath);//移動文件,從臨時上傳位置移走(這位置是根據php的配置決定的)
$request->file('photo')->move($destinationPath, $fileName);//移動文件而且重命名

9.響應對象Response

//相比於return一個字符串來講,響應對象可以提供更多的控制響應體的操做
use Illuminate\Http\Response;

Route::get('home', function () {
    return (new Response($content, $status))
                  ->header('Content-Type', $value);
});
Route::get('home', function () {//response是其工廠函數
    return response($content, $status)
                  ->header('Content-Type', $value);
});

//response對象的大部分方法是能夠級聯調用的
return response($content)
            ->header('Content-Type', $type) //使用header方法設置響應頭
            ->header('X-Header-One', 'Header Value')
            ->header('X-Header-Two', 'Header Value');
return response($content)
            ->withHeaders([//使用withHeaders方法設置多個響應頭域
                'Content-Type' => $type,
                'X-Header-One' => 'Header Value',
                'X-Header-Two' => 'Header Value',
            ]);

//使用cookie方法添加新的cookie值
//cookie方法的原型:cookie($name, $value, $minutes, $path, $domain, $secure, $httpOnly)
return response($content)
                ->header('Content-Type', $type)
                ->cookie('name', 'value');
//lavarel生成的cookie都是加密的,能夠將其關掉:
//位於App\Http\Middleware\EncryptCookies中
/**
 * The names of the cookies that should not be encrypted.
 *
 * @var array
 */
protected $except = [//此數組中的cookie值是不加密的。
    'cookie_name',
];

//當response方法不帶參數調用時,產生一個implementation of the Illuminate\Contracts\Routing\ResponseFactory contract
//在同時須要返回視圖和控制response的狀態和頭時,使用下列方法:
return response()
            ->view('hello', $data)
            ->header('Content-Type', $type);
//返回json數據,並自動設置Content-Type:application/json
return response()->json(['name' => 'Abigail', 'state' => 'CA']);
//使瀏覽器下載一個文件:
return response()->download($pathToFile);//第一個參數是文件的路徑
return response()->download($pathToFile, $name, $headers);//第二個是用戶看到的文件名,第三個是控制響應的header域
//直接在瀏覽器展現一個文件,而無需下載
return response()->file($pathToFile);
return response()->file($pathToFile, $headers);

//重定向的response
Route::get('dashboard', function () {
    return redirect('home/dashboard');//最簡單的方式,使用redirect方法
});
//在表單驗證失敗後,重定向至前一個頁面(注意,使用back的路由規則必須已經使用了web中間件
Route::post('user/profile', function () {
    // Validate the request...
    return back()->withInput();
});
//重定向至某個路由規則
return redirect()->route('login', ['id' => 1]);//第二個參數爲路由url參數
//重定向至某個控制器方法
return redirect()->action('UserController@profile', ['id' => 1]);
//重定向,而且把參數放進session中:
Route::post('user/profile', function () {
    // Update the user's profile...
    return redirect('dashboard')->with('status', 'Profile updated!');
});
@if (session('status'))
    <div class="alert alert-success">
        {{ session('status') }}
    </div>
@endif

//響應請求宏macro
//若想要自定義一個響應對象以便route和controller共用、重用,可使用Response facade:
<?php

namespace App\Providers;

use Response;
use Illuminate\Support\ServiceProvider;

class ResponseMacroServiceProvider extends ServiceProvider
{
    /**
     * Perform post-registration booting of services.
     *
     * @return void
     */
    public function boot()
    {
        Response::macro('caps', function ($value) {
            return Response::make(strtoupper($value));
        });
    }
}
//這樣,在route中就能夠用相應的函數名返回響應對象:
return response()->caps('foo');

10.視圖views

//決定view是否存在:
if (view()->exists('emails.customer')) {
    //
}

//傳參:
return view('greetings', ['name' => 'Victoria']);
return view('greeting')->with('name', 'Victoria');

//在全部的views中共享一個變量(在AppServiceProvider的service provider的boot方法中調用view()->share(' ', ' ');)
<?php

namespace App\Providers;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        view()->share('key', 'value');
    }

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

//view composer的使用場景:當view視圖被渲染時,它所綁定的類或者閉包函數將會被調用。當某個視圖須要每次在渲染時都要使用一個參數時,這種方式比較有效,在一個地方就能夠進行控制。
//首先提供一個service provider,在其中指明view composer:
<?php

namespace App\Providers;
use Illuminate\Support\ServiceProvider;

class ComposerServiceProvider extends ServiceProvider
{
    /**
     * Register bindings in the container.
     *
     * @return void
     */
    public function boot()
    {
        // Using class based composers...
        view()->composer(
            'profile', 'App\Http\ViewComposers\ProfileComposer'
        );

        // Using Closure based composers...
        view()->composer('dashboard', function ($view) {
            //
        });
    }

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}
//其次,創建一個文件夾App\Http\ViewComposers,保存composer類:
<?php

namespace App\Http\ViewComposers;

use Illuminate\View\View;
use Illuminate\Users\Repository as UserRepository;

class ProfileComposer
{
    /**
     * The user repository implementation.
     *
     * @var UserRepository
     */
    protected $users;

    /**
     * Create a new profile composer.
     *
     * @param  UserRepository  $users
     * @return void
     */
    public function __construct(UserRepository $users)
    {
        // Dependencies automatically resolved by service container...
        $this->users = $users;
    }

    /**
     * Bind data to the view.
     *
     * @param  View  $view
     * @return void
     */
    public function compose(View $view)//該方法在每次profile視圖被渲染時,都會調用
    {
        $view->with('count', $this->users->count());
    }
}
//其餘:綁定一個composer到多個視圖上:
view()->composer(
    ['profile', 'dashboard'],
    'App\Http\ViewComposers\MyViewComposer'
);
view()->composer('*', function ($view) {
    //
});

//最後還提到了一個叫作View Creators的東西,不知道啥意思:View creators are very similar to view composers; however, they are fired immediately when the view is instantiated instead of waiting until the view is about to render.(view什麼時候初始化,什麼時候渲染?區別是什麼)
//To register a view creator, use the creator method:

view()->creator('profile', 'App\Http\ViewCreators\ProfileCreator');

11.blade模板引擎

blade模板能夠編譯爲原聲php文件而且緩存起來,因此不會形成性能損失。

//layout模板文件
<!-- Stored in resources/views/layouts/master.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.master')

@section('title', 'Page Title') //注意作這個section的用法

@section('sidebar')//這裏可使得父模板運用子模板的section,即在父模板的基礎上擴展父模板的section
    @parent

    <p>This is appended to the master sidebar.</p>
@endsection

@section('content')
    <p>This is my body content.</p>
@endsection

//變量顯示方面:{{ }}能夠阻止XSS攻擊

//某些js框架使用{{ }}號,向前面添加@號能夠告訴blade不要解析這塊內容
<h1>Laravel</h1>
Hello, @{{ name }}.

//某些變量可能不存在或者沒定義,使用下列方式
{{ $name or 'Default' }}

//非轉義輸出
Hello, {!! $name !!}

//註釋:
{{-- This comment will not be present in the rendered HTML --}}

//棧功能:
@push('scripts')
    <script src="/example.js"></script>
@endpush
//調用棧:
<head>
    <!-- Head Contents -->
    @stack('scripts')
</head>

//service inject:
@inject('metrics', 'App\Services\MetricsService')
<div>
    Monthly Revenue: {{ $metrics->monthlyRevenue() }}.
</div>

//移除view緩存
php artisan view:clear

//【高級】還能夠自定義blade中使用的指令,好比定義一個@datetime($var):
<?php

namespace App\Providers;

use Blade;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Perform post-registration booting of services.
     *
     * @return void
     */
    public function boot()
    {
        Blade::directive('datetime', function($expression) {
            return "<?php echo with{$expression}->format('m/d/Y H:i'); ?>";
        });
        //Laravel's with helper function was used in this directive. The with helper simply returns the object / value it is given, allowing for convenient method chaining.
    }

    /**
     * Register bindings in the container.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}
相關文章
相關標籤/搜索