This is the Silex 2.0 compatible version. It is in development and NOT STABLE. See 1.1 branch for stable version.
A Silex ServiceProvider that defines annotations that can be used in a Silex controller. Define your controllers in a class and use annotations to setup routes and define modifiers.
Install the silex-annotation-provider using composer.
{
"require": {
"ddesrosiers/silex-annotation-provider": "~2.0@dev"
}
}
$app->register(new DDesrosiers\SilexAnnotations\AnnotationServiceProvider(), array(
"annot.cache" => new ApcCache(),
"annot.controllerDir" => "$srcDir/Controller",
"annot.controllerNamespace" => "Company\\Controller\\"
));
Specify the directory in which to search for controllers. This directory will be searched recursively for classes with the @Controller
annotation. Found controller classes will be processed for route annotations. Either this or annot.controllers is required to locate controllers. If a cache object is given using the 'annot.cache' option and the 'debug' option is true, the list of controller classes will be cached to improve performance.
The base namespace of the controllerDir. This option works with the annot.controllerDir option. It is not required, but saves the service from having to do the work of figuring out the namespace of the controller classes.
An array of fully qualified controller names. If set, the provider will automatically register each controller as a ServiceController and set up routes and modifiers based on annotations found. Controllers can be grouped into controller collections by grouping them with an associative array using the array key as the mount point.
$app['annot.controllers'] = array(
'group1' => array(
"MyControllerNamespace\\Controller1",
"MyControllerNamespace\\Controller2"
),
'group2' => array(
"MyControllerNamespace\\Controller3",
"MyControllerNamespace\\Controller4"
)
);
An instance of a class that implements Doctrine\Common\Cache\Cache. This is the cache that will be used by the AnnotationReader to cache annotations so they don't have to be parsed every time. Make sure to include Doctrine Cache as it is not a required dependency of this project.
Create your controller. The following is an example demonstrating the use of annotations to register an endpoint.
namespace DDesrosiers\Controller;
use DDesrosiers\SilexAnnotations\Annotations as SLX;
use Symfony\Component\HttpFoundation\Response;
/**
* @SLX\Controller(prefix="/prefix")
* @SLX\RequireHttps
*/
class TestController
{
/**
* @SLX\Route(
* @SLX\Request(method="GET", uri="test/{var}"),
* @SLX\Assert(variable="var", regex="\d+"),
* @SLX\Convert(variable="var", callback="\DDesrosiers\Controller\TestController::converter")
* )
*/
public function testMethod($var)
{
return new Response("test Method: $var");
}
public static function converter($var)
{
return $var;
}
}
The annotations in our TestController are interpreted as follows:
$controllerCollection = $app['controller_factory'];
$controllerCollection->requireHttps();
$controller->get("test/{var}", "\\DDesrosiers\\Controller\\TestController:testMethod")
->assert('var', '\d+')
->convert('var', "\\DDesrosiers\\Controller\\TestController::converter");
$app->mount('/prefix', $controllerCollection);
If we want to use a ControllerProvider, we can use the annotations service's process() method directly.
namespace DDesrosiers\Controller;
use DDesrosiers\SilexAnnotations\Annotations as SLX;
use Silex\Application;
use Silex\ControllerProviderInterface;
use Symfony\Component\HttpFoundation\Response;
class TestProviderController implements ControllerProviderInterface
{
function connect(Application $app)
{
return $app['annot']->process(get_class($this), false, true);
}
/**
* @SLX\Route(
* @SLX\Request(method="GET", uri="test/{var}"),
* @SLX\Assert(variable="var", regex="\d+"),
* )
*/
public function testMethod()
{
return new Response("test Method");
}
}
The ControllerProviderInterface's connect() requirement was satisfied by calling the annotation service's process() method.
When registered, an instance of AnnotationService is available via $app['annot']; The AnnotationService's process() method parses annotations in a class to configure controllers. It is usually not necessary to use the service directly. AnnotationService->process() takes 3 arguments:
- controllerName: The fully qualified class name of the controller to process.
- isServiceController: This matters because Silex expects a different string representation of a controller method for ServiceControllers. Default: false.
- newCollection: If true, all routes found will be put into a new controller collection and that collection will be returned. Default: false.
Controllers are registered as service controllers by default. This option can be used to override this default.
Define your own callback to search for controllers.
This callback registers the service controller. Override it if you need to do anything special to register your controllers.
Controller
The @Controller annotation marks a class as a controller. The 'prefix' option defines the mount point for the controller collection.
@Route
The @Route annotation groups annotations into an isolated endpoint definition. This is required if you have multiple aliases for your controller method with different modifiers. All other annotations can be included as sub-annotations of @Route or stand on their own.
@Request
The @Request annotation associates a uri pattern to the controller method. If multiple @Request annotations are given, all modifiers will be applied to all @Requests unless they wrapped in a @Route annotation.
- method: A valid Silex method (get, post, put, delete, match)
- uri: The uri pattern.
@Assert
Silex\Route::assert()
- variable
- regex
@Convert
Silex\Route::convert()
- variable
- callback
@Host
Silex\Route::host()
- host
@RequireHttp
Silex\Route::requireHttp()
@RequestHttps
Silex\Route::requireHttps()
@Value
Silex\Route::value()
- variable
- default
@Before
Silex\Route::before()
- callback
@After
Silex\Route::after()
- callback
@Bind
Silex\Controller::bind()
- routeName
@Modifier
The Modifier annotation is a catch-all to execute any method of the Controller or Route. All methods should have an annotation, but this annotation is provided as a way to "future-proof" the annotation provider. In case something is added in the future, users can use it right away instead of waiting for a new annotation to be added.
Silex\Route::{method}()
Silex\Controller::{method}()
- method (name of the method to call on the Route object)
- args (array of arguments to send the the method)