raphhh/puppy-application

Puppy 框架的 HTTP 包

1.2.0 2015-04-18 11:40 UTC

This package is auto-updated.

Last update: 2024-08-25 21:43:50 UTC


README

Puppy 框架的 HTTP 包

Latest Stable Version Build Status Scrutinizer Quality Score Code Coverage Dependency Status Total Downloads Reference Status License

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使用)