[SP-pm] Controller thin, model fat ! Como fazê-lo ?

Eden Cardim edencardim at gmail.com
Fri Jun 8 06:29:26 PDT 2012


>>>>> "Solli" == Solli Honorio <shonorio em gmail.com> writes:

    Solli> Por exemplo, tenho que receber um arquivo de imagem, que deverá ser
    Solli> validada (se é uma imagem mesmo, etc), depois relacionar ao usuário
    Solli> e armazenar em um storage.

    Solli> Nesta situação eu tenho diversas tarefas, algumas que seriam
    Solli> natural colocar no controller, outras nem tanto.
    
    Solli> Qual a melhor maneira de lidar com isto ?

Cria uma classe contendo um ou mais métodos que aceitem o usuário, o arquivo e
o storage e que execute as operações necessárias com eles, esse tipo de classe
se chama "Façade" porque fornece acesso simplificado a uma parte mais
complicada da lógica de negócio. A questão é encontrar a melhor forma de
abstrair essas 3 entidades. Por exemplo, elas podem ser modeladas/abstraídas
dentro de suas próprias classes, caso seja necessário. A melhor forma de
pensar em como montar essas classes, é imaginar como você usaria elas fora do
contexto de web app.

Para abstrair os arquivos, geralmente eu recomendo a API do IO::Handle, ou
seja, você passa um objeto filehandle-like para o método, representando o
arquivo em questão.

"Storage" é bastante dependente da lógica de negócio, e depende da
flexibilidade que você deseja. Um caso comum é que o seu storage seja um banco
de dados, e nesse caso, a abstração mais óbvia seria um dbh do DBI. Se você
precisar de mais "inteligência" nesse objeto, cria uma classe que encapsule o
dbh e faça as operações adequadas em cima dele (um objeto DBIx::Class::Schema,
por exemplo)

"User" poderia ser o objeto retornado por $c->user, já que você tá usando
Catalyst. Mas uma abordagem mais flexível seria passar o username ou coisa que
o valha, assim você não fica amarrado numa implementação específica.

nesse caso, seu model poderia implementar um método assim:

sub handle {
  my($self, $fh, $dbh, $user) = @_;
  # biz logic goes here
}

E o seu lean controller ficaria mais ou menos assim:

sub my_action :Local {
  my($self, $c) = @_;
  $c->model('MyBizClass')
    ->handle($c->req->upload('file')->fh, $c->model('DB')->dbh, $c->user->email);
}

Assumindo que você esteja pegando o arquivo de um campo upload chamado 'file'
e que tenha um model chamado 'DB' já com um dbh conectado, etc. A mentalidade
do lean controller é apenas a de integrar a sua classe contendo a lógica de
negócio com o contexto da web.

Observe que você pode usar essa classe de model em qualquer lugar, como por
exemplo, numa utilidade CLI:

my $biz = MyBizClass->new;
$biz->handle(\*STDIN, DBI->connect($ARGV[0]), $ARGV[1])

cat arquivo | perl util.pl dbi:Pg:dbname=foobar foo em bar.baz

-- 
Eden Cardim
+55 11 9644 8225
http://insoli.de


More information about the SaoPaulo-pm mailing list