naglfar/amper

PHP的简单REST API引擎

安装次数: 131

依赖项: 0

建议者: 0

安全: 0

星标: 2

关注者: 3

分支: 0

开放性问题: 0

类型:引擎

dev-master 2019-12-25 19:19 UTC

This package is auto-updated.

Last update: 2024-09-10 20:53:28 UTC


README

Amper是一个用于快速原型设计和构建REST API的PHP微框架。

安装

要使用composer安装,请使用以下命令:

composer require naglfar/amper:dev-master

您可以使用默认安装程序启动您的项目。在您的根目录中创建install.php并运行它。

define('GLOBAL_DIR', __DIR__);
require_once(GLOBAL_DIR.'/vendor/autoload.php');
$Installer = new Amper\Installer;
$Installer->start();

如果您不想使用安装程序,请使用以下手动方法:

在您的项目根目录中创建index.php文件。

define('GLOBAL_DIR', __DIR__);
require_once(GLOBAL_DIR.'/config/bootstrapper.php');

为了使用队列,请安装predis库和pm2。

composer require predis/predis
npm i -g pm2

composer.json示例

{
    "require": {
        "naglfar/amper": "dev-master",
        "predis/predis": "^1.1"
    },
    "autoload": {
        "psr-4": {
            "App\\": "app/"
        }
    }
}

根据以下结构配置您的项目:

一般结构

  • App
    • 控制器
      • ExampleController.php
    • 分发器
      • ExampleDispatcher.php
    • 实体
      • ExampleEntity.php
    • 中间件
      • ExampleMiddleware.php
    • 存储库
      • ExampleRepo.php
    • Routes.php
  • config
    • bootstrapper.php
    • cache.php
    • database.php
    • queue.php
    • modules.php
  • modules
    • example
      • 控制器
      • 实体
      • 中间件
      • 存储库
      • EntityLoader.php
      • Routes.php
  • index.php
  • migrate.php
  • queue.php

路由

Amper将自动在App命名空间中搜索Routes类并调用_register()方法。

namespace App;

use Amper\Router;

class Routes
{

  public function _register(Router $Router) : void
  {
    // Passing array of middlewares as a 3-rd argument
    $Router->options('/api/*', '', [ 'CorsMiddleware' ]);
    // Grouping routes with same middleware
    $Router->group('/api/v1',
    [
      ['GET','{product}', 'ExampleController@index'],
      ['POST','{product}/show', 'ExampleController@show']
    ], [ 'CorsMiddleware' ]);
    // Passing single routes
    $Router
      ->get('/example', 'ExampleController@example', [ 'CorsMiddleware' ])
      ->post('/example', 'ExampleController@examplePost', [ 'CorsMiddleware' ]);
  }
}

控制器

控制器类的每个方法默认接收两个参数:请求和响应。

namespace App\Controllers;

use \Amper\Request;
use \Amper\Response;

class ExampleController {
  
  public function show(Request $req, Response $res)
  {
    // Body of the request. In case of GET method body always is empty array
    $Body = $req->getBody(); 
    // Params from the Router. In case of show method, param from example is "product"
    $Params = $req->getParams();
    // Method of the request. POST, GET or another one
    $Method = $req->getMethod();
    // Query from the request URL string. In case of GET method this one will be filled up
    $Query = $req->getQuery();
    // Headers of the request
    $Headers = $req->getHeaders();

    $res
      ->setStatus(200) // Setting up HTTP status code of the response
      ->setMeta(['type' => 'success']) // Building meta data of response
      ->setData(['some' => 'payload']) // Passing payload
      ->toJson(); // Encoding to JSON
  }
}

中间件

中间件是将在请求到达控制器之前执行的功能。

以下是一个CORS中间件的示例,设置正确的响应头。

namespace App\Middleware;

use Amper\Request;
use Amper\Response;

class CorsMiddleware {
  // By default Amper will search for handle() method and passes into this method Request and Response instances
  public function handle(Request $request, Response $response)
  {
    header('Content-Type: text/html; charset=utf-8');
    header('Access-Control-Allow-Origin: *');
    header('Access-Control-Allow-Headers: *');
    header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
    // If request method is OPTIONS, send response directly to client, in other cases set proper headers
    if ($request->getMethod() == 'OPTIONS') {
      $response
        ->setMeta(['type' => 'success'])
        ->toJson()
        ->execute();
      $response->finish();
    }
  }

}

实体

实体可以帮助您在迁移时轻松操作数据库结构并创建用于存储库的模型。实体类的每个属性都必须包含一些注释

  • @Id - 数据库中行的唯一ID
  • @GeneratedValue : strategy=AUTO_INCREMENT - 自动生成字段值的策略
  • @Field : name=<some_name>, type=<some_type>, length=<some_length> - 数据库中字段的名字、类型和长度
  • @NotNull - 将字段设置为数据库中的非空字段
  • @Nullable - 将字段设置为数据库中的可空字段

类注释必须包含@Table : name=<some_name>的表。

namespace App\Entities;

use \Amper\Entity;
/**
 * @Table : name=example
 */
class ExampleEntity extends Entity {
  /**
   * @Id
   * @GeneratedValue : strategy=AUTO_INCREMENT
   * @Field : name=id, type=int, length=11
   * @NotNull
   * @var integer
   */
  private $id;
  /**
   * @NotNull
   * @Field : name=keyname, type=varchar, length=255
   * @var string
   */
  private $keyname;
  /**
   * @Nullable
   * @Field : name=value, type=varchar, length=255
   * @var string
   */
  private $value;

  /**
   * @NotNull
   * @Field: name=date_add, type=int, length=11
   * @var integer
   */
  private $dateAdd;
  
  // getters and setters
}

存储库

存储库扮演ORM的角色,帮助您管理实体与数据库的连接。

默认情况下,CrudRepository可以帮助您从方法名构造SQL查询。例如,findById($id)将转换为SELECT * FROM table WHERE id = $id。更复杂的例子:findAllByStatusAndTypeOrderByIdLimitDesc($status, $type, $limitStart, $limitEnd) 等于 SELECT * FROM table WHERE status = $status AND type = $type LIMIT $limitStart, $limitEnd ORDER BY id DESC。

CrudRepository具有以下内置方法

  • save (如果传递的实体有ID,将应用UPDATE查询,否则将应用INSERT查询)
  • remove
  • query
  • findAll
  • findAllDesc
namespace App\Repositories;

use Amper\CrudRepository;
use \App\Entities\ExampleEntity;

class ConfigRepo extends CrudRepository {

  public function __construct()
  {
    parent::__construct(ExampleEntity::class);
  }
  
}

配置

默认情况下,Amper将在您的根目录中搜索config文件夹。bootstrapper.php(启动您的应用)

require_once(GLOBAL_DIR.'/vendor/autoload.php');

$Core = new Amper\Core();
$Core->run();

cache.php(脚本、路由和实体缓存的规则)

return [
  'reset_cache' => true, // In dev mode should be true to reset opcache
  'script_cache' => false, // Allow to use opcache for engine scripts
  'middleware_cache' => false, // Allow to use opcache for middleware
  'router_cache' => false, // Allows to cache all routes in a file
  'router_cache_method' => 'file',
  'entities_cache' => false, // Allow to cache entities in a file
  'entities_cache_method' => 'file'
];

database.php(数据库连接和实体的规则)

return [
  'connection' => [
    'prefix' => 'pre_', // prefix for table
    'user' => 'root', // db user
    'password' => '', // db password
    'driver' => 'mysql', // db access driver
    'host' => 'localhost', // db host
    'name' => 'amper_example' // db name
  ],
  'redis' => [ // array directly passing to Predis\Client
    'scheme' => 'tcp', // redis protocol
    'host'   => '127.0.0.1', // redis host
    'port'   => 6379, // redis address
  ],
  'entities' => [ // All registered entities
    'ExampleEntity'
  ]

];

queue.php(队列管理的规则)

return [
  'max_priority' => 5, // Max allowed priority of task
  'max_dispatch_time' => 300, // Time to retry task in fail case
  'dispatched_amount' => 10, // Single-tick dispatched tasks amount
  'dispatchers' => [ // List of all dispatchers
    'SleepDispatcher'
  ]

];

迁移

要创建迁移,您应该在您的实体中具有适当的注释结构,如上所述。在您的项目根目录中放置migrate.php文件

define('GLOBAL_DIR', __DIR__);
require_once(GLOBAL_DIR.'/config/bootstrapper.php');

$Migrate = new Amper\Migrate;
$Migrate->refresh(); // Refresh your database structure

// some db inserts, updates and so on

队列

要从项目的任何地方创建队列任务,请从任何地方调用push($dispatcher, $priority, $payload)方法

Amper\Queue::push('ExampleDispatcher', 0, ['email' => 'example@example.com', 'title' => 'title', 'body' => 'body']);

之后,您应该在App\Dispatchers目录中创建一个分发器。例如,ExampleDispatcher.php

namespace App\Dispatchers;

class ExampleDispatcher {
  
  public function handle(array $payload)
  {
    mail($payload['email'],$payload['title'],$payload['body']);
    return true; // To ensure queue manager that your task is done, return true. In other cases task will return to execution again.
  }
}

要分发所有任务,在您的项目根目录中创建queue.php文件

define('GLOBAL_DIR', __DIR__);
require_once(GLOBAL_DIR.'/config/bootstrapper.php');
while (true) {
  Amper\Queue::dispatchAll(); // Dispatch all tasks by priority
  Amper\Queue::dispatch($dispatcher, $priority); // Use this if you want to separate dispatching in multiple processes
}

为了保持您的循环24/7并控制内存泄漏,请使用pm2。例如:"pm2 start queue.php"。

模块

您可以使用两行代码将已编写的模块添加到项目中。首先配置 config 目录下的 modules.php 文件。

return [
  'modules' => [
    'App',
    'ExampleModule'
  ]
];

第二步是将模块的命名空间添加到 composer 自动加载器。

{
    "require": {
        "naglfar/amper": "dev-master",
        "predis/predis": "^1.1"
    },
    "autoload": {
        "psr-4": {
            "App\\": "app/",
            "ExampleModule\\": "modules/example/"
        }
    }
}

每个模块都必须有一个 EntityLoader 类,该类从 _register() 方法返回实体列表。

namespace ExampleModule;


class EntityLoader
{
  public function _register()
  {
    return [
      'NewsEntity',
      'DatasEntity',
      'TestEntity'
    ];
  }
}

模块表现得像常规的控制器、中间件、实体和仓库。因此,在将模块连接到项目后,它将自动使用其实体进行迁移和路由。另外,模块没有自己的数据库连接,所以将使用通用前缀和数据库。