Skip to content
Snippets Groups Projects
class.orm.php 107 KiB
Newer Older
  • Learn to ignore specific revisions
  • Jared Hancock's avatar
    Jared Hancock committed
    
            $types = '';
            $ps = array();
    
            foreach ($params as $i=>&$p) {
    
                if (is_int($p) || is_bool($p))
    
    Jared Hancock's avatar
    Jared Hancock committed
                    $types .= 'i';
    
                elseif (is_float($p))
                    $types .= 'd';
    
    Jared Hancock's avatar
    Jared Hancock committed
                elseif (is_string($p))
                    $types .= 's';
    
                elseif ($p instanceof DateTime) {
                    $types .= 's';
    
                    $p = $p->format('Y-m-d H:i:s');
    
                elseif (is_object($p)) {
                    $types .= 's';
                    $p = (string) $p;
                }
    
                // TODO: Emit error if param is null
    
    Jared Hancock's avatar
    Jared Hancock committed
                $ps[] = &$p;
            }
    
    Jared Hancock's avatar
    Jared Hancock committed
            array_unshift($ps, $types);
            call_user_func_array(array($this->stmt,'bind_param'), $ps);
        }
    
        function _setup_output() {
    
            if (!($meta = $this->stmt->result_metadata()))
                throw new OrmException('Unable to fetch statment metadata: ', $this->stmt->error);
    
            $this->fields = $meta->fetch_fields();
    
            $meta->free_result();
    
    Jared Hancock's avatar
    Jared Hancock committed
        }
    
        // Iterator interface
        function rewind() {
            if (!isset($this->stmt))
                $this->_prepare();
            $this->stmt->data_seek(0);
        }
    
        function next() {
            $status = $this->stmt->fetch();
            if ($status === false)
    
                throw new OrmException($this->stmt->error);
    
    Jared Hancock's avatar
    Jared Hancock committed
            elseif ($status === null) {
                $this->close();
                return false;
            }
            return true;
        }
    
        function getArray() {
            $output = array();
            $variables = array();
    
            if (!isset($this->stmt))
                $this->_prepare();
    
            foreach ($this->fields as $f)
                $variables[] = &$output[$f->name]; // pass by reference
    
    
            if (!call_user_func_array(array($this->stmt, 'bind_result'), $variables))
                throw new OrmException('Unable to bind result: ' . $this->stmt->error);
    
    
    Jared Hancock's avatar
    Jared Hancock committed
            if (!$this->next())
                return false;
            return $output;
        }
    
    
        function getRow() {
            $output = array();
            $variables = array();
    
            if (!isset($this->stmt))
                $this->_prepare();
    
            foreach ($this->fields as $f)
                $variables[] = &$output[]; // pass by reference
    
    
            if (!call_user_func_array(array($this->stmt, 'bind_result'), $variables))
                throw new OrmException('Unable to bind result: ' . $this->stmt->error);
    
    
            if (!$this->next())
                return false;
            return $output;
        }
    
    
    Jared Hancock's avatar
    Jared Hancock committed
        function close() {
            if (!$this->stmt)
                return;
    
            $this->stmt->close();
            $this->stmt = null;
        }
    
    
        function affected_rows() {
            return $this->stmt->affected_rows;
        }
    
        function insert_id() {
            return $this->stmt->insert_id;
        }
    
    
    Jared Hancock's avatar
    Jared Hancock committed
        function __toString() {
    
            $self = $this;
    
            return preg_replace_callback("/:(\d+)(?=([^']*'[^']*')*[^']*$)/",
            function($m) use ($self) {
    
                $p = $self->params[$m[1]-1];
    
                switch (true) {
                case is_bool($p):
                    $p = (int) $p;
                case is_int($p):
                case is_float($p):
                    return $p;
                case $p instanceof DateTime:
    
                    $p = $p->format('Y-m-d H:i:s');
    
    Peter Rotich's avatar
    Peter Rotich committed
                    return db_real_escape((string) $p, true);
               }
    
            }, $this->sql);
    
    /**
     * Simplified executor which uses the mysqli_query() function to process
     * queries. This method is faster on MySQL as it doesn't require the PREPARE
     * overhead, nor require two trips to the database per query. All parameters
     * are escaped and placed directly into the SQL statement. With this style,
     * it is possible that multiple parameters could compile a statement which
     * exceeds the MySQL max_allowed_packet setting.
     */
    class MySqlExecutor
    extends MySqlPreparedExecutor {
        function execute() {
            $sql = $this->__toString();
            if (!($this->stmt = db_query($sql, true, !$this->unbuffered)))
                throw new InconsistentModelException(
                    'Unable to prepare query: '.db_error().' '.$sql);
            // mysqli_query() return TRUE for UPDATE queries and friends
            if ($this->stmt !== true)
                $this->_setupCast();
            return true;
        }
    
        function _setupCast() {
            $fields = $this->stmt->fetch_fields();
            $this->types = array();
            foreach ($fields as $F) {
                $this->types[] = $F->type;
            }
        }
    
        function _cast($record) {
            $i=0;
            foreach ($record as &$f) {
                switch ($this->types[$i++]) {
                case MYSQLI_TYPE_DECIMAL:
                case MYSQLI_TYPE_NEWDECIMAL:
                case MYSQLI_TYPE_LONGLONG:
                case MYSQLI_TYPE_FLOAT:
                case MYSQLI_TYPE_DOUBLE:
                    $f = isset($f) ? (double) $f : $f;
                    break;
    
                case MYSQLI_TYPE_BIT:
                case MYSQLI_TYPE_TINY:
                case MYSQLI_TYPE_SHORT:
                case MYSQLI_TYPE_LONG:
                case MYSQLI_TYPE_INT24:
                    $f = isset($f) ? (int) $f : $f;
                    break;
    
                default:
                    // No change (leave as string)
                }
            }
            unset($f);
            return $record;
        }
    
        function getArray() {
            if (!isset($this->stmt))
                $this->execute();
    
            if (null === ($record = $this->stmt->fetch_assoc()))
                return false;
            return $this->_cast($record);
        }
    
        function getRow() {
            if (!isset($this->stmt))
                $this->execute();
    
            if (null === ($record = $this->stmt->fetch_row()))
                return false;
            return $this->_cast($record);
        }
    
        function affected_rows() {
            return db_affected_rows();
        }
    
        function insert_id() {
            return db_insert_id();
        }
    }
    
    
    class Q implements Serializable {
    
        const NEGATED = 0x0001;
        const ANY =     0x0002;
    
        var $constraints;
        var $negated = false;
        var $ored = false;
    
    
        function __construct($filter=array(), $flags=0) {
    
            if (!is_array($filter))
                $filter = array($filter);
    
            $this->constraints = $filter;
            $this->negated = $flags & self::NEGATED;
            $this->ored = $flags & self::ANY;
        }
    
        function isNegated() {
            return $this->negated;
        }
    
        function isOred() {
            return $this->ored;
        }
    
        function negate() {
            $this->negated = !$this->negated;
            return $this;
        }
    
    
        function union() {
            $this->ored = true;
        }
    
        function add($constraints) {
            if (is_array($constraints))
                $this->constraints = array_merge($this->constraints, $constraints);
            elseif ($constraints instanceof static)
                $this->constraints[] = $constraints;
            else
                throw new InvalidArgumentException('Expected an instance of Q or an array thereof');
            return $this;
        }
    
    
        static function not($constraints) {
    
            return new static($constraints, self::NEGATED);
        }
    
    
        static function any($constraints) {
    
            return new static($constraints, self::ANY);
    
        static function all($constraints) {
            return new static($constraints);
        }
    
    
        function serialize() {
    
            return serialize(array($this->negated, $this->ored, $this->constraints));
    
        }
    
        function unserialize($data) {
    
            list($this->negated, $this->ored, $this->constraints) = unserialize($data);