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];
 }
 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);
     }
 }
 public function getEntityHistory($className, $id)
 {
     if (!$this->metadataFactory->isAudited($className)) {
         throw new NotAuditedException($className);
     }
     /** @var ClassMetadataInfo|ClassMetadata $class */
     $class = $this->em->getClassMetadata($className);
     $tableName = $this->config->getTableName($class);
     if (!is_array($id)) {
         $id = array($class->identifier[0] => $id);
     }
     $whereId = array();
     foreach ($class->identifier as $idField) {
         if (isset($class->fieldMappings[$idField])) {
             $columnName = $class->fieldMappings[$idField]['columnName'];
         } else {
             if (isset($class->associationMappings[$idField])) {
                 $columnName = $class->associationMappings[$idField]['joinColumns'][0];
             } else {
                 continue;
             }
         }
         $whereId[] = "{$columnName} = ?";
     }
     $whereSQL = implode(' AND ', $whereId);
     $columnList = array($this->config->getRevisionFieldName());
     $columnMap = array();
     foreach ($class->fieldNames as $columnName => $field) {
         $type = Type::getType($class->fieldMappings[$field]['type']);
         $columnList[] = $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']) {
             continue;
         }
         foreach ($assoc['targetToSourceKeyColumns'] as $sourceCol) {
             $columnList[] = $sourceCol;
             $columnMap[$sourceCol] = $this->platform->getSQLResultCasing($sourceCol);
         }
     }
     $values = array_values($id);
     $query = "SELECT " . implode(', ', $columnList) . " FROM " . $tableName . " e WHERE " . $whereSQL . " ORDER BY e.rev DESC";
     $stmt = $this->em->getConnection()->executeQuery($query, $values);
     $result = array();
     while ($row = $stmt->fetch(Query::HYDRATE_ARRAY)) {
         $rev = $row[$this->config->getRevisionFieldName()];
         unset($row[$this->config->getRevisionFieldName()]);
         $result[] = $this->createEntity($class->name, $row, $rev);
     }
     return $result;
 }
 /**
  * @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;
     }
 }