Rxn PHP 示例项目

dev-master 2018-09-29 05:09 UTC

This package is not auto-updated.

Last update: 2024-09-29 04:49:24 UTC


README

alt tag

A fast, simple, and powerful API framework for PHP. Responds to API requests with JSON, ensuring that your backend is completely separated from your frontend

请注意:Rxn 目前处于积极开发中,并被认为仍处于 早期 alpha 阶段

Rxn("reaction"的缩写)是一个旨在简化PHP生成视图的复杂性和混乱的框架 -- 将视图卸载到任何您喜欢的任何前端。

Rxn背后的哲学很简单:严格的后端/前端解耦

  1. 后端应该 通过API访问
  2. 后端应该 以JSON格式渲染响应
  3. 前端应负责解析JSON响应
  4. 前端应负责生成用户视图
  5. 通过严格的 后端/前端解耦,可以发生一些奇妙的事情
  • 后端和前端都可以分别使用版本化的API合约作为参考进行开发
  • 后端和前端都具有较少的纠缠复杂性,提供简单且干净的流程
  • 后端或前端可以完全用完全不同的解决方案替换,从而在以后提供更大的灵活性
  • 并行前端开发变得极其简化(例如,利用内部应用程序、外部应用程序、手机应用程序等,使用相同的后端)。

Alpha 版本特性

包括计划的beta版功能(未勾选)

  • 3.5+ GPA代码气候
  • 80%+ 单元测试代码覆盖率
  • 温和的学习曲线 (你不必是专家就可以快速上手)
    • 通过Composer安装
  • 与现有数据库模式简单的工作流程
    • 代码生成
      • 命令行界面(CLI)实用工具,用于创建控制器和模型
  • 数据库抽象
    • PDO支持多个数据库
    • 支持多个数据库连接
  • 安全
    • 预处理语句 (有助于防止SQL注入攻击)
    • I/O清理 (有助于防止XSS攻击)
    • 会话同步令牌 (有助于防止CSRF攻击)
    • SSL/TLS支持 (有助于防止中间人攻击)
  • 强大的错误处理 (在任意位置抛出异常,Rxn 处理其余部分)
  • 调试实用工具
  • 版本化 (有助于将来减少API维护的麻烦)
    • 版本化控制器
    • 版本化操作
  • 脚手架 (快速应用程序原型设计)
    • 无版本CRUD端点,反映当前的记录
  • URI路由
    • 使用Apache2
    • 使用NGINX
  • 依赖注入(DI)容器容器
    • 控制器方法注入
    • DI自动绑定 (使用类型提示自动注入构造函数参数)
  • 对象关系映射(ORM)
    • Rxn-ORM
      • 对任何数据库记录或关系表进行CRUD操作
      • ORM自动绑定 (从数据库结构和外键自动推导关系)
      • 软删除
    • 支持第三方ORM
  • 速度和性能
    • PSR-4自动加载 (小体积)
    • 缓存机制
      • 本地查询缓存 (带有过期时间)
      • 对象文件缓存 (快速的实例化)
  • 认证
    • 支持第三方库
      • OAUTH2
      • OpenId
      • SAML
  • 使用现有(或生成的)API合约自动验证API请求
  • 事件日志记录
  • 邮件发送器
  • 调度器
  • 可选的模块化插件,实现松耦合和更高的灵活性

许可证

Rxn 采用许可和免费的 MIT 许可。

分层命名空间和自动加载

Rxn 使用与类文件目录结构明确匹配的命名空间结构。虽然这也非常方便,但它主要用于实现一些相当酷的自动加载功能。

例如,假设你创建了一个名为 \Organization\Product\Model\MyAwesomeModel 的类。只需将文件放入遵循命名空间约定的目录结构中(例如,{root}/organization/product/model/MyAwesomeModel.php)。当你需要调用该类时,只需直接调用类即可。无需在任何地方放置 require

BEFORE(未使用自动加载)

<?php

require_once('/organization/product/model/MyAwesomeModel.php');

use \Organization\Product\Model\MyAwesomeModel;

$object = new MyAwesomeModel()
// object gets created!

AFTER(使用自动加载)

<?php

use \Organization\Product\Model\MyAwesomeModel;

$object = new MyAwesomeModel()
// object gets created!

这种模式也存在于 Rxn 的原生类中。例如,响应类(\Rxn\Framework\Http\Response)位于 {root}/rxn/api/controller 目录。自动加载是 Rxn 减少开销的许多方法之一。

自动加载功能支持以下文件扩展名(你还可以在 \Rxn\Framework\Config 中定义自定义扩展名)

  • .php
  • .class.php
  • .interface.php
  • .model.php
  • .controller.php

错误处理

Rxn 生存、呼吸、进食异常。考虑以下代码片段

try {
    $result = $databse->query($sql,$bindings);
} catch (\PDOException $exception) {
    throw new \Exception("Something went terribly wrong!",422);
}

如果你在任何地方抛出 \Exception,Rxn 将自动终止,回滚任何正在进行的数据库事务,然后使用 JSON 优雅地响应

{
    "_rxn": {
        "success": false,
        "code": 422,
        "result": "Unprocessable Entity",
        "message": "Something went terribly wrong!",
        //...
    }
}

路由请求参数

使用 Rxn 的后端可能的一个 API 端点示例可能如下所示

https://yourapp.tld/v2.1/order/doSomething

其中

  1. v2.1 是端点的 版本
  2. order控制器
  3. doSomething 是控制器的 动作(一个公共方法)

现在,如果你想在请求中添加一个 id=1234 的 GET 键值对,在 PHP 中你通常会这样做

BEFORE

https://yourapp.tld/v2.1/order/someAction?id=1234

在 Rxn 中,你可以通过在 URL 中使用正斜杠(/)作为分隔符来简化这一点,如下所示

AFTER

https://yourapp.tld/v2.1/order/someAction/id/1234

versioncontrolleraction 之后,参数的个数必须是奇数,否则会导致错误。

版本化控制器与动作

通过版本化你的端点 URL(例如,v1.1v2.4 等),你可以放心地知道,当你改变后端端点行为时,你不会意外地破坏前端。此外,版本化还有助于保持你的文档井然有序;前端开发者可以按照文档进行构建,一切都将 正常工作

因此,对于版本为 v2.1 的端点,第一个数字(2)是 控制器版本,第二个数字(1)是 动作版本。下面的示例是声明控制器版本 2 和动作版本 1 的方法

namespace Organization\Product\Controller\v2;

class Order extends \Rxn\Framework\Http\Controller
{
    public function doSomething_v1() {
        //...
    }
}

这允许创建可维护、符合现实的文档,前端和后端开发者都可以支持。

脚手架

想要探索和实验你的新式后端架构吗?没问题,只要你有数据库模式,你就有一系列脚手架 API 可以玩耍!使用类似以下 URI 访问脚手架端点(注意 api 而不是版本号)

https://yourapp.tld/api/order/create
https://yourapp.tld/api/order/read/id/{id}
https://yourapp.tld/api/order/update/id/{id}
https://yourapp.tld/api/order/delete/id/{id}
https://yourapp.tld/api/order/search

脚手架 API 是无版本号的 API,旨在允许前端开发者通过创建、读取、更新和删除(CRUD)操作以及搜索的形式完全访问后端。它们的主要优点是在应用开发的早期阶段,你不需要花费大量时间手动创建 CRUD 端点。(因为需求在这些开发早期阶段不断变化,事情一直在不断变化。)

警告:由于脚手架API没有版本号,它们继承了所有与无版本号API相关的问题。一旦后端被更改,这些API也会相应更改;这可能会以意想不到或隐蔽的方式破坏应用程序。因此,在开发过程即将完成时,将无版本号API转换为有版本号的API是明智之举。

依赖注入(DI)容器

尽管大多数人甚至没有意识到,也会以某种形式进行依赖注入,但事实上,手动实例化和注入具有大量依赖关系的类可能相当麻烦。以下示例应有助于展示通过容器容器进行自动依赖注入的好处。

之前(手动DI)

// instantiate the dependencies
$config    = new Config();
$database  = new Database($config);
$registry  = new Registry($config,$database);
$filecache = new Filecache($config);
$map       = new Map($registry,$database,$filecache);

// call the action method
$this->doSomething_v1($registry,$database,$map);

public function doSomething_v1(Registry $registry, Database $database, Map $map) {
    $customer = new Customer($registry,$database,$map);
    //...
}

之后(使用DI容器容器)

// call the action method
$this->doSomething_v1($app->container);

public function doSomething_v1(Container $container) {
    $customer = $container->get(Customer::class);
    //...
}

希望您能看出好处。使用Rxn,无需每次都实例化前提条件!使用容器容器让生活更轻松。

控制器方法注入

只需将所需的类作为参数进行类型提示,然后瞬间,DI容器容器将为您猜测所有依赖项,并自动加载和注入它们。无需混乱的require。 您无需手动注入依赖项!

之前(手动实例化)

// require the dependencies
require_once('/path/to/Config.php');
require_once('/path/to/Collector.php');
require_once('/path/to/Request.php');

public function doSomething_v1() {
    // instantiate the dependencies
    $config = new Config();
    $collector = new Collector($config);
    $request = new Request($collector,$config);
    
    // grab the id from the request
    $id = $request->collectFromGet('id');
    //...
}

之后(自动实例化和注入)

public function doSomething_v1(Request $request) {
    // grab the id from the request
    $id = $request->collectFromGet('id');
    //...
}

看到区别了吗?