<?php
/**
* Copyright (c) 2008, SARL Adaltas. All rights reserved.
* Code licensed under the BSD License:
* http://porte.adaltas.com/en/developer/license.html
*/
/**
* PorteOneToManyHasMany
*
* @package Porte
* @subpackage plugin
* @author David Worms info(at)adaltas.com
* @copyright 2008 Adaltas
*/
class PorteOneToManyHasMany{
/**
* One-to-many from the belongs_to (many) side
*
* @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 PorteOneToManyHasMany::addRecords($property,$record,$assocRecord);
}
/**
* One-to-many from the belongs_to (many) side
*
* @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){
$config = $record->porte->models->{$record->type}['properties'][$property];
$assocRecords = new PorteIterator($record->porte->tables->get($config['has_many']['type']),$assocRecords);
if(!$assocRecords->count()) return $record;
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()
);
}
foreach($assocRecords as $assocRecord){
$skip = false;
// Make sure we do not create twice the same association
foreach($record->associations[$property] as $registeredRecord){
if($assocRecord->isNew() && $registeredRecord===$assocRecord){
$skip = true;
break;
}else if(!$assocRecord->isNew() && $registeredRecord->getIdentifier() == $assocRecord->getIdentifier()){
$skip = true;
break;
}
}
$record->associations[$property]->rewind();
if(!$skip){
$record->associations[$property]->array[] = $assocRecord;
//$config = $record->model->properties->$property;
//$assocModel = $record->porte->models->{$config['has_many']['type']};
$assocProperty = $config['has_many']['property'];
PorteOneToManyBelongsTo::setRecord($assocProperty,$assocRecord,$record);
}
}
return $record;
}
/**
* One-to-many from the belongs_to (many) side
*
* @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,PorteRecord $record,array $options=array()){
$model = $record->porte->models->{$record->type};
$config = $model['properties'][$property];
$assocModel = $record->porte->models->{$config['has_many']['type']};
$assocProperty = $config['has_many']['property'];
$assocConfig = $assocModel['properties'][$assocProperty];
$primaryKeyField = $model['primary_key'];
$primaryKeyValue = $record->getIdentifier();
$options = array_merge(array(
'select'=>'`'.$assocModel['database'].'`.`'.$assocModel['table'].'`.*',
'from'=>'`'.$assocModel['database'].'`.`'.$assocModel['table'].'` INNER JOIN `'.$model['database'].'`.`'.$model['table'].'` on `'.$model['database'].'`.`'.$model['table'].'`.'.$model['primary_key'].' = `'.$assocModel['database'].'`.`'.$assocModel['table'].'`.`'.$assocConfig['field'].'`',
'where'=>'`'.$assocModel['database'].'`.`'.$assocModel['table'].'`.`'.$assocConfig['field'].'` = \''.$primaryKeyValue.'\'',
),$options);
$options['where'] .= ' AND `'.$assocModel['database'].'`.`'.$assocModel['table'].'`.`'.$assocConfig['field'].'` = \''.$primaryKeyValue.'\'';
$assocRecords = $record->porte->tables->{$config['has_many']['type']}->find($options);
/*
foreach($assocRecords as $assocRecord){
// This is nice but it create circular references we were not able to digg at the time
// See OneToManyBelongsToTest->testDelete
//call_user_func(array($assocRecord,'set'.PorteUtils::camelize($assocProperty)),$record);
}
$assocRecords->rewind();
*/
return $record->associations[$property] = $assocRecords;
}
public static function deleteRecords($property,PorteRecord $record){
$config = $record->porte->models->{$record->type}['properties'][$property];
$assocModel = $record->porte->models->{$config['has_many']['type']};
$query = 'update '.$assocModel['database'].'.'.$assocModel['table'].' SET '.$config['has_many']['property'].' = null WHERE '.$config['has_many']['property'].'=\''.$record->getIdentifier().'\'';
$record->porte->exec($query);
return $record;
}
public static function countRecords($property,$record,$options=array()){
$model = $record->porte->models->{$record->type};
$config = $model['properties'][$property];
$assocModel = $record->porte->models->{$config['has_many']['type']};
$assocConfig = $assocModel['properties'][$config['has_many']['property']];
$options = array_merge(array(
'select'=>'count(*)',
'from'=>'`'.$assocModel['database'].'`.`'.$assocModel['table'].'` INNER JOIN `'.$model['database'].'`.`'.$model['table'].'` on `'.$model['database'].'`.`'.$model['table'].'`.'.$model['primary_key'].' = `'.$assocModel['database'].'`.`'.$assocModel['table'].'`.`'.$assocConfig['field'].'`',
'where'=>'1',
),$options);
$options['where'] .= ' AND `'.$assocModel['database'].'`.`'.$assocModel['table'].'`.`'.$assocConfig['field'].'` = \''.$record->getIdentifier().'\'';
// todo: why are we not calling find without execute?
return intval($record->porte->query($record->table->find(array_merge($options,array('return_sql'=>true,'limit'=>null))))->fetchColumn());
}
}
?>