Sei sulla pagina 1di 10

Laravel: De Aprendiz a Arteso (Brazilian

Portuguese)
Taylor Otwell and Pedro Borges
This book is for sale at http://leanpub.com/laravel-pt-br
This version was published on 2013-10-01
This is a Leanpub book. Leanpub empowers authors and publishers with the Lean Publishing
process. Lean Publishing is the act of publishing an in-progress ebook using lightweight tools
and many iterations to get reader feedback, pivot until you have the right book and build
traction once you do.
2013 Taylor Otwell and Pedro Borges
Tweet This Book!
Please help Taylor Otwell and Pedro Borges by spreading the word about this book on Twitter!
The suggested tweet for this book is:
Acabei de comprar o livro Laravel: De Aprendiz a Arteso por @taylorotwell.
Find out what other people are saying about the book by clicking on this link to search for this
hashtag on Twitter:
https://twitter.com/search/#
Contedo
Injeo de Dependncia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
O Problema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Construa um Contrato . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Indo Alm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
No muito Java? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Injeo de Dependncia
O Problema
A fundao do framework Laravel seu poderoso container de inverso de controle (inversion
of control ou IoC, em ingls). Para compreender o framework de verdade, necessrio ter
um bom entendimento sobre o funcionamento do container. Entretanto, ns devemos notar
que o container IoC simplesmente um mecanismo conveniente para se alcanar o padro de
desenvolvimento de programas injeo de dependncia (dependency injection, em ingls). O uso
do container no obrigatrio para se injetar dependncias, ele apenas facilita esta tarefa.
Em primeiro lugar, vamos explorar porque a injeo de dependncia vantajosa. Considere a
seguinte classe e mtodo:
1 class UserController extends BaseController {
2
3 public function getIndex()
4 {
5 $users = User::all();
6
7 return View::make('users.index', compact('users'));
8 }
9
10 }
Mesmo sendo um cdigo conciso, no podemos test-lo sem acessar um banco de dados. Em
outras palavras, o ORM Eloquent est fortemente acoplado ao nosso controlador. No podemos,
de forma alguma, usar ou testar este controlador sem usar tambm todo o Eloquent, incluindo a
necessidade de um banco de dados. Este cdigo tambm viola um princpio de desenvolvimento
de programas conhecido como separao de conceitos (separation of concerns ou SoC, em ingls).
Em outras palavras: nosso controlador sabe mais do que deveria. Controladores no precisam
saber de onde os dados vm, mas somente como acess-los. O controlador no precisa saber que
os dados esto disponveis em MySQL, apenas que eles existem em algum lugar.
Separao de conceitos
Toda classe deve ter apenas uma responsabilidade e esta responsabilidade deve ser
completamente encapsulada pela classe.
Sendo assim, melhor desacoplar completamente nossa camada web (controlador) da nossa
camada de acesso aos dados. Isso permitir migrar mais facilmente nossa implementao de
Injeo de Dependncia 2
armazenamento de dados e tornar o nosso cdigo mais fcil de ser testado. Pense na web
apenas como uma camada de transporte para a sua aplicao real.
Imagine que sua aplicao um monitor com portas para diversos cabos. Voc pode acessar as
funcionalidades do monitor via HDMI, VGA ou DVI. Pense na internet como sendo apenas um
cabo conectado sua aplicao. O monitor funciona independente do cabo utilizado. O cabo
apenas um meio de transporte, assim como HTTP um meio de transporte que leva sua
aplicao. Assim sendo, ns no queremos entupir nosso meio de transporte (o controlador) com
a parte lgica da aplicao. Isso permitir que qualquer camada de transporte, tais como uma
API ou aplicao mvel, acessem a lgica da nossa aplicao.
Por isso, ao invs de acoplar o controlador ao Eloquent, vamos injetar uma classe repositria.
Construa um Contrato
Em primeiro lugar, vamos definir uma interface e uma implementao correspondente:
1 interface UserRepositoryInterface {
2
3 public function all();
4
5 }
6
7 class DbUserRepository implements UserRepositoryInterface {
8
9 public function all()
10 {
11 return User::all()->toArray();
12 }
13
14 }
Injeo de Dependncia 3
Em seguida, vamos injetar uma implementao desta interface em nosso controlador:
1 class UserController extends BaseController {
2
3 public function __construct(UserRepositoryInterface $users)
4 {
5 $this->users = $users;
6 }
7
8 public function getIndex()
9 {
10 $users = $this->users->all();
11
12 return View::make('users.index', compact('users'));
13 }
14
15 }
Nosso controlador completamente ignorante quanto ao local onde os dados esto sendo
armazenados. Neste caso, esta ignorncia benfica! Os dados podem estar em um banco de
dados MySQL, MongoDB ou Redis. Nosso controlador no reconhece a diferena, isso no
sua responsabilidade. Fazendo essa pequena mudana, ns podemos testar nossa camada
web separadamente da nossa camada de dados, alm de podermos facilmente alternar nossa
implementao de armazenamento de dados.
Respeite os limites
Lembre-se de respeitar os limites da responsabilidade. Controladores e rotas servem
como mediadores entre HTTP e sua aplicao. Ao escrever uma aplicao de grande
porte, no polua-os com lgica de domnio.
Para solidificar nossa compreenso, vamos escrever uma teste rpido. Em primeiro lugar, vamos
simular (mock, em ingls) o repositrio vinculando-o ao container IoC da aplicao. Em seguida,
nos certificaremos de que o controlador invoca o repositrio devidamente:
Injeo de Dependncia 4
1 public function testIndexActionBindsUsersFromRepository()
2 {
3 // Preparar...
4 $repository = Mockery::mock('UserRepositoryInterface');
5 $repository->shouldReceive('all')->once()->andReturn(array('foo'));
6 App::instance('UserRepositoryInterface', $repository);
7
8 // Agir...
9 $response = $this->action('GET', 'UserController@getIndex');
10
11 // Conferir...
12 $this->assertResponseOk();
13 $this->assertViewHas('users', array('foo'));
14 }
Faa de conta
Neste exemplo, ns usamos uma biblioteca chamada Mockery. Esta biblioteca oferece
uma interface limpa e expressiva para fazer os mocks das suas classes. Mockery pode
ser facilmente instalado via Composer.
Indo Alm
Vamos considerar um outro exemplo para solidificar nossa compreenso. Suponha que ns
queremos notificar nossos clientes sobre as cobranas realizadas em suas contas. Para isso, vamos
definir duas interfaces, ou contratos. Estes contratos nos daro flexibilidade para mudar suas
implementaes no futuro.
1 interface BillerInterface {
2 public function bill(array $user, $amount);
3 }
4
5 interface BillingNotifierInterface {
6 public function notify(array $user, $amount);
7 }
Injeo de Dependncia 5
Continuando, vamos construir uma implementao do nosso contrato chamado BillerInterface:
1 class StripeBiller implements BillerInterface {
2
3 public function __construct(BillingNotifierInterface $notifier)
4 {
5 $this->notifier = $notifier;
6 }
7
8 public function bill(array $user, $amount)
9 {
10 // Cobrar o usurio via Stripe...
11
12 $this->notifier->notify($user, $amount);
13 }
14
15 }
Porque separamos a responsabilidade de cada classe, agora ns podemos facilmente injetar
vrias implementaes de notificao em nossa classe de cobrana. Por exemplo, ns poderamos
injetar um SmsNotifier ou um EmailNotifier. A cobrana no est mais preocupado com a
implementao da notificao, somente com o contrato. Enquanto uma classe estiver de acordo
com o contrato (interface), a cobrana ir aceit-la. Alm do mais, ns no apenas adicionamos
flexibilidade, mas tambm a possibilidade de testarmos a nossa cobrana separadamente dos
notificadores apenas injetando um mock BillingNotifierInterface.
Use interfaces
Escrever interfaces pode parecer muito trabalho extra, mas na verdade, elas tornam o
seu desenvolvimento mais rpido. Use interfaces para simular e testar todo o back-end
da sua aplicao antes de escrever uma nica linha de implementao!
Ento, como ns podemos injetar uma dependncia? simples assim:
1 $biller = new StripeBiller(new SmsNotifier);
Isso injeo de dependncia. Ao invs da cobrana se preocupar em notificar os usurios,
ns simplesmente lhe passamos um notificador. Uma mudana simples como esta pode fazer
maravilhas sua aplicao. Seu cdigo instantaneamente se torna mais fcil de manter, porque as
responsabilidades de cada classe foram claramente definidas. A testabilidade de suas aplicaes
aumentar consideravelmente porque agora voc pode injetar mocks de dependncias para isolar
o cdigo em teste.
Mas, e quanto aos containers IoC? Eles no so necessrios na injeo de dependncia? Claro
que no! Conforme veremos nos prximos captulos, containers tornam a injeo de dependncia
mais fcil de gerenciar, mas o seu uso no obrigatrio. Seguindo os princpios deste captulo,
voc j pode praticar injeo de dependncia em qualquer projeto, mesmo que voc ainda no
tenha um container sua disposio.
Injeo de Dependncia 6
No muito Java?
Uma crtica muito comum do uso de interfaces em PHP que elas tornam o seu cdigo muito
parecido com o Java. Em outras palavras, o cdigo se torna muito verbal. Voc precisa definir
uma interface e uma implementao; isso exigir algumas tecladas a mais.
Para aplicaes simples e menores, esta crtica pode at ser vlida. Muitas vezes, as interfaces
no so necessrias nestas aplicaes e perfeitamente ok no us-las. Se voc tem certeza que
a implementao no mudar, voc no precisa criar uma interface.
J para aplicaes maiores, as interfaces sero muito teis. As tecladas extras no sero nada em
comparao com a flexibilidade e testabilidade que voc ganhar. Poder mudar rapidamente a
implementao de uma contrato arrancar um uau do seu chefe, alm de permitir que voc
escreva um cdigo que facilmente se adapta a mudanas.
Para concluir, tenha em mente que este livro apresenta uma arquitetura muito pura. Caso voc
precise reduz-la para uma aplicao menor, no sinta-se culpado. Lembre-se, voc est tentando
programar com alegria. Se voc no gosta do que faz ou est programando por culpa, pare um
pouco e faa uma reavaliao.

Potrebbero piacerti anche