protected function assembleConnectedDatasetSourceStatement(DataControllerCallContext $callcontext, ReferenceLink $link, array $columnNames, array $linkExecutionStack = NULL)
 {
     $TABLE_ALIAS__LINK = 'l';
     $nestedLinkExecutionStack = $linkExecutionStack;
     $nestedLinkExecutionStack[] = $link;
     $selectedColumnNames = ReferenceLinkBuilder::selectReferencedColumnNames4ReferenceLink($nestedLinkExecutionStack, $columnNames);
     $linkTableAliasPrefix = $TABLE_ALIAS__LINK . $link->linkId;
     $statement = $this->assembleDatasetSourceStatement($callcontext, $link->dataset, $selectedColumnNames);
     $statement->addTableAliasPrefix($linkTableAliasPrefix);
     // adding columns which we use to join with parent dataset
     if (!$link->isRoot()) {
         foreach ($link->columnNames as $columnName) {
             $joinColumnAlias = ReferencePathHelper::assembleDatabaseColumnName($this->getMaximumEntityNameLength(), ReferencePathHelper::assembleReference($link->dataset->name, $columnName));
             $joinTable = $statement->findColumnTable($columnName);
             if (!isset($joinTable)) {
                 $joinTable = $statement->tables[0];
             }
             $joinColumn = $joinTable->findColumnByAlias($joinColumnAlias);
             if (!isset($joinColumn)) {
                 $joinTable->columns[] = new ColumnSection($columnName, $joinColumnAlias);
             }
         }
     }
     // adding columns which we use to join with nested datasets
     if (isset($link->nestedLinks)) {
         foreach ($link->nestedLinks as $nestedLink) {
             foreach ($nestedLink->parentColumnNames as $parentColumnName) {
                 $parentColumnAlias = ReferencePathHelper::assembleDatabaseColumnName($this->getMaximumEntityNameLength(), ReferencePathHelper::assembleReference($link->dataset->name, $parentColumnName));
                 $joinTable = $statement->getColumnTable($parentColumnName);
                 $joinColumn = $joinTable->findColumnByAlias($parentColumnAlias);
                 if (!isset($joinColumn)) {
                     $joinTable->columns[] = new ColumnSection($parentColumnName, $parentColumnAlias);
                 }
             }
         }
     }
     // collecting columns which we need to mark as invisible
     $shouldBeInvisibleColumns = NULL;
     foreach ($statement->tables as $table) {
         if (isset($table->columns)) {
             foreach ($table->columns as $column) {
                 $shouldBeInvisibleColumns[$table->alias][$column->alias] = $column;
             }
         } else {
             $table->columns = array();
             // We do not need any columns
         }
     }
     // adding or making as visible columns which we need to return
     if (isset($selectedColumnNames)) {
         foreach ($selectedColumnNames as $originalColumnName => $selectedColumnName) {
             // we need to show only those columns which are requested.
             // All intermediate columns (which are used to link with nested datasets) will not be shown
             if (array_search($originalColumnName, $columnNames) !== FALSE) {
                 $databaseColumnName = ReferencePathHelper::assembleDatabaseColumnName($this->getMaximumEntityNameLength(), $originalColumnName);
                 $table = $statement->getColumnTable($selectedColumnName, TRUE);
                 $column = $table->findColumnByAlias($databaseColumnName);
                 if (isset($column)) {
                     $column->visible = TRUE;
                     unset($shouldBeInvisibleColumns[$table->alias][$column->alias]);
                 } else {
                     $column = $table->findColumnByAlias($selectedColumnName);
                     if (isset($column)) {
                         // adding clone of the same column with another alias
                         $column = clone $column;
                         $column->visible = TRUE;
                         $column->alias = $databaseColumnName;
                     } else {
                         $column = new ColumnSection($selectedColumnName, $databaseColumnName);
                     }
                     $table->columns[] = $column;
                 }
                 $callcontext->columnMapping[$databaseColumnName] = $originalColumnName;
             }
         }
     }
     if (isset($shouldBeInvisibleColumns)) {
         foreach ($shouldBeInvisibleColumns as $tableColumns) {
             foreach ($tableColumns as $column) {
                 $column->visible = FALSE;
             }
         }
     }
     // supporting nested links
     if (isset($link->nestedLinks)) {
         foreach ($link->nestedLinks as $nestedLink) {
             $nestedStatement = $this->assembleConnectedDatasetSourceStatement($callcontext, $nestedLink, $columnNames, $nestedLinkExecutionStack);
             foreach ($nestedLink->parentColumnNames as $referencePointColumnIndex => $parentColumnName) {
                 // preparing parent table alias
                 $parentColumnAlias = ReferencePathHelper::assembleDatabaseColumnName($this->getMaximumEntityNameLength(), ReferencePathHelper::assembleReference($link->dataset->name, $parentColumnName));
                 $parentTableAlias = $statement->getColumnTable($parentColumnAlias)->alias;
                 // linking with parent
                 $nestedColumnName = $nestedLink->columnNames[$referencePointColumnIndex];
                 $nestedColumnAlias = ReferencePathHelper::assembleDatabaseColumnName($this->getMaximumEntityNameLength(), ReferencePathHelper::assembleReference($nestedLink->dataset->name, $nestedColumnName));
                 $nestedStatement->getColumnTable($nestedColumnAlias)->conditions[] = new JoinConditionSection($nestedColumnName, new TableColumnConditionSectionValue($parentTableAlias, $parentColumnName));
             }
             $statement->merge($nestedStatement);
         }
     }
     return $statement;
 }
    protected function detectRoutes(ReferenceLink $rootLink, array $referencePaths) {
        $routeId = 0;
        foreach ($referencePaths as $referencePath => $required) {
            // preparing possible routes
            $referenceRoutes = $rootLink->prepareRoutes($referencePath);

            // selecting 'the best' route
            $selectedRoute = NULL;
            if (isset($referenceRoutes)) {
                foreach ($referenceRoutes as $directReferenceFlag => $routes) {
                    foreach ($routes as $route) {
                        if (!isset($selectedRoute) || ($selectedRoute->weight > $route->weight)) {
                            $selectedRoute = $route;
                        }
                    }
                }
            }

            if (isset($selectedRoute)) {
                $rootLink->assignRouteId($selectedRoute, $routeId);
                $routeId++;
            }
            elseif ($required) {
                $metamodel = data_controller_get_metamodel();

                LogHelper::log_error(t('Could not execute reference path: @referencePath', array('@referencePath' => $referencePath)));

                list($referencedDatasetName) = ReferencePathHelper::splitReference($referencePath);
                $referencedDataset = $metamodel->getDataset($referencedDatasetName);

                throw new IllegalArgumentException(t(
                    '%datasetNameA and %datasetNameB datasets are not connected',
                    array('%datasetNameA' => $rootLink->dataset->publicName, '%datasetNameB' => $referencedDataset->publicName)));
            }
        }
    }