Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add extra fields and indices to audit tables, based on configuration #61

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions composer.json
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
"ext-json": "*",
"doctrine/annotations": "^1.8",
"doctrine/orm": "^2.7",
"symfony/cache": "^4.0|^5.0",
"symfony/event-dispatcher": "^4.0|^5.0",
"symfony/lock": "^4.0|^5.0",
"symfony/options-resolver": "^4.0|^5.0"
"symfony/cache": "^4.0|^5.0|^6.0",
"symfony/event-dispatcher": "^4.0|^5.0|^6.0",
"symfony/lock": "^4.0|^5.0|^6.0",
"symfony/options-resolver": "^4.0|^5.0|^6.0"
},
"suggest": {
"damienharper/auditor-bundle": "Integrate auditor library in your Symfony projects."
Expand All @@ -42,7 +42,7 @@
"phpstan/phpstan-doctrine": "^1.0",
"phpstan/phpstan-strict-rules": "^1.0",
"phpunit/phpunit": "^9.0",
"symfony/var-dumper": "^4.0|^5.0"
"symfony/var-dumper": "^4.0|^5.0|^6.0"
},
"conflict": {
"doctrine/persistence": "<1.3"
Expand Down
97 changes: 93 additions & 4 deletions src/Provider/Doctrine/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace DH\Auditor\Provider\Doctrine;

use DH\Auditor\Provider\ConfigurationInterface;
use DH\Auditor\Provider\Doctrine\Persistence\Helper\SchemaHelper;
use DH\Auditor\Provider\Doctrine\Service\AuditingService;
use Symfony\Component\OptionsResolver\OptionsResolver;

Expand All @@ -23,6 +24,16 @@ class Configuration implements ConfigurationInterface
*/
private $tableSuffix;

/**
* @var array
*/
private $extraFields = [];

/**
* @var array
*/
private $extraIndices = [];

/**
* @var array
*/
Expand Down Expand Up @@ -75,6 +86,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 All @@ -90,6 +115,8 @@ public function configureOptions(OptionsResolver $resolver): void
'table_suffix' => '_audit',
'ignored_columns' => [],
'entities' => [],
'extra_fields' => [],
'extra_indices' => [],
'storage_services' => [],
'auditing_services' => [],
'viewer' => true,
Expand All @@ -99,6 +126,8 @@ public 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 Expand Up @@ -179,6 +208,69 @@ public function getIgnoredColumns(): array
return $this->ignoredColumns;
}

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

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

/**
* @param array<string, mixed> $extraFields
*
* @return $this
*/
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
*
* @return $this
*/
public function setExtraIndices(array $extraIndices): self
{
$this->extraIndices = $extraIndices;

return $this;
}

/**
* Get the value of entities.
*/
Expand Down Expand Up @@ -238,10 +330,7 @@ public function setStorageMapper(callable $mapper): self
return $this;
}

/**
* @return null|callable|string
*/
public function getStorageMapper()
public function getStorageMapper(): ?callable
{
return $this->storageMapper;
}
Expand Down
22 changes: 2 additions & 20 deletions src/Provider/Doctrine/DoctrineProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,6 @@ public function getStorageServiceForEntity(string $entity): StorageServiceInterf
return array_values($this->getStorageServices())[0];
}

\assert(\is_callable($storageMapper)); // helps PHPStan

return $storageMapper($entity, $this->getStorageServices());
}

Expand All @@ -97,19 +95,8 @@ public function persist(LifecycleEvent $event): void
$entity = $payload['entity'];
unset($payload['table'], $payload['entity']);

$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',
];
$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)',
Expand All @@ -127,11 +114,6 @@ public function persist(LifecycleEvent $event): void
}

$statement->execute();

// let's get the last inserted ID from the database so other providers can use that info
$payload = $event->getPayload();
$payload['id'] = (int) $storageService->getEntityManager()->getConnection()->lastInsertId();
$event->setPayload($payload);
}

/**
Expand Down
13 changes: 11 additions & 2 deletions src/Provider/Doctrine/Persistence/Reader/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

use DH\Auditor\Exception\InvalidArgumentException;
use DH\Auditor\Model\Entry;
use DH\Auditor\Provider\ConfigurationInterface;
use DH\Auditor\Provider\Doctrine\Configuration;
use DH\Auditor\Provider\Doctrine\Persistence\Helper\SchemaHelper;
use DH\Auditor\Provider\Doctrine\Persistence\Reader\Filter\DateRangeFilter;
use DH\Auditor\Provider\Doctrine\Persistence\Reader\Filter\FilterInterface;
Expand Down Expand Up @@ -44,6 +46,11 @@ class Query
*/
private $table;

/**
* @var Configuration
*/
private $configuration;

/**
* @var int
*/
Expand All @@ -54,10 +61,12 @@ class Query
*/
private $limit = 0;

public function __construct(string $table, Connection $connection)
public function __construct(string $table, Connection $connection, ConfigurationInterface $configuration)
{
$this->connection = $connection;
$this->table = $table;
\assert($configuration instanceof Configuration);
$this->configuration = $configuration;

foreach ($this->getSupportedFilters() as $filterType) {
$this->filters[$filterType] = [];
Expand Down Expand Up @@ -162,7 +171,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
17 changes: 16 additions & 1 deletion src/Provider/Doctrine/Persistence/Reader/Reader.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@ public function createQuery(string $entity, array $options = []): Query
/** @var StorageService $storageService */
$storageService = $this->provider->getStorageServiceForEntity($entity);

$query = new Query($this->getEntityAuditTableName($entity), $storageService->getEntityManager()->getConnection());
$query = new Query(
$this->getEntityAuditTableName($entity),
$storageService->getEntityManager()->getConnection(),
$this->provider->getConfiguration()
);
$query
->addOrderBy(Query::CREATED_AT, 'DESC')
->addOrderBy(Query::ID, 'DESC')
Expand Down Expand Up @@ -81,6 +85,12 @@ public function createQuery(string $entity, array $options = []): Query
$query->addFilter(new SimpleFilter(Query::DISCRIMINATOR, $entity));
}

foreach ($this->provider->getConfiguration()->getExtraIndices() as $indexedField => $extraIndexConfig) {
if (null !== $config[$indexedField]) {
$query->addFilter($indexedField, $config[$indexedField]);
}
}

return $query;
}

Expand Down Expand Up @@ -109,6 +119,11 @@ public function configureOptions(OptionsResolver $resolver): void
return null === $value || $value >= 1;
})
;

foreach ($this->provider->getConfiguration()->getExtraIndices() as $indexedField => $extraIndexConfig) {
$resolver->setDefault($indexedField, null);
$resolver->setAllowedTypes($indexedField, ['null', 'int', 'string', 'array']);
}
}

/**
Expand Down
11 changes: 6 additions & 5 deletions src/Provider/Doctrine/Persistence/Schema/SchemaManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
use DH\Auditor\Provider\Doctrine\DoctrineProvider;
use DH\Auditor\Provider\Doctrine\Persistence\Helper\DoctrineHelper;
use DH\Auditor\Provider\Doctrine\Persistence\Helper\PlatformHelper;
use DH\Auditor\Provider\Doctrine\Persistence\Helper\SchemaHelper;
use DH\Auditor\Provider\Doctrine\Service\AuditingService;
use DH\Auditor\Provider\Doctrine\Service\StorageService;
use Doctrine\DBAL\Connection;
Expand Down Expand Up @@ -188,7 +187,7 @@ public function createAuditTable(string $entity, $table, ?Schema $schema = null)

// Add columns to audit table
$isJsonSupported = PlatformHelper::isJsonSupported($connection);
foreach (SchemaHelper::getAuditTableColumns() as $columnName => $struct) {
foreach ($configuration->getAllFields() as $columnName => $struct) {
if (DoctrineHelper::getDoctrineType('JSON') === $struct['type'] && $isJsonSupported) {
$type = DoctrineHelper::getDoctrineType('TEXT');
} else {
Expand All @@ -199,7 +198,7 @@ public function createAuditTable(string $entity, $table, ?Schema $schema = null)
}

// Add indices to audit table
foreach (SchemaHelper::getAuditTableIndices($auditTablename) as $columnName => $struct) {
foreach ($configuration->getAllIndices($auditTablename) as $columnName => $struct) {
if ('primary' === $struct['type']) {
$auditTable->setPrimaryKey([$columnName]);
} else {
Expand Down Expand Up @@ -232,14 +231,16 @@ public function updateAuditTable(string $entity, Table $table, ?Schema $schema =
$schema = $schemaManager->createSchema();
}

/** @var Configuration $configuration */
$configuration = $this->provider->getConfiguration();
$table = $schema->getTable($table->getName());
$columns = $schemaManager->listTableColumns($table->getName());

// process columns
$this->processColumns($table, $columns, SchemaHelper::getAuditTableColumns(), $connection);
$this->processColumns($table, $columns, $configuration->getAllFields(), $connection);

// process indices
$this->processIndices($table, SchemaHelper::getAuditTableIndices($table->getName()), $connection);
$this->processIndices($table, $configuration->getAllIndices($table->getName()), $connection);

return $schema;
}
Expand Down
Loading