Ticket: 195
This commit is contained in:
parent
ff85f8c668
commit
0d75147c70
@ -30,7 +30,7 @@ class Doctrine_DataDict {
|
||||
|
||||
protected $dbh;
|
||||
|
||||
public function __construct(PDO $dbh) {
|
||||
public function __construct($dbh = null) {
|
||||
$file = Doctrine::getPath().DIRECTORY_SEPARATOR."Doctrine".DIRECTORY_SEPARATOR."adodb-hack".DIRECTORY_SEPARATOR."adodb.inc.php";
|
||||
|
||||
if( ! file_exists($file))
|
||||
@ -39,6 +39,7 @@ class Doctrine_DataDict {
|
||||
require_once($file);
|
||||
|
||||
$this->dbh = $dbh;
|
||||
if($dbh)
|
||||
$this->dict = NewDataDictionary($dbh);
|
||||
}
|
||||
/**
|
||||
|
@ -29,7 +29,7 @@
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
class Doctrine_DataDict_Mysql extends Doctrine_DataDict {
|
||||
class Doctrine_DataDict_Pgsql extends Doctrine_DataDict {
|
||||
/**
|
||||
* Obtain DBMS specific SQL code portion needed to declare an text type
|
||||
* field to be used in statements like CREATE TABLE.
|
||||
@ -53,7 +53,7 @@ class Doctrine_DataDict_Mysql extends Doctrine_DataDict {
|
||||
* @return string DBMS specific SQL code portion that should be used to
|
||||
* declare the specified field.
|
||||
*/
|
||||
public function getTypeDeclaration(array $field) {
|
||||
public function getNativeDeclaration(array $field) {
|
||||
switch ($field['type']) {
|
||||
case 'string':
|
||||
case 'array':
|
||||
@ -115,8 +115,8 @@ class Doctrine_DataDict_Mysql extends Doctrine_DataDict {
|
||||
* @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
|
||||
* @return array containing the various possible types, length, sign, fixed
|
||||
*/
|
||||
public function mapNativeDatatype($field) {
|
||||
$db_type = preg_replace('/\d/','', strtolower($field['type']) );
|
||||
public function getDoctrineDeclaration(array $field) {
|
||||
|
||||
$length = $field['length'];
|
||||
if ($length == '-1' && !empty($field['atttypmod'])) {
|
||||
$length = $field['atttypmod'] - 4;
|
||||
@ -126,7 +126,7 @@ class Doctrine_DataDict_Mysql extends Doctrine_DataDict {
|
||||
}
|
||||
$type = array();
|
||||
$unsigned = $fixed = null;
|
||||
switch ($db_type) {
|
||||
switch ($field['type']) {
|
||||
case 'smallint':
|
||||
case 'int2':
|
||||
$type[] = 'integer';
|
||||
@ -159,7 +159,7 @@ class Doctrine_DataDict_Mysql extends Doctrine_DataDict {
|
||||
case 'bool':
|
||||
case 'boolean':
|
||||
$type[] = 'boolean';
|
||||
$length = null;
|
||||
$length = 1;
|
||||
break;
|
||||
case 'text':
|
||||
case 'varchar':
|
||||
|
233
lib/Doctrine/Expression.php
Normal file
233
lib/Doctrine/Expression.php
Normal file
@ -0,0 +1,233 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.phpdoctrine.com>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Doctrine_Expression
|
||||
*
|
||||
* @package Doctrine ORM
|
||||
* @url www.phpdoctrine.com
|
||||
* @license LGPL
|
||||
*/
|
||||
class Doctrine_Expression {
|
||||
|
||||
/**
|
||||
* @var Doctrine_Connection $connection
|
||||
*/
|
||||
protected $conn;
|
||||
/**
|
||||
* @param Doctrine_Connection $conn
|
||||
*/
|
||||
public function __construct(Doctrine_Connection $conn) {
|
||||
$this->conn = $conn;
|
||||
}
|
||||
/**
|
||||
* Returns the average value of a column
|
||||
*
|
||||
* @param string $column the column to use
|
||||
* @return string generated sql including an AVG aggregate function
|
||||
*/
|
||||
public function avg($column) {
|
||||
$column = $this->getIdentifier($column);
|
||||
return 'AVG(' . $column . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of rows (without a NULL value) of a column
|
||||
*
|
||||
* If a '*' is used instead of a column the number of selected rows
|
||||
* is returned.
|
||||
*
|
||||
* @param string|integer $column the column to use
|
||||
* @return string generated sql including a COUNT aggregate function
|
||||
*/
|
||||
public function count($column) {
|
||||
$column = $this->getIdentifier($column);
|
||||
return 'COUNT(' . $column . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the highest value of a column
|
||||
*
|
||||
* @param string $column the column to use
|
||||
* @return string generated sql including a MAX aggregate function
|
||||
*/
|
||||
public function max($column) {
|
||||
$column = $this->getIdentifier($column);
|
||||
return 'MAX(' . $column . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the lowest value of a column
|
||||
*
|
||||
* @param string $column the column to use
|
||||
* @return string
|
||||
*/
|
||||
public function min($column) {
|
||||
$column = $this->getIdentifier($column);
|
||||
return 'MIN(' . $column . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total sum of a column
|
||||
*
|
||||
* @param string $column the column to use
|
||||
* @return string
|
||||
*/
|
||||
public function sum($column) {
|
||||
$column = $this->getIdentifier($column);
|
||||
return 'SUM(' . $column . ')';
|
||||
}
|
||||
|
||||
// scalar functions
|
||||
|
||||
/**
|
||||
* Returns the md5 sum of a field.
|
||||
*
|
||||
* Note: Not SQL92, but common functionality
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function md5($column) {
|
||||
$column = $this->getIdentifier($column);
|
||||
return 'MD5(' . $column . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of a text field.
|
||||
*
|
||||
* @param string $expression1
|
||||
* @param string $expression2
|
||||
* @return string
|
||||
*/
|
||||
public function length($column) {
|
||||
$column = $this->getIdentifier($column);
|
||||
return 'LENGTH(' . $column . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Rounds a numeric field to the number of decimals specified.
|
||||
*
|
||||
* @param string $expression1
|
||||
* @param string $expression2
|
||||
* @return string
|
||||
*/
|
||||
public function round($column, $decimals) {
|
||||
$column = $this->getIdentifier($column);
|
||||
|
||||
return 'ROUND(' . $column . ', ' . $decimals . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the remainder of the division operation
|
||||
* $expression1 / $expression2.
|
||||
*
|
||||
* @param string $expression1
|
||||
* @param string $expression2
|
||||
* @return string
|
||||
*/
|
||||
public function mod($expression1, $expression2) {
|
||||
$expression1 = $this->getIdentifier($expression1);
|
||||
$expression2 = $this->getIdentifier($expression2);
|
||||
return 'MOD(' . $expression1 . ', ' . $expression2 . ')';
|
||||
}
|
||||
/**
|
||||
* ltrim
|
||||
* returns the string $str with leading space characters removed
|
||||
*
|
||||
* @param string $str literal string or column name
|
||||
* @return string
|
||||
*/
|
||||
public function ltrim($str) {
|
||||
return 'LTRIM(' . $str . ')';
|
||||
}
|
||||
/**
|
||||
* upper
|
||||
* Returns the string $str with all characters changed to uppercase according to the current character set mapping.
|
||||
*
|
||||
* @param string $str literal string or column name
|
||||
* @return string
|
||||
*/
|
||||
public function upper($str) {
|
||||
return 'UPPER(' . $str . ')';
|
||||
}
|
||||
/**
|
||||
* lower
|
||||
* Returns the string $str with all characters changed to lowercase according to the current character set mapping.
|
||||
*
|
||||
* @param string $str literal string or column name
|
||||
* @return string
|
||||
*/
|
||||
public function lower($str) {
|
||||
return 'LOWER(' . $str . ')';
|
||||
}
|
||||
/**
|
||||
* locate
|
||||
* returns the position of the first occurrence of substring $substr in string $str
|
||||
*
|
||||
* @param string $substr literal string
|
||||
* @param string $str literal string
|
||||
* @return string
|
||||
*/
|
||||
public function locate($substr, $str) {
|
||||
return 'LOCATE(' . $str . ', ' . $substr . ')';
|
||||
}
|
||||
/**
|
||||
* Returns the current system date.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function now() {
|
||||
return 'NOW()';
|
||||
}
|
||||
/**
|
||||
* Returns part of a string.
|
||||
*
|
||||
* Note: Not SQL92, but common functionality.
|
||||
*
|
||||
* @param string $value the target $value the string or the string column.
|
||||
* @param int $from extract from this characeter.
|
||||
* @param int $len extract this amount of characters.
|
||||
* @return string sql that extracts part of a string.
|
||||
*/
|
||||
public function subString($value, $from, $len = null) {
|
||||
$value = $this->getIdentifier($value);
|
||||
if ($len === null)
|
||||
return 'SUBSTRING(' . $value . ' FROM ' . $from . ')';
|
||||
else {
|
||||
$len = $this->getIdentifier($len);
|
||||
return 'SUBSTRING(' . $value . ' FROM ' . $from . ' FOR ' . $len . ')';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a series of strings concatinated
|
||||
*
|
||||
* concat() accepts an arbitrary number of parameters. Each parameter
|
||||
* must contain an expression or an array with expressions.
|
||||
*
|
||||
* @param string|array(string) strings that will be concatinated.
|
||||
*/
|
||||
public function concat($arg1, $arg2) {
|
||||
$args = func_get_args();
|
||||
$cols = $this->getIdentifiers($cols);
|
||||
return 'CONCAT(' . join(', ', $cols) . ')';
|
||||
}
|
||||
}
|
45
lib/Doctrine/Expression/Oracle.php
Normal file
45
lib/Doctrine/Expression/Oracle.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.phpdoctrine.com>.
|
||||
*/
|
||||
Doctrine::autoload('Doctrine_Expression');
|
||||
/**
|
||||
* Doctrine_Expression_Sqlite
|
||||
*
|
||||
* @package Doctrine ORM
|
||||
* @url www.phpdoctrine.com
|
||||
* @license LGPL
|
||||
*/
|
||||
class Doctrine_Expression_Oracle extends Doctrine_Expression {
|
||||
/**
|
||||
* Returns a series of strings concatinated
|
||||
*
|
||||
* concat() accepts an arbitrary number of parameters. Each parameter
|
||||
* must contain an expression
|
||||
*
|
||||
* @param string $arg1, $arg2 ... $argN strings that will be concatinated.
|
||||
* @return string
|
||||
*/
|
||||
public function concat($arg1, $arg2) {
|
||||
$args = func_get_args();
|
||||
|
||||
$cols = $this->getIdentifiers( $args );
|
||||
return join( ' || ' , $cols );
|
||||
}
|
||||
}
|
91
lib/Doctrine/Expression/Pgsql.php
Normal file
91
lib/Doctrine/Expression/Pgsql.php
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.phpdoctrine.com>.
|
||||
*/
|
||||
Doctrine::autoload('Doctrine_Expression');
|
||||
/**
|
||||
* Doctrine_Expression_Pgsql
|
||||
*
|
||||
* @package Doctrine ORM
|
||||
* @url www.phpdoctrine.com
|
||||
* @license LGPL
|
||||
*/
|
||||
class Doctrine_Expression_Pgsql extends Doctrine_Expression {
|
||||
/**
|
||||
* Returns the md5 sum of a field.
|
||||
*
|
||||
* Note: Not SQL92, but common functionality
|
||||
*
|
||||
* md5() works with the default PostgreSQL 8 versions.
|
||||
*
|
||||
* If you are using PostgreSQL 7.x or older you need
|
||||
* to make sure that the digest procedure.
|
||||
* If you use RPMS (Redhat and Mandrake) install the postgresql-contrib
|
||||
* package. You must then install the procedure by running this shell command:
|
||||
* <code>
|
||||
* psql [dbname] < /usr/share/pgsql/contrib/pgcrypto.sql
|
||||
* </code>
|
||||
* You should make sure you run this as the postgres user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function md5($column) {
|
||||
$column = $this->getIdentifier($column);
|
||||
|
||||
if ($this->version > 7)
|
||||
return 'MD5(' . $column . ')';
|
||||
else
|
||||
return 'encode(digest(' . $column .', md5), hex)';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns part of a string.
|
||||
*
|
||||
* Note: Not SQL92, but common functionality.
|
||||
*
|
||||
* @param string $value the target $value the string or the string column.
|
||||
* @param int $from extract from this characeter.
|
||||
* @param int $len extract this amount of characters.
|
||||
* @return string sql that extracts part of a string.
|
||||
*/
|
||||
public function subString($value, $from, $len = null) {
|
||||
$value = $this->getIdentifier($value);
|
||||
|
||||
if ($len === null) {
|
||||
$len = $this->getIdentifier($len);
|
||||
return 'SUBSTR(' . $value . ', ' . $from . ')';
|
||||
} else
|
||||
return 'SUBSTR(' . $value . ', ' . $from . ', ' . $len . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a series of strings concatinated
|
||||
*
|
||||
* concat() accepts an arbitrary number of parameters. Each parameter
|
||||
* must contain an expression or an array with expressions.
|
||||
*
|
||||
* @param string|array(string) strings that will be concatinated.
|
||||
* @return string
|
||||
*/
|
||||
public function concat($arg1, $arg2) {
|
||||
$args = func_get_args();
|
||||
$cols = $this->getIdentifiers($cols);
|
||||
|
||||
return join(' || ' , $cols);
|
||||
}
|
||||
}
|
49
lib/Doctrine/Expression/Sqlite.php
Normal file
49
lib/Doctrine/Expression/Sqlite.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.phpdoctrine.com>.
|
||||
*/
|
||||
Doctrine::autoload('Doctrine_Expression');
|
||||
/**
|
||||
* Doctrine_Expression_Sqlite
|
||||
*
|
||||
* @package Doctrine ORM
|
||||
* @url www.phpdoctrine.com
|
||||
* @license LGPL
|
||||
*/
|
||||
class Doctrine_Expression_Sqlite extends Doctrine_Expression {
|
||||
/**
|
||||
* Returns part of a string.
|
||||
*
|
||||
* Note: Not SQL92, but common functionality. SQLite only supports the 3
|
||||
* parameter variant of this function, so we are using 2^30-1 as
|
||||
* artificial length in that case.
|
||||
*
|
||||
* @param string $value the target $value the string or the string column.
|
||||
* @param int $from extract from this characeter.
|
||||
* @param int $len extract this amount of characters.
|
||||
* @return string sql that extracts part of a string.
|
||||
*/
|
||||
public function subString($value, $from, $len = null) {
|
||||
$value = $this->getIdentifier( $value );
|
||||
if ( $len === null )
|
||||
$len = 1073741823;
|
||||
|
||||
return 'SUBSTR(' . $value . ', ' . $from . ', ' . $len . ')';
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
<?php
|
||||
class Doctrine_Filter {
|
||||
|
||||
private $name;
|
||||
|
||||
public function __construct($name) {
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function getName() {
|
||||
return $this->name;
|
||||
}
|
||||
}
|
||||
|
@ -1,943 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.phpdoctrine.com>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Doctrine_Session
|
||||
*
|
||||
* @package Doctrine ORM
|
||||
* @url www.phpdoctrine.com
|
||||
* @license LGPL
|
||||
*/
|
||||
abstract class Doctrine_Session extends Doctrine_Configurable implements Countable, IteratorAggregate {
|
||||
/**
|
||||
* Doctrine_Session is in open state when it is opened and there are no active transactions
|
||||
*/
|
||||
const STATE_OPEN = 0;
|
||||
/**
|
||||
* Doctrine_Session is in closed state when it is closed
|
||||
*/
|
||||
const STATE_CLOSED = 1;
|
||||
/**
|
||||
* Doctrine_Session is in active state when it has one active transaction
|
||||
*/
|
||||
const STATE_ACTIVE = 2;
|
||||
/**
|
||||
* Doctrine_Session is in busy state when it has multiple active transactions
|
||||
*/
|
||||
const STATE_BUSY = 3;
|
||||
/**
|
||||
* @var $dbh the database handle
|
||||
*/
|
||||
private $dbh;
|
||||
/**
|
||||
* @see Doctrine_Session::STATE_* constants
|
||||
* @var boolean $state the current state of the session
|
||||
*/
|
||||
private $state = 0;
|
||||
/**
|
||||
* @var integer $transaction_level the nesting level of transactions, used by transaction methods
|
||||
*/
|
||||
private $transaction_level = 0;
|
||||
/**
|
||||
* @var array $tables an array containing all the initialized Doctrine_Table objects
|
||||
* keys representing Doctrine_Table component names and values as Doctrine_Table objects
|
||||
*/
|
||||
protected $tables = array();
|
||||
/**
|
||||
* @var Doctrine_Validator $validator transaction validator
|
||||
*/
|
||||
protected $validator;
|
||||
/**
|
||||
* @var array $update two dimensional pending update list, the records in
|
||||
* this list will be updated when transaction is committed
|
||||
*/
|
||||
protected $update = array();
|
||||
/**
|
||||
* @var array $insert two dimensional pending insert list, the records in
|
||||
* this list will be inserted when transaction is committed
|
||||
*/
|
||||
protected $insert = array();
|
||||
/**
|
||||
* @var array $delete two dimensional pending delete list, the records in
|
||||
* this list will be deleted when transaction is committed
|
||||
*/
|
||||
protected $delete = array();
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* the constructor
|
||||
*
|
||||
* @param Doctrine_Manager $manager the manager object
|
||||
* @param PDO $pdo the database handler
|
||||
*/
|
||||
public function __construct(Doctrine_Manager $manager,PDO $pdo) {
|
||||
$this->dbh = $pdo;
|
||||
$this->state = Doctrine_Session::STATE_OPEN;
|
||||
|
||||
$this->setParent($manager);
|
||||
|
||||
$this->dbh->setAttribute(PDO::ATTR_CASE, PDO::CASE_NATURAL);
|
||||
$this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
$this->getAttribute(Doctrine::ATTR_LISTENER)->onOpen($this);
|
||||
}
|
||||
/**
|
||||
* returns the state of this session
|
||||
*
|
||||
* @see Doctrine_Session::STATE_* constants
|
||||
* @return integer the session state
|
||||
*/
|
||||
public function getState() {
|
||||
return $this->state;
|
||||
}
|
||||
/**
|
||||
* returns the manager that created this session
|
||||
*
|
||||
* @return Doctrine_Manager
|
||||
*/
|
||||
public function getManager() {
|
||||
return $this->getParent();
|
||||
}
|
||||
/**
|
||||
* returns the database handler of which this session uses
|
||||
*
|
||||
* @return object PDO the database handler
|
||||
*/
|
||||
public function getDBH() {
|
||||
return $this->dbh;
|
||||
}
|
||||
/**
|
||||
* query
|
||||
* queries the database with Doctrine Query Language
|
||||
*
|
||||
* @param string $query DQL query
|
||||
* @param array $params query parameters
|
||||
*/
|
||||
final public function query($query,array $params = array()) {
|
||||
$parser = new Doctrine_Query($this);
|
||||
|
||||
return $parser->query($query, $params);
|
||||
}
|
||||
/**
|
||||
* queries the database with limit and offset
|
||||
* added to the query and returns a PDOStatement object
|
||||
*
|
||||
* @param string $query
|
||||
* @param integer $limit
|
||||
* @param integer $offset
|
||||
* @return PDOStatement
|
||||
*/
|
||||
public function select($query,$limit = 0,$offset = 0) {
|
||||
if($limit > 0 || $offset > 0)
|
||||
$query = $this->modifyLimitQuery($query,$limit,$offset);
|
||||
|
||||
return $this->dbh->query($query);
|
||||
}
|
||||
/**
|
||||
* @param string $query sql query
|
||||
* @param array $params query parameters
|
||||
*
|
||||
* @return PDOStatement
|
||||
*/
|
||||
public function execute($query, array $params = array()) {
|
||||
if( ! empty($params)) {
|
||||
$stmt = $this->dbh->prepare($query);
|
||||
$stmt->execute($params);
|
||||
return $stmt;
|
||||
} else {
|
||||
return $this->dbh->query($query);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* whether or not this session has table $name initialized
|
||||
*
|
||||
* @param $mixed $name
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasTable($name) {
|
||||
return isset($this->tables[$name]);
|
||||
}
|
||||
/**
|
||||
* returns a table object for given component name
|
||||
*
|
||||
* @param string $name component name
|
||||
* @return object Doctrine_Table
|
||||
*/
|
||||
public function getTable($name) {
|
||||
if(isset($this->tables[$name]))
|
||||
return $this->tables[$name];
|
||||
|
||||
$class = $name."Table";
|
||||
|
||||
if(class_exists($class) && in_array("Doctrine_Table", class_parents($class))) {
|
||||
return new $class($name);
|
||||
} else {
|
||||
|
||||
return new Doctrine_Table($name);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* returns an array of all initialized tables
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTables() {
|
||||
return $this->tables;
|
||||
}
|
||||
/**
|
||||
* returns an iterator that iterators through all
|
||||
* initialized table objects
|
||||
*
|
||||
* @return ArrayIterator
|
||||
*/
|
||||
public function getIterator() {
|
||||
return new ArrayIterator($this->tables);
|
||||
}
|
||||
/**
|
||||
* returns the count of initialized table objects
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function count() {
|
||||
return count($this->tables);
|
||||
}
|
||||
/**
|
||||
* @param $objTable a Doctrine_Table object to be added into registry
|
||||
* @return boolean
|
||||
*/
|
||||
public function addTable(Doctrine_Table $objTable) {
|
||||
$name = $objTable->getComponentName();
|
||||
|
||||
if(isset($this->tables[$name]))
|
||||
return false;
|
||||
|
||||
$this->tables[$name] = $objTable;
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* creates a record
|
||||
*
|
||||
* create creates a record
|
||||
* @param string $name component name
|
||||
* @return Doctrine_Record Doctrine_Record object
|
||||
*/
|
||||
public function create($name) {
|
||||
return $this->getTable($name)->create();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* buildFlushTree
|
||||
* builds a flush tree that is used in transactions
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function buildFlushTree(array $tables) {
|
||||
$tree = array();
|
||||
foreach($tables as $k => $table) {
|
||||
$k = $k.$table;
|
||||
if( ! ($table instanceof Doctrine_Table))
|
||||
$table = $this->getTable($table);
|
||||
|
||||
$nm = $table->getComponentName();
|
||||
|
||||
$index = array_search($nm,$tree);
|
||||
if($index === false) {
|
||||
$tree[] = $nm;
|
||||
$index = max(array_keys($tree));
|
||||
|
||||
//print "$k -- adding <b>$nm</b>...<br \>";
|
||||
}
|
||||
|
||||
$rels = $table->getRelations();
|
||||
|
||||
// group relations
|
||||
|
||||
foreach($rels as $key => $rel) {
|
||||
if($rel instanceof Doctrine_Relation_ForeignKey) {
|
||||
unset($rels[$key]);
|
||||
array_unshift($rels, $rel);
|
||||
}
|
||||
}
|
||||
|
||||
foreach($rels as $rel) {
|
||||
$name = $rel->getTable()->getComponentName();
|
||||
$index2 = array_search($name,$tree);
|
||||
$type = $rel->getType();
|
||||
|
||||
// skip self-referenced relations
|
||||
if($name === $nm)
|
||||
continue;
|
||||
|
||||
if($rel instanceof Doctrine_Relation_ForeignKey) {
|
||||
if($index2 !== false) {
|
||||
if($index2 >= $index)
|
||||
continue;
|
||||
|
||||
unset($tree[$index]);
|
||||
array_splice($tree,$index2,0,$nm);
|
||||
$index = $index2;
|
||||
|
||||
//print "$k -- pushing $nm into $index2...<br \>";
|
||||
|
||||
} else {
|
||||
$tree[] = $name;
|
||||
//print "$k -- adding $nm :$name...<br>";
|
||||
}
|
||||
|
||||
} elseif($rel instanceof Doctrine_Relation_LocalKey) {
|
||||
if($index2 !== false) {
|
||||
if($index2 <= $index)
|
||||
continue;
|
||||
|
||||
unset($tree[$index2]);
|
||||
array_splice($tree,$index,0,$name);
|
||||
|
||||
//print "$k -- pushing $name into <b>$index</b>...<br \>";
|
||||
|
||||
} else {
|
||||
//array_splice($tree, $index, 0, $name);
|
||||
array_unshift($tree,$name);
|
||||
$index++;
|
||||
|
||||
//print "$k -- pushing <b>$name</b> into 0...<br \>";
|
||||
}
|
||||
} elseif($rel instanceof Doctrine_Relation_Association) {
|
||||
$t = $rel->getAssociationFactory();
|
||||
$n = $t->getComponentName();
|
||||
|
||||
if($index2 !== false)
|
||||
unset($tree[$index2]);
|
||||
|
||||
array_splice($tree,$index, 0,$name);
|
||||
$index++;
|
||||
|
||||
$index3 = array_search($n,$tree);
|
||||
|
||||
if($index3 !== false) {
|
||||
if($index3 >= $index)
|
||||
continue;
|
||||
|
||||
unset($tree[$index]);
|
||||
array_splice($tree,$index3,0,$n);
|
||||
$index = $index2;
|
||||
|
||||
//print "$k -- pushing $nm into $index3...<br \>";
|
||||
|
||||
} else {
|
||||
$tree[] = $n;
|
||||
//print "$k -- adding $nm :$name...<br>";
|
||||
}
|
||||
}
|
||||
//print_r($tree);
|
||||
}
|
||||
//print_r($tree);
|
||||
|
||||
}
|
||||
return array_values($tree);
|
||||
}
|
||||
|
||||
/**
|
||||
* flush
|
||||
* saves all the records from all tables
|
||||
* this operation is isolated using a transaction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function flush() {
|
||||
$this->beginTransaction();
|
||||
$this->saveAll();
|
||||
$this->commit();
|
||||
}
|
||||
/**
|
||||
* saveAll
|
||||
* saves all the records from all tables
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function saveAll() {
|
||||
$tree = $this->buildFlushTree($this->tables);
|
||||
|
||||
foreach($tree as $name) {
|
||||
$table = $this->tables[$name];
|
||||
|
||||
foreach($table->getRepository() as $record) {
|
||||
$this->save($record);
|
||||
}
|
||||
}
|
||||
foreach($tree as $name) {
|
||||
$table = $this->tables[$name];
|
||||
foreach($table->getRepository() as $record) {
|
||||
$record->saveAssociations();
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* clear
|
||||
* clears all repositories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function clear() {
|
||||
foreach($this->tables as $k => $table) {
|
||||
$table->getRepository()->evictAll();
|
||||
$table->clear();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function evictTables() {
|
||||
$this->tables = array();
|
||||
}
|
||||
/**
|
||||
* close
|
||||
* closes the session
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function close() {
|
||||
$this->getAttribute(Doctrine::ATTR_LISTENER)->onPreClose($this);
|
||||
|
||||
$this->clear();
|
||||
$this->state = Doctrine_Session::STATE_CLOSED;
|
||||
|
||||
$this->getAttribute(Doctrine::ATTR_LISTENER)->onClose($this);
|
||||
}
|
||||
/**
|
||||
* get the current transaction nesting level
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getTransactionLevel() {
|
||||
return $this->transaction_level;
|
||||
}
|
||||
/**
|
||||
* beginTransaction
|
||||
* starts a new transaction
|
||||
* @return void
|
||||
*/
|
||||
public function beginTransaction() {
|
||||
if($this->transaction_level == 0) {
|
||||
|
||||
if($this->getAttribute(Doctrine::ATTR_LOCKMODE) == Doctrine::LOCK_PESSIMISTIC) {
|
||||
$this->getAttribute(Doctrine::ATTR_LISTENER)->onPreTransactionBegin($this);
|
||||
$this->dbh->beginTransaction();
|
||||
$this->getAttribute(Doctrine::ATTR_LISTENER)->onTransactionBegin($this);
|
||||
}
|
||||
$this->state = Doctrine_Session::STATE_ACTIVE;
|
||||
} else {
|
||||
$this->state = Doctrine_Session::STATE_BUSY;
|
||||
}
|
||||
$this->transaction_level++;
|
||||
}
|
||||
/**
|
||||
* commits the current transaction
|
||||
* if lockmode is optimistic this method starts a transaction
|
||||
* and commits it instantly
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function commit() {
|
||||
|
||||
$this->transaction_level--;
|
||||
|
||||
if($this->transaction_level == 0) {
|
||||
|
||||
|
||||
if($this->getAttribute(Doctrine::ATTR_LOCKMODE) == Doctrine::LOCK_OPTIMISTIC) {
|
||||
$this->getAttribute(Doctrine::ATTR_LISTENER)->onPreTransactionBegin($this);
|
||||
|
||||
$this->dbh->beginTransaction();
|
||||
|
||||
$this->getAttribute(Doctrine::ATTR_LISTENER)->onTransactionBegin($this);
|
||||
}
|
||||
|
||||
if($this->getAttribute(Doctrine::ATTR_VLD))
|
||||
$this->validator = new Doctrine_Validator();
|
||||
|
||||
try {
|
||||
|
||||
$this->bulkInsert();
|
||||
$this->bulkUpdate();
|
||||
$this->bulkDelete();
|
||||
|
||||
if($this->getAttribute(Doctrine::ATTR_VLD)) {
|
||||
if($this->validator->hasErrors()) {
|
||||
$this->rollback();
|
||||
throw new Doctrine_Validator_Exception($this->validator);
|
||||
}
|
||||
}
|
||||
|
||||
$this->dbh->commit();
|
||||
|
||||
} catch(PDOException $e) {
|
||||
$this->rollback();
|
||||
|
||||
throw new Doctrine_Exception($e->__toString());
|
||||
}
|
||||
|
||||
$this->getAttribute(Doctrine::ATTR_LISTENER)->onTransactionCommit($this);
|
||||
|
||||
$this->delete = array();
|
||||
$this->state = Doctrine_Session::STATE_OPEN;
|
||||
|
||||
$this->validator = null;
|
||||
|
||||
} elseif($this->transaction_level == 1)
|
||||
$this->state = Doctrine_Session::STATE_ACTIVE;
|
||||
}
|
||||
/**
|
||||
* rollback
|
||||
* rolls back all transactions
|
||||
*
|
||||
* this method also listens to onPreTransactionRollback and onTransactionRollback
|
||||
* eventlisteners
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function rollback() {
|
||||
$this->getAttribute(Doctrine::ATTR_LISTENER)->onPreTransactionRollback($this);
|
||||
|
||||
$this->transaction_level = 0;
|
||||
$this->dbh->rollback();
|
||||
$this->state = Doctrine_Session::STATE_OPEN;
|
||||
|
||||
$this->getAttribute(Doctrine::ATTR_LISTENER)->onTransactionRollback($this);
|
||||
}
|
||||
/**
|
||||
* bulkInsert
|
||||
* inserts all the objects in the pending insert list into database
|
||||
* @return void
|
||||
*/
|
||||
public function bulkInsert() {
|
||||
if(empty($this->insert))
|
||||
return false;
|
||||
|
||||
foreach($this->insert as $name => $inserts) {
|
||||
if( ! isset($inserts[0]))
|
||||
continue;
|
||||
|
||||
$record = $inserts[0];
|
||||
$table = $record->getTable();
|
||||
$seq = $table->getSequenceName();
|
||||
|
||||
$increment = false;
|
||||
$keys = $table->getPrimaryKeys();
|
||||
$id = null;
|
||||
|
||||
if(count($keys) == 1 && $keys[0] == $table->getIdentifier()) {
|
||||
$increment = true;
|
||||
}
|
||||
|
||||
foreach($inserts as $k => $record) {
|
||||
$table->getAttribute(Doctrine::ATTR_LISTENER)->onPreSave($record);
|
||||
// listen the onPreInsert event
|
||||
$table->getAttribute(Doctrine::ATTR_LISTENER)->onPreInsert($record);
|
||||
|
||||
|
||||
$this->insert($record);
|
||||
if($increment) {
|
||||
if($k == 0) {
|
||||
// record uses auto_increment column
|
||||
|
||||
$id = $this->dbh->lastInsertID();
|
||||
|
||||
if( ! $id)
|
||||
$id = $table->getMaxIdentifier();
|
||||
}
|
||||
|
||||
$record->assignIdentifier($id);
|
||||
$id++;
|
||||
} else
|
||||
$record->assignIdentifier(true);
|
||||
|
||||
// listen the onInsert event
|
||||
$table->getAttribute(Doctrine::ATTR_LISTENER)->onInsert($record);
|
||||
|
||||
$table->getAttribute(Doctrine::ATTR_LISTENER)->onSave($record);
|
||||
}
|
||||
}
|
||||
$this->insert = array();
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* returns maximum identifier values
|
||||
*
|
||||
* @param array $names an array of component names
|
||||
* @return array
|
||||
*/
|
||||
public function getMaximumValues(array $names) {
|
||||
$values = array();
|
||||
foreach($names as $name) {
|
||||
$table = $this->tables[$name];
|
||||
$keys = $table->getPrimaryKeys();
|
||||
$tablename = $table->getTableName();
|
||||
|
||||
if(count($keys) == 1 && $keys[0] == $table->getIdentifier()) {
|
||||
// record uses auto_increment column
|
||||
|
||||
$sql = "SELECT MAX(".$table->getIdentifier().") FROM ".$tablename;
|
||||
$stmt = $this->dbh->query($sql);
|
||||
$data = $stmt->fetch(PDO::FETCH_NUM);
|
||||
$values[$tablename] = $data[0];
|
||||
|
||||
$stmt->closeCursor();
|
||||
}
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
/**
|
||||
* bulkUpdate
|
||||
* updates all objects in the pending update list
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function bulkUpdate() {
|
||||
foreach($this->update as $name => $updates) {
|
||||
$ids = array();
|
||||
|
||||
foreach($updates as $k => $record) {
|
||||
$record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onPreSave($record);
|
||||
// listen the onPreUpdate event
|
||||
$record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onPreUpdate($record);
|
||||
|
||||
$this->update($record);
|
||||
// listen the onUpdate event
|
||||
$record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onUpdate($record);
|
||||
|
||||
$record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onSave($record);
|
||||
}
|
||||
}
|
||||
$this->update = array();
|
||||
}
|
||||
/**
|
||||
* bulkDelete
|
||||
* deletes all records from the pending delete list
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function bulkDelete() {
|
||||
foreach($this->delete as $name => $deletes) {
|
||||
$record = false;
|
||||
$ids = array();
|
||||
foreach($deletes as $k => $record) {
|
||||
$ids[] = $record->getIncremented();
|
||||
$record->assignIdentifier(false);
|
||||
}
|
||||
if($record instanceof Doctrine_Record) {
|
||||
$table = $record->getTable();
|
||||
|
||||
$params = substr(str_repeat("?, ",count($ids)),0,-2);
|
||||
$query = "DELETE FROM ".$record->getTable()->getTableName()." WHERE ".$table->getIdentifier()." IN(".$params.")";
|
||||
$this->execute($query,$ids);
|
||||
|
||||
$record->getTable()->getCache()->deleteMultiple($ids);
|
||||
}
|
||||
}
|
||||
$this->delete = array();
|
||||
}
|
||||
/**
|
||||
* saves a collection
|
||||
*
|
||||
* @param Doctrine_Collection $coll
|
||||
* @return void
|
||||
*/
|
||||
public function saveCollection(Doctrine_Collection $coll) {
|
||||
$this->beginTransaction();
|
||||
|
||||
foreach($coll as $key=>$record):
|
||||
$record->save();
|
||||
endforeach;
|
||||
|
||||
$this->commit();
|
||||
}
|
||||
/**
|
||||
* deletes all records from collection
|
||||
*
|
||||
* @param Doctrine_Collection $coll
|
||||
* @return void
|
||||
*/
|
||||
public function deleteCollection(Doctrine_Collection $coll) {
|
||||
$this->beginTransaction();
|
||||
foreach($coll as $k=>$record) {
|
||||
$record->delete();
|
||||
}
|
||||
$this->commit();
|
||||
}
|
||||
/**
|
||||
* saves the given record
|
||||
*
|
||||
* @param Doctrine_Record $record
|
||||
* @return void
|
||||
*/
|
||||
public function save(Doctrine_Record $record) {
|
||||
switch($record->getState()):
|
||||
case Doctrine_Record::STATE_TDIRTY:
|
||||
$this->addInsert($record);
|
||||
break;
|
||||
case Doctrine_Record::STATE_DIRTY:
|
||||
case Doctrine_Record::STATE_PROXY:
|
||||
$this->addUpdate($record);
|
||||
break;
|
||||
case Doctrine_Record::STATE_CLEAN:
|
||||
case Doctrine_Record::STATE_TCLEAN:
|
||||
// do nothing
|
||||
break;
|
||||
endswitch;
|
||||
}
|
||||
/**
|
||||
* saves all related records to $record
|
||||
*
|
||||
* @param Doctrine_Record $record
|
||||
*/
|
||||
final public function saveRelated(Doctrine_Record $record) {
|
||||
$saveLater = array();
|
||||
foreach($record->getReferences() as $k=>$v) {
|
||||
$fk = $record->getTable()->getRelation($k);
|
||||
if($fk instanceof Doctrine_Relation_ForeignKey ||
|
||||
$fk instanceof Doctrine_Relation_LocalKey) {
|
||||
switch($fk->getType()):
|
||||
case Doctrine_Relation::ONE_COMPOSITE:
|
||||
case Doctrine_Relation::MANY_COMPOSITE:
|
||||
$local = $fk->getLocal();
|
||||
$foreign = $fk->getForeign();
|
||||
|
||||
if($record->getTable()->hasPrimaryKey($fk->getLocal())) {
|
||||
switch($record->getState()):
|
||||
case Doctrine_Record::STATE_TDIRTY:
|
||||
case Doctrine_Record::STATE_TCLEAN:
|
||||
$saveLater[$k] = $fk;
|
||||
break;
|
||||
case Doctrine_Record::STATE_CLEAN:
|
||||
case Doctrine_Record::STATE_DIRTY:
|
||||
$v->save();
|
||||
break;
|
||||
endswitch;
|
||||
} else {
|
||||
// ONE-TO-ONE relationship
|
||||
$obj = $record->get($fk->getTable()->getComponentName());
|
||||
|
||||
if($obj->getState() != Doctrine_Record::STATE_TCLEAN)
|
||||
$obj->save();
|
||||
|
||||
}
|
||||
break;
|
||||
endswitch;
|
||||
} elseif($fk instanceof Doctrine_Relation_Association) {
|
||||
$v->save();
|
||||
}
|
||||
}
|
||||
return $saveLater;
|
||||
}
|
||||
/**
|
||||
* updates the given record
|
||||
*
|
||||
* @param Doctrine_Record $record
|
||||
* @return boolean
|
||||
*/
|
||||
private function update(Doctrine_Record $record) {
|
||||
$array = $record->getPrepared();
|
||||
|
||||
if(empty($array))
|
||||
return false;
|
||||
|
||||
$set = array();
|
||||
foreach($array as $name => $value):
|
||||
$set[] = $name." = ?";
|
||||
|
||||
if($value instanceof Doctrine_Record) {
|
||||
switch($value->getState()):
|
||||
case Doctrine_Record::STATE_TCLEAN:
|
||||
case Doctrine_Record::STATE_TDIRTY:
|
||||
$record->save();
|
||||
default:
|
||||
$array[$name] = $value->getIncremented();
|
||||
$record->set($name, $value->getIncremented());
|
||||
endswitch;
|
||||
}
|
||||
endforeach;
|
||||
|
||||
if(isset($this->validator)) {
|
||||
if( ! $this->validator->validateRecord($record)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$params = array_values($array);
|
||||
$id = $record->obtainIdentifier();
|
||||
|
||||
|
||||
if( ! is_array($id))
|
||||
$id = array($id);
|
||||
|
||||
$id = array_values($id);
|
||||
$params = array_merge($params, $id);
|
||||
|
||||
|
||||
$sql = "UPDATE ".$record->getTable()->getTableName()." SET ".implode(", ",$set)." WHERE ".implode(" = ? AND ",$record->getTable()->getPrimaryKeys())." = ?";
|
||||
|
||||
$stmt = $this->dbh->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
|
||||
$record->assignIdentifier(true);
|
||||
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* inserts a record into database
|
||||
*
|
||||
* @param Doctrine_Record $record
|
||||
* @return boolean
|
||||
*/
|
||||
private function insert(Doctrine_Record $record) {
|
||||
$array = $record->getPrepared();
|
||||
|
||||
if(empty($array))
|
||||
return false;
|
||||
|
||||
$seq = $record->getTable()->getSequenceName();
|
||||
|
||||
if( ! empty($seq)) {
|
||||
$id = $this->getNextID($seq);
|
||||
$name = $record->getTable()->getIdentifier();
|
||||
$array[$name] = $id;
|
||||
}
|
||||
|
||||
if(isset($this->validator)) {
|
||||
if( ! $this->validator->validateRecord($record)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$strfields = join(", ", array_keys($array));
|
||||
$strvalues = substr(str_repeat("?, ",count($array)),0,-2);
|
||||
|
||||
$sql = "INSERT INTO ".$record->getTable()->getTableName()." (".$strfields.") VALUES (".$strvalues.")";
|
||||
|
||||
$stmt = $this->dbh->prepare($sql);
|
||||
|
||||
$stmt->execute(array_values($array));
|
||||
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* deletes all related composites
|
||||
* this method is always called internally when a record is deleted
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
final public function deleteComposites(Doctrine_Record $record) {
|
||||
foreach($record->getTable()->getRelations() as $fk) {
|
||||
switch($fk->getType()):
|
||||
case Doctrine_Relation::ONE_COMPOSITE:
|
||||
case Doctrine_Relation::MANY_COMPOSITE:
|
||||
$obj = $record->get($record->getTable()->getAlias($fk->getTable()->getComponentName()));
|
||||
$obj->delete();
|
||||
break;
|
||||
endswitch;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* deletes this data access object and all the related composites
|
||||
* this operation is isolated by a transaction
|
||||
*
|
||||
* this event can be listened by the onPreDelete and onDelete listeners
|
||||
*
|
||||
* @return boolean true on success, false on failure
|
||||
*/
|
||||
final public function delete(Doctrine_Record $record) {
|
||||
switch($record->getState()):
|
||||
case Doctrine_Record::STATE_PROXY:
|
||||
case Doctrine_Record::STATE_CLEAN:
|
||||
case Doctrine_Record::STATE_DIRTY:
|
||||
$this->beginTransaction();
|
||||
|
||||
$this->deleteComposites($record);
|
||||
$this->addDelete($record);
|
||||
|
||||
$this->commit();
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
endswitch;
|
||||
}
|
||||
/**
|
||||
* adds record into pending insert list
|
||||
* @param Doctrine_Record $record
|
||||
*/
|
||||
public function addInsert(Doctrine_Record $record) {
|
||||
$name = $record->getTable()->getComponentName();
|
||||
$this->insert[$name][] = $record;
|
||||
}
|
||||
/**
|
||||
* adds record into penging update list
|
||||
* @param Doctrine_Record $record
|
||||
*/
|
||||
public function addUpdate(Doctrine_Record $record) {
|
||||
$name = $record->getTable()->getComponentName();
|
||||
$this->update[$name][] = $record;
|
||||
}
|
||||
/**
|
||||
* adds record into pending delete list
|
||||
* @param Doctrine_Record $record
|
||||
*/
|
||||
public function addDelete(Doctrine_Record $record) {
|
||||
$name = $record->getTable()->getComponentName();
|
||||
$this->delete[$name][] = $record;
|
||||
}
|
||||
/**
|
||||
* returns the pending insert list
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getInserts() {
|
||||
return $this->insert;
|
||||
}
|
||||
/**
|
||||
* returns the pending update list
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getUpdates() {
|
||||
return $this->update;
|
||||
}
|
||||
/**
|
||||
* returns the pending delete list
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getDeletes() {
|
||||
return $this->delete;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a string representation of this object
|
||||
* @return string
|
||||
*/
|
||||
public function __toString() {
|
||||
return Doctrine_Lib::getSessionAsString($this);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user