基础控制器
控制器定义
创建控制器命令: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文件
use Illuminate\Support\Facades\Schema;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
//配置默认长度
Schema::defaultStringLength(191);
}
}
命名空间
在定义控制器路由时不需要指定完整的控制器命名空间。因为 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 。但是实际上我们是可以不用继承与这个类。只是这样我们可能就不能够很方便的使用middleware,validate和dispatch方法。
以后在业务、功能我们就可以选择拆分来使用,提取公用操作类库,在统一模块下面进行使用操作。
单行为控制器
单个行为的控制器只需要创建一个__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');
控制器中间件
通过路由注册中间件
Route::get('profile', 'UserController@show')->middleware('auth');
在控制器中指定中间件
class UserController extends Controller { /** * 实例化一个新的控制器实例. * * @return void */ public function __construct() { $this->middleware('auth'); $this->middleware('log')->only('index'); $this->middleware('subscribed')->except('store'); } }
在控制器中使用闭包指定中间件
$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 化,需要遵循以下约束。遵循了这些约束的分布式系统,就会拥有如下非功能属性:性能,伸缩性,易用性,扩展性,可见性,可移植性和可靠性。
- CS模式:CS 模式通过分离客户端和服务器端的关注点,让客户端不再关注数据的存储问题,从而提高客户端代码的可移植性。另一方面,服务器端不再关注用户界面和用户状态,从而变得更简单,提高了伸缩性。服务器端跟客户端可以独立开发,只要它们都遵守契约。
- 无状态:客户端上下文在多个请求之间是绝不会保存在服务器上的。每个请求必须包含必要的信息。无状态的服务器通过快速释放资源和简化实现提高了可伸缩性。可靠性使得从局部失败中恢复变得容易。很明显,监控系统不必通过考虑单个请求来判断请求的性质。 无状态服务器的一个缺点是降低了网络性能,因为所有需要的数据必须在每次请求中发送。
- 可缓存:REST 应用程序是 web 系统,因此客户端和中间层可以缓存响应。响应必须被定义为可缓存或不可缓存的,以防客户端重复使用旧数据导致降低可靠性。如果缓存中的陈旧数据与已生成的请求的数据显著不同,则由服务器处理请求。缓存可以消除一些客户端和服务器之间的交互,这就提升了可伸缩性、效率和通过减少平均延迟达到的用户可感知的性能。
- 统一的接口:使用统一的接口降低了系统复杂度和耦合度,让系统的不同部分可以独立演化。稍后会解释 URI,资源和超媒体是如何通过生成标准接口来提升用户交互可见性,降低系统复杂度,促进系统组件独立演化的。但是我们需要在效率方面做出妥协,毕竟消息是通过标准格式传输的,并不能满足所有应用对消息格式的要求。
- 分层的系统:分层系统通过约束组件的行为来降低系统复杂度,组件不能越过它们的媒介层去访问其它层。通过组件的阻断来保持层间的独立性。遗留的组件可以被封装成新的层,不让旧的客户端访问。媒介层可以通过负载均衡来提升伸缩性。分层系统存在的主要不足,是它给数据处理增加了一些额外的开销,增加了延迟,对用户体验有所影响。
- 按需编码:REST 允许客户端通过下载执行脚本来扩展它们的功能,简化了客户端,也提升了扩展性。但这同时也降低了可见性,所以这个约束不是必须遵循的。
- 元素:REST 提供了以下几种元素来构建无状态,可伸缩的 web API。
- HTTP协议
- HTTP动词
- 概念
- 幂等性:操作可以被重复执行,就算在失败以后。
- 安全性:对客户端来说操作不会产生副作用。
- HTTP动词分类
- GET :用来从服务器端读取状态。
- POST:用来在服务器端创建某种状态。
- PUT :用来在服务器端更新状态的。
- DELETE:用来在服务器端删除状态。
- 概念
- 响应状态码:HTTP 在请求资源的响应里提供了元数据信息,也就是状态码
- 1XX — 元数据
- 2XX — 正确的响应
- 3XX — 重定向
- 4XX — 客户端错误
- 5XX — 服务端错误
- 头部信息:HTTP 在消息头部里为请求响应提供了额外信息
- 一般头部:在请求跟响应里都有,跟消息体里传输的数据没有关系。
- 请求头部:更多的是关于被请求资源或者客户端的信息。
- 响应头部:响应的额外信息。实体头部:消息体的额外信息,比如 content-length 或 MIMI-type。
- 资源:资源可以是由系统暴露出来的任何具有唯一标识的东西