Skip to content

Commit

Permalink
Add extra fields and indices to audit tables, based on configuration D…
Browse files Browse the repository at this point in the history
  • Loading branch information
wouter-toppy committed Nov 28, 2023
1 parent a40416e commit 3101c09
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 80 deletions.
19 changes: 0 additions & 19 deletions src/Model/Transaction.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,10 @@
*/
class Transaction implements TransactionInterface
{
/**
* @var string
*/
public const INSERT = 'insert';

/**
* @var string
*/
public const UPDATE = 'update';

/**
* @var string
*/
public const REMOVE = 'remove';

/**
* @var string
*/
public const ASSOCIATE = 'associate';

/**
* @var string
*/
public const DISSOCIATE = 'dissociate';

private ?string $transaction_hash = null;
Expand Down
23 changes: 23 additions & 0 deletions src/Provider/Doctrine/Auditing/Transaction/AuditTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\MappingException as ORMMappingException;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Throwable;
use UnitEnum;

Expand Down Expand Up @@ -125,6 +126,28 @@ private function value(EntityManagerInterface $entityManager, Type $type, mixed
return $convertedValue;
}

/**
* Returns the extra fields if set.
*/
private function extraFields(object $entity): array
{
$configuration = $this->provider->getConfiguration();
$extraFieldProperties = array_keys($configuration->getExtraFields());
$propertyAccessor = PropertyAccess::createPropertyAccessor();

$extraFields = [];

foreach ($extraFieldProperties as $extraField) {
if (!$propertyAccessor->isReadable($entity, $extraField)) {
continue;
}

$extraFields[$extraField] = $propertyAccessor->getValue($entity, $extraField);
}

return $extraFields;
}

/**
* Computes a usable diff.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ private function insert(EntityManagerInterface $entityManager, object $entity, a
'action' => 'insert',
'blame' => $this->blame(),
'diff' => $this->diff($entityManager, $entity, $ch),
'extra_fields' => $this->extraFields($entity),
'table' => $meta->getTableName(),
'schema' => $meta->getSchemaName(),
'id' => $this->id($entityManager, $entity),
Expand All @@ -85,6 +86,7 @@ private function update(EntityManagerInterface $entityManager, object $entity, a
'action' => 'update',
'blame' => $this->blame(),
'diff' => $diff,
'extra_fields' => $this->extraFields($entity),
'table' => $meta->getTableName(),
'schema' => $meta->getSchemaName(),
'id' => $this->id($entityManager, $entity),
Expand All @@ -104,6 +106,7 @@ private function remove(EntityManagerInterface $entityManager, object $entity, m
'action' => 'remove',
'blame' => $this->blame(),
'diff' => $this->summarize($entityManager, $entity, ['id' => $id]),
'extra_fields' => $this->extraFields($entity),
'table' => $meta->getTableName(),
'schema' => $meta->getSchemaName(),
'id' => $id,
Expand Down Expand Up @@ -184,6 +187,7 @@ private function associateOrDissociate(string $type, EntityManagerInterface $ent
'target' => $this->summarize($entityManager, $target, ['field' => $mapping['isOwningSide'] ? $mapping['inversedBy'] : $mapping['mappedBy']]),
'is_owning_side' => $mapping['isOwningSide'],
],
'extra_fields' => $this->extraFields($source),
'table' => $meta->getTableName(),
'schema' => $meta->getSchemaName(),
'id' => $this->id($entityManager, $source),
Expand Down Expand Up @@ -221,6 +225,7 @@ private function audit(array $data): void
'discriminator' => $data['discriminator'],
'transaction_hash' => (string) $data['transaction_hash'],
'diffs' => json_encode($diff, JSON_THROW_ON_ERROR),
...$data['extra_fields'] ?? [],
'blame_id' => $data['blame']['user_id'],
'blame_user' => $data['blame']['username'],
'blame_user_fqdn' => $data['blame']['user_fqdn'],
Expand Down
87 changes: 83 additions & 4 deletions src/Provider/Doctrine/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use DH\Auditor\Provider\ConfigurationInterface;
use DH\Auditor\Provider\Doctrine\Persistence\Helper\DoctrineHelper;
use DH\Auditor\Provider\Doctrine\Persistence\Helper\SchemaHelper;
use DH\Auditor\Provider\Doctrine\Persistence\Schema\SchemaManager;
use DH\Auditor\Provider\Doctrine\Service\AuditingService;
use Symfony\Component\OptionsResolver\OptionsResolver;
Expand All @@ -21,13 +22,14 @@ final class Configuration implements ConfigurationInterface

private string $tableSuffix;

/**
* @var array<string>
*/
private array $ignoredColumns = [];
private array $ignoredColumns;

private ?array $entities = null;

private array $extraFields = [];

private array $extraIndices = [];

private array $storageServices = [];

private array $auditingServices = [];
Expand Down Expand Up @@ -60,6 +62,20 @@ public function __construct(array $options)
}
}

if (isset($config['extra_fields']) && !empty($config['extra_fields'])) {
// use field names as array keys for easier lookup
foreach ($config['extra_fields'] as $fieldName => $fieldOptions) {
$this->extraFields[$fieldName] = $fieldOptions;
}
}

if (isset($config['extra_indices']) && !empty($config['extra_indices'])) {
// use index names as array keys for easier lookup
foreach ($config['extra_indices'] as $indexName => $indexOptions) {
$this->extraIndices[$indexName] = $indexOptions;
}
}

$this->storageServices = $config['storage_services'];
$this->auditingServices = $config['auditing_services'];
$this->isViewerEnabled = $config['viewer'];
Expand Down Expand Up @@ -191,6 +207,65 @@ public function getEntities(): array
return $this->entities ?? [];
}

public function getExtraFields(): array
{
return $this->extraFields;
}

public function getAllFields(): array
{
return array_merge(
SchemaHelper::getAuditTableColumns(),
$this->extraFields
);
}

/**
* @param array<string, mixed> $extraFields
*/
public function setExtraFields(array $extraFields): self
{
$this->extraFields = $extraFields;

return $this;
}

public function getExtraIndices(): array
{
return $this->extraIndices;
}

public function prepareExtraIndices(string $tablename): array
{
$indices = [];
foreach ($this->extraIndices as $extraIndexField => $extraIndexOptions) {
$indices[$extraIndexField] = [
'type' => $extraIndexOptions['type'] ?? 'index',
'name' => sprintf('%s_%s_idx', $extraIndexOptions['name_prefix'] ?? $extraIndexField, md5($tablename)),
];
}

return $indices;
}

public function getAllIndices(string $tablename): array
{
return array_merge(
SchemaHelper::getAuditTableIndices($tablename),
$this->prepareExtraIndices($tablename)
);
}

/**
* @param array<string, mixed> $extraIndices
*/
public function setExtraIndices(array $extraIndices): self
{
$this->extraIndices = $extraIndices;

return $this;
}

/**
* Enables auditing for a specific entity.
*
Expand Down Expand Up @@ -258,6 +333,8 @@ private function configureOptions(OptionsResolver $resolver): void
'table_suffix' => '_audit',
'ignored_columns' => [],
'entities' => [],
'extra_fields' => [],
'extra_indices' => [],
'storage_services' => [],
'auditing_services' => [],
'viewer' => true,
Expand All @@ -267,6 +344,8 @@ private function configureOptions(OptionsResolver $resolver): void
->setAllowedTypes('table_suffix', 'string')
->setAllowedTypes('ignored_columns', 'array')
->setAllowedTypes('entities', 'array')
->setAllowedTypes('extra_fields', 'array')
->setAllowedTypes('extra_indices', 'array')
->setAllowedTypes('storage_services', 'array')
->setAllowedTypes('auditing_services', 'array')
->setAllowedTypes('viewer', 'bool')
Expand Down
24 changes: 5 additions & 19 deletions src/Provider/Doctrine/DoctrineProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,6 @@
*/
final class DoctrineProvider extends AbstractProvider
{
/**
* @var array<string, string>
*/
private const FIELDS = [
'type' => ':type',
'object_id' => ':object_id',
'discriminator' => ':discriminator',
'transaction_hash' => ':transaction_hash',
'diffs' => ':diffs',
'blame_id' => ':blame_id',
'blame_user' => ':blame_user',
'blame_user_fqdn' => ':blame_user_fqdn',
'blame_user_firewall' => ':blame_user_firewall',
'ip' => ':ip',
'created_at' => ':created_at',
];

private TransactionManager $transactionManager;

public function __construct(ConfigurationInterface $configuration)
Expand Down Expand Up @@ -126,11 +109,14 @@ public function persist(LifecycleEvent $event): void
$entity = $payload['entity'];
unset($payload['table'], $payload['entity']);

$fields = array_combine(array_keys($payload), array_map(function ($x) {return ":{$x}"; }, array_keys($payload)));
\assert(\is_array($fields)); // helps PHPStan

$query = sprintf(
'INSERT INTO %s (%s) VALUES (%s)',
$auditTable,
implode(', ', array_keys(self::FIELDS)),
implode(', ', array_values(self::FIELDS))
implode(', ', array_keys($fields)),
implode(', ', array_values($fields))
);

/** @var StorageService $storageService */
Expand Down
39 changes: 7 additions & 32 deletions src/Provider/Doctrine/Persistence/Reader/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
use DateTimeZone;
use DH\Auditor\Exception\InvalidArgumentException;
use DH\Auditor\Model\Entry;
use DH\Auditor\Provider\Doctrine\Persistence\Helper\SchemaHelper;
use DH\Auditor\Provider\ConfigurationInterface;
use DH\Auditor\Provider\Doctrine\Configuration;
use DH\Auditor\Provider\Doctrine\Persistence\Reader\Filter\DateRangeFilter;
use DH\Auditor\Provider\Doctrine\Persistence\Reader\Filter\FilterInterface;
use DH\Auditor\Provider\Doctrine\Persistence\Reader\Filter\RangeFilter;
Expand All @@ -23,39 +24,12 @@
*/
final class Query
{
/**
* @var string
*/
public const TYPE = 'type';

/**
* @var string
*/
public const CREATED_AT = 'created_at';

/**
* @var string
*/
public const TRANSACTION_HASH = 'transaction_hash';

/**
* @var string
*/
public const OBJECT_ID = 'object_id';

/**
* @var string
*/
public const USER_ID = 'blame_id';

/**
* @var string
*/
public const ID = 'id';

/**
* @var string
*/
public const DISCRIMINATOR = 'discriminator';

private array $filters = [];
Expand All @@ -66,16 +40,17 @@ final class Query

private string $table;

private Configuration $configuration;

private int $offset = 0;

private int $limit = 0;

private DateTimeZone $timezone;

public function __construct(string $table, Connection $connection, string $timezone)
public function __construct(string $table, Connection $connection, ConfigurationInterface $configuration, string $timezone)
{
$this->connection = $connection;
$this->table = $table;
$this->configuration = $configuration;
$this->timezone = new DateTimeZone($timezone);

foreach ($this->getSupportedFilters() as $filterType) {
Expand Down Expand Up @@ -169,7 +144,7 @@ public function limit(int $limit, int $offset = 0): self

public function getSupportedFilters(): array
{
return array_keys(SchemaHelper::getAuditTableIndices('fake'));
return array_keys($this->configuration->getAllIndices('fake'));
}

public function getFilters(): array
Expand Down
Loading

0 comments on commit 3101c09

Please sign in to comment.