@a5635268
2016-05-04T16:47:37.000000Z
字数 14914
阅读 2446
源码分析与使用笔记
http://laravelacademy.org/lumen-docs
http://lumen.laravel-china.org/docs
http://laravelacademy.org/post/3361.html
http://laravelacademy.org/post/3365.html
http://lumen.laravel-china.org/docs/configuration
# 读取配置
$value = config('app.timezone');
# 设置配置
config(['app.timezone' => 'America/Chicago']);
# 自定义配置文件的加载
$app->configure('在config目录下的文件名');
http://lumen.laravel-china.org/docs/routing
// 有效的路由方法
$app->get($uri, $callback);
$app->post($uri, $callback);
$app->put($uri, $callback);
$app->patch($uri, $callback);
$app->delete($uri, $callback);
$app->options($uri, $callback);
$app->get('/', function() {
return 'Hello World';
});
$app->post('foo/bar', function() {
return 'Hello World';
});
$app->get('posts/{post}/comments/{comment}', function ($postId, $commentId) {
//路由参数不能包含’-‘字符,需要的话可以使用_替代。
});
// 从URL中抓取参数
$app->get('user/{id}', function($id) {
return 'User '.$id;
});
// 正则表达式约束 和 Laravel 不兼容
$app->get('user/{name:[A-Za-z]+}', function($name) {
//
});
# 生成 URL
$url = url('foo');
# 命名路由
$app->get('user/profile', ['as' => 'profile', function() {
//
}]);
$app->get('user/profile', [
'as' => 'profile', 'uses' => 'UserController@showProfile'
]);
// 使用路由名称
$url = route('profile');
// 进行重定向
$redirect = redirect()->route('profile');
# 路由群组
// 统一处理foo与bar
$app->group(['middleware' => 'foo|bar'], function($app)
{
$app->get('/', function() {
// Uses Foo & Bar Middleware
});
$app->get('user/profile', function() {
// Uses Foo & Bar Middleware
});
});
// 指定在这群组中控制器的命名空间:
$app->group(['namespace' => 'Admin'], function() use ($app){
// 控制器在 "App\Http\Controllers\Admin" 命名空间下
$app->group(['namespace' => 'User'], function()
{
// 控制器在 "App\Http\Controllers\Admin\User" 命名空间下
});
});
http://laravelacademy.org/post/3385.html
http://lumen.laravel-china.org/docs/controllers
<?php
namespace App\Http\Controllers;
use App\User;
class UserController extends Controller
{
/**
* 为指定用户显示详情
*
* @param int $id
* @return Response
*/
public function show($id)
{
return User::findOrFail($id);
}
}
// 绑定路由
$app->get('user/{id}', 'UserController@show');
默认情况下,bootstrap/app.php
将会在一个路由分组中载入routes.php文件,该路由分组包含了控制器的根命名空间。
// 指定控制器路由的名字
# ceshi
$app->get('foo', ['uses' => 'FooController@method', 'as' => 'name']);
// 为已命名的路由生成URL;
$url = route('name');
// 中间件分配给控制器路由
$app->get('profile', [
'middleware' => 'auth',
'uses' => 'UserController@show'
]);
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使用服务容器解析所有的Lumen控制器,因此,可以在控制器的构造函数中类型提示任何依赖,这些依赖会被自动解析并注入到控制器实例中:
namespace App\Http\Controllers;
use Illuminate\Routing\Controller;
use App\Repositories\UserRepository;
class UserController extends Controller
{
/**
* The user repository instance.
*/
protected $users;
/**
* 创建新的控制器实例
*
* @param UserRepository $users
* @return void
* @translator http://laravelacademy.org
*/
public function __construct(UserRepository $users)
{
$this->users = $users;
}
}
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
class UserController extends Controller
{
/**
* 存储新用户
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$name = $request->input('name');
//
}
//$app->put('user/{id}', 'UserController@update');
//将路由参数放到其他依赖之后
public function update(Request $request, $id)
{
//
}
}
http://laravelacademy.org/post/3396.html
http://lumen.laravel-china.org/docs/requests
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
class UserController extends Controller
{
/**
* 存储新用户
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
//获取用户输入的name
$name=$request->input('name');
//第二参数为默认值
$name = $request->input('name', 'Sally');
//表单输入使用点来访问数组;
$input = $request->input('products.0.name');
$names = $request->input('products.*.name');
if ($request->has('name')) {
//判断输入值是否出现
}
//获取所有输入数据
$input = $request->all();
//获取输入的部分数据
$input = $request->only('username', 'password');
$input = $request->except('credit_card');
//获取请求url
$uri=$request->path();
if($request->is('admin/*')){
// is方法允许你验证进入的请求是否与给定模式匹配。使用该方法时可以使用*通配符
# ceshi
}
// 获取完整url
//不带请求参数
$url=$request->url();
//带请求参数
$url = $request->fullUrl();
//获取请求方法
$method=$request->method();
if($request->isMethod('post')){
//
}
//文件上传
$file = $request->file('photo');
if ($request->hasFile('photo')) {
//判断文件在请求中是否存在
}
if ($request->file('photo')->isValid()){
//验证文件是否上传成功
}
//使用move方法将上传文件保存到新的路径,该方法将上传文件从临时目录(在PHP配置文件中配置)移动到指定新目录
$request->file('photo')->move($destinationPath);
$request->file('photo')->move($destinationPath, $fileName);
}
}
关于文件上传,更多可以查看: http://api.symfony.com/2.7/Symfony/Component/HttpFoundation/File/UploadedFile.html
略
http://lumen.laravel-china.org/docs/requests#old-input
Lumen 可以让你保留这次的输入数据,直到下一次请求发送前。例如,你可能需要在表单验证失败后重新填入表单值。
http://lumen.laravel-china.org/docs/requests#cookies
http://laravelacademy.org/post/3399.html
http://lumen.laravel-china.org/docs/responses
# 基本响应 返回一个字符串
$app->get('/', function () {
return 'Hello World';
});
# 响应对象
use Illuminate\Http\Response;
$app->get('home', function () {
return (new Response($content, $status))
->header('Content-Type', $value);
});
// 可以使用辅助函数response:
$app->get('home', function () {
return response($content, $status)
->header('Content-Type', $value);
});
完整的Response方法列表:
- https://laravel.com/api/master/Illuminate/Http/Response.html
- http://api.symfony.com/2.7/Symfony/Component/HttpFoundation/Response.html
// 添加响应头到响应
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',
]);
// json
return response()->json(['name' => 'Abigail', 'state' => 'CA']);
// jsonp
return response()->json(['name' => 'Abigail', 'state' => 'CA'])
->setCallback($request->input('callback'));
// 文件下载
return response()->download($pathToFile);
return response()->download($pathToFile, $name, $headers);
// 重定向
$app->get('dashboard', function () {
return redirect('home/dashboard');
});
// 重定向到命名路由
return redirect()->route('login');
// 如果路由中有参数,可以将其作为第二个参数传递到route方法
return redirect()->route('profile', [1]);
//如果要重定向到带ID参数的路由,并从Eloquent模型中取数据填充表单,可以传递模型本身,ID会被自动解析出来:
return redirect()->route('profile', [$user]);
http://lumen.laravel-china.org/docs/views
略,一般lumen框架用不到视图
http://lumen.laravel-china.org/docs/middleware
http://laravelacademy.org/post/3379.html
HTTP 中间件提供一个方便的机制来过滤进入应用程序的 HTTP 请求,例如,Lumen 默认包含了一个中间件来检验用户身份验证,如果用户没有经过身份验证,中间件会将用户导向登录页面,然而,如果用户通过身份验证,中间件将会允许这个请求进一步继续前进。
当然,除了身份验证之外,中间件也可以被用来执行各式各样的任务,CORS 中间件负责替所有即将离开程序的响应加入适当的响应头,一个日志中间件可以记录所有传入应用程序的请求。 Lumen 框架已经内置一些中间件,包括维护、身份验证、CSRF 保护,等等。所有的中间件都位于 app/Http/Middleware
目录内。
感觉有点类似YII框架中的行为;
class OldMiddleware {
// 在类里面增加handle方法
public function handle($request, $next)
{
return $next($request);
}
// 若是年龄小于200 ,中间件将会返回 HTTP 重定向给客户端
public function handle($request, Closure $next)
{
if ($request->input('age') < 200) {
return redirect('home');
}
//请求将会进一步传递到应用程序。只需调用带有 $request 的 $next 方法,即可将请求传递到更深层的应用程序(允许跳过中间件)。
return $next($request);
}
}
HTTP 请求在实际碰触到应用程序之前,最好是可以层层通过许多中间件,每一层都可以对请求进行检查,甚至是完全拒绝请求。
# 在请求前执行操作
namespace App\Http\Middleware;
class BeforeMiddleware implements Middleware {
public function handle($request, Closure $next)
{
// Perform action
return $next($request);
}
}
# 在请求后执行操作
namespace App\Http\Middleware;
class AfterMiddleware implements Middleware {
public function handle($request, Closure $next)
{
$response = $next($request);
// Perform action
return $response;
}
}
# 全局中间件注册:只需要将相应中间件类放到bootstrap/app.php文件的$app->middleware()调用中即可:
$app->middleware([
App\Http\Middleware\OldMiddleware::class
]);
# 分配中间件到指定路由,首先应该在bootstrap/app.php文件中分配给该中间件一个简写的key,默认情况下,$app->routeMiddleware()方法包含了Lumen自带的入口中间件,添加你自己的中间件只需要将其追加到后面并为其分配一个key:
$app->routeMiddleware([
// 分配一个key为old
'old' => 'App\Http\Middleware\OldMiddleware',
]);
// 在路由选项数组中使用middleware键来指定中间件
$app->get('admin/profile', ['middleware' => 'old', function () {
//
}]);
// 为某个路由指定多个中间件
$app->get('/', ['middleware' => ['first', 'second'], function () {
//
}]);
namespace App\Http\Middleware;
use Closure;
class RoleMiddleware
{
/**
* 运行请求过滤器
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string $role
* @return mixed
* translator http://laravelacademy.org
*/
//controller前
public function handle($request, Closure $next, $role)
{
if (! $request->user()->hasRole($role)) {
// Redirect...
}
return $next($request);
}
//controller后;
public function terminate($request, $response)
{
// 存储session数据...
}
}
// 中间件参数可以在定义路由时通过:分隔中间件名和参数名来指定,多个中间件参数可以通过逗号分隔
$app->put('post/{id}', ['middleware' => 'role:editor', function ($id) {
//
}]);
有时候中间件可能需要在HTTP响应发送到浏览器之后做一些工作。比如,Lumen自带的“session”中间件会在响应发送到浏览器之后将session数据写到存储器中,为了实现这个,定义一个“终结者”中间件并添加terminate方法到这个中间件:
namespace Illuminate\Session\Middleware;
use Closure;
class StartSession
{
public function handle($request, Closure $next)
{
return $next($request);
}
// terminate方法将会接收请求和响应作为参数。一旦你定义了一个终结中间件,应该将其加入到 bootstrap/app.php 的全局中间件列表中。
public function terminate($request, $response)
{
// 存储session数据...
}
}
在中间件上调用 terminate
方法时,Lumen 会从服务容器中解析一个该中间件的新实例,如果你想要在处理 handle 和 terminate
方法时使用同一个中间件实例,在容器中注册中间件时使用singleton方法即可。
服务提供者是所有Laravel应用启动的中心,是应用配置的中心.注册服务容器绑定、事件监听器、中间件甚至路由。
在lumen中再是bootstrap/app.php中注册服务提供者;
<?php
namespace App\Providers;
use Riak\Connection;
use Illuminate\Support\ServiceProvider;
class RiakServiceProvider extends ServiceProvider{
/**
* 服务提供者加是否延迟加载.
* 这个地方如果设置为true的话,还需要定义一个provides方法;
*/
protected $defer = true;
/**
* 继承ServiceProvider,并且至少在服务提供者中定义一个方法:register。在register方法内,你唯一要做的事情就是绑事物到服务容器,不要尝试在其中注册任何时间监听器,路由或者任何其它功能。
*/
public function register()
{
// 在服务容器中定义了一个Riak\Contracts\Connection的实现。这里的类可以写在任何地方但建议写在app下面建立对应的目录来存放
$this->app->singleton('Riak\Contracts\Connection', function ($app) {
return new Connection(config('riak'));
});
}
// 在服务提供者中注册视图composer就要用到boot方法,还可以在boot方法中类型提示依赖,服务容器会自动注册你所需要的依赖 boot(Illuminate\Contracts\Routing\ResponseFactory $factory)
public function boot()
{
view()->composer('view', function () {
//
});
}
// 使用 bind 方法注册一个绑定
public function bindTest(){
$this->app->bind('HelpSpot\API', function ($app) {
return new HelpSpot\API($app['HttpClient']);
});
}
//singleton 方法绑定一个只需要解析一次的类或接口到容器,
public function singletonTest(){
$this->app->singleton('FooBar', function ($app) {
return new FooBar($app['SomethingElse']);
});
}
//绑定一个已存在的实例;
public function instanceTest(){
$fooBar = new FooBar(new SomethingElse);
$this->app->instance('FooBar', $fooBar);
}
/**
* 获取由提供者提供的服务.
*
* @return array
*/
public function provides()
{
return ['Riak\Contracts\Connection'];
}
}
http://laravelacademy.org/post/2910.html
# 绑定接口到实现
/*
App\Contracts\EventPusher是接口,通过该接口依赖注入App\Services\RedisEventPusher
*/
$this->app->bind('App\Contracts\EventPusher', 'App\Services\RedisEventPusher');
# 上下文绑定貌似只适合构造函数解析的情况
$this->app->when('App\Handlers\Commands\CreateOrderHandler')
->needs('App\Contracts\EventPusher')
->give('App\Services\PubNubEventPusher');
$this->app->when('App\Handlers\Commands\CreateOrderHandler')
->needs('App\Contracts\EventPusher')
->give(function () {
// Resolve dependency...
});
# 绑定原始值
$this->app->when('App\Handlers\Commands\CreateOrderHandler')
->needs('$maxOrderCount')
->give(10);
# 标签
$this->app->bind('SpeedReport', function () {
//
});
$this->app->bind('MemoryReport', function () {
//
});
$this->app->tag(['SpeedReport', 'MemoryReport'], 'reports');
$this->app->bind('ReportAggregator', function ($app) {
return new ReportAggregator($app->tagged('reports'));
});
# 解析
$fooBar = $this->app->make('FooBar');
$fooBar = $this->app['FooBar'];
// 最常用的就是通过在类的构造函数中对依赖进行类型提示来从容器中解析对象,包括控制器、事件监听器、队列任务、中间件等都是通过这种方式。在实践中,这是大多数对象从容器中解析的方式。
# 容器事件
$this->app->resolving(function ($object, $app) {
// 容器解析所有类型对象时调用
});
$this->app->resolving(function (FooBar $fooBar, $app) {
// 容器解析“FooBar”对象时调用
});
// 通过服务提供者EventServiceProvider的$listen数组
protected $listen = [
'App\Events\PodcastWasPurchased' => [
'App\Listeners\EmailPurchaseConfirmation',
],
// 事件 => 对应的事件监听器
];
// 在业务逻辑中通过 Event 门面或者 Illuminate\Contracts\Events\Dispatcher 契约的具体实现类作为事件分发器手动注册事件
public function boot(DispatcherContract $events)
{
parent::boot($events);
$events->listen('event.name', function ($foo, $bar) {
//
});
}
// 可以使用通配符作为事件监听器,从而允许你通过同一个监听器捕获多个事件
$events->listen('event.*', function (array $data) {
//
});
namespace App\Events;
// 没有其他特定逻辑,仅仅存储一个逻辑对象,如果需要序列化的话,就使用的 SerializesModels trait
public function __construct(Podcast $podcast)
{
$this->podcast = $podcast;
}
namespace App\Listeners;
// 所有事件监听器通过服务容器解析,所以依赖会自动注入:
public function __construct(Mailer $mailer){
$this->mailer = $mailer;
}
// 在 handle 方法内,你可以执行任何需要的逻辑以响应事件。
public function handle(PodcastWasPurchased $event)
{
// Access the podcast using $event->podcast...
return false; //停止事件向下传播;
}
namespace App\Listeners;
use App\Events\PodcastWasPurchased;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
// 监听器类实现 ShouldQueue 接口既可放到队列;
class EmailPurchaseConfirmation implements ShouldQueue{
//
}
namespace App\Listeners;
use App\Events\PodcastWasPurchased;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class EmailPurchaseConfirmation implements ShouldQueue{
use InteractsWithQueue;
// Illuminate\Queue\InteractsWithQueue trait 提供了delete 和 release方法的访问权限
public function handle(PodcastWasPurchased $event)
{
if (true) {
$this->release(30);
}
}
}
namespace App\Http\Controllers;
# 使用辅助函数event或Event门面来触发事件
event(new ExampleEvent);
Event::fire(new ExampleEvent);
laravelacademy.org/post/3279.html
# file: App\Http\Controllers\Controller
protected static $responseBuilder = 'responseBuilder'; //指明通过该方法来输出验证提示;
// 通过自己的validate来返回验证信息
protected function validate(Request $request , array $rules , array $messages = [] , array $customAttributes = []){
$validator = Validator::make($request->all(), $rules,$messages);
if ($validator->fails()) {
$errors = $validator->errors()->getMessages();
$errors = current(current($errors));
$this->returnData($errors);
}
}
$this->validate($request, [
// 分配bail规则以后,如果title属性上的required规则验证失败,则不会检查unique规则
'title' => 'bail|required|unique:posts|max:255',
'body' => 'required',
// 嵌套内容可以通过.来访问
'author.name' => 'required',
// 验证给定person数组输入中每个email是否是唯一的
'person.*.email' => 'email|unique:users'
]
);
// 验证钩子之后
$validator = Validator::make(...);
$validator->after(function($validator) {
if ($this->somethingElseIsInvalid()) {
// errors()获取Illuminate\Support\MessageBag
$validator->errors()->add('field', 'Something is wrong with this field!');
}
});
在laravel中的视图有一个error变量来保存这些信息,该变量是保存在session中,是一个Illuminate\Support\MessageBag对象实例,该错误的格式可以自定义
$messages = $validator->errors();
// 第一条错误信息
$messages->first();
// 关于email的第一条错误信息
$messages->first('email');
// 关于email的所有错误信息
$messages->get('email');
// 获取所有字段的所有错误信息
$messages->all()
// 判断消息中是否存在某字段的错误信息
$messages->has('email')
// 获取指定格式的错误信息
$messages->first('email', '<p>:message</p>');
$messages->all('<li>:message</li>');
// 自定义错误信息,手动传入;
$messages = [
'required' => 'The :attribute field is required.',
];
// 除:attribute占位符外还可以在验证消息中使用其他占位符
$messages = [
'same' => 'The :attribute and :other must match.',
'size' => 'The :attribute must be exactly :size.',
'between' => 'The :attribute must be between :min - :max.',
'in' => 'The :attribute must be one of the following types: :values',
];
// 为特定字段指定自定义错误信息,可以通过”.”来实现,首先指定属性名,然后是规则
$messages = [
'email.required' => 'We need to know your e-mail address!',
];
$validator = Validator::make($input, $rules, $messages);
// 定义语言包resources/lang/xx/validation.php语言文件的custom数组,然后进行配置;
'locale' => env('APP_LOCALE', 'zh_cn'),