hello lumen
前言
版本信息如下
"php": ">=7.1.3",
"laravel/lumen-framework": "5.8.*",
我参考的是5.6的文档,英语比较自信的小伙伴可以去找下5.8的英文版
https://learnku.com/docs/lumen/5.6/install/1924
那么,开始吧
目录
大家可以有选择的看本文:
- 安装
- 配置
- 路由
- 中间件
- 控制器
- HTTP Requests
- HTTP Response
- 总结
安装
lumen使用composer做依赖管理,所以首先需要安装composer
通过Lumen安装器
首先,使用Composer下载Lumen安装器:
composer global require "laravel/lumen-installer"
确保~/.composer/vendor/bin在系统路径PATH中,否则不能在命令行调用lumen命令。
安装完成后,只需简单通过lumen new命令就可以在当前目录下创建一个新的Lumen应用,例如,lumen new blog将会创建一个名为blog的Lumen安装目录,该目录中已经包含了所有Lumen依赖。该安装方法比通过Composer安装要快很多:
lumen new blog
通过Composer Create-Project安装
你还可以在终端中通过Composer的create-project命令来安装Lumen:
composer create-project --prefer-dist laravel/lumen blog
运行下试试
可以使用 Laravel Homestead 虚拟机,Laravel Valet ,或者内置的 PHP 开发服务器:
php -S localhost:8088 -t public
或者自己配置nginx,输入地址到public文件夹运行
成功后可以看到lumen版本信息
配置
记得不要把这个文件上传到git!!!
记得不要把这个文件上传到git!!!
记得不要把这个文件上传到git!!!
环境配置在.env
文件中,而我关注的配置项如下,之后有遇上的了再更新
APP_NAME=Lumen
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost
APP_TIMEZONE=UTC
...其他配置
DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=test
DB_USERNAME=test
DB_PASSWORD=test
路由
配置路由
路由信息是在routes/web.php文件中配置的,文件中有一些预置内容如下:
$router->get('/', function () use ($router) {
return $router->app->version();
});
还是很易懂的,尝试一个hello world
$router->get('/index', [
//'middleware' => 'auth', 定义中间件
'as' => 'index', 'uses' => 'IndexController@indexAction'
//这里as 是一种命名,之后就可以route('index')定位到 IndexController@indexAction
]);
然后在app/Http/Controllers下新建IndexController文件,以及indexAction函数
输入http://localhost:8088/index
可以看到自定义的输出 hello lumen
生成URL
生成指定的路由地址或者重定向是肯定会用到的,可以如下操作
$router->get('/getindex', function () {
//return redirect()->route('index');
return route('index', ['id' => 1]);
});
路由组
lumen中还支持路由组的方式
实现中间件
、命名空间
、路由前缀
等功能的批量处理,也是非常易懂,可以看文后的链接详细查看
中间件
定义中间件
中间件放在app/Http/Middleware
目录内,它类似于一种过滤器
可以用内置的ExampleMiddleware来测试下
<?php
namespace App\Http\Middleware;
use Closure;
class ExampleMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
echo 'middleware\n';
return $next($request);
}
}
前置 & 后置 中间件
中间件先执行还是后执行时取决于中间件本身
如此我们可以改写下ExampleMiddleware
<?php
namespace App\Http\Middleware;
use Closure;
class ExampleMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
echo 'middleware before\n';
return $next($request);
}
}
并添加后置中间件
<?php
namespace App\Http\Middleware;
use Closure;
class Example2Middleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$response = $next($request);
echo 'middleware after \n';
return $response;
}
}
测试一下,貌似有报错,这个自然,因为中间件需要手动注册
注册中间件
- 全局中间件
若是希望中间件在应用处理每个 HTTP 请求期间运行,只需要在bootstrap/app.php
文件中的$app->middleware()
方法中列出这个中间件:
$app->middleware([
App\Http\Middleware\OldMiddleware::class
]);
- 为路由分配中间件
如果你想将中间件分配给特定的路由,首先需要在bootstrap/app.php
文件中调用$app->routeMiddleware()
方法时为中间件分配一个简短的键:
$app->routeMiddleware([
'auth' => App\Http\Middleware\Authenticate::class,
]);
检查一下分配的中间件:
$router->get('/index', [
'middleware' => ['ExampleMiddleware', 'Example2Middleware'],
'as' => 'index', 'uses' => 'IndexController@indexAction'
]);
测试一下,done!输出如下:
middleware before
hello lumen
middleware after
中间件还可以添加参数
<?php
namespace App\Http\Middleware;
use Closure;
class RoleMiddleware
{
/**
* 运行请求过滤
*
* @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)) {
// 重定向...
}
return $next($request);
}
}
//传参方式如下:
$router->put('post/{id}', ['middleware' => 'role:editor', function ($id) {
//
}]);
Terminable 中间件
有时中间件可能需要在 HTTP 响应发送到浏览器之后处理一些工作。例如,「session」中间件会在响应发送到浏览器之后将会话数据写入存储器中。想要做到这一点,你需要定义一个名为「terminable」的方法。
<?php
namespace Illuminate\Session\Middleware;
use Closure;
class StartSession
{
public function handle($request, Closure $next)
{
return $next($request);
}
public function terminate($request, $response)
{
// 存储 session 数据...
}
}
这个暂时没有体会,可以后续交流下。
下面来看控制器
控制器
控制器中间件
除了在路由中定义中间件之外,还可以在控制器中注册中间件,甚至为某些方法配置中间件
class UserController extends Controller
{
/**
* 实例化一个新的 UserController 实例.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
//这个auth,就是你注册中间件时的键名
//'auth' => App\Http\Middleware\Authenticate::class,
$this->middleware('log', ['only' => [
'fooAction',
'barAction',
]]);
$this->middleware('subscribed', ['except' => [
'fooAction',
'barAction',
]]);
}
}
依赖注入与控制器
- 构造器注入
Lumen 使用 服务容器 来解析所有的控制器的依赖注入。因此,你可以在控制器的构造函数中使用类型提示需要的任何依赖。这些依赖将会自动的解析并注入到控制器实例中:
<?php
namespace App\Http\Controllers;
use App\Repositories\UserRepository;
class UserController extends Controller
{
/**
* 用户存储库实例
*/
protected $users;
/**
* 新建一个控制器实例
*
* @param UserRepository $users
* @return void
*/
public function __construct(UserRepository $users)
{
$this->users = $users;
}
}
- 方法注入
除了构造器注入以外,你也可以在你的控制器方法中使用类型提示依赖项。例如,在某个方法中添加 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');
//
}
}
如果你想在控制器里获取路由参数,只需要在路由之后列出参数即可。 例如,你的路由这样来定义:
$router->put('user/{id}', 'UserController@update');
你可以像下面的例子一样定义你的控制器,用类型提示注入 Illuminate\Http\Request 类和你的路由参数 id :
<?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)
{
//
}
}
下面来看 request
HTTP Requests
基本请求信息
Illuminate\Http\Request
实例继承了 Symfony\Component\HttpFoundation\Request
类,并提供了多种检查 HTTP 请求的方法,下面是该类的几个实用方法:
- 获取请求的 URI
path
方法会返回请求的 URI,如果请求的目标是 http://domain.com/foo/bar
, path
方法将会返回 foo/bar
:
$uri = $request->path();
is
方法可以校验接收到的请求 URI 是否与指定规则匹配,你可以使用 *
符号作为通配符:
if ($request->is('admin/*')) {
//
}
如果要获取完整的 URL 而不是 URI,可以使用 url
或者 fullUrl
方法:
// 不包含请求参数
$url = $request->url();
// 包含请求参数
$url = $request->fullUrl();
- 获取请求的方法
method
方法将会返回请求的 HTTP 动作,你可以使用 isMethod
方法校验 HTTP 动作是否与指定字符串匹配:
$method = $request->method();
if ($request->isMethod('post')) {
//
}
PSR-7 请求
PSR-7 标准规定了 HTTP 消息接口包含了请求及响应,如果你想获得 PSR-7 的请求实例,就需要先安装几个库,Laravel 使用 Symfony 的 HTTP 消息桥接组件,将原 Laravel 的请求及响应转换至 PSR-7 所支持的实现:
composer require symfony/psr-http-message-bridge
composer require zendframework/zend-diactoros
安装完这些库后,你就可以在路由或控制器中,简单的对请求类型使用类型提示来获取 PSR-7 请求:
use Psr\Http\Message\ServerRequestInterface;
$router->get('/', function (ServerRequestInterface $request) {
//
});
如果你从路由或控制器返回了一个 PSR-7 的响应实例,那么它会被框架自动转换回 Laravel 的响应实例并显示。
获取输入数据
- 获取指定输入值
你可以通过 Illuminate\Http\Request
实例,使用几个简单的方法来获取所有的用户输入数据,而不需要担心请求的 HTTP 动作,因为它们的获取方式是相同的:
$name = $request->input('name');
你可以在 input
方法的第二个参数中传入一个默认值,当请求参数不存在时,就会返回默认值:
$name = $request->input('name', 'Sally');
当数据是以数组形式输入时,你可以使用 「点」符号来获取数组:
$name = $request->input('products.0.name');
$names = $request->input('products.*.name');
- 确认输入值是否存在
你可以通过 has
方法判断输入值是否存在,输入值存在时 has
方法将会返回 true
:
if ($request->has('name')) {
//
}
当给定一个数组时, has
方法将确定是否所有指定值都存在:
if ($request->has(['name', 'email'])) {
//
}
如果你想确定请求中是否存在值并且不为空,可以使用 filled
方法:
if ($request->filled('name')) {
//
}
- 获取所有输入数据
你可以使用 all
方法以 数组
形式获取所有的输入数据:
$input = $request->all();
- 获取部分输入数据
如果你想获取数据的子集, 你可以使用 only
和 except
方法,这两个方法都接受单个 数组
或动态列表作为参数:
$input = $request->only(['username', 'password']);
$input = $request->only('username', 'password');
$input = $request->except(['credit_card']);
$input = $request->except('credit_card');
文件上传
- 获取上传文件
你可以使用 Illuminate\Http\Request
实例中的 file
方法获取上传的文件, file
方法返回的对象是 Symfony\Component\HttpFoundation\File\UploadedFile
类的实例,这个类继承了 PHP 的 SplFileInfo
类,并且提供了多种与文件交互的方法:
$file = $request->file('photo');
你可以使用 hasFile
方法确认上传的文件是否存在:
if ($request->hasFile('photo')) {
//
}
- 验证上传是否成功
除了检查文件是否存在之外,你还可以通过 isValid
方法验证上传是否存在问题:
if ($request->file('photo')->isValid()) {
//
}
- 移动上传文件
要将上传的文件移动到新的位置,你应该使用 move
方法,这个方法会将文件从临时位置(由你的 PHP 配置决定)移动到你指定永久保存位置:
$request->file('photo')->move($destinationPath);
$request->file('photo')->move($destinationPath, $fileName);
- 其他上传文件方法
UploadedFile
实例还有很多其他可用的方法,可以到 该类的 API 文档 了解这些方法的详细信息。
下面是Response
HTTP Response
基本响应
当然,所有的路由及控制器必须返回某个类型的响应,并发送回用户的浏览器。Laravel 提供了几种不同的方法来返回响应。最基本的响应就是从路由或控制器简单的返回一个字符串:
$router->get('/', function () {
return 'Hello World';
});
指定的字符串会被框架自动转换成 HTTP 响应。
- 响应对象
但是,对于大多数路由和控制器行为操作,你将返回完整的 Illuminate\Http\Response
实例。 返回完整的 Response
实例允许你自定义响应的 HTTP 状态码和标题。 一个 Response
实例继承自 Symfony\Component\HttpFoundation\Response
类,并且提供了多种构建 HTTP 响应的方法:
use Illuminate\Http\Response;
$router->get('home', function () {
return (new Response($content, $status))
->header('Content-Type', $value);
});
为了方便起见,你可以使用 response
辅助函数:
$router->get('home', function () {
return response($content, $status)
->header('Content-Type', $value);
});
注意: 有关
Response
方法的完整列表可以参照 API 文档 以及 Symfony API 文档。
- 附加标头至响应
大部份的响应方法是可链式调用的,这让你可以顺畅的创建响应。举例来说,你可以在响应发送给用户之前,使用 header
方法增加一系列的标头至响应:
return response($content)
->header('Content-Type', $type)
->header('X-Header-One', 'Header Value')
->header('X-Header-Two', 'Header Value');
或者你可以使用 withHeaders
方法来设置数组标头:
return response($content)
->withHeaders([
'Content-Type' => $type,
'X-Header-One' => 'Header Value',
'X-Header-Two' => 'Header Value',
]);
其它响应类型
使用辅助函数 response
可以轻松的生成其它类型的响应实例。当你调用辅助函数 response
且不带任何参数时,将会返回 Illuminate\Contracts\Routing\ResponseFactory
contract 的实现。此 Contract 提供了一些有用的方法来生成响应。
- JSON 响应
json
方法会自动将标头的 Content-Type
设置为 application/json
,并通过 PHP 的 json_encode
函数将指定的数组转换为 JSON:
return response()->json(['name' => 'Abigail', 'state' => 'CA']);
你可以选择提供一个状态码和一个额外的标题数组:
return response()->json(['error' => 'Unauthorized'], 401, ['X-Header-One' => 'Header Value']);
如果你想创建一个 JSONP 响应,则可以使用 json
方法并加上 setCallback
方法:
return response()
->json(['name' => 'Abigail', 'state' => 'CA'])
->setCallback($request->input('callback'));
- 文件下载
download
方法可以用于生成强制让用户的浏览器下载指定路径文件的响应。download
方法接受文件名称作为方法的第二个参数,此名称为用户下载文件时看见的文件名称。最后,你可以传递一个 HTTP 标头的数组作为第三个参数传入该方法:
return response()->download($pathToFile);
return response()->download($pathToFile, $name, $headers);
注意: 管理文件下载的扩展包 Symfony HttpFoundation,要求下载文件必须是 ASCII 文件名。
重定向
重定向响应是类 Illuminate\Http\RedirectResponse
的实例,并且包含用户要重定向至另一个 URL 所需的标头。有几种方法可以生成 RedirectResponse
的实例。最简单的方式就是通过全局的 redirect
辅助函数:
$router->get('dashboard', function () {
return redirect('home/dashboard');
});
- 重定向至命名路由
当你调用 redirect
辅助函数且不带任何参数时,将会返回 Illuminate\Routing\Redirector
的实例,你可以对该 Redirector
的实例调用任何方法。举个例子,要生成一个 RedirectResponse
到一个命名路由,你可以使用 route
方法:
return redirect()->route('login');
如果你的路由有参数,则可以将参数放进 route
方法的第二个参数:
// 重定向到以下 URI: profile/{id}
return redirect()->route('profile', ['id' => 1]);
如果你要重定向至路由且路由的参数为 Eloquent 模型的「ID」,则可以直接将模型传入,ID 将会自动被提取:
return redirect()->route('profile', [$user]);
总结
整体感觉,结构清晰易懂,使用很舒服,中间件和路由的设计很是方便了开发和管理。
还有laravel和lumen中,据说非常好用的Eloquent ORM,之后会单独写文章来学习。
本文总归到底只是一份入门,具体和更深度的内容,需要之后具体的挖掘了。
抛砖引玉,希望大家能够一起学习,共同进步。
谢谢
参考文件
路由
中间件
Eloquent ORM快速入门
全面理解 ActiveRecord
Eloquent ORM使用速查-基础部分
欢迎大家关注我的公众号