Usamos cookies para medir audiência e melhorar sua experiência. Você pode aceitar ou recusar a qualquer momento. Veja sobre o iMasters.
olá...
como fazer para validar as entradas do usuário, considerando varias classes?!
por exemplo a classe cliente e a classe endereco...
a classe cliente valida se o nome foi preenchido e se o CPF é valido...
a classe endereco valida se foi informado o CEP...
como juntar as mensagens de validacao das duas classses, para apresentar de uma unica vez para o usuário?!
>
16 minutos atrás, Gabriel Heming disse:
Como você está fazendo a validação?
com um outro exemplo...
só para exemplificar mesmo...
class impostos
{
public $totalicms;
public $totalipi;
public function calclularImpostos($paricms1 = 0, $paricms2 = 0, $paripi1 = 0, $paripi2 = 0)
{
$icms = new icms;
$this->totalicms = $icms->calcularIcms($paricms1, $paricms2);
$ipi = new ipi;
$this->totalipi = $ipi->calcularIpi($paripi1, $paripi2);
}
}
class icms
{
public function calcularIcms($p1, $p2)
{
if ($p1 == 10)
{
throw new Exception('erro icms');
}
return $p1 + $p2;
}
}
class ipi
{
public function calcularIpi($p1, $p2)
{
if ($p1 == 10)
{
throw new Exception('erro ipi');
}
return $p1 + $p2;
}
}
ao invés de colocar exception, eu gostaria de colocar tipo um array, que fosse agrupando as msgs de erro de cada classe para a classe principal (impostos) mostrar os erros...
não sei se é correto ou não...
na verdade nem sei como fazer mesmo...
estava pensando em passar para cada funcao o array de erros... mas ai fica bem estranho...
valeu!Validações são exceções. Isso está claro e correto. O que você deve se tratar é se o processo deve ou não ser interrompido.
Partindo do seu exemplo, sem alterações nas classes, o que você pode fazer é o seguinte:
public function calclularImpostos($paricms1 = 0, $paricms2 = 0, $paripi1 = 0, $paripi2 = 0)
{
$errors = [];
try
{
$icms = new icms;
$this->totalicms = $icms->calcularIcms($paricms1, $paricms2);
}
catch (Exception $exception)
{
$errors[] = $exception->getMessage();
}
try
{
$ipi = new ipi;
$this->totalipi = $ipi->calcularIpi($paripi1, $paripi2);
}
catch (Exception $exception)
{
$errors[] = $exception->getMessage();
}
// Nota: array vazio é interpretado como false
if ((boolean)$errors)
{
throw new RuntimeException(implode("\n" , $errors));
}
}
Agora, se isso for muito recorrente. Existem outras tratativas, como adicionar uma dependência no objeto que executará terá a validação. Esse objeto será o responsável por validar e loggar o erro.
Mas se o seu problema é restrito ao código acima, quanto mais simples melhor.valeu pela resposta...
>
11 minutos atrás, Gabriel Heming disse:
Existem outras tratativas, como adicionar uma dependência no objeto
como seria isso?!
não fica muito ruim ficar tratando tudo com try catch?!
terei lugares com (acho) uns 30 try catch!!!
e também não é objetivo interrompido o processo...
Não tenho costume em tratar erros da forma que você quer, nem de implementar tais tratamento, mas o que eu consegui pensar até o momento foi o seguinte, sem implicar em muitas alterações no que você já possui e manterá uma certa retrocompatibilidade.
Segue a interface.
Spoiler
/applications/core/interface/imageproxy/imageproxy.php?img=https://i.imgur.com/qlT1vOH.png&key=b6f798ebe0e53264dd472226cf478342d6b0b118bc97778ed22557ad14522dda" width="572" />
Basicamente, você terá o participante ErrorProvider, que abrigará as mensagens de erro que forem lançadas e o participante ValidationSubject, que utilizará (injeção de dependência) o ErrorProvider e inserirá nle as mensagens de erro sempre que ocorrerem.
Além disso, ErrorProvider extenderá a interface IteratorAggregate para que você possa iterar sobre as mensagens de erro.
Vamos as Interfaces:
ErrorProvider
interface ErrorProvider extends IteratorAggregate
{
public function add(string $error) : ErrorProvider;
public function clear() : void;
public function hasErrors() : bool;
}
**ValidationSubject**
interface ValidationSubject
{
public function setErrorProvider(ErrorProvider $errorProvider) : void;
}
Agora a implementação de ErrorProvider
**ConcreteErrorProvider**
class ConcreteErrorProvider implements ErrorProvider
{
private $errorList = [];
public function add(string $errorMessage) : ErrorProvider
{
$this->errorList[] = $errorMessage;
return $this;
}
public function clear() : void
{
$this->errorList = [];
}
public function hasErrors() : bool
{
return (boolean)$this->errorList;
}
public function __toString() : string
{
return implode("\n" , $this->errorList);
}
public function getIterator() : \Iterator
{
return new ArrayIterator($this->errorList);
}
}
**Nota**: criatividade zero em nomes... =P
Como você já possui as classes prontas, para ter o mínimo possível de alterações, seria interessante utilizar herança, para que a classe na qual conterá as validações apenas herde os métodos necessários sem ter que implementar o mesmo método em todas as classes.
Neste caso, eu preferi utilizar uma trait para simular a herança múltipla.
trait ValidationSubjectTrait
{
private $errorProvider;
public function setErrorProvider(ErrorProvider $errorProvider) : void
{
$this->errorProvider = $errorProvider;
}
protected function setErrorMessage(string $errorMessage) : void
{
//Caso não haja um ErrorProvider, será lançada uma exception como de costume
if (!$this->errorProvider instanceof ErrorProvider)
{
throw new \RuntimeException($errorMessage);
}
$this->errorProvider->add($errorMessage);
}
}
**Nota:** trait não é herança múltipla, apenas simula e deve ser em conjunto de uma interface (no caso, ValidationSubject).
Já nos objetos que desejas implementar o ErrorProvider, basta apenas implementar a interface e usar a trait. E, ao invés de lançar uma Exception, use o método setErrorMessage que está implementado na trait ValidationSubjectTrait.
class Person implements ValidationSubject
{
use ValidationSubjectTrait;
/** método apenas para testes **/
public function setName($name) : void
{
$this->setErrorMessage("O nome não foi informado");
}
/** método apenas para testes **/
public function setLastName($lastName) : void
{
$this->setErrorMessage("O sobrenome não foi informado");
}
}
Quando for utilizar o objeto, pode ser assim:
try
{
$person = new Person();
$person->setName('Gabriel');
$person->setLastName('Heming');
} echo $exception->getMessage();
}
Resultado:
>
Citar
O nome não foi informado
Ou assim:
$errorProvider = new ConcreteErrorProvider();
$person = new Person();
$person->setErrorProvider($errorProvider);
$person->setName('Gabriel');
$person->setLastName('Heming');
if ($errorProvider->hasErrors())
{
echo $errorProvider;
}
Resultado:
>
Citar
O nome não foi informado
O sobrenome não foi informado
Algumas considerações
Apesar de "parecer" uma solução elegante, eu não chequei a fundo se está ferindo alguma questão de designer (mas tenho a impressão que está e não estou satisfeito com isso). Tanto que, ao meu ver, o fluxo natural de exceptions é o mais indicado.
De qualquer forma, fica a implementação que pode ser útil e aberta para melhorias/críticas.
Todos os códigos foram implementados para o PHP >= 7.1. Caso utilize alguma outra versão, as alterações são simples.
Código em funcionamento: https://3v4l.org/aDUGW
obrigado...
vou estou seu codigo agora mesmo!
>
4 minutos atrás, Gabriel Heming disse:
Não tenho costume em tratar erros da forma que você quer,
como você trata erros?!
Normalmente da forma que você está tratando. Apenas no .NET existe o ErrorProvider (similar ao que foi implementado) que é específico para Forms.
vixi...
valeu pela ajudar...
realmente nao consigo entender...
DESISTO!
programar nao é para mim não!!!
já estava pensando em mudar de área mesmo...
O que foi que você não entendeu? Conseguiu implementar o código passado?
@panetony, se o que você quer é ter todas as mensagens de erros, em uma lista, de uma forma bem simples, poderia fazer assim:
class ErrorLog
{
public static $errors;
}
class XptoNumber
{
public function execute($xpto)
{
if (is_string($xpto)) {
ErrorLog::$errors[] = 'xpto não pode ser uma string';
}
/**
* etc...
*/
}
}
class XptoString
{
public function execute($xpto)
{
if (is_numeric($xpto)) {
ErrorLog::$errors[] = 'xpto não pode ser um numero';
}
/**
* etc...
*/
}
}
$xptoNumber = new XptoNumber;
$xptoNumber->execute('abc');
$xptoString = new XptoString;
$xptoString->execute(123);
print_r(ErrorLog::$errors);
Array (
[0] => xpto não pode ser uma string
[1] => xpto não pode ser um numero
)
Se entendi o seu problema, uma simples classe, com uma propriedade estática resolveria. E, obviamente, essa sugestão da classe ErrorLog que dei, é bem simplista, e você pode adicionar métodos conforme achar melhor.
Como você está fazendo a validação?