A lightweight PHP API Framework Great fpr CRUD applications

栏目: IT技术 · 发布时间: 4年前

内容简介:A lightweight PHP API FrameworkGreat for CRUD applications

Spry

A lightweight PHP API Framework

Great for CRUD applications

@PSR2 and @Symfony Compliant

Documentation

Installation

The best way to install Spry and use it is through the CLI. https://github.com/ggedde/spry-cli

composer global require ggedde/spry-cli

Please reference the Installation Process on the CLI Page.

Then from the command line:

spry new [project_name]
cd [project_name]

An enpoint is automatically created for you

public/index.php

include dirname(__DIR__).'/vendor/autoload.php';
include dirname(__DIR__).'/spry/init.php';

Manual Installation

composer require ggedde/spry

You will need to add the composer autoloader if it has not already been added. Then use the run method and include a path to your config file or include a config object. See

Example:

include_once '/vendor/autoload.php';
Spry\Spry::run('../config.php');

QuickStart

Create a project through the CLI

spry new [project_name]
cd [project_name]

Folder Structure

- public/
    index.php
- spry/
    - components/
    - logs/
        - api.log
        - php.log
    - config.php
    - init.php

To Start the Spry test server run

spry up

Then open a separate termal and run some tests

spry test

Create a Single FIle Component

spry component MyComponent

Now View and Edit spry/components/MyComponent.php

Update Database Schema from New Component to Database

spry migrate

Run Tests again with new Component

spry test

Thats It!

Happy Coding

Well, I guess you might need more info. Most of all your coding will be in the components files you create and the rest will most likely be in the configuration file. See more details below :)

Configuration

Spry requires a config file or a config object.

When using a config file Spry will pass a pre-initialized $config object to the file. You will just need to set the variables within the object

Example Config File:

<?php
$config->salt = '';
$config->endpoint = 'http://localhost:8000';
$config->componentsDir = __DIR__.'/components';
...
Setting Type Default Description
componentsDir String __DIR__.'/components' Directory where Components are stored. Component Filenames must match the Class name of the Component.
db Array [] Database Object
See Database documentation
dbProvider String 'Spry\\SpryProvider\\SpryDB' Database Provider Class
See Database documentation
endpoint String ' http://localhost:8000 ' Spry Server Endpoint url. Used for internal requests only.
logger Array [] Logger Object
See Logger documentation
loggerProvider Array 'Spry\\SpryProvider\\SpryLogger' Logger Provider Class
See Logger documentation
projectPath String __DIR__ Path to Spry Project. Default is to use the same directory the config.php file is in.
responseCodes Array [] Array of Response Codes
See Response Codes documentation
responseHeaders Array [] Default Response Codes
routes Array [] Array of Routes
See Routes documentation
salt String '' Salt for Security. Change this to be Unique for each one of your API's. You should use a long and Strong key. DO NOT CHANGE IT ONCE YOU HAVE CREATED DATA. Otherwise things like logins may no longer work.
tests Array [] Array of Tests
See Tests documentation

Accessing Config Settings

You can access any setting by calling the config() object from Spry

Example:

echo Spry::config()->salt;
echo Spry::config()->db['database_name']

Extending Config Settings

You can add your own settings and then access them later in your component, provider or plugin

config.php

$config->mySetting = '123';

MyComponent.php

echo Spry::config()->mySetting;

Components

Spry is mainly used through components added in the componentsDir set in the.

Components are classes within the SpryComponent Namespace.

Components can set their own Routes, Response Codes, DB Schema and Tests by using built in methods. Or you can configure everything through the config.php

These built in Methods are Optional:

Method Description
setup Hook on initial Spry setup
getCodes Returns Array of Codes and adds them to the Config
getRoutes Returns Array of Routes and adds them to the Config
getSchema Returns Array of Table Schema and adds them to the Config
getTests Returns Array of Tests and adds them to the Config

Any Methods that resolve a route is called a Controller and gets passed any Parameters from the route.

Basic Example:

<?php

namespace Spry\SpryComponent;

use Spry\Spry;

class MyComponent
{
    private static $id = 2; // Component ID

    public static function setup() {
        Spry::addFilter('configure', 'MyComponent::stuff');
    }

    public static function stuff($config) {
        // Do Stuff
        return $config;
    }

    public static function getRoutes() {
        return [
            '/items/{id}' => [
                'label' => 'Get Item',
                'controller' => 'MyComponent::get',
                'access' => 'public',
                'methods' => 'GET',
                'params' => [
                    'id' => [
                        'required' => true,
                        'type' => 'int',
                    ],
                ],
            ],
        ];
    }
    public static function getCodes() {
        return [
            0 => [
                'success' => ['en' => 'Successfully Retrieved Item'],
                'warning' => ['en' => 'No Item with that ID Found'],
                'error' => ['en' => 'Error: Retrieving Item'],
            ],
            1 => [
                'info' => ['en' => 'Empty Results'],
                'success' => ['en' => 'Successfully Retrieved All Items'],
                'error' => ['en' => 'Error: Retrieving All Items'],
            ],
        ];
    }
    public static function getSchema() {
        return [
            'items' => [
                'columns' => [
                    'name' => [
                        'type' => 'string',
                    ],
                ],
            ],
        ];
    }
    public static function getTests() {
        return [
            'items_get' => [
                'label' => 'Get Example',
                'route' => '/items/123',
                'method' => 'GET',
                'params' => [],
                'expect' => [
                    'status' => 'success',
                ],
            ],
        ];
    }

    public static function get($params = [])
    {
        $response = Spry::db()->get('items', '*', $params)
        return Spry::response(self::$id, 01, $response);
    }
}

Routes

When using single file components you can set the routes in the Components by returning the routes in the getRoutes() method.

Example:

public static function getRoutes() {
    return [
        '/items/{id}' => [
            'label' => 'Get Item',
            'controller' => 'MyComponent::get',
            'access' => 'public',
            'methods' => 'GET',
            'params' => [
                'id' => [
                    'required' => true,
                    'type' => 'int',
                ],
            ],
        ],
    ];
}

Or within the Config Settings

$config->routes[
    '/items/{id}' => [
        'label' => 'Get Item',
        'controller' => 'MyComponent::get',
        'access' => 'public',
        'methods' => 'GET',
        'params' => [
            'id' => [
                'required' => true,
                'type' => 'int',
            ],
        ],
    ],
    ...
];

Route Options

Setting Type Default Description
label String Path Sanitized Name used to Label Route
controller String '' Path to Component Method. Ex. MyComponent::method or NameSpace\\Framework\\Class::someMethod
access String public Spry has a getRoutes method which will return all public routes. You can remove the route from that method by setting the access to private
methods String|Array POST Method allowed for route. POST|GET|DELETE|PUT
params Array [] Allowed Parameters for the Route. Any Parameters passed that do not match will get ignored. You can specify Validation for each Parameter.
params_trim Boolean false Trim all Params for surrounding whitespace. This can be overwritten per param.

Param Options

Setting Type Default Description
type String string Types: integer | number | float | array | cardNumber | date | email | url | ip | domain | string | boolean | password
between Array[min,max] [] Validates Param is between 2 values
betweenLength Array[min,max] [] Validates Param length is between 2 values
callback Callback Custom Callback function to return true for valid. Can be array for array(CLASS, METHOD) or closure.
endsWith String '' Validates Param ends with a substr.
filter Callback Closure to filter value. Closure accepts one argument of the value and must return filtered value.
has String '' Checks if Param is array and contains value.
hasLetters Integer 1 Validates Param contains x number of letters [a-zA-Z]
hasLowercase Integer 1 Validates Param contains x number of lower case letters [a-z]
hasNumbers Integer 1 Validates Param contains x number of numbers [0-9]
hasSymbols Integer 1 Validates Param contains x number of Symbols
hasUppercase Integer 1 Validates Param contains x number of upper case letters [A-Z]
in Array [] Validates Param is within Array
length Interger Length of Param must match value. Accepts Length of Array or String
matches String '' Validates Param matches Value. Strict Type comparison is enabled.
max Integer Maximum count of Array or length of String
maxDate Integer | String 0 If Integer then maximum days from today or String of Date formatted
maxLength Integer Maximum length of String for Parameter. Strings only.
meta Boolean false If true then the parameter will not be passed back to the controller as a Param, but as a Meta Value instead and returned back to the Controller in the second argument. Useful for route settings like pagination page, etc
min Integer Minimum count of Array or length of String
minDate Integer | String 0 If Integer then minimum days from today or String of Date formatted
minLength Integer Maximum length of String for Parameter. Strings only.
notEndsWith String '' Validates Param does not end with a substr.
notMatches String '' Validates Param does not match Value. Strict Type comparison is enabled.
notStartsWith String '' Validates Param does not start with a substr.
numbersOnly Boolean true Validates Param only contains numbers.
required Boolean | Array true Validates Param has a Value. if Array then Only requires if params within required array have value (conditional checking).
startsWith String '' Validates Param starts with a substr.
trim Boolean true Trims Param for surrounding whitespace
validateOnly Boolean true Validates the param, but does not send the value back to the controller. Ex. good for 'confirm_password' which doesn't need to be returned to the controller, but present for 'password' to match it.
unique Boolean true If Param is Array then duplicate values within array will be removed.

Database

Spry's default Database Provider is SpryDB based on Medoo

See SpryDB's full documentation

This allows you to swap out the Provider later on without having to change your project code.

Spry::db()->get('items', '*', ['id' => 123]);
Spry::db()->select('items', '*', ['date[>]' => '2020-01-01']);
Spry::db()->insert('items', ['name' => 'test', 'date' => '2020-01-01']);
Spry::db()->update('items', ['name' => 'newtest'], ['id' => 123]);
Spry::db()->delete('items', ['id' => 123]);

Spry Config Settings

$config->dbProvider = 'Spry\\SpryProvider\\SpryDB';
$config->db = [... ];

Logger

Spry's default Log Provider is SpryLogger

See SpryLogger's full documentation

This allows you to swap out the Provider later on without having to change your project code.

Spry::log()->message("My Message");
Spry::log()->warning("Warning");
Spry::log()->error("Error");

Spry Configuration

$config->loggerProvider = 'Spry\\SpryProvider\\SpryLogger';
$config->logger = [... ];

Tests

Spry comes with its own pre-built testing solution. You can still use other like PHPUnit, but Spry's Tests utilize's Spry's config for rapid testing. When using single file components you can set the routes in the Components by returning the routes in the getTests() method.

Example:

public static function getTests() {
    return [
        'items_insert' => [
            'label' => 'Insert Item',
            'route' => '/items/insert',
            'method' => 'POST',
            'params' => [
                'name' => 'TestData',
            ],
            'expect' => [
                'status' => 'success',
            ],
        ],
        'items_get' => [
            'label' => 'Get Item',
            'route' => '/items/{items_insert.body.id}',
            'method' => 'GET',
            'params' => [],
            'expect' => [
                'status' => 'success',
            ],
        ],
        'items_delete' => [
            'label' => 'Delete Item',
            'route' => '/items/delete/',
            'method' => 'POST',
            'params' => [
                'id' => '{items_insert.body.id}'
            ],
            'expect' => [
                'status' => 'success',
            ],
        ],
    ];
}

Or within the Config Settings

$config->tests[
    'items_get' => [
        'label' => 'Get Example',
        'route' => '/items/123',
        'params' => [],
        'expect' => [
            'code' => '1-200',
        ],
    ],
    'items_get' => [
        'label' => 'Get Example',
        'route' => '/items/123',
        'params' => [],
        'expect' => [
            'body.id[>]' => 12,
        ],
    ],
    ...
];

Test Options

Setting Type Default Description
label String '' Name used to Label Test
route String '' Route that is enabled in Spry Routes
method String GET Route that is enabled in Spry Routes
params Array [] Params passed in Route
expect Array [] Key and Value of what is expected valid from the Response. Keys accept dot notation and [>], [>=], [<], [<=], [!=], [===], [!==] comparison checks. See above.

Running Tests with Spry CLI

All Tests

spry test

Specific Test

spry test items_get

More Options

spry test --verbose --repeat 10

Response

Spry has 2 built in functions for building the response ( response and stop ).

response

Spry::response($data = null, $responseCode = 0, $responseStatus = null, $meta = null, $additionalMessages = []);

You can use this to build the response data and return it from the Controller.

$responseCode: This is the Response code id from the Component. $responseStatus: This can be either null | info | success | warning | error
If null then the function will auto detect the status based on the value of $data

Example:

$data = ['id' => 123, 'name' => 'John'];
return Spry::response($data, 0);

stop

Spry::stop($responseCode = 0, $responseStatus = null, $data = null, $additionalMessages = [], $privateData = null);

This will immediately kill the application and return the response

Example:

if ($error) {
    Spry::stop(0);
}

* See Response Codes Below to see how this works

ResponseCodes

Single File Component Example:

public static function getCodes()
{
    return [
        0 => [ // Get Single
            'success' => ['en' => 'Successfully Retrieved Item'],
            'warning' => ['en' => 'No Item with that ID Found'],
            'error' => ['en' => 'Error: Retrieving Item'],
        ],
        1 => [ // Get Multiple
            'info' => ['en' => 'No Results Found'],
            'success' => ['en' => 'Successfully Retrieved Items'],
            'error' => ['en' => 'Error: Retrieving Items'],
        ],
        2 => [ // Insert
            'success' => ['en' => 'Successfully Created Item'],
            'error' => ['en' => 'Error: Creating Item'],
        ],
        3 => [ // Update
            'success' => ['en' => 'Successfully Updated Item'],
            'error' => ['en' => 'Error: Updating Item'],
        ],
        4 => [ // Delete
            'success' => ['en' => 'Successfully Deleted Item'],
            'error' => ['en' => 'Error: Deleting Item'],
        ],
    ];
}

Config File Example

Notice you will need to add a Group Group Number for the component codes. This is not needed in the Single File Component setup

$config->tests[
    1 => [
        0 => [ // Get Single
            'success' => ['en' => 'Successfully Retrieved Item'],
            'warning' => ['en' => 'No Item with that ID Found'],
            'error' => ['en' => 'Error: Retrieving Item'],
        ],
        1 => [ // Get Multiple
            'info' => ['en' => 'No Results Found'],
            'success' => ['en' => 'Successfully Retrieved Items'],
            'error' => ['en' => 'Error: Retrieving Items'],
        ],
        2 => [ // Insert
            'success' => ['en' => 'Successfully Created Item'],
            'error' => ['en' => 'Error: Creating Item'],
        ],
        3 => [ // Update
            'success' => ['en' => 'Successfully Updated Item'],
            'error' => ['en' => 'Error: Updating Item'],
        ],
        4 => [ // Delete
            'success' => ['en' => 'Successfully Deleted Item'],
            'error' => ['en' => 'Error: Deleting Item'],
        ],
    ],
    2 => [
        0 => [ // Get Single
            'success' => ['en' => 'Successfully Retrieved Other Item'],
            'warning' => ['en' => 'No Other Item with that ID Found'],
            'error' => ['en' => 'Error: Retrieving Other Item'],
        ],
        1 => [ // Get Multiple
            'info' => ['en' => 'No Results Found'],
            'success' => ['en' => 'Successfully Retrieved Other Items'],
            'error' => ['en' => 'Error: Retrieving Other Items'],
        ],
        2 => [ // Insert
            'success' => ['en' => 'Successfully Created Other Item'],
            'error' => ['en' => 'Error: Creating Other Item'],
        ],
        3 => [ // Update
            'success' => ['en' => 'Successfully Updated Other Item'],
            'error' => ['en' => 'Error: Updating Other Item'],
        ],
        4 => [ // Delete
            'success' => ['en' => 'Successfully Deleted Other Item'],
            'error' => ['en' => 'Error: Deleting Other Item'],
        ],
        5 => ['redirect' = ['en' => 'Depricated: This route is depricated']],
        6 => ['error' = ['en' => 'Error: Custom Error Message']],
        7 => ['error' = ['en' => 'Error: Another Custom Error Message']],
        8 => ['error' = ['en' => 'Error: And Another Custom Error Message']],
    ],
    ...
];

Component Group Number

The first number is to separate the Components codes by ID

Ex.

1-200   # Success For Component A 
2-200   # Success For Component B

Multi-Language Support

1 => [
    'success' => [
        'en' => 'Success!',
        'es' => '¡Éxito!'
    ]
]

Format - Info, Success, Redirect or Depricated, Client Error and Server Error

The first number in the code represents the code type.

[group_id]-[1]xx - the 1 represents 'Info' or 'Empty'

[group_id]-[2]xx - the 2 represents 'Success'

[group_id]-[3]xx - the 3 represents 'Redirect' or 'Depricated'

[group_id]-[4]xx - the 4 represents 'Client Error', or 'Unkown'

[group_id]-[5]xx - the 5 represents 'Server Error'

When using Spry::response() you can pass just the last 2 digits as the code and the data parameter.

Ex.

Spry::response($data, 1);

If $data is an array but empty then the response will automatically Prepend the code with a 1 and return 1-101 .

If $data has a value and is not empty then the response will automatically Prepend the code with a 2 and return 1-201 .

If $data is an array but not null then the response will automatically Prepend the code with a 4 and return 1-401 .

If $data is false or null then the response will automatically Prepend the code with a 5 and return 1-501 .

Response Status

In the response there will be a key of status
The possible values for this will only be success , error , or unknown

info , success , and redirect all represent a successfully response and will return success
warning and error represent a failed response and will return error

Lifecycle

Hooks & Filters Lifecycle in order of completion:

Name Type Details
initialized hook Has access to the initial config, but before any filters or components
configure filter Runs after all Components and Plugins have been loaded
configure hook Runs after the configure filter and after the OPTIONS pre-flight response
getPath filter Runs after route path has been recieved
setPath hook Runs after route path has been set
setRoutes hook Runs after routes has been set
params filter Runs after the Params have been fetched
setParams hook Runs after the Params have been set
getRoute hook Runs after the Route has been set
validateParams filter Runs after Params Validation.
response filter Runs after the response has been built.
output filter Runs right before the Output is returned.

Non Lifecycle Hooks & Filters

Name Type Details
stop hook This may run at anytime when their is an error or Spry needs to stop
database hook Called after the Database connection has been made or accessing the DatabaseProvider for the first time
dbJoin filter Called right before the query is ran. Allows to filter the JOIN statement and will include $meta on the query details
dbColumns filter Called right before the query is ran. Allows to filter the FROM statement and will include $meta on the query details
dbWhere filter Called right before the query is ran. Allows to filter the WHERE statement and will include $meta on the query details
dbData filter Called right before the query is ran. Allows to filter the data for INSERT, UPDATE, REPLACE statement and will include $meta on the query details
dbGet filter Called right before the get query is ran and includes entire statement object
dbSelect filter Called right before the select query is ran and includes entire statement object
dbInsert filter Called right before the insert query is ran and includes entire statement object
dbUpdate filter Called right before the update query is ran and includes entire statement object
dbReplace filter Called right before the replace query is ran and includes entire statement object
dbDelete filter Called right before the delete query is ran and includes entire statement object
dbHas filter Called right before the has query is ran and includes entire statement object
dbRand filter Called right before the rand query is ran and includes entire statement object
dbCount filter Called right before the count query is ran and includes entire statement object
dbAvg filter Called right before the avg query is ran and includes entire statement object
dbMax filter Called right before the max query is ran and includes entire statement object
dbMin filter Called right before the min query is ran and includes entire statement object
dbSum filter Called right before the sum query is ran and includes entire statement object

Hooks

Hooks allow you to run your own code at specific times and life cycles. This is how you can run middleware and other life cycle aware code.

Adding Hooks

Spry::addHook(string $hookName, string|callable $controller, [ mixed $extraData = null [, int $order = 0 ]] ) : void

Example:

Spry::addHook('configure', 'Spry\\SpryComponent\\MyComponent::myMethod', ['bar' => 345], 100);

Running Hooks

Spry::runHook(string $hookName, [ mixed $data ] ) : void

Example:

Spry::runHook('configure',['foo' => 123] [[ mixed $data = null ], mixed $meta = null ] );

Your Controller

class MyComponent

public static function myMethod($data = null, $meta = null, $extraData = null) {
    $data // [foo => 123]
    $meta // null
    $extraData // [bar => 345]
    // Do Stuff
}

Filters

Filters allow you to filter data at specific times and life cycles. A filter typically requires a return value.

Adding Filters

Spry::addFilter(string $filterName, string|callable $controller, [ mixed $extraData = null [, int $order = 0 ]] ) : void

Example:

Spry::addFilter('configure', 'Spry\\SpryComponent\\MyComponent::myMethod', ['bar' => 345], 100);

Running Filters

Spry::runFilter(string $filterName, [[ mixed $data = null ], mixed $meta = null ] ) : void

Example:

$config = Spry::runFilter('configure', $config, ['component' => 'someComponent', 'var' => 'abc']);

Your Controller

class MyComponent

public static function myMethod($config = null, $meta = null, $extraData = null) {
    $config // $config
    $meta // ['component' => 'someComponent', 'var' => 'abc']
    $extraData // [bar => 345]
    // Do Stuff
    return $config;
}

Todos

  • Add Types and Interfaces to everything
  • Review and optimize Performance
  • Review PSR-7 for response
  • Drink a Beer!

以上所述就是小编给大家介绍的《A lightweight PHP API Framework Great fpr CRUD applications》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

世界是平的

世界是平的

[美] 托马斯·弗里德曼 / 何帆、肖莹莹、郝正非 / 湖南科学技术出版社 / 2006-11 / 56.00元

当学者们讨论世界这20年发展的历史,并把目光聚集在2000年到2004年3月这一段时间时,他们将说些什么?9·11恐怖袭击还是伊拉克战争?或者,他们将讨论:科技的汇集与传播使得印度、中国和许多发展中国家成为世界商品和服务产品供给链上的一员,从而为世界大的发展中国家中的中产阶级带来了大量的财富,使这两个国家在全球化浪潮中占据更有利的位置?随着世界变得平坦,我们必须以更快的速度前进,才能在竞争中赢得胜......一起来看看 《世界是平的》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

MD5 加密
MD5 加密

MD5 加密工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试