/** * @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; }