owen-it / laravel-auditing

Record the change log from models in Laravel
https://laravel-auditing.com
MIT License
3.03k stars 391 forks source link

Invalid resolver implementation error for custom resolver #977

Closed rizkyzhang closed 1 week ago

rizkyzhang commented 1 week ago

PHP Version

8.2.24

Laravel Version

11.6

Package Version

13.6.8

Description

I am trying to create a request id custom resolver to assign it to request_column which I add from a new migration.

Error message:

{
    "message": "Invalid Resolver implementation for: request_id",
    "exception": "OwenIt\\Auditing\\Exceptions\\AuditingException",
    "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/owen-it/laravel-auditing/src/Auditable.php",
    "line": 411,
    "trace": [
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/owen-it/laravel-auditing/src/Auditable.php",
            "line": 420,
            "function": "runResolvers",
            "class": "App\\Models\\Product",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/owen-it/laravel-auditing/src/AuditableObserver.php",
            "line": 108,
            "function": "preloadResolverData",
            "class": "App\\Models\\Product",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/owen-it/laravel-auditing/src/AuditableObserver.php",
            "line": 41,
            "function": "dispatchAudit",
            "class": "OwenIt\\Auditing\\AuditableObserver",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php",
            "line": 478,
            "function": "created",
            "class": "OwenIt\\Auditing\\AuditableObserver",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php",
            "line": 286,
            "function": "Illuminate\\Events\\{closure}",
            "class": "Illuminate\\Events\\Dispatcher",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php",
            "line": 266,
            "function": "invokeListeners",
            "class": "Illuminate\\Events\\Dispatcher",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasEvents.php",
            "line": 215,
            "function": "dispatch",
            "class": "Illuminate\\Events\\Dispatcher",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php",
            "line": 1324,
            "function": "fireModelEvent",
            "class": "Illuminate\\Database\\Eloquent\\Model",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php",
            "line": 1142,
            "function": "performInsert",
            "class": "Illuminate\\Database\\Eloquent\\Model",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php",
            "line": 1069,
            "function": "save",
            "class": "Illuminate\\Database\\Eloquent\\Model",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Support/helpers.php",
            "line": 359,
            "function": "Illuminate\\Database\\Eloquent\\{closure}",
            "class": "Illuminate\\Database\\Eloquent\\Builder",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php",
            "line": 1068,
            "function": "tap"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Support/Traits/ForwardsCalls.php",
            "line": 23,
            "function": "create",
            "class": "Illuminate\\Database\\Eloquent\\Builder",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php",
            "line": 2340,
            "function": "forwardCallTo",
            "class": "Illuminate\\Database\\Eloquent\\Model",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php",
            "line": 2352,
            "function": "__call",
            "class": "Illuminate\\Database\\Eloquent\\Model",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/app/Http/Controllers/ProductController.php",
            "line": 30,
            "function": "__callStatic",
            "class": "Illuminate\\Database\\Eloquent\\Model",
            "type": "::"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php",
            "line": 46,
            "function": "store",
            "class": "App\\Http\\Controllers\\ProductController",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Routing/Route.php",
            "line": 260,
            "function": "dispatch",
            "class": "Illuminate\\Routing\\ControllerDispatcher",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Routing/Route.php",
            "line": 206,
            "function": "runController",
            "class": "Illuminate\\Routing\\Route",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
            "line": 806,
            "function": "run",
            "class": "Illuminate\\Routing\\Route",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
            "line": 144,
            "function": "Illuminate\\Routing\\{closure}",
            "class": "Illuminate\\Routing\\Router",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php",
            "line": 50,
            "function": "Illuminate\\Pipeline\\{closure}",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
            "line": 183,
            "function": "handle",
            "class": "Illuminate\\Routing\\Middleware\\SubstituteBindings",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Auth/Middleware/Authenticate.php",
            "line": 64,
            "function": "Illuminate\\Pipeline\\{closure}",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
            "line": 183,
            "function": "handle",
            "class": "Illuminate\\Auth\\Middleware\\Authenticate",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
            "line": 119,
            "function": "Illuminate\\Pipeline\\{closure}",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
            "line": 805,
            "function": "then",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
            "line": 784,
            "function": "runRouteWithinStack",
            "class": "Illuminate\\Routing\\Router",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
            "line": 748,
            "function": "runRoute",
            "class": "Illuminate\\Routing\\Router",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
            "line": 737,
            "function": "dispatchToRoute",
            "class": "Illuminate\\Routing\\Router",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php",
            "line": 200,
            "function": "dispatch",
            "class": "Illuminate\\Routing\\Router",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
            "line": 144,
            "function": "Illuminate\\Foundation\\Http\\{closure}",
            "class": "Illuminate\\Foundation\\Http\\Kernel",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php",
            "line": 21,
            "function": "Illuminate\\Pipeline\\{closure}",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ConvertEmptyStringsToNull.php",
            "line": 31,
            "function": "handle",
            "class": "Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
            "line": 183,
            "function": "handle",
            "class": "Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php",
            "line": 21,
            "function": "Illuminate\\Pipeline\\{closure}",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php",
            "line": 51,
            "function": "handle",
            "class": "Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
            "line": 183,
            "function": "handle",
            "class": "Illuminate\\Foundation\\Http\\Middleware\\TrimStrings",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Http/Middleware/ValidatePostSize.php",
            "line": 27,
            "function": "Illuminate\\Pipeline\\{closure}",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
            "line": 183,
            "function": "handle",
            "class": "Illuminate\\Http\\Middleware\\ValidatePostSize",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php",
            "line": 110,
            "function": "Illuminate\\Pipeline\\{closure}",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
            "line": 183,
            "function": "handle",
            "class": "Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Http/Middleware/HandleCors.php",
            "line": 62,
            "function": "Illuminate\\Pipeline\\{closure}",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
            "line": 183,
            "function": "handle",
            "class": "Illuminate\\Http\\Middleware\\HandleCors",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Http/Middleware/TrustProxies.php",
            "line": 57,
            "function": "Illuminate\\Pipeline\\{closure}",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
            "line": 183,
            "function": "handle",
            "class": "Illuminate\\Http\\Middleware\\TrustProxies",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
            "line": 119,
            "function": "Illuminate\\Pipeline\\{closure}",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php",
            "line": 175,
            "function": "then",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php",
            "line": 144,
            "function": "sendRequestThroughRouter",
            "class": "Illuminate\\Foundation\\Http\\Kernel",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Foundation/Application.php",
            "line": 1172,
            "function": "handle",
            "class": "Illuminate\\Foundation\\Http\\Kernel",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/public/index.php",
            "line": 17,
            "function": "handleRequest",
            "class": "Illuminate\\Foundation\\Application",
            "type": "->"
        },
        {
            "file": "/home/coderz/Projects/personal/learning/laravel-api/vendor/laravel/framework/src/Illuminate/Foundation/resources/server.php",
            "line": 16,
            "function": "require_once"
        }
    ]
}

Here is the migration file:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::table('audits', function (Blueprint $table) {
            $table->string('request_id')->nullable()->after('tags');
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::table('audits', function (Blueprint $table) {
            $table->dropColumn('request_id');
        });
    }
};

Here is the custom resolver:

<?php

namespace App\AuditResolvers;

use Illuminate\Support\Facades\Request;
use Illuminate\Support\Str;
use OwenIt\Auditing\Contracts\Auditable;
use OwenIt\Auditing\Contracts\Resolver;

class RequestIdResolver implements Resolver
{
    public static function resolve(Auditable $auditable): string
    {
      return Request::header('X-Request-ID') ?? (string) Str::ulid();
    }
}

Here is the audit resolver config:

    'resolvers' => [
        'ip_address' => OwenIt\Auditing\Resolvers\IpAddressResolver::class,
        'user_agent' => OwenIt\Auditing\Resolvers\UserAgentResolver::class,
        'url'        => OwenIt\Auditing\Resolvers\UrlResolver::class,
        'request_id' => app\AuditResolvers\RequestIdResolver::class,
    ],

Here is the model:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use OwenIt\Auditing\Contracts\Auditable;

class Product extends Model implements Auditable
{
    use \OwenIt\Auditing\Auditable;
    use HasFactory;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name',
        'description',
        'price',
    ];
}

Steps To Reproduce

  1. Create a migration file to add a new column
  2. Create a custom resolver
  3. Add the custom resolver to the resolvers array on audit config

Possible Solutions

No response

rizkyzhang commented 1 week ago

Fixed: typo in custom resolver namespace