swashata/php-number-to-word-india

View on GitHub
src/NTWIndia.php

Summary

Maintainability
C
1 day
Test Coverage
<?php
namespace NTWIndia;

/**
 * Number to Words in Indian Version
 *
 * PHP Library
 *
 * @author Swashata Ghosh <swashata@iptms.co>
 * @license GPL-v3.0
 */
class NTWIndia {
    /**
     * Hundred Word
     *
     * @var        string
     */
    public $hundred = 'Hundred';
    /**
     * Thousand Word
     *
     * @var        string
     */
    public $thousand = 'Thousand';
    /**
     * Lakh Word
     *
     * @var        string
     */
    public $lakh = 'Lakh';
    /**
     * Crore Word
     *
     * @var        string
     */
    public $crore = 'Crore';
    /**
     * And word
     *
     * @var string
     */
    public $and = 'And';
    /**
     * Number to Words
     *
     * These are the presets we will need
     *
     * Rest will be calculated automatically
     *
     * @var        array
     */
    public $numToWord = array(
        '0'  => 'Zero',
        '1'  => 'One',
        '2'  => 'Two',
        '3'  => 'Three',
        '4'  => 'Four',
        '5'  => 'Five',
        '6'  => 'Six',
        '7'  => 'Seven',
        '8'  => 'Eight',
        '9'  => 'Nine',
        '10' => 'Ten',
        '11' => 'Eleven',
        '12' => 'Twelve',
        '13' => 'Thirteen',
        '14' => 'Fourteen',
        '15' => 'Fifteen',
        '16' => 'Sixteen',
        '17' => 'Seventeen',
        '18' => 'Eighteen',
        '19' => 'Nineteen',
        '20' => 'Twenty',
        '30' => 'Thirty',
        '40' => 'Forty',
        '50' => 'Fifty',
        '60' => 'Sixty',
        '70' => 'Seventy',
        '80' => 'Eighty',
        '90' => 'Ninety',
    );

    /**
     * Crore Divisor
     *
     * @var        integer
     * @access     private
     */
    private $croreDivisor = 10000000;
    /**
     * Lakh Divisor
     *
     * @var        integer
     * @access     private
     */
    private $lakhDivisor = 100000;
    /**
     * Thousand Divisor
     *
     * @var        integer
     * @access     private
     */
    private $thousandDivisor = 1000;
    /**
     * Hundred Divisor
     *
     * @var        integer
     * @access     private
     */
    private $hundredDivisor = 100;
    /**
     * A flag to properly append AND to the last hundred word
     *
     * @var        boolean
     * @access     private
     */
    private $firstCall = false;

    /**
     * Converts a number into words value following indian number system with
     * lakh and crore
     *
     * The number supplied has to be greater than 0. Negative numbers aren't
     * supported.
     *
     * @param      integer|float                     $number  The number to
     *                                                        convert
     *
     * @throws     Exception\NTWIndiaInvalidNumber   When passed variable is not numeric
     * @throws     Exception\NTWIndiaNumberOverflow  When passed number is greater than system maximum
     *
     * @return     string                            The covnerted value
     */
    public function numToWord( $number ) {
        /**
         * Check if a valid number is passed
         *
         * If not then log a warning
         */
        if ( ! is_numeric( $number ) ) {
            throw new Exception\NTWIndiaInvalidNumber( 'Valid number not given.' );
        }

        // Check if number is exceeding the system maximum
        if ( $number > PHP_INT_MAX ) {
            throw new Exception\NTWIndiaNumberOverflow( 'Number is greater than system maximum.' );
        }

        // Convert to the absolute value
        $number = abs( $number );

        // Check if zero
        if ( 0 == $number ) {
            return $this->numToWord['0'];
        }

        // Change flag
        $this->firstCall = true;

        // Special consideration for floats
        if ( is_float( $number ) ) {
            $dot = explode( '.', $number );
            // If there is some integer after the dot and not just zero
            // then we consider adding XXX/1000 to it
            if ( isset( $dot[1] ) && $dot[1] > 0 ) {
                // We dont need the and here
                $this->firstCall = false;
                return $this->convertNumber( $dot[0] ) . ' ' . $this->and . ' ' . intval( $dot[1] ) . '/1' . str_repeat( '0', strlen( $dot[1] ) );
            } else {
                return $this->convertNumber( $dot[0] );
            }
        }

        return $this->convertNumber( $number );
    }

    /**
     * Converts the number into word by breaking into quotients and remainders
     *
     * All the calculations happen here and it shouldn't be called directly
     *
     * @access     private
     *
     * @param      integer  $number  The number
     *
     * @return     string   Converted word value of the number
     */
    private function convertNumber( $number ) {
        // Init the return
        $word = array();
        // Lets start with crore
        $crore_quotient = floor( $number / $this->croreDivisor );
        $crore_remainder = $number % $this->croreDivisor;

        // If more than crore
        if ( $crore_quotient > 0 ) {
            // Modify the flag
            $firstCall = $this->firstCall;
            $this->firstCall = false;
            $word['crore'] = $this->convertNumber( $crore_quotient );
            // Swap the flag
            $this->firstCall = $firstCall;
            unset( $firstCall );
        }

        // Calculate Lakh
        $lakh_quotient = floor( $crore_remainder / $this->lakhDivisor );
        $lakh_remainder = $crore_remainder % $this->lakhDivisor;

        // If more than lakh
        if ( $lakh_quotient > 0 ) {
            $word['lakh'] = $this->numToWordSmall( $lakh_quotient );
        }

        // Calculate thousand
        $thousand_quotient = floor( $lakh_remainder / $this->thousandDivisor );
        $thousand_remainder = $lakh_remainder % $this->thousandDivisor;

        // If more than thousand
        if ( $thousand_quotient > 0 ) {
            $word['thousand'] = $this->numToWordSmall( $thousand_quotient );
        }

        // Calculate hundred
        $hundred_quotient = floor( $thousand_remainder / $this->hundredDivisor );
        $hundred_remainder = $thousand_remainder % $this->hundredDivisor;

        // If more than hundred
        if ( $hundred_quotient > 0 ) {
            $word['hundred'] = $this->numToWordSmall( $hundred_quotient );
        }

        // If less than hundred but more than zero
        if ( $hundred_remainder > 0 ) {
            $word['zero'] = $this->numToWordSmall( $hundred_remainder );
        }

        // Now finalize the return
        $return = '';
        foreach ( $word as $pos => $val ) {
            if ( 'zero' == $pos ) {
                if ( true == $this->firstCall && $number > 99 ) {
                    $return .= ' ' . $this->and;
                }
                $return .= ' ' . $val;
            } else {
                $return .= ' ' . $val . ' ' . $this->{$pos};
            }
        }
        return trim( $return );
    }

    /**
     * Converts a small number to its word value
     *
     * The number has to be less than 100 otherwise it will call convertNumber
     * method
     *
     * It can be called when you know the number is less than 100 to reduce
     * memory and calculation
     *
     * @param      int                               $number  The number
     *
     * @throws     Exception\NTWIndiaInvalidNumber   When a valid number is not given
     * @throws     Exception\NTWIndiaNumberOverflow  When number is greater than 99
     *
     * @return     string                            Word value of the number
     */
    public function numToWordSmall( $number ) {
        // Check if number is numeric
        if ( ! is_numeric( $number ) ) {
            throw new Exception\NTWIndiaInvalidNumber( 'Valid number not given.' );
        }
        $number = floor( abs( $number ) );

        // Check if number is greater than 99
        // If so, then just throw an exception
        if ( $number > 99 ) {
            throw new Exception\NTWIndiaNumberOverflow( 'Number is greater than 99. Use numToWord method.' );
        }

        // Calculate the last character beforehand
        $lastCharacter = substr( "$number", -1 );

        // Check if direct mapping is possible
        if ( isset( $this->numToWord[ "$number" ] ) ) {
            return $this->numToWord[ "$number" ];
        } elseif ( $number < 30 ) {
            return $this->numToWord['20'] . ' ' . $this->numToWord[ $lastCharacter ];
        } elseif ( $number < 40 ) {
            return $this->numToWord['30'] . ' ' . $this->numToWord[ $lastCharacter ];
        } elseif ( $number < 50 ) {
            return $this->numToWord['40'] . ' ' . $this->numToWord[ $lastCharacter ];
        } elseif ( $number < 60 ) {
            return $this->numToWord['50'] . ' ' . $this->numToWord[ $lastCharacter ];
        } elseif ( $number < 70 ) {
            return $this->numToWord['60'] . ' ' . $this->numToWord[ $lastCharacter ];
        } elseif ( $number < 80 ) {
            return $this->numToWord['70'] . ' ' . $this->numToWord[ $lastCharacter ];
        } elseif ( $number < 90 ) {
            return $this->numToWord['80'] . ' ' . $this->numToWord[ $lastCharacter ];
        } elseif ( $number < 100 ) {
            return $this->numToWord['90'] . ' ' . $this->numToWord[ $lastCharacter ];
        }
    }
}