Example #1
0
 /**
  * @param string &$tableName
  * @param array &$propertyPath
  * @param array &$sql
  * @throws Exception
  * @throws Exception\InvalidRelationConfigurationException
  * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\MissingColumnMapException
  */
 protected function addUnionStatement(&$tableName, &$propertyPath, array &$sql)
 {
     $table = Tca::table($tableName);
     $explodedPropertyPath = explode('.', $propertyPath, 2);
     $fieldName = $explodedPropertyPath[0];
     // Field of type "group" are special because property path must contain the table name
     // to determine the relation type. Example for sys_category, property path will look like "items.sys_file"
     if ($table->field($fieldName)->isGroup()) {
         $parts = explode('.', $propertyPath, 3);
         $explodedPropertyPath[0] = $parts[0] . '.' . $parts[1];
         $explodedPropertyPath[1] = $parts[2];
         $fieldName = $explodedPropertyPath[0];
     }
     $parentKeyFieldName = $table->field($fieldName)->getForeignField();
     $childTableName = $table->field($fieldName)->getForeignTable();
     if ($childTableName === NULL) {
         throw new Exception\InvalidRelationConfigurationException('The relation information for property "' . $fieldName . '" of class "' . $tableName . '" is missing.', 1353170925);
     }
     if ($table->field($fieldName)->hasOne()) {
         // includes relation "one-to-one" and "many-to-one"
         // sometimes the opposite relation is not defined. We don't want to force this config for backward compatibility reasons.
         // $parentKeyFieldName === NULL does the trick somehow. Before condition was if (isset($parentKeyFieldName))
         if ($table->field($fieldName)->hasRelationManyToOne() || $parentKeyFieldName === NULL) {
             $sql['unions'][$childTableName] = 'LEFT JOIN ' . $childTableName . ' ON ' . $tableName . '.' . $fieldName . '=' . $childTableName . '.uid';
         } else {
             $sql['unions'][$childTableName] = 'LEFT JOIN ' . $childTableName . ' ON ' . $tableName . '.uid=' . $childTableName . '.' . $parentKeyFieldName;
         }
     } elseif ($table->field($fieldName)->hasRelationManyToMany()) {
         $relationTableName = $table->field($fieldName)->getManyToManyTable();
         $parentKeyFieldName = $table->field($fieldName)->isOppositeRelation() ? 'uid_foreign' : 'uid_local';
         $childKeyFieldName = !$table->field($fieldName)->isOppositeRelation() ? 'uid_foreign' : 'uid_local';
         // MM table e.g sys_category_record_mm
         $relationTableNameAlias = $this->generateAlias($relationTableName);
         $join = sprintf('LEFT JOIN %s AS %s ON %s.uid=%s.%s', $relationTableName, $relationTableNameAlias, $tableName, $relationTableNameAlias, $parentKeyFieldName);
         $sql['unions'][$relationTableNameAlias] = $join;
         // Foreign table e.g sys_category
         $childTableNameAlias = $this->generateAlias($childTableName);
         $this->currentChildTableNameAlias = $childTableNameAlias;
         $join = sprintf('LEFT JOIN %s AS %s ON %s.%s=%s.uid', $childTableName, $childTableNameAlias, $relationTableNameAlias, $childKeyFieldName, $childTableNameAlias);
         $sql['unions'][$childTableNameAlias] = $join;
         // Find a possible table name for a MM condition.
         $tableNameCondition = $table->field($fieldName)->getAdditionalTableNameCondition();
         if ($tableNameCondition) {
             // If we can find a source file name,  we can then retrieve more MM conditions from the TCA such as a field name.
             $sourceFileName = $this->query->getSourceFieldName();
             if (empty($sourceFileName)) {
                 $additionalMMConditions = array('tablenames' => $tableNameCondition);
             } else {
                 $additionalMMConditions = Tca::table($tableNameCondition)->field($sourceFileName)->getAdditionalMMCondition();
             }
             foreach ($additionalMMConditions as $additionalFieldName => $additionalMMCondition) {
                 $additionalJoin = sprintf(' AND %s.%s = "%s"', $relationTableNameAlias, $additionalFieldName, $additionalMMCondition);
                 $sql['unions'][$relationTableNameAlias] .= $additionalJoin;
                 $additionalJoin = sprintf(' AND %s.%s = "%s"', $relationTableNameAlias, $additionalFieldName, $additionalMMCondition);
                 $sql['unions'][$childTableNameAlias] .= $additionalJoin;
             }
         }
     } elseif ($table->field($fieldName)->hasMany()) {
         // includes relations "many-to-one" and "csv" relations
         $childTableNameAlias = $this->generateAlias($childTableName);
         $this->currentChildTableNameAlias = $childTableNameAlias;
         if (isset($parentKeyFieldName)) {
             $join = sprintf('LEFT JOIN %s AS %s ON %s.uid=%s.%s', $childTableName, $childTableNameAlias, $tableName, $childTableNameAlias, $parentKeyFieldName);
             $sql['unions'][$childTableNameAlias] = $join;
         } else {
             $join = sprintf('LEFT JOIN %s AS %s ON (FIND_IN_SET(%s.uid, %s.%s))', $childTableName, $childTableNameAlias, $childTableNameAlias, $tableName, $fieldName);
             $sql['unions'][$childTableNameAlias] = $join;
         }
     } else {
         throw new Exception('Could not determine type of relation.', 1252502725);
     }
     // TODO check if there is another solution for this
     $sql['keywords']['distinct'] = 'DISTINCT';
     $propertyPath = $explodedPropertyPath[1];
     $tableName = $childTableName;
 }