基础控制器

控制器定义

创建控制器命令:php artisan make:controller UserController
迁移数据命令:php artisan migrate
当迁移命令出现报错信息:PDOException::(“SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 1000 bytes”)
则需要配置app/Providers/ AppServiceProvider.php文件

  1. use Illuminate\Support\Facades\Schema;
  2. class AppServiceProvider extends ServiceProvider
  3. {
  4. public function boot()
  5. {
  6. //配置默认长度
  7. Schema::defaultStringLength(191);
  8. }
  9. }

命名空间

在定义控制器路由时不需要指定完整的控制器命名空间。因为 RouteServiceProvider 会在一个包含命名空间的路由组中加载路由文件,我们只需要指定类名中 App\Http\Controllers 命名空间之后的部分就可以了。
定义在路由文件中的内容实际都是在app\Providers\RouteServiceProvider.php进行了路由文件的引入后才能进行路由的定义。

<?php

namespace App\Providers;

use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Route;

class RouteServiceProvider extends ServiceProvider
{
    /**
     * This namespace is applied to your controller routes.
     *
     * In addition, it is set as the URL generator's root namespace.
     *
     * @var string
     */
    #protected $namespace = 'App\Http\Controllers\Photos';
    protected $namespace = 'App\Http\Controllers';
       */
    public function map()
    {

        $this->mapWebRoutes();

        //
    }
     /**
     * Define the "web" routes for the application.
     *
     * These routes all receive session state, CSRF protection, etc.
     *
     * @return void
     */
    protected function mapWebRoutes()
    {
        Route::middleware('web')
             ->namespace($this->namespace)
             ->group(base_path('routes/web.php'));
    }

通过命令artisan所创建的控制器,通常是会继承与App\Http\Controllers\Controller 。但是实际上我们是可以不用继承与这个类。只是这样我们可能就不能够很方便的使用middlewarevalidatedispatch方法。
以后在业务、功能我们就可以选择拆分来使用,提取公用操作类库,在统一模块下面进行使用操作。

单行为控制器

单个行为的控制器只需要创建一个__invoke方法

<?php

namespace App\Http\Controllers;

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

class ShowProfile extends Controller
{
    /**
     * 显示给定用户的资料.
     *
     * @param  int  $id
     * @return View
     */
    public function __invoke($id)
    {
        return view('user.profile', ['user' => User::findOrFail($id)]);
    }
}

当注册单个行为控制器的路由时,不需要指明方法:

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

控制器中间件

  1. 通过路由注册中间件

    Route::get('profile', 'UserController@show')->middleware('auth');
    
  2. 在控制器中指定中间件

    class UserController extends Controller
    {
     /**
      * 实例化一个新的控制器实例.
      *
      * @return void
      */
     public function __construct()
     {
         $this->middleware('auth');
    
         $this->middleware('log')->only('index');
    
         $this->middleware('subscribed')->except('store');
     }
    }
    
  3. 在控制器中使用闭包指定中间件

    $this->middleware(function ($request, $next) {
     // ...
    
     return $next($request);
    });
    

    请求

    接收请求

    通过依赖注入获取当前 HTTP 请求实例:在控制器上引入 Illuminate\Http\Request 类, 传入的请求实例将会由 服务容器 自动注入 ```php namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserController extends Controller { /**

 * 存储一个新用户。
 *
 * @param  Request  $request
 * @return Response
 */
public function store(Request $request)
{
    $name = $request->input('name');
}

}

**依赖注入 & 路由参数**:如果你的控制器需要从路由参数中获取数据,你应该在其他依赖项之后列入参数。举个例子,你的路由是这样定义的:
```php
Route::put('user/{id}', 'UserController@update');
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserController extends Controller
{
    /**
     * Update the specified user.
     *
     * @param  Request  $request
     * @param  string  $id
     * @return Response
     */
    public function update(Request $request, $id)
    {
        //
    }
}

通过闭包路由获取参数:你也可以在路由闭包中使用 Illuminate\Http\Request 类, 服务容器会自动的将请求参数注入到路由闭包中

use Illuminate\Http\Request;

Route::get('/', function (Request $request) {
    //
});

检索请求路径path 方法返回请求的路径信息。因此,如果接收到的请求目标http://domain.com/foo/bar,则 path 方法会返回 foo/bar

$uri = $request->path();

is 方法验证请求的路径是否与给定的模式匹配。使用此方法时,可以将 * 字符作为通配符:

if ($request->is('admin/*')) {
    //
}

检索请求URL:要获取请求的完整 url ,可以使用 url fullUrl 方法。 url 方法返回不带查询条件的 url 字符串,而 fullUrl 方法包含查询字符串:

// 没有查询字符串...
$url = $request->url();

// 带查询字符串...
$url = $request->fullUrl();

检索请求方法method 方法将会返回请求的 HTTP 动词。你也可以使用 isMethod 方法验证 HTTP 动词是否与给定的字符串匹配:

$method = $request->method();

if ($request->isMethod('post')) {
    //
}

接收数据

$input = $request->all();
$input = $request->input();
$query = $request->query();
$name = $request->input('name');
$name = $request->query('name');
//设置默认值
$name = $request->input('name', 'default');
$name = $request->query('name', 'Helen');
$name = $request->input('products.0.name');
$names = $request->input('products.*.name');
//只获取username password字段
$input = $request->only(['username', 'password']);
$input = $request->only('username', 'password');
//只获取除了credit_card的其他字段
$input = $request->except(['credit_card']);
$input = $request->except('credit_card');
//name存在
$request->has('name')
//name和email同时存在
$request->has(['name', 'email'])

// 判断name存在,并且不为空
$request->filled('name')

Session数据

//存储全部数据
$request->flash();
//只存储部分数据
$request->flashOnly(['username', 'email']);
//存储时排除部分数据
$request->flashExcept('password');
//携带所有请求数据
return redirect('form')->withInput();
//携带部分请求数据
return redirect('form')->withInput(
    $request->except('password')
);
$username = $request->old('username');

文件

file 方法返回 Illuminate\Http\UploadedFile 类的实例,该类继承了 PHP 的 SplFileInfo 类的同时也提供了各种与文件交互的方法。、

$file = $request->file('photo');

$file = $request->photo;
$request->hasFile('photo')
$request->file('photo')->isValid()
//获取文件绝对路径
$path = $request->photo->path();
//获取文件扩展名
$extension = $request->photo->extension();
//第一个参数为相对于文件系统配置的存储文件根目录的路径
$path = $request->photo->store('images');
//第二个参数表示存储文件的磁盘名称
$path = $request->photo->store('images', 's3');

//指定文件名
$path = $request->photo->storeAs('images', 'filename.jpg');
//指定文件名 和 存储磁盘
$path = $request->photo->storeAs('images', 'filename.jpg', 's3');

响应

Route::get('/', function () {
    return 'Hello World';
});
Route::get('/', function () {
    return [1, 2, 3];
});
return response($content)
            //添加响应头
            ->header('Content-Type', $type)
            ->header('X-Header-One', 'Header Value')
            ->header('X-Header-Two', 'Header Value');

return response($content)
            //添加响应头
            ->withHeaders([
                'Content-Type' => $type,
                'X-Header-One' => 'Header Value',
                'X-Header-Two' => 'Header Value',
            ]);
return response()
            ->view('hello', $data, 200)
            ->header('Content-Type', $type);
return response()->json([
    'name' => 'Abigail',
    'state' => 'CA'
]);
return response()
            ->json(['name' => 'Abigail', 'state' => 'CA'])
            ->withCallback($request->input('callback'));
return response()->download($pathToFile);

return response()->download($pathToFile, $name, $headers);

return response()->download($pathToFile)->deleteFileAfterSend();

重定向

Route::get('dashboard', function () {
    return redirect('home/dashboard');
});
Route::post('user/profile', function () {
    // 验证请求
    return back()->withInput();
});
return redirect()->route('login');
//携带路由参数
return redirect()->route('profile', ['id' => 1]);
return redirect()->action('HomeController@index');
//携带参数
return redirect()->action(
    'UserController@profile', ['id' => 1]
);
return redirect()->away('https://www.google.com');

RESTful 风格

定义:REST 是 “呈现状态转移(REpresentational State Transfer)” 的缩写。它是一种 API 的架构风格,在客户端和服务端之间通过呈现状态的转移来驱动应用状态的演进。
要让应用 RESTful 化,需要遵循以下约束。遵循了这些约束的分布式系统,就会拥有如下非功能属性:性能,伸缩性,易用性,扩展性,可见性,可移植性和可靠性。

  1. CS模式:CS 模式通过分离客户端和服务器端的关注点,让客户端不再关注数据的存储问题,从而提高客户端代码的可移植性。另一方面,服务器端不再关注用户界面和用户状态,从而变得更简单,提高了伸缩性。服务器端跟客户端可以独立开发,只要它们都遵守契约。
  2. 无状态:客户端上下文在多个请求之间是绝不会保存在服务器上的。每个请求必须包含必要的信息。无状态的服务器通过快速释放资源和简化实现提高了可伸缩性。可靠性使得从局部失败中恢复变得容易。很明显,监控系统不必通过考虑单个请求来判断请求的性质。 无状态服务器的一个缺点是降低了网络性能,因为所有需要的数据必须在每次请求中发送。
  3. 可缓存:REST 应用程序是 web 系统,因此客户端和中间层可以缓存响应。响应必须被定义为可缓存或不可缓存的,以防客户端重复使用旧数据导致降低可靠性。如果缓存中的陈旧数据与已生成的请求的数据显著不同,则由服务器处理请求。缓存可以消除一些客户端和服务器之间的交互,这就提升了可伸缩性、效率和通过减少平均延迟达到的用户可感知的性能。
  4. 统一的接口:使用统一的接口降低了系统复杂度和耦合度,让系统的不同部分可以独立演化。稍后会解释 URI,资源和超媒体是如何通过生成标准接口来提升用户交互可见性,降低系统复杂度,促进系统组件独立演化的。但是我们需要在效率方面做出妥协,毕竟消息是通过标准格式传输的,并不能满足所有应用对消息格式的要求。
  5. 分层的系统:分层系统通过约束组件的行为来降低系统复杂度,组件不能越过它们的媒介层去访问其它层。通过组件的阻断来保持层间的独立性。遗留的组件可以被封装成新的层,不让旧的客户端访问。媒介层可以通过负载均衡来提升伸缩性。分层系统存在的主要不足,是它给数据处理增加了一些额外的开销,增加了延迟,对用户体验有所影响。
  6. 按需编码:REST 允许客户端通过下载执行脚本来扩展它们的功能,简化了客户端,也提升了扩展性。但这同时也降低了可见性,所以这个约束不是必须遵循的。
  7. 元素:REST 提供了以下几种元素来构建无状态,可伸缩的 web API。
    1. HTTP协议
    2. HTTP动词
      1. 概念
        1. 幂等性:操作可以被重复执行,就算在失败以后。
        2. 安全性:对客户端来说操作不会产生副作用。
      2. HTTP动词分类
        1. GET :用来从服务器端读取状态。
        2. POST:用来在服务器端创建某种状态。
        3. PUT :用来在服务器端更新状态的。
        4. DELETE:用来在服务器端删除状态。
    3. 响应状态码:HTTP 在请求资源的响应里提供了元数据信息,也就是状态码
      1. 1XX — 元数据
      2. 2XX — 正确的响应
      3. 3XX — 重定向
      4. 4XX — 客户端错误
      5. 5XX — 服务端错误
    4. 头部信息:HTTP 在消息头部里为请求响应提供了额外信息
      1. 一般头部:在请求跟响应里都有,跟消息体里传输的数据没有关系。
      2. 请求头部:更多的是关于被请求资源或者客户端的信息。
      3. 响应头部:响应的额外信息。实体头部:消息体的额外信息,比如 content-length 或 MIMI-type。
    5. 资源:资源可以是由系统暴露出来的任何具有唯一标识的东西