Laravel-activitylog: How to use activitylog with spatie/permissons?

Created on 30 Dec 2017  路  14Comments  路  Source: spatie/laravel-activitylog

Hello together,

I would like to log the activities for the permissions. For this I created new Models of roles and permission. But I don't see any log in the database:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Spatie\Permission\Models\Permission as SpatiePermission;
use Spatie\Activitylog\Traits\LogsActivity;
use Illuminate\Database\Eloquent\SoftDeletes;

class Permission extends SpatiePermission
{
    use LogsActivity;
    /** The following change of attributes will be logged. */
    //protected static $logAttributes = ['name', 'text'];

    /** Alternativly we can define that following attribute changes should be not recoreded */
    //protected static $ignoreChangedAttributes = ['text'];

    /** Only the `deleted` event will get logged automatically */
    //protected static $recordEvents = ['deleted'];
    protected static $logOnlyDirty = true;

    //use SoftDeletes; // ad in schema $table->softDeletes();
}

config/permissions.php

<?php

return [

    'models' => [

        /*
         * When using the "HasRoles" trait from this package, we need to know which
         * Eloquent model should be used to retrieve your permissions. Of course, it
         * is often just the "Permission" model but you may use whatever you like.
         *
         * The model you want to use as a Permission model needs to implement the
         * `Spatie\Permission\Contracts\Permission` contract.
         */

        // 'permission' => Spatie\Permission\Models\Permission::class,
        'permission' => \App\Models\Permission::class,

        /*
         * When using the "HasRoles" trait from this package, we need to know which
         * Eloquent model should be used to retrieve your roles. Of course, it
         * is often just the "Role" model but you may use whatever you like.
         *
         * The model you want to use as a Role model needs to implement the
         * `Spatie\Permission\Contracts\Role` contract.
         */

        //'role' => Spatie\Permission\Models\Role::class,
        'role' => \App\Models\Role::class,

    ],

Did I missed anything?

Thank you.

Most helpful comment

the problem is right there. Please change this line use Spatie\Permission\Models\Permission; to use App\Permission.

You need to use the extended/new models which you have created.

All 14 comments

Hi!

The way you've set it up should be good. Did you try adding the LogsActivity trait to another simple Laravel model (e.g. User) to see if that works?

When I use Auth::user()->activity it returns me an empty array. What can be in this case? I'm using the HasActivity trait in the User model.

Do I have to do anything else besides that?

I think you should be using the CausesActivity trait on the user and the LogsActivity trait on the Permission model.

If that's not working out you can try activity()->causedBy(auth()->user())->log('just a test'); and check the existence of that log entry in the database.

I'm having the same issue. Activity logs are working fine in my other simple models and only these two Permission and Role models are not working. here's my code.

namespace App;

use Spatie\Permission\Models\Permission as SpatiePermission;
use Spatie\Activitylog\Traits\LogsActivity;
use Illuminate\Database\Eloquent\Model;

class Permission extends SpatiePermission
{
    use LogsActivity;
    protected static $logName = 'permissions';
    protected static $logAttributes = ['*'];

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

@lionwalker what do you mean with are not working? Without more detailed explanation of the error/unexpected behavior we can't help you to fix it.

Sorry, Since making changes to vendor folder models is a bad practice, i have created two models in app folder named Permission and Role. then i change config/permission.php model paths to as follows.

'permission' => App\Permission::class,
'role' => App\Role::class,

Then i wrote my custom model as follows and did the same to roles model,

namespace App;

use Spatie\Permission\Models\Permission as SpatiePermission;
use Spatie\Activitylog\Traits\LogsActivity;
use Illuminate\Database\Eloquent\Model;

class Permission extends SpatiePermission
{
    use LogsActivity;
    protected static $logName = 'permissions';
    protected static $logAttributes = ['*'];

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

issue is when i add _use LogsActivity;_ to vendor folder models it's working and when i add it to my app folder model it's not working.

@lionwalker did you change default models in config/permissions.php and are you using extended models to CRUD your roles and permissions?

If not, don't forget to config:cache after applying changes.

Note: You do not need to "use Illuminate\Database\Eloquent\Model;" in extended models because they are already using it.

'models' => [

    /*
     * When using the "HasRoles" trait from this package, we need to know which
     * Eloquent model should be used to retrieve your permissions. Of course, it
     * is often just the "Permission" model but you may use whatever you like.
     *
     * The model you want to use as a Permission model needs to implement the
     * `Spatie\Permission\Contracts\Permission` contract.
     */

//        'permission' => Spatie\Permission\Models\Permission::class,
           'permission' => App\Permission::class,

    /*
     * When using the "HasRoles" trait from this package, we need to know which
     * Eloquent model should be used to retrieve your roles. Of course, it
     * is often just the "Role" model but you may use whatever you like.
     *
     * The model you want to use as a Role model needs to implement the
     * `Spatie\Permission\Contracts\Role` contract.
     */

//        'role' => Spatie\Permission\Models\Role::class,
           'role' => App\Role::class

],`

@junaid-A-khan yes, i changed the default models and i extended models to only add activity logs to it as in my code.

@lionwalker can we see your complete controller file(s) which you are using for roles/permissions ?
and please try "composer dump-autoload" .

I have the same setup and it works flawlessly.

@junaid-A-khan

Ok sure, this is the permission controller.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Spatie\Permission\Models\Permission;

class PermissionController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        //
        return view('auth.permission');
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        //
        Permission::create(['name'=>$request['name']]);
        return "Permission successfully added!";
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        //
        $permission = Permission::findById($id);
        $permission->name = $request->name;
        $permission->save();
        return "Permission successfully updated!";
    }

    /**
     * Return JSON array for datatable.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function datatable(Request $request)
    {
        //
        $user = auth()->user();
        $order_by = $_REQUEST['order']; // This array contains order information of clicked column
        $search = $_REQUEST['search']['value']; // This array contains search value information datatable
        $start = $_REQUEST['start']; // start limit of data
        $length = $_REQUEST['length']; // end limit of data
        $order_by_str = $order_by[0]['dir'];
        if ($order_by[0]['column']==0){
            $order_column = "id";
        }
        if ($order_by[0]['column']==1){
            $order_column = "name";
        }
        if ($order_by[0]['column']==2){
            $order_column = "guard_name";
        }
        $where_query = array();
        if ($search!='' || $search!=NULL) {
            array_push($where_query,array('id','like',"%$search%"));
            array_push($where_query,array('name','like',"%$search%"));
            array_push($where_query,array('guard_name','like',"%$search%"));
        }

        if (count($where_query)==0)
        {
            $permissions = DB::table('permissions')
                ->select('id','name','guard_name')
                ->orderBy($order_column, $order_by_str)
                ->offset($start)
                ->limit($length)
                ->get();
            $permissions_count = DB::table('permissions')
                ->select('id')
                ->get();
        } else {
            $permissions = DB::table('permissions')
                ->select('id','name','guard_name')
                ->where($where_query)
                ->orderBy($order_column, $order_by_str)
                ->offset($start)
                ->limit($length)
                ->get();
            $permissions_count = DB::table('permissions')
                ->select('id')
                ->where($where_query)
                ->get();
        }

        $data[][] = array();
        $i = 0;
        $edit_btn = "";
        $delete_btn = "";
        $can_edit = 0;
        $can_delete = 0;
        if ($user->can('edit_permission')){
            $can_edit = 1;
        }
        if ($user->can('delete_permission')){
            $can_delete = 1;
        }
        foreach ($permissions as $permission)
        {
            if ($can_edit) {
                $edit_btn = "<i class='btn icon-md icon-pencil' data-toggle='modal' data-target='#edit_data_modal' data-id='{$permission->id}' data-name='{$permission->name}'></i>&nbsp;";
            }
            if ($can_delete) {
                $delete_btn = "<i class='btn icon-md icon-trash' onclick='deleteItem({$permission->id})'></i>";
            }
            $data[$i] = array(
                $permission->id,
                $permission->name,
                $permission->guard_name,
                $edit_btn.$delete_btn
            );
            $i++;
        }

        $totalRecords = $permissions_count->count();
        if ($totalRecords==0){
            $data = array();
        }
        $json_data = array(
            "draw"            => intval($_REQUEST['draw']),
            "recordsTotal"    => intval($totalRecords),
            "recordsFiltered" => intval($totalRecords),
            "data"            => $data   // total data array
        );
        $json_data = json_encode($json_data);
        return $json_data;
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        //
        $permission = Permission::findById($id);
        $permission->delete();
        return 0;
    }
}

the problem is right there. Please change this line use Spatie\Permission\Models\Permission; to use App\Permission.

You need to use the extended/new models which you have created.

To also add the most flexible and correct way for completion. You should use the binded models instead of hardcoded ones. This will always use the same model like in the package itself.
https://github.com/spatie/laravel-permission/blob/c7bb3d1bb6090006ee75bc312ff70e96cf3fb01f/src/PermissionServiceProvider.php#L61-L67

use Spatie\Permission\Contracts\Permission as PermissionContract;

app(PermissionContract::class)->create(...);

You could also move the app(PermissionContract::class) call into a method with return type-hint for better IDE auto-completion.

Yes that's worked. Thanks for your time. highly appreciated.

@lionwalker as a bonus: never use $_REQUEST in a framework! use the prepared $request you have in your controller.
DB::table('permissions') you could also use the model query builder Permission::query()
$edit_btn = "<i class='btn icon-md icon-pencil' data-toggle='modal' data-target='#edit_data_modal' data-id='{$permission->id}' data-name='{$permission->name}'></i>&nbsp;"; doesn't belong into a controller.

https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller#Components

Accepts input and converts it to commands for the model or view.

But it will never generate a view by it's own! 馃槈

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jeangomes picture jeangomes  路  5Comments

BerendSpigt picture BerendSpigt  路  4Comments

TheFrankman picture TheFrankman  路  5Comments

federico-arona picture federico-arona  路  5Comments

lflucasferreira picture lflucasferreira  路  3Comments