Вход Регистрация
Файл: sys/library/goDB/DB.php
Строк: 634
<?php
/**
 * goDB2: the library for working with relational databases (for PHP)
 *
 * @package goDB
 * @license https://raw.github.com/vasa-c/go-db/master/LICENSE MIT
 * @link https://github.com/vasa-c/go-db source
 * @link https://github.com/vasa-c/go-db/wiki documentation
 * @uses PHP >= 5.3
 * @uses specific dependencies for a specific adapters
 */

namespace goDB;

use 
goDBHelpersFetchersCursor as CursorFetcher;
use 
goDBHelpersConnector;
use 
goDBHelpersTemplater;
use 
goDBHelpersConfig;
use 
goDBExceptionsUnknownAdapter;
use 
goDBExceptionsQuery;
use 
goDBExceptionsClosed;
use 
goDBExceptionsConfigSys;
use 
goDBHelpersDebuggersOutConsole as DebuggerOutConsole;
use 
goDBHelpersDebuggersOutHtml as DebuggerOutHtml;

/**
 * The basic class of database adapters
 *
 * @author Oleg Grigoriev <go.vasac@gmail.com>
 */
abstract class DB
{
    
/**
     * Creates an instance for database access
     *
     * @param array $params
     *        database connection parameters
     * @param string $adapter [optional]
     *        a name of a db-adapter (if it not specified in $params)
     * @return goDBDB
     *         the instance for database access
     * @throws goDBExceptionsConfig
     *         parameters is invalid
     * @throws goDBExceptionsConnect
     *         a connection error
     */
    
final public static function create(array $params$adapter null)
    {
        
$adapter = isset($params['_adapter']) ? $params['_adapter'] : $adapter;
        
$adapter strtolower($adapter);
        
$classname __NAMESPACE__.'\Adapters\'.ucfirst($adapter);
        if (!class_exists($classname, true)) {
            throw new UnknownAdapter($adapter);
        }
        $params['
_adapter'] = $adapter;
        return (new $classname($params));
    }

    /**
     * Returns the list of available adapters
     *
     * @return array
     */
    final public static function getAvailableAdapters()
    {
        if (!self::$availableAdapters) {
            $adapters = array();
            foreach (glob(__DIR__.'
/Adapters/*.php') as $filename) {
                if (preg_match('~([a-z0-9]*).php$~si', $filename, $matches)) {
                    $adapters[] = strtolower($matches[1]);
                }
            }
            self::$availableAdapters = $adapters;
        }
        return self::$availableAdapters;
    }

    /**
     * Performs a query on the database
     *
     * @param string $pattern
     *        the query pattern
     * @param array $data [optional]
     *        the incoming data for the query pattern
     * @param string $fetch [optional]
     *        the result format
     * @param string $prefix [optional]
     *        a table prefix for the current query
     * @return goDBResult
     *         the query result in specified format
     * @throws goDBExceptionsConnect
     *         an error of lazy connection
     * @throws goDBExceptionsClosed
     *         the connection is closed
     * @throws goDBExceptionsTemplater
     *         an error of the templating system ($pattern or $data is invalid)
     * @throws goDBExceptionsQuery
     *         an error of the query
     * @throws goDBExceptionsFetch
     *         the result format is invalid for this query type
     */
    
final public function query($pattern$data null$fetch null$prefix null)
    {
        
$query $this->makeQuery($pattern$data$prefix);
        return 
$this->plainQuery($query$fetch);
    }

    
/**
     * Saves a pre-query
     *
     * @param string $pattern
     * @param array $data [optional]
     * @throws goDBExceptionsException
     */
    
final public function preQuery($pattern$data null)
    {
        
$this->preQueries[] = array($pattern$data);
        if (
$this->connected) {
            
$this->execPre();
        }
    }

    
/**
     * Performs a "plain" query
     *
     * @param string $query
     *        a plain query
     * @param string $fetch [optional]
     *        the result format
     * @return goDBResult
     *         the query result in specified format
     * @throws goDBExceptionsConnect
     *         an error of lazy connection
     * @throws goDBExceptionsClosed
     *         the connection is closed
     * @throws goDBExceptionsQuery
     *         an error of the query
     * @throws goDBExceptionsFetch
     *         the result format is invalid for this query type
     */
    
final public function plainQuery($query$fetch null)
    {
        
$this->forcedConnect();
        
$implementation $this->connector->getImplementation();
        
$connection $this->connector->getConnection();
        
$duration microtime(true);
        
$cursor $implementation->query($connection$query);
        
$duration microtime(true) - $duration;
        
$this->query_number++;
        
$this->tpassed += $duration// TODO: ???
        
if (!$cursor) {
            
$errorInfo $implementation->getErrorInfo($connection);
            
$errorCode $implementation->getErrorCode($connection);
            throw new 
Query($query$errorInfo$errorCode);
        }
        
$this->debugLog($query$durationnull);
        
$fetcher $this->createFetcher($cursor);
        if (
$fetch === null) {
            return 
$fetcher;
        }
        return 
$fetcher->fetch($fetch);
    }

    
/**
     * @alias for query()
     *
     * The next examples are identical:
     * @example $db->query('SELECT * FROM `table`');
     * @example $db('SELECT * FROM `table`');
     *
     * @param string $pattern
     * @param array $data [optional]
     * @param string $fetch [optional]
     * @param string $prefix [optional]
     * @return goDBResult
     * @throws goDBExceptionsConnect
     * @throws goDBExceptionsClosed
     * @throws goDBExceptionsTemplater
     * @throws goDBExceptionsQuery
     * @throws goDBExceptionsFetch
     */
    
final public function __invoke($pattern$data null$fetch null$prefix null)
    {
        return 
$this->query($pattern$data$fetch$prefix);
    }

    
/**
     * Checks if connection is actually established
     *
     * @return bool
     */
    
final public function isConnected()
    {
        if (
$this->hardClosed) {
            return 
false;
        }
        return 
$this->connector->isConnected();
    }

    
/**
     * Chick if connection is closed (hard)
     *
     * @return bool
     */
    
final public function isClosed()
    {
        return 
$this->hardClosed;
    }

    
/**
     * Forced establishes a connection (if its is not establishes)
     *
     * @return bool
     *         a connection has been established at this time
     * @throws goDBExceptionsConnect
     *         a connection error
     * @throws goDBExceptionsClosed
     *         a connection has been closed (hard)
     */
    
final public function forcedConnect()
    {
        if (
$this->hardClosed) {
            throw new 
Closed();
        }
        if (
$this->connected) {
            return 
false;
        }
        
$res $this->connector->connect();
        
$this->connected true;
        
$this->execPre();
        return 
$res;
    }

    
/**
     * Closes a connection
     *
     * @param boolean $soft [optional]
     *        uses "soft" closing (it is possible to restore)
     * @return boolean
     *         a connection has been closed at this time
     */
    
final public function close($soft false)
    {
        if (
$this->hardClosed) {
            return 
false;
        }
        
$this->hardClosed = !$soft;
        if (!
$this->connected) {
            return 
false;
        }
        
$this->connected false;
        return 
$this->connector->close();
    }

    
/**
     * Sets the prefix for tables
     *
     * @param string $prefix
     */
    
final public function setPrefix($prefix)
    {
        
$this->prefix $prefix;
    }

    
/**
     * Returns the prefix for tables
     *
     * @return string
     */
    
final public function getPrefix()
    {
        return 
$this->prefix;
    }

    
/**
     * Sets a handler for the debug info
     *
     * @param callable|bool $callback [optional]
     *        a callback($query, $duration, $info) or TRUE for the standard handler or NULL for disable
     */
    
final public function setDebug($callback true)
    {
        if (
$callback === true) {
            if (
php_sapi_name() === 'cli') {
                
$callback = new DebuggerOutConsole();
            } else {
                
$callback = new DebuggerOutHtml();
            }
        }
        
$this->debugCallback $callback;
    }

    
/**
     * Returns a debug handler
     *
     * @return callback
     */
    
final public function getDebug()
    {
        return 
$this->debugCallback;
    }

    
/**
     * Disables the debug info output
     */
    
final public function disableDebug()
    {
        
$this->debugCallback null;
    }

    
/**
     * Returns a low-level connection implementation (adapter depended)
     *
     * @param bool $connect
     *        force connect
     * @return mixed
     *         an implementation or FALSE if it is not created
     * @throws goDBExceptionsConnect
     * @throws goDBExceptionsClosed
     */
    
final public function getImplementationConnection($connect true)
    {
        if (
$connect && (!$this->connector->isConnected())) {
            
$this->forcedConnect();
        }
        return 
$this->connector->getConnection();
    }

    
/**
     * Creates a query by a pattern and an incoming data
     *
     * @param string $pattern
     *        a query pattern
     * @param array $data
     *        an incoming data for the pattern
     * @param string $prefix
     *        a prefix for tables
     * @return string
     *         the plain query
     * @throws goDBExceptionsTemplater
     *         an error of templating system
     */
    
public function makeQuery($pattern$data$prefix null)
    {
        
Compat::setCurrentOpts($this->paramsSys['compat']);
        
$this->forcedConnect();
        if (
$prefix === null) {
            
$prefix $this->prefix;
        }
        
$templater $this->createTemplater($pattern$data$prefix);
        
$templater->parse();
        return 
$templater->getQuery();
    }

    
/**
     * Returns an object for a table access
     *
     * @param string $tableName
     *        a table name
     * @param array $map [optional]
     *        a map (a key => a real table column)
     * @return goDBTable
     *         a "table" instance
     */
    
public function getTable($tableName, array $map null)
    {
        if ((
$map === null) && (is_string($tableName))) {
            if (isset(
$this->cacheTables[$tableName])) {
                
$table $this->cacheTables[$tableName];
            } else {
                
$table = new Table($this$tableName);
                
$this->cacheTables[$tableName] = $table;
            }
        } else {
            
$table = new Table($this$tableName$map);
        }
        return 
$table;
    }

    
/**
     * The hidden constructor (for instance create use a static method create())
     *
     * @param array $params
     *        a database configuration
     * @throws goDBExceptionsConnect
     * @throws goDBExceptionsConfigConnect
     */
    
protected function __construct($params)
    {
        
$this->separateParams($params);
        
$this->connector $this->createConnector();
        
$this->setPrefix($this->paramsSys['prefix']);
        
$this->setDebug($this->paramsSys['debug']);
        if (
is_array($this->paramsSys['pre'])) {
            
$this->preQueries $this->paramsSys['pre'];
        }
        if (!
$this->paramsSys['lazy']) {
            
$this->connector->connect();
            
$this->connected true;
            
$this->execPre();
        }
    }

    
/**
     * The destructor
     */
    
final public function __destruct()
    {
        
$this->connector->close();
        
$this->connector->removeLink();
        
$this->connector null;
    }

    
/**
     * Cloning the instance
     */
    
public function __clone()
    {
        
$this->connector->addLink($this->connected);
    }

    
/**
     * Creates an instance for a database connect
     *
     * @return goDBHelpersConnector
     */
    
protected function createConnector()
    {
        return (new 
Connector($this->paramsSys['adapter'], $this->paramsDB));
    }

    
/**
     * Creates a templating for a query
     *
     * @param string $pattern
     * @param array $data
     * @param string $prefix
     * @return goDBHelpersTemplater
     */
    
protected function createTemplater($pattern$data$prefix)
    {
        return (new 
Templater($this->connector$pattern$data$prefix));
    }

    
/**
     * Creates an instance for a result representation
     *
     * @param mixed $cursor
     * @return goDBResult
     */
    
protected function createFetcher($cursor)
    {
        return (new 
CursorFetcher($this->connector$cursor));
    }

    
/**
     * Analysis parameters and separates its to system and adapter-depending
     *
     * @param array $params
     * @throws goDBExceptionsConfigSys
     */
    
protected function separateParams($params)
    {
        
$this->paramsDB = array();
        
$this->paramsSys Config::get('configsys');
        foreach (
$params as $name => $value) {
            if (
substr($name01) === '_') {
                
$name substr($name1);
                if (!
array_key_exists($name$this->paramsSys)) {
                    throw new 
ConfigSys('Unknown system param "'.$name.'"');
                }
                
$this->paramsSys[$name] = $value;
            } else {
                
$this->paramsDB[$name] = $value;
            }
        }
    }

    
/**
     * Sends a debug info to the handler
     *
     * @param string $query
     * @param float $duration
     * @param mixed $info
     */
    
protected function debugLog($query$duration$info)
    {
        if (
$this->debugCallback) {
            
call_user_func($this->debugCallback$query$duration$info);
        }
    }

    
/**
     * Executes all pre-queries
     *
     * @throws goDBExceptionsException
     */
    
protected function execPre()
    {
        foreach (
$this->preQueries as $pq) {
            if (
is_array($pq)) {
                
$pattern $pq[0];
                
$data = isset($pq[1]) ? $pq[1] : null;
            } else {
                
$pattern $pq;
                
$data null;
            }
            
$this->query($pattern$data);
        }
        
$this->preQueries = array();
    }
    public 
$tpassed 0;
    public 
$query_number=0;
    
/**
     * The list of avaliable adapters (cache)
     *
     * @var array
     */
    
private static $availableAdapters;

    
/**
     * The connection instance
     *
     * @var goDBHelpersConnector
     */
    
protected $connector;

    
/**
     * System parameters
     *
     * @var array
     */
    
protected $paramsSys;

    
/**
     * Connection parameters
     *
     * @var array
     */
    
protected $paramsDB;

    
/**
     * The current table prefix
     *
     * @var string
     */
    
protected $prefix;

    
/**
     * The debug handler
     *
     * @var callback
     */
    
protected $debugCallback;

    
/**
     * Flag: the connection is established
     *
     * @var bool
     */
    
protected $connected false;

    
/**
     * Flag: the connection is closed (hard)
     *
     * @var bool
     */
    
protected $hardClosed false;

    
/**
     * The list of pre-queries
     *
     * @var array
     */
    
protected $preQueries = array();

    
/**
     * @var array
     */
    
protected $cacheTables = array();
}

/**
 * @alias goDBDB::create
 *
 * @param array $params
 * @param string $adapter [optional]
 * @return goDBDB
 * @throws goDBExceptionsConfig
 * @throws goDBExceptionsConnect
 */
function create(array $params$adapter null)
{
    return 
DB::create($params$adapter);
}

/**
 * @alias goDBStorage::query
 *
 * @param string $pattern
 * @param array $data [optional]
 * @param string $fetch [optional]
 * @param string $prefix [optional]
 * @return goDBResult
 * @throws goDBExceptionsStorageDBCentral
 * @throws goDBExceptionsConnect
 * @throws goDBExceptionsClosed
 * @throws goDBExceptionsTemplater
 * @throws goDBExceptionsQuery
 * @throws goDBExceptionsFetch
 */
function query($pattern$data null$fetch null$prefix null)
{
    return 
Storage::getInstance()->query($pattern$data$fetch$prefix);
}
Онлайн: 1
Реклама