PHP经验分享Lumen程序员技术栈

hello lumen

2019-05-07  本文已影响6人  半亩房顶

前言

版本信息如下

"php": ">=7.1.3",
"laravel/lumen-framework": "5.8.*",

我参考的是5.6的文档,英语比较自信的小伙伴可以去找下5.8的英文版
https://learnku.com/docs/lumen/5.6/install/1924
那么,开始吧

目录

大家可以有选择的看本文:

安装

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;
    }
}

测试一下,貌似有报错,这个自然,因为中间件需要手动注册

注册中间件

$app->middleware([
   App\Http\Middleware\OldMiddleware::class
]);
$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',
        ]]);
    }
}

依赖注入与控制器

<?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;
    }
}
<?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 请求的方法,下面是该类的几个实用方法:

path 方法会返回请求的 URI,如果请求的目标是 http://domain.com/foo/barpath 方法将会返回 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();

如果你想获取数据的子集, 你可以使用 onlyexcept 方法,这两个方法都接受单个 数组 或动态列表作为参数:

$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 方法会自动将标头的 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使用速查-基础部分


欢迎大家关注我的公众号


半亩房顶
上一篇 下一篇

猜你喜欢

热点阅读