laravel-auditing
laravel-auditing copied to clipboard
Can I use separate audit table for each model ?
Is there any way to use separate audit table for each model as this package "https://github.com/mpociot/versionable#use-different-version-table" allows this thing ?
Greetings, I'm having the same issue here. Is there any chance to get this feature very soon ? thanks
It is not supported, but could probably be implemented if it makes sense to do.
What is the use case / what problem would this solve? Is it because the Audit table grows too large, or are there other concerns to bear in mind?
One use case might be if some models using integer and others use uuid as id
Im having the same issue on my end @MortenDHansen In my application I want to implement different audit tables for each model , let me give a scenario assume we have an application with an Author model and a book model and I want to log the changes that happen in author Model in a table called author_audit_table and as for the book model I want to log the changes into a separate audit table lets say book_audit_table. Rather than storing all those changes in the default Audit table . I would really appreciate a response on this @MortenDHansen
Size is the main issue, we have a table of products that has around 350,000,000 products, expected to grow to around 1,000,000,000 in the next 18 months, these tables have five sub-tables that will have a similar amount of records, having in effect auditing of six billion records all feeding into one table does seem a little restrictive.
It seems the software was written with the intention of having this feature as the "drivers" in audit.php has been structured as an array, not sure what it would take for the author of this system to make this a multi-table audit platform but it would make it a lot more useful for larger projects.
- Related https://github.com/owen-it/laravel-auditing/issues/514
For large scale solutions using this where the number of audited records could exceed millions or even billions (lots of entities, lots of data entry with auto saving features) I think the single table solution would fall over.
Possible Solutions Whle there is different drivers currently available for this to abstract to systems which would be more powerful for dealing with large datasets (file based/elastic search), I think a potential compromise could be to have a config option for the polymorphic relations when using the database driver.
Setting as true by default to allow the current functionality of an audits table, or false to allow any models which use the trait to load from an audits table named using a prefix of the model name with no model column since this can be implied from the table name (or declared if fine tuning needed).
This way less data would need to be stored due to the lack of the polymorphic column, audit operations would be quicker for single entity type auditing, and database limits would less likely be reached.
Even without knowing the codebase that well I can imagine this would be a very large amount of work but I think a very desirable option that I would even be willing to help contribute with if other people agreed and were interested.
We could actually dynamically create a new audit table for each auditable. Same technique could create a new table per month for each auditable. Would require a bit of refactoring, but i guess it would be possible.
The tables would not be managed through the laravel migrations, but prefixed nicely, i would not consider that an issue either.
@MortenDHansen I do it by changing the config on the fly, I don't know if it's the best way, but it has worked for me for years without problems, example:
namespace App;
class AbstractModel extends \Illuminate\Database\Eloquent\Model implements \OwenIt\Auditing\Contracts\Auditable{
use \OwenIt\Auditing\Auditable;
public static function boot() {
parent::boot();
self::creating(function($model) {
self::setAuditTable($model);
});
self::updating(function($model) {
self::setAuditTable($model);
});
self::deleting(function($model) {
self::setAuditTable($model);
});
if(in_array('Illuminate\Database\Eloquent\SoftDeletes', class_uses(get_called_class()))){
self::restoring(function($model){
self::setAuditTable($model);
});
}
}
public function audits(): \Illuminate\Database\Eloquent\Relations\MorphMany{
self::setAuditTable($this);
return $this->morphMany(
\Config::get('audit.implementation', \OwenIt\Auditing\Models\Audit::class),
'auditable'
);
}
public function hasIndividualAudit() :bool {
return $this->individualAudit ?? false;
}
public static function setAuditTable($model = null){
if(is_null($model)){
$name=get_called_class();
$model=new $name();
}
$audit_table = 'audits';
if ($model->hasIndividualAudit()) {
$audit_table .= '_' . $model->getTable();
}
config(['audit.drivers.database.table' => $audit_table]);
}
}
All my audited models extends AbstractModel
namespace App\Models;
class MyModel extends \App\AbstractModel {
public $individualAudit = true;
}
I have a separate connection, a database only for audits tables, also the database name could be per year
Also, it needs a custom migration for reading all the models and create audits table when hasIndividualAudit()
is true
parent::up(); // create original table
$files = glob(app_path('Models/*.php'));
\Illuminate\Support\Collection::make($files)->map(function ($path) {
try{
$class = '\\App\Models\\'.pathinfo($path, PATHINFO_FILENAME);
$model = new $class();
if (! $model->hasIndividualAudit()) {
return null;
}
config(['audit.drivers.database.table' => 'audits_' . $model->getTable()]);
parent::up(); // create individual table
}catch(\Throwable $e){ }
return null;
});