Пример #1
0
 /**
  * @param $referencePath
  * @param null $parentColumnName
  * @return ReferenceRoute[]
  */
 public function prepareRoutes($referencePath, $parentColumnName = NULL)
 {
     $routes = NULL;
     $referenceParts = ReferencePathHelper::splitReference($referencePath);
     $columnName = array_pop($referenceParts);
     $datasetName = array_pop($referenceParts);
     // checking that dataset is the same and parent column name is the same
     $isReferenceFound = $this->dataset->name == $datasetName && (!isset($parentColumnName) || array_search($parentColumnName, $this->parentColumnNames) !== FALSE);
     $nestedReferencePath = $isReferenceFound ? ReferencePathHelper::assembleSplitReferenceParts($referenceParts) : $referencePath;
     // it is possible that not full execution path is provided
     if (isset($nestedReferencePath)) {
         if (isset($this->nestedLinks)) {
             $nestedRoutes = NULL;
             foreach ($this->nestedLinks as $nestedLink) {
                 $nestedLinkRoutes = $nestedLink->prepareRoutes($nestedReferencePath, $isReferenceFound ? $columnName : NULL);
                 if (isset($nestedLinkRoutes)) {
                     // current reference could not be found. We mark nested found reference as not direct
                     if (!$isReferenceFound && isset($nestedLinkRoutes[TRUE])) {
                         $adjustedNestedLinkRoutes = null;
                         $adjustedNestedLinkRoutes[FALSE] = $nestedLinkRoutes[TRUE];
                         $nestedRoutes[] = $adjustedNestedLinkRoutes;
                     } else {
                         $nestedRoutes[] = $nestedLinkRoutes;
                     }
                 }
             }
             if (isset($nestedRoutes)) {
                 // checking if we found direct route
                 $isNestedReferenceFound = FALSE;
                 foreach ($nestedRoutes as $nestedLinkRoutes) {
                     if (isset($nestedLinkRoutes[TRUE])) {
                         $isNestedReferenceFound = TRUE;
                         break;
                     }
                 }
                 foreach ($nestedRoutes as $nestedLinkRoutes) {
                     if (!isset($nestedLinkRoutes[$isNestedReferenceFound])) {
                         continue;
                     }
                     foreach ($nestedLinkRoutes[$isNestedReferenceFound] as $nestedLinkRoute) {
                         $route = new ReferenceRoute($this->linkId, $this->weight);
                         $route->combineFrom($nestedLinkRoute);
                         $routes[$isNestedReferenceFound][] = $route;
                     }
                 }
             }
         }
     } elseif ($isReferenceFound) {
         $routes[$isReferenceFound][] = new ReferenceRoute($this->linkId, $this->weight);
     }
     return $routes;
 }
Пример #2
0
 protected function prepareDatasetSequence(ReferenceCallContext $callcontext, MetaModel $metamodel, ReferenceLink $link, $referencePath)
 {
     $referenceParts = ReferencePathHelper::splitReference($referencePath);
     $parentColumnName = array_pop($referenceParts);
     $parentDatasetName = array_pop($referenceParts);
     $referencedColumnName = $referencedDatasetName = NULL;
     $leftReferencePartCount = count($referenceParts);
     $nestedReferencePath = $referencePath;
     if ($link->dataset->name == $parentDatasetName) {
         // dataset is there and it is link's dataset
         if ($leftReferencePartCount == 0) {
             return;
         }
         // assembling new reference path
         $nestedReferencePath = ReferencePathHelper::assembleSplitReferenceParts($referenceParts);
         $referencedColumnName = array_pop($referenceParts);
         $referencedDatasetName = array_pop($referenceParts);
         if (!isset($referencedDatasetName)) {
             throw new UnsupportedOperationException(t('Dataset name is not set in the reference path: @referencePath', array('@referencePath' => $referencePath)));
         }
     } elseif (isset($parentDatasetName)) {
         $referencedColumnName = $parentColumnName;
         $referencedDatasetName = $parentDatasetName;
         $parentColumnName = $parentDatasetName = NULL;
     } else {
         if ($leftReferencePartCount > 0) {
             throw new UnsupportedOperationException(t('Dataset name is not set in the reference path: @referencePath', array('@referencePath' => $referencePath)));
         }
         // it means that we just point to column in link's dataset
         return;
     }
     // checking if there any references which could be used to find required dataset
     $references = $metamodel->findReferencesByDatasetName($link->dataset->name);
     if (!isset($references)) {
         return;
     }
     // checking what references can be used to proceed and
     $selectedReferences = NULL;
     foreach ($references as $reference) {
         if (isset($callcontext->referenceNameStack[$reference->name])) {
             continue;
         }
         $selectedReferences[$reference->name] = $reference;
     }
     if (!isset($selectedReferences)) {
         return;
     }
     // maximum number of columns in direct references
     $directReferencePointColumnCount = NULL;
     // checking if there is any reference which directly link to referenced dataset
     $parentReferencePointIndex4References = $directReferencePointIndex4References = $transitionalReferencePointIndexes4References = NULL;
     foreach ($selectedReferences as $reference) {
         $referencePointColumnCount = $reference->getPointColumnCount();
         // checking if the reference can be used to link with other datasets
         $parentReferencePointIndex4Reference = $directReferencePointIndex4Reference = $transitionalReferencePointIndexes4Reference = NULL;
         for ($referencePointColumnIndex = 0; $referencePointColumnIndex < $referencePointColumnCount; $referencePointColumnIndex++) {
             $parentReferencePointIndex = $directReferencePointIndex = $transitionalReferencePointIndexes = NULL;
             foreach ($reference->points as $referencePointIndex => $referencePoint) {
                 $datasetName = $referencePoint->columns[$referencePointColumnIndex]->datasetName;
                 if ($link->dataset->name == $datasetName && (!isset($parentColumnName) || $parentColumnName == $referencePoint->columns[$referencePointColumnIndex]->columnName)) {
                     if (isset($parentReferencePointIndex)) {
                         // Found several possible ways to start a join from the referring dataset.
                         // That happens because we do not have parent column name and possible join is ambiguous
                         // We cannot use this way to proceed
                         continue 3;
                     } else {
                         $parentReferencePointIndex = $referencePointIndex;
                     }
                 } elseif ($datasetName == $referencedDatasetName) {
                     if (isset($directReferencePointIndex)) {
                         // found several possible ways to join with the referenced dataset
                         continue 3;
                     } else {
                         $directReferencePointIndex[$referencePointIndex] = TRUE;
                     }
                 } else {
                     $transitionalReferencePointIndexes[$referencePointIndex] = FALSE;
                 }
             }
             // this reference cannot be used because none of the reference points linked with parent dataset
             if (!isset($parentReferencePointIndex)) {
                 continue 2;
             }
             if (isset($directReferencePointIndex)) {
                 // if we have direct reference we do not care about indirect ones
                 $transitionalReferencePointIndexes = NULL;
             } else {
                 // there is no direct or indirect ways. This reference is useless :)
                 if (!isset($transitionalReferencePointIndexes)) {
                     continue 2;
                 }
             }
             $parentReferencePointIndex4Reference[$referencePointColumnIndex] = $parentReferencePointIndex;
             if (isset($directReferencePointIndex)) {
                 $directReferencePointIndex4Reference[$referencePointColumnIndex] = $directReferencePointIndex;
             }
             if (isset($transitionalReferencePointIndexes)) {
                 $transitionalReferencePointIndexes4Reference[$referencePointColumnIndex] = $transitionalReferencePointIndexes;
             }
         }
         // we support only direct references between datasets
         // in this case we have direct reference based on some columns only. Rest columns are connected indirectly
         if (isset($directReferencePointIndex4Reference) && isset($transitionalReferencePointIndexes4Reference)) {
             continue;
         }
         $parentReferencePointIndex4References[$reference->name] = $parentReferencePointIndex4Reference;
         if (isset($directReferencePointIndex4Reference)) {
             $directReferencePointIndex4References[$reference->name] = $directReferencePointIndex4Reference;
             $directReferencePointColumnCount = MathHelper::max($directReferencePointColumnCount, $referencePointColumnCount);
         }
         if (isset($transitionalReferencePointIndexes4Reference)) {
             $transitionalReferencePointIndexes4References[$reference->name] = $transitionalReferencePointIndexes4Reference;
         }
     }
     // we could use none of the selected references
     if (!isset($parentReferencePointIndex4References)) {
         return;
     }
     // removing all useless direct and indirect references if there is a direct way
     if (isset($directReferencePointColumnCount)) {
         foreach ($parentReferencePointIndex4References as $referenceName => $parentReferencePointIndex4Reference) {
             $referencePointColumnCount = count($parentReferencePointIndex4Reference);
             if (isset($directReferencePointIndex4References[$referenceName])) {
                 // we preserve only direct ways with maximum number of columns
                 if ($referencePointColumnCount == $directReferencePointColumnCount) {
                     continue;
                 }
             } else {
                 // we preserve only indirect ways with more columns than in direct way
                 if ($referencePointColumnCount > $directReferencePointColumnCount) {
                     continue;
                 }
             }
             unset($parentReferencePointIndex4References[$referenceName]);
             unset($directReferencePointIndex4References[$referenceName]);
             unset($transitionalReferencePointIndexes4References[$referenceName]);
         }
     }
     foreach ($parentReferencePointIndex4References as $referenceName => $parentReferencePointIndex4Reference) {
         $reference = $selectedReferences[$referenceName];
         // registering the reference in a stack to avoid excessive calls
         // registration was moved here because we could have date[->month->quarter->year] and year columns in one dataset
         // if references related to date and year are registered before we start to process individual references
         // we will end up with nested links for date->month->quarter->year which do not contain a reference to year
         // which leads to GOVDB-1313 issue
         $callcontext->referenceNameStack[$reference->name] = TRUE;
         $referencePointColumnCount = $reference->getPointColumnCount();
         $referencePointIndexes4Reference = isset($directReferencePointIndex4References[$referenceName]) ? $directReferencePointIndex4References[$referenceName] : NULL;
         $isDirectReference = isset($referencePointIndexes4Reference);
         if (!$isDirectReference) {
             $referencePointIndexes4Reference = isset($transitionalReferencePointIndexes4References[$referenceName]) ? $transitionalReferencePointIndexes4References[$referenceName] : NULL;
         }
         // preparing dataset names for each reference point
         $referencePointDatasetNames = NULL;
         for ($referencePointColumnIndex = 0; $referencePointColumnIndex < $referencePointColumnCount; $referencePointColumnIndex++) {
             foreach ($referencePointIndexes4Reference[$referencePointColumnIndex] as $referencePointIndex => $directReferencePointFlag) {
                 $referencePointColumn = $reference->points[$referencePointIndex]->columns[$referencePointColumnIndex];
                 $datasetName = $referencePointColumn->datasetName;
                 // it is expected that dataset name is the same for all columns in a reference point
                 if (isset($referencePointDatasetNames[$referencePointIndex])) {
                     if ($referencePointDatasetNames[$referencePointIndex] != $datasetName) {
                         // Dataset name is not the same for all columns for the reference point
                         $referencePointDatasetNames[$referencePointIndex] = FALSE;
                     }
                 } else {
                     $referencePointDatasetNames[$referencePointIndex] = $datasetName;
                 }
             }
         }
         // removing all reference points which we cannot support now
         foreach ($referencePointDatasetNames as $referencePointIndex => $datasetName) {
             if ($datasetName === FALSE) {
                 unset($referencePointDatasetNames[$referencePointIndex]);
             }
         }
         // if nothing left there is not need to proceed
         if (count($referencePointDatasetNames) == 0) {
             continue;
         }
         // preparing list of parent column names
         $parentColumnNames = NULL;
         for ($referencePointColumnIndex = 0; $referencePointColumnIndex < $referencePointColumnCount; $referencePointColumnIndex++) {
             $parentReferencePointIndex = $parentReferencePointIndex4Reference[$referencePointColumnIndex];
             $parentReferencePointColumnName = $reference->points[$parentReferencePointIndex]->columns[$referencePointColumnIndex]->columnName;
             $parentColumnNames[$referencePointColumnIndex] = $parentReferencePointColumnName;
         }
         $referenceCallContext = $isDirectReference ? $callcontext : clone $callcontext;
         // adding all indirect datasets in stack to prevent recursive calls
         if (!$isDirectReference) {
             foreach ($referencePointDatasetNames as $referencePointIndex => $datasetName) {
                 if (isset($referenceCallContext->datasetNameStack[$datasetName])) {
                     unset($referencePointDatasetNames[$referencePointIndex]);
                 } else {
                     $referenceCallContext->datasetNameStack[$datasetName] = TRUE;
                 }
             }
         }
         foreach ($referencePointDatasetNames as $referencePointIndex => $datasetName) {
             // looking for existing link
             $referencedLink = $link->findNestedLinkByDatasetNameAndParentColumnNames($datasetName, $parentColumnNames);
             if (!isset($referencedLink)) {
                 $dataset = $metamodel->getDataset($datasetName);
                 $referencedLink = new ReferenceLink($dataset);
                 foreach ($parentColumnNames as $referencePointColumnIndex => $parentReferencePointColumnName) {
                     $referencePointColumn = $reference->points[$referencePointIndex]->columns[$referencePointColumnIndex];
                     $referencedLink->linkColumnWithParent($referencePointColumnIndex, $parentReferencePointColumnName, $referencePointColumn->columnName);
                 }
                 $link->registerNestedLink($referencedLink);
             }
             ArrayHelper::addUniqueValue($referencedLink->referenceNames, $referenceName);
             // marking the link as required for the branch so it will not be deleted by the optimizer later
             if ($isDirectReference) {
                 $referencedLink->required = TRUE;
             }
             // because this reference path is not processed completely we need to continue scanning this branch
             if (isset($nestedReferencePath)) {
                 $referencePointCallContext = clone $referenceCallContext;
                 $this->prepareDatasetSequence($referencePointCallContext, $metamodel, $referencedLink, $nestedReferencePath);
             }
         }
     }
 }