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;
     }
 }