naglfar / amper
Simple REST API engine for PHP
Installs: 133
Dependents: 0
Suggesters: 0
Security: 0
Stars: 2
Watchers: 2
Forks: 0
Open Issues: 0
Type:engine
Requires
- php: >=7.2.0
This package is auto-updated.
Last update: 2025-06-10 22:17:54 UTC
README
Amper is a PHP micro-framework for extremely fast prototyping and building REST API.
Installation
To install via composer use:
composer require naglfar/amper:dev-master
You can initiate your project with default installer. Create install.php in your root directory and run it:
define('GLOBAL_DIR', __DIR__); require_once(GLOBAL_DIR.'/vendor/autoload.php'); $Installer = new Amper\Installer; $Installer->start();
If you don't want to use installer, use the manual below:
Create index.php file in your project's root directory:
define('GLOBAL_DIR', __DIR__); require_once(GLOBAL_DIR.'/config/bootstrapper.php');
In order to use queues install predis library and pm2:
composer require predis/predis
npm i -g pm2
composer.json example:
{ "require": { "naglfar/amper": "dev-master", "predis/predis": "^1.1" }, "autoload": { "psr-4": { "App\\": "app/" } } }
Configurate your project according to the structure below:
General structure
- App
- Controllers
- ExampleController.php
- Dispatchers
- ExampleDispatcher.php
- Entities
- ExampleEntity.php
- Middleware
- ExampleMiddleware.php
- Repositories
- ExampleRepo.php
- Routes.php
- Controllers
- config
- bootstrapper.php
- cache.php
- database.php
- queue.php
- modules.php
- modules
- example
- Controllers
- Entities
- Middleware
- Repositories
- EntityLoader.php
- Routes.php
- example
- index.php
- migrate.php
- queue.php
Routing
Automatically Amper will search for Routes class in the App namespace and call _register() method.
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' ]); } }
Controllers
Each method of the controller class gets two arguments by default: request and response.
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 } }
Middlewares
Middlewares are functions, that is going to be executed before request get to the controller
Example of CORS middleware, setting the proper response headers:
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(); } } }
Entities
Entities help you to easily manipulate with database structure at the migration time and making model for repositories. Each property of Entity class must hold some annotations:
- @Id - unique id of the row in database
- @GeneratedValue : strategy=AUTO_INCREMENT - Strategy of auto generating the field value
- @Field : name=<some_name>, type=<some_type>, length=<some_length> - Name, type and length of field in database
- @NotNull - Setting the field as not nullable in database
- @Nullable - Setting the field as nullable in database
Class annotation must contain @Table : name=<some_name> of the table.
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 }
Repositories
Repositories are acting role of ORM and helps you to manage connections of entities to the database.
By default CrudRepository helps you to construct SQL queries from method-name. For example, findById($id) will transform to SELECT * FROM table WHERE id = $id. More complex example: findAllByStatusAndTypeOrderByIdLimitDesc($status, $type, $limitStart, $limitEnd) equals to SELECT * FROM table WHERE status = $status AND type = $type LIMIT $limitStart, $limitEnd ORDER BY id DESC.
CrudRepository has following built-in methods:
- save (If the passing entity has ID, will apply UPDATE query, else will apply INSERT query)
- 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); } }
Configurating
By default Amper will search for config folder in your root directory. bootstrapper.php (starting your app):
require_once(GLOBAL_DIR.'/vendor/autoload.php'); $Core = new Amper\Core(); $Core->run();
cache.php (rules for script, routes and entities caching):
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 (rules for database connections and entities):
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 (rules for managing queues):
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' ] ];
Migrations
To create a migration you should have proper annotations structure in your Entity, that is described above. Place a migrate.php file in your projects root directory:
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
Queues
To create a task in a queue from any place of your project call the push($dispatcher, $priority, $payload) method:
Amper\Queue::push('ExampleDispatcher', 0, ['email' => 'example@example.com', 'title' => 'title', 'body' => 'body']);
After that you should create a dispatcher in your App\Dispatchers dir. 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. } }
To dispatch all tasks create a queue.php file in your project's root dir:
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 }
To hold your loop 24/7 and control memory leaks use pm2. Example: "pm2 start queue.php".
Modules
You can add already written modules to your project with 2 lines of code. Firstly configure modules.php of your config:
return [ 'modules' => [ 'App', 'ExampleModule' ] ];
Second step is adding namespaces of the module to composer autoloader:
{ "require": { "naglfar/amper": "dev-master", "predis/predis": "^1.1" }, "autoload": { "psr-4": { "App\\": "app/", "ExampleModule\\": "modules/example/" } } }
Each module must have EntityLoader class, returning list of Entities from _register():
namespace ExampleModule; class EntityLoader { public function _register() { return [ 'NewsEntity', 'DatasEntity', 'TestEntity' ]; } }
Modules behave as usual Controllers, Middlewares, Entities and Repositories. So after connecting module to the project it will automatically use it's Entities for migrations and Routes for routing. Also modules doesn't have it's own database connection, so general prefixes and database will be used.