精华内容
下载资源
问答
  • Lumen

    2021-01-08 12:24:18
    <p>Is it possible to have migrations-generator in Lumen too? <p>trying to use it in Lumen but failed. <p><img alt="migrations-generator-error" src=...
  • lumen

    2019-09-21 23:59:09
    HTTP路由 基本路由 路由参数 必填参数 可选参数 正则表达式约束 命名路由 路由组 ...最基本的Lumen路由仅接受URL和一个Closure: $router->get('foo', function(){ return 'Hello, World'; }...

    HTTP路由

    • 基本路由
    • 路由参数
      1. 必填参数
      2. 可选参数
      3. 正则表达式约束
    • 命名路由
    • 路由组
      1. 中间件
      2. 命令空间
      3. 路由前缀

    基本路由

    你可以在 route/web.php 文件中定义应用程序的全部路由。最基本的Lumen路由仅接受URL和一个Closure:

    $router->get('foo', function(){
        return 'Hello, World';
    });
    
    $router->post('foo', function(){
        //
    });

    可供使用的路由方法

    我们可以注册路由来响应任何方法的HTTP请求:

    $router->get($uri, $callback);
    $router->post($uri, $callback);
    $router->put($uri, $callback);
    $router->patch($uri, $callback);
    $router->delete($uri, $callback);
    $router->options($uri, $callback);

    路由参数

    必填参数

    当然,有时需要在路由中捕获一些URL片段。例如,从URL中捕获用户的ID,可以通过通过定义路由参数来执行此操作:

    $router->get('user/{id}', function ($id) {
        return "User:" . $id;
    });

    也可以根据需要在路由中定义多个参数:

    $router->get('posts/{postId}/comments/{commentId}', function ($postId, $commentId) {
        //
    });

    路由的参数都会被放在[大括号]内。当运行路由时,参数会传递到Closure里面。

    注意:路由参数不能包含-字符。请用下划线_代替。

    可选参数

    你可以通过将部分路由URI包含在[...]中来定义可选的路由参数。那么像/foo[bar]将会匹配到/foo和/foobar。可选参数仅支持放在URI的末尾。换句话说,你不能在路由定义的中间位置放置可选参数:

    $router->get('user'[/{name}]', function ($name = null) {
        return $name;
    });

    正则表达式约束

    你可以通过在路由定义中使用正则表达式来约束路由参数的格式:

    $router->get('user2/{name:[a-zA-Z]}', function () {
        //
    });

    命名路由

    命名路由可以方便的为特定路由生成URL或者进行重定向。你可以使用as数组键指定名称到路由上:

    $router->get('profile', ['as' => 'profile', function() {
        //
    }]);

    你还可以指定控制器行为的路由名称:

    $router->get('profile', [
        'as' => 'profile',
        'uses' => 'UserController@showProfile',
    ]);

    生成指定路由的URL

    为路由制定了名称后,就可以使用全局辅导函数route来生成链接或者重定向到该路由:

    //Generating URLs...
    $url = route('profile');

    //Generating Redirects...
    return redirect()->route('profile');

    如果是有定义参数的命名路由,可以把参数作为route函数的第二个参数传入,指定的参数将会自动插入到URL中对应的位置:

    $router->get('user/{id}/profile', ['as' => 'profile', function ($id) {
        return $id;
    }]);
    
    $url = route('profile', ['id' => 1]);

    路由组

    路由群组允许你共用路由属性,例如:中间件、命名空间,你可以利用路由组统一为多个路由设置共同属性,而不需要在每个路由都设置一次。共用属性被指定为数组格式,当做$router->group方法的第一个参数。

    为了了解更多路由群组的相关内容,我们可以通过几个常用样例来熟悉这些特性。

    中间件

    要给路由组中所有的路由分配中间件,你可以在group属性数组中使用middleware字段。中间件会依照它们在数组中列出的顺序来运行:

    $router->group(['middleware' => 'auth'], function () use ($router) {
        $router->get('/', function () {
            //使用Auth中间件
        });
    
        $router->get('user/profile', function () {
            //使用Auth 中间件
        });
    });

    命名空间

    另一个常见的例子是,指定相同的PHP命名空间给控制器群组。可以使用namespace参数来指定群组内所有控制器的命名空间:

    $router->group(['namespace' => 'Admin'], function () use ($router) {
        //使用"App\Http\Controllers\Admin"命名空间
        $router->group(['namespace' => 'User', function () use ($router) {
            //使用"App\Http\Controllers\Admin\User" 命名空间...
        }]);
    });

    路由前缀

    通过路由群组数组属性中的prefix,在路由群组内为每个路由指定的URI加上前缀。例如,你可能想要在路由群组中将所有的路由URI加上前缀admin:

    $router->group(['prefix,' => 'admin'], function () use ($roter) {
        $router->get('users', function () {
            //匹配The "/admin/users"URL
        });
    });

    你也可以使用prefix参数去指定路由群组中共用的参数:
    $router->group(['prefix' => 'accounts/{accountId}'], function () use ($router) {
    $router->get('detail', function ($accountId) {
    //匹配The "/accounts/{accountId}/detail" URL
    });
    });

    HTTP中间件

    • 简介
    • 定义中间件
    • 注册中间件

      • 全局中间件
      • 为路由指定中间件
    • 中间件参数
    • Terminal中间件

    简介

    HTTP中间件提供了一个方便的机制来过滤进入应用程序的HTTP请求。例如,lumen内置了一个中间件来验证用户的身份认证。如果用户未通过省份证,中间件将会把用户导向登录页面,反之,当用户通过了身份证,中间件将会通过此请求并接着往下执行。

    当然,除了身份证之外,中间件也可以被用来运行各式各样的任何,如:CORS中间件负责替换所有即将离开程序的响应加入适当的标头;而日志中间件则可以记录所有出入应用从程序的请求。

    所有的中间件都放在app/Http/Middleware目录内。

    定义中间件

    你可以通过赋值lumen内置的示例文件ExampleMiddleware来创建一个中间件。在这个中间件中,我们只允许参数age大于200的请求才能访问该路由。否则,我们将此用户重定向到首页"home"这个URI上。

    正如你所见,假如给定的age参数小于或者等于200,这个中间件将返回一个HTTP重定向到客户端;否则,请求将进一步传递到应用中。要让请求继续传递到应用程序中(即允许“通过”中间件验证的),只需要使用$request作为参数去调用回调函数$next。

    最好将中间件想象为一系列HTTP请求必须经过才能进入你的应用的层。每一个都会检查请求
    (是否符合某些条件),(如果不符合)甚至可以(在请求访问你的应用之前)完全拒绝掉。

    前置/后置中间件

    中间件是在请求之前或者之后运行取决于中间件本身。例如,接下来的这个中间件将在应用处理请求before执行其任务:

    <?php
    namespace App\Http\Middleware;
    use Closure;
    class BeforeMiddleware
    {
    public function handle($request, Closure $next)
    {
    //执行操作
    return $next($request);
    }
    }

    而接下来的这个中间件将在应用处理请求之后执行其任务:

    <?php
    namespace App\Http\Middelware;
    use Closure;

    class AfterMiddleware
    {
        public function handle($request, Closure $next)
        {
            return $next($request);
        }
    }

    注册中间件

    全局中间件

    若是希望中间件在应用处理每个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,]);

    一旦在HTTP内核中定义好了中间件,就可以在路由选项内使用middleware键:

    $router->get('admin/profile', ['middleware' => 'auth', function () {
        //
    }]);

    可以使用数组为路由指定多个中间件:

    $router->get('/', ['middleware' => ['first', 'second'], function () {
        //
    }]);

    中间件参数

    中间件也可以接受自定义传参,例如,要在运行特定操作前检查已验证用户是否具备该操作的“角色”,可以创建RoleMiddleware来接受角色名称作为额外的传参。

    附加的中间件参数将会在$next参数之后被传入中间件:

    <?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”的中间并添加一个terminal方法:

    <?php
        
    namespace Illuminate\Session\Middleware;
    
    use Closure;
    
    class StartSession
    {
        public function handle($request, Closure $next)
        {
            return $next($request);
        }
    
        public function terminate($request, $response)
        {
            //存储session数据
        }
    }

    terminate方法应该同时接受和响应。一旦定义了这个中间件,你应该将它添加路由列表或者bootstrap/app.php文件的全局中间件中。

    在你的中间件上条用terminite调用时,lumen会从服务器中解析出一个新的中间件实例。如果你希望在handle及terminate方法被调用时使用一致的中间件实例,只需要在容器中使用容器的singleton方法注册中间件。

    HTTP控制器

    简介

    为了替代把所有的请求处理逻辑都定义在routes.php路由文件中,你或许想要使用控制来组织这些行为。控制器可以把相关的请求处理逻辑整合为一个控制器类。控制器类文件被存储在app/HTTP/Controllers目录下。

    基础控制器

    这里有一个基础控制器的示例。所有lumen的控制器都应该继承lumen安装时内置的默认的控制器基类:

    <?php
    
    namespace App\Http\Controllers;
    
    use App\User;
    
    class UserController extends Controller
    {
    /**
     * 获取指定 ID 的用户
     *
     * @param  int  $id
     * @return Response
     */
    public function show($id)
    {
    return User::findOrFail($id);
    }
    }

    我们可以像下面这样路由指向控制器的方法:

    $router->get("user/{id}", "UserController@show");

    现在,当请求匹配到这个特定的URL时,UserController类中的show方法就会执行。当然,路由的参数也同样传递给了这个方法。

    控制器和命名空间

    有一点非常重要,那就是我们要注意在定义控制器路由时,不需要指定完整的控制器命名空间。我们只需定义“根”命名空间App\Http\Controllers之后的类名部分。默认情况下,bootstrap/app.php文件在加载routes.php时已经把所有路由都配置到了根控制器命名空间。

    如果你选择在App\Htpp\Controllers目录内层使用PHP命名空间嵌套或者组织控制器,只要使用相对于App\Http\Controllers根命名空间的特定名称即可。因此,如果你的控制器类全名是App\Http\Controllers\Photos\AdminController,那么你应该注册一个路由,如下所示:

    $router->get('foo', 'Photos\AdminController@method');

    命名控制器路由

    像闭包那样,你可以给控制器路由指定一个名称:

    $router->get('foo', ['uses' => 'FooController@method', 'as' => 'name']);

    你也可以使用route辅助函数,来生成指向控制器路由的URL:

    $url = route('name');

    控制器中间件

    中间件可通过如下方式分配到路由中:

    $router->get('profile', [
        'middleware' => 'auth',
        'uses' => 'UserController@showProfile'
    ]);

    然而,更方便的方式是在控制器的构造方法里面使用middleware方法指定中间件。你甚至可以限制中间件只应用于该控制器类的某些方法:

    class UserController extends Controller
    {
    /**
    实例化一个新的UserController实例。
    @return void
    */
    public function __construct()
    {
    $this->middleware('auth');

        $this->middleware('log', [
            'only' => ['fooAction', 'barAction']
        ]);
    
        $this->middleware('subscribed', ['except' => [
            'fooAction',
            'barAction',
        ]]);
    }

    }

    依赖注入与控制器

    构造器注入

    lumen使用[服务容器]来解析所有的控制器的依赖注入。因此,你可以在控制器的构造函数中使用类型提示需要的任何依赖。这些依赖会自动的解析并注入到控制器实例中:

    namespace App\Http\Controllers;
    
    use App\Repositories\UserRepository;
    
    class UserController extends Controller
    {
        /**
        *新建一个控制器实例
        *
        *@param UserRepository $users
        *@return void
        */
        public function __contruct(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()
            {
                $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
    {
        /**
        *更新指定用户
        *
        *@param Request $request
        *@param string $id
        *@return Response
        */
        public function update(Request $request, $id)
        {
            //
        }
    }

    HTTP请求

    获取请求实例

    要通过依赖注入的方式获取当前HTTP请求的实例,你应该在控制器构造函数或者方法中使用
    Illuminate\Http\Request类,当前请求实例将自动被服务容器注入:

    <?php
    
    namespace App\Http\Controller;
    
    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
    {
        /**
        *更新指定用户
        *
        *@param Request $request
        *@param string $id
        *
        *@return Response
        */
        public function update(Request $request, $id)
        {
            //
        }
    }

    基本请求信息

    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-diactors

    安装完这些库后,你就可以在路由或者控制器中,简单的对请求类型使用类型提示来获取PSR-7请求:

    use Psr\Http\Message\ServerRequestInterface;
    
    $router->get('/', function (ServerReuestInterface $request) {
        //
    });

    如果你从路由或者控制器反悔了一个PSR-7的响应实例,那么它会被框架自动转换为laravel的响应实例并显示。

    获取输入数据

    获取指定输入值

    你可以通过Illuminate\Http\Request实例,使用几个简单的方法来获取所有的用户输入数据,而不需要担心请求的HTTP动作,因为它们的获取方式是相同的:

    $name = $request->input('name');

    你可以在input方法的第二个参数中传入一个默认值,当请求参数不存在时,就会返回默认值:

    $name = $request->input('name', 'Sally');

    当数据是以数组形式输入时,你可以使用“点”符号来获取数组:

    $name = $request->input('products.0.name');
    
    $name = $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\UploadFile类的实例,这个类继承了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);

    其他上传文件方法

    UploadFile实例还有很多其他可用的方法,可以到该类的API文档了解这些方法的详细信息。

    HTTP响应

    基本响应

    当然,所有的路由及控制器必须返回某个类型的响应,并发送回用户的浏览器。laravel提供了集中不同的方法来返回响应。最基本的响应就是从路由或者控制器简单的返回一个字符串:

    $router->get('/', function () {
        return 'Hello World';
    });

    指定的字符串会被框架自动转为HTTP响应。

    响应对象

    但是,对于大多数路由和控制器行为操作,你将返回完整的Illuminate\Http\Response实例。返回完整的Response实例允许你自定义响应的HTTP状态码和标题。一个Response实例继承自Symfony\Componet\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并且不带任何参数时,将会返回Laravel\Lumen\Http\ResponseFactory contract的实现。此Contract提供了一些有用的方法来生成响应。

    JSON响应

    json方法会自动将标头的Content-Type设置为application/json。并且通过PHP的接送_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方法接受文件名称作为方法的第二个参数,此名称为用户下载文件时看见的文件名称。最后,你可以传递一个标头的数组作为第三个参数传入该方法:

    return reponse()->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辅助函数并且不带任何参数时,将会返回laravel\Lumen\Http\Redirecotr的实例,你可以对该Redirector的实例调用任何方法。举个例子,要生成一个RedirectResponse到一个命名路由,你可以使用route方法:

    return redirect()->route('login');

    如果你的路由有参数,则可以将参数放进route方法的第二个参数,如下:

    //For a route with follwing URI:profile/{id}
    return redirect()->route('profile', ['id' => 1]);

    如果你要重定向至路由并且路由的参数为Eloquent模型的[ID],则可以直接将模型传入,ID将会自动被提取:

    return redirect()->route('profile', [$user]);

    用户认证

    简介

    lumen虽然与laravel使用了相同的底层类库实现,但是因lumen面向的是无状态API的开发,不支持session,所以默认的配置不同。lumen必须使用无状态的机制来实现认证,如api令牌(Token)。

    开始

    认证服务提供者

    注意:在使用lumen的认证功能前,请取消bootstrap/app.php文件中的AuthServiceProvider调用代码的注释。

    AuthServiceProvider存放在app/Providers文件夹中,此文件中只有一个Auth::viaRequest调用。viaRequest会在系统需要认证的时候被调用,此方法接受一个Closure(匿名函数)参数。在此closure(匿名函数)内,你可以任意的解析App\User并返回,或者在解析失败时返回null:

    $this->app['auth']->viaRequest('api', function ($request) {
        //返回User或者null...
    });

    同样,你可以使用你期望的方式取得用户认证,比如在请求头或者查询字符串中使用api令牌、请求中的bearer令牌,或者使用应用程序需要的任何其他方法。

    如果你的项目没有使用Eloquent,你需要返回一个Illuminate\Auth\GenericUser类的实例。这个类接受一个属性数组作为构造函数的唯一参数:

    use Illuminate\Auth\GenericUser;
    
    return new GenericUser(['id' => 1, 'name' => 'Taylor']);

    缓存

    简介

    laravel为各种缓存系统提供了统一的api。缓存配置位于.env文件中。在该文件中你可以指定应用默认使用哪个缓存驱动。laravel支持当前流行的后端缓存,例如memcached和Redis。

    不同于laravel

    lumen缓存驱动与laravel缓存驱动使用了完全相同的代码。除配置之外,在lumen中使用缓存和在laravel中使用缓存没有区别;因此,请参阅laravel文档来获取使用示例。

    注意:在使用cache facade之前,请确保在bootstrap/app.php文件中没有注释掉$app->withFacaes()方法的调用。

    Redis支持

    在使用lumen的Redis缓存之前,你需要通过composer安装illuminate/redis(5.5.*)包。然后,你需要在bootstrap/app.php文件中注册illuminate\Redis\RedisServiceProvider。

    如果你没有在bootstrap/app.php文件中调用$app->withEloquent(),那么你应该在bootstrap/app.php文件中调用$app->configure('database');以确保正确加载Redis数据库配置。

    缓存

    简介

    laravel为各种缓存系统提供了统一的api。缓存配置位于.env文件中。在该文件中你可以指定应用默认使用哪个缓存驱动。laravel支持当前流行的后端缓存,例如Memcached和Redis。

    不同于laravel

    lumen缓存驱动与laravel缓存驱动使用了完全相同的代码。除配置之外,在lumen中使用缓存和在laravel中使用缓存没有区别;因此,请参阅laravel文档来获取使用示例。

    注意:在使用Cache Facade之前,请确保在bootstrap/app.php文件中没有注释掉$app->withFacdes()方法的调用。

    Redis支持

    在使用lumen的Redis缓存之前,你需要通过composer安装illuminate/redis(5.5.*)包。然后,你需要在bootstrap/app.php文件中注册illuminate\Redis\RedisServiceProvider。

    如果你没有在bootstrap/app.php文件中调用$app->withEloquent()。那么你应该在bootstrap/app.php文件中调用$app->configure();以确保正确加载Redis数据库配置。

    数据库

    配置

    lumen让连接数据库和执行查询变得非常简单。目前lumen支持四种数据库系统:MySQL,Postgres,SQLite和SqlServer。

    你可以在.env配置文件中使用DB_*选项配置数据库设置,例如数据库驱动、host、用户名和密码。

    基本用法

    注意:如果你想使用DB facade,你应该去掉在bootstrap/app.php文件中$app->withFacades()的调用的注释。

    例如,在不启用facades时,你可以通过app辅助函数连接数据库:

    $result = app('db')->select("SELECT * FROM users");

    或者,在启用facades后,你可以通过DB facade来连接数据库:

    $result = DB::select("SELECT * FROM users");

    基本查询

    要了解如何通过数据库组件执行基本的原始SQL查询,请参考laravel文档

    查询构造器

    lumen同样支持Eloquent ORM的流式查询构造器。要了解这个特性的更多信息,请参阅laravel文档。

    Eloquent ORM

    如果你喜欢使用Eloquent ORM,你应该去掉bootstrap/app.php文件中对$app->withQloquent()调用的注释。
    当然,你可以在lumen中非常容易的使用完整的Eloquent ORM。要了解如何使用Eloquent,请参考laravel文档。

    迁移

    关于如何创建数据库表和执行迁移的更多文档,请参考laravel文档中的迁移。

    加密与解密

    配置

    在使用lumen的加密之前,你应该先把.env文件中APP_KEY选项设置为32位随机字符串。如果没有适当地设置这个值,所有被lumen加密的值都将是不安全的。

    基本用法

    加密一个值

    你可以使用crypt门面来加密一个值。所有的加密值都使用OpenSSL和AES-256-CBC来进行加密。此外,所有加密过的值都会使用消息认证码(MAC)来进行签名,以检测加密字符串是否被篡改过:

    例如,我们可以使用encrypt方法加密机密信息,并把它保存在Eloquent模型:

    <?php
    namespace App\Http\Controllers;
    
    use App\User;
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Crypt;
    
    class UserController extends Controller
    {
        /**
        * 保存用户的机密信息。
        * @param Request $request
        * @param int $id
        * @return Response
        */
        public function storeSecret(Request $request, $id)
        {
            $user = User::findOrFail($id);
            
            $user->fill([
                'secret' => Crpty::encrypt($request->secret)
            ])->save();
        }
    }

    加密一个值

    当然,你可以使用crypt门面的decrypt方法来解密值。如果该值不能够被正确的解密。例如当MAC(消息认证码)无效时,就会抛出异常Illuminate \Contracts\Encryption\DecryptException:

    use Illuminate\Contracts\Encryption\DecryptException;
    
    try{
        $desrypted = Crypt::decrypt($encryptedValue);
    }catch (DecryptException $e){
        //
    }

    错误与日志

    简介

    当你开始一个新的Lumen项目时,lumen就已经帮你配置好错误和异常处理的操作。另外,lumen也集成了Monolog日志函数库,Monolog支持和提供多种强大的日志处理功能。

    有关错误的更多信息,请参阅完整的laravel错误文档。
    有关日志的更多信息,请参阅完整的laravel的日志文档。

    错误处理

    介绍

    当你启动一个新的laravel项目时,错误及异常处理是已为你配置好了的。
    App\Exceptions\Handler类负责记录应用程序触发的所有异常并呈现给用户。在本文档中,我们将深入探讨这个类。

    配置

    你的config/app.php配置文件中的debug选项决定了对于一个错误实际上讲显示多少信息给用户。默认情况下,该选项的设置将遵循存储在.env文件中的APP_DEBUG环境变量的值。

    对于本地开发,你应该将APP_DEBUG环境变量的值设置为true。在生产环境中,该值赢始终未false。如果在生产将该值设置为true,则可能会将敏感配置暴露给应用程序的最终用户。

    异常处理器

    report方法

    所有异常都是由App\Exceptions\Handler类处理。这个类包含两个方法:report和rendor。我们将详细剖析这些方法。report方法用户记录异常或将它们发送给如Bugsnag或者Sentry等外部服务。默认情况下,report方法将异常传递给记录异常的基类。不过,你可以任何自己喜欢的方式来记录异常。

    例如,如果你需要以不同方式报告不同类型的异常,则可以使用PHP的instanceof比较运算符:

    /**
    *报告或者记录异常
    *
    *此处是发送异常给sentry、Bugsnag等外部服务的好位置。
    *
    *@param \Exception $exception
    *@return void
    */
    public function report()
    {
        if ($exception instance CustomException) {
            //
        }
        return parent::report($exception);
    }

    {tip}不要在report方法中进行太多的instanceof检查,而应该考虑使用[可报告异常(reportable exception)]
    {(/docs/laravel/5.7/errors#renderable-exceptions)}。

    Report辅助函数

    有时你可能需要报告异常,但又不希望终止当前请求的处理。report辅助函数允许你使用异常处理器的report方法在不显示错误页面的情况下快速报告异常:

    public function isValid()
    {
        try{
        }catch(Exception $e){
            report($e);
            return false;
        }
    }

    按类型忽略异常

    异常处理器的$dontReport属性包含一组不会被记录的异常类型。例如,由04错误导致的异常一级其他几种类型的错误不会写入日志文件。你可以根据需要添加其他异常类型到此数组中:

    /**
    *不应被报告的异常类型清单。
    *
    *@var array
    */
    protected $dontReport = [
        \Illuminate\Auth\AuthenticationException::class,
        \Illuminate\Auth\Access\AuthorizationException::class,
        \Symfony\Component\HttpKernel\Exception\HttpException::class,
        \Illuminate\DataBase\Eloquent\ModelNotFoundException::class,
        \Illuminate\Validation\ValidationException::class,
    ];

    Render方法

    Rendor方法负责将给定的异常转换为将被发送回浏览器的HTTP响应。默认值情况下,异常将传递给你生成响应的基类。不过,你可以按自己意愿检查异常类型或者返回自己的自定义响应:

    /**
    *将异常1转换为HTTP响应。

    • @param \Illuminate\Http\Request $request
      @param \Illuminate\Exception $exception
      @return \Illuminate\Http\Response
      /
      public funtion render($request, Exception $exception)
      {
      if ($exception instanceof CustomException) {
      return response()->view('errors.custom', [], 500);
      }

    return parent::render($request, $exception);
    }

    Reportable & Renderable 异常

    除了在异常处理器的report和render方法中检查异常类型,你还可以直接在定义异常上定义report和render方法。当定义了这些方法时,它们会被框架自动调用:

    <?php
    namespace App\Exceptions;
    use Exception;
    class RenderException exteds Exception
    {
    /**
    * 报告异常

    @return void
    */
    public function report()
    {
    //
    }

        /**
         * 转换异常为 HTTP 响应
         *
         * @param  \Illuminate\Http\Request
         * @return \Illuminate\Http\Response
         */
        public function render($request)
        {
            return response(...);
        }
    }

    HTTP异常

    一些异常用描述产生自服务器的HTTP错误代码。例如,[页面未找到]错误(404),【未经授权的错误】(401),甚至可以是开发人员引起的500错误。你可以使用abort辅助函数从应用程序的任何地方生成这样的响应:

    abort(404);

    辅助函数abort会立即引发一个由异常处理器渲染的异常。你还可以选择性地提供响应文本:
    abort(403, 'Unauthorized action.');

    自定义HTTP错误页面

    laravel可以轻松显示各种HTTP状态代码的自定义错误页面。例如,如果你希望自定义404HTTP状态码的错误页面,可以创建一个resources/views/errors/404.blade.php视图文件。该文件将被用于你的应用程序产生的所有404错误。此目录中的视图文件的命名应匹配它们对应的HTTP状态码。由abort函数引发的HTTPException实例将作为$exception变量传递给视图:

    {{ $exception->getMessage() }}

    日志

    简介

    为了帮助你更多的了解应用程序中到底发生了什么,laravel提供了强大的日志服务,允许你将日志消息,系统错误日志记录到文件,甚至使用slack通知到你的整个团队。

    在laravel框架中,laravel使用monolog库,它为各种强大的日志处理提供支持。laravel使用配置这些处理程序变得简单,允许泥混合并匹配它们自定义的应用程序日志处理。

    配置

    所有的应用程序日志系统配置都位于config/logging.php配置文件中。这个文件允许你配置你的应用程序日志通信,
    所以务必查看每个可用的通信及它们的选项。当然,我们将在下面回顾一些常用的选项。

    默认情况下,laravel将使用stack去记录日志消息。stack通道被用来将多个日志通道聚合到一个单一的通道中。关于堆栈的更多信息,查看以下文档。

    配置通道名称

    默认强狂下,monolog使用与当前环境匹配的【通道名称】进行实例化,比如production或者local。要改变这个值,需添加一个name选项到你的通道配置中:

    'stack' => [
        'driver' => 'stack',
        'name' => 'channel-name',
        'channels' => ['single', 'slack'],
    ];

    可用的通道驱动

    名称 描述
    single 一个便于创建[多通道]通道的包装器
    daily 单个文件或者基于日志通道的路径(StreamHandler)
    slack 一个每天轮换的基于monolog驱动的RotatingFileHandler
    syslog 一个基于monolog驱动的sysloghandler
    errorlog 一个基于monolog驱动的errorlogHandler
    monolog 一个可以任何支持monolog处理程序的monolog工厂驱动程序
    custom 一个调用指定工厂创建通信通道的驱动程序

    {tip}有关monolog和custom驱动,查看高级通道自定义

    配置slack通道

    slack通道需要url配置选项。这个URL应当与你为slack团队配置的一个incoming webhook相匹配。

    构建日志栈

    如前所述,stack驱动允许你将多个通道合并到一个单一日志通道中。为了说明如何使用日志栈,让我们看一个你可能在生产应用配置中看到的实例配置:

    'channels' => [
        'stack' => [
            'driver' => 'stack',
            'channels' => ['syslog', 'slack'],
        ],
            
        'syslog' => [
            'driver' => 'slack',
            'url' => env('LOG_SLACK_WEBHOOK_URL'),
            'username' => 'Laravel Log',
            'emoji' => ':boom:',
            'level' => 'critical',
        ],
    ],

    让我们剖析这个配置。首先,注意我们的stack通道通过它的Channels选项聚合其它两个通道:syslog和slack。因此,当记录日志消息时,这两个通道都有机会去记录日志消息。

    日志级别

    注意上面实例中在syslog和slack通道配置中存在的level配置选项。这个选项决定了一个消息必须被通道记录的最小[level]。monolog为laravel的日志服务提供了RFC-542规范中定义的所有日志级别:emergency,
    alert,critical,error,warning,notice,info和debug。

    因此,假设我们记录一个日志消息使用debug方法:

    Log::debug('An informational message.');

    根据我们的配置,syslog通道将写消息到系统日志;然而,由于错误消息不是critical或者这个级别之上,它将不被发送到slack。但是,如果我们记录一个emergency消息,它将被同时发送到系统日志和slack,因为emergency级别高于我们对两个通道最低级别的阈值:

    Log::emergency('The system is down!');

    记录日志消息

    你可以通过Log外观类将信息写入到日志。如前所述,日志器提供在RPC 5424规范中定义的八个日志级别:

    emergency,alert,critical,error,warning,notice,info和debug:

    Log::emergency($message);
    Log::alert($message);
    Log::critical($message);
    Log::error($mesage);
    Log::warning($message);
    Log::notice($message);
    Log::info($message);
    Log::debug($message);

    因此,你可以调用这些方法中的任何一个去记录相应级别的一个日志消息。默认情况下,消息将写入到你的config/logging.php配置文件配置的默认日志通道中:
    <?php
    namespace App\Http\Controllers;

    use App\User;
    use Illuminate\Support\Facades\Log;
    use App\Http\Controllers\Controllers;

    class UserController extendx Controller
    {
    /**
    * Show the profile for the given user.

    @param int $id
    * @return Response
    */
    public function showProfile($id)
    {
    Log::info('Showing user profile for user: '.$id);

        return view('user.profile', ['user' => User::findOrFail($id)]);
    }

    }

    记录日志到指定通道

    有时候你可能希望将日志记录到非默认通道。你可以使用log facade中的channel方法,将日志记录到应用配置中存在的任何聚到:

    Log::channel('stack')->info('Something happened!');

    如果你想按需要创建多个渠道的日志堆栈,你可以使用stack方法:

    Log::stack(['single', 'slack'])->info("Something happened!");

    先进的monolog日志通道定制

    自定义monolog日志通道

    首先你可能需要完全配置monolog现有的通道。例如:你想要为现有通道自定义一个monolog formatterInterface实现。

    首先,在频道配置文件中定义一个tap数组。tap数组应该该包含所需的类列表,这些类就是Monolog实例创建后需要自定义(或者开发)的类:

    'single' => [
    'driver' => 'single',
    'tap' => [],],

    事件

    简介

    lumen事件提供了简单的监听器实现,允许你订阅和监听事件,事件类通常被保存在app/Events目录下,而它们的侦听器被保存在app/Listeners目录下。

    与laravel的差异

    通常,lumen中的事件方法恰好与laravel全栈框架功能一致,所以,请阅读完整的laravel文档。lumen同样支持事件广播,它允许客户端的JavaScript监听服务器的事件。然而,这里还是有些差异值得谈论。

    生成器

    lumen中没有可以用来生成事件和监听器的命令,你可以通过简单赋值ExampleEvent或者ExampleListener文件来定义你自己的事件和监听器,这两个示例文件提供了每个事件和监听器的基础类结构。

    注册事件或者监听器

    像laravel框架一样,lumen应用内置的EventServiceProvider提供了一个注册所有事件监听器的地方。listen属性一个数组,它包含了所有的事件(键)和监听器(值)。所以,你可以根据应用程序的需要添加事件到这个数组:

    /**
    *应用程序的事件监听器映射。
    *
    *@var array
    */
    protected $listen = [
        'App\Events\ExampleEvent => [
            'App\Listeners\ExampleListener',
        ],
    ];

    触发事件

    你可以使用event辅助函数或者event门面在lumen应用程序中触发事件。同样,这些函数的行为与laravel框架一致:

    event(new ExampleEvent);
    
    Event::dispatch(new ExampleEvent);

    队列

    简介

    lumen的队列服务给不同的后端队列提供统的API。队列允许你延迟处理消失的任务,例如在远程服务器上执行任务直到更晚的时间,而同一时间你的应用程序可以快速的处理web应用程序的请求。

    就像该框架的许多其他部分一样,lumen的队列服务跟laravel的队列服务功能相同。因此,如果要了解更多关于lumen的队列,则可以参阅laravel消息队列文档。

    配置

    队列配置选项对话都在.env文件中。

    如果您想要完全自定义的配置,必须您将vendor/laravel/lumen-framework/config/queue.php文件完整的复制到你的项目目录根中config目录,并且要调整必要的配置。如果config目录不存在,则要创建。

    驱动程序先决条件

    数据库

    使用为了database队列驱动程序,您将需要数据库表保存作业和失败情况:

    Schema::create('jobs', function (Blueprint $table) {
        $table->bigIncrement('id');
        $table->string('queue');
        $table->longText('payload');
        $table->tinyInteger('attempts')->unsigned();
        $table->unsignedInteger('reserved_at')->nullable();
        $table->unsignedInteger('available_at');
        $table->unsignedInteger('created_at');
        $table->index(['queue', 'reserved_at']);
    });
    
    
    Schema::create('failed_jobs', function (Blueprint $table) {
        $table->increment('id');
        $table->text('connection');
        $table->text('queue');
        $table->longText('payload');
        $table->longText('exception');
        $table->timestamp('failed_at')->useCurrent();
    });

    Redis的

    要想使用Redis队列驱动程序,需要先通过composer安装illuminate/redis(5.5.*)扩展包。然后再bootstrap/app.php文件中注册Illuminate\Redis\RedisServiceProvider;

    其他队列驱动程序的依赖包

    下面列出其他队列驱动程序所需要的依赖扩展包:
    亚马逊SQS:aws/aws-sdk-php ~3.0
    Beanstalked:pda/pheanstalk ~3.0

    与laravel的差异

    与框架的许多其他部分一样,lumen队列作业的功能与laravel的队列作业功能相同。因此,要了解lumen队列作业功能,请查看完整的laravel队列文档。

    不过呢,我们现在讲讨论两个框架间的一些细微差异。首先,我们来谈谈lumen中如何生成队列作业。

    生成器

    lumen不包括用于自动创建新job类的生成器。因此你需要赋值框架所带的exampleJob类。这个类提供了每个job类共享的基本结构。examplejob所继承的job基类已包含所需的interactswithqueue,queueable和serializesmodels特性:

    <?php

    namespace App\Jobs;

    class ExampleJob extendx Job
    {
    /**

    • 创建一个新的作业实例。
    • @return void
      */
      public function __construct()
      {
      //
      }

    /**

    • 执行作业。
    • @return void
      */
      public function handle()
      {
      //
      }
      }

    调度作业

    再次重申,你应该查阅完整的laravel文档以获取有关调节队列作业的完整信息;和laravel框架一样,你可以使用dispatch函数从lumen应用程序中的任意位置调度作业:

    dispatch(new ExampleJob);

    当然,你也可以使用Queue facade。如果你选择使用facade,请务必在bootstrap/app.php文件中取消对$app->withFacades()调用的注释:

    Queue::push(new ExampleJob);

    服务容器:

    简介

    laravel的服务容器是一个管理类依赖和执行依赖注入的强力工具。依赖注入是个花俏的名字,事实上是指:类的依赖通过构造器或者在某些情况下通过【setter】方法【注入】。

    与laravel的差异

    lumen使用了与laravel框架相同的服务器。所以,你可以使用它们所有强大的功能。有关容易的完整文档,请阅读laravel容器文档。

    获取服务容器

    laravel\lumen\application实例是Illuminate\Container\Container的扩展,所以你可以当做服务容器来使用。
    通常我们会在服务提供者注册我们的容器解析规则。当然,你可以使用bind、singleton’instance、以及容器提供的其他方法。请记住,所有这些方法都记录在laravel服务器容易文档中。
    解析实例

    想要从服务容器中解析实例,你可以在大部分的功能类里自动解析(依赖注入),如路由closure,控制器的构造方法、控制器方法、中间件、事件监听器,或者队列等。或者,你也可以在应用程序中的任何地方使用App函数来进行解析:

    $instance = app(Something::class);

    服务提供者

    简介
    服务提供者是所有lumen应用程序启动的中心所在。包括你自己的应用程序,以及所有的核心服务,都是服务提供者启动的。

    但是,我们所说的启动值得是什么?一般而言,我们指的是注册事物,包括注册服务容易绑定、事件侦听器、中间件,甚至路由、服务提供者设置你的应用程序的中心所在。

    若你打开lumen的bootstrap/app.php文件,你将会看到$app->register()方法的调用。你也许需要额外的调用来注册你的服务提供者。

    编写服务提供者

    所有的服务提供者都集成了illuminate\Support\ServiceProvider这个类。这个抽象类要求你在你的提供者上定义至少一个方法:register。在register方法内,你应该只需要将事物绑定到服务容器中。永远不要试图在register方法中注册任何事件侦听器,路由或者任何其他功能。

    注册方法

    如前面所讲,在register方法中,你只要将事物绑定到【服务容器中】。永远不要试图在register方法中注册任何事件侦听器、路由或者任何其它功能。否则,你有可能会以外的使用到尚未加载的服务提供者提供的服务。

    现在,让我们来看一个基本的服务提供者代码:

    <?php
    
    namespace App\Providers;
    
    use Riak\Connection;
    use Illuminate\Support\ServiceProvider;
    
    class RiakServiceProvider extends ServiceProvder
    {
        /**
        *注册绑定到容器中
        *
        *@return void
        */
        public function register()
        {
            $this->app->singleton(Connection::class, function ($app) {
                return new Connection(config('riak'));
            });
        }
    }

    这个服务提供者自定义了一个register方法,并且用这个方法在服务容器中绑定了Riak\Connection的一个实例。如果你不是很了解服务容器的运行原理,请查看[its documentation]。

    启动方法

    那么,如果我们要在服务提供者当中注册一个视图组件呢?这应该在boot方法内完成。此方法在所有其他服务提供者都注册之后才能调用,也就意味着可以访问已经被框架注册的所有服务:

    <?php
    namespace App\Providers;
    
    use Queue;
    use Illuminate\Support\ServiceProvider;
    
    class AppServiceProvider extends ServiceProvier
    {
        //其他服务提供者属性。。。
        /**
        *引导任何应用程序服务。
        *@return void
        */
        public function boot()
        {
            Queue::failing(function ($envent) {
                
            });
        }
    }

    注册服务提供者

    所有的服务提供者在bootstrap/app.php文件中被注册。这个文件中包含对$app->register()方法调用。你也行需要额外的调用$app->register()来注册你的服务提供者。

    测试

    简介

    lumen在创建时就已考虑到测试部分。事实上,lumen默认就支持用PHPunit来做测试,并为你的应用程序创建好了phpunit.xml文件。框架还提供了一些便利的辅助函数,让你可以更直观的测试应用程序的json响应。

    测试环境

    在运行测试时,lumen自动配置讲缓存驱动配置为array,意味着在测试的时候不会保存任何的缓存数据。

    你可以随意创建其他必要的测试配置环境。testing的环境变量可以在phpunit.xml文件中进行修改;

    定义和运行测试

    要创建一个测试用例,直接将新的测试文件创建到tests文件夹下即可。测试文件必须继承TestCase。接着就可以像平常使用PHPunit一样来定义测试方法。要运行测试只需要在命令行上运行PHPunit命令即可:

    <?php
    
    class FooTest extends TestCase
    {
        public function testSomethingIsTrue()
        {
            $this->assertTrue(true);
        }
    }

    注意:如果要在你的类自定义setUp方法,请确保调用了parent::setUp。

    应用测试

    lumen提供了一个非常好用的api,使用它用来向你的应用发起HTTP请求,并查看输出结果。

    测试json api接口

    lumen同样提供了几个测试用于测试json api接口和响应数据的助手。例如,get,post,put,patch和delete方法可以被用于发起各种HTTP请求方式,并且声明以json格式返回一个指定的数组:

    <?php
        
    class ExampleTest extends TestCase
    {
        /**
        *一个简单的测试例子
        *
        *@return void
        */
        public function testBasicExample()
        {
            $this->json('POST', '/user', ['name' => 'Sally']);
                ->seeJson([
                    'created' => true,
                ]);
        }
    }

    seeJson方法数组转换为json,并验证这个json片段发生在应用返回的整个json响应的任意位置。所以,即使在json响应中存在其他属性,只要指定的片段存在,这个测试任然会成功!

    验证完全匹配的json

    如果你想验证传入的数组是否与应用程序返回的json完全匹配,你可以用seeJsonEquals方法:
    <?php

    class ExampleTest extendx TestCase
    {
        /**
        *一个简单的测试例子
        *
        *@return void
        */
        public function testBasicExample()
        {
            $this->post('/user', ['name' => 'Sally'])
                ->seeJsonEquals([
                    'created' => true,
                ]);
        }
    }

    认证

    actingAs辅助函数提供了简单的方式来让指定的用户认证为当前的用户:
    <?php

    class ExampeTest exntends TestCase
    {
        public function testApplication()
        {
            $user = factory('App\User')->create();
            $this->actingAs($user)
                ->get('/user');
        }
    }

    自定义HTTP请求

    如果你想要创建一个自定义的HTTP请求到应用程序上,并获取完整的 Illuminate\Http\Response对象,可以使用call方法:

    public function testApplication()
    {
        $response = $this->call('GET', '/');
        $this->assertEquals(200, $response->status());
    }

    如果你想构造POST,PUT,或者PATCH请求,可以在请求时传入一个数组作为请求参数,当然,你也可以在路由及控制器中通过请求实例来获取传过来的参数:

    $response = $this->call('POST', '/user', ['name' => 'Taylor']);

    使用数据库

    为了使得测试使用了数据库的应用更加简便,lumen提供了各种有用的工具。首先,你可以使用seeInDatabase助手函数来断言数据库中是否存在给定条件的数据。例如,我们想要验证users表中的有一条email的值为Sally@example.com的记录,我们可以按如下操作:

    public function testDatabse()
    {
        //Make call to application...
        
        $this->seeInDatabase('users', ['email' => 'sally@foo.com']);
    }

    当然,seeInDatabase方法和类似的助手方法就是会为了方便使用。你也可以在测试中自由使用PHPunit的内置断言方法。

    每次测试之后重置数据库

    在每次测试后重置数据库时非常有必要的,这样之前的测试数据不会响应后面的测试。

    使用迁移

    有一个选择是每次测试之后回滚数据库,并且在下一次测试之前将其迁移。lumen提供了一个简单的DatabaseMigrations特性,它可以自动位您处理。简单的在您的测试类中运用这个特性如下:

    <?php
    
    use Laravel\Lumen\Testing\DatabaseMigrations;
    use Laravel\Lumen\Testing\DatabaseTransactions;
    
    class ExampleTest extends TestCase
    {
        use DatabaseMigrations;
        
        /**
        *A basic functional test example.
        *
        *@return void
        */
        public function testBasicExample()
        {
            $this->get('/foo');
        }
    }

    使用事务

    另一个选择是将每一个测试用例包装在数据库事务中。撸们提供了便利的DatabaseTransactions特性,可以为您自动的执行这些:

    <?php

    use Laravel\Lumen\Testing\DatabaseMigrations;
    use Laravel\Lumen\Testing\DatabaseTransactions;

    class ExampleTest extends TestCase
    {
    use DatabaseTransactions;
    /**
    A basic functional test example


    /
    }

    模型工厂

    在测试时,在执行测试之前我们需要将少量的数据插入到数据库中很常见的。当创建这些数据的时候,lumen不会手动指定这些列的值。而是允许您使用“factories”为每个Eloquent models定义一组默认属性。首先,在您的应用中看看database/factories/ModelFactory.php文件。这个文件包含一个工厂定义:

    $factory->define('App\User', function ($faker) {
        return [
            'name' => $faker->name,
            'email' => $faker->email,
        ];
    });

    在作为工厂定义的闭包中,您可以返回模型上所有属性的默认测试值。闭包将接收Faker PHP库的一个实例,它将允许您便利的生成各种随机数据以方便测试。

    当然,您可以将您自己的额外的工厂添加到ModelFactory.php文件中。

    多种工厂类型

    有时您可能希望同一个Eloquent模型有多种工厂。例如,可能您会希望除了普通的用户之外还有管理员用户的工厂。您可能会使用defineAs方法定义这些工厂:

    $factory->defineAs('App\User', 'admin', function ($faker) {
        return [
            'name' => $faker->name,
            'email' => $faker->email,
            'admin' => true,
        ];
    });

    您可以使用raw方法检索其基本属性,而不是复制基本用户工厂中的所有属性。一旦拥有这些属性,只需要使用您需要的任何附加值补充它们:

    $factory->defineAs('App\Users', 'admin', function ($faker) use ($factory) {
        $user = $factory->raw('App\User');
        return array_merge($user, ['admin' => true]);
    });

    在测试中使用工厂

    在工厂定以后,就可以在测试或者是数据库的填充文件中,通过全局的factory函数来生成模型实例。接着让我们先来看看几个创建模型的例子。首先我们会使用make方法创建模型,但不将他们保存至数据库:
    public function testDatabase()
    {
    $user = factory('App\User')->make();
    }

    如果你想要写模型中的某些默认值,则可以传递一个包含数值的数组至make方法。只有指定的数值会被替换,其他剩余的数值则会安装工程指定的默认值来设置:

    $user = factory('App\User')->make([
    'name' => 'Abigail',]);

    你还可以创建许多模型的集合或者创建给定类型的模型:

    //Create three App\User isntance...

    $users = factory('App\User', 3)->make();

    //Create an App\User "admin" instance...
    $user = factory('App\User', 'admin')->make();

    //Create three App\User "admin" instances...
    $users = factory("App\User", 'admin', 3)->make();

    维持工厂模式
    可以使用create方法创建模型实例,还可以使用save方法将数据保存到数据库:

    public function testDatabase()
    {
        $user = factory("App\User")->create();
        // Use model in tests...
    }

    同样,你也可以使用数组的方式使用create方法将数据写入模型

    $user = factory('App\User')->create([
        'name' => 'abigail',
    ]);

    添加关联至模型

    你甚至可以保存多个模型到数据库上。在本例中,我们还会增加关联至我们所创建的模型。当使用create方法创建多个模型时,它会返回一个Eloquent集合实例,让你能使用集合提供的便利方法,例如each方法:
    $users = factory('App\User', 3)
    ->create()
    ->each(function ($u) {
    $u->posts()->save(factory('App\Posts')->make);
    });

    模拟
    模拟事件
    如果你大量地使用lumen的事件系统,你可能会希望在测试停止或者模拟某些事件。例如,如果你在测试你的注册功能,你可能不希望所有的UserRegistered事件被触发,因为它们会触发“欢迎”邮件的发送。

    lumen提供了简单的expectsEvents方法,以验证预期的事件有没有被运行,可防止该事件的任何处理进程被进行:
    <?php

    class ExampleTest extends TestCase
    {
        public function testUserRegistration()
        {
            $this->expectsEvents('App\Events\UserRegistered');
            //测试用户注册功能...
        }
    }

    如果你想阻止所有的事件处理程序运行,你可以使用withoutEvents方法:

    <?php
    class Example extends TestCase
    {
        public function testUserRegistraction()
        {
            $this->withoutEvents();
            //Test user registraction code。。。
        }
    }

    模拟任务

    有时你可能希望当请求发送至应用程序时,简单地对控制器所派送的任务进行测试。这么做能够让你隔离测试路由或者控制器,设置除了任务以外的逻辑。当然,在此之后你也可以在一个单独的测试案例中测试该任务。

    lumen提供了一个简便的expectsJob方法,以验证预期的任务有没有被派送,但任务本身不会被运行:

    <?php
    class Example extends TestCase
    {
        public function testPurchasePodcast()
        {
            $this->expectsJobs('App\Jobs\PurchasePodcast');
            //测试购买博客代码...
        }
    }

    注意:该方法只检测通过全局猪手函数dispatch或者路由或控制器中的$this->dispatch方法派送的任务。它并不会检测被直接发送到Queue::push的任务。

    模拟facades

    在测试时,经常需要模拟对lumen facade的调用。例如,考虑如下控制器的操作:
    <?php
    namespace App\Http\Controllers;

    use Cache;
    class UserController extends Controller
    {
    /**
    * 展示应用程序所有用户的列表。

    @return Response
    */
    public function index()
    {
    $value = Cache::get('key');

        //
    }

    }

    我们可以使用shouldReceive方法来模拟调用Cache门面它会返回一个mockery模拟的实例。因为门面实际上已经被lumen的服务容器,解析和管理,它们比一般的静态类更具有可测性。例如,让我们模拟调用cache门面:
    <?php
    class FooTest extends TestCase
    {
    public function testGetIndex()
    {
    Cache::shouldReceive('get')
    ->once()
    ->with('key')
    ->andReturn('value');

            $this->get('/users');
        }
    }

    注意:你不应该模拟Request门面。应该在测试时使用如call及post这样的HTTP辅助函数来传递你想要的数据。

    数据验证

    简介

    lumen提供了数种不同的方法来验证传入应用程序的数据。默认情况下,lumen的基本控制器类使用名为ProvidesConvenienceMethods的trait,其提供了一种便捷的方法来使用各种强大的验证规则验证传入的HTTP请求。

    一般来说,lumen中的数据验证与laravel中的数据验证并无多大区别,因此你应该查过完整的laravel数据验证文档以熟悉其使用;不过,它们之间也存在少许重要的差异。

    与laravel的差异

    表单请求

    lumen不支持表单请求。如果想使用表单请求,则赢使用完整的laravel框架。

    $this->validate方法

    在lumen中可用的$this->validate辅助方法将始终返回带有相关错误消息的json响应。而该方法的laravel版本,如果请求不是ajax请求,返回的则是重定向响应。由于lumen是无状态的,且不支持会话,所以闪存错误信息在会话中是不可能的。如果想要使用重定向及闪存错误数据,应该使用完整的laravel框架。

    与laravel不同的是,lumen支持在Route闭包中访问validate方法:

    use Illuminate\Http\Request;
    
    $router->post('/user', function (Request $request) {
        $this->validate($request, [
            'name' => 'required',
            'email' => 'required|email|unique:users',
        ]);
    
        //存储用户
    });

    当然,你可以自由地使用Validator::make facade方法手动创建验证器实例,就像在laravel中一样。

    exists和unique规则

    如果想要使用exists或者unique验证规则,则应该在bootstrap/app.php文件中取消$app->withEloquent()方法调用的注释。

    视图变量$errors

    lumen不支持session,因此在laravel中每个视图都可用的$errors视图变量在lumen中式不可用的。如果验证失败,那么$this->validate辅助方法会抛出Illuminate\ValidationException异常,期中嵌入了包含所有相关错误消息的json响应,如果你并非只构建仅发送json响应的无状态api,则应使用完整的laravel框架。tongzhuo_examination_db

    转载于:https://www.cnblogs.com/2018-05-9-ygk/p/10254709.html

    展开全文
  • lumen-blog lumen 构建个人博客 安装 $ composer install -vvv
  • Lumen support

    2021-01-01 18:20:25
    <div><p>Is there any plan to add support for lumen? I tried out with lumen 5.4 but it seem to break ...
  • Lumen Support

    2020-12-01 17:07:00
    <div><p>I had a look at the documentation finding that the Lumen support is WIP. Then is this package well able to support Lumen or how long should I wait for any updates on Lumen WIP project (no ...
  • Lumen 5.2

    2020-12-06 07:16:28
    <div><p>Now Laravel 5.2.0 is released, is lumen going to update or remain on 5.1?</p><p>该提问来源于开源项目:laravel/lumen-framework</p></div>
  • Lumen?

    2020-12-08 19:36:19
    <div><p>Hello, Does this work with <a href="https://lumen.laravel.com/">Lumen</a>?</p><p>该提问来源于开源项目:tabuna/web-socket</p></div>
  • lumen-源码

    2021-03-08 21:40:27
    Lumen试图通过减轻大多数Web项目中使用的常见任务(例如路由,数据库抽象,排队和缓存)来减轻开发的痛苦。 官方文件 该框架的文档可以在上找到。 贡献 感谢您考虑为流明做出贡献! 可以在找到贡献指南。 安全漏洞 ...
  • Lumen compatibility

    2021-01-09 09:51:30
    <div><p>This package can also be compatible with Lumen framework. <p>What I did to make it work: 1. removed "illuminate/routing": "~5.0", from composer.json (it is not required) 2. ...
  • lumen-passport, 使用Lumen制作 Laravel 护照 lumen护照 使用Lumen制作 Laravel 护照一个简单的服务提供者,使 Laravel Passport与依赖项PHP> = 5.6.3流明> = 5.3通过Composer安
  • 使Laravel Passport与Lumen一起工作 一个简单的服务提供商,使Laravel Passport与Lumen一起工作 依存关系 PHP> = 5.6.3 流明> = 5.3 通过Composer安装 如果尚未安装Lumen,请先安装它: $ composer create-...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,262
精华内容 1,304
关键字:

lumen