“基本功能”的版本间的差异

来自tomtalk
跳转至: 导航搜索
单Action控制器
Tom讨论 | 贡献
依赖注入 & 控制器
第212行: 第212行:
 
===依赖注入 & 控制器===
 
===依赖注入 & 控制器===
  
通过构造方法注入#
+
====通过构造方法注入====
  
 
Laravel 中的控制器都是使用服务容器解析的。所以,你可以在控制器的构造方法里使用依赖注入。声明的依赖会自动注入到控制器实例中:
 
Laravel 中的控制器都是使用服务容器解析的。所以,你可以在控制器的构造方法里使用依赖注入。声明的依赖会自动注入到控制器实例中:
  
 +
<source lang="php">
 
<?php
 
<?php
  
第229行: 第230行:
 
     protected $users;
 
     protected $users;
  
    /**
 
    * Create a new controller instance.
 
    *
 
    * @param  UserRepository  $users
 
    * @return void
 
    */
 
 
     public function __construct(UserRepository $users)
 
     public function __construct(UserRepository $users)
 
     {
 
     {
第240行: 第235行:
 
     }
 
     }
 
}
 
}
Laravel 契约类也支持依赖注入。 有时,注入这些依赖可能会让应用程序有更好可测试性。
+
</source>
  
方法注入#
+
====方法注入====
  
 
除了在构造方法里注入,还可以在控制器方法里注入。一个常见的使用方式是将 Illuminate\Http\Request 实例注入到控制器方法里:
 
除了在构造方法里注入,还可以在控制器方法里注入。一个常见的使用方式是将 Illuminate\Http\Request 实例注入到控制器方法里:
  
 +
<source lang="php">
 
<?php
 
<?php
  
第254行: 第250行:
 
class UsersController extends Controller
 
class UsersController extends Controller
 
{
 
{
    /**
 
    * Store a new user.
 
    *
 
    * @param  Request  $request
 
    * @return Response
 
    */
 
 
     public function store(Request $request)
 
     public function store(Request $request)
 
     {
 
     {
 
         $name = $request->name;
 
         $name = $request->name;
 
 
         //
 
         //
 
     }
 
     }
 
}
 
}
 +
</source>
 +
 
如果路由包含参数,那么这些参数要列在这些依赖项之后。例如,如果路由是这样的:
 
如果路由包含参数,那么这些参数要列在这些依赖项之后。例如,如果路由是这样的:
  
 +
<source lang="php">
 
Route::put('users/{id}', 'UsersController@update');
 
Route::put('users/{id}', 'UsersController@update');
 +
</source>
 +
 
在控制器方法里,就要在 Illuminate\Http\Request 依赖声明之后,获取咱们的用户 ID:
 
在控制器方法里,就要在 Illuminate\Http\Request 依赖声明之后,获取咱们的用户 ID:
  
 +
<source lang="php">
 
<?php
 
<?php
  
第280行: 第275行:
 
class UsersController extends Controller
 
class UsersController extends Controller
 
{
 
{
    /**
 
    * Update the given user.
 
    *
 
    * @param  Request  $request
 
    * @param  string  $id
 
    * @return Response
 
    */
 
 
     public function update(Request $request, $id)
 
     public function update(Request $request, $id)
 
     {
 
     {
第292行: 第280行:
 
     }
 
     }
 
}
 
}
 +
</source>
  
 
==请求==
 
==请求==

2017年10月24日 (二) 09:14的版本

路由

简单的路由,RouteServiceProvider功能介绍。

// 简单路由
Route::get('/', function () {
    return view('welcome');
});
 
//为多重动作注册路由
Route::match(['get', 'post'], '/get-post', function () {
    return 'get and post';
});
 
Route::any('foo', function () {
    return 'any foo ' . url('foo') . ' ' . url('router');
});
 
//路由参数
Route::get('posts/{pid}/comments/{comment?}', function ($pId, $commentId = 'empty') {
    return "postId = $pId, comments = $commentId";
});
 
//正则表达式限制参数。也可为参数设定全局规则pattern filter。
Route::get('user/{id}/{name?}', function ($id, $name = 'empty') {
    return "userId = $id, name = $name";
})->where(['id' => '[0-9]?', 'name' => '[a-z]+']);
 
//命名路由
Route::get('user/list', ['as' => 'userList', function () {
    return 'name router: ' . route('userList');
}]);
 
Route::get('user/info/{id?}', 'UserController@UserInfo')->name('userInfo');
 
//路由群组:中间件、命名空间、子域名、前缀
Route::group([
    /*'middleware' => 'auth',*/
    'namespace' => 'Member',
    'domain' => '{account}.tomtalk.net',
    'prefix' => 'member'], function () {
    Route::get('{id?}', 'MemberController@detail');
});
 
//CSRF保护:试了一下,还是不知道怎么用。
 
//路由模型绑定
Route::get('user/model/{user}', 'UserController@UserModel')->name('userModel');
 
//请求方法伪造 - echo method_field('PUT')
 
//抛出404错误 - abort(404)

中间件

中间件用来过滤项目中的 HTTP 请求,实际上 Laravel 项目中大量使用了中间件。例如,Laravel 中有一个验证用户是否认证的中间件,如果用户没认证,就跳转到登录页面;如果认证了,就会允许进一步的操作。

当然,中间件的作用不只在认证上。CORS 中间件负责给项目中的响应设定正确的表头(Headers );日志中间件负责记录项目中处理的所有请求信息。

Laravel 框架中包含了几个中间件,包括负责处理认证和 CSRF 保护的。所有这些中间件位于 app/Http/Middleware 目录下。

创建一个中间件
php artisan make:middleware OldMiddleware
public function handle($request, Closure $next)
{
    if ($request->input('age') <= 200) {
        return redirect('home');
    }
 
    return $next($request);
}
前置中间件/后置中间件
public function handle($request, Closure $next)
{
    // 运行动作
 
    return $next($request);
}
 
public function handle($request, Closure $next)
{
    $response = $next($request);
 
    // 运行动作
 
    return $response;
}


全局中间件

若是希望每个HTTP请求都经过一个中间件,只要将中间件的类加入到app/Http/Kernel.php的$middleware属性清单列表中。


为路由指派中间件


中间件参数


Terminable中间件

有些时候中间件需要在HTTP响应被发送到浏览器之后才运行,例如,Laravel内置的「session」中间件存储的session数据是在响应被发送到浏览器之后才进行写入的。想要做到这一点,你需要定义中间件为「terminable」

控制器

基础控制器

//一旦你指定了控制器路由的名称,则可以很容易地生成能实现该行为的URL。
$url = route('name');
 
//你也可以使用action辅助函数生成指向控制器行为的URL。
$url = action('FooController@method');
 
//你可以使用Route facade的currentRouteAction方法取到正在运行的控制器行为名称。
$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']]);
        $this->middleware('subscribed', ['except' => ['fooAction', 'barAction']]);
    }
}

RESTful资源控制器

资源控制器就是指包含index、create、store、show、edit、update和destroy这7个方法的控制器。之所以称为「资源控制器」,是因为这7个方法包括了操作某个资源所需的全部基本操作,也就是CRUD操作。

Route::resource('photos', 'PhotosController');
 
//部分资源路由
Route::resource('photos', 'PhotosController', ['only' => ['index', 'show']]);
Route::resource('photos', 'PhotosController', ['except' => ['create', 'store', 'update', 'destroy']]);
 
//命名资源路由
Route::resource('photos', 'PhotosController', ['names' => ['create' => 'photo.build']]);
 
//嵌套资源
Route::resource('photos.comments', 'PhotoCommentController');
 
//附加资源控制器。如果想在资源控制器中默认的资源路由之外加入其它额外路由,则应该在调用Route::resource之前定义这些路由。否则,由resource方法定义的路由可能会不小心覆盖你附加的路由:
Route::get('photos/popular', 'PhotosController@method');
Route::resource('photos', 'PhotosController');
 
//隐式控制器
Route::controller('users', 'UserController');

单Action控制器

有时,一个控制器只有唯一的一个方法,那么这时只要在控制器中定义一个 __invoke 方法就行:

<?php
 
namespace App\Http\Controllers;
 
use App\User;
use App\Http\Controllers\Controller;
 
class ShowProfile extends Controller
{
    /**
     * Show the profile for the given user.
     *
     * @param  int  $id
     * @return Response
     */
    public function __invoke($id)
    {
        return view('users.profile', ['user' => User::findOrFail($id)]);
    }
}

指向这个单 Action 控制器的路由,定义起来就变成下面这样了:

Route::get('users/{id}', 'ShowProfile');

依赖注入 & 控制器

通过构造方法注入

Laravel 中的控制器都是使用服务容器解析的。所以,你可以在控制器的构造方法里使用依赖注入。声明的依赖会自动注入到控制器实例中:

<?php
 
namespace App\Http\Controllers;
 
use App\Repositories\UserRepository;
 
class UsersController extends Controller
{
    /**
     * The user repository instance.
     */
    protected $users;
 
    public function __construct(UserRepository $users)
    {
        $this->users = $users;
    }
}

方法注入

除了在构造方法里注入,还可以在控制器方法里注入。一个常见的使用方式是将 Illuminate\Http\Request 实例注入到控制器方法里:

<?php
 
namespace App\Http\Controllers;
 
use Illuminate\Http\Request;
 
class UsersController extends Controller
{
    public function store(Request $request)
    {
        $name = $request->name;
        //
    }
}

如果路由包含参数,那么这些参数要列在这些依赖项之后。例如,如果路由是这样的:

Route::put('users/{id}', 'UsersController@update');

在控制器方法里,就要在 Illuminate\Http\Request 依赖声明之后,获取咱们的用户 ID:

<?php
 
namespace App\Http\Controllers;
 
use Illuminate\Http\Request;
 
class UsersController extends Controller
{
    public function update(Request $request, $id)
    {
        //
    }
}

请求

获取请求

要通过依赖注入的方式获取HTTP请求的实例,就必须在控制器的构造器或方法中,使用Illuminate\Http\Request类型提示。

use Illuminate\Http\Request;
 
class UserController extends Controller
{
    public function store(Request $request)
    {
        $name = $request->input('name');
        //
    }
}

如果控制器方法也有输入数据是从路由参数传入的,只需将路由参数置于其它依赖之后。

public function update(Request $request, $id)
{
    //
}
 
//基本请求信息
$uri = $request->path();  //返回请求的URI
$url = $request->url(); //获取完整的网址
 
//获取请求的方法
$method = $request->method();
if ($request->isMethod('post')) {
    //
}

获取输入数据

$name = $request->input('name');
 
$name = $request->name; //使用属性访问用户输入
 
//你可以在input方法的第二个参数中传入一个默认值。当请求的输入数据不存在于此次请求时,就会返回默认值:
$name = $request->input('name', 'Sally');
 
//确认是否有输入值
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');
 
//将输入数据闪存至Session
$request->flash();
$request->flashOnly('username', 'email');
$request->flashExcept('password');
 
//闪存输入数据至Session后重定向
return redirect('form')->withInput();
return redirect('form')->withInput($request->except('password'));
 
//获取旧输入数据
$username = $request->old('username');
{{ old('username') }}

Cookies

$value = $request->cookie('name');
 
//将新的 Cookie 附加到响应
$response = new Illuminate\Http\Response('Hello World');
$response->withCookie(cookie('name', 'value', $minutes));
return $response;
 
//如果要创建一个可长期存在,为期五年的 cookie。
$response->withCookie(cookie()->forever('name', 'value'));

上传文件

$file = $request->file('photo');
 
//确认上传的文件是否存在:
if ($request->hasFile('photo')) {
    //
}
 
//确认上传的文件是否有效
if ($request->file('photo')->isValid()) {
    //
}
 
//移动上传的文件
$request->file('photo')->move($destinationPath);
$request->file('photo')->move($destinationPath, $fileName);

视图

判断view是否存在

// 这个可以判断相应的view是不是存在的
if (View::exists('pages.index'))
    return view('pages.index');
else
    return 'No view available';

向 view 传递数据

// 表示 $users 这个变量会传递到view中。
return view('admin.users.index', compact('users'));
 
//要传递两个变量,分别是text和name。
return view('pages.index', ['text' => '<b>Laravel</b>', 'name' => 'Nicole']);

另一种向 view 传递数据的方法

return view('pages.index')
    ->with('text', '<b>Laravel</b>')
    ->with('name', 'Nicole');

视图组件

用于每次渲染某些视图时绑定数据。

view()->composer(['profile', 'dashboard'], 'App\Http\ViewComposers\MyViewComposer');

视图的 composer 方法可以接受 * 作为通配符,所以你可以对所有视图附加 composer。如下:

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

视图创建者

视图创建者几乎和视图组件运作方式一样;只是视图创建者会在视图初始化后就立即运行,而不是像视图组件一样要一直等到视图即将被渲染完成时才会被运行。要注册一个创建者,只要使用 creator 方法即可:

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

blade模板

所有 Blade 视图都会被编译缓存成普通的 PHP 代码,一直到它们被更改为止。这代表 Blade 基本不会对你的应用程序生成负担。

@extends('layouts.master')
 
@section('title', 'LaravelExample')
 
@section('sidebar')
    @parent
 
    <div>
        sidebar
    </div>
@endsection
 
@section('content')
    <h3>变量的使用</h3>
    <p>目前的 UNIX 时间戳为 {{ $time }}<p>目前的 UNIX 时间戳为 {{ time() }}<p>目前的 UNIX 时间戳为 @{{ time() }}<p>My name is {{ $name or 'Default' }}.
    <p>My name is {{ $html or 'html' }}.
    <p>My name is {!! $html or 'html' !!}.
 
    {{-- @符号如何显示 --}}
 
    <h3>include</h3>
    @include('usersList', ['users' => $users])
 
    <h3>each</h3>
    @each('userInfo', $users, 'name')
 
    {{-- 服务注入 --}}
 
    <h3>自定义模板指令</h3>
    @datetime(new Datetime())
@endsection

blade layout

上面的各种view,主要讲到了三个指令,分别是@extends、@yield('body'),@section。

@extends简单,主要是在子view中用,表示要去使用哪个layout。

@yield('body')是在layout中用,有点像在埋一个点,等着子view来放真正的内容。

@section在子view里真正放yield内容的地方。

服务注入

@inject命令可以取出Laravel服务容器中的服务。传递给@inject的第一个参数为置放该服务的变量名称,而第二个参数为你想要解析的服务的类或是接口的名称:

@inject('metrics', 'App\Services\MetricsService')
 
<div>
    每月收入:{{$metrics->monthlyRevenue()}}</div>