protected function prepareJoinReference($reference, $alias_this, $alias_ref, $baseDefinition, $refDefinition, $isBackReference)
{
$new = array();
foreach ($reference as $k => $v)
{
if ($k === 'LOGIC')
{
$new[$k] = $v;
continue;
}
if (is_numeric($k))
{
// subfilter, recursive call
$new[$k] = $this->prepareJoinReference($v, $alias_this, $alias_ref, $baseDefinition, $refDefinition, $isBackReference);
}
else
{
// key
$sqlWhere = new \CSQLWhere();
$csw_result = $sqlWhere->makeOperation($k);
list($field, $operation) = array_values($csw_result);
if (strpos($field, 'this.') === 0)
{
// parse the chain
$definition = str_replace(\CSQLWhere::getOperationByCode($operation).'this.', '', $k);
$absDefinition = $baseDefinition <> ''? $baseDefinition.'.'.$definition : $definition;
$chain = $this->getRegisteredChain($absDefinition, true);
if (!$isBackReference)
{
// make sure these fields will be joined before the main join
$this->buildJoinMap(array($chain));
}
else
{
$chain->getLastElement()->setParameter('talias', $alias_this);
}
// recursively collect all "build_from" fields
if ($chain->getLastElement()->getValue() instanceof ExpressionField)
{
$this->collectExprChains($chain);
$buildFrom = $chain->getLastElement()->getValue()->getBuildFromChains();
foreach ($buildFrom as $bf)
{
// set base chain
$baseChain = clone $chain;
// remove the last one - expression itself
$baseChain->removeLastElement();
// remove parent entity for this child
$bf->removeFirstElement();
// set new parents
$bf->prepend($baseChain);
}
$this->buildJoinMap($buildFrom);
}
$k = \CSQLWhere::getOperationByCode($operation).$chain->getSqlDefinition();
}
elseif (strpos($field, 'ref.') === 0)
{
$definition = str_replace(\CSQLWhere::getOperationByCode($operation).'ref.', '', $k);
if (strpos($definition, '.') !== false)
{
throw new Main\ArgumentException(sprintf(
'Reference chain `%s` is not allowed here. First-level definitions only.', $field
));
}
$absDefinition = $refDefinition <> ''? $refDefinition.'.'.$definition : $definition;
$chain = $this->getRegisteredChain($absDefinition, true);
if ($isBackReference)
{
// make sure these fields will be joined before the main join
$this->buildJoinMap(array($chain));
}
else
{
$chain->getLastElement()->setParameter('talias', $alias_ref);
}
// recursively collect all "build_from" fields
if ($chain->getLastElement()->getValue() instanceof ExpressionField)
{
$this->collectExprChains($chain);
$this->buildJoinMap($chain->getLastElement()->getValue()->getBuildFromChains());
}
$k = \CSQLWhere::getOperationByCode($operation).$chain->getSqlDefinition();
}
else
{
throw new Main\SystemException(sprintf('Unknown reference key `%s`, it should start with "this." or "ref."', $k));
}
// value
if (is_array($v))
{
// field = expression
$v = new \CSQLWhereExpression($v[0], array_slice($v, 1));
}
elseif ($v instanceof Main\DB\SqlExpression)
{
// set entity connection
$v->setConnection($this->entity->getConnection());
}
elseif (!is_object($v))
{
if (strpos($v, 'this.') === 0)
{
$definition = str_replace('this.', '', $v);
$absDefinition = $baseDefinition <> ''? $baseDefinition.'.'.$definition : $definition;
$chain = $this->getRegisteredChain($absDefinition, true);
if (!$isBackReference)
{
// make sure these fields will be joined before the main join
$this->buildJoinMap(array($chain));
}
else
{
$chain->getLastElement()->setParameter('talias', $alias_this);
}
// recursively collect all "build_from" fields
if ($chain->getLastElement()->getValue() instanceof ExpressionField)
{
$this->collectExprChains($chain);
$buildFrom = $chain->getLastElement()->getValue()->getBuildFromChains();
foreach ($buildFrom as $bf)
{
// set base chain
$baseChain = clone $chain;
// remove the last one - expression itself
$baseChain->removeLastElement();
// remove parent entity for this child
$bf->removeFirstElement();
// set new parents
$bf->prepend($baseChain);
}
$this->buildJoinMap($buildFrom);
}
$field_def = $chain->getSqlDefinition();
}
elseif (strpos($v, 'ref.') === 0)
{
$definition = str_replace('ref.', '', $v);
if (strpos($definition, '.') !== false)
{
throw new Main\ArgumentException(sprintf(
'Reference chain `%s` is not allowed here. First-level definitions only.', $v
));
}
$absDefinition = $refDefinition <> ''? $refDefinition.'.'.$definition : $definition;
$chain = $this->getRegisteredChain($absDefinition, true);
if ($isBackReference)
{
// make sure these fields will be joined before the main join
$this->buildJoinMap(array($chain));
}
else
{
$chain->getLastElement()->setParameter('talias', $alias_ref);
}
$this->buildJoinMap(array($chain));
// recursively collect all "build_from" fields
if ($chain->getLastElement()->getValue() instanceof ExpressionField)
{
// here could be one more check "First-level definitions only" for buildFrom elements
$buildFromChains = $this->collectExprChains($chain);
// set same talias to buildFrom elements
foreach ($buildFromChains as $buildFromChain)
{
if (!$isBackReference && $buildFromChain->getSize() > $chain->getSize())
{
throw new Main\ArgumentException(sprintf(
'Reference chain `%s` is not allowed here. First-level definitions only.',
$buildFromChain->getDefinition()
));
}
if ($buildFromChain->getSize() === $chain->getSize())
{
// same entity, same table
$buildFromChain->getLastElement()->setParameter('talias', $alias_ref);
}
}
$this->buildJoinMap($buildFromChains);
}
$field_def = $chain->getSqlDefinition();
}
else
{
throw new Main\SystemException(sprintf('Unknown reference value `%s`', $v));
}
$v = new \CSQLWhereExpression($field_def);
}
else
{
throw new Main\SystemException(sprintf('Unknown reference value `%s`, it should start with "this." or "ref."', $v));
}
$new[$k] = $v;
}
}
return $new;
}