<?php
 
/**
 
 * @package DATA
 
 */
 
 
/**
 
 * ANSI SQL arbitrary size number with decimals data type representation.
 
 * 
 
 * When inboxing, if the field cannot hold the desired value
 
 * {@link DATA_InvalidDecimal} is thrown.
 
 * 
 
 * @todo Arbitrary math implementation.
 
 */
 
class DATA_SQLDecimal extends DATA_SQLType implements DATA_Number {
 
    /**
 
     * How many digits can hold this field.
 
     * @var int
 
     */
 
    protected $precision;
 
    /**
 
     * How many digits after the decimal point this field has.
 
     * @var int
 
     */
 
    protected $scale;
 
    /**
 
     * The stored number.
 
     * @var mixed
 
     */
 
    protected $number;
 
    
 
    /**
 
     * Construct a sql numeric type with requested precision, scale and initial value (optional).
 
     * 
 
     * Throws {@link DATA_InvalidDecimal} when number to be stored is bigger than allowed.
 
     * 
 
     * @param int $precision How many digits can hold this field.
 
     * @param int $scale How many digits after the decimal point this field has.
 
     * @param mixed $number The stored number.
 
     */
 
    public function __construct($nullable, $precision, $scale, $number = '0') {
 
        $this->precision = $precision;
 
        $this->scale = $scale;
 
        $this->setNumber($number);
 
        parent::__construct($nullable, is_null($number));
 
    }
 
    
 
    /**
 
     * Returns the field precision.
 
     * 
 
     * @return int Field precision.
 
     */
 
    public function getPrecision() {
 
        return $this->precision;
 
    }
 
    
 
    /**
 
     * Returns the field scale.
 
     * 
 
     * @return int Field scale.
 
     */
 
    public function getScale() {
 
        return $this->scale;
 
    }
 
    
 
    /**
 
     * Returns the stored number.
 
     * 
 
     * @return mixed The stored number.
 
     */
 
    public function getNumber() {
 
        return $this->number;
 
    }
 
    
 
    /**
 
     * Returns the stored number as an integer.
 
     * 
 
     * @return int The stored number.
 
     */
 
    public function getNumberAsInt() {
 
        return (int)$this->number;
 
    }
 
    
 
    /**
 
     * Returns the stored number as a float.
 
     * 
 
     * @return float The stored number.
 
     */
 
    public function getNumberAsFloat() {
 
        return (float)$this->number;
 
    }
 
    
 
    /**
 
     * Sets the stored number.
 
     * 
 
     * Throws {@link DATA_InvalidDecimal} when number to be stored is bigger than allowed.
 
     * 
 
     * @param mixed $number The stored number.
 
     */
 
    public function setNumber($number) {
 
        if (!$this->checkNumber($number)) {
 
            throw new DATA_InvalidDecimal($this->precision, $this->scale, $number);
 
        }
 
        $this->number = $number;
 
        $this->setNotNull();
 
    }
 
    
 
    public function setNull() {
 
        parent::setNull();
 
        $this->number = null;
 
    }
 
    
 
    public function __toString() {
 
        return number_format($this->number, $this->scale, ".", "");
 
    }
 
    
 
    /**
 
     * Adds this number to another and returns the result.
 
     * 
 
     * Throws {@link DATA_InvalidDecimal}.
 
     * 
 
     * @param DATA_Number $other The number to add.
 
     * @return DATA_SQLNumeric The result.
 
     */
 
    public function add(DATA_Number $other) {
 
        return new DATA_SQLNumeric($this->isNullable(), $this->precision, $this->scale, $this->number + $other->getNumber());
 
    }
 
    
 
    /**
 
     * Substracts this number to another and returns the result.
 
     * 
 
     * Throws {@link DATA_InvalidDecimal}.
 
     * 
 
     * @param DATA_Number $other The number to substract.
 
     * @return DATA_SQLNumeric The result.
 
     */
 
    public function substract(DATA_Number $other) {
 
        return new DATA_SQLNumeric($this->isNullable(), $this->precision, $this->scale, $this->number - $other->getNumber());
 
    }
 
    
 
    /**
 
     * Multiplies this number by another and returns the result.
 
     * 
 
     * Throws {@link DATA_InvalidDecimal}.
 
     * 
 
     * @param DATA_Number $other The number to multiply by.
 
     * @return DATA_SQLNumeric The result.
 
     */
 
    public function multiply(DATA_Number $other) {
 
        return new DATA_SQLNumeric($this->isNullable(), $this->precision, $this->scale, $this->number * $other->getNumber());
 
    }
 
    
 
    /**
 
     * Divides this number by another and returns the result.
 
     * 
 
     * Throws {@link DATA_InvalidDecimal}.
 
     * 
 
     * @param DATA_Number $other The number to divide by.
 
     * @return DATA_SQLNumeric The result.
 
     */
 
    public function divide(DATA_Number $other) {
 
        return new DATA_SQLNumeric($this->isNullable(), $this->precision, $this->scale, (int)($this->number / $other->getNumber()));
 
    }
 
    
 
    /**
 
     * Checks if a number could fit inside this field
 
     * 
 
     * @param mixed $number The number.
 
     * @return bool True if the value fits in this field.
 
     */
 
    protected function checkNumber($number) {
 
        if (is_float($number)) {
 
            $number = number_format($number, $this->scale+1, "", ".");
 
        } else {
 
            $number = (string)$number;
 
        }
 
        $regexp = '[+-]?';
 
        if ($this->precision > $this->scale) {
 
            $regexp .= '[0-9]{1,' . ($this->precision - $this->scale) . '}';
 
        } else {
 
            $regexp .= '0';
 
        }
 
        if ($this->scale > 0) {
 
            $regexp .= '(\\.[0-9]{1,' . $this->scale . '})?';
 
        }
 
        if (preg_match("/^{$regexp}$/", $number)) {
 
            return true;
 
        }
 
        return false;
 
    }
 
}
 
?>
 
 
 |