laravel-auditing icon indicating copy to clipboard operation
laravel-auditing copied to clipboard

Can I use separate audit table for each model ?

Open webosdeveloper opened this issue 3 years ago • 3 comments

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 ?

webosdeveloper avatar Jun 03 '21 10:06 webosdeveloper

Greetings, I'm having the same issue here. Is there any chance to get this feature very soon ? thanks

khalifaelbanan avatar Sep 16 '21 09:09 khalifaelbanan

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?

MortenDHansen avatar Feb 23 '22 13:02 MortenDHansen

One use case might be if some models using integer and others use uuid as id

nrueckmann avatar Apr 29 '22 08:04 nrueckmann

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

ch1n069 avatar Feb 09 '23 16:02 ch1n069

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.

michaelduregon avatar Feb 09 '23 22:02 michaelduregon

  • 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.

parallels999 avatar Mar 09 '23 15:03 parallels999

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 avatar Mar 14 '23 20:03 MortenDHansen

@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;
});

erikn69 avatar Mar 14 '23 21:03 erikn69