Ir para conteúdo

Arquivado

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

Bruno Augusto

Response...

Recommended Posts

Continuando os aprimoramentos do sistema, através da implementação da Request e da Response, após ler a respeito, compreendi que a renderização de um arquivo de template é responsabilidade da View mas isto deve passar pela Response, sendo esta a responsável por, de fato, ecoar o HTML.

 

Pois bem, como antes não tinha uma Request tão elaborada e não tinha uma Response, todo procedimento de exibição, isto é, desde a captura do buffer, detecção do arquivo de template correto, encerramento do buffer até exibição do HTML (echo), era tudo feito na View::render(), método abaixo disposto:

 

public function render( $name = NULL, $search = TRUE ) {

   if( ! $this -> _shouldRender || self::$_isRendered || ob_get_length() != 0 ) ) {

       return;
   }

   if( $search == FALSE && empty( $name ) ) {
       throw new ViewException( 'You have to enter the filepath of Template View File or activate the auto-search.' );
   }

   ob_start();

   include ( $search ? $this -> findFile( $name ) : $name );

   $data = ob_get_clean();

   // Clening Up HTML's extra NewLines

   if( $this -> _cleanupHTML ) {

       $data = preg_replace( sprintf( '/%s/', self::CLEANUP_REGEXP ), "\n\n", $data );
   }

   // Telling our Flag that Template is already rendered (or being rendered)

   self::$_isRendered = TRUE;

   echo $data;
}

Para não me aprofundar muito, View::findFile() apenas encontra o arquivo, anaisando o File Spec previamente definido e que não vem ao caso.

 

O preg_replace(), frescura minha, limpa as possíveis linhas em branco duplicadas no código.

 

Mas como fazer para integrar com a Response?

 

Para topdos os efeitos, minha Response virtualmente não existe. É apenas uma classe Singleton onde, no construtor, tenho um ob_start().

Compartilhar este post


Link para o post
Compartilhar em outros sites

É, sua camada View está um tanto mais avançada que a minha... Eu basicamente uso includes. Apenas faço com que o Controller decida qual página exibir e retorná-la...

O que existe nessa sua classe Response exatamente?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Como eu disse... "nada".

 

Como ela não existia antes, por hora, é apenas uma classe Singleton tendo, no construtor um ob_start().

 

Não prossegui nela, ontem pelo menos, pois não consigo enxergar uma forma de integrar.

 

Pelo menos não sem "gambiarra" como, por exemplo, informar à algum método da Response aquilo que a View::render() detectar.

Compartilhar este post


Link para o post
Compartilhar em outros sites
Mas como fazer para integrar com a Response?

Explica um pouco melhor o que você espera dessa "integração"...

Compartilhar este post


Link para o post
Compartilhar em outros sites

Na verdade eu estou apenas especulando.

 

Não tenho quase nenhuma noção do que, de fato, é uma classe de Response.

 

O pouco que sei é que é ela quem,de fato, deve devolveralguma resposta (duh) para o usuário,ao invés da View Engine, como atualmente faço.

 

Sei também, graças à ajuda do JCMais, que a Response lê e envia cabeçalhos HTTP.

 

E como cabeçalhos não devem ser enviados depois de conteúdo, sei que ela manipula o buffer de saída.

 

Mas, como eu disse, atualmente minha View Engine analisa um File Spec e monta, através dele, automaticamente, o caminho completo até um arquivo de template (se eu for preguiçoso) ou utiliza um template que eu decidir (render manual).

 

Daí eu não sei como fazer essa renderização, que ocorre na View, passar a ser na Response como deveria. Ainda não faz sentido essa parte.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Hmmm... acho que to començando a entender... Me manda esse material que você leu, deixa eu dar uma olhada também... quem sabe chegamos a alguma conclusão :lol:

Compartilhar este post


Link para o post
Compartilhar em outros sites

Assim, não tem um material propriamente dito.

 

São apenas fragmentos de informações espalhadas por aí a fora :(

Compartilhar este post


Link para o post
Compartilhar em outros sites

Eu até tentei dar uma pesquisada, mas não achei nada muito útil...

Quais os termos que você usou na pesquisa???

Compartilhar este post


Link para o post
Compartilhar em outros sites

A escassez de material, ou a dificuldade de combinar keywords, é tanta que infelizmente não consigo de ajudar nisso e, consequentemente, não onsigo me ajudar.

 

Mas em parte, foi mais por dedução.

 

Pensei assim: Se Response manipula uma resposta a ser entregue ao usuário e a View Engine seleciona um HTML para ser mostrado, logo a View deveria informar a Response "o quê" seria informado.

 

A View não precisa saber como a Response trabalha e a Response idem com a View, mas se elas não conversarem de alguma forma (que eu não sei como), nenhuma das duas faz o seu devido trabalho.

 

"O quê mais" a Response faz, e com isso me refiro aos cabeçalhos, foram os conhecimentos obtidos ao longo deste tópico

 

Encontrei também algo com relação aos Cookies e ao Content-Type.

 

Vi também que,ainda na manipulação de cabeçalhos, é a Response quem envia os HTTP Codes (200, 403, 500...), coisa que não cabe à alçada da View. Tal informação veio da própria RFC 2616 (Section 6)

 

Fora isso, vi algumas implementações um tanto quanto estranhas, as quais, por exemplo, possuiam métodos para manipular o próprio HTML a ser enviado, como criar META tags ou adicionar Stylesheets, o que me pareceu burrice.

 

Outras mais possuiam rotinas para codificar/decodificar GZIP DEFLATE.

 

No mais, não tenho mais dados para trabalhar e no meio de tanta informação difusa, acabo por não focar quais são, exatamente, as reais responsabilidades de uma Response, o que dificulta ainda mais a "integração".

Compartilhar este post


Link para o post
Compartilhar em outros sites

Bom eu trabalho com ZF, e tenho mais experiência com ela, então vou fazer um pseudocode baseado no código da mesma.

 

Quem deve setar o conteúdo da Response com aquilo que tua View renderizou, não é nem a View e nem tua Response, mas a classe responsável por controlar o fluxo de tua aplicação. Para saber qual é essa classe na tua aplicação, basta ver qual é a responsável por instanciar o Controller, e executar a Action no mesmo.

 

interface View {

   /* renderiza o template, e retorna o conteúdo do mesmo como string */
   public function render($template);
}

interface Response {
   /* adiciona o conteúdo de $body ao fim do $body existente */
   public function appendBody($body);
}

interface Dispatch {
  public function dispatch(Request $request, Response $response);
}

 

O metódo dispatch da classe Dispatch executa o metódo do controller responsável por renderizar a View do Request atual, então o conteúdo renderizado é jogado na Response através do metódo appendBody.

 

algo como:

$controller = $request->getControllerName();
$action     = $request->getActioName();

//instancia o controller

$controller->dispatch($action);
$content = ob_get_clean();
$response->appendBody($content);

 

Espero que tenha dado para entender, tá meio confuso. :lol:

 

Sobre a parte de criar stylesheets, e tals, geralmente para isto são utilizados filtros que manipulam o conteúdo renderizado na View. E não a View em si.

Compartilhar este post


Link para o post
Compartilhar em outros sites

É complicado mesmo achar alguma coisa sobre isso... tentei algumas (várias) combinações de keywords sem sucesso...

No meu sistema atual, acontece +/- assim:

A requisição chega ao FrontController, que possui um método dispatch.

Esse método chama o controller responsável por aquela requisição. Normalmente a URL é dessa maneira:

http://exemplo.com/controller/action

 

Dentro do método "action", é feita a requisição ao model pelos dados e eles são retornados sob a forma de um registro (um array associativo com envoltório).

Nesse método eu informo qual a View que precisará ser incluída.

Com esse conteúdo em mãos, na seção correta do HTML eu incluo a página que o Controller me informou.

 

Problemas:

Não consegui definir um padrão para esse registro de dados que vem do modelo.

Não utilizo ob_*, o que acaba dificultando certas coisas... É o próxima coisa que pretendo modificar...

 

@JCMais, uma coisa que não ficou clara pra mim é sobre a response: ela já traz o HTML gerado? (Ao que parece sim, pois você adiciona ela ao body do HTML).

Se sim, que tipo de classes implementariam essa interface?

Um DataGrid, um List, por exemplo, seria o caso?

 

É incrível que quanto mais eu aprendo, menos eu vejo que eu sei :P

Compartilhar este post


Link para o post
Compartilhar em outros sites

@JCMais, uma coisa que não ficou clara pra mim é sobre a response: ela já traz o HTML gerado? (Ao que parece sim, pois você adiciona ela ao body do HTML).

Se sim, que tipo de classes implementariam essa interface?

Um DataGrid, um List, por exemplo, seria o caso?

 

Hum, parece que você confundiu um pouco, o body ali é referente ao body da resposta HTTP que o server retorna, e não à tag body.

 

Request (section 5) and Response (section 6) messages use the generic message format of RFC 822 [9] for transferring entities (the payload of the message). Both types of message consist of a start-line, zero or more header fields (also known as "headers"), an empty line (i.e., a line with nothing preceding the CRLF) indicating the end of the header fields, and possibly a message-body.

http://tools.ietf.org/html/rfc2616#section-4.1

 

No momento que é chamado o metódo render da View, ele apenas faz um include do arquivo de script/template, pega o conteúdo inserido e envia para o buffer de saída, mais tarde apenas pegamos esse mesmo conteúdo (Que é o html gerado) com a função ob_get_clean e adicionamos ao corpo da resposta.

 

A classe de response não deve ter conhecimento sobre a estrutura HTML, como gerá-la ou como requisitá-la. Ele deve apenas ter uma interface para adicionar headers, remover headers, modificar o corpo da resposta HTTP, adicionar mais conteúdo à resposta, etc, e o mais importante, enviar a resposta ao cliente.

E sobre as classes que implementariam, para esse problema, só vejo uma:

Response\Http

Compartilhar este post


Link para o post
Compartilhar em outros sites

Hmmmm... Então que une os recursos é, indiretamente, o Dispatcher. Interesante!

 

Por isso que eu estudava o ZF e não via sentido em o Dispatcher receber como argumentos a Request e a Response.

 

Acredito que tenha dado uma clareada nas coisas mas só poderei experimentar em casa, à noite.

 

Talvez não tenha ficado claro pra mim pois como atualmente meu output está na View::render() eu tenho, no meu Dispatcher um return sobre o Controller instanciado.

 

Mas vamos melhorando aos poucos.

Compartilhar este post


Link para o post
Compartilhar em outros sites
Hum, parece que você confundiu um pouco, o body ali é referente ao body da resposta HTTP que o server retorna, e não à tag body.

Duh! ashuashsuh...

Estou mais perdido mesmo nessa parte mesmo, me concentrei mais nas camadas Model e Contoller, deixando a View um pouco de lado

 

A classe de response não deve ter conhecimento sobre a estrutura HTML, como gerá-la ou como requisitá-la. Ele deve apenas ter uma interface para adicionar headers, remover headers, modificar o corpo da resposta HTTP, adicionar mais conteúdo à resposta, etc, e o mais importante, enviar a resposta ao cliente.

É, faz mais sentido assim...

 

De qualquer forma, $content abaixo contém o HTML gerado...

$content = ob_get_clean();
$response->appendBody($content);

 

Só uma coisa:

e o mais importante, enviar a resposta ao cliente.

Como isso é feito na pática?

Envia os headers e depois dá um echo no corpo da requisição adicionado no método appendBody?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Acho que essa eu sei, Henrique.

 

Pelo que eu vi, existe um método que inicia a captura do buffer, logo em seguida envia todos os cabeçalhos de resposta necessários e, então retorna o buffer OU envia-o e o encerra.

 

mas não é no appendBody() não, aí acho que você se confundiu, afinal esse método enfiaria mais coisa no corpo (uia!), ao invés de trabalhar com tudo o que se tem.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Não, não... hehe, não foi isso que eu disse...

Faltou uma vírgula:

Envia os headers e depois dá um echo no corpo da requisição, (que foi) adicionado no método appendBody?

 

Pelo que eu entendi, na classe Response tem algum método "flush" ou algo do tipo que 'empurra' o conteúdo do buffer (corpo da resposta) para a saída do navegador...

appendBody apenas adiciona conteúdo ao corpo da resposta...

Compartilhar este post


Link para o post
Compartilhar em outros sites

Hmmmmm...

 

Apenas... deu certo <_<

 

Mas ficou estranho para caramba. Partindo do View::render() que havia postado o mais próximo que consegui de uma integração foi dar o include no arquivo e via Response::appendBody() associar o conteúdo do buffer, com ob_get_contents().

 

No Response::sendResponse() por sua vez ecoei todo o buffer armazenado na propriedade através do método citado.

 

Pelo menos a View não renderiza mais o Template. Ela o inclui, mas não envia. Mas sei lá, fedeu a gambiarra. :P

Compartilhar este post


Link para o post
Compartilhar em outros sites

Como isso é feito na pática?

Envia os headers e depois dá um echo no corpo da requisição adicionado no método appendBody?

 

Exatamente.

Algo como:

namespace Response;
class Http extends Response {
   private $headers = array();
   private $body    = array();    

   public function sendHeaders()
   {
       foreach($this->headers as $name => $headerInfo)
           //usa função header() para definir os headers, verifica se o header já foi definido, faz outra lógica com o header atual, etc...
       return $this;
   }

   public function sendBody()
   {
       $body = implode('', $this->body);
       echo $body;
   }

   public function sendResponse()
   {
       try {
           $this->sendHeaders()->sendBody();
       } catch(Response\Exception $e) {
           //...
       }
   }

   //demais metódos...
}

 

Pelo menos a View não renderiza mais o Template. Ela o inclui, mas não envia. Mas sei lá, fedeu a gambiarra. :P

 

Depende da sua definição de renderizar.

 

Ela continua renderizando o arquivo, no momento que você inclui o mesmo, você dá acesso ao escopo atual do objeto da View, e então as variaveis no template que você incluiu são usadas, mas isso você já deve saber. :P

Compartilhar este post


Link para o post
Compartilhar em outros sites

Eu tenho como "renderizar", nas vias de fato, "mostrar" algo para o usuário.

 

Pode até ser uma má interpretação da minha parte, mas na falta de termo melhor...

 

Li, li, li mais um pouco, virei o ZF de ponta cabeça por assim dizer e vi que, do jeitinho cabuloso dele, também é feito dessa forma, isto é, setando ao Response Body o valor do buffer atual, depois do include do arquivo de template.

 

Mas me deparei com uma situação estranha. Depois de implementado, meu response::send() ficou assim:

 

public function send() {

   // Cleaning current Output Buffer

   if( ob_get_length() ) {

       ob_end_clean();
   }

   // Sending Headers

   // @TODO

   // Clening Up HTML's extra NewLines

   echo preg_replace( self::CLEANUP, "\n\n", $this -> body );

   // Outputs the Buffer

   ob_end_flush();
}

Funcionava lindamente. Mas, minhas exceções, que são mostradas num template próprio, com View própria (instância, não classe à parte) começaram a se duplicar, sendo exibidas duas vezes.

 

Fiquei horas virando meu código, testando várias possibilidades e acabei movendo um ob_start() na View::render() algumas linhas para baixo. Sumiu a duplicata, mas eu recebi um erro de falha na deleção do buffer.

 

troquei a última linha da Response::send() para:

 

if( ob_get_length() ) { ob_end_flush(); }

e ficou perfeito. Mas não entendi o motivo.

 

Sei que estou no caminho certo do funcionamento da coisa, mas esse fato me fez segurar a empolgação antes de ir pra galera. :grin:

 

Algum comentário sobre isso?

 

[EDIT]

 

Quem bateu o martelo dizendo que o tópico está Resolvido?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Provavelmente deve ter ocorrido algum tipo de "redirect", digamos assim, para o template da view, e o buffer não foi limpo durante esse "redirect".

 

Sobre o edit: Não fui eu.

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.