278 lines
8.3 KiB
PHP
278 lines
8.3 KiB
PHP
<?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_Relation
|
|
* This class represents a relation between components
|
|
*
|
|
* @package Doctrine
|
|
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
|
* @category Object Relational Mapping
|
|
* @link www.phpdoctrine.com
|
|
* @since 1.0
|
|
* @version $Revision$
|
|
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
|
*/
|
|
abstract class Doctrine_Relation {
|
|
/**
|
|
* RELATION CONSTANTS
|
|
*/
|
|
|
|
/**
|
|
* constant for ONE_TO_ONE and MANY_TO_ONE aggregate relationships
|
|
*/
|
|
const ONE_AGGREGATE = 0;
|
|
/**
|
|
* constant for ONE_TO_ONE and MANY_TO_ONE composite relationships
|
|
*/
|
|
const ONE_COMPOSITE = 1;
|
|
/**
|
|
* constant for MANY_TO_MANY and ONE_TO_MANY aggregate relationships
|
|
*/
|
|
const MANY_AGGREGATE = 2;
|
|
/**
|
|
* constant for MANY_TO_MANY and ONE_TO_MANY composite relationships
|
|
*/
|
|
const MANY_COMPOSITE = 3;
|
|
|
|
/**
|
|
* @var Doctrine_Table $table foreign factory
|
|
*/
|
|
protected $table;
|
|
/**
|
|
* @var string $local local field
|
|
*/
|
|
protected $local;
|
|
/**
|
|
* @var string $foreign foreign field
|
|
*/
|
|
protected $foreign;
|
|
/**
|
|
* @var integer $type bind type
|
|
*/
|
|
protected $type;
|
|
/**
|
|
* @var string $alias relation alias
|
|
*/
|
|
protected $alias;
|
|
|
|
/**
|
|
* @param Doctrine_Table $table
|
|
* @param string $local
|
|
* @param string $foreign
|
|
* @param integer $type
|
|
* @param string $alias
|
|
*/
|
|
public function __construct(Doctrine_Table $table, $local, $foreign, $type, $alias) {
|
|
$this->table = $table;
|
|
$this->local = $local;
|
|
$this->foreign = $foreign;
|
|
$this->type = $type;
|
|
$this->alias = $alias;
|
|
}
|
|
/**
|
|
* getAlias
|
|
* returns the relation alias
|
|
*
|
|
* @return string
|
|
*/
|
|
final public function getAlias() {
|
|
return $this->alias;
|
|
}
|
|
/**
|
|
* getType
|
|
* returns the relation type, either 0 or 1
|
|
*
|
|
* @see Doctrine_Relation MANY_* and ONE_* constants
|
|
* @return integer
|
|
*/
|
|
final public function getType() {
|
|
return $this->type;
|
|
}
|
|
/**
|
|
* getTable
|
|
* returns the foreign table object
|
|
*
|
|
* @return object Doctrine_Table
|
|
*/
|
|
final public function getTable() {
|
|
return $this->table;
|
|
}
|
|
/**
|
|
* getLocal
|
|
* returns the name of the local column
|
|
*
|
|
* @return string
|
|
*/
|
|
final public function getLocal() {
|
|
return $this->local;
|
|
}
|
|
/**
|
|
* getForeign
|
|
* returns the name of the foreignkey column where
|
|
* the localkey column is pointing at
|
|
*
|
|
* @return string
|
|
*/
|
|
final public function getForeign() {
|
|
return $this->foreign;
|
|
}
|
|
/**
|
|
* isComposite
|
|
* returns whether or not this relation is a composite relation
|
|
*
|
|
* @return boolean
|
|
*/
|
|
final public function isComposite() {
|
|
return ($this->type == Doctrine_Relation::ONE_COMPOSITE ||
|
|
$this->type == Doctrine_Relation::MANY_COMPOSITE);
|
|
}
|
|
/**
|
|
* isOneToOne
|
|
* returns whether or not this relation is a one-to-one relation
|
|
*
|
|
* @return boolean
|
|
*/
|
|
final public function isOneToOne() {
|
|
return ($this->type == Doctrine_Relation::ONE_AGGREGATE ||
|
|
$this->type == Doctrine_Relation::ONE_COMPOSITE);
|
|
}
|
|
/**
|
|
* getRelationDql
|
|
*
|
|
* @param integer $count
|
|
* @return string
|
|
*/
|
|
public function getRelationDql($count) {
|
|
$dql = "FROM ".$this->table->getComponentName().
|
|
" WHERE ".$this->table->getComponentName(). '.' . $this->foreign.
|
|
" IN (".substr(str_repeat("?, ", $count),0,-2).")";
|
|
|
|
return $dql;
|
|
}
|
|
/**
|
|
* getDeleteOperations
|
|
*
|
|
* get the records that need to be deleted in order to change the old collection
|
|
* to the new one
|
|
*
|
|
* The algorithm here is very simple and definitely not
|
|
* the fastest one, since we have to iterate through the collections twice.
|
|
* the complexity of this algorithm is O(n^2)
|
|
*
|
|
* We iterate through the old collection and get the records
|
|
* that do not exists in the new collection (Doctrine_Records that need to be deleted).
|
|
*
|
|
* @param Doctrine_Collection $old
|
|
* @param Doctrine_Collection $new
|
|
* @return array
|
|
*/
|
|
public static function getDeleteOperations(Doctrine_Collection $old, Doctrine_Collection $new) {
|
|
$r = array();
|
|
|
|
foreach ($old as $k => $record) {
|
|
$id = $record->getIncremented();
|
|
|
|
if (empty($id)) {
|
|
continue;
|
|
}
|
|
$found = false;
|
|
foreach ($new as $k2 => $record2) {
|
|
if ($record2->getIncremented() === $record->getIncremented()) {
|
|
$found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( ! $found) {
|
|
$r[] = $record;
|
|
unset($old[$k]);
|
|
}
|
|
}
|
|
|
|
return $r;
|
|
}
|
|
/**
|
|
* getInsertOperations
|
|
*
|
|
* get the records that need to be added in order to change the old collection
|
|
* to the new one
|
|
*
|
|
* The algorithm here is very simple and definitely not
|
|
* the fastest one, since we have to iterate through the collections twice.
|
|
* the complexity of this algorithm is O(n^2)
|
|
*
|
|
* We iterate through the old collection and get the records
|
|
* that exists only in the new collection (Doctrine_Records that need to be added).
|
|
*
|
|
* @param Doctrine_Collection $old
|
|
* @param Doctrine_Collection $new
|
|
* @return array
|
|
*/
|
|
public static function getInsertOperations(Doctrine_Collection $old, Doctrine_Collection $new) {
|
|
$r = array();
|
|
|
|
foreach ($new as $k => $record) {
|
|
$found = false;
|
|
|
|
$id = $record->getIncremented();
|
|
if ( ! empty($id)) {
|
|
foreach ($old as $k2 => $record2) {
|
|
if ($record2->getIncremented() === $record->getIncremented()) {
|
|
$found = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if ( ! $found) {
|
|
$old[] = $record;
|
|
$r[] = $record;
|
|
}
|
|
}
|
|
|
|
return $r;
|
|
}
|
|
/**
|
|
* fetchRelatedFor
|
|
*
|
|
* fetches a component related to given record
|
|
*
|
|
* @param Doctrine_Record $record
|
|
* @return Doctrine_Record|Doctrine_Collection
|
|
*/
|
|
abstract public function fetchRelatedFor(Doctrine_Record $record);
|
|
/**
|
|
* __toString
|
|
*
|
|
* @return string
|
|
*/
|
|
public function __toString() {
|
|
$r[] = "<pre>";
|
|
$r[] = "Class : ".get_class($this);
|
|
$r[] = "Component : ".$this->table->getComponentName();
|
|
$r[] = "Table : ".$this->table->getTableName();
|
|
$r[] = "Local key : ".$this->local;
|
|
$r[] = "Foreign key : ".$this->foreign;
|
|
$r[] = "Type : ".$this->type;
|
|
$r[] = "</pre>";
|
|
return implode("\n", $r);
|
|
}
|
|
}
|