public function postGenerateSchemaTable(GenerateSchemaTableEventArgs $eventArgs) { $cm = $eventArgs->getClassMetadata(); if (!$this->metadataFactory->isAudited($cm->name)) { $audited = false; if ($cm->isInheritanceTypeJoined() && $cm->rootEntityName == $cm->name) { foreach ($cm->subClasses as $subClass) { if ($this->metadataFactory->isAudited($subClass)) { $audited = true; } } } if (!$audited) { return; } } $schema = $eventArgs->getSchema(); $entityTable = $eventArgs->getClassTable(); $revisionTable = $schema->createTable($this->config->getTablePrefix() . $entityTable->getName() . $this->config->getTableSuffix()); foreach ($entityTable->getColumns() as $column) { /* @var $column Column */ $revisionTable->addColumn($column->getName(), $column->getType()->getName(), array_merge($column->toArray(), array('notnull' => false, 'autoincrement' => false))); } $revisionTable->addColumn($this->config->getRevisionFieldName(), $this->config->getRevisionIdFieldType()); $revisionTable->addColumn($this->config->getRevisionTypeFieldName(), 'string', array('length' => 4)); if (!in_array($cm->inheritanceType, array(ClassMetadataInfo::INHERITANCE_TYPE_NONE, ClassMetadataInfo::INHERITANCE_TYPE_JOINED, ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_TABLE))) { throw new \Exception(sprintf('Inheritance type "%s" is not yet supported', $cm->inheritanceType)); } $pkColumns = $entityTable->getPrimaryKey()->getColumns(); $pkColumns[] = $this->config->getRevisionFieldName(); $revisionTable->setPrimaryKey($pkColumns); }
private function getInsertRevisionSQL($class) { if (!isset($this->insertRevisionSQL[$class->name])) { $placeholders = array('?', '?'); $tableName = $this->config->getTablePrefix() . $class->table['name'] . $this->config->getTableSuffix(); $sql = "INSERT INTO " . $tableName . " (" . $this->config->getRevisionFieldName() . ", " . $this->config->getRevisionTypeFieldName(); $fields = array(); foreach ($class->associationMappings as $assoc) { if (($assoc['type'] & ClassMetadata::TO_ONE) > 0 && $assoc['isOwningSide']) { foreach ($assoc['targetToSourceKeyColumns'] as $sourceCol) { $fields[$sourceCol] = true; $sql .= ', ' . $sourceCol; $placeholders[] = '?'; } } } foreach ($class->fieldNames as $field) { if (array_key_exists($field, $fields)) { continue; } $type = Type::getType($class->fieldMappings[$field]['type']); $placeholders[] = !empty($class->fieldMappings[$field]['requireSQLConversion']) ? $type->convertToDatabaseValueSQL('?', $this->platform) : '?'; $sql .= ', ' . $class->getQuotedColumnName($field, $this->platform); } $sql .= ") VALUES (" . implode(", ", $placeholders) . ")"; $this->insertRevisionSQL[$class->name] = $sql; } return $this->insertRevisionSQL[$class->name]; }
/** * Return a list of ChangedEntity instances created at the given revision. * * @param int $revision * @return ChangedEntity[] */ public function findEntitiesChangedAtRevision($revision) { $auditedEntities = $this->metadataFactory->getAllClassNames(); $changedEntities = array(); foreach ($auditedEntities as $className) { /** @var ClassMetadataInfo|ClassMetadata $class */ $class = $this->em->getClassMetadata($className); if ($class->isInheritanceTypeSingleTable() && count($class->subClasses) > 0) { continue; } $tableName = $this->config->getTableName($class); $params = array(); $whereSQL = "e." . $this->config->getRevisionFieldName() . " = ?"; $columnList = "e." . $this->config->getRevisionTypeFieldName(); $params[] = $revision; $columnMap = array(); foreach ($class->fieldNames as $columnName => $field) { $type = Type::getType($class->fieldMappings[$field]['type']); $tableAlias = $class->isInheritanceTypeJoined() && $class->isInheritedField($field) && !$class->isIdentifier($field) ? 're' : 'e'; $columnList .= ', ' . $tableAlias . '.' . $type->convertToPHPValueSQL($class->getQuotedColumnName($field, $this->platform), $this->platform) . ' AS ' . $this->platform->quoteSingleIdentifier($field); $columnMap[$field] = $this->platform->getSQLResultCasing($columnName); } foreach ($class->associationMappings as $assoc) { if (($assoc['type'] & ClassMetadata::TO_ONE) > 0 && $assoc['isOwningSide']) { foreach ($assoc['targetToSourceKeyColumns'] as $sourceCol) { $columnList .= ', ' . $sourceCol; $columnMap[$sourceCol] = $this->platform->getSQLResultCasing($sourceCol); } } } $joinSql = ''; if ($class->isInheritanceTypeSingleTable()) { $columnList .= ', e.' . $class->discriminatorColumn['name']; $whereSQL .= " AND e." . $class->discriminatorColumn['fieldName'] . " = ?"; $params[] = $class->discriminatorValue; } elseif ($class->isInheritanceTypeJoined() && $class->rootEntityName != $class->name) { $columnList .= ', re.' . $class->discriminatorColumn['name']; /** @var ClassMetadataInfo|ClassMetadata $rootClass */ $rootClass = $this->em->getClassMetadata($class->rootEntityName); $rootTableName = $this->config->getTableName($rootClass); $joinSql = "INNER JOIN {$rootTableName} re ON"; $joinSql .= " re.rev = e.rev"; foreach ($class->getIdentifierColumnNames() as $name) { $joinSql .= " AND re.{$name} = e.{$name}"; } } $query = "SELECT " . $columnList . " FROM " . $tableName . " e " . $joinSql . " WHERE " . $whereSQL; $revisionsData = $this->em->getConnection()->executeQuery($query, $params); foreach ($revisionsData as $row) { $id = array(); foreach ($class->identifier as $idField) { $id[$idField] = $row[$idField]; } $entity = $this->createEntity($className, $row, $revision); $changedEntities[] = new ChangedEntity($className, $id, $row[$this->config->getRevisionTypeFieldName()], $entity); } } return $changedEntities; }
public function postGenerateSchemaTable(GenerateSchemaTableEventArgs $eventArgs) { $cm = $eventArgs->getClassMetadata(); if ($this->metadataFactory->isAudited($cm->name)) { $schema = $eventArgs->getSchema(); $entityTable = $eventArgs->getClassTable(); $revisionTable = $schema->createTable($this->config->getTablePrefix() . $entityTable->getName() . $this->config->getTableSuffix()); foreach ($entityTable->getColumns() as $column) { /* @var $column Column */ $revisionTable->addColumn($column->getName(), $column->getType()->getName(), array_merge($column->toArray(), array('notnull' => false, 'autoincrement' => false))); } $revisionTable->addColumn($this->config->getRevisionFieldName(), $this->config->getRevisionIdFieldType()); $revisionTable->addColumn($this->config->getRevisionTypeFieldName(), 'string', array('length' => 4)); $pkColumns = $entityTable->getPrimaryKey()->getColumns(); $pkColumns[] = $this->config->getRevisionFieldName(); $revisionTable->setPrimaryKey($pkColumns); } }
/** * @param ClassMetadata $class * * @return string * @throws \Doctrine\DBAL\DBALException */ private function getInsertRevisionSQL($class) { if (!isset($this->insertRevisionSQL[$class->name])) { $placeholders = array('?', '?'); $tableName = $this->config->getTableName($class); $sql = "INSERT INTO " . $tableName . " (" . $this->config->getRevisionFieldName() . ", " . $this->config->getRevisionTypeFieldName(); $fields = array(); foreach ($class->associationMappings as $field => $assoc) { if ($class->isInheritanceTypeJoined() && $class->isInheritedAssociation($field)) { continue; } if (($assoc['type'] & ClassMetadata::TO_ONE) > 0 && $assoc['isOwningSide']) { foreach ($assoc['targetToSourceKeyColumns'] as $sourceCol) { $fields[$sourceCol] = true; $sql .= ', ' . $sourceCol; $placeholders[] = '?'; } } } foreach ($class->fieldNames as $field) { if (array_key_exists($field, $fields)) { continue; } if ($class->isInheritanceTypeJoined() && $class->isInheritedField($field) && !$class->isIdentifier($field)) { continue; } $type = Type::getType($class->fieldMappings[$field]['type']); $placeholders[] = !empty($class->fieldMappings[$field]['requireSQLConversion']) ? $type->convertToDatabaseValueSQL('?', $this->platform) : '?'; $sql .= ', ' . $this->quoteStrategy->getColumnName($field, $class, $this->platform); } if ($class->isInheritanceTypeJoined() && $class->rootEntityName == $class->name || $class->isInheritanceTypeSingleTable()) { $sql .= ', ' . $class->discriminatorColumn['name']; $placeholders[] = '?'; } $sql .= ") VALUES (" . implode(", ", $placeholders) . ")"; $this->insertRevisionSQL[$class->name] = $sql; } return $this->insertRevisionSQL[$class->name]; }
protected function initialize() { if (!$this->initialized) { $params = array(); $sql = 'SELECT MAX(' . $this->configuration->getRevisionFieldName() . ') as rev, '; $sql .= $this->configuration->getRevisionTypeFieldName() . ' AS revtype, '; $sql .= implode(', ', $this->metadata->getIdentifierColumnNames()) . ' '; if (isset($this->associationDefinition['indexBy'])) { $sql .= ', ' . $this->associationDefinition['indexBy'] . ' '; } $sql .= 'FROM ' . $this->configuration->getTablePrefix() . $this->metadata->table['name'] . $this->configuration->getTableSuffix() . ' t '; $sql .= 'WHERE ' . $this->configuration->getRevisionFieldName() . ' <= ' . $this->revision . ' '; foreach ($this->foreignKeys as $column => $value) { $sql .= 'AND ' . $column . ' = ? '; $params[] = $value; } //we check for revisions greater than current belonging to other entities $sql .= 'AND NOT EXISTS (SELECT * FROM ' . $this->configuration->getTablePrefix() . $this->metadata->table['name'] . $this->configuration->getTableSuffix() . ' st WHERE'; //ids foreach ($this->metadata->getIdentifierColumnNames() as $name) { $sql .= ' st.' . $name . ' = t.' . $name . ' AND'; } //foreigns $sql .= ' (('; //master entity query, not equals $notEqualParts = $nullParts = array(); foreach ($this->foreignKeys as $column => $value) { $notEqualParts[] = $column . ' <> ?'; $nullParts[] = $column . ' IS NULL'; $params[] = $value; } $sql .= implode(' AND ', $notEqualParts) . ') OR (' . implode(' AND ', $nullParts) . '))'; //revision $sql .= ' AND st.' . $this->configuration->getRevisionFieldName() . ' <= ' . $this->revision; $sql .= ' AND st.' . $this->configuration->getRevisionFieldName() . ' > t.' . $this->configuration->getRevisionFieldName(); $sql .= ') '; //end of check for for belonging to other entities //check for deleted revisions older than requested $sql .= 'AND NOT EXISTS (SELECT * FROM ' . $this->configuration->getTablePrefix() . $this->metadata->table['name'] . $this->configuration->getTableSuffix() . ' sd WHERE'; //ids foreach ($this->metadata->getIdentifierColumnNames() as $name) { $sql .= ' sd.' . $name . ' = t.' . $name . ' AND'; } //revision $sql .= ' sd.' . $this->configuration->getRevisionFieldName() . ' <= ' . $this->revision; $sql .= ' AND sd.' . $this->configuration->getRevisionFieldName() . ' > t.' . $this->configuration->getRevisionFieldName(); $sql .= ' AND sd.' . $this->configuration->getRevisionTypeFieldName() . ' = ?'; $params[] = 'DEL'; $sql .= ') '; //end check for deleted revisions older than requested $sql .= 'GROUP BY ' . implode(', ', $this->metadata->getIdentifierColumnNames()) . ' '; $sql .= 'HAVING ' . $this->configuration->getRevisionTypeFieldName() . ' <> ?'; //add rev type parameter $params[] = 'DEL'; $rows = $this->auditReader->getConnection()->fetchAll($sql, $params); foreach ($rows as $row) { $entity = array('rev' => $row['rev'], 'revtype' => $row['revtype']); unset($row['rev'], $row['revtype']); $entity['keys'] = $row; if (isset($this->associationDefinition['indexBy'])) { $key = $row[$this->associationDefinition['indexBy']]; unset($entity['keys'][$this->associationDefinition['indexBy']]); $this->entities[$key] = $entity; } else { $this->entities[] = $entity; } } $this->initialized = true; } }