
Validar em symfony é fácil. Mas as vezes precisa dar uma “personalizada” na validação. Hoje vamos falar sober isso.
Estou trabalhando em um projeto excelente. Meu cliente me deu total liberdade pra programar. Isso é bom, mas traz uma grande responsabilidade também. Resumindo, estou me esforçando ao máximo pra fazer uma ótima programação, Orientada a Objeto, quando vejo que podia ter feito algo melhor, volto, corrijo, etc.
Está sendo assim com a validação de cartão de crédito. Peguei uma excelente classe feita por John Gardner lááá em 2005. Personalizei ela, alterei umas coisas, e estou usando no symfony. Mágica e bilingue! =)
Primeiro, no SomethingForm.class.php eu faço duas coisinhas
Na função configure(), eu insiro
// add a post validator
$this->validatorSchema->setPostValidator(
new sfValidatorCallback(array('callback' => array($this, 'checkCreditCard')))
);
E a função checkCreditCard() abaixo:
public function checkCreditCard($validator, $values)
{
if ($values['numero'])
{
$oCreditCard = new myCreditCardValidator($values);
$sError = $oCreditCard->execute($values['tipo'], $values['numero'], ‘pt_BR’);
if ($sError != 1){
// Create the error object
$sfError = new sfValidatorError($validator, $sError);
// throw an error bound to the number field
throw new sfValidatorErrorSchema($validator, array(’numero’ => $sfError));
}
return $values;
}
}
A classe segue abaixo
<?php
/**
* This class has been converted to a Symfony Validator from original code
* created by John Gardner, 4th January 2005.
* http://www.braemoor.co.uk/software/index.shtml
*
* Symfony conversion by Fellipe Brito, Lado Direito Solucoes, 2009
* http://www.ladodireito.com
*
**/
class myCreditCardValidator
{
static protected $CARDS = array (
array ('name' => 'American Express',
'length' => '15',
'prefixes' => '34,37',
'checkdigit' => true
),
array ('name' => 'Carte Blanche',
'length' => '14',
'prefixes' => '300,301,302,303,304,305,36,38',
'checkdigit' => true
),
array ('name' => 'Diners Club',
'length' => '14',
'prefixes' => '300,301,302,303,304,305,36,38',
'checkdigit' => true
),
array ('name' => 'Discover',
'length' => '16',
'prefixes' => '6011',
'checkdigit' => true
),
array ('name' => 'Enroute',
'length' => '15',
'prefixes' => '2014,2149',
'checkdigit' => true
),
array ('name' => 'JCB',
'length' => '15,16',
'prefixes' => '3,1800,2131',
'checkdigit' => true
),
array ('name' => 'Maestro',
'length' => '16',
'prefixes' => '5020,6',
'checkdigit' => true
),
array ('name' => 'MasterCard',
'length' => '16',
'prefixes' => '51,52,53,54,55',
'checkdigit' => true
),
array ('name' => 'Solo',
'length' => '16,18,19',
'prefixes' => '6334, 6767',
'checkdigit' => true
),
array ('name' => 'Switch',
'length' => '16,18,19',
'prefixes' => '4903,4905,4911,4936,564182,633110,6333,6759',
'checkdigit' => true
),
array ('name' => 'Visa',
'length' => '13,16',
'prefixes' => '4',
'checkdigit' => true
),
array ('name' => 'Visa Electron',
'length' => '16',
'prefixes' => '417500,4917,4913',
'checkdigit' => true
)
);
static protected $ERRORS = array(
"en" => array(
"cc_error_type" => 'Unknown card type',
"cc_error_missing" => 'No card number provided',
"cc_error_format" => 'Credit card number has invalid format',
"cc_error_number" => 'Credit card number is invalid',
"cc_error_length" => 'Credit card number is wrong length'
),
"pt_BR" => array(
"cc_error_type" => 'Tipo de cartão desconhecido',
"cc_error_missing" => 'Nenhum número de cartão informado',
"cc_error_format" => 'Este número tem um formato inválido',
"cc_error_number" => 'Este número é inválido',
"cc_error_length" => 'Este número não tem um tamanho correto'
)
);
public function execute(&$cardName, &$cardNumber, $sCulture)
{
// Establish card type
$cardType = -1;
for ($i=0; $i<sizeof(self::$CARDS); $i++)
{ // See if it is this card (ignoring the case of the string)
if (strtolower($cardName) == strtolower(self::$CARDS[$i]['name']))
{
$cardType = $i;
break;
}
}
// If card type not found, report an error
if ($cardType == -1)
{
$error = self::$ERRORS[$sCulture]['cc_error_type'];
return $error;
}
// Ensure that the user has provided a credit card number
if (strlen($cardNumber) == 0)
{
$error = self::$ERRORS[$sCulture]['cc_error_missing'];
return $error;
}
// Remove any non-digits from the credit card number
$cardNo = preg_replace(’/[^0-9]/’, ”, $cardNumber);
// Check that the number is numeric and of the right sort of length.
if (!eregi(’^[0-9]{13,19}$’,$cardNo))
{
$error = self::$ERRORS[$sCulture]['cc_error_format'];
return $error;
}
// Now check the modulus 10 check digit - if required
if (self::$CARDS[$cardType]['checkdigit'])
{
$checksum = 0; // running checksum total
$mychar = “”; // next char to process
$j = 1; // takes value of 1 or 2
// Process each digit one by one starting at the right
for ($i = strlen($cardNo) - 1; $i >= 0; $i–)
{
// Extract the next digit and multiply by 1 or 2 on alternative digits.
$calc = $cardNo{$i} * $j;
// If the result is in two digits add 1 to the checksum total
if ($calc > 9) {
$checksum = $checksum + 1;
$calc = $calc - 10;
}
// Add the units element to the checksum total
$checksum = $checksum + $calc;
// Switch the value of j
if ($j ==1) {$j = 2;} else {$j = 1;};
}
// All done - if checksum is divisible by 10, it is a valid modulus 10.
// If not, report an error.
if ($checksum % 10 != 0)
{
$error = self::$ERRORS[$sCulture]['cc_error_number'];
return $error;
}
}
// The following are the card-specific checks we undertake.
// Load an array with the valid prefixes for this card
$prefix = split(’,',self::$CARDS[$cardType]['prefixes']);
// Now see if any of them match what we have in the card number
$prefixValid = false;
for ($i=0; $i<sizeof($prefix); $i++)
{
$exp = ‘^’ . $prefix[$i];
if (ereg($exp,$cardNo))
{
$prefixValid = true;
break;
}
}
// If it isn’t a valid prefix there’s no point at looking at the length
if (!$prefixValid)
{
$error = self::$ERRORS[$sCulture]['cc_error_number'];
return $error;
}
// See if the length is valid for this card
$lengthValid = false;
$lengths = split(’,',self::$CARDS[$cardType]['length']);
for ($j=0; $j<sizeof($lengths); $j++)
{
if (strlen($cardNo) == $lengths[$j])
{
$lengthValid = true;
break;
}
}
// See if all is OK by seeing if the length was valid.
if (!$lengthValid)
{
$error = self::$ERRORS[$sCulture]['cc_error_length'];
return $error;
};
// The credit card is in the required format.
return true;
}
}