From 1b6322e675f3482c7c824bd6aedec7a2d4f2f8b2 Mon Sep 17 00:00:00 2001 From: Roman Shvets Date: Mon, 15 Jul 2013 14:16:24 +0300 Subject: [PATCH 1/7] credit cards --- src/Faker/Provider/Payment.php | 150 +++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 src/Faker/Provider/Payment.php diff --git a/src/Faker/Provider/Payment.php b/src/Faker/Provider/Payment.php new file mode 100644 index 00000000..c143cfdf --- /dev/null +++ b/src/Faker/Provider/Payment.php @@ -0,0 +1,150 @@ + 'American Express', + 'number' => '378282246310005' + ), + array( + 'type' => 'American Express', + 'number' => '371449635398431' + ), + array( + 'type' => 'American Express Corporate', + 'number' => '378734493671000' + ), + array( + 'type' => 'Australian BankCard', + 'number' => '5610591081018250' + ), + array( + 'type' => 'Diners Club', + 'number' => '30569309025904' + ), + array( + 'type' => 'Diners Club', + 'number' => '38520000023237' + ), + array( + 'type' => 'Discover', + 'number' => '6011111111111117' + ), + array( + 'type' => 'Discover', + 'number' => '6011000990139424' + ), + array( + 'type' => 'JCB', + 'number' => '3530111333300000' + ), + array( + 'type' => 'JCB', + 'number' => '3566002020360505' + ), + array( + 'type' => 'MasterCard', + 'number' => '5555555555554444' + ), + array( + 'type' => 'MasterCard', + 'number' => '5105105105105100' + ), + array( + 'type' => 'Visa', + 'number' => '4111111111111111' + ), + + array( + 'type' => 'Visa', + 'number' => '4012888888881881' + ), + array( + 'type' => 'Visa', + 'number' => '4222222222222' + ), //Note : Even though this number has a different character count than the other test numbers, it is the correct and functional number. + array( + 'type' => 'Dankort (PBS)', + 'number' => '76009244561' + ), + array( + 'type' => 'Dankort (PBS)', + 'number' => '5019717010103742' + ), + array( + 'type' => 'Switch/Solo (Paymentech)', + 'number' => '6331101999990016' + ) + ); + + + public function creditCard() + { + return static::randomElement(static::$creditCards); + } + + public function creditCardType() + { + $cc = static::creditCard(); + return $cc['type']; + } + + public function creditCardNumber() + { + $cc = static::creditCard(); + return $cc['number']; + } + + /** + * @example '04/13' + */ + public function expirationDate($valid = true) + { + $dt = new \DateTime(); + if($valid) { + $dt->modify("+1 year"); + } else { + $dt->modify("-1 year"); + } + return $dt->format(static::$expirationDateFormat); + } + + /** + * @example 'John Doe' + */ + public function cardHolderName() + { + $format = static::randomElement(static::$formats); + + return $this->generator->parse($format); + } + + /** + * @example 'John' + */ + public static function firstName() + { + return static::randomElement(static::$firstName); + } + + /** + * @example 'Doe' + */ + public static function lastName() + { + return static::randomElement(static::$lastName); + } +} From 5d3ecd58e2d2ee249bcb1cb2e434564cd24debfe Mon Sep 17 00:00:00 2001 From: Roman Shvets Date: Tue, 16 Jul 2013 13:28:12 +0300 Subject: [PATCH 2/7] credit card generator --- src/Faker/Provider/Payment.php | 176 ++++++++-------------------- test/Faker/Provider/PaymentTest.php | 32 +++++ 2 files changed, 81 insertions(+), 127 deletions(-) create mode 100644 test/Faker/Provider/PaymentTest.php diff --git a/src/Faker/Provider/Payment.php b/src/Faker/Provider/Payment.php index c143cfdf..5cfeea60 100644 --- a/src/Faker/Provider/Payment.php +++ b/src/Faker/Provider/Payment.php @@ -2,149 +2,71 @@ namespace Faker\Provider; +use Faker\Provider\Person; + class Payment extends Base { - protected static $formats = array( - '{{firstName}} {{lastName}}', + public static $expirationDateFormat = "m/y"; + + protected static $cardsParams = array( + 'visa' => array( + 'prefix' => array("4539","4556","4916","4532","4929","40240071","4485","4716","4"), + 'length' => array(16, 13), + 'name' => 'Visa' + ), + 'mastercard' => array( + 'prefix' => array("51","52","53","54", "55"), + 'length' => array(16), + 'name' => 'MasterCard' + ), + 'amex' => array( + 'prefix' => array("34", "37"), + 'length' => array(15), + 'name' => 'American Express' + ), + 'discover' => array( + 'prefix' => array("6011"), + 'length' => array(16), + 'name' => 'Discover' + ), ); - protected static $expirationDateFormat = "MM/yy"; - - protected static $firstName = array('John', 'Jane'); - - protected static $lastName = array('Doe'); - - protected static $creditCards = array( - array( - 'type' => 'American Express', - 'number' => '378282246310005' - ), - array( - 'type' => 'American Express', - 'number' => '371449635398431' - ), - array( - 'type' => 'American Express Corporate', - 'number' => '378734493671000' - ), - array( - 'type' => 'Australian BankCard', - 'number' => '5610591081018250' - ), - array( - 'type' => 'Diners Club', - 'number' => '30569309025904' - ), - array( - 'type' => 'Diners Club', - 'number' => '38520000023237' - ), - array( - 'type' => 'Discover', - 'number' => '6011111111111117' - ), - array( - 'type' => 'Discover', - 'number' => '6011000990139424' - ), - array( - 'type' => 'JCB', - 'number' => '3530111333300000' - ), - array( - 'type' => 'JCB', - 'number' => '3566002020360505' - ), - array( - 'type' => 'MasterCard', - 'number' => '5555555555554444' - ), - array( - 'type' => 'MasterCard', - 'number' => '5105105105105100' - ), - array( - 'type' => 'Visa', - 'number' => '4111111111111111' - ), - - array( - 'type' => 'Visa', - 'number' => '4012888888881881' - ), - array( - 'type' => 'Visa', - 'number' => '4222222222222' - ), //Note : Even though this number has a different character count than the other test numbers, it is the correct and functional number. - array( - 'type' => 'Dankort (PBS)', - 'number' => '76009244561' - ), - array( - 'type' => 'Dankort (PBS)', - 'number' => '5019717010103742' - ), - array( - 'type' => 'Switch/Solo (Paymentech)', - 'number' => '6331101999990016' - ) - ); - - - public function creditCard() + public static function randomCard($valid = true) { - return static::randomElement(static::$creditCards); + $params = static::randomElement(static::$cardsParams); + + $CCPrefix = static::randomElement($params['prefix']); + $CCLength = static::randomElement($params['length']); + + $CCNumber = static::randomCardNumber($CCPrefix, $CCLength); + + return array( + 'type' => $params['name'], + 'number' => $CCNumber, + 'name' => strtoupper(Person::firstName() . " " . Person::lastName()), + 'expirationDate' => static::expirationDate($valid) + ); } - public function creditCardType() + public static function randomCardNumber($prefix, $length) { - $cc = static::creditCard(); - return $cc['type']; - } + $cardNumber = $prefix; + while( strlen($cardNumber) < $length ) { + $cardNumber .= static::randomDigit(); + } - public function creditCardNumber() - { - $cc = static::creditCard(); - return $cc['number']; + return $cardNumber; } /** * @example '04/13' */ - public function expirationDate($valid = true) + public static function expirationDate($valid = true) { $dt = new \DateTime(); - if($valid) { - $dt->modify("+1 year"); - } else { - $dt->modify("-1 year"); - } + $sign = ($valid) ? '+' : '-'; + $dt->modify(sprintf($sign . "%s %s", rand(1,36), 'month')); + return $dt->format(static::$expirationDateFormat); } - - /** - * @example 'John Doe' - */ - public function cardHolderName() - { - $format = static::randomElement(static::$formats); - - return $this->generator->parse($format); - } - - /** - * @example 'John' - */ - public static function firstName() - { - return static::randomElement(static::$firstName); - } - - /** - * @example 'Doe' - */ - public static function lastName() - { - return static::randomElement(static::$lastName); - } } diff --git a/test/Faker/Provider/PaymentTest.php b/test/Faker/Provider/PaymentTest.php new file mode 100644 index 00000000..bcd567ba --- /dev/null +++ b/test/Faker/Provider/PaymentTest.php @@ -0,0 +1,32 @@ +assertTrue($dt2 >= $dt); + + $expDate = Payment::expirationDate(false); + $dt2 = \DateTime::createFromFormat(Payment::$expirationDateFormat, $expDate); + $this->assertTrue($dt2 < $dt); + + } + + public function testRandomCard() + { + $card = Payment::randomCard(); + $this->assertEquals(count($card), 4); + $this->assertEquals(array('type','number','name','expirationDate')); + + } + +} \ No newline at end of file From 4b4682ed78cd2724c9727cdb57227053c37a8613 Mon Sep 17 00:00:00 2001 From: Roman Shvets Date: Tue, 16 Jul 2013 13:45:43 +0300 Subject: [PATCH 3/7] typo --- test/Faker/Provider/PaymentTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Faker/Provider/PaymentTest.php b/test/Faker/Provider/PaymentTest.php index bcd567ba..3db16637 100644 --- a/test/Faker/Provider/PaymentTest.php +++ b/test/Faker/Provider/PaymentTest.php @@ -25,7 +25,7 @@ class PaymentTest extends \PHPUnit_Framework_TestCase { $card = Payment::randomCard(); $this->assertEquals(count($card), 4); - $this->assertEquals(array('type','number','name','expirationDate')); + $this->assertEquals(array('type', 'number', 'name', 'expirationDate'), array_keys($card)); } From 52a54bebeb3a906225e64fc11a4e8f9cc7319524 Mon Sep 17 00:00:00 2001 From: Roman Shvets Date: Tue, 16 Jul 2013 13:54:57 +0300 Subject: [PATCH 4/7] use formats --- src/Faker/Provider/Payment.php | 55 +++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/src/Faker/Provider/Payment.php b/src/Faker/Provider/Payment.php index 5cfeea60..246a9dd8 100644 --- a/src/Faker/Provider/Payment.php +++ b/src/Faker/Provider/Payment.php @@ -10,23 +10,46 @@ class Payment extends Base protected static $cardsParams = array( 'visa' => array( - 'prefix' => array("4539","4556","4916","4532","4929","40240071","4485","4716","4"), - 'length' => array(16, 13), + 'mask' => array( + "4539#########", + "4539############", + "4556#########", + "4556############", + "4916#########", + "4916############", + "4532#########", + "4532############", + "4929#########", + "4929############", + "40240071#####", + "40240071########", + "4485#########", + "4485############", + "4716#########", + "4716############", + "4############", + "4###############" + ), 'name' => 'Visa' ), 'mastercard' => array( - 'prefix' => array("51","52","53","54", "55"), - 'length' => array(16), + 'mask' => array( + "51##############", + "52##############", + "53##############", + "54##############", + "55##############" + ), 'name' => 'MasterCard' ), 'amex' => array( - 'prefix' => array("34", "37"), - 'length' => array(15), + 'mask' => array( + "34#############", + "37#############"), 'name' => 'American Express' ), 'discover' => array( - 'prefix' => array("6011"), - 'length' => array(16), + 'mask' => array("6011############"), 'name' => 'Discover' ), ); @@ -34,11 +57,7 @@ class Payment extends Base public static function randomCard($valid = true) { $params = static::randomElement(static::$cardsParams); - - $CCPrefix = static::randomElement($params['prefix']); - $CCLength = static::randomElement($params['length']); - - $CCNumber = static::randomCardNumber($CCPrefix, $CCLength); + $CCNumber = static::randomCardNumber($params['mask']); return array( 'type' => $params['name'], @@ -48,14 +67,14 @@ class Payment extends Base ); } - public static function randomCardNumber($prefix, $length) + public static function randomCardNumber($mask = null) { - $cardNumber = $prefix; - while( strlen($cardNumber) < $length ) { - $cardNumber .= static::randomDigit(); + if(is_null($mask)) { + $cp = static::randomElement(static::$cardsParams); + $mask = $cp['mask']; } - return $cardNumber; + return static::numerify($mask); } /** From b897e614892cbb1d7a7cf9f94d1e72e1a7c717fb Mon Sep 17 00:00:00 2001 From: Francois Zaninotto Date: Mon, 23 Sep 2013 23:03:10 +0200 Subject: [PATCH 5/7] Fix coding standards --- src/Faker/Provider/Payment.php | 2 +- test/Faker/Provider/PaymentTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Faker/Provider/Payment.php b/src/Faker/Provider/Payment.php index 246a9dd8..f78dee0d 100644 --- a/src/Faker/Provider/Payment.php +++ b/src/Faker/Provider/Payment.php @@ -69,7 +69,7 @@ class Payment extends Base public static function randomCardNumber($mask = null) { - if(is_null($mask)) { + if (is_null($mask)) { $cp = static::randomElement(static::$cardsParams); $mask = $cp['mask']; } diff --git a/test/Faker/Provider/PaymentTest.php b/test/Faker/Provider/PaymentTest.php index 3db16637..66e08c94 100644 --- a/test/Faker/Provider/PaymentTest.php +++ b/test/Faker/Provider/PaymentTest.php @@ -29,4 +29,4 @@ class PaymentTest extends \PHPUnit_Framework_TestCase } -} \ No newline at end of file +} From 64ac4a0289a49ca51a95ceb03007eb0632325b5c Mon Sep 17 00:00:00 2001 From: Francois Zaninotto Date: Tue, 24 Sep 2013 00:21:00 +0200 Subject: [PATCH 6/7] Refactor provider and tests to make it more Faker-like --- src/Faker/Provider/Base.php | 16 ++- src/Faker/Provider/Payment.php | 172 +++++++++++++++++----------- test/Faker/Provider/PaymentTest.php | 45 +++++--- 3 files changed, 149 insertions(+), 84 deletions(-) diff --git a/src/Faker/Provider/Base.php b/src/Faker/Provider/Base.php index 654e9a12..acfcba19 100644 --- a/src/Faker/Provider/Base.php +++ b/src/Faker/Provider/Base.php @@ -130,10 +130,24 @@ class Base */ public static function randomElement($array = array('a', 'b', 'c')) { + return $array ? $array[self::randomKey($array)] : null; + } + + /** + * Returns a random key from a passed associative array + * + * @param array $array + * @return mixed + */ + public static function randomKey($array = array()) + { + if (!$array) { + return null; + } $keys = array_keys($array); $key = $keys[mt_rand(0, count($keys) - 1)]; - return $array[$key]; + return $key; } /** diff --git a/src/Faker/Provider/Payment.php b/src/Faker/Provider/Payment.php index f78dee0d..5a017922 100644 --- a/src/Faker/Provider/Payment.php +++ b/src/Faker/Provider/Payment.php @@ -2,90 +2,128 @@ namespace Faker\Provider; -use Faker\Provider\Person; - class Payment extends Base { public static $expirationDateFormat = "m/y"; - protected static $cardsParams = array( - 'visa' => array( - 'mask' => array( - "4539#########", - "4539############", - "4556#########", - "4556############", - "4916#########", - "4916############", - "4532#########", - "4532############", - "4929#########", - "4929############", - "40240071#####", - "40240071########", - "4485#########", - "4485############", - "4716#########", - "4716############", - "4############", - "4###############" - ), - 'name' => 'Visa' + protected static $cardVendors = array( + 'Visa', 'Visa', 'Visa', 'Visa', 'Visa', + 'MasterCard', 'MasterCard', 'MasterCard', 'MasterCard', 'MasterCard', + 'American Express', 'Discover Card' + ); + + // see http://en.wikipedia.org/wiki/Bank_card_number for a reference of existing prefixes + protected static $cardParams = array( + 'Visa' => array( + "4539#########", + "4539############", + "4556#########", + "4556############", + "4916#########", + "4916############", + "4532#########", + "4532############", + "4929#########", + "4929############", + "40240071#####", + "40240071########", + "4485#########", + "4485############", + "4716#########", + "4716############", + "4############", + "4###############" ), - 'mastercard' => array( - 'mask' => array( - "51##############", - "52##############", - "53##############", - "54##############", - "55##############" - ), - 'name' => 'MasterCard' + 'MasterCard' => array( + "51##############", + "52##############", + "53##############", + "54##############", + "55##############" ), - 'amex' => array( - 'mask' => array( - "34#############", - "37#############"), - 'name' => 'American Express' + 'American Express' => array( + "34#############", + "37#############" ), - 'discover' => array( - 'mask' => array("6011############"), - 'name' => 'Discover' + 'Discover Card' => array( + "6011############" ), ); - public static function randomCard($valid = true) + /** + * @return string Returns a credit card vendor name + * + * @example 'MasterCard' + */ + public static function creditCardType() { - $params = static::randomElement(static::$cardsParams); - $CCNumber = static::randomCardNumber($params['mask']); - - return array( - 'type' => $params['name'], - 'number' => $CCNumber, - 'name' => strtoupper(Person::firstName() . " " . Person::lastName()), - 'expirationDate' => static::expirationDate($valid) - ); - } - - public static function randomCardNumber($mask = null) - { - if (is_null($mask)) { - $cp = static::randomElement(static::$cardsParams); - $mask = $cp['mask']; - } - - return static::numerify($mask); + return static::randomElement(static::$cardVendors); } /** + * Returns the String of a credit card number. + * + * @param string $type Supporting any of 'Visa', 'MasterCard', 'Amercian Express', and 'Discover' + * @param boolean $formatted Set to true if the output string should contain one separator every 4 digits + * @param string $separator Separator string for formatting card number. Defaults to dash (-). + * + * @example '4485480221084675' + */ + public static function creditCardNumber($type = null, $formatted = false, $separator = '-') + { + if (is_null($type)) { + $type = static::cardType(); + } + $mask = static::randomElement(static::$cardParams[$type]); + + $number = static::numerify($mask); + + if ($formatted) { + $p1 = substr($number, 0, 4); + $p2 = substr($number, 4, 4); + $p3 = substr($number, 8, 4); + $p4 = substr($number, 12); + $number = $p1 .$separator . $p2 . $separator . $p3 . $separator . $p4; + } + + return $number; + } + + /** + * @param boolean $valid True (by default) to get a valid expiration date, false to get a maybe valid date + * @example 04/13 + */ + public function creditCardExpirationDate($valid = true) + { + if ($valid) { + return $this->generator->dateTimeBetween('now', '36 months'); + } + return $this->generator->dateTimeBetween('-36 months', '36 months'); + } + + /** + * @param boolean $valid True (by default) to get a valid expiration date, false to get a maybe valid date + * @param string $expirationDateFormat * @example '04/13' */ - public static function expirationDate($valid = true) + public function creditCardExpirationDateString($valid = true, $expirationDateFormat = null) { - $dt = new \DateTime(); - $sign = ($valid) ? '+' : '-'; - $dt->modify(sprintf($sign . "%s %s", rand(1,36), 'month')); + return $this->creditCardExpirationDate($valid)->format(is_null($expirationDateFormat) ? static::$expirationDateFormat : $expirationDateFormat); + } - return $dt->format(static::$expirationDateFormat); + /** + * @param boolean $valid True (by default) to get a valid expiration date, false to get a maybe valid date + * @return array() + */ + public function creditCardDetails($valid = true) + { + $type = static::creditCardType(); + + return array( + 'type' => $type, + 'number' => static::creditCardNumber($type), + 'name' => $this->generator->name(), + 'expirationDate' => $this->creditCardExpirationDateString($valid) + ); } } diff --git a/test/Faker/Provider/PaymentTest.php b/test/Faker/Provider/PaymentTest.php index 66e08c94..f075feef 100644 --- a/test/Faker/Provider/PaymentTest.php +++ b/test/Faker/Provider/PaymentTest.php @@ -2,31 +2,44 @@ namespace Faker\Test\Provider; -use Faker\Provider\Payment; - class PaymentTest extends \PHPUnit_Framework_TestCase { - - public function testExpirationDate() + public function setUp() { - $dt = new \DateTime('now'); + $faker = new \Faker\Generator(); + $faker->addProvider(new \Faker\Provider\Base($faker)); + $faker->addProvider(new \Faker\Provider\DateTime($faker)); + $faker->addProvider(new \Faker\Provider\Person($faker)); + $faker->addProvider(new \Faker\Provider\Payment($faker)); + $this->faker = $faker; + } - $expDate = Payment::expirationDate(true); - $dt2 = \DateTime::createFromFormat(Payment::$expirationDateFormat, $expDate); - $this->assertTrue($dt2 >= $dt); + public function testCreditCardTypeReturnsValidVendorName() + { + $this->assertTrue(in_array($this->faker->creditCardType, array('Visa', 'MasterCard', 'American Express', 'Discover Card'))); + } - $expDate = Payment::expirationDate(false); - $dt2 = \DateTime::createFromFormat(Payment::$expirationDateFormat, $expDate); - $this->assertTrue($dt2 < $dt); + public function testCreditCardNumberReturnsValidCreditCardNumber() + { + $this->assertRegExp('/^6011\d{12}$/', $this->faker->creditCardNumber('Discover Card')); + } + public function testCreditCardNumberCanFormatOutput() + { + $this->assertRegExp('/^6011-\d{4}-\d{4}-\d{4}$/', $this->faker->creditCardNumber('Discover Card', true)); + } + + public function testCreditCardExpirationDateReturnsValidDateByDefault() + { + $expirationDate = $this->faker->creditCardExpirationDate; + $this->assertTrue(intval($expirationDate->format('U')) > strtotime('now')); + $this->assertTrue(intval($expirationDate->format('U')) < strtotime('+36 months')); } public function testRandomCard() { - $card = Payment::randomCard(); - $this->assertEquals(count($card), 4); - $this->assertEquals(array('type', 'number', 'name', 'expirationDate'), array_keys($card)); - + $cardDetails = $this->faker->creditCardDetails; + $this->assertEquals(count($cardDetails), 4); + $this->assertEquals(array('type', 'number', 'name', 'expirationDate'), array_keys($cardDetails)); } - } From ac73291f587febc80b1c08e58822b75ff741e465 Mon Sep 17 00:00:00 2001 From: Francois Zaninotto Date: Tue, 24 Sep 2013 00:24:59 +0200 Subject: [PATCH 7/7] Add new providers to readme --- readme.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/readme.md b/readme.md index 40471a9c..d94181a6 100644 --- a/readme.md +++ b/readme.md @@ -195,6 +195,13 @@ Each of the generator properties (like `name`, `address`, and `lorem`) are calle safeColorName // 'fuchsia' colorName // 'Gainsbor' +### `Faker\Provider\Payment` + + creditCardType // 'MasterCard' + creditCardNumber($type = null) // '4485480221084675' + creditCardExpirationDate($valid = true) // DateTime('2014-10-23 13:46:23') + creditCardExpirationDateString($valid = true) // '10/14' + ## Unique and Optional modifiers Faker provides two special providers, `unique()` and `optional()`, to be called before any provider. `optional()` can be useful for seeding non-required fields, like a mobile telephone number ; `unique()` is required to populate fields that cannot accept twice the same value, like primary identifiers.