/** * Creates a query object working on the given class name * * @param string $className The class name * @return \TYPO3\CMS\Extbase\Persistence\QueryInterface * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception */ public function create($className) { $query = $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\QueryInterface::class, $className); $querySettings = $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface::class); $dataMap = $this->dataMapper->getDataMap($className); if ($dataMap->getIsStatic() || $dataMap->getRootLevel()) { $querySettings->setRespectStoragePage(false); } $frameworkConfiguration = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK); $querySettings->setStoragePageIds(\TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $frameworkConfiguration['persistence']['storagePid'])); $query->setQuerySettings($querySettings); return $query; }
/** * Checks if a Value Object equal to the given Object exists in the database * * @param AbstractValueObject $object The Value Object * @return mixed The matching uid if an object was found, else FALSE * @throws SqlErrorException */ public function getUidOfAlreadyPersistedValueObject(AbstractValueObject $object) { $dataMap = $this->dataMapper->getDataMap(get_class($object)); $tableName = $dataMap->getTableName(); $queryBuilder = $this->connectionPool->getQueryBuilderForTable($tableName); if ($this->environmentService->isEnvironmentInFrontendMode()) { $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class)); } $whereClause = []; // loop over all properties of the object to exactly set the values of each database field $properties = $object->_getProperties(); foreach ($properties as $propertyName => $propertyValue) { // @todo We couple the Backend to the Entity implementation (uid, isClone); changes there breaks this method if ($dataMap->isPersistableProperty($propertyName) && $propertyName !== 'uid' && $propertyName !== 'pid' && $propertyName !== 'isClone') { $fieldName = $dataMap->getColumnMap($propertyName)->getColumnName(); if ($propertyValue === null) { $whereClause[] = $queryBuilder->expr()->isNull($fieldName); } else { $whereClause[] = $queryBuilder->expr()->eq($fieldName, $queryBuilder->createNamedParameter($this->dataMapper->getPlainValue($propertyValue))); } } } $queryBuilder->select('uid')->from($tableName)->where(...$whereClause); try { $uid = (int) $queryBuilder->execute()->fetchColumn(0); if ($uid > 0) { return $uid; } else { return false; } } catch (DBALException $e) { throw new SqlErrorException($e->getPrevious()->getMessage(), 1470231748); } }
/** * Dump non-localized contents of the repository * * @return void */ public function sqlDumpNonLocalizedData() { // Get the information of the table and its fields $dataMap = $this->dataMapper->getDataMap($this->objectType); $tableName = $dataMap->getTableName(); // Class TYPO3\CMS\Install\Sql\SchemaMigrator was renamed in TYPO3 6.2 if (class_exists('TYPO3\\CMS\\Install\\Service\\SqlSchemaMigrationService')) { $installToolSqlParser = $this->objectManager->get('TYPO3\\CMS\\Install\\Service\\SqlSchemaMigrationService'); } else { $installToolSqlParser = $this->objectManager->get('TYPO3\\CMS\\Install\\Sql\\SchemaMigrator'); } $dbFieldDefinitions = $installToolSqlParser->getFieldDefinitions_database(); $dbFields = array(); $dbFields[$tableName] = $dbFieldDefinitions[$tableName]; $extensionKey = \TYPO3\CMS\Core\Utility\GeneralUtility::camelCaseToLowerCaseUnderscored($this->extensionName); $extensionPath = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($extensionKey); $ext_tables = \TYPO3\CMS\Core\Utility\GeneralUtility::getUrl($extensionPath . 'ext_tables.sql'); $tableFields = array_keys($dbFields[$tableName]['fields']); foreach ($tableFields as $field) { // This is a very simple check if the field is from static_info_tables and not from a language pack $match = array(); if (!preg_match('#' . preg_quote($field) . '#m', $ext_tables, $match)) { unset($dbFields[$tableName]['fields'][$field]); } } $databaseUtility = $this->objectManager->get('SJBR\\StaticInfoTables\\Utility\\DatabaseUtility'); return $databaseUtility->dumpStaticTables($dbFields); }
/** * adds a union statement to the query, mostly for tables referenced in the where condition. * The property for which the union statement is generated will be appended. * * @param string &$className The name of the parent class, will be set to the child class after processing. * @param string &$tableName The name of the parent table, will be set to the table alias that is used in the union statement. * @param array &$propertyPath The remaining property path, will be cut of by one part during the process. * @param string $fullPropertyPath The full path the the current property, will be used to make table names unique. * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception * @throws InvalidRelationConfigurationException * @throws MissingColumnMapException */ protected function addUnionStatement(&$className, &$tableName, &$propertyPath, &$fullPropertyPath) { $explodedPropertyPath = explode('.', $propertyPath, 2); $propertyName = $explodedPropertyPath[0]; $columnName = $this->dataMapper->convertPropertyNameToColumnName($propertyName, $className); $realTableName = $this->dataMapper->convertClassNameToTableName($className); $tableName = isset($this->tablePropertyMap[$fullPropertyPath]) ? $this->tablePropertyMap[$fullPropertyPath] : $realTableName; $columnMap = $this->dataMapper->getDataMap($className)->getColumnMap($propertyName); if ($columnMap === null) { throw new MissingColumnMapException('The ColumnMap for property "' . $propertyName . '" of class "' . $className . '" is missing.', 1355142232); } $parentKeyFieldName = $columnMap->getParentKeyFieldName(); $childTableName = $columnMap->getChildTableName(); if ($childTableName === null) { throw new InvalidRelationConfigurationException('The relation information for property "' . $propertyName . '" of class "' . $className . '" is missing.', 1353170925); } $fullPropertyPath .= $fullPropertyPath === '' ? $propertyName : '.' . $propertyName; $childTableAlias = $this->getUniqueAlias($childTableName, $fullPropertyPath); // If there is already exists a union with the current identifier we do not need to build it again and exit early. if (in_array($childTableAlias, $this->unionTableAliasCache, true)) { return; } if ($columnMap->getTypeOfRelation() === ColumnMap::RELATION_HAS_ONE) { if (isset($parentKeyFieldName)) { // @todo: no test for this part yet $joinConditionExpression = $this->queryBuilder->expr()->eq($tableName . '.uid', $childTableAlias . '.' . $parentKeyFieldName); } else { $joinConditionExpression = $this->queryBuilder->expr()->eq($tableName . '.' . $columnName, $childTableAlias . '.uid'); } $this->queryBuilder->leftJoin($tableName, $childTableName, $childTableAlias, $joinConditionExpression); $this->unionTableAliasCache[] = $childTableAlias; $this->queryBuilder->andWhere($this->getAdditionalMatchFieldsStatement($this->queryBuilder->expr(), $columnMap, $childTableAlias, $realTableName)); } elseif ($columnMap->getTypeOfRelation() === ColumnMap::RELATION_HAS_MANY) { // @todo: no tests for this part yet if (isset($parentKeyFieldName)) { $joinConditionExpression = $this->queryBuilder->expr()->eq($tableName . '.uid', $childTableAlias . '.' . $parentKeyFieldName); } else { $joinConditionExpression = $this->queryBuilder->expr()->inSet($tableName . '.' . $columnName, $childTableAlias . '.uid'); } $this->queryBuilder->leftJoin($tableName, $childTableName, $childTableAlias, $joinConditionExpression); $this->unionTableAliasCache[] = $childTableAlias; $this->queryBuilder->andWhere($this->getAdditionalMatchFieldsStatement($this->queryBuilder->expr(), $columnMap, $childTableAlias, $realTableName)); } elseif ($columnMap->getTypeOfRelation() === ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) { $relationTableName = $columnMap->getRelationTableName(); $relationTableAlias = $relationTableAlias = $this->getUniqueAlias($relationTableName, $fullPropertyPath . '_mm'); $joinConditionExpression = $this->queryBuilder->expr()->eq($tableName . '.uid', $relationTableAlias . '.' . $columnMap->getParentKeyFieldName()); $this->queryBuilder->leftJoin($tableName, $relationTableName, $relationTableAlias, $joinConditionExpression); $joinConditionExpression = $this->queryBuilder->expr()->eq($relationTableAlias . '.' . $columnMap->getChildKeyFieldName(), $childTableAlias . '.uid'); $this->queryBuilder->leftJoin($relationTableAlias, $childTableName, $childTableAlias, $joinConditionExpression); $this->queryBuilder->andWhere($this->getAdditionalMatchFieldsStatement($this->queryBuilder->expr(), $columnMap, $relationTableAlias, $realTableName)); $this->unionTableAliasCache[] = $childTableAlias; $this->queryBuilder->addGroupBy($this->tableName . '.uid'); } else { throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception('Could not determine type of relation.', 1252502725); } $propertyPath = $explodedPropertyPath[1]; $tableName = $childTableAlias; $className = $this->dataMapper->getType($className, $propertyName); }
/** * Returns the identifier for an object * * @param \TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject $object * @return string */ public function getObjectIdentifierForObject(\TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject $object = NULL) { $objectIdentifier = false; if ($object) { $dataMap = $this->dataMapper->getDataMap(get_class($object)); $tableName = $dataMap->getTableName(); $objectIdentifier = 'r-' . $tableName . '_' . $object->getUid(); } return $objectIdentifier; }
/** * Tries to fetch the UID of the entity from the database that is related to * the given imported record UID. * * @param string $entityClass * @param int $importedUid * @return int|null */ protected function getEntityUidForImportedUid($entityClass, $importedUid) { $entityTableName = $this->dataMapper->getDataMap($entityClass)->getTableName(); $row = $this->getDatabaseConnection()->exec_SELECTgetSingleRow('uid', $entityTableName, 'tx_czsimplecalimportercal_imported_uid=' . (int) $importedUid); if (empty($row)) { return NULL; } else { return (int) $row['uid']; } }
/** * adds a union statement to the query, mostly for tables referenced in the where condition. * The property for which the union statement is generated will be appended. * * @param string &$className The name of the parent class, will be set to the child class after processing. * @param string &$tableName The name of the parent table, will be set to the table alias that is used in the union statement. * @param array &$propertyPath The remaining property path, will be cut of by one part during the process. * @param array &$sql The SQL statement parts, will be filled with the union statements. * @param string $fullPropertyPath The full path the the current property, will be used to make table names unique. * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\InvalidRelationConfigurationException * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\MissingColumnMapException */ protected function addUnionStatement(&$className, &$tableName, &$propertyPath, array &$sql, &$fullPropertyPath) { $explodedPropertyPath = explode('.', $propertyPath, 2); $propertyName = $explodedPropertyPath[0]; $columnName = $this->dataMapper->convertPropertyNameToColumnName($propertyName, $className); $realTableName = $this->dataMapper->convertClassNameToTableName($className); $tableName = isset($this->tablePropertyMap[$fullPropertyPath]) ? $this->tablePropertyMap[$fullPropertyPath] : $realTableName; $columnMap = $this->dataMapper->getDataMap($className)->getColumnMap($propertyName); if ($columnMap === null) { throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\MissingColumnMapException('The ColumnMap for property "' . $propertyName . '" of class "' . $className . '" is missing.', 1355142232); } $parentKeyFieldName = $columnMap->getParentKeyFieldName(); $childTableName = $columnMap->getChildTableName(); if ($childTableName === null) { throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\InvalidRelationConfigurationException('The relation information for property "' . $propertyName . '" of class "' . $className . '" is missing.', 1353170925); } $fullPropertyPath .= $fullPropertyPath === '' ? $propertyName : '.' . $propertyName; $childTableAlias = $this->getUniqueAlias($sql, $childTableName, $fullPropertyPath); // If there is already exists a union with the current identifier we do not need to build it again and exit early. if (isset($sql['unions'][$childTableAlias])) { $propertyPath = $explodedPropertyPath[1]; $tableName = $childTableAlias; $className = $this->dataMapper->getType($className, $propertyName); return; } if ($columnMap->getTypeOfRelation() === ColumnMap::RELATION_HAS_ONE) { if (isset($parentKeyFieldName)) { $sql['unions'][$childTableAlias] = 'LEFT JOIN ' . $childTableName . ' AS ' . $childTableAlias . ' ON ' . $tableName . '.uid=' . $childTableAlias . '.' . $parentKeyFieldName; } else { $sql['unions'][$childTableAlias] = 'LEFT JOIN ' . $childTableName . ' AS ' . $childTableAlias . ' ON ' . $tableName . '.' . $columnName . '=' . $childTableAlias . '.uid'; } $sql['unions'][$childTableAlias] .= $this->getAdditionalMatchFieldsStatement($columnMap, $childTableName, $childTableAlias, $realTableName); } elseif ($columnMap->getTypeOfRelation() === ColumnMap::RELATION_HAS_MANY) { if (isset($parentKeyFieldName)) { $sql['unions'][$childTableAlias] = 'LEFT JOIN ' . $childTableName . ' AS ' . $childTableAlias . ' ON ' . $tableName . '.uid=' . $childTableAlias . '.' . $parentKeyFieldName; } else { $onStatement = '(FIND_IN_SET(' . $childTableAlias . '.uid, ' . $tableName . '.' . $columnName . '))'; $sql['unions'][$childTableAlias] = 'LEFT JOIN ' . $childTableName . ' AS ' . $childTableAlias . ' ON ' . $onStatement; } $sql['unions'][$childTableAlias] .= $this->getAdditionalMatchFieldsStatement($columnMap, $childTableName, $childTableAlias, $realTableName); } elseif ($columnMap->getTypeOfRelation() === ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) { $relationTableName = $columnMap->getRelationTableName(); $relationTableAlias = $relationTableAlias = $this->getUniqueAlias($sql, $relationTableName, $fullPropertyPath . '_mm'); $sql['unions'][$relationTableAlias] = 'LEFT JOIN ' . $relationTableName . ' AS ' . $relationTableAlias . ' ON ' . $tableName . '.uid=' . $relationTableAlias . '.' . $columnMap->getParentKeyFieldName(); $sql['unions'][$childTableAlias] = 'LEFT JOIN ' . $childTableName . ' AS ' . $childTableAlias . ' ON ' . $relationTableAlias . '.' . $columnMap->getChildKeyFieldName() . '=' . $childTableAlias . '.uid'; $sql['unions'][$childTableAlias] .= $this->getAdditionalMatchFieldsStatement($columnMap, $relationTableName, $relationTableAlias, $realTableName); } else { throw new \TYPO3\CMS\Extbase\Persistence\Generic\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 = $childTableAlias; $className = $this->dataMapper->getType($className, $propertyName); }
/** * Since ExtBase isn't forcing the one to one relationships * for FileReferences, we're doing it here. * * ASSUMPTION: FileReference to File is one to one as well. * Meaning, deleting a FileReference will delete the File. * * NOTE: At this point, the FileReference object has not been saved * in the database. * * @param FileReference $fileReference * @param \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object * @param string $fieldname * @param string $propertyPath */ public function saveOneToOne(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, $fieldname, FileReference $fileReference, $propertyPath = 'file') { // This is a new $object, unlikely to have any existing FileReferences for this field. if (!$object->getUid() || $fileReference->getUid()) { return $this->save($fileReference, $propertyPath); } // Remove all FileReferences for this field $datamap = $this->dataMapper->getDataMap(get_class($object)); $this->removeFileReferences($object->getUid(), $datamap->getTableName(), $fieldname); return $this->save($fileReference, $propertyPath); }
/** * Counts the elements in the storage array * * @throws Exception * @return integer The number of elements in the ObjectStorage */ public function count() { $columnMap = $this->dataMapper->getDataMap(get_class($this->parentObject))->getColumnMap($this->propertyName); $numberOfElements = NULL; if (!$this->isInitialized && $columnMap->getTypeOfRelation() === Mapper\ColumnMap::RELATION_HAS_MANY) { $numberOfElements = $this->dataMapper->countRelated($this->parentObject, $this->propertyName, $this->fieldValue); } else { $this->initialize(); $numberOfElements = count($this->storage); } if (is_null($numberOfElements)) { throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception('The number of elements could not be determined.', 1252514486); } return $numberOfElements; }
/** * adds a union statement to the query, mostly for tables referenced in the where condition. * * @param string &$className * @param string &$tableName * @param array &$propertyPath * @param array &$sql * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\InvalidRelationConfigurationException * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\MissingColumnMapException */ protected function addUnionStatement(&$className, &$tableName, &$propertyPath, array &$sql) { $explodedPropertyPath = explode('.', $propertyPath, 2); $propertyName = $explodedPropertyPath[0]; $columnName = $this->dataMapper->convertPropertyNameToColumnName($propertyName, $className); $tableName = $this->dataMapper->convertClassNameToTableName($className); $columnMap = $this->dataMapper->getDataMap($className)->getColumnMap($propertyName); if ($columnMap === NULL) { throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\MissingColumnMapException('The ColumnMap for property "' . $propertyName . '" of class "' . $className . '" is missing.', 1355142232); } $parentKeyFieldName = $columnMap->getParentKeyFieldName(); $childTableName = $columnMap->getChildTableName(); if ($childTableName === NULL) { throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\InvalidRelationConfigurationException('The relation information for property "' . $propertyName . '" of class "' . $className . '" is missing.', 1353170925); } if ($columnMap->getTypeOfRelation() === ColumnMap::RELATION_HAS_ONE) { if (isset($parentKeyFieldName)) { $sql['unions'][$childTableName] = 'LEFT JOIN ' . $childTableName . ' ON ' . $tableName . '.uid=' . $childTableName . '.' . $parentKeyFieldName; } else { $sql['unions'][$childTableName] = 'LEFT JOIN ' . $childTableName . ' ON ' . $tableName . '.' . $columnName . '=' . $childTableName . '.uid'; } $className = $this->dataMapper->getType($className, $propertyName); } elseif ($columnMap->getTypeOfRelation() === ColumnMap::RELATION_HAS_MANY) { if (isset($parentKeyFieldName)) { $sql['unions'][$childTableName] = 'LEFT JOIN ' . $childTableName . ' ON ' . $tableName . '.uid=' . $childTableName . '.' . $parentKeyFieldName; } else { $onStatement = '(FIND_IN_SET(' . $childTableName . '.uid, ' . $tableName . '.' . $columnName . '))'; $sql['unions'][$childTableName] = 'LEFT JOIN ' . $childTableName . ' ON ' . $onStatement; } $className = $this->dataMapper->getType($className, $propertyName); } elseif ($columnMap->getTypeOfRelation() === ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) { $relationTableName = $columnMap->getRelationTableName(); $sql['unions'][$relationTableName] = 'LEFT JOIN ' . $relationTableName . ' ON ' . $tableName . '.uid=' . $relationTableName . '.' . $columnMap->getParentKeyFieldName(); $sql['unions'][$childTableName] = 'LEFT JOIN ' . $childTableName . ' ON ' . $relationTableName . '.' . $columnMap->getChildKeyFieldName() . '=' . $childTableName . '.uid'; $className = $this->dataMapper->getType($className, $propertyName); } else { throw new \TYPO3\CMS\Extbase\Persistence\Generic\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; }
/** * Remove related objects * * @param \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object The object to scanned for related objects * @return void */ protected function removeRelatedObjects(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object) { $className = get_class($object); $dataMap = $this->dataMapper->getDataMap($className); $classSchema = $this->reflectionService->getClassSchema($className); $properties = $object->_getProperties(); foreach ($properties as $propertyName => $propertyValue) { $columnMap = $dataMap->getColumnMap($propertyName); $propertyMetaData = $classSchema->getProperty($propertyName); if ($propertyMetaData['cascade'] === 'remove') { if ($columnMap->getTypeOfRelation() === \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap::RELATION_HAS_MANY) { foreach ($propertyValue as $containedObject) { $this->removeEntity($containedObject); } } elseif ($propertyValue instanceof \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface) { $this->removeEntity($propertyValue); } } } }
/** * Checks if a Value Object equal to the given Object exists in the data base * * @param \TYPO3\CMS\Extbase\DomainObject\AbstractValueObject $object The Value Object * @return mixed The matching uid if an object was found, else FALSE * @todo this is the last monster in this persistence series. refactor! */ public function getUidOfAlreadyPersistedValueObject(\TYPO3\CMS\Extbase\DomainObject\AbstractValueObject $object) { $fields = array(); $parameters = array(); $dataMap = $this->dataMapper->getDataMap(get_class($object)); $properties = $object->_getProperties(); foreach ($properties as $propertyName => $propertyValue) { // @todo We couple the Backend to the Entity implementation (uid, isClone); changes there breaks this method if ($dataMap->isPersistableProperty($propertyName) && $propertyName !== 'uid' && $propertyName !== 'pid' && $propertyName !== 'isClone') { if ($propertyValue === NULL) { $fields[] = $dataMap->getColumnMap($propertyName)->getColumnName() . ' IS NULL'; } else { $fields[] = $dataMap->getColumnMap($propertyName)->getColumnName() . '=?'; $parameters[] = $this->dataMapper->getPlainValue($propertyValue); } } } $sql = array(); $sql['additionalWhereClause'] = array(); $tableName = $dataMap->getTableName(); $this->addVisibilityConstraintStatement(new \TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings(), $tableName, $sql); $statement = 'SELECT * FROM ' . $tableName; $statement .= ' WHERE ' . implode(' AND ', $fields); if (!empty($sql['additionalWhereClause'])) { $statement .= ' AND ' . implode(' AND ', $sql['additionalWhereClause']); } $this->replacePlaceholders($statement, $parameters, $tableName); // debug($statement,-2); $res = $this->databaseHandle->sql_query($statement); $this->checkSqlErrors($statement); $row = $this->databaseHandle->sql_fetch_assoc($res); if ($row !== FALSE) { return (int) $row['uid']; } else { return FALSE; } }