gyselroth / micro
Micro PHP library
Requires
- php: >=7.1
- psr/container: *
- psr/log: 1.*
Requires (Dev)
- phpunit/phpunit: 5.7.*
This package is not auto-updated.
Last update: 2018-02-01 12:04:01 UTC
README
Use the micro components instead:
- micro-auth
- micro-log
- micro-config
- micro-container
- micro-http
Micro (Yet another PHP library)
...but no shit
Description
Micro provides minimalistic core features to write a new Application. Instead providing a rich featured fatty library it only provides a couple of namespaces. It comes with a logger (and multiple adapters), configuration parser, HTTP routing/response, Authentication (and multiple adapters) and some wrapper around databases and ldap.
- \Micro\Auth
- \Micro\Config
- \Micro\Container
- \Micro\Http
- \Micro\Log
Requirements
The library is only >= PHP7.1 compatible.
Download
The package is available at packagist: https://packagist.org/packages/gyselroth/micro
To install the package via composer execute:
composer require gyselroth/micro
Configuration (\Micro\Config)
Read
Simply read an xml configuration and initialize your configuration:
$config = new \Micro\Config(new \Micro\Config\Xml($path)); var_dump($config->myconfigentry); string(1) "1"
And your actual XML configuration would look like:
<config version="1.0"> <production> <myconfigentry>1</myconfigentry> </production> </config>
Every configuration got configuration environment, if you only have one, just stick with as your first node within . See environments for further information.
Merge
Merge multiple configuration files:
$config1 = new \Micro\Config\Xml($path); $config2 = new \Micro\Config\Xml($path); $config1->merge($config2); $config = new \Micro\Config($config1);
Environments
You can request a custom configuration environment:
$config = new \Micro\Config(new \Micro\Config\Xml($path, 'development')); var_dump($config->myconfigentry); string(1) "2"
While your XML configuration would look like:
<config version="1.0"> <production> <myconfigentry>1</myconfigentry> </production> <development> <myconfigentry>2</myconfigentry> </development> </config>
Inheritance
The configuration parser supports inheritance. A simple example would be to just inherit one environment from another:
<config version="1.0"> <production> <a>a</a> </production> <development inherits="production"> </development> </config>
$config = new \Micro\Config(new \Micro\Config\Xml($path, 'development')); var_dump($config->a); string(1) "a"
You can also inherit single elements (recursively) within one environment and overwrite elements which were inherit in the first place:
<config version="1.0"> <production> <a>a</a> <b inherits="a"/> <c> <child>c</child> </c> <d inherits="c"> <child2>d</child2> </d> </development> </config>
$config = new \Micro\Config(new \Micro\Config\Xml($path)); var_dump($config->a); string(1) "a" var_dump($config->b); string(1) "a" var_dump($config->c->child); string(1) "c" var_dump($config->d->child); var_dump($config->d->child2); string(1) "c" string(1) "d"
It possible as well to access any elements (node path is separated with a "."):
<config version="1.0"> <production> <a> <child> <subchild>a</subchild> </child> </a> <b inherits="c"> <child inherits="a.child"> <child2 inherits="a.child.subchild"> </b> </development> </config>
$config = new \Micro\Config(new \Micro\Config\Xml($path)); var_dump($config->a->child->subchild); string(1) "a" var_dump($config->b->child->subchild); var_dump($config->b->child2); string(1) "a" string(1) "a"
XML Attributes
There is no more a difference between XML attributes and XML nodes. \Micro\Config\Xml parses both equally. So you can decide or switch on the fly whether a name/value should be an attribute or a node.
<config version="1.0"> <production> <a enabled="1"/> </development> </config>
Meaning the above configuration gets parsed as the same Config object as the following:
<config version="1.0"> <production> <a> <enabled>1</enabled> </a> </development> </config>
Logger (\Micro\Log)
Description
\Micro\Log is a PSR-3 compatible logger with multiple log adapters.
Initialize
$logger = new Logger(Iterable $options); $logger->info(string $message, array $context);
Configuration
$logger = new Logger([ 'adapter_name' => [ 'class' => '\Micro\Log\Adapter\File', 'config' => [ 'file' => '/path/to/file', 'date_format' => 'Y-d-m H:i:s', //http://php.net/manual/en/function.date.php 'format' => '{date} {level} {message} {context.category}', 'level' => 7 //PSR-3 log levels 1-7 ], ], 'adapter2_name' => [] ]);
Of course you can initialize the logger with a configuration object as well (any any other iterable objects):
<log> <adapter_name enabled="1" class="\Micro\Log\Adapter\File"> <config> <file>/path/to/file</file> <date_format>Y-d-m H:i:s</date_format> <format>{date} {level} {message} {context.category}</format> <level>7</level> </config </adapter_name> </log>
$config = new \Micro\Config(new \Micro\Config\Xml($path)); $logger = new Logger($config);
Format
The message formate is configured in each adapter separately. Available variables are:
- {message} - The message iteself
- {date} - The current timestamp formatted with the configured date_format option
- {level} - The log level, the configured number will be replaced with a string, for exampe 7 => debug
- {context.} - You can acces each context option and include them in the message format. For example you have a context ['category' => 'router'] then you can configure {context.category} to include this context value within your message.
Log adapters
- \Micro\Log\Adapter\File
- \Micro\Log\Adapter\Blackhole
- \Micro\Log\Adapter\Stdout
- \Micro\Log\Adapter\Syslog
You can always create your own log adapter using \Micro\Log\Adapter\AdapterInterface.
HTTP (\Micro\Http)
Initialize router
The http router requires an array with http headers, usually this is $_SERVER and a PSR-3 compatible logger.
$router = new \Micro\Http\Router(array $server, \Psr\Log\LoggerInterface $logger)
Adding routes
$router = (new \Micro\Http\Router($_SERVER, $logger)) ->clearRoutingTable() ->addRoute(new \Micro\Http\Router\Route('/api/v1/user', 'MyApp\Rest\v1\User')) ->addRoute(new \Micro\Http\Router\Route('/api/v1/user/{uid:#([0-9a-z]{24})#}', 'MyApp\Rest\v1\User')) ->addRoute(new \Micro\Http\Router\Route('/api/v1$', 'MyApp\Rest\v1\Rest')) ->addRoute(new \Micro\Http\Router\Route('/api/v1', 'MyApp\Rest\v1\Rest')) ->addRoute(new \Micro\Http\Router\Route('/api$', 'MyApp\Rest\v1\Rest')); ->run(array $controller_params);
The router tries to map a request to the first matching route in his routing table. The request gets mappend to a class and method. Optional parameters/query string gets automatically submitted to the final controller class.
Given the routing table above and the following final controller class:
namespace MyApp\Rest\v1; class User { /** * GET http://localhost/api/v1/user/540f1fc9a641e6eb708b4618/attributes * GET http://localhost/api/v1/user/attributes?uid=540f1fc9a641e6eb708b4618 */ public function getAttributes(string $uid=null): \Micro\Http\Response { } /** * GET http://localhost/api/v1/user/540f1fc9a641e6eb708b4618 * GET http://localhost/api/v1/user?uid=540f1fc9a641e6eb708b4618 */ public function get(string $uid=null): \Micro\Http\Response { } /** * POST http://localhost/api/v1/user/540f1fc9a641e6eb708b4618/password / POST body password=1234 * POST http://localhost/api/v1/user/password?uid=540f1fc9a641e6eb708b4618 / POST body password=1234 * POST http://localhost/api/v1/user/password / POST body password=1234, uid=540f1fc9a641e6eb708b4618 */ public function postPassword(string $uid, string $password): \Micro\Http\Response { } /** * DELETE http://localhost/api/v1/user/540f1fc9a641e6eb708b4618/mail * DELETE http://localhost/api/v1/user/mail?uid=540f1fc9a641e6eb708b4618 */ public function deleteMail(string $uid=null): \Micro\Http\Response { } /** * DELETE http://localhost/api/v1/540f1fc9a641e6eb708b4618/mail * DELETE http://localhost/api/v1/user?uid=540f1fc9a641e6eb708b4618 */ public function delete(string $uid=null): \Micro\Http\Response { } /** * HEAD http://localhost/api/v1/user/540f1fc9a641e6eb708b4618 * HEAD http://localhost/api/v1/user?uid=540f1fc9a641e6eb708b4618 */ public function headExists(string $uid=null): \Micro\Http\Response { } }
Response
Each endpoint needs to return a Response object to the router.
/** * HEAD http://localhost/api/v1/user/540f1fc9a641e6eb708b4618 * HEAD http://localhost/api/v1/user?uid=540f1fc9a641e6eb708b4618 */ public function headExists(string $uid=null): \Micro\Http\Response { if(true) { return (new \Micro\Http\Response())->setCode(200)->setBody('user does exists'); } else { return (new \Micro\Http\Response())->setCode(404); } }