<?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;
}
}
?>
|