Digamos que sempre que eu faço uma operação CRUD ou modifico um relacionamento de uma maneira específica, também quero fazer outra coisa. Por exemplo, sempre que alguém publica uma postagem, também quero salvar algo em uma tabela para análise. Talvez não seja o melhor exemplo, mas em geral há muito dessa funcionalidade "agrupada".
Normalmente, vejo esse tipo de lógica colocada nos controladores. Tudo bem, até que você queira reproduzir essa funcionalidade em muitos lugares. Quando você começa a usar parciais, criando uma API e gerando conteúdo fictício, torna-se um problema manter os itens secos.
As maneiras que eu já vi para gerenciar isso são eventos, repositórios, bibliotecas e adição de modelos. Aqui estão meus entendimentos de cada um:
Serviços: é aqui que a maioria das pessoas provavelmente colocaria esse código. Meu principal problema com os serviços é que, às vezes, é difícil encontrar funcionalidades específicas e sinto que eles são esquecidos quando as pessoas estão focadas no uso do Eloquent. Como eu sei que preciso chamar um método publishPost()
em uma biblioteca quando posso fazer isso $post->is_published = 1
?
A única condição em que vejo isso funcionando bem é se você APENAS usar serviços (e idealmente tornar o Eloquent inacessível de alguma forma pelos controladores todos juntos).
Por fim, parece que isso criaria apenas um monte de arquivos desnecessários extras se suas solicitações geralmente seguirem a estrutura do seu modelo.
Repositórios: Pelo que entendi, isso é basicamente como um serviço, mas há uma interface para que você possa alternar entre ORMs, dos quais não preciso.
Eventos: Eu vejo isso como o sistema mais elegante em certo sentido, porque você sabe que seus eventos de modelo sempre serão chamados em métodos Eloquent, para que você possa escrever seus controladores como faria normalmente. Eu posso ver isso ficando confuso e se alguém tiver exemplos de grandes projetos usando eventos para acoplamento crítico, eu gostaria de vê-lo.
Modelos: Tradicionalmente, eu tinha aulas que realizavam CRUD e também lidavam com acoplamentos críticos. Isso realmente facilitou as coisas, porque você sabia que todas as funcionalidades do CRUD + tinham que ser feitas com ele.
Simples, mas na arquitetura MVC isso normalmente não é o que vejo feito. Em certo sentido, eu prefiro isso a serviços, pois é um pouco mais fácil de encontrar e há menos arquivos para acompanhar. Pode ficar um pouco desorganizado. Eu gostaria de ouvir quedas nesse método e por que a maioria das pessoas parece não fazer isso.
Quais são as vantagens / desvantagens de cada método? Estou esquecendo de algo?
fonte
Respostas:
Eu acho que todos os padrões / arquiteturas que você apresenta são muito úteis, desde que você siga os princípios do SOLID .
Para onde adicionar lógica , acho importante referir-se ao Princípio da Responsabilidade Única . Além disso, minha resposta considera que você está trabalhando em um projeto de médio / grande porte. Se for um projeto jogar algo na página , esqueça esta resposta e adicione tudo aos controladores ou modelos.
A resposta curta é: onde faz sentido para você (com serviços) .
A resposta longa:
Controladores : Qual é a responsabilidade dos controladores? Claro, você pode colocar toda a sua lógica em um controlador, mas isso é responsabilidade do controlador? Acho que não.
Para mim, o controlador deve receber uma solicitação e retornar dados e este não é o lugar para colocar validações, chamar métodos db, etc.
Modelos : este é um bom lugar para adicionar lógica, como enviar um email de boas-vindas quando um usuário registrar ou atualizar a contagem de votos de uma postagem? E se você precisar enviar o mesmo email de outro lugar no seu código? Você cria um método estático? E se esses emails precisarem de informações de outro modelo?
Eu acho que o modelo deve representar uma entidade. Com Laravel, eu só uso a classe modelo para adicionar coisas como
fillable
,guarded
,table
e as relações (isto é porque eu uso o padrão de repositório, caso contrário, o modelo também teria ossave
,update
,find
métodos, etc.).Repositórios (Padrão de Repositório) : No começo, fiquei muito confuso com isso. E, como você, pensei "bem, eu uso o MySQL e é isso.".
No entanto, equilibrei os prós e os contras do uso do Padrão de Repositório e agora eu o uso. Eu acho que agora , neste exato momento, precisarei usar apenas o MySQL. Porém, se daqui a três anos precisar mudar para algo como o MongoDB, a maior parte do trabalho está concluída. Tudo à custa de uma interface extra e a
$app->bind(«interface», «repository»)
.Eventos ( Padrão do Observador ): Eventos são úteis para itens que podem ser lançados em qualquer classe a qualquer momento. Pense, por exemplo, em enviar notificações para um usuário. Quando necessário, você aciona o evento para enviar uma notificação para qualquer classe do seu aplicativo. Em seguida, você pode ter uma classe como
UserNotificationEvents
essa que lida com todos os seus eventos acionados para notificações do usuário.Serviços : até agora, você tem a opção de adicionar lógica aos controladores ou modelos. Para mim, faz todo o sentido adicionar a lógica nos Serviços . Vamos ser sinceros, serviços é um nome sofisticado para as aulas. E você pode ter quantas aulas fizer sentido em seu aplicativo.
Veja este exemplo: Há pouco tempo, desenvolvi algo como o Formulários Google. Comecei com uma
CustomFormService
e acabou comCustomFormService
,CustomFormRender
,CustomFieldService
,CustomFieldRender
,CustomAnswerService
eCustomAnswerRender
. Por quê? Porque isso fez sentido para mim. Se você trabalha com uma equipe, deve colocar sua lógica onde faz sentido para a equipe.A vantagem de usar Serviços x Controladores / Modelos é que você não é limitado por um único Controlador ou um único Modelo. Você pode criar quantos serviços forem necessários, com base no design e nas necessidades do seu aplicativo. Acrescente a isso a vantagem de chamar um Serviço dentro de qualquer classe do seu aplicativo.
Isso demora muito, mas eu gostaria de mostrar como estruturei meu aplicativo:
Eu uso cada pasta para uma função específica. Por exemplo, o
Validators
diretório contém umaBaseValidator
classe responsável por processar a validação, com base na$rules
e$messages
de validadores específicos (normalmente um para cada modelo). Eu poderia facilmente colocar esse código em um Serviço, mas faz sentido ter uma pasta específica para isso, mesmo que seja usada apenas dentro do serviço (por enquanto).Eu recomendo que você leia os seguintes artigos, pois eles podem explicar as coisas um pouco melhor para você:
Breaking the Mold por Dayle Rees (autor do CodeBright): Foi aqui que reuni tudo, mesmo que eu tenha mudado algumas coisas para atender às minhas necessidades.
Desacoplar seu código no Laravel usando Repositórios e Serviços de Chris Goosey: Esta postagem explica bem o que é um Serviço e o Padrão de Repositório e como eles se encaixam.
Os Laracasts também têm os Repositórios de Responsabilidade Simplificada e Única, que são bons recursos com exemplos práticos (mesmo que você precise pagar).
fonte
Eu queria postar uma resposta para minha própria pergunta. Eu poderia falar sobre isso por dias, mas vou tentar publicá-lo rapidamente para garantir que eu aconteça.
Acabei utilizando a estrutura existente que o Laravel fornece, o que significa que mantive meus arquivos principalmente como Model, View e Controller. Também tenho uma pasta Bibliotecas para componentes reutilizáveis que não são realmente modelos.
NÃO ENVIEI MEUS MODELOS EM SERVIÇOS / BIBLIOTECAS . Todos os motivos apresentados não me convenceram 100% do benefício do uso de serviços. Embora eu esteja errado, até onde eu vejo, eles resultam em toneladas de arquivos quase vazios extras que eu preciso criar e alternar ao trabalhar com modelos e também reduzir realmente o benefício de usar eloquentes (especialmente quando se trata de RECUPERAR modelos por exemplo, usando paginação, escopos etc.).
Coloquei a lógica de negócios NOS MODELOS e acesso eloquente diretamente dos meus controladores. Eu uso várias abordagens para garantir que a lógica de negócios não seja ignorada:
Abordando as preocupações das pessoas com o uso de modelos:
Nota adicional: Eu sinto que envolver seus modelos em serviços é como ter um canivete suíço, com muitas ferramentas, e construir outra faca em torno dele que basicamente faz a mesma coisa? Sim, às vezes você pode colar uma lâmina ou garantir que duas lâminas sejam usadas juntas ... mas normalmente existem outras maneiras de fazer isso ...
QUANDO USAR SERVIÇOS : Este artigo articula excelentes exemplos de quando usar serviços ( dica: não é muito frequente ). Ele diz que basicamente quando seu objeto usa vários modelos ou modelos em partes estranhas de seu ciclo de vida , faz sentido. http://www.justinweiss.com/articles/where-do-you-put-your-code/
fonte
O que costumo fazer para criar a lógica entre controladores e modelos é criar uma camada de serviço . Basicamente, este é o meu fluxo para qualquer ação no meu aplicativo:
É assim que eu faço:
Este é o método de um controlador para criar algo:
Esta é a classe de serviço que executa a lógica relacionada à operação:
E este é o meu modelo:
Para obter mais informações sobre esse caminho, uso para organizar meu código para um aplicativo Laravel: https://github.com/rmariuzzo/Pitimi
fonte
$congregation->save();
então talvez você não precise de Repositórios. No entanto, você pode ver suas necessidades de acesso a dados aumentarem com o tempo. Você pode começar a ter necessidades para$congregation->destroyByUser()
ou$congregationUsers->findByName($arrayOfSelectedFields);
e assim por diante. Por que não separar seus serviços das necessidades de acesso a dados. Deixe o resto do seu aplicativo trabalhar com objetos / matrizes retornados de repositórios e apenas manipule / formate / etc ... Seus repositórios crescerão (mas os dividirão em arquivos diferentes, no final, a complexidade de um projeto deve residir em algum lugar).Na minha opinião, o Laravel já tem muitas opções para você armazenar sua lógica de negócios.
Resposta curta:
Request
objetos do laravel para validar automaticamente sua entrada e, em seguida, persista os dados na solicitação (crie o modelo). Como todas as entradas de usuários estão diretamente disponíveis na solicitação, acredito que faça sentido executar isso aqui.Job
objetos do laravel para executar tarefas que exigem componentes individuais e, em seguida, simplesmente despache-os. Eu acho queJob
abrangem classes de serviço. Eles executam uma tarefa, como lógica de negócios.Resposta longa (er):
Usar repositórios quando necessário: os repositórios devem ser exagerados e, na maioria das vezes, são simplesmente usados como
accessor
modelo no modelo. Eu sinto que eles definitivamente têm alguma utilidade, mas, a menos que você esteja desenvolvendo um aplicativo massivo que exija tanta flexibilidade para poder se livrar completamente do laravel, fique longe dos repositórios. Você se agradecerá mais tarde e seu código será muito mais direto.Pergunte a si mesmo se existe a possibilidade de alterar as estruturas PHP ou para um tipo de banco de dados que o laravel não suporta.
Se sua resposta for "Provavelmente não", não implemente o padrão de repositório.
Além do acima, não coloque um padrão em cima de um ORM excelente como o Eloquent. Você está apenas adicionando complexidade que não é necessária e que não será benéfica para você.
Utilize os Serviços com moderação: As classes de serviço para mim são apenas um local para armazenar a lógica de negócios para executar uma tarefa específica com suas dependências fornecidas. O Laravel possui esses itens prontos para uso, chamados 'Trabalhos', e eles têm muito mais flexibilidade do que uma classe de Serviço personalizada.
Sinto que o Laravel tem uma solução completa para o
MVC
problema de lógica. É apenas uma questão ou organização.Exemplo:
Pedido :
Controlador :
No exemplo acima, a entrada da solicitação é validada automaticamente, e tudo o que precisamos fazer é chamar o método persist e passar uma nova postagem. Acho que a legibilidade e a manutenção devem sempre superar os padrões de design complexos e desnecessários.
Você também pode utilizar exatamente o mesmo método persistente para atualizar as postagens, pois podemos verificar se a postagem já existe ou não e executar uma lógica alternativa quando necessário.
fonte
ShouldQueue
que o Laravel fornece. Se você deseja gravar a lógica de negócios em um comando ou evento, basta disparar o trabalho dentro desses eventos / comandos. Os trabalhos do Laravels são extremamente flexíveis, mas no final são apenas classes de serviço simples.