<?php
/**
* Copyright (c) 2008, SARL Adaltas. All rights reserved.
* Code licensed under the BSD License:
* http://porte.adaltas.com/en/developer/license.html
*/
/**
* PorteOneToManyBelongsTo
*
* @package Porte
* @subpackage plugin
* @author David Worms info(at)adaltas.com
* @copyright 2008 Adaltas
*/
class PorteManyToManyJoin{
public static function setRecord($property,$record,$assocRecords){
return self::setRecords($property,$record,$assocRecords);
}
public static function setRecords($property,$record,$assocRecords){
$config = $record->porte->models->{$record->type}['properties'][$property];
$assocRecords = new PorteIterator($record->porte->tables->{$config['has_many']['type']},$assocRecords);
if(!isset($record->associations[$property])){
$record->associations[$property] = new PorteIterator(
$record->table,
// Preload PorteIterator with primary_keys
(isset($record->attributes[$property]))?explode(',',$record->attributes[$property]):array()
);
}else{
// Keep the same instance of PorteIterator but remove its content
foreach($record->associations[$property]->array as $k=>$v){
unset($record->associations[$property]->array[$k]);
}
}
//$record->associations[$property]->mode = 'set';
$record->associations[$property]->remove_existing_associations = true;
if(empty($assocRecords)) return $record;
foreach($assocRecords as $assocRecord){
$record->associations[$property]->array[] = $assocRecord;
}
return $record;
}
/**
* many-to-many with a join table
*
* @return PorteIterator Iterator containing the associated records
* @param $property String Name of the property being accessed
* @param $record PorteRecord
* @param $assocRecord PorteIterator Record to be associated with the current record
*/
public static function addRecord($property,$record,$assocRecord){
return PorteManyToManyListPersisted::addRecord($property,$record,$assocRecord);
}
/**
* many-to-many with a join table
*
* @return PorteIterator Iterator containing the associated records
* @param $property String Name of the property being accessed
* @param $record PorteRecord
* @param $assocRecords PorteIterator Records to be associated with the current record
*/
public static function addRecords($property,$record,$assocRecords){
// @todo This descently can't work, it call the load(force) method based on the
// existence of attributes[property] and it at some other places
return PorteManyToManyListPersisted::addRecords($property,$record,$assocRecords);
}
/**
* many-to-many with a join table
*
* @return PorteIterator Iterator containing the associated records
* @param $property String Name of the property being accessed
* @param $record PorteRecord
* @param $options array[optional] Optional array
*/
public static function getRecords($property,$record,$options=array()){
$config = $record->porte->models->{$record->type}['properties'][$property];
$assocModel = $record->porte->models->{$config['has_many']['type']};
$assocConfig = $assocModel['properties'][$config['has_many']['property']];
// Load record from db if not already done
//if(!array_key_exists($property,$record->associations)&&!$record->isNew()){
//$record->load($record->getIdentifier(),array('force'=>true));
//}
// todo: move this in else condition
$options = array_merge(array(
'select'=>'`'.$assocModel['table'].'`.*',
'where'=>'1 ',
),$options);
if(isset($record->associations[$property])){
$assocRecords = $record->associations[$property];
foreach($assocRecords as $key=>$assocRecord){
if(is_int($assocRecord)){
$record->associations[$property]->array[$key] =
$record->porte->tables->{$config['has_many']['type']}->load($assocRecord);
}
}
return $assocRecords;
}else if($record->isNew()){
return $record->associations[$property] = new PorteIterator($record->table,array());
}else{
if(is_array($config['has_many']['join']['field'])){
$options['from'] = ' `'.$assocModel['database'].'`.`'.$assocModel['table'].'`, `'.$config['has_many']['join']['database'].'`.`'.$config['has_many']['join']['table'].'` ';
$options['where'] .= ' AND (`'.$config['has_many']['join']['database'].'`.`'.$config['has_many']['join']['table'].'`.`'.$config['has_many']['join']['field'][0].'` = `'.$assocModel['database'].'`.`'.$assocModel['table'].'`.`'.$assocModel['primary_key'].'` AND `'.$config['has_many']['join']['database'].'`.`'.$config['has_many']['join']['table'].'`.`'.$config['has_many']['join']['field'][1].'` = \''.$record->getIdentifier().'\') OR (`'.$config['has_many']['join']['database'].'`.`'.$config['has_many']['join']['table'].'`.`'.$config['has_many']['join']['field'][1].'` = `'.$assocModel['database'].'`.`'.$assocModel['table'].'`.`'.$assocModel['primary_key'].'` AND `'.$config['has_many']['join']['database'].'`.`'.$config['has_many']['join']['table'].'`.`'.$config['has_many']['join']['field'][0].'` = \''.$record->getIdentifier().'\')';
}else{
$options['from'] = ' `'.$assocModel['database'].'`.`'.$assocModel['table'].'` INNER JOIN `'.$config['has_many']['join']['database'].'`.`'.$config['has_many']['join']['table'].'` ON `'.$assocConfig['has_many']['join']['database'].'`.`'.$assocConfig['has_many']['join']['table'].'`.`'.$assocConfig['has_many']['join']['field'].'` = `'.$assocModel['database'].'`.`'.$assocModel['table'].'`.`'.$assocModel['primary_key'].'`';
$options['where'] .= ' AND `'.$config['has_many']['join']['database'].'`.`'.$config['has_many']['join']['table'].'`.`'.$config['has_many']['join']['field'].'` = \''.$record->getIdentifier().'\' ';
}
return $record->associations[$property] = $record->porte->tables->get($config['has_many']['type'])->find($options);
}
}
public static function deleteRecord($property,$record,$id){
self::deleteRecords($property,$record,$id);
}
public static function deleteRecords($property,$record,$assocRecords=array()){
$model = $record->porte->models->{$record->type};
$config = $model['properties'][$property];
/*
if(is_string($assocRecords)){
$assocRecords = explode(',',$assocRecords);
}else if(is_int($assocRecords)){
$assocRecords = array(strval($assocRecords));
}else if(is_array($assocRecords)){
foreach($assocRecords as $k=>$assocRecord){
if(is_object($assocRecord)){
$assocRecords[$k] = strval($assocRecord->getIdentifier());
}else if(is_int($assocRecord)||ctype_digit($assocRecord)){
$assocRecords[$k] = strval($assocRecord);
}
}
}else if($assocRecords instanceof PorteRecord){
$assocRecords = array($assocRecords->getIdentifier());
}
*/
$assocRecords = new PorteIterator($record->porte->tables->{$config['has_many']['type']},$assocRecords);
$assocRecords = $assocRecords->getIdentifier();
$primaryKey = $model['primary_key'];
$primaryKeyValue = $record->getIdentifier();
$joinDb = $config['has_many']['join']['database'];
$joinTable = $config['has_many']['join']['table'];
$joinField = $config['has_many']['join']['field'];
$assocConfig = $record->porte->models->{$config['has_many']['type']}['properties'][$config['has_many']['property']];
$joinRelatedField = $assocConfig['has_many']['join']['field'];
$query = 'DELETE `'.$joinDb.'`.`'.$joinTable.'`.* FROM `'.$joinDb.'`.`'.$joinTable.'` INNER JOIN `'.$model['database'].'`.`'.$model['table'].'` ON `'.$model['database'].'`.`'.$model['table'].'`.`'.$primaryKey.'` = `'.$joinDb.'`.`'.$joinTable.'`.`'.$joinField.'` WHERE `'.$model['database'].'`.`'.$model['table'].'`.`'.$primaryKey.'` = \''.$primaryKeyValue.'\'';
if(!empty($assocRecords)){
$query .= 'AND FIND_IN_SET(`'.$joinDb.'`.`'.$joinTable.'`.`'.$joinRelatedField.'`,\''.implode(',',$assocRecords).'\')';
}
$query .= ';';
$record->porte->exec($query);
if(empty($assocRecords)){
$record->associations[$property] = new PorteIterator($record->table);
}else{
$hum = $record->associations[$property]->array;
foreach($hum as $key=>$association){
if(in_array($association->getIdentifier(),$assocRecords)){
unset($hum[$key]);
}
}
// Re-index the array
$record->associations[$property]->array = array_values($hum);
$record->associations[$property]->rewind();
}
return $assocRecords;
//throw new PorteException('Error while deleting associations: '.$query);
}
public static function countRecords($property,$record,$options=array()){
$config = $record->porte->models->{$record->type}['properties'][$property];
$assocModel = $record->porte->models->{$config['has_many']['type']};
$options = array_merge(array(
'select'=>'count(*)',
'from'=>'`'.$config['has_many']['join']['database'].'`.`'.$config['has_many']['join']['table'].'`',
'where'=>'1',
),$options);
$options['where'] .= ' AND `'.$config['has_many']['join']['database'].'`.`'.$config['has_many']['join']['table'].'`.`'.$config['has_many']['join']['field'].'` = \''.$record->getIdentifier().'\'';
return intval($record->porte->query($record->table->find(array_merge($options,array('return_sql'=>true,'limit'=>null))))->fetchColumn());
}
public static function save($property,$record,&$circular){
// @todo this is very slow since we loop through each record an make 2 queries for each
// (one select count and on insert).
//http://www.xaprb.com/blog/2005/09/25/insert-if-not-exists-queries-in-mysql/
//http://forums.mysql.com/read.php?97,164551,164551
$config = $record->porte->models->{$record->type}['properties'][$property];
$assocConfig = $record->porte->models->{$config['has_many']['type']}['properties'][$config['has_many']['property']];
$assocRecords = $record->associations[$property];
$pks = array();
foreach($assocRecords as $assocRecord){
if($assocRecord instanceof PorteRecord && !$assocRecord->isNew()){
$pks[] = $assocRecord->save($circular)->getIdentifier();
}else if($assocRecord instanceof PorteRecord){
$pks[] = $assocRecord->save($circular)->getIdentifier();
}else if(is_int($assocRecord)||(is_string($assocRecord)&&(int)$assocRecord!=0)){
$pks[] = $assocRecord;
}
}
$assocRecords->rewind();
if(!empty($assocRecords->remove_existing_associations)){
$assocRecords->remove_existing_associations = false;
if(is_array($config['has_many']['join']['field'])){
$query = 'DELETE FROM `'.$config['has_many']['join']['database'].'`.`'.$config['has_many']['join']['table'].'` WHERE (`'.$config['has_many']['join']['field'][0].'`=\''.$record->getIdentifier().'\') OR (`'.$config['has_many']['join']['field'][1].'`=\''.$record->getIdentifier().'\') ';
}else{
$query = 'DELETE FROM `'.$config['has_many']['join']['database'].'`.`'.$config['has_many']['join']['table'].'` WHERE `'.$config['has_many']['join']['field'].'`=\''.$record->getIdentifier().'\'; ';
}
$record->porte->exec($query);
}
if(!empty($pks)){
if(is_array($config['has_many']['join']['field'])){
$query = 'SELECT `'.$config['has_many']['join']['field'][0].'`,`'.$config['has_many']['join']['field'][0].'` FROM `'.$config['has_many']['join']['database'].'`.`'.$config['has_many']['join']['table'].'` as `join_table` WHERE (`join_table`.`'.$config['has_many']['join']['field'][0].'`=\''.$record->getIdentifier().'\' AND FIND_IN_SET(`join_table`.`'.$config['has_many']['join']['field'][1].'`,\''.implode(',',$pks).'\')) OR (FIND_IN_SET(`join_table`.`'.$config['has_many']['join']['field'][0].'`,\''.implode(',',$pks).'\') AND `join_table`.`'.$config['has_many']['join']['field'][1].'`=\''.$record->getIdentifier().'\') ';
}else{
$query = 'SELECT `'.$assocConfig['has_many']['join']['field'].'` FROM `'.$config['has_many']['join']['database'].'`.`'.$config['has_many']['join']['table'].'` as `join_table` WHERE `join_table`.`'.$config['has_many']['join']['field'].'`=\''.$record->getIdentifier().'\' AND FIND_IN_SET(`join_table`.`'.$assocConfig['has_many']['join']['field'].'`,\''.implode(',',$pks).'\'); ';
}
$existingPks = array();
$statement = $record->porte->query($query);
while($row = $statement->fetch(Porte::FETCH_NUM)){
$existingPks[] = $row[0];
if(is_array($config['has_many']['join']['field'])){
$existingPks[] = $row[1];
}
}
$statement->closeCursor();
if(is_array($config['has_many']['join']['field'])){
$pks = array_unique($pks);
}
$pks = array_diff($pks,$existingPks);
if(!empty($pks)){
foreach($pks as $pk){
if(is_array($config['has_many']['join']['field'])){
$query = 'INSERT INTO `'.$config['has_many']['join']['database'].'`.`'.$config['has_many']['join']['table'].'` (`'.$config['has_many']['join']['field'][0].'`,`'.$config['has_many']['join']['field'][1].'`) VALUES (\''.$record->getIdentifier().'\',\''.$pk.'\');';
}else{
$query = 'INSERT INTO `'.$config['has_many']['join']['database'].'`.`'.$config['has_many']['join']['table'].'` (`'.$config['has_many']['join']['database'].'`.`'.$config['has_many']['join']['table'].'`.`'.$config['has_many']['join']['field'].'`,`'.$assocConfig['has_many']['join']['database'].'`.`'.$assocConfig['has_many']['join']['table'].'`.`'.$assocConfig['has_many']['join']['field'].'`) VALUES (\''.$record->getIdentifier().'\',\''.$pk.'\');';
}
$record->porte->exec($query);
//throw new PorteException('Error saving on join table: '.$query);
}
}
}
}
}
?>