damienharper/auditor-doctrine-provider
Doctrine ORM provider for DamienHarper/auditor. Automatically records audit logs for Doctrine entities (create/update/delete) with DBAL/ORM integration and configurable auditing, making change tracking and accountability easy in PHP applications.
## Getting Started
### **Minimal Setup**
1. **Installation**
Add the package via Composer (updated for 1.2.0):
```bash
composer require damienharper/auditor-doctrine-provider:^1.2.0
Ensure audit is installed (this package extends its functionality):
composer require ocramius/audit
Register the Provider
In config/audit.php, add the Doctrine provider:
'providers' => [
\DamienHarper\AuditorDoctrineProvider\DoctrineProvider::class,
],
Configure Doctrine
Ensure your EntityManager is properly configured. The provider auto-detects it, but verify lifecycle callbacks are enabled in your entities:
use Doctrine\ORM\Mapping as ORM;
/** @ORM\Entity @ORM\HasLifecycleCallbacks */
class User { ... }
First Audit
Use the Auditor facade to log changes (now correctly handles inverse-side OneToMany associations):
use Audit;
$user = User::find(1);
$user->name = 'Updated Name';
Audit::log($user); // Automatically captures changes, including inverse-side associations
preUpdate, prePersist, and preRemove events. New in 1.2.0: Fixed inverse-side OneToMany association auditing.config/audit.php for provider-specific settings (e.g., ignored attributes, metadata).@ORM\HasLifecycleCallbacks and @ORM\Entity.// Example: User has OneToMany relationship with Posts
use Doctrine\ORM\Event\LifecycleEventArgs;
use Audit;
class User {
/** @ORM\OneToMany(targetEntity="Post", mappedBy="user") */
private $posts;
public function preUpdate(LifecycleEventArgs $args) {
$auditor = new \Audit();
$auditor->log($this); // Now correctly logs inverse-side (Post) changes
}
}
Leverage Doctrine’s lifecycle events for seamless integration. The fix in 1.2.0 ensures inverse-side associations are audited:
// In a Doctrine subscriber or entity listener
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\PreUpdateEventArgs;
use Audit;
class AuditSubscriber implements EventSubscriber {
public function getSubscribedEvents() {
return ['preUpdate', 'prePersist', 'preRemove'];
}
public function preUpdate(PreUpdateEventArgs $args) {
$entity = $args->getEntity();
Audit::log($entity); // Now includes inverse-side OneToMany changes
}
}
Override default behavior via config/audit.php:
'audit' => [
'providers' => [
\DamienHarper\AuditorDoctrineProvider\DoctrineProvider::class => [
'ignored_attributes' => ['password', 'temp_token'],
'metadata' => [
'User' => [
'audit_table' => 'user_audit_logs',
'audit_columns' => ['id', 'name', 'email'],
],
'Post' => [ // Explicitly define for inverse-side associations
'audit_table' => 'post_audit_logs',
],
],
],
],
],
For mass updates (e.g., via QueryBuilder), manually log changes. Note: The 1.2.0 fix ensures inverse-side associations are captured even in bulk operations:
$userIds = [1, 2, 3];
$users = User::whereIn('id', $userIds)->get();
foreach ($users as $user) {
$user->status = 'active';
Audit::log($user); // Logs changes, including inverse-side (Post) updates
}
If using Laravel + Doctrine (e.g., via laravel-doctrine), bind the EntityManager:
// In a service provider
$this->app->bind(\Doctrine\ORM\EntityManagerInterface::class, function ($app) {
return Doctrine::entityManager();
});
Use the Audit facade to fetch logs for entities and their inverse-side associations:
$logs = Audit::find(User::class, 1); // Get audit logs for User#1 (and related Posts)
$logs = Audit::all(); // All logs (provider-dependent)
Missing Lifecycle Callbacks
@ORM\HasLifecycleCallbacks, events may not trigger.@HasLifecycleCallbacks to entities or use a global subscriber.Inverse-Side OneToMany Associations (Fixed in 1.2.0)
^1.2.0 and ensure your entities have proper @ORM\OneToMany/@ORM\ManyToOne mappings.Circular Dependencies
postUpdate/postPersist if using pre* events.Performance Overhead
ignored_attributes).Doctrine Version Mismatch
Enable Doctrine Logging
$entityManager->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger());
Verify events fire during updates, especially for inverse-side associations.
Check Audit Configuration
Ensure the provider is listed in config/audit.php and Doctrine is autowired.
Inspect Entity Metadata Use Doctrine’s metadata tools:
php bin/console doctrine:metadata:info Your\Entity
Log Provider Output
Temporarily enable debug mode in config/audit.php:
'debug' => true,
Verify Inverse-Side Associations After updating to 1.2.0, test bulk operations to confirm inverse-side associations are logged:
$user1 = new User(); $user1->posts = [new Post(), new Post()];
$user2 = new User(); $user2->posts = [new Post()];
$entityManager->persist($user1);
$entityManager->persist($user2);
$entityManager->flush(); // All Post entities should now be audited
Custom Audit Tables Extend the provider to support multiple schemas/tables:
class CustomDoctrineProvider extends \DamienHarper\AuditorDoctrineProvider\DoctrineProvider {
protected function getAuditTable($entityName) {
return "audit_{$entityName}_logs";
}
}
Pre/Post-Processing
Hook into Audit::log() to modify payloads:
Audit::extend(function ($auditor, $entity) {
$auditor->setMetadata('custom_field', 'value');
});
Conditional Logging Skip audits for specific actions:
if (!$this->shouldAudit()) {
return;
}
Audit::log($entity);
Testing Inverse-Side Associations Add tests for bulk operations with inverse-side relationships:
public function testBulkInverseSideAudit() {
$user1 = new User(); $user1->posts = [new Post(), new Post()];
$user2 = new User(); $user2->posts = [new Post()];
$entityManager->persist($user1);
$entityManager->persist($user2);
$entityManager->flush();
$this->assertCount(3, Audit::find(Post::class)); // All Posts audited
}
How can I help you explore Laravel packages today?