Jump to content

Archived

This topic is now archived and is closed to further replies.

Henrique Barcelos

HTTP Response e Request

Recommended Posts

Isso sem contar que você deixou a cargo da Request a responsabilidade relativa aos controllers e actions.

 

Seu eu entendi direito, isso é coisa do FrontController que pode, opcionalmente, ter um Dispatcher separado.

 

Em termos gerais, como foi dito no Bee Movie: "São várias pequenas tarefas, mas se cada um fizer com dedicação, dá certo".

 

Claro que eles não disseram essa bobagem, mas é o que meu muito sono me deixa lembrar. :lol:

 

A Index recebe a requisição, passa pro FrontController que, seja na mesma classe, seja em outra, passa ao Roteador as informações da Request, identifica a a Application, instancia o Controller devido e chama a Action.

 

Depois de invocada a Action, o fluxo volta um passo para o Controller que por sua vez, chama informa à View qual Template deve ser mostrado e esta, enfim, chama Response, informa à ela o conteúdo desse Template, para que, depois que ela enviar os cabeçalhos devidos, mostre para o usuário (echo) os dados em tela.

 

Mas cada um no seu quadrado. :thumbsup:

Share this post


Link to post
Share on other sites
Henrique, esse seu método getUserAgent não tem muita responsabilidade não ? se fosse eu, criaria um objeto HttpUserAgent, e nele continha os métodos 'getUserAgent' , 'isMobileDevice' , 'getAgentVersion' , 'getEnvironment' .. coisas do tipo, fica bem mais elegante.

 

Daí você mantém esse método na classe que está, mas vai retornar um objeto responsável pelas informações do User-Agent.

 

Estava com o mesmo pensamento, analisando o código depois :D.

 

Outra coisa, seu método _processFiles .. eu faria assim

<?php

      $FILES = array ( 
             0 => array ( 
                    'file' => 'xxx.jpg' ,
                    'contentType' => 'image/jpeg'
                    // ...
             ) ,
             1 => array ( 
                    'file' => 'xxx.jpg' ,
                    'contentType' => 'image/jpeg'
             ) ,

             // nunca tentei .. mas 
             3 => array ( 
                    1 => array ( 
                        'file' => 'ccc.png' ,
                        'contentType' => 'image/png'
                    ) ,
                    2 => array ( 
                        'file' => 'yyy.png' ,
                        'contentType' => 'image/png'
                    )
             )
      ) ;

      $flag = RecursiveIteratorIterator::CATCH_GET_CHILD ;
      $arrayIterator = new RecursiveArrayIterator ( $FILES ) ;
      $iterator = new RecursiveIteratorIterator ( $arrayIterator ) ;

      echo '<pre>' ;
      for ( $iterator->rewind ( ) ; $iterator->valid ( ) ; $iterator->next ( ) ) 
             $_files [ $iterator->key ( ) ] [ ] = $iterator->current ( ) ;

      print_r ( $_files ) ;

 

Não entendi essa parte.

Existem apenas 2 estruturas possíveis para o array $_FILES:

 

Upload Múltiplo

Array
(
[image] => Array
       (
           [name] => Array
               (
                   [0] => 400.png
                   [1] => 401.png
               )
           [type] => Array
               (
                   [0] => image/png
                   [1] => image/png                 )
           [tmp_name] => Array
               (
                   [0] => /tmp/php5Wx0aJ
                   [1] => /tmp/php5Za038                 )
           [error] => Array
               (
                   [0] => 0
                   [1] => 0                 )
           [size] => Array
               (
                   [0] => 15726
                   [1] => 13421                 )
       )
) 

 

Upload Simples:

Array
(
   [image] => Array
       (
	[name] => 400.png
	[type] => image/png
	[tmp_name] => /tmp/php5Wx0aJ
	[error] => 0
	[size] => 15726
       )
)

 

A ideia é apenas transpor a matriz no caso de uploads múltiplos, para ficar da forma:

Array
(
   [image] => Array
       (
           [0] => Array
               (
                   [name] => 400.png
                   [type] => image/png
                   [tmp_name] => /tmp/php5Wx0aJ
                   [error] => 0
                   [size] => 15726
               )
           [1] => Array
               (
                   [name] => 401.png
                   [type] => image/png
                   [tmp_name] => /tmp/php5Za038
                   [error] => 0
                   [size] => 13421
               )
       )
)

 

O problema dessas classes Iterator é que elas só fazem parte do core do PHP a partir da versão 5.3, antes disso, são extensões, ou seja, podem estar desabilitadas em alguns servidores.

 

Outra coisa .. '://input' , '://output' => InputStreamReader , OutputStreamReader , tanto Reader qnto Writer .. objetos separados ..

Concordo que possa melhorar incluindo essas classes Reader/Writer, mas não vejo necessidade de criar uma classe para Input/Output Stream por enquanto.

Acho difícil que eu vá manipular esses wrappers de maneira complexa. O que eu faria no máximo seria ler, nem escrever no '://output' eu faria assim diretamente.

 

Pergunta:

 do {
    $seg = $segs[$index];
    $baseUrl .= '/' . $seg . $baseUrl;
    $index++;
} while($last > $index && strpos($path, $baseUrl) != 0);

Qual o motivo do uso do 'do-while' ?

 

$baseUrl contém, como o nome diz, a URL base da requisição.

$path armazena a variável de ambiente PHP_SELF.

$segs contém o array reverso dos segmentos da URL. Segmentos são separados por '/'.

 

O que eu faço é ir pré-concatenando os segmentos até que eles não sejam iguais ao início $path ou não haja mais segmentos.

Pra que isso? Para evitar que parâmetros de routing sejam incluidos na URL base da requisição.

 

EU mudaria uma pá de coisas nesse code aí .. aplicaria um strategy para pegar dados enviados em uma requisição ..

Não entendi a ideia do Strategy aí...

 

... isso ainda PELO MENOS evitaria executar um parse para algo que nem temos.

Mas se não existem dados em $_POST, $_GET, $_FILES ou $_COOKIE, eles simplesmente não são adicionados...

 

 

Isso sem contar que você deixou a cargo da Request a responsabilidade relativa aos controllers e actions.

 

Seu eu entendi direito, isso é coisa do FrontController que pode, opcionalmente, ter um Dispatcher separado.

 

Nessa parte, tenho que admitir que confiei no Zend... Achei um tanto estranho também e se não enxergar um uso pra isso quando começar com o Front Controller, irei remover.

Share this post


Link to post
Share on other sites

$baseUrl contém, como o nome diz, a URL base da requisição.

$path armazena a variável de ambiente PHP_SELF.

$segs contém o array reverso dos segmentos da URL. Segmentos são separados por '/'.

 

O que eu faço é ir pré-concatenando os segmentos até que eles não sejam iguais ao início $path ou não haja mais segmentos.

Pra que isso? Para evitar que parâmetros de routing sejam incluidos na URL base da requisição.

 

Não perguntei o que você faz, e sim o motivo de uso, é diferente.

 

Não entendi a ideia do Strategy aí...

Mas se não existem dados em $_POST, $_GET, $_FILES ou $_COOKIE, eles simplesmente não são adicionados...

 

Se não existe, não há porque chamar o método, um strategy se aplicaria em verificar a existência, pra daí sim chamar o método.

Share this post


Link to post
Share on other sites
Não perguntei o que você faz, e sim o motivo de uso, é diferente.

A resposta:

Pra que isso? Para evitar que parâmetros de routing sejam incluidos na URL base da requisição.

 

Se não existe, não há porque chamar o método, um strategy se aplicaria em verificar a existência, pra daí sim chamar o método.

Os métodos apenas percorrem os arrays superglobais colocando os dados no objeto. Se os arrays estão vazios, o loop foreach não é nem executado... Não entendi o "grilo"...

Share this post


Link to post
Share on other sites

@Henrique Barcelos, releia minha pergunta.

 

Os métodos apenas percorrem os arrays superglobais colocando os dados no objeto. Se os arrays estão vazios, o loop foreach não é nem executado... Não entendi o "grilo"...

Exato, mas estou falando de separar estes, por outros objetos, como PostDataRequest ( dados que vem de post ) .. e então, mesma coisa pros outros, além de poder manipular o array com mais liberdade, fica mais refatorado, e podendo ser utilizado separadamente !

Share this post


Link to post
Share on other sites

Ah, sim, desculpe...

Então Andrey, aí eu já estou achando meio exagerado, nunca precisei "manipular o array com mais liberdade". Você teria algum exemplo de quando isso seria necessário?

Share this post


Link to post
Share on other sites

Então Andrey, aí eu já estou achando meio exagerado, nunca precisei "manipular o array com mais liberdade". Você teria algum exemplo de quando isso seria necessário?

 

Não exatamente, mas existem vários, estou falando que se aplica ao seu caso, pense no seguinte, você precisa escrever algo, até mesmo que não passe na request, response ( o que eu duvido ), e então você precise pegar algo do GET, POST, COOKIES .. qualquer desses arrays que você acessa pela sua request ..

 

Portanto, você poderia simplesmente fazer $_POST [ 'índice' ] , mas com o objeto separado, você teria mais liberdade em tratar isso ou até utilizar isso, veja o fragmento

<?php
      $post = new PostRequestData ( ) ;
      echo $post->getParam ( 'name' ) ; // ...


      // .. agora enviando o valor enviado do formulário da sua página 
      // pra um webservice .. ou algo similar .. apenas demonstrando uma utilidade
      $request = $post->createRequest ( 'http://127...' , 80 ) ;
      $request->setParam ( 'name' , $post->getParam ( 'name' ) ) ;
      $response = $request->execute ( )->getResponse ( ) ; 

      var_dump ( $response ) ; 

 

Existem várias outras maneiras, se você ficar sempre se baseando nos exemplos dos outros, vai ficar sempre limitado, daí se nunca alterarem o código, você nunca vai alterar o seu .. e enfim

Share this post


Link to post
Share on other sites

Entendi a sua ideia, mas acredito que não se aplique ao meu caso por enquanto. Como estou desenvolvendo agora no intuito apenas de aprender, vou tentar manter o mais simples possível, desde que funcione.

 

Existem várias outras maneiras, se você ficar sempre se baseando nos exemplos dos outros, vai ficar sempre limitado, daí se nunca alterarem o código, você nunca vai alterar o seu .. e enfim

Realmente eu tenho um certo gap de conhecimento nessa parte, o que me resta, por enquanto é isso... Um dia (e isso sempre acontece), magicamente eu começo a entender e minha imaginação fértil começa a trabalhar, hehe...

 

Mais tarde vou trabalhar na Request, alterar algumas coisas que vocês sugeriram e outras que eu mesmo não gostei muito e se der tempo, brincar um pouco com a Response...

Aí torno a encher o saco aqui... B)

 

Agradeço a atenção de vocês...

[]'s

Share this post


Link to post
Share on other sites

Certo .. mas eu estou falando que é pra você não se limitar ao que já foi desenvolvido por terceiros , faça o seu .. da sua forma .. leia e estude bastante sobre o que está desenvolvendo, e no final .. você vai ter o próprio orgulho de falar 'eu estudei, eu li, eu fiz!' , não estou falando que você viu como o zend faz e tentou imitar .. mas só pelo fato de você se basear nele, causa essa impressão !

Share this post


Link to post
Share on other sites

Eu estou fazendo um apanhado das IDEIAS dos principais frameworks que eu conheço para tentar compreender a ideia global de um framework. Estou tentando fazer um aprendizado em 2 partes, na primeira, sim, estou "copiando" ideias, pois é muito difícil encontrar material de qualidade sobre o assunto, infelizmente.

Na segunda parte, aí não vai ter o dedo de ninguém, só o meu, tanto que quero fazer meu TCC sobre isso, se tiver cópia, ou algo que possa ser considerado como tal, eu não me formo... hehe...

Share this post


Link to post
Share on other sites

Opa, estou de volta.

Fiz algumas modificações na classe Request, dei uma enxugada, alterei o "pacote" da mesma.

 

 

<?php
/**
* Representa uma requisição.
* @author henrique
*/
class Http_Request {
/**
    * Scheme para http
    */
const SCHEME_HTTP  = 'http';

/**
    * Scheme para https
    */
const SCHEME_HTTPS = 'https';

/**
    * Parâmetros de routing parseados a partir da URL.
    * 
    * @var array
    */
private $_params = array(
	'module' => null,
	'controller' => null,
	'action' => null
);

/**
    * Parâmetros POST da requisição.
    * 
    * @var array
    */
private $_post = array();

/**
    * Parâmetros GET da requisição (via query string).
    * 
    * @var array
    */
private $_get = array();

/**
    * Arquivos enviados junto com a requisição.
    * 
    * @var array
    */
private $_files = array();

/**
    * Os cookies enviados junto com a requisição.
    * 
    * @var array
    */
private $_cookies = array();

/**
    * Se a requisição atual já foi despachada ou não.
    * 
    * @var boolean
    */
private $_dispatched = false;

/**
    * A URI da requisição.
    * 
    * @var string
    */
private $_uri;

/**
    * A URL base da aplicação.
    * 
    * @var string
    */
private $_baseUrl;

/**
    * O caminho base da requisição.
    * 
    * @var string
    */
private $_basePath;

/**
    * O corpo da requisição.
    * 
    * @var string
    */
private $_rawBody;

/**
    * O User Agent da requisição
    * @var Http_UserAgent
    */
private $_userAgent;

/**
* Os detectores padrão usados no método is().
* @see Request::addDetector
* @var array
*/
private $_detectors = array(
	'get' => array('env' => 'REQUEST_METHOD', 'value' => 'GET'),
	'post' => array('env' => 'REQUEST_METHOD', 'value' => 'POST'),
	'put' => array('env' => 'REQUEST_METHOD', 'value' => 'PUT'),
	'delete' => array('env' => 'REQUEST_METHOD', 'value' => 'DELETE'),
	'head' => array('env' => 'REQUEST_METHOD', 'value' => 'HEAD'),
	'options' => array('env' => 'REQUEST_METHOD', 'value' => 'OPTIONS'),
	'secure' => array('env' => 'HTTPS', 'value' => 1),
	'ajax' => array('env' => 'HTTP_X_REQUESTED_WITH', 'value' => 'XMLHttpRequest'),
	'flash' => array('env' => 'HTTP_USER_AGENT', 'pattern' => '/^(Shockwave|Adobe) Flash/'),
	'mobile' => array('env' => 'HTTP_USER_AGENT', 'options' => array(
		'Android', 'AvantGo', 'BlackBerry', 'DoCoMo', 'Fennec', 'iPod', 'iPhone', 'iPad',
		'J2ME', 'MIDP', 'NetFront', 'Nokia', 'Opera Mini', 'Opera Mobi', 'PalmOS', 'PalmSource',
		'portalmmm', 'Plucker', 'ReqwirelessWeb', 'SonyEricsson', 'Symbian', 'UP\\.Browser',
		'webOS', 'Windows CE', 'Windows Phone OS', 'Xiino'
	))
);

/**
    * Construtor.
    * 
    * @param string $uri : URI da requisição
    * @param boolean $parseEnvironment : se os dados dos arrays globais _GET, _POST, _FILES devem ser processados
    */
public function __construct($uri = null, $parseEnvironment = true, $envToParse = array('get', 'post', 'files', 'cookies')) {
	$this->setUri($uri);
	$this->_userAgent = new Http_UserAgent();

	if($parseEnvironment) {
		$envToParse = array_map('strtolower', $envToParse);
		if(in_array('get', $envToParse)) {
			$this->_proccessGet();
		}
		if(in_array('post', $envToParse)) {
			$this->_proccessPost();
		}
		if(in_array('files', $envToParse)) {
			$this->_proccessFiles();
		}
		if(in_array('cookies', $envToParse)) {
			$this->_proccessCookies();
		}
	}
}

/**
    * Processa os dados GET da requisição, colocando-os neste objeto.
    * 
    * @return void
    */
private function _proccessGet() {
	foreach($_GET as $key => $value) {
		if(!empty($value)) {
			$this->_get[$key] = $value;
		}
	}
}

/**
    * Processa os dados POST da requisição, colocando-os neste objeto.
    * 
    * @return void
    */
private function _proccessPost() {
	foreach($_POST as $key => $value) {
		if(!empty($value)) {
			$this->_post[$key] = $value;
		}
	}
}

/**
    * Processa os dados de $_FILES, colocando-os neste objeto.
    * Se tivermos um upload múltiplo, os dados serão transpostos, ficando da forma:
    * array (
    * 		0 => array (
    * 			'name' => 'file.txt'
    * 			'tmp_name' => 'afd2213a121.tmp'
    * 			'mime' => 'text/plain'
    * 			'size' => '1024'
    * 			'error' => 0
    * 		),
    * 		1 => array (
    * 			'name' => 'file.jpg'
    * 			'tmp_name' => 'bfc2419a329.tmp'
    * 			'mime' => 'image/jpeg'
    * 			'size' => '104321'
    * 			'error' => 0
    * 		),
    * 		...
    * )
    * 
    * @return void
    */
private function _proccessFiles() {
	if(isset($_FILES)){
		foreach($_FILES as $key => $value) {
			// Transpõe o array $_FILES em caso de upload múltiplo.
			if(is_array(current($value))) {
				foreach($value as $fileKey => $fileVal) {
					for($i = 0; $i < count($fileVal); $i++) {
						$this->_files[$key][$i][$fileKey] = $fileVal[$i];
					}
				}
			} else {
				$this->_files[$key] = $value;
			}
		}
	}
}

/**
    * Processa dos dados de $_COOKIE, colocando-os dentro do objeto.
    * 
    * @return void
    */
private function _proccessCookies() {
	if(isset($_COOKIE)) {
		foreach($_COOKIE as $key => $value) {
			if(!empty($value)) {
				$this->_cookies[$key] = $value;
			}
		}
	}		
}

/**
    * Seta a URI da requisição. Se nenhum parâmetro for informado, 
    * tenta obter esse valor a partir das variáveis do servidor.
    * 
    * @param string|null $reqUri
    * @return Request : fluent interface
    */
public function setUri($reqUri = null) {
	if($reqUri === null) {
		if($envUri = $this->getServer('HTTP_X_REWRITE_URL')) {
			$reqUri = $envUri;
		} elseif($this->getServer('IIS_WasUrlRewritten') == 1 &&
			     $envUri = $this->getServer('ENCODED_URL')) {
			$reqUri = $envUri;
		} elseif($envUri = $this->getServer('REQUEST_URI')) {
			$reqUri = $envUri;
		} 
	} 

	if(!is_string($reqUri)) {
		trigger_error('Impossível determinar a URI da requisição atual!', E_USER_NOTICE);
		return $this;
	}

	$uri = new Uri($reqUri);
	$this->_get = array_merge($this->_get, $uri->query());
	$this->_uri = $uri->path();

	return $this;
}

/**
    * Retorna a URI da requisição.
    * 
    * @return string
    */
public function getUri() {
	if(empty($this->_uri)) {
		$this->setUri();
	}
	return $this->_uri;
}

/**
    * Seta a URL base da aplicação.
    * 
    * @param string|null $baseUrl
    */
public function setBaseUrl($baseUrl = null) {
	if($baseUrl !== null && !is_string($baseUrl)) {
		return $this;
	}

	if($baseUrl == null) {
		$fileName = basename($this->getServer('SCRIPT_FILENAME'));

		$scriptName = $this->getServer('SCRIPT_NAME');
		$phpSelf = $this->getServer('PHP_SELF');
		$origScriptName = $this->getServer('ORIG_SCRIPT_NAME');

		if($scriptName && basename($scriptName) == $fileName) {
			$baseUrl = $scriptName;
		} elseif($phpSelf && basename($phpSelf) == $filename) {
			$baseUrl = $phpSelf;
		} else if($origScriptName && basename($origScriptName) == $filename) {
			$baseUrl = $origScriptName;
		} else {
			$path = $phpSelf;
			$file = $filename;

			$segs = array_reverse(explode('/', rtrim($file, '/')));
			$index = 0;
			$last = count($segs);
			$baseUrl = '';

			do {
				$seg = $segs[$index];
				$baseUrl .= '/' . $seg . $baseUrl;
				$index++;
			} while($last > $index && strpos($path, $baseUrl) != 0);
		}


		$requestUri = $this->getUri();
		if(strpos($requestUri, $baseUrl) === 0) {
			$this->_baseUrl = $baseUrl;
			return $this;
		}

		if(strpos($requestUri, dirname($baseUrl)) === 0) {
			$this->_baseUrl = rtrim(dirname($baseUrl), '/');
			return $this;
		}

		$truncReqUri = reset(explode('?', $requestUri));

		$baseName = baseName($baseUrl);
		if(empty($basename) || !strpos($truncReqUri, $basename)) {
			$this->_baseUrl = '';
			return $this;
		} 

		if(strlen($requestUri) >= strlen($baseUrl) 
	       && ($pos = strpos($requestUri, $baseUrl)) != 0) {
				$baseUrl = substr($requestUri, 0, $pos + strlen($baseUrl));
		}
	}

	$this->_baseUrl = rtrim($baseUrl, '/');
	return $this;
}

/**
    * Retorna a URL base da requisição.
    * 
    * @param boolean $raw : se FALSE, a url deve ser codificada com urlencode
    * @return string
    */
public function getBaseUrl($raw = true) {
	if(empty($this->_baseUrl)) {
		$this->setBaseUrl();
	}
	return $raw === true ? $this->_baseUrl : urlencode($this->_baseUrl);
}

/**
    * Seta o caminho base da requisição.
    * 
    * @param string|null $path
    * @return Request
    */
public function setBasePath($path = null) {
	if($path === null) {
		$baseUrl = $this->getBaseUrl();
		if(empty($baseUrl)) {
			$this->_basePath = '';
			return $this;
		}

		$fileName = basename($this->getServer('SCRIPT_FILENAME'));
		if(basename($baseUrl) == $fileName) {
			$path = dirname($baseUrl);
		} else {
			$path = $baseUrl;
		}
	}

	// Diretórios no Windows podem ser separados por \
	if(stripos(PHP_OS, 'WIN') === 0) {
		$path = str_replace('\\', '/', $path);
	}

	$this->_basePath = rtrim($path, '/');
	return $this;
}

/**
    * Retorna o caminho base da requisição.
    * 
    * @return string
    */
public function getBasePath() {
	if($this->_basePath === null) {
		$this->setBasePath();
	}

	return $this->_basePath;
}

/**
    * Seta um parâmetro de routing na requisição.
    * 
    * @param string $key
    * @param mixed $value
    * @return Request : fluent interface
    */
public function setParam($key, $value) {
	$this->_params[(string) $key] = $value;
	return $this;
}

/**
    * Retorna um parâmetro de routing da requisição.
    * 
    * @param string $key
    * @param mixed $default : o valor padrão de retorno, caso não exista o parâmetro $key
    */
public function getParam($key, $default = null) {
	$key = (string) $key;
	return $this->hasParam($key) ? $this->_params[$key] : $default;
}

/**
    * Verifica se um dado parâmetro de routing existe.
    * 
    * @param string $key
    * @return boolean
    */
public function hasParam($key) {
	$key = (string) $key;
	return isset($this->_params[$key]);
}

/**
    * Remove um parâmetro de routing.
    * 
    * @param string $key
    * @return boolean
    */
public function unsetParam($key) {
	if($this->hasParam($key)) {
		unset($this->_params[$key]);
		return true;
	}
	return false;
}

/**
    * Seta um parâmetro POST na requisição.
    * 
    * @param string $spec : se é uma string, o parâmetro $value é obrigatório
    * 					     se é um array, deve ser associativo nome => valor
    * @param mixed $value
    * @return Request : fluent interface
    */
public function setPost($spec, $value = null) {
	return $this->_setVar('_post', $spec, $value);
}

/**
    * Retorna um parâmetro POST da requisição ou todos eles, se $key for NULL
    * 
    * @param string|null $key
    * @param mixed $default : o valor padrão de retorno, caso não exista o parâmetro $key
    * @return array|mixed|null
    */
public function getPost($key = null, $default = null) {
	return $this->_getVar('_post', $key, $default);
}

/**
    * Seta um parâmetro GET na requisição.
    * 
    * @param mixed $spec: se é uma string, o parâmetro $value é obrigatório
    * 						se é um array, deve ser associativo nome => valor
    * @param string $value
    * @return Request
    */
public function setQuery($spec, $value = null) {
	return $this->_setVar('_query', $spec, $value);
}

/**
    * Retorna um parâmetro POST na requisição.
    * 
    * @param string|null $key
    * @param mixed $default : o valor padrão de retorno, caso não exista o parâmetro $key
    * @return array|mixed|null
    */
public function getQuery($key = null, $default = null) {
	return $this->_getVar('_get', $key, $default);
}

/**
    * Retorna um cookie da requisição.
    * 
    * @param string|null $key
    * @param mixed $default : o valor padrão de retorno, caso não exista o parâmetro $key
    * @return array|mixed|null
    */
public function getCookie($key = null, $default = null) {
	return $this->_getVar('_cookie', $key, $default);
}

/**
    * Retorna uma variável da requisição (_get, _post, _cookie ou _files).
    * 
    * @param string $varName
    * @param string|null $key
    * @param mixed $default
    * @return array|mixed|null
    */
private function _getVar($varName, $key, $default) {
	if($key === null) {
		return $this->{$varName};
	}
	$key = (string) $key;
	return isset($this->{$varName}[$key]) ? $this->{$varName}[$key] : $default;
}

/**
    * Seta uma variável da requisição (_get ou _post)
    * 
    * @param string $varName
    * @param string|array $spec : se é uma string, o parâmetro $value é obrigatório
    * 						       se é um array, deve ser associativo nome => valor
    * @param mixed $value
    * @throws Request_Exception : se $spec não é um array e $value é NULL
    * @return Request : fluent interface
    */
private function _setVar($varName, $spec, $value) {
	if($value === null){
		if(is_array($spec)) {
			foreach($spec as $key => $value) {
				$this->_setVar($vaName, $key, $value);
			}
			return $this;
		} else {
			throw new Request_Exception(sprintf('Argumentos inválidos para o médodo %s;	deve ser um
														array de valores ou um par chave/valor', __FUNCTION__));
		}
	}

	$this->{$varName}[(string) $spec] = $value;
	return $this;
}

/**
    * Retorna o método da requisição.
    * @return string|null
    */
public function getMethod() {
	return $this->getServer('REQUEST_METHOD');
}

/**
    * Faz uso dos detectores para características da requisição.
    * @param string $type
    */
public function is($type) {
	$type = strtolower($type);
	if(!isset($this->_detectors[$type])) {
		return false;
	}

	$detector = $this->_detectors[$type];
	$envVar = $this->getServer($detector['env']);

	if(isset($detector['env'])) {
		if(isset($detector['value'])) {
			return ($envVar == $detector['value']);
		}

		if(isset($detector['pattern'])) {
			return (bool) preg_match($detector['pattern'], $envVar);
		}

		if(isset($detector['options'])) {
			$pattern = '/' . join('|', $detect['options']) . '/i';
			return (bool) preg_match($pattern, $envVar);
		}
	}

	if(isset($detector['callback']) && is_callable($detector['callback'])) {
		return call_user_func($detect['callback'], $this);
	}

	return false;
}

/**
    * Adiciona um detector na lista de detectores que a requisição pode utilizar.
    *
    * Existem 4 formatos diferentes para a criação de detectores:
    * <ul>
    * 	<li>
    * 		addDetector('post', array('env' => 'REQUEST_METHOD', 'value' => 'POST'))
    * 		Comparação com alguma variável do ambiente.
    * 	</li>
    * 	<li>
    * 		addDetector('iphone', array('env' => 'HTTP_USER_AGENT', 'pattern' => '/iPhone/i'))
    * 		Comparação com alguma variável do ambiente através de uma expressão regular.
    * 	</li>
    * 	<li>
    * 		addDetector('mobile', array('env' => 'HTTP_USER_AGENT', 'options' => array('Fennec', 'Opera Mini'))
    * 		Comparação com uma lista de valores, com a qual é gerada uma expressão regular para comparação.
    * 	</li>
    * <li>
    * 		addDetector('custom', array('env' => 'HTTP_USER_AGENT', 'callback' => 'someFunction')
    * 		Utiliza o callback informado para manipular a checagem. O único argumento passado
    * 		para o callback é o objeto Http_Request. O tipo de retorno deve ser booleano.
    * 	</li>
    * </ul>
    *
    *
    * @param string $name
    * @param array $options
    */
public function addDetector($name, $options) {
	$name = strtolower($name);
	$this->_detectors[$name] = $options;
}

/**
    * Realiza a leitura do conteúdo de 'php://input'. 
    * Útil quando interagimos com requisições JSON ou XML.
    * 
    * Conseguindo um input com uma função de decodificação:
    * $request->input('json_decode');
    * 
    * Utilizando um callback com parâmetros:
    * $request->input('someFunction', $arg1, [[$arg2], $arg3, ...]);
    * 
    * @param string $callback
    * @param mixed $arg1 [OPCIONAL]
    * @param mixed $_ [OPCIONAL]
    * @return string
    */
public function getRawBody($callback) {
	$body = $this->_readInput();
	if(is_callable($callback)){
		$argv = func_get_args();
		if(!empty($argv)) {
			$callback = array_shift($argv);
			array_unshift($argv, $body);
			return call_user_func_array($callback, $argv);
		}
	}
	return $body;
}

/**
    * Lê o conteúdo de 'php://input'
    * @return string
    */
private function _readInput() {
	if(empty($this->_rawBody)) {
		try {
			$handler = fopen('php://input', 'r');
			$contents = stream_get_contents($handler);
		} catch(ErrorException $e) {
			$contents = '';
		}
		$this->_rawBody = $contents;
	}
	return $this->_rawBody;
}

/**
    * Retorna um header da requisição.
    * 
    * @param string $header
    * @throws Request_Exception
    * @return string|null
    */
public function getHeader($header) {
	if(empty($header)) {
		throw new Request_Exception('O nome do header HTTP é necessário!');
	}

	$varName = 'HTTP_' . strtoupper(str_replace('-', '_', $header));
	return $this->getServer($varName);
}

/**
    * Retorna o scheme da requisição.
    * 
    * @return string
    */
public function getScheme() {
	return $this->getServer('HTTPS') == 'on' ? self::SCHEME_HTTPS : self::SCHEME_HTTP;
}

/**
    * Retorna uma variável do servidor.
    * 
    * @param string $varName
    * @return string|null
    */
public function getServer($varName) {
	return Environment::getVar($varName);
}

/**
    * Retorna o host da requisição.
    * 
    * @return string
    */
public function getHost() {
	static $host;

	if(empty($host)) {
		$host = $this->getServer('HTTP_HOST');
		if($host !== null) {
			return $host;
		}

		$scheme = $this->getScheme();
		$name   = $this->getServer('SERVER_NAME');
		$port   = $this->getServer('SERVER_PORT');

		if($name === null) {
			$host = '';
		} else if($scheme == self::SCHEME_HTTP && $port = 80 || $scheme == self::SCHEME_HTTPS && $port = 443) {
			$host = $name;
		} else {
			$host = $name . ':' . $port;
		}
	}
	return $host;
}

/**
    * Retorna o IP do cliente.
    * 
    * @param boolean $secure : TRUE se houver suspeita que o cliente pode alterar seu próprio IP
    * @return string|null
    */
public function getClientIp($secure = true) {
	static $clientIp;
	if(empty($clientIp)) {
		$clientIp = $this->getServer('REMOTE_ADDR');
		if($secure){ 
			if(($ip = $this->getServer('HTTP_CLIENT_IP')) !== null) {
				$clientIp = $ip;
			} else if(($ip = $this->getServer('HTTP_X_FORWARDED_FOR')) !== null) {
				$clientIp = $ip;
			}
		} 
	}

	return $clientIp;
}

/**
    * Retorna a URL de referência.
    * 
    * @return string
    */
public function getReferer() {
	static $ref;
	if(empty($ref)) {
		$ref = Environment::getVar('HTTP_REFERER');
		$forwarded = Environment::getVar('HTTP_X_FORWARDED_HOST');
		if($forwarded) {
			$ref = $forwarded;
		}

		if(!$ref) {
			$ref = $this->_baseUrl;
		}
	}

	return $ref;
}

/**
    * Retorna informações sobre o user agent da requisição.
    * @param string|array|null $value : qual informação retornar. Valores possíveis:
    * <ul>
    * 	<li>browser</li>
    * 	<li>version</li>
    * 	<li>plataform</li>
    * 	<li>robot</li>
    *  	<li>raw</li>
    * </ul>
    *
    * Se nenhum valor for informado, serão retornados todos os possíveis.
    *
    * @return string|array
*/
public function getUserAgent($value = null) {
	return $this->_userAgent->getInfo($value);		
}

/**
    * Verifica se a requisição já foi despachada.
    * 
    * @return boolean
    */
public function isDispatched() {
	return $this->_dispatched;
}

/**
    * Seta a flag indicando se a requisição já foi despachada.
    * 
    * @param boolen $opt
    * @return Request : fluent interface
    */
public function setDispatched($opt) {
	$this->_dispatched = (bool) $opt;
	return $this;
}
}

 

 

Tá meio grande, mas acredito que está atendendo o SRP, tirei a responsabilidade sobre o User Agent, refatorando e colocando em um outro objeto.

Retirei as configurações que haviam sobre os parâmetros de routing, elas cabem melhor em um FrontController talvez, mas não coloquemos a carroça na frente dos bois =].

Considerando a documentação e os comentários, são 800 linhas, considerando que a maioria dos métodos são setters e getters, acho que está correto.

 

Não segui a sugestão de criar objetos separados para as streams de entrada e saída porque julgo desnecessárias por enquanto. Preciso dar uma acelerada nessa primeira etapa para no máximo até o meio do ano já ter começado o desenvolvimento sem me guiar pelo que já existe.

Share this post


Link to post
Share on other sites

Eu ainda acho que você não alcançou o SRP.

 

Mas como apesar de estar melhorando consideralvelmente em Design Patterns eu ainda tenho certa dificuldade em identificar os porquês de um objeto ainda ter mais responsabilidade do que deveria ter, eu falo apenas o que eu sinto sobre a Orientação a Objetos.

 

É, sinto, mesmo. Não é maluquice, é tipo um "fenômeno" que acontece comigo só quando estou refatorando códigos. Mesmo que não saiba precisamente os jargões utilizados, eu "sinto" quando uma coisa está errada e/ou pode melhorar.

 

Continuando... Você diz que não quer colocar a carroça na frente dos bois, só que nesse caso, implementar um FrontController não justifica o ditado.

 

O meu FrontController é uma classe pequena e bobinha, mas cumpre o papel dela que é receber a requisição e coordenar o fluxo entre o Router, o Dispatcher e os ActionControllers, instanciados após um roteamento de sucesso ou a Error Response, se falhar.

 

Opinião pessoal. Tudo aquilo referente ao Browser do usuário vai, ou deveria ir, numa classe própria, ficando a Request apenas com, opcionalmente, a tarefa de fazer uma ponte entre quem deseja a informação (Controller) e quem a tem (Browser)

 

Eu tenho uma classe dessas. Tenho diversos métodos que analisam o UserAgent e "descobrem" o Browser em uso e a versão do mesmo.

 

Na mesma classe eu ofereço uma forma de pegar o IP do usuário, mesmo que através de proxies.

 

Na Request tenho um método getBrowser() que retorna uma instância de Browser, fazendo a ponte citada.

Share this post


Link to post
Share on other sites

Você sempre procurando chifre em cabeça de cavalo, Bruno Augusto :grin:... Não é uma crítica, nem um elogio também...

Eu também costumava ser perfeccionista ao extremo, mas acabei percebendo que PRA MIM isso não funciona.

 

E como dizem na engenharia: "faça o mais simples que funcione".

Eu sempre acabava fazendo o complicado que NÃO FUNCIONA, uma obra-prima em codificação, mas um lixo em usabilidade.

 

Contanto que eu não cometa um crime contra as boas práticas de programação, se o negócio funciona, melhor parar de mexer pra não fazer cagada.

Depois, com o tempo, eu volto naquela parte e vou melhorando.

 

Estou trabalhando na Response agora, em breve posto =]

Share this post


Link to post
Share on other sites

A Response:

 

 

<?php
/**
* Representa a resposta de uma requisição.
* @author henrique
*/
class Http_Response {
/**
 * Armazena os headers a serem enviados na resposta.
 *
 * @var array
 */
private $_headers = array();

/**
 * Armazena os headers padrão a serem enviados na resposta.
 *
 * @var array
 */
private static $_defaultHeaders = array();

/**
 * Contém o corpo da resposta.
 *
 * @var array
 */
private $_body = array();

/**
 * O código do status da resposta.
 *
 * @var integer
 */
private $_responseCode = 200;

/**
 * Pilha de exceções.
 *
 * @var array
 */
private $_exceptions = array();

/**
 * Se devemos ou não renderizar exceções.
 *
 * @var boolean
 */
private $_renderExceptions = false;

/**
 * Se devemos ou não lançar uma exceção caso alguma operação sobre
 * headers tente ser executada depois dos mesmos terem sido enviados.
 *
 * @var unknown_type
 */
private $_headersSentThrowsException = true;

/**
 * Construtor.
 *
 * @param integer $code : o código da resposta HTTP.
 */
public function __construct($headers = array(), $body = null, $code = null) {
	$this->_headers = self::$_defaultHeaders;
	$headers  = (array) $headers;

	foreach($headers as $name => $value) {
		if(is_numeric($name)) {
			$this->setHeader($value);
		} else {
			$this->setHeader($name, $value);
		}
	}

	if($body !== null) {
		$this->setBody($body);
	}

	if($code !== null) {
		$this->setHttpResponseCode($code);
	}
}

/**
 * Seta um header para a resposta.
 * Usando apenas 1 parâmetro, o header deve estar na forma:
 * 		Header-Name:header_value
 *
 * @param string $name
 * @param string|null $value
 * @throws Http_Response_Exception
 * @return Http_Response : fluent interface
 */
public function setHeader($name, $value = null) {
	$this->canSendHeaders(true);
	self::_doSetHeader($this->_headers, $name, $value);
	return $this;		
}

/**
 * Seta um header padrão para todos os objetos Http_Response.
 * 
 * @return void
 */
public static function setDefaultHeader() {
	self::_doSetHeader(self::$_defaultHeaders, $name, $value);
}

/**
 * Faz a inserção de um header.
 * 
 * @param reference $var
 * @param string $name
 * @param string $value
 * @throws Http_Response_Exception
 * @return void
 */
private static function _doSetHeader(&$var, $name, $value) {
	if($value === null) {
		$pieces = explode(':', $name);
		if(count($pieces) != 2) {
			throw new Http_Response_Exception(sprintf('Header "%s" inválido', $name));
		}
		$name = trim($pieces[0]);
		$value = trim($pieces[1]);
	}
	$name = self::_normalizeHeader($name);
	$var[$name] = $value;
}

/**
 * Normaliza o nome de um header para o padrão X-Capitalized-Header.
 *
 * @param string $name
 * @return string;
 */
private static function _normalizeHeader($name) {
	$headerName = str_replace(array('-', '_'), ' ', $name);
	$headerName = ucwords(strtolower($headerName));
	$headerName = str_replace(' ', '-', $headerName);
	return $headerName;
}

/**
 * Se $headers é NULL, retorna os headers da resposta.
 * Se $headers é uma string, procura o valor do header dentro do atributo $_headers e o retorna se encontrar.
 * Se $headers é um array, returna um array com os valores encontrados.
 *
 * @param array|string|NULL $headers
 * @return array|string|NULL
 */
public function getHeaders($headers = null) {
	if($headers === null) {
		return $this->_headers;
	}

	if(is_string($headers)) {
		$headers = self::_normalizeHeader($headers);
		return isset($this->_headers[$headers]) ? $this->_headers[$headers] : null;
	} elseif(is_array($headers)) {
		$ret = array();
		foreach($headers as $h) {
			if(($value = $this->getHeaders($h)) !== null) {
				$ret[$h] = $value;
			}
		}
		return $ret;
	}
	return null;
}

/**
 * Limpa os headers da resposta.
 * 
 * @param boolean $keepDefault : se os headers padrão devem ou não ser mantidos. 
 * @return Http_Response : fluent interface
 */
public function clearHeaders($keepDefault = true) {
	if($keepDefault === false){
		$this->_headers = array();
	} else {
		$this->_headers = self::$_defaultHeaders;
	}

	return $this;
}

/**
 * Remove um header da resposta.
 * 
 * @param string $name : o nome do header
 * @return Http_Response : fluent interface
 */
public function clearHeader($name) {
	$name = $this->_normalizeHeader($name);
	if(isset($this->_headers[$name])) {
		unset($this->_headers[$name]);
	}
	return $this;
}

/**
 * Seta uma URL de redirecionamento.
 * Seta o header 'Location' quee redireciona para a URL informada.
 *
 * @param string|Url $url
 * @param integer $code
 * @return Http_Response : fluent interface
 */
public function setRedirect($url, $code = 301) {
	$this->canSendHeaders(true);
	$this->setHeader('Location', $url)
	->setHttpResponseCode($code);

	return $this;
}

/**
 * Verifica se a resposta é de redirecionamento.
 *
 * @return boolean
 */
public function isRedirect() {
	return $this->_responseCode >= 300 && $this->_responseCode <= 307;
}

/**
 * Seta um código de status para a resposta HTTP.
 * 
 * @param integer $code
 * @throws Http_Response_Exception : se o código for inválido
 * @return Http_Response : fluent interface
 */
public function setHttpResposeCode($code) {
	$code = (int) $code;
	if($code < 100 || $code > 599) {
		throw new Http_Response_Exception(sprintf('O código de resposta HTTP %d é inválido', $code));
	}

	$this->_responseCode = $code;
	return $this;
}

/**
 * Retorna o código de status da resposta HTTP.
 * 
 * @return integer
 */
public function getHttpResposeCode() {
	return $this->_responseCode;
}

/**
 * Verifica se ainda é possível enviar headers de resposta,
 * ou seja, se a saída para o navegador ainda não foi iniciada.
 * 
 * @param boolean $throwException : se TRUE, uma exceção é lançada uma exceção 
 * 									caso não seja possível enviar headers
 * @throws Http_Response_Exception : se os headers já foram enviados e $throwExcetion e 
 * 									$this->_headersSentThrowException forem TRUE
 * @return boolean
 */
public function canSendHeaders($throwException = false) {
	$sent = headers_sent($file, $line);
	if($sent && $throw && $this->_headersSentThrowsException) {
		throw new Http_Response_Exception(sprintf('Não é possível enviar headers; Saída iniciada em %s, linha %d', $file, $line));
	}
	return !$sent;
}

/**
 * Envia os headers da resposta.
 * 
 * @return Http_Response : fluent interface
 */
public function sendHeaders() {
	if(empty($this->_headers)) {
		return $this;
	}

	$this->canSendHeaders(true);

	foreach($this->_headers as $header => $value) {
		header($header . ':' . $value);
	} 

	if($this->_responseCode != 200) {
		header('HTTP/1.1 ' . $this->_responseCode);
	}

	return $this;
}

/**
 * Seta o conteúdo do corpo da resposta.
 * 
 * Se $name não é informado, resetamos o corpo da resposta
 * e colocamos $content no segmento 'default'.
 * 
 * Se $name é uma string, adicionamos ao array do corpo o 
 * $content sob a chave $name.
 * 
 * @param string $content
 * @param string|null $name
 * @return Http_Response : fluent interface
 */
public function setBody($content, $name = null) {
	if($name == null) {
		$this->_body = array('default' => (string) $content);
	} else {
		$this->_body[(string) $name] = (string) $content;
	}

	return $this;
}

/**
 * Adiciona $content ao fim do segmento $name.
 * Se $name não é informado, utilizamos o segmento 'default'.
 * 
 * @param string $content
 * @param string|null $name
 * @return Http_Response : fluent interface
 */
public function appendBody($content, $name = null) {
	if($name == null) {
		$name = 'default';
	}

	if(isset($this->_body[$name])) {
		$this->_body[$name] .= $content;
	} else {
		$this->append($name, $content);
	}

	return $this;
}

/**
 * Limpa o corpo da resposta ou apenas um segmento,
 * caso $name seja informado.
 * 
 * @param string|null $name
 * @return boolean : FALSE caso o segmento $name não exista 	 
 */
public function clearBody($name = null) {
	if($name !== null) {
		$name = (string) $name;
		if(isset($this->_body[$name])) {
			unset($this->_body[$name]);
			return true;
		}
		return false;
	}

	unset($this->_body);
	$this->_body = array();
	return true;
}

/**
 * Retorna o conteúdo do corpo da resposta.
 * 
 * Se $spec é FALSE, retorna os valores concatenados do array do corpo da resposta;
 * Se $spec é TRUE, retorna o próprio array do corpo da resposta;
 * Se $spec é o nome de um segmento do corpo, o conteúdo do segmento é adicionado.
 * 
 * @param boolean|string $spec
 * @return string|array|null
 */
public function getBody($spec = false) {
	if($spec === false) {
		ob_start();
		$this->outputBody();
		return ob_get_clean();
	} else if($spec === true) {
		return $this->_body;
	} else if(isset($this->_body[(string) $spec])) {
		return $this->_body[(string) $spec];
	}

	return null;
}

/**
 * Adiciona um segmento nomeado ao fim do array do corpo da resposta.
 * Se o segmento já existe, o seu conteúdo será substituído.
 * 
 * @param string $name
 * @param string $content
 * @throws Http_Response_Exception : caso $name não seja uma string
 * @return Http_Response : fluent interface
 */
public function append($name, $content) {
	if(!is_string($name)) {
		throw new Http_Response_Exception('Chave de segmento de corpo inválida! 
										Esperado string, dado ' . gettype($name));
	}

	// Se o segmento $name já existe, iremos substituir seu conteúdo.
	if(isset($this->_body[$name])) {
		unset($this->_body[$name]);
	}

	$this->_body[$name] = (string) $content;
	return $this;
}

/**
 * Adiciona um segmento nomeado ao início do array do corpo da resposta.
 * Se o segmento já existe, o seu conteúdo será substituído.
 *
 * @param string $name
 * @param string $content
 * @throws Http_Response_Exception : caso $name não seja uma string
 * @return Http_Response : fluent interface
 */
public function prepend($name, $content) {
	if(!is_string($name)) {
		throw new Http_Response_Exception('Chave de segmento de corpo inválida!
												Esperado string, dado ' . gettype($name));
	}

	// Se o segmento $name já existe, iremos substituir seu conteúdo.
	if(isset($this->_body[$name])) {
		unset($this->_body[$name]);
	}

	$new = array($name => (string) $content);
	$this->_body[$name] = $new + $this->_body;
	return $this;
}

/**
 * Insere um segmento nomeado no array de conteúdo do corpo da resposta.
 * 
 * @param string $name : o nome do segmento
 * @param string $content : o conteúdo a ser adicionado
 * @param string $parent [OPTIONAL] : o segmento pai do segmento inserido
 * @param boolean $beforeParent : se o segmento pai for informado, este
 * 		argumento indica se o conteúdo deve ser inserido antes ou depois
 * 		do segmento pai.
 * @throws Http_Response_Exception : se $name não for uma string ou se $parent
 * 		for diferente de NULL e não for uma string
 * @return Http_Response : fluent interface
 */
public function insert($name, $content, $parent = null, $beforeParent = false) {
	if(!is_string($name)) {
		throw new Http_Response_Exception('Chave de segmento de corpo inválida!
															Esperado string, dado ' . gettype($name));
	}

	if($parent !== null && !is_string($parent)) {
		throw new Http_Response_Exception('Chave de segmento pai inválida!
															Esperado string, dado ' . gettype($name));
	}

	if(isset($body[$name])) {
		unset($body[$name]);
	}

	if($parent === null || !isset($this->_body[$parent])) {
		$this->append($name, $content);
	}

	$ins = array($name => (string) $content);
	$keys = array_keys($this->_body);

	$loc = array_search($parent, $keys);
	if($beforeParent === false) {
		$loc++;
	}

	// Se estamos inserindo no começo do array...
	if($loc == 0) {
		$this->_body = $ins + $this->_body;
	} 
	// Se estamos inserindo no final do array... 
	else if($loc >= count($this->_body)) {
		$this->_body += $ins;
	}
	// Caso contrário, precisamos inserir numa posição específica... 
	else {
		$pre = array_slice($this->_body, 0, $loc, true);
		$post = array_slice($this->_body, $loc, null, true);
		$this->_body = $pre + $ins + $post;
	}

	return $this;
}

/**
 * Fornece a saída para o navegador, mostrano o conteúdo do corpo da resposta.
 * 
 * @return void
 */
public function outputBody() {
	$body = implode('', $this->_body);
	echo $body;
}

/**
 * Seta uma exceção na resposta.
 * 
 * @param Exception $e
 * @return Http_Response : fluent interface
 */
public function setException(Exception $e) {
	array_unshift($this->_exceptions, $e);
	return $this;
}

/**
 * Retorna a pilha de exceções.
 * 
 * @return array
 */
public function getException() {
	return $this->_exceptions;
}

/**
 * Verifica se a resposta tem exceções registradas.
 * 
 * @return boolean
 */
public function isException() {
	return !empty($this->_exceptions);
}

/**
 * Verifica se existem exceções do tipo $type na respota.
 * 
 * @param string $type
 * @return boolean
 */
public function hasExceptionOfType($type) {
	foreach($this->_exceptions as $e) {
		if($e instanceof $type) {
			return true;
		}
	}
	return false;
}

/**
 * Verifica se existem exceções com a mensagem $message na resposta.
 * 
 * @param string $message
 * @return boolean
 */
public function hasExceptionOfMessage($message) {
	foreach($this->_exceptions as $e) {
		if($e->getMessage() == $message) {
			return true;
		}
	}
	return false;
}

/**
 * Se devemos ou não renderizar as exceções.
 * 
 * Se nenhum argumento é passado, retorna o valor da flag;
 * Se o argumento for booleano, seta a flag e retorna o valor setado.
 * 
 * @param boolean|null $flag [OPCIONAL]
 * @return boolean
 */
public function renderExceptions($flag = null) {
	if($flag !== null) {
		$this->_renderExceptions = (bool) $flag;
	}

	return $this->_renderExceptions;
}

/**
 * Envia a resposta para o navegador, incluindo os headers e 
 * renderizando as exceções, se requisitado.
 * 
 * @return void
 */
public function send() {
	$this->sendHeaders();

	if($this->isException() && $this->renderExceptions()) {
		$exceptions = '';
		foreach($this->getException() as $e) {
			$exceptions .= $e->__toString() . PHP_EOL;
		}
		echo $exceptions;
		return;
	}

	$this->outputBody();
}

/**
 * Converte o objeto para string
 * @return string
 */
public function __toString() {
	ob_start();
	$this->send();
	return ob_get_clean();
}
}

 

 

 

Sugestões, elogios, críticas, como sempre, muito bem-vindos =]...

Share this post


Link to post
Share on other sites

Tópico morreu? Li quase todas as respostas! :lol:

Achei a idéia muito bacana, mas eu mal mal estou tendo tempo pra continuar um projeto aqui, quanto mais implementar uma Request. O bom disto é que são informações super valiosas, e que se me der na cabeça de fazer a minha, certamente este tópico me ajudará.

 

E como dizem na engenharia: "faça o mais simples que funcione".

Eu sempre acabava fazendo o complicado que NÃO FUNCIONA, uma obra-prima em codificação, mas um lixo em usabilidade.

Esta afirmação praticamente se refere a mim. :closedeyes:

Mas já deixei essa paranóia um pouco de lado, mas é obvio que não fazer aquele LIXO de código, que quando for ver, eu me pergunto: "O que isso faz? Nossa, não acredito que fiz esse pog."

Vejo muita coisa por aí que funciona direitinho, mas quando você vai ver o código, dá vontade de chorar, de TANTA gambiarra que tem. Ao meu ver, o ideal é fazer a coisa funcionar xuxu beleza, e ainda ter um código descente.

Eu mesmo reformulei meu sistema, funciona? Sim, mas o código estava meio gambiarrado. Então eu reencrevi a base, usando metodologia MVC. Aí você pergunta, está bom o acabei de fazer? Não, NUNCA está bom o suficiente, este o nosso problema. Por MAIS que esteja FUNCIONANDO, você SEMPRE acha que pode melhorar, isso é CANSATIVO, mas ao mesmo tempo, é uma evolução constante, pois a cada atualização que faz, explora mais recursos da linguagens e aprende mais sobre OO e Design Patterns.

Share this post


Link to post
Share on other sites

×

Important Information

Ao usar o fórum, você concorda com nossos Terms of Use.