Orlex attempts to give a mild amount of structure to Silex without extending, overwriting, or using any dirty hacks., (*1)
Setting up Orlex is as simple as registering a service provider and pointing it to a directory of controllers:, (*2)
<?php
$app = new \Silex\Application();
$app->register(new \Orlex\ServiceProvider(),[
'orlex.controller.dirs' => [
__DIR__ . '/app/Controllers',
],
]);
$app->run();
And then actually creating a controller:, (*3)
<?php
namespace app\Controllers;
use Orlex\Annotation\Route;
use Orlex\Annotation\Before;
use Orlex\Annotation\After;
/**
* @Route(path="/")
*/
class IndexController {
/**
* @Route(path="/", name="root")
* @Before("beforeIndex")
* @After("afterIndex")
*/
public function indexAction() { /* Do Stuff */ }
public function beforeIndex() { /* Do Stuff Before */ }
public function afterIndex() { /* Do Stuff After */ }
/**
* @Route(path="/page/{id}", name="root_page", methods={"GET", "POST"})
*/
public function pageAction($id) { /* Do Stuff With $id */ }
}
Installation
Orlex is provided as a composer package and requires PHP 5.4 and up. To use Orlex, simply add:, (*4)
{
"require": {
"dcousineau/orlex": "dev-master"
}
}
Controller Traits
Since Orlex seeks to be an "Organized Silex", it provides several convenience traits for your controller classes. These traits include a Twig trait, a Form trait, a Session trait., (*5)
To use them, your controller MUST use the \Orlex\ContainerAwareTrait
., (*6)
NOTE: Any controller classes that use the aforementioned ContainerAwareTrait will have their container automatically set by the route compiler., (*7)
For example:, (*8)
<?php
namespace app\Controllers;
use Orlex\Annotation\Route;
use Orlex\ContainerAwareTrait;
use Orlex\Controller\TwigTrait;
/**
* @Route(path="/")
*/
class IndexController {
use ContainerAwareTrait;
use TwigTrait;
/**
* @Route(path="/", name="root")
*/
public function indexAction() {
return $this->render('index.html.twig', []);
}
}
Obviously each respective trait will require their companion service provider to be already registered with the Silex application., (*9)
Custom Annotations
Orlex will support custom annotations. If you give your Orlex manager a directory and a namespace it will look for annotations contained there within:, (*10)
<?php
//...
$app->register(new \Orlex\ServiceProvider(),[
'orlex.controller.dirs' => [
__DIR__ . '/app/Controllers',
],
'orlex.annotation.dirs' => [
__DIR__ => 'app\Annotation',
]
]);
//...
NOTE: The path key for annotation autoloading should be the root directory containing the entire namespace. If your annotation files are of the namespace app\Annotation
and your annotation files are in /path/to/src/app/Annotation
, the proper annotation configuration would be '/path/to/src' => 'app\Annotation'
, (*11)
If the annotation implements the Orlex\Annotation\RouteModifier
interface, Orlex will allow it to alter the internal Silex controller created for that specific route/action:, (*12)
<?php
namespace app\Annotation;
use Orlex\Annotation\RouteModifier;
use Silex\Controller;
use Silex\Application;
/**
* @Annotation
* @Target({"METHOD"})
*/
class Test implements RouteModifier {
public function weight() { return 1; }
public function modify($serviceid, Controller $controller, Application $app, \ReflectionClass $class, \ReflectionMethod $method) {
$controller->before(function() {
var_dump('From @Test annotation');
});
}
}
For more information on how to define annotations, please see the Doctrine Annotations documentation., (*13)
Expect this interface to possibly change in the future, particularly where the modify(…)
signature is concerned., (*14)
Annotation Caching
Orlex is setup for easy annotation caching via the Doctrine\Common\Annotations\CachedReader
reader. Simply include a cache directory:, (*15)
<?php
$app->register(new \Orlex\ServiceProvider(),[
'orlex.cache.dir' => __DIR__ . '/cache',
'orlex.controller.dirs' => [
__DIR__ . '/app/Controllers',
],
]);
And Orlex will setup a Doctrine\Common\Cache\FilesystemCache
pointed at that directory and use said cache with the CachedReader
. Alternatively you can override the orlex.cache
service in your application container to return a Doctrine\Common\Cache\Cache
object and it will be used instead., (*16)
Internal Behavior
Orlex works by scanning controller directories and inspecting annotations on all classes contained therewithin. Each controller class has a Service Controller created for it (as seen in the above modify(…)
example's parameter $serviceid
)., (*17)
Orlex automatically registers the ServiceControllerServiceProvider
with the specified Silex application., (*18)
Then, each method with a @Route
annotation is created by performing an $app->match($path, "$serviceid:$methodName")
. The result of $app->match(…)
is a Silex Controller, which is then passed in a chain through each annotation that implements the Orlex\Annotation\RouteModifier
interface, allowing it to chain anything that is required to the Silex controller., (*19)
Want To Help?
Please do! Just remember this is early alpha under going "api stress testing" (meaning I'm using this internally on a project and new features are being implemented on demand and going through trial-by-fire)., (*20)
To-Do
- ~~Clean up route compiler, become more DI friendly~~
- ~~Post to packagist.org~~
- ~~Functional Testing~~
- ~~Annotation Caching~~
- Route Caching
- CLI Scaffolding (similar to Symfony's console command)