Ir para conteúdo

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Marcielo

Onde posso renderizar o layout?

Recommended Posts

Boa noite pessoal! Minha duvida é de qual seria o lugar mais correto|indicado para se chamar o render da view? Possuo um FrontController, será que esse seria correto chamá-lo ali levando em conta as boas praticas? Nele também tenho a response.

 

Obrigado a todos desde já! :thumbsup:

Compartilhar este post


Link para o post
Compartilhar em outros sites

FrontControler controla todo o processo até chegar nos Action Controllers e não deve manipular, e muito menos conhecer, a View.

 

Mesmo porque cada Action faz uma coisa diferente e requer um Template View diferente. Forçar o FrontController a descobrir uma relação entre URL e o FileSystem seria sofrível.

 

Logo você tem como resposta que tal procedimento deve ser feito nos Action Controllers.

 

Atente apenas ao fato de que também não é responsabilidade da View mostrar dados e sim construir a Resposta que será enviada.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Sim também concordo com você, mas não conseguia ver um bom lugar para renderizar a View, bom pelo que eu entendi se essa é uma tarefa para as Action Controllers haveria uma forma de fazer isso automaticamente? Eu pensei assim se houvesse um método render() dentro da minha classe abstrata das Controllers que ficaria encarregada de descobrir qual foi a View requisitada, renderizá-la e se possivel já enviá-la à Response, ou cuido disso em outro lugar?

 

E outra duvida que surgiu, e se eu despachar outra Action Controller, como ficará a View se fizer da forma automática por assim dizer? Renderizo a View da última Action Controller despachada, e se quiser define manualmente?

Compartilhar este post


Link para o post
Compartilhar em outros sites
Eu pensei assim se houvesse um método render() dentro da minha classe abstrata das Controllers que ficaria encarregada de descobrir qual foi a View requisitada, renderizá-la e se possivel já enviá-la à Response, ou cuido disso em outro lugar?

Apesar de eu mesmo achar que não a coisa mais sensata a se fazer, você pode renderizar automaticamente no destrutor da classe base de todos os seus Controllers.

 

Mas como se __destruct() não aceita argumentos?

 

FileSpec!

 

FileSpecs é um conceito onde você padroniza sua estrutura de diretórios e com base em alguns tokens interpretáveis de uma string, você monta o filepath automaticamente.

 

Um exemplo seria:

 

:controller/:action

View::render() lê essa string e substitui :controller pelo nome da classe do Controller e :action pelo método que está sendo invocado.

 

Para uma classe como a seguinte:

 

<?php

class MyController extends AbstractController {

   public function indexAction() {}
}

O Template View seria buscado em /MyController/indexAction.tpl a partir do diretório-base de suas Views.

 

Esse exemplo em particular não é o mais elegante mas é aí que está a graça da técnica. Você pode limpar aquilo que esses tokens receberão permitindo que o path final seja, por exemplo, /my/index.tpl, por remover os termos Controller e action.

 

O único inconveniente aqui é a relativa queda de performance que você teria comparando com o renderizamento manual, pois aqui uma séries de outras rotinas deveriam ser feitas até se obter o caminho final.

 

E outra duvida que surgiu, e se eu despachar outra Action Controller, como ficará a View se fizer da forma automática por assim dizer? Renderizo a View da última Action Controller despachada, e se quiser define manualmente?

Cada Requisição deve ser trabalhada por um Controller apenas, principal, mas não exclusivamente, para que não hajam conflitos de roteamento.

 

Sendo assim, o Response Body estará sempre limpo a cada nova requisição.

 

A menos, é claro, que você esteja se utilizando de auto_prepend_file e/ou auto_append_file.

 

Mas isso são outros quinhentos.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Excelente idéia Bruno! Isso com certeza resolveu o problema. Gostei bastante do FileSpec e apesar de não querer muito utilizar o __destruct() essa é uma boa opção para que a Controller possa renderizar a View, então utilizarei o __destruct() e na questão de despachar outra Controller não entendi muito bem o que você quis dizer com o "não exclusivamente" já que disse que cada requisição deve ser trabalha por um Controller apenas. Mas realmente isso é uma coisa que tenho pensado bastante, despachar somente a Controller da requisição feita pelo cliente.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Principal, refere-se a que a razão mais importante, ao meu ver, é evitar o conflito de rotas de URL.

 

Mas não exclusivamente, porque não é a única coisa que essa prática evita. Podem haver conflitos com sessões, bancos de dados, output buffer e etc.

 

O mais legal de se ter Controller, View e Response, cada um fazendo a sua parte isoladamente, é montar, pelo menos como aprendi, um HMVC, onde cada componente de uma página, é um MVC próprio, com Controller, Model e View próprios.

 

A diferença é que ao invés de você ter vários Response Bodies sendo ecoados frenéticamente, o Response Body do "Controller principal" (digamos assim) é construído não a partir de uma View, mas a partir dos Response Bodies dos outros MVC's.

 

É um assunto um pouquinho mais complexo, não vou me estender fora do escopo.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Ok! Agora sim pude entender com mais clareza :thumbsup: e já estou botando a mão na massa para adaptar minha View e a base da Controller :grin: e quanto a Response estive lendo alguns tópicos seus e achei um assunto bastante interessante, confesso que minha Response ainda não esta como o desejado, mas sempre que posso busco melhorá-la, ainda tenho muitas duvidas quanto ao funcionamento de algumas coisas e que gostaria de aproveitar para perguntar a você que é um expert no assunto rsrs :grin: e ficaria agradecido se pudesse me ajudar breviamente com isso, segundo o que vi no Zend Framework na Response há um setException() não entendi muito bem porque ele tem isso mas agora não vem ao caso, o que eu ainda não sei é como tratar os erros utilizando a Response, por exemplo poderia simplismente redirecionar a uma Controller que exibiria a mensagem do erro, mas como obter o Stack Trace da exceção já que foi redirecionado?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Expert? Eu? Estou a léguas disso. :lol:

 

Mas enfim, sobre esse setException() não tenho o que dizer porque não sei o que se trata, qual sua assinatura ou seu corpo,logo, não sei o que ele faz.

 

Quanto aos erros, tratados na forma de Exceptions, por hora e na falta de alternativa melhor, eu tenho um Exception Handler definido através de set_exception_handler() que captura toda Exception não pêga (com catch) e exibe amigavelmente, com Stack Trace aninhado e tudo o mais.

 

Mesmo que eu esteja usando e funcione muito bem, ainda é um pouco inflexível no âmbito de produção, onde o Stack Trace não deve aparecer.

 

Mas enfim, não sou o Bátima também né? :P

Compartilhar este post


Link para o post
Compartilhar em outros sites

Expert? Eu? Estou a léguas disso. :lol:

Hahahahaha sim você Bruno, e se não quiser ser entitulado assim então, inteligente pra você! :grin: :worship:

 

Renderização da View

Bom, primeiramente peço desculpas pela demora em responder, estava trabalhando nas mudanças que tive que fazer em algumas de minhas classes para que enfim acredito que obtive um bom resultado graças a sua ajuda Bruno e algumas pesquisas mais, a respeito da renderização da view e quanto as mudanças feitas ficaram da seguinte forma:

  • Antes haviam duas classes Layout e View, a Layout possuia a View e ambas tinham um método render() a diferença é que a Layout renderizava não só o layout mas também a view, pois bem cheguei a conclusão de que "Toda view deve ter o seu layout"(ou visse versa, acho que seria ao contrário hahah ^_^ ), coloquei isso entre aspas porque nem sempre vamos querer renderizar um e outro podendo desabilitá-los, então resumindo eu juntei o Layout a View essa foi a forma que mais convenceu e facilitou muito em alguns aspectos.
  • Quanto ao FileSpec não sei se deveria implementá-lo dentro da View mesmo, mas foi ali que eu fiz e na base da controller um método render() que era assim(era porque eu mudei um pouco as coisas e direi mais adiante) ficou basicamente assim:
    public function render() {
       //path base onde estarão localizadas as views
       $view->addBasePath('...project/app/views/scripts');
       //esse é o que esta como padrão
       $view->setPathSpec(':controller/:action.:suffix');
       //aqui defino os valores a serem substituidos no spec
       $view->setRulesPathSpec(array('controller' => 'minhacontroller', 'action' => 'minhaaction', 'suffix' => 'phtml'));
       $this->getResponse()
            ->appendBody($view->render());
    }
    


    Então na view eu possuo um método que busca qual o path base que possui a respectiva view, então tendo isso, pronto! Já que possuimos o caminho completo do arquivo ele estará pronto para ser renderizado e é ai que entra a parte final da renderização.
    Obs: no render() da base da controller também posso definir a view e layout manualmente.

  • No __destruct() invocava o render() caso não haja sido renderizado manualmente, mas como eu disse que não gostaria de usar o __destruct() andei pesquisando um pouco a forma com que alguns Framework's trabalham em relação a parte de renderização e a do Zend me agradou um pouco e percebi algo importante que vi em muitos Framework's, a utilização de Helpers, no Zend as Helpers possuem métodos preDispacth() pré despache e postDispatch() pós despache, que são notificados a todas as Helpers registradas. E para a renderização ele utiliza uma Helper chamada ViewRenderer com postDispatch() onde ele chama a renderização, com outras palavras seria o mesmo que utilizar o __destruct(), mas resolvi implementar o conceito já que seria útil para outros fins.

Quanto a me basear em coisas assim muitas vezes confesso que faço já que as dificuldades enfrentadas em programação hoje já foram as dificuldades enfrentadas por muitos antes, como uso de Arrays antes implementados pelo usuário através de pilha, fila e etc.. então porque não reaproveitar ideias e conceitos existentes? Acho que se basear não é nenhum mal já que você pensou antes de fazer e não obteve melhores soluções ou esta com duvida em algo, se basear sim, cópia ou plágio nunca! :lol:

 

Tratando exceções Exception Handler

Bom, agora chega de fugir do assunto e vamos ao que interessa :grin:

Quanto aos erros, tratados na forma de Exceptions, por hora e na falta de alternativa melhor, eu tenho um Exception Handler definido através de set_exception_handler() que captura toda Exception não pêga (com catch) e exibe amigavelmente, com Stack Trace aninhado e tudo o mais.

 

Mesmo que eu esteja usando e funcione muito bem, ainda é um pouco inflexível no âmbito de produção, onde o Stack Trace não deve aparecer.

 

Mas enfim, não sou o Bátima também né? :P

Achei bem "legal" a forma com que o set_exception_handler() trabalha, mas também acho que seria algo pouco viável, pensei pensei e pensei e nada de encontrar outra solução que fosse a altura, então novamente fui pesquisar nos Framework's :( encontrei muitas coisas que não agradaram, até que por fim novamente o Zend conseguiu me agradar, só que dessa vez ele utiliza Plugins que me pareceu "igual" as Helpers mas possuindo outros métodos de notificações e que são notificados pela FrontController, aproveitando fui ver o porque do setException() na Response e descobri que ele esta lá apenas como um get set e na mais, nenhuma funcionalidade interna. As exceções são todas armazenadas pelo setException(), no plugin ErrorHandler ele utiliza os métodos que serão notificados pegando a exceção e definindo para a Request qual será a controller e action que tratará o erro, despachando-as. Para mim essa parte do tratamento de erros ainda esta um pouco confusa, e creio que não tenho motivos para implementar Plugins, a não ser que utilizasse uma Helper mesmo, ExceptionHandler para se encarregar disso, adicionaria mais métodos de notificação e ao invés de instanciar a classe principal de Helper dentro da controller, instanciaria na FrontController(também é outra coisa que não sei se seria algo correto a se fazer) e ali notificaria os métodos desejados.

 

 

Bom, espero que tenha conseguido ter paciência para chegar ao fim :wacko: se tiver feito alguma coisa de errado lá na view me diga ^_^ e agradeço muito pela enorme ajuda! :joia:

Compartilhar este post


Link para o post
Compartilhar em outros sites
Antes haviam duas classes Layout e View, a Layout possuia a View e ambas tinham um método render() a diferença é que a Layout renderizava não só o layout mas também a view

Isso pode te abrir um caminho para Composite Views :thumbsup:

 

pois bem cheguei a conclusão de que "Toda view deve ter o seu layout"

Toda action tem seu Template View, mas nem todo Template View precisa necessariamente ser um layout (com HTML completo e tudo o mais).

 

Como só a Response ecoa dados, é de se imaginar que, por exemplo, uma resposta XML ou JSON possa ser construída diretamente no Controller e setado ao Response Body por ele.

 

Mas o Controller apenas controla os dados. Ele não deveria setar nada ao Response Body. Ele pode ler, como parte de um HMVC, mas não setar.

 

É aí que entra a classe View, que vai buscar um template onde você vai montar a resposta com uns foreach's e tal.

 

É um argumento controverso, se Entidade pode ser convertida para um array e esse array serve perfeitamente como uma resposta JSON, porque não setar o Response Body diretamente do resultado de um json_encode()?

 

Quanto ao FileSpec não sei se deveria implementá-lo dentro da View mesmo

Oras, mas claro que é na View. Se é ela quem vai construir o path até o arquivo para você, é ela quem manipulará o FileSpec. :thumbsup:

 

e na base da controller um método render()
~

Você não precisava ter feito isso, bastaria acessar o método público (que deveria ser de interface) View::render() através da propriedade protegida onde reside a instância do objeto View:

 

Quanto ao seu código, não sei como anda sua estrutura mas falando por mim, eu não seto o basepath na renderização e sim logo que instancio o objeto View.

 

E quanto ao FileSpec, você só seta ele se para aquela Action, daquele Controller em particular sua estrutura de diretórios for variar. Se toda sua aplicação mantém o mesmo padrão, você define um FileSpec na declaração da propriedade e não modifica mais.

 

No __destruct() invocava o render() caso não haja sido renderizado manualmente, mas como eu disse que não gostaria de usar o __destruct()

Por quê? Mesmo que você não o use, seu objeto mais cedo ou mais tarde será destruído, óbvio.

 

E esse método te permite fazer algo mais antes que de fato isso aconteça.

 

andei pesquisando um pouco a forma com que alguns Framework's trabalham em relação a parte de renderização e a do Zend me agradou um pouco e percebi algo importante que vi em muitos Framework's, a utilização de Helpers, no Zend as Helpers possuem métodos preDispacth() pré despache e postDispatch() pós despache, que são notificados a todas as Helpers registradas. E para a renderização ele utiliza uma Helper chamada ViewRenderer com postDispatch() onde ele chama a renderização, com outras palavras seria o mesmo que utilizar o __destruct(), mas resolvi implementar o conceito já que seria útil para outros fins.

Não sei como funcionam View Helpers a fundo porque eu pulei essa etapa.

 

Mas eu os vejo como um atalho para você fazer uma tarefa específicaque potencialmente vá se repetir.

 

Por exemplo, num sistema de URL's amigáveis, principalmente aqueles dinâmicos (o/), isto é, aqueles onde toda requisição passa pelo index.php e o FrontController nele instanciado se vira, criar links é uma coisa chata pra caramba.

 

Daí entra em cena um View Helper que define uma interface simples para que através de simples parâmetros faça essa tarefa dispendiosa por você.

 

No seuTemplate View (que conhece os Helpers registrados) você invoca, sei lá, o url, informa o módulo, o controller a action e passa um array de valores (que seriam as variáveis GET) e ele monta o link absoluto inteirinho pra você.

 

Quanto a me basear em coisas assim muitas vezes confesso que faço já que as dificuldades enfrentadas em programação hoje já foram as dificuldades enfrentadas por muitos antes

Parafraseando Aleksandar Mandic, na Internet nada se cria, nada se perde, tudo se copia.

 

Muitas vezes ocorre que no âmbito de fazer alguma coisa sólida para outros desenvolvedores, o criador acaba detalhando demais uma coisa que deveria ser simplificada ao máximo para facilitar o entendimento de como essa coisa funciona.

 

Não exclusivamente, isso é o que ocorre com manuais e RFC's.

 

Cara, ler e entender uma RFC é maçante demais. Eu demorei pra caramba até finalizar uma parte de um código quando me debrucei sobre a Seção 14 da RFC 2616.

 

Só a seção 14, imagina se eu me aprofundasse em todas as outras 20 Seções

 

Hoje eu comecei um YAML Dumper. A especificação do formato até que é ajeirada, mas não é nada trivial. Então eu resolvi dar uma olhadinha no SPYC e no Componente YAML do Symfony.

 

Não vou comentar sobre os Plugins porque não entendi bulhufas. :P

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.