iuravic/duktig-skeleton-web-app

基于Duktig MVC微型Web框架的PHP 7.1骨架Web应用程序

dev-master 2017-07-07 12:03 UTC

This package is not auto-updated.

Last update: 2024-09-29 02:58:31 UTC


README

Build Status Coverage Status

duktig-skeleton-web-app

这是一个使用Duktig微型MVC Web框架和基于PHP 7.1编写的库 iuravic/duktig-core 制作的骨架Web应用程序。

目录

关于

duktig-skeleton-web-app 是使用Duktig框架开发自己应用的起点。它基于 duktig-core 包,并提供所有必要的依赖。骨架应用程序还包含Duktig框架主要功能的示例。

duktig-core

建议您也查看 duktig-core 文档,它描述了Duktig框架的目的和功能,并解释了其基本元素和功能。

包设计

Duktig的核心服务大多数都与 duktig-core 包完全解耦。 duktig-core 通过定义其接口来描述它们,并且每个接口都作为独立包以适配器形式实现,针对现成的开源项目。这种方法提供了高度的灵活性、可重用性,并且通常被认为是良好的包设计。

依赖项

duktig-skeleton-web-app 通过使用流行和经过测试的开源包来组合完整的Duktig Web应用程序框架。适配器包用于简单地适配外部包的API以符合核心接口,从而使它们可以通过 duktig-core 使用。

以下项目和使用到的包用于为Duktig框架提供完整的功能

核心服务

services.php 文件显示了这些包是如何实现和配置以提供核心功能的。

安装

以下命令通过Composer创建新项目

$ composer create-project -s dev iuravic/duktig-skeleton-web-app {$PROJECT_PATH}

Duktig包的仓库目前尚未标记为相应版本,对此我深表歉意,但此命令仍将正确解析和获取所有依赖项,并创建您的项目。

使用和应用流程

让我们查看一个完整的请求到响应的生命周期,以及其中的一些关键元素,按照命令链中的顺序。

index.php

典型的index.php文件可能如下所示

<?php
    require __DIR__.'/../vendor/autoload.php';

    $app = (new \Duktig\Core\AppFactory)->make(
        __DIR__.'/../src/Config/config.php',
        \Duktig\Core\App::class
    );

    $app->run();

我们发现该应用程序是由 Duktig\Core\AppFactory 创建的,它通过提供自定义配置文件和应用程序类来实现。

AppFactory

Duktig\Core\AppFactory 通过以下方式创建应用程序实例:

  • 将用户配置与核心配置合并,
  • 通过使用 Duktig\Core\DI\ContainerFactory 实例化和配置 DI 容器,
  • 解析应用程序及其依赖项。

请求处理和 App

Duktig\Core\App 是框架的主要类,其 run() 方法是请求的入口点。框架通过完整的应用程序堆栈“运行”请求。它在其核心使用 HTTP 中间件,并组成一个由以下组成的中间件堆栈:

  • 应用程序中间件,
  • 路由中间件,
  • 控制器响应中间件。

Duktig 中存在两种中间件:应用程序中间件——它用于每个请求,以及特定于路由的中间件——它可以被分配到特定的路由。

在中间件堆栈的末尾是 ControllerResponder 中间件。它负责解析控制器/路由处理程序,并将响应对象从它返回到堆栈。

处理完响应后,框架将其发送到浏览器并终止应用程序业务。

示例项目功能

在此包中,一些功能被实现为简单的示例。这些可以作为“如何做”,它们可以被修改,或者简单地从您的项目中删除。基本上,它们应该有助于快速了解如何使用 Duktig 框架构建应用程序。

以下是一个功能列表的快速列表。

核心服务

'Config/services.php' 定义并注册了所有 核心服务,通过使用外部包来实现。

路由

参见路由配置 Config/routes.php

控制器

参见控制器目录 Controller/

DuktigSkeleton\Controller\IndexController 特点

  • 扩展 BaseController
  • 构造函数参数解析
  • 使用外部服务
  • 响应定义
  • 模板渲染
  • 重定向
  • URI 路径参数
  • 查询参数

中间件

以下中间件实现了它们对应的功能

事件

事件 EventIPInRange 是一个简单的事件对象,展示了如何

  • 扩展 EventAbstract
  • 使用外部服务
  • 为其监听器提供上下文数据

EventIPInRange 有一个监听器通过配置文件 Config/events.php 注册,名为 ListenerReportIP,演示了如何

服务

ExampleIPService 是一个简单的服务,实现了一些基本功能

  • ExampleIPService 本身是通过容器自动配置功能解析的(注意,它没有在 Config/services.php 中显式注册,因为Auryn实现了这个功能)
  • 依赖注入
  • 访问配置服务和配置参数

配置

在骨架项目中实现了以下配置设置

配置

在进行最终步骤并查看配置之前,请花点时间也看看 duktig-core 的文档。

配置文件

Duktig 的配置包含在 Config 目录中简单的 .php 配置文件 中。您的应用程序的 Config 文件夹 应该与 duktig-core 的配置内容相匹配。核心和您的应用程序的配置在运行时完全合并,并且您应用程序中定义的所有配置值都会覆盖核心的配置值。唯一的例外是 services.php 文件,其内容不会被覆盖,而是与您的应用程序的 services.php 合并。要跳过核心的服务配置,可以使用配置参数 'skipCoreServices'

配置服务

配置服务用于访问配置参数和值,即 config.php 文件的内容。它实现了由 Duktig\Core\Config\ConfigInterface 提供的简单 API。

它可以通过依赖注入访问,其中它被类型提示为 ConfigInterface,这将解析为其位置上的 Duktig\Core\Config\Config 服务。

配置服务是一个共享服务,这意味着其实例化不会返回一个空实例,而是一个已配置的值对象。

实现duktig-core的要求

duktig-core 包有一些 要求,必须实现并提供以创建一个完整的功能应用程序环境。这些要求需要实现,并且需要与容器 注册duktig-skeleton-web-app 包已经实现了所有这些要求;它们是分别打包的(见章节 依赖关系),并且已经作为项目的 要求 解决。

注册服务

服务在您的应用程序目录中的 Config/services.php 文件中注册。该文件必须返回一个闭包,它将容器作为参数,并在配置后返回它

<?php
return function($container) {
    // ...
    return $container;
};

中间件

Duktig 使用“单遍”兼容 PSR-15 中间件及其调度系统。框架内部存在两种不同的中间件类型。

应用程序中间件

应用程序中间件是每次请求都会运行的中间件。它是全局中间件,在您的应用程序目录中的 Config/middlewares.php 配置文件中定义。以下示例显示了如何分配两个应用程序中间件

<?php
return [
    \MyProject\Middleware\ExampleAppMiddleware1::class,
    \MyProject\Middleware\ExampleAppMiddleware2::class,
];

路由中间件

路由中间件分配给特定的路由,并且只有在解析该路由时才会运行。路由中间件通过使用应用程序的 Config/routes.php 文件中的 'middlewares' 路由配置参数来定义。以下简短摘录显示了如何将一个特定路由的中间件分配给 'example-route' 路由

<?php
return [
    'example-route' => [
        // ...
        'middlewares' => [
            \MyProject\Middleware\ExampleRouteMiddleware::class,
        ],
    ],
];

事件

事件和监听器可以通过配置或编程方式注册。尽管两种机制都可用,但通常建议使用配置来定义事件及其监听器,而不是编程方法,因为配置和代码的分离通常会导致代码的更好分解。但是,这种编程实践应根据具体情况评估。

通过配置文件注册

要注册事件及其监听器,请使用应用程序目录中的 Config/events.php 文件。以下示例显示了如何将两个事件及其各自的监听器进行注册

<?php
return [
    \MyProject\Event\EventIPInRange::class => [
        \MyProject\Event\ListenerReportIP::class,
    ],
    'custom-event-name' => [
        function($event) {
            // ...
            $event->getName();
        },
    ],
];

第一个事件作为一个独立的类存在,并使用其完全限定类名作为事件名称。其监听器 ListenerReportIP 也作为一个独立的类定义。所有此类具有自己类的独立事件都必须扩展 Duktig\Core\Event\EventAbstract 类。所有此类监听器都必须实现 Duktig\Core\Event\ListenerInterface。事件和监听器都由容器解决,并注入其构造函数依赖项。

第二个事件通过自定义名称定义,并分配一个闭包类型的监听器。闭包类型的监听器可以分配给任何事件,无论是独立的类还是自定义名称的事件。此监听器只能接受一个参数,即事件,并且不由容器解决。

如果事件仅由其唯一的名称确定,并且没有为其监听器提供特定的上下文信息,则它可以作为特殊的 Duktig\Core\Event\EventSimple 类分发和实例化。该 EventSimple 类会根据其唯一的名称动态创建事件。

程序化配置

要程序化地附加监听器,我们使用由 Duktig\Core\Event\Dispatcher\EventDispatcherInterface 定义的事件调度器 API。以下示例演示了注册与之前示例中相同的事件和监听器,其中使用了配置文件

$eventDispatcher->addListener(
    \MyProject\Event\EventIPInRange::class,
    \MyProject\Event\ListenerReportIP::class
);
$eventDispatcher->addListener(
    'custom-event-name',
    function($event) {
        // ...
    }
);

可以以相同的方式向 核心事件 添加自定义监听器,因此可以访问框架的内部检查点。

路由

路由在 Config/route.php 文件中定义。由于 Duktig 的 路由模型 受到 Symfony 路由模型的影响很大,因此其元素与之非常相似。

以下是一个路由示例,它接受一个名为 myParam 的 URI 路径参数。该参数作为参数传递给 IndexController::exampleAction。在以下示例中,路由被分配了一个 ExampleRouteMiddleware

<?php
return [
    'example-route-w-controller' => [
        'path' => '/example/{myParam}',
        'params_requirements' => ['myParam' => '.*'],
        'handler' => \MyProject\Controller\IndexController::class,
        'handler_method' => 'exampleAction',
        'methods' => ['GET'],
        'middlewares' => [\MyProject\Middleware\ExampleRouteMiddleware::class],
    ],
];

让我们看看另一个示例,其中一个路由在末尾有一个可选的后缀斜杠,并使用闭包类型处理程序。这种路由处理程序也会由容器解决,其参数将得到解决并注入。

<?php
return [
    'example-route-with-callable-handler' => [
        'path' => '/example-callable-handler{trailingSlash}',
        'params_requirements' => ['trailingSlash' => '/?'],
        'handler' => function (\Interop\Http\Factory\ResponseFactoryInterface $responseFactory) {
            $response = $responseFactory->createResponse();
            $response->getBody()->write('Response set by a callable route handler');
            return $response;
        },
        'handler_method' => null,
        'methods' => ['GET'],
    ]
];

完整的路由配置参数列表可以在 ´duktig-core´ 的 Config/routes.php 文件中找到。

测试

此软件包使用 PHPUnit 和 Mockery 实现了高代码覆盖率。要在命令行中运行其测试,请将软件包作为具有完整开发需求的新项目安装,然后在项目目录中运行命令

$ vendor/bin/phpunit -c phpunit.xml.dist

这将还在项目目录中的 coverage 目录中生成覆盖率报告。

这些测试涵盖了项目的 功能元素,而所有其他在项目中使用的包都分别进行了完全的单元测试。