Completed
by Gabriel
02:39
created

### Euro::stringIsTooLong()   A

#### Complexity

 Conditions 1 Paths 1

#### Size

 Total Lines 3

#### Duplication

 Lines 0 Ratio 0 %

#### Code Coverage

 Tests 2 CRAP Score 1

#### Importance

 Changes 0
Metric Value
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
 1 `` 12 ` */` 13 `final class Euro {` 14 15 ` private const DECIMAL_COUNT = 2;` 16 ` private const CENTS_PER_EURO = 100;` 17 18 ` private \$cents;` 19 20 ` /**` 21 ` * @param int \$cents` 22 ` * @throws InvalidArgumentException` 23 ` */` 24 54 ` private function __construct( int \$cents ) {` 25 54 ` if ( \$cents < 0 ) {` 26 5 ` throw new InvalidArgumentException( 'Amount needs to be positive' );` 27 ` }` 28 29 49 ` \$this->cents = \$cents;` 30 49 ` }` 31 32 ` /**` 33 ` * @param int \$cents` 34 ` * @return self` 35 ` * @throws InvalidArgumentException` 36 ` */` 37 30 ` public static function newFromCents( int \$cents ): self {` 38 30 ` return new self( \$cents );` 39 ` }` 40 41 ` /**` 42 ` * Constructs a Euro object from a string representation such as "13.37".` 43 ` *` 44 ` * This method takes into account the errors that can arise from floating` 45 ` * point number usage. Amounts with too many decimals are rounded to the` 46 ` * nearest whole euro cent amount.` 47 ` *` 48 ` * @param string \$euroAmount` 49 ` * @return self` 50 ` * @throws InvalidArgumentException` 51 ` */` 52 19 ` public static function newFromString( string \$euroAmount ): self {` 53 19 ` if ( !is_numeric( \$euroAmount ) ) {` 54 3 ` throw new InvalidArgumentException( 'Not a number' );` 55 ` }` 56 57 16 ` if ( self::stringIsTooLong( \$euroAmount ) ) {` 58 3 ` throw new InvalidArgumentException( 'Number is too big' );` 59 ` }` 60 61 13 ` \$parts = explode( '.', \$euroAmount, 2 );` 62 63 13 ` \$euros = (int)\$parts[0];` 64 13 ` \$cents = self::centsFromString( \$parts[1] ?? '0' );` 65 66 13 ` return new self( \$euros * self::CENTS_PER_EURO + \$cents );` 67 ` }` 68 69 16 ` private static function stringIsTooLong( string \$euroString ): bool {` 70 16 ` return strlen( \$euroString ) + 2 > log10( PHP_INT_MAX );` 71 ` }` 72 73 13 ` private static function centsFromString( string \$cents ): int {` 74 13 ` if ( strlen( \$cents ) > self::DECIMAL_COUNT ) {` 75 2 ` return self::roundCentsToInt( \$cents );` 76 ` }` 77 78 ` // Turn .1 into .10, so it ends up as 10 cents` 79 11 ` return (int)str_pad( \$cents, self::DECIMAL_COUNT, '0' );` 80 ` }` 81 82 2 ` private static function roundCentsToInt( string \$cents ): int {` 83 2 ` \$centsInt = (int)substr( \$cents, 0, self::DECIMAL_COUNT );` 84 85 2 ` if ( (int)\$cents[self::DECIMAL_COUNT] >= 5 ) {` 86 1 ` \$centsInt++;` 87 ` }` 88 89 2 ` return \$centsInt;` 90 ` }` 91 92 ` /**` 93 ` * This method takes into account the errors that can arise from floating` 94 ` * point number usage. Amounts with too many decimals are rounded to the` 95 ` * nearest whole euro cent amount.` 96 ` *` 97 ` * @param float \$euroAmount` 98 ` * @return self` 99 ` * @throws InvalidArgumentException` 100 ` */` 101 9 ` public static function newFromFloat( float \$euroAmount ): self {` 102 9 ` self::assertMaximumValueNotExceeded( \$euroAmount );` 103 6 ` return new self( intval(` 104 6 ` round(` 105 6 ` round( \$euroAmount, self::DECIMAL_COUNT ) * self::CENTS_PER_EURO,` 106 ` 0` 107 ` )` 108 ` ) );` 109 ` }` 110 111 ` /**` 112 ` * @param int|float \$euroAmount` 113 ` */` 114 18 ` private static function assertMaximumValueNotExceeded( \$euroAmount ): void {` 115 ` // When \$euroAmount == PHP_INT_MAX / self::CENTS_PER_EURO, multiplying it` 116 ` // by self::CENTS_PER_EURO still exceeds PHP_INT_MAX, which leads type errors` 117 ` // due to float conversion. The safest thing to do here is using a safety` 118 ` // margin of 1 with self::CENTS_PER_EURO` 119 18 ` if ( \$euroAmount > floor( PHP_INT_MAX / ( self::CENTS_PER_EURO + 1 ) ) ) {` 120 6 ` throw new InvalidArgumentException( 'Number is too big' );` 121 ` }` 122 12 ` }` 123 124 ` /**` 125 ` * @param int \$euroAmount` 126 ` * @return self` 127 ` * @throws InvalidArgumentException` 128 ` */` 129 9 ` public static function newFromInt( int \$euroAmount ): self {` 130 9 ` self::assertMaximumValueNotExceeded( \$euroAmount );` 131 6 ` return new self( \$euroAmount * self::CENTS_PER_EURO );` 132 ` }` 133 134 33 ` public function getEuroCents(): int {` 135 33 ` return \$this->cents;` 136 ` }` 137 138 10 ` public function getEuroFloat(): float {` 139 10 ` return \$this->cents / self::CENTS_PER_EURO;` 140 ` }` 141 142 ` /**` 143 ` * Returns the euro amount as string with two decimals always present in format "42.00".` 144 ` */` 145 6 ` public function getEuroString(): string {` 146 6 ` return number_format( \$this->getEuroFloat(), self::DECIMAL_COUNT, '.', '' );` 147 ` }` 148 149 10 ` public function equals( Euro \$euro ): bool {` 150 10 ` return \$this->cents === \$euro->cents;` 151 ` }` 152 153 `}` 154