Hide some fields from AuditLog, make it handle entities better, improve table display.

This commit is contained in:
Buster Neece 2019-08-15 14:01:00 -05:00
parent 3384002979
commit b13752d827
No known key found for this signature in database
GPG Key ID: 6D9E12FF03411F4E
5 changed files with 80 additions and 26 deletions

View File

@ -7,10 +7,12 @@ use App\Annotations\AuditLog\AuditIgnore;
use App\Entity;
use Doctrine\Common\Annotations\Reader;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Event\OnFlushEventArgs;
use Doctrine\ORM\Events;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Proxy\Proxy;
/**
* A hook into Doctrine's event listener to write changes to "Auditable"
@ -63,16 +65,34 @@ class AuditLog implements EventSubscriber
}
// Get the changes made to the entity.
$changes = $uow->getEntityChangeSet($entity);
$changesRaw = $uow->getEntityChangeSet($entity);
// Look for the @AuditIgnore annotation on properties.
foreach ($changes as $change_field => $field_changes) {
$property = $reflectionClass->getProperty($change_field);
$changes = [];
foreach ($changesRaw as $changeField => [$fieldPrev, $fieldNow]) {
// With new entity creation, fields left NULL are still included.
if ($fieldPrev === $fieldNow) {
continue;
}
// Ensure the property isn't ignored.
$property = $reflectionClass->getProperty($changeField);
$annotation = $this->reader->getPropertyAnnotation($property, AuditIgnore::class);
if (null !== $annotation) {
unset($changes[$change_field]);
continue;
}
// Check if either field value is an object.
if ($this->isEntity($em, $fieldPrev)) {
$fieldPrev = $this->getIdentifier(new \ReflectionObject($fieldPrev), $fieldPrev);
}
if ($this->isEntity($em, $fieldNow)) {
$fieldNow = $this->getIdentifier(new \ReflectionObject($fieldNow), $fieldNow);
}
$changes[$changeField] = [$fieldPrev, $fieldNow];
}
if (Entity\AuditLog::OPER_UPDATE === $changeType && empty($changes)) {
@ -199,6 +219,28 @@ class AuditLog implements EventSubscriber
}
}
/**
* @param EntityManager $em
* @param object|string $class
* @return bool
*/
protected function isEntity(EntityManager $em, $class): bool
{
if (is_object($class)) {
$class = ($class instanceof Proxy)
? get_parent_class($class)
: get_class($class);
} else if (!is_string($class)) {
return false;
}
if (!class_exists($class)) {
return false;
}
return !$em->getMetadataFactory()->isTransient($class);
}
/**
* Get the identifier string for an entity, if it's set or fetchable.
*

View File

@ -25,12 +25,18 @@ class ApiKey implements \JsonSerializable
/**
* @ORM\Column(name="verifier", type="string", length=128, nullable=false)
*
* @AuditLog\AuditIgnore()
*
* @var string
*/
protected $verifier;
/**
* @ORM\Column(name="user_id", type="integer")
*
* @AuditLog\AuditIgnore()
*
* @var int
*/
protected $user_id;

View File

@ -111,6 +111,8 @@ class Station
/**
* @ORM\Column(name="adapter_api_key", type="string", length=150, nullable=true)
*
* @AuditLog\AuditIgnore()
*
* @var string|null An internal-use API key used for container-to-container communications from Liquidsoap to AzuraCast
*/
protected $adapter_api_key;

View File

@ -93,6 +93,8 @@ class User
/**
* @ORM\Column(name="created_at", type="integer")
*
* @AuditLog\AuditIgnore()
*
* @OA\Property(example=SAMPLE_TIMESTAMP)
* @var int
*/

View File

@ -26,28 +26,30 @@ $assets
</div>
<h2 class="card-title"></h2>
</div>
<table class="table-responsive data-table table table-striped align-middle">
<colgroup>
<col width="20%">
<col width="25%">
<col width="5%">
<col width="20%">
<col width="20%">
<col width="10%">
</colgroup>
<thead>
<tr>
<th data-column-id="date_time" data-formatter="datetime"><?=__('Date/Time') ?></th>
<th data-column-id="user"><?=__('User') ?></th>
<th data-column-id="operation" data-formatter="operation" data-sortable="false">&nbsp;</th>
<th data-column-id="identifier" data-formatter="identifier"><?=__('Identifier') ?></th>
<th data-column-id="target" data-formatter="target"><?=__('Target') ?></th>
<th data-column-id="actions" data-formatter="actions" data-sortable="false"><?=__('Actions') ?></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div class="table-responsive">
<table class="data-table table table-striped align-middle">
<colgroup>
<col width="20%">
<col width="25%">
<col width="5%">
<col width="20%">
<col width="20%">
<col width="10%">
</colgroup>
<thead>
<tr>
<th data-column-id="date_time" data-formatter="datetime"><?=__('Date/Time') ?></th>
<th data-column-id="user"><?=__('User') ?></th>
<th data-column-id="operation" data-formatter="operation" data-sortable="false">&nbsp;</th>
<th data-column-id="identifier" data-formatter="identifier"><?=__('Identifier') ?></th>
<th data-column-id="target" data-formatter="target"><?=__('Target') ?></th>
<th data-column-id="actions" data-formatter="actions" data-sortable="false"><?=__('Actions') ?></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
<div class="modal fade" id="mdl-changes" tabindex="-1" role="dialog">