raphhh / puppy-application
Puppy 框架的 HTTP 包
Requires
- php: >=5.4
- pimple/pimple: >=v3.0
- raphhh/trex-parser: ~1.0
- raphhh/trex-reflection: ~0.1
- symfony/http-foundation: ~2.6
- tedivm/stash: 0.12.*
Requires (Dev)
- phpunit/phpunit: @stable
This package is auto-updated.
Last update: 2024-08-25 21:43:50 UTC
README
Puppy 框架的 HTTP 包
Puppy 应用类似于 HTTP 控制器。它解析当前请求并调用匹配的控制器。
应用基本逻辑
- 指定所有特定请求的控制器
- 添加服务
- 从模块中管理服务和控制器
- 管理中间件
- 预处理/后处理
- 管理应用错误(待办事项)
安装
$ composer require raphhh/puppy-application
基本用法
Puppy 需要配置和请求才能运行。然后您可以添加一个控制器。
use Puppy\Application; use Puppy\Config\Config; use Symfony\Component\HttpFoundation\Request; $puppy = new Application(new Config(), Request::createFromGlobals()); $puppy->get('hello', function(){ return 'Hello world!'; }); $puppy->run(); //good dog! :)
对于配置,您可以使用任何实现 \ArrayAccess 的类,而不是 Puppy Config。
路由
路由简单地将请求匹配到控制器。当您调用此 uri 时,将调用该控制器。
如何添加控制器?
Puppy\Application 有一些简单的方法来帮助您声明您的控制器。
$puppy->get($uri, $controller); //filter on GET http method $puppy->post($uri, $controller); //filter on POST http method $puppy->json($uri, $controller); //filter on JSON format $puppy->any($uri, $controller); //filter only on the requested uri $puppy->filter($filter, $controller); //specific filter as callable
如何定义路由模式?
路由的模式是一个正则表达式,它将与特定的请求 uri 匹配。
只有当其模式与请求 uri 匹配时,您的控制器之一才会被调用。因此,根据 uri,您的控制器的代码将被执行。
$puppy->get('my/page/(\d)', $controller);
为了简化您的操作并使 uri 更易于阅读,您可以定义一些绑定。例如
$puppy->get('my/specific/:uri', $controller)->bind('uri');
默认情况下,绑定将接受字符串、数字、'_' 和 '-' 的模式。但您可以添加特定的正则表达式
$puppy->get('my/page/:index', $controller)->bind('index', '\d');
为了使您的生活更加简单,您可以使用预定义的绑定。例如
$puppy->get(':all', $controller); //every uri $puppy->get(':home', $controller); //home uri (empty or '/') $puppy->get(':slug', $controller); //string uri, with numeric, '_' and '-' $puppy->get(':id', $controller); //any unsigned int, except 0 $puppy->get(':index', $controller); //any unsigned int $puppy->get(':lang', $controller); //two letters lower case, eventually followed by hyphen and two letters upper case (e.i. fr-FR) $puppy->get(':datetime', $controller); //datetime with format yyyy-mm-ddThh:mm:ss or yyyy-mm-ddThh:mm:ss+hh:ss $puppy->get(':date', $controller); //date with format yyyy-mm-dd $puppy->get(':time', $controller); //time with format hh:mm:ss
如何指定其他请求约束?
当您使用 Puppy 方法设置控制器时,您还可以继续指定一些其他规则。
$puppy->get($uri, $controller)->content('xml/application'); $puppy->json($uri, $controller)->method('post');
所有约束都可以链接到同一个路由。
$puppy->any('my/page/:index', $controller) ->bind('index', '\d') ->method('post') ->content('json/application');
您还可以将路由限制为特定的路径命名空间。
$puppy->get('users', $controller)->restrict('admin'); // this is accessible only with the request uri 'admin/users'
如何分组路由?
您还可以将多个路由分组以执行一些常见操作。
$puppy->group([ $puppy->get($uri1, $controller1), $puppy->get($uri2, $controller2), ]) ->bind('index', '\d') ->method('post') ->restrict('admin');
控制器
什么是控制器?
控制器是任何可调用的。
例如,控制器可以是闭包
$puppy->get('hello', function(){ ... });
或它可以是类方法
$puppy->get('hello', array($controller, 'method'));
或您想要的可调用的任何内容...
控制器将返回什么?
字符串
您的控制器将返回发送给客户端的响应。这可能是一个简单的字符串。
$puppy->get('hello', function(){ return '<h1>Hello world!</h1>'; });
响应
但更强大的是,这也可以是一个 Response,它还将管理 http 标头。
$puppy->get('hello', function(){ return new Response('<h1>Hello world!</h1>'); });
为了帮助您管理一些常见操作,AppController 为您提供了一些酷的方法。请参阅 AppController 部分。
控制器将接收哪些参数?
控制器接收两种类型的参数,具体取决于您想要什么。
模式匹配
如果您想要接收模式与 uri 之间的匹配列表,您必须指定参数 "array $args"。
$puppy->get('hello/:all', function(array $args){ return $args['all']; //will return the value "world" for the uri "/hello/world" });
如果您使用绑定,则匹配 arg 的键是不带 ":" 的别名。例如,绑定 ":id" 可以通过键 "id" 获取。
服务
如果您想拥有服务容器,您必须指定参数 "ArrayAccess $services"。
$puppy->get('hello', function(\ArrayAccess $services){ ... });
当然,您可以使用匹配的 arg 来获取服务。
$puppy->get('hello', function(array $args, Container $services){ ... });
参数的顺序没有关系!
您还可以指定您想要的服务。您只需在参数中命名它。(参数的名称必须与您服务的名称完全相同。)
$puppy->get('hello', function(Request $request){ return 'You ask for the uri "'.htmlentities($request->getRequestUri()); });
请参阅服务部分以了解默认情况下可用的服务。
控制器能做什么?
控制器管理HTTP响应。因此,为了帮助您执行常见操作,您可以使用Puppy\Controller\AppController。这是一个包含一些实用方法的简单类。
AppController有哪些方法?
方法例如
$appController->render($templateFile); $appController->redirect($url); $appController->call($uri); $appController->abort(); $appController->flash()->get($myMessage); $appController->retrieve($key); $appController->getService($serviceName);
如何实现AppController?
有三种使用它的方法。
作为绑定类
首先,如果您简单地将闭包用作控制器,则AppController的所有方法都将绑定到您的闭包。
$puppy->get('hello', function(){ return $this->abort(); });
作为父类
其次,您可以创建自己的Controller类,该类继承自AppController。
use Puppy\Controller\AppController; class MyController extends AppController { public function myAction() { return $this->abort(); } }
作为服务类
第三,您可以在params中请求AppController作为服务。
$puppy->get('hello', function(AppController $appController){ return $appController->abort(); });
有关更多信息,请参阅服务部分。
是否有依赖项?
请注意,如果您使用AppController::flash(),则需要服务'session'。如果使用AppController::rend(),则需要服务'template'。
为了简化您的操作,您有两种解决方案。
与Puppy一起工作
直接与raphhh/puppy一起工作。
包含您所需的一切。
与Puppy/Service一起工作
您可以直接使用Puppy\Service\Session和Puppy\Service\Template。这两个服务与AppController配合得很好。
首先,您需要将它们的包包含到您的项目中。然后,您只需使用Puppy\Application::addService()添加这两个服务。有关更多信息,请参阅服务部分。
中间件
什么是中间件?
中间件只是执行在控制器之前的一段代码。中间件将触发与其关联的控制器调用。
例如,假设您只想为具有管理员权限的用户调用控制器。然后,您的中间件可以通过仅过滤可访问的控制器来为您控制这一点。
如何实现中间件?
只需将可调用对象链接到控制器。
$puppy->get($uri, $controller)->filter(function(){ return true; });
中间件像控制器一样工作:它可以任何可调用对象。唯一不同的是,中间件必须返回一个布尔值,表示是否可以调用控制器。
您也可以添加任何想要的中间件。它们将以相同的顺序执行。但是,当中间件返回false时,链将停止。
$puppy->get($uri, $controller) ->filter($middleware1) ->filter($middleware2) ->filter($middleware3);
像控制器一样,中间件使用相同的动态参数系统。您可以检索任何想要的服务。您只需在参数中指定它。
$puppy->get($uri, $controller)->filter(function(Request $request){ ... });
您还可以将中间件应用于一组路由。有关分组方法的更多信息,请参阅路由部分。
$puppy->group($routes) ->filter($middleware1) ->filter($middleware2);
预处理和后处理
您可以在路由前后轻松处理HTTP请求和响应。
方法'before'在路由之前调用并接收HTTP请求。
$puppy->before(function(Request $request){ ... });
方法'after'在路由之后调用并接收HTTP响应。
$puppy->after(function(Response $response){ ... });
您可以添加任意多的处理。
$puppy->before($callback1) ->before($callback2) ->after($callback3) ->after($callback4);
请注意,如果将闭包作为处理提供,则上下文将与应用程序绑定。
镜像
您需要一些uri像其他uri一样进行分析。这些uri将像指向特定预定义路由的镜像。
例如,您希望请求uri "mail"指向"contact"。 "contact"是一个实际路由,而"mail"必须执行完全相同的操作。因此,如果请求uri是"mail",则将调用路由"contact"。
$puppy->mirror('mail', 'contact'); //request uri "mail" will point to "contact"
镜像也接受动态参数。
$puppy->mirror('mail/:id', 'contact/{id}');
服务
什么是服务?
服务是一个类,它将存在于您所有的控制器中。
默认情况下,Puppy添加了一些服务
- config(一个包含根据您的环境配置的对象)
- request(一个包含当前请求上下文的对象。请注意,当前请求可能不是主请求。)
- requestStack(一个包含整个过程中所有请求的对象。您可以检索当前请求和主请求。)
- router(一个对象,可以分析您的应用程序中定义的所有路由和控制器。)
- frontController(Puppy\Controller\AppController类的实例)
- appController(Puppy\Controller\AppController类的实例)
- retriever(Puppy\Helper\Retriever类的实例)
您可以添加任何您想要的服务,例如模板库、ORM等。
如何添加服务?
因为Puppy使用Pimple作为服务容器,因此必须从可调用的函数中添加服务。
$puppy->addService('serviceName', function(Container $services){ return new MyService(); });
如何检索任何服务?
从应用程序
如果您使用应用程序对象。
$puppy->getService('myService');
从AppController
如果您使用AppController对象。
$appController->getService('myService');
请参阅AppController部分以获取有关此类的更多信息。
从任何控制器
更强大的方法是动态地从控制器的参数中检索您的服务。您只需指定一个与您的服务同名参数即可。
//you want the request? $puppy->get('hello', function(Request $request){ ... }); //you want the request and the config? $puppy->get('hello', function(Request $request, \ArrayAccess $config){ ... }); //you want the router and the appController? $puppy->get('hello', function(Router $router, AppController $appController){ ... });
参数的顺序无关紧要。
模块
什么是模块?
模块是一个类,它包装了一系列特定的服务和控制器。模块接收应用程序作为参数。因此,您的模块类可以添加任何在您的包中的服务和控制器。
//your module class class MyModule implements \Puppy\Module\IModule{ function init(\Puppy\Application $puppy){ $puppy->get('my-module/:all', function(){ return 'This is my module'; }); } } //add the module to the Application $puppy->addModule(new MyModule());
如何动态加载模块?
您可以为您的项目动态加载所有模块。您只需创建具有以下两个规定的类
- 类的名称必须以'Module'结尾。
- 类必须扩展Puppy\Module\IModule。
Application::initModules(new ModulesLoader())将为您加载项目中的模块(默认情况下为"src"和"vendor"目录中的模块)。您可以使用带有ModulesLoaderProxy()的缓存加载器。搜索将在第一次调用时仅在项目中执行,并将缓存到文件系统中。
应用程序错误(待办事项)
您可以为每个错误(包括致命错误)和未捕获的异常添加错误/异常处理器。
$puppy->error(function(\Exception $exception){ ... });
如果脚本因致命错误而中断,您可以指定一个控制器以发送正确的HTTP头。
$puppy->die($controller);
建议仅在开发环境中显示错误(display_error),但始终截获错误(error_reporting)。有关错误的更多信息,请参阅PHP文档。
配置选项
- 'module.directories' => 定义查找动态模块的目录。(由ModuleFactory使用)
- 'module.cache.enable' => 启用模块加载器的文件缓存。(由ModuleFactory使用)
- 'module.cache.path' => 设置保存模块加载器缓存的文件路径。(由ModuleFactory使用)