diff --git a/src/Admin/AdminServiceProvider.php b/src/Admin/AdminServiceProvider.php index 3302b78f4..580792149 100644 --- a/src/Admin/AdminServiceProvider.php +++ b/src/Admin/AdminServiceProvider.php @@ -1,10 +1,32 @@ app->singleton('flarum.admin.assetManager', function () { + return new AssetManager($this->app->make('files'), public_path('assets'), 'admin'); + }); + + $this->app->singleton( + 'Flarum\Http\UrlGeneratorInterface', + function () { + return new UrlGenerator($this->app->make('flarum.admin.routes')); + } + ); + } + /** * Bootstrap the application events. * @@ -20,18 +42,26 @@ class AdminServiceProvider extends ServiceProvider $root.'/public/fonts' => public_path('assets/fonts') ]); - include __DIR__.'/routes.php'; + $this->routes(); } - /** - * Register the service provider. - * - * @return void - */ - public function register() + protected function routes() { - $this->app->singleton('flarum.admin.assetManager', function () { - return new AssetManager($this->app->make('files'), public_path('assets'), 'admin'); - }); + $this->app->instance('flarum.admin.routes', $routes = new RouteCollection); + + $routes->get( + '/', + 'flarum.admin.index', + $this->action('Flarum\Admin\Actions\IndexAction') + ); + } + + protected function action($class) + { + return function (ServerRequestInterface $httpRequest, $routeParams) use ($class) { + $action = $this->app->make($class); + + return $action->handle($httpRequest, $routeParams); + }; } } diff --git a/src/Admin/routes.php b/src/Admin/routes.php deleted file mode 100755 index 75f32da8c..000000000 --- a/src/Admin/routes.php +++ /dev/null @@ -1,16 +0,0 @@ -app->make($class); - - return $action->handle($httpRequest, $routeParams); - }; -}; - -/** @var Flarum\Http\Router $router */ -$router = $this->app->make('Flarum\Http\Router'); - -$router->get('/admin', 'flarum.admin.index', $action('Flarum\Admin\Actions\IndexAction')); diff --git a/src/Api/ApiServiceProvider.php b/src/Api/ApiServiceProvider.php index fc196a927..4a796ebc6 100644 --- a/src/Api/ApiServiceProvider.php +++ b/src/Api/ApiServiceProvider.php @@ -1,9 +1,29 @@ app->singleton('Flarum\Support\Actor'); + + $this->app->singleton( + 'Flarum\Http\UrlGeneratorInterface', + function () { + return new UrlGenerator($this->app->make('flarum.api.routes')); + } + ); + } + /** * Bootstrap the application events. * @@ -16,18 +36,250 @@ class ApiServiceProvider extends ServiceProvider 'Flarum\Api\ExceptionHandler' ); - $this->app->singleton('Flarum\Http\Router'); - - include __DIR__.'/routes.php'; + $this->routes(); } - /** - * Register the service provider. - * - * @return void - */ - public function register() + protected function routes() { - $this->app->singleton('Flarum\Support\Actor'); + $this->app->instance('flarum.api.routes', $routes = new RouteCollection); + + // Get forum information + $routes->get( + '/forum', + 'flarum.api.forum.show', + $this->action('Flarum\Api\Actions\Forum\ShowAction') + ); + + // Retrieve authentication token + $routes->post( + '/token', + 'flarum.api.token', + $this->action('Flarum\Api\Actions\TokenAction') + ); + + // Send forgot password email + $routes->post( + '/forgot', + 'flarum.api.forgot', + $this->action('Flarum\Api\Actions\ForgotAction') + ); + + /* + |-------------------------------------------------------------------------- + | Users + |-------------------------------------------------------------------------- + */ + + // List users + $routes->get( + '/users', + 'flarum.api.users.index', + $this->action('Flarum\Api\Actions\Users\IndexAction') + ); + + // Register a user + $routes->post( + '/users', + 'flarum.api.users.create', + $this->action('Flarum\Api\Actions\Users\CreateAction') + ); + + // Get a single user + $routes->get( + '/users/{id}', + 'flarum.api.users.show', + $this->action('Flarum\Api\Actions\Users\ShowAction') + ); + + // Edit a user + $routes->put( + '/users/{id}', + 'flarum.api.users.update', + $this->action('Flarum\Api\Actions\Users\UpdateAction') + ); + + // Delete a user + $routes->delete( + '/users/{id}', + 'flarum.api.users.delete', + $this->action('Flarum\Api\Actions\Users\DeleteAction') + ); + + // Upload avatar + $routes->post( + '/users/{id}/avatar', + 'flarum.api.users.avatar.upload', + $this->action('Flarum\Api\Actions\Users\UploadAvatarAction') + ); + + // Remove avatar + $routes->delete( + '/users/{id}/avatar', + 'flarum.api.users.avatar.delete', + $this->action('Flarum\Api\Actions\Users\DeleteAvatarAction') + ); + + /* + |-------------------------------------------------------------------------- + | Activity + |-------------------------------------------------------------------------- + */ + + // List activity + $routes->get( + '/activity', + 'flarum.api.activity.index', + $this->action('Flarum\Api\Actions\Activity\IndexAction') + ); + + // List notifications for the current user + $routes->get( + '/notifications', + 'flarum.api.notifications.index', + $this->action('Flarum\Api\Actions\Notifications\IndexAction') + ); + + // Mark a single notification as read + $routes->put( + '/notifications/{id}', + 'flarum.api.notifications.update', + $this->action('Flarum\Api\Actions\Notifications\UpdateAction') + ); + + /* + |-------------------------------------------------------------------------- + | Discussions + |-------------------------------------------------------------------------- + */ + + // List discussions + $routes->get( + '/discussions', + 'flarum.api.discussions.index', + $this->action('Flarum\Api\Actions\Discussions\IndexAction') + ); + + // Create a discussion + $routes->post( + '/discussions', + 'flarum.api.discussions.create', + $this->action('Flarum\Api\Actions\Discussions\CreateAction')); + + // Show a single discussion + $routes->get( + '/discussions/{id}', + 'flarum.api.discussions.show', + $this->action('Flarum\Api\Actions\Discussions\ShowAction') + ); + + // Edit a discussion + $routes->put( + '/discussions/{id}', + 'flarum.api.discussions.update', + $this->action('Flarum\Api\Actions\Discussions\UpdateAction') + ); + + // Delete a discussion + $routes->delete( + '/discussions/{id}', + 'flarum.api.discussions.delete', + $this->action('Flarum\Api\Actions\Discussions\DeleteAction') + ); + + /* + |-------------------------------------------------------------------------- + | Posts + |-------------------------------------------------------------------------- + */ + + // List posts, usually for a discussion + $routes->get( + '/posts', + 'flarum.api.posts.index', + $this->action('Flarum\Api\Actions\Posts\IndexAction') + ); + + // Create a post + // @todo consider 'discussions/{id}/links/posts'? + $routes->post( + '/posts', + 'flarum.api.posts.create', + $this->action('Flarum\Api\Actions\Posts\CreateAction') + ); + + // Show a single or multiple posts by ID + $routes->get( + '/posts/{id}', + 'flarum.api.posts.show', + $this->action('Flarum\Api\Actions\Posts\ShowAction') + ); + + // Edit a post + $routes->put( + '/posts/{id}', + 'flarum.api.posts.update', + $this->action('Flarum\Api\Actions\Posts\UpdateAction') + ); + + // Delete a post + $routes->delete( + '/posts/{id}', + 'flarum.api.posts.delete', + $this->action('Flarum\Api\Actions\Posts\DeleteAction') + ); + + /* + |-------------------------------------------------------------------------- + | Groups + |-------------------------------------------------------------------------- + */ + + // List groups + $routes->get( + '/groups', + 'flarum.api.groups.index', + $this->action('Flarum\Api\Actions\Groups\IndexAction') + ); + + // Create a group + $routes->post( + '/groups', + 'flarum.api.groups.create', + $this->action('Flarum\Api\Actions\Groups\CreateAction') + ); + + // Show a single group + $routes->get( + '/groups/{id}', + 'flarum.api.groups.show', + $this->action('Flarum\Api\Actions\Groups\ShowAction') + ); + + // Edit a group + $routes->put( + '/groups/{id}', + 'flarum.api.groups.update', + $this->action('Flarum\Api\Actions\Groups\UpdateAction') + ); + + // Delete a group + $routes->delete( + '/groups/{id}', + 'flarum.api.groups.delete', + $this->action('Flarum\Api\Actions\Groups\DeleteAction') + ); + } + + protected function action($class) + { + return function (ServerRequestInterface $httpRequest, $routeParams) use ($class) { + $action = app($class); + $actor = app('Flarum\Support\Actor'); + + $input = array_merge($httpRequest->getAttributes(), $routeParams); + $request = new Request($input, $actor, $httpRequest); + + return $action->handle($request); + }; } } diff --git a/src/Api/routes.php b/src/Api/routes.php deleted file mode 100644 index 4e64707dd..000000000 --- a/src/Api/routes.php +++ /dev/null @@ -1,134 +0,0 @@ -app->make($class); - $actor = $this->app->make('Flarum\Support\Actor'); - - $input = array_merge($httpRequest->getAttributes(), $routeParams); - $request = new Request($input, $actor, $httpRequest); - - return $action->handle($request); - }; -}; - -/** @var Flarum\Http\Router $router */ -$router = $this->app->make('Flarum\Http\Router'); - -// Get forum information -$router->get('/api/forum', 'flarum.api.forum.show', $action('Flarum\Api\Actions\Forum\ShowAction')); - -// Retrieve authentication token -$router->post('/api/token', 'flarum.api.token', $action('Flarum\Api\Actions\TokenAction')); - -// Send forgot password email -$router->post('/forgot', 'flarum.api.forgot', $action('Flarum\Api\Actions\ForgotAction')); - -/* -|-------------------------------------------------------------------------- -| Users -|-------------------------------------------------------------------------- -*/ - -// List users -$router->get('/api/users', 'flarum.api.users.index', $action('Flarum\Api\Actions\Users\IndexAction')); - -// Register a user -$router->post('/api/users', 'flarum.api.users.create', $action('Flarum\Api\Actions\Users\CreateAction')); - -// Get a single user -$router->get('/api/users/{id}', 'flarum.api.users.show', $action('Flarum\Api\Actions\Users\ShowAction')); - -// Edit a user -$router->put('/api/users/{id}', 'flarum.api.users.update', $action('Flarum\Api\Actions\Users\UpdateAction')); - -// Delete a user -$router->delete('/api/users/{id}', 'flarum.api.users.delete', $action('Flarum\Api\Actions\Users\DeleteAction')); - -// Upload avatar -$router->post('/api/users/{id}/avatar', 'flarum.api.users.avatar.upload', $action('Flarum\Api\Actions\Users\UploadAvatarAction')); - -// Remove avatar -$router->delete('/api/users/{id}/avatar', 'flarum.api.users.avatar.delete', $action('Flarum\Api\Actions\Users\DeleteAvatarAction')); - -/* -|-------------------------------------------------------------------------- -| Activity -|-------------------------------------------------------------------------- -*/ - -// List activity -$router->get('/api/activity', 'flarum.api.activity.index', $action('Flarum\Api\Actions\Activity\IndexAction')); - -// List notifications for the current user -$router->get('/api/notifications', 'flarum.api.notifications.index', $action('Flarum\Api\Actions\Notifications\IndexAction')); - -// Mark a single notification as read -$router->put('/api/notifications/{id}', 'flarum.api.notifications.update', $action('Flarum\Api\Actions\Notifications\UpdateAction')); - -/* -|-------------------------------------------------------------------------- -| Discussions -|-------------------------------------------------------------------------- -*/ - -// List discussions -$router->get('/api/discussions', 'flarum.api.discussions.index', $action('Flarum\Api\Actions\Discussions\IndexAction')); - -// Create a discussion -$router->post('/api/discussions', 'flarum.api.discussions.create', $action('Flarum\Api\Actions\Discussions\CreateAction')); - -// Show a single discussion -$router->get('/api/discussions/{id}', 'flarum.api.discussions.show', $action('Flarum\Api\Actions\Discussions\ShowAction')); - -// Edit a discussion -$router->put('/api/discussions/{id}', 'flarum.api.discussions.update', $action('Flarum\Api\Actions\Discussions\UpdateAction')); - -// Delete a discussion -$router->delete('/api/discussions/{id}', 'flarum.api.discussions.delete', $action('Flarum\Api\Actions\Discussions\DeleteAction')); - -/* -|-------------------------------------------------------------------------- -| Posts -|-------------------------------------------------------------------------- -*/ - -// List posts, usually for a discussion -$router->get('/api/posts', 'flarum.api.posts.index', $action('Flarum\Api\Actions\Posts\IndexAction')); - -// Create a post -// @todo consider 'discussions/{id}/links/posts'? -$router->post('/api/posts', 'flarum.api.posts.create', $action('Flarum\Api\Actions\Posts\CreateAction')); - -// Show a single or multiple posts by ID -$router->get('/api/posts/{id}', 'flarum.api.posts.show', $action('Flarum\Api\Actions\Posts\ShowAction')); - -// Edit a post -$router->put('/api/posts/{id}', 'flarum.api.posts.update', $action('Flarum\Api\Actions\Posts\UpdateAction')); - -// Delete a post -$router->delete('/api/posts/{id}', 'flarum.api.posts.delete', $action('Flarum\Api\Actions\Posts\DeleteAction')); - -/* -|-------------------------------------------------------------------------- -| Groups -|-------------------------------------------------------------------------- -*/ - -// List groups -$router->get('/api/groups', 'flarum.api.groups.index', $action('Flarum\Api\Actions\Groups\IndexAction')); - -// Create a group -$router->post('/api/groups', 'flarum.api.groups.create', $action('Flarum\Api\Actions\Groups\CreateAction')); - -// Show a single group -$router->get('/api/groups/{id}', 'flarum.api.groups.show', $action('Flarum\Api\Actions\Groups\ShowAction')); - -// Edit a group -$router->put('/api/groups/{id}', 'flarum.api.groups.update', $action('Flarum\Api\Actions\Groups\UpdateAction')); - -// Delete a group -$router->delete('/api/groups/{id}', 'flarum.api.groups.delete', $action('Flarum\Api\Actions\Groups\DeleteAction')); diff --git a/src/Core/CoreServiceProvider.php b/src/Core/CoreServiceProvider.php index 2d219ced1..b7e2dba16 100644 --- a/src/Core/CoreServiceProvider.php +++ b/src/Core/CoreServiceProvider.php @@ -70,11 +70,6 @@ class CoreServiceProvider extends ServiceProvider $this->app->singleton('flarum.formatter', 'Flarum\Core\Formatter\FormatterManager'); - $this->app->bind( - 'Flarum\Http\UrlGeneratorInterface', - 'Flarum\Http\UrlGenerator' - ); - $this->app->bind( 'Flarum\Core\Repositories\DiscussionRepositoryInterface', 'Flarum\Core\Repositories\EloquentDiscussionRepository' diff --git a/src/Forum/ForumServiceProvider.php b/src/Forum/ForumServiceProvider.php index 9ce974e34..5016bf7f1 100644 --- a/src/Forum/ForumServiceProvider.php +++ b/src/Forum/ForumServiceProvider.php @@ -1,10 +1,32 @@ app->singleton('flarum.forum.assetManager', function ($app) { + return new AssetManager($app['files'], $app['path.public'].'/assets', 'forum'); + }); + + $this->app->singleton( + 'Flarum\Http\UrlGeneratorInterface', + function () { + return new UrlGenerator($this->app->make('flarum.forum.routes')); + } + ); + } + /** * Bootstrap the application events. * @@ -20,18 +42,60 @@ class ForumServiceProvider extends ServiceProvider $root.'/public/fonts' => public_path('assets/fonts') ]); - include __DIR__.'/routes.php'; + $this->routes(); } - /** - * Register the service provider. - * - * @return void - */ - public function register() + protected function routes() { - $this->app['flarum.forum.assetManager'] = $this->app->share(function ($app) { - return new AssetManager($app['files'], $app['path.public'].'/assets', 'forum'); - }); + $this->app->instance('flarum.forum.routes', $routes = new RouteCollection); + + /** + * Route::group(['middleware' => 'Flarum\Forum\Middleware\LoginWithCookie'], function () use ($action) { + * For the two below + */ + $routes->get( + '/', + 'flarum.forum.index', + $this->action('Flarum\Forum\Actions\IndexAction') + ); + + $routes->get( + '/logout', + 'flarum.forum.logout', + $this->action('Flarum\Forum\Actions\LogoutAction') + ); + + $routes->post( + '/login', + 'flarum.forum.login', + $this->action('Flarum\Forum\Actions\LoginAction') + ); + + $routes->get( + '/confirm/{token}', + 'flarum.forum.confirmEmail', + $this->action('Flarum\Forum\Actions\ConfirmEmailAction') + ); + + $routes->get( + '/reset/{token}', + 'flarum.forum.resetPassword', + $this->action('Flarum\Forum\Actions\ResetPasswordAction') + ); + + $routes->post( + '/reset', + 'flarum.forum.savePassword', + $this->action('Flarum\Forum\Actions\SavePasswordAction') + ); + } + + protected function action($class) + { + return function (ServerRequestInterface $httpRequest, $routeParams) use ($class) { + $action = $this->app->make($class); + + return $action->handle($httpRequest, $routeParams); + }; } } diff --git a/src/Forum/routes.php b/src/Forum/routes.php deleted file mode 100755 index 43023354a..000000000 --- a/src/Forum/routes.php +++ /dev/null @@ -1,31 +0,0 @@ -app->make($class); - - return $action->handle($httpRequest, $routeParams); - }; -}; - -/** @var Flarum\Http\Router $router */ -$router = $this->app->make('Flarum\Http\Router'); - -/** - * Route::group(['middleware' => 'Flarum\Forum\Middleware\LoginWithCookie'], function () use ($action) { - * For the two below - */ - -$router->get('/', 'flarum.forum.index', $action('Flarum\Forum\Actions\IndexAction')); - -$router->get('/logout', 'flarum.forum.logout', $action('Flarum\Forum\Actions\LogoutAction')); - -$router->post('/login', 'flarum.forum.login', $action('Flarum\Forum\Actions\LoginAction')); - -$router->get('/confirm/{token}', 'flarum.forum.confirmEmail', $action('Flarum\Forum\Actions\ConfirmEmailAction')); - -$router->get('/reset/{token}', 'flarum.forum.resetPassword', $action('Flarum\Forum\Actions\ResetPasswordAction')); - -$router->post('/reset', 'flarum.forum.savePassword', $action('Flarum\Forum\Actions\SavePasswordAction')); diff --git a/src/Http/RouteCollection.php b/src/Http/RouteCollection.php new file mode 100644 index 000000000..ecfe9c635 --- /dev/null +++ b/src/Http/RouteCollection.php @@ -0,0 +1,83 @@ +dataGenerator = new DataGenerator\GroupCountBased; + $this->routeParser = new RouteParser\Std; + } + + public function get($path, $name, $handler) + { + return $this->addRoute('GET', $path, $name, $handler); + } + + public function post($path, $name, $handler) + { + return $this->addRoute('POST', $path, $name, $handler); + } + + public function put($path, $name, $handler) + { + return $this->addRoute('PUT', $path, $name, $handler); + } + + public function delete($path, $name, $handler) + { + return $this->addRoute('DELETE', $path, $name, $handler); + } + + public function addRoute($method, $path, $name, $handler) + { + $this->dataGenerator->addRoute( + $method, + $parsed = $this->routeParser->parse($path), + $handler + ); + + $this->reverse[$name] = $parsed; + + return $this; + } + + public function getRouteData() + { + return $this->dataGenerator->getData(); + } + + public function getPath($name, $parameters = []) + { + $parts = $this->reverse[$name]; + + $path = implode('', array_map(function ($part) use ($parameters) { + if (is_array($part)) { + $part = $parameters[$part[0]]; + } + return $part; + }, $parts)); + + $path = '/' . ltrim($path, '/'); + return $path; + } +} diff --git a/src/Http/RouteNotFoundException.php b/src/Http/RouteNotFoundException.php new file mode 100644 index 000000000..534f58a54 --- /dev/null +++ b/src/Http/RouteNotFoundException.php @@ -0,0 +1,9 @@ +routeParser = new RouteParser\Std; - $this->dataGenerator = new DataGenerator\GroupCountBased; - } - - public function get($path, $name, $handler) - { - return $this->addRoute('GET', $path, $name, $handler); - } - - public function post($path, $name, $handler) - { - return $this->addRoute('POST', $path, $name, $handler); - } - - public function put($path, $name, $handler) - { - return $this->addRoute('PUT', $path, $name, $handler); - } - - public function delete($path, $name, $handler) - { - return $this->addRoute('DELETE', $path, $name, $handler); - } - - public function addRoute($method, $path, $name, $handler) - { - $routeData = $this->routeParser->parse($path); - $this->dataGenerator->addRoute($method, $routeData, $handler); - - $routeData['method'] = $method; - $this->reverse[$name] = $routeData; - - return $this; - } - - public function getPath($name, $parameters = []) - { - $parts = $this->reverse[$name]; - array_forget($parts, 'method'); - - $path = implode('', array_map(function ($part) use ($parameters) { - if (is_array($part)) { - $part = $parameters[$part[0]]; - } - return $part; - }, $parts)); - - $path = '/' . ltrim($path, '/'); - return $path; - } - - public function getCurrentPath() - { - $name = $this->currentRequestName; - $parameters = $this->currentRequestParameters; - - return $this->getPath($name, $parameters); - } - - public function getMethod($handler) - { - return array_get($this->reverse, $handler . '.method', ''); - } - - public function dispatch(Request $request) - { - $method = $request->getMethod(); - $uri = $request->getUri()->getPath(); - - $routeInfo = $this->getDispatcher()->dispatch($method, $uri); - - switch ($routeInfo[0]) { - case Dispatcher::NOT_FOUND: - throw new \Exception('404 Not Found'); - case Dispatcher::METHOD_NOT_ALLOWED: - throw new \Exception('405 Method Not Allowed'); - case Dispatcher::FOUND: - $handler = $routeInfo[1]; - $parameters = $routeInfo[2]; - - return $handler($request, $parameters); - } - } - - protected function getDispatcher() - { - if (! isset($this->dispatcher)) { - $this->dispatcher = new Dispatcher\GroupCountBased($this->dataGenerator->getData()); - } - - return $this->dispatcher; - } -} diff --git a/src/Http/RouterMiddleware.php b/src/Http/RouterMiddleware.php new file mode 100644 index 000000000..012839655 --- /dev/null +++ b/src/Http/RouterMiddleware.php @@ -0,0 +1,68 @@ +routes = $routes; + } + + /** + * Dispatch the given request to our route collection. + * + * @param Request $request + * @param Response $response + * @param callable $out + * @return Response + * @throws RouteNotFoundException + */ + public function __invoke(Request $request, Response $response, callable $out = null) + { + $method = $request->getMethod(); + $uri = $request->getUri()->getPath(); + + $routeInfo = $this->getDispatcher()->dispatch($method, $uri);dd($request, $this->routes, $routeInfo); + + switch ($routeInfo[0]) { + case Dispatcher::NOT_FOUND: + case Dispatcher::METHOD_NOT_ALLOWED: + throw new RouteNotFoundException; + case Dispatcher::FOUND: + $handler = $routeInfo[1]; + $parameters = $routeInfo[2]; + + return $handler($request, $parameters); + } + } + + protected function getDispatcher() + { + if (! isset($this->dispatcher)) { + $this->dispatcher = new Dispatcher\GroupCountBased($this->routes->getRouteData()); + } + + return $this->dispatcher; + } +} \ No newline at end of file diff --git a/src/Http/UrlGenerator.php b/src/Http/UrlGenerator.php index f712102cc..7630a80e7 100644 --- a/src/Http/UrlGenerator.php +++ b/src/Http/UrlGenerator.php @@ -4,17 +4,17 @@ namespace Flarum\Http; class UrlGenerator implements UrlGeneratorInterface { - protected $router; + protected $routes; - public function __construct(Router $router) + public function __construct(RouteCollection $routes) { - $this->router = $router; + $this->routes = $routes; } public function toRoute($name, $parameters = []) { - $path = $this->router->getPath($name, $parameters); + $path = $this->routes->getPath($name, $parameters); $path = ltrim($path, '/'); // TODO: Prepend real base URL