Silex – Encaminhar solicitações

Vamos começar com uma pequena introdução.
Atualmente trabalho em uma empresa que usa uma API para servir dados de vários serviços.
Esta API é construída usando silex, o que é incrível.

Temos muitos endpoints de API como:
/ blog / blog_id / comments /

/ blog é mapeado para um controlador de blog usando:

$application = new SilexApplication();
$application
->mount('/blog', new AppControllerBlog

O controlador do blog costumava ser algo assim:

namespace AppController;

use SilexApplication,
SilexControllerProviderInterface
;

class Blog implements ControllerProviderInterface
{
public function connect(Application $application)
{
$this
->app = $application;
$controllers
= $this->app['controllers_factory'];

$controllers
->get(
'/',
array
($this, 'getAllBlogPosts')
);
$controllers
->get(
'/{blogpost_id}/',
array
($this, 'getOneBlogPost')
);
$controllers
->get(
'/{blogpost_id}/authors/',
array
($this, 'getAllAuthors')
);
$controllers
->get(
'/{blogpost_id}/authors/{author_id}/',
array
($this, 'getOneAuthor')
);
$controllers
->get(
'/{blogpost_id}/comments/',
array
($this, 'getAllComments')
);
$controllers
->get(
'/{blogpost_id}/comments/{comment_id}/',
array
($this, 'getOneComment')
);
$controllers
->get(
'/{blogpost_id}/tags/',
array
($this, 'getAllTags')
);
$controllers
->get(
'/{blogpost_id}/tags/{tag_id}/',
array
($this, 'getOneTag')
);

return $controllers;
}
}

Neste exemplo, deixei de fora os outros métodos, mas você entendeu a idéia geral.

Como você pode imaginar, você pode querer obter comentários como um recurso de API de primeira classe (por exemplo, api_url / comments /. Os comentários seriam mapeados para um controlador de comentários. Este controlador teria muito da mesma lógica dos métodos getAllComments e getOneComment do controlador de blog. Isso é ruim quando você mantém o princípio DRY em mente.

Uma solução melhor para esse problema seria encaminhar os métodos getAllComments e getOneComment do controlador de blog para o controlador de comentários. Deixe-me mostrar como isso pode ser alcançado.

1) crie um controlador de comentários separado que tenha os métodos getAllComments e getOneComments.

namespace AppController;

use SilexApplication,
SilexControllerProviderInterface
;

class Comments implements ControllerProviderInterface
{
public function connect(Application $application)
{
$controllers
= $app['controllers_factory'];

$controllers
->get('/', array($this, 'getAllComments'));
$controllers
->get('/{comment_id}/', array($this, 'getOneComment'));

return $controllers;
}

// ... other methods

}

2) mapear / comentários para o controlador de comentários
$ application = new Silex Application ();
// … / blog
$ application-> mount (‘/ comments’, new App Controller Comments

3) No controlador de blog, encaminhe solicitações para / blog / id do blog / comentários / & / blog / id do blog / comentários / comment_id / para o novo controlador de comentários.

namespace AppController;

use SilexApplication,
SilexControllerProviderInterface
,
SymfonyComponentHttpFoundationRequest
,
SymfonyComponentHttpKernelHttpKernelInterface
;

class Blog implements ControllerProviderInterface
{
protected $app;

public function connect(Application $application)
{
$this
->app = $application;
$controllers
= $this->app['controllers_factory'];

...
$controllers
->get(
'/{blogpost_id}/comments/',
array
($this, 'forwardToComments')
);
$controllers
->get(
'/{blogpost_id}/comments/{comment_id}/',
array
($this, 'forwardToComments')
);
...

return $controllers;
}

public function forwardToComments($blogpost_id, $comment_id = null)
{
$request
= $this->app['request'];
$query
= array('blogpost_id' => $blogpost_id);
$uri
= $request->getUriForPath('/comments').'/';
$uri
.= $comment_id ? $comment_id.'/' : '';

$query
= '?' . http_build_query(array_merge(
$request
->query->all(),
$query

));

$subRequest
= Request::create(
$uri
.$query,
$request
->getMethod(),
$request
->request->all(),
$request
->cookies->all(),
$request
->files->all(),
$request
->server->all()
);

return $this->app->handle(
$subRequest
,
HttpKernelInterface::SUB_REQUEST,
false
);
}
}

É isso, você só precisa criar uma nova instância de Request com os parâmetros corretos e deixar Silex Application cuidar disso.