Skip to content

Instantly share code, notes, and snippets.

@tarlepp
Created March 18, 2016 19:20
Show Gist options
  • Save tarlepp/6ab7d0ce68385de9d97e to your computer and use it in GitHub Desktop.
Save tarlepp/6ab7d0ce68385de9d97e to your computer and use it in GitHub Desktop.
<?php
/**
* /src/App/Providers/ControllerProvider.php
*
* @author TLe, Tarmo Leppänen <tarmo.leppanen@protacon.com>
*/
namespace App\Providers;
// Application components
use App\Application;
use App\Controllers;
// Silex components
use Silex\Application as App;
use Silex\ControllerCollection;
use Silex\ControllerProviderInterface;
// 3rd party components
use phpDocumentor\Reflection\DocBlockFactory;
/**
* Class ControllerProvider
*
* @category Provider
* @package App\Providers
* @author TLe, Tarmo Leppänen <tarmo.leppanen@protacon.com>
*/
class ControllerProvider implements ControllerProviderInterface
{
/**
* Current Silex application
*
* @var Application
*/
private $app;
/**
* Returns routes to connect to the given application.
*
* @param App $app An Application instance
*
* @return ControllerCollection A ControllerCollection instance
*/
public function connect(App $app)
{
// Store application
$this->app = $app;
// Set error handling globally
$this->app->error([$this, 'error']);
/**
* Get application current controllers
*
* @var ControllerCollection $controllers
*/
$controllers = $this->app['controllers_factory'];
// Mount controllers to specified routes.
$this->mount();
return $controllers;
}
/**
* Generic error handler for application. Note that this will _not_ catch PHP errors, those are handled via
* App\Core\ExceptionHandler class which extends base Symfony ExceptionHandler class.
*
* @param \Exception $exception
* @param integer $status
*
* @return \Symfony\Component\HttpFoundation\JsonResponse
*/
public function error(\Exception $exception, $status)
{
// Basic error data
$error = [
'message' => $exception->getMessage(),
'status' => $status,
'code' => $exception->getCode(),
];
// If we're running application in debug mode, attach some extra information about actual error
if ($this->app['debug']) {
$error += [
'debug' => [
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'trace' => $exception->getTrace(),
'traceString' => $exception->getTraceAsString(),
]
];
}
// And return JSON output
return $this->app->json($error, $status);
}
/**
* Attach application mount points to specified controllers.
*
* @return void
*/
private function mount()
{
foreach ($this->getMountPoints() as $mount) {
$this->app->mount($mount->mountPoint, new $mount->controller);
}
}
private function getMountPoints()
{
// Create doc block factory
$factory = DocBlockFactory::createInstance();
/**
* Lambda function to iterate all controller classes to return mount points to each of them.
*
* @param string $file
*
* @return null|\stdClass
*/
$iterator = function($file) use ($factory) {
$className = '\\App\\Controllers\\' . str_replace('.php', '', basename($file));
$reflectionClass = new \ReflectionClass($className);
if ($reflectionClass->isAbstract()) {
return null;
}
// Get 'mountPoint' tags from class comment block
$tags = $factory->create($reflectionClass->getDocComment())->getTagsByName('mountPoint');
// Nice, we have one 'mountPoint' tag in comments, so we'll use that
if (count($tags) === 1) {
$tag = $tags[0];
// Normalize mount point name
$mountPoint = trim(str_replace('@' . $tag->getName(), '', $tag->render()));
// Create output
$output = new \stdClass();
$output->mountPoint = $mountPoint;
$output->controller = $className;
return $output;
}
return null;
};
return array_filter(array_map($iterator, glob($this->app->getRootDir() . 'src/App/Controllers/*.php')));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment