Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

OneNonlyNova's avatar

Eloquent Models not updating / flushing Cache correctly

Hey guys i'm having a problem with my eloquent models in a test project. I'm using Zizaco/entrust, VentureCraft/revisionable and spiritix/lada-cache like below.

my problem is that my table data (the cached models) don't get updated if i update from the group controller. if i update from the user controller it works fine.

  • adding two users from group controller adds entries in group_user pivot
  • if i do $group->users->lists('id')->toArray() i get empty array
  • if i do $user->groups->lists('id')->toArray() i get the group i assigned above

this is really messing me up and i cannot find the problem, any help would be great!

PS: tried touches in both models but didn't help, even tried to ->touch() right after the ->attach but didn't help either

PPS: regarding the revisions my normal fields are tracked fine but the relation between group <-> user is not tracked at all even if the git of revisionable says it should track many-to-many updates

my custom base model:

<?php

namespace App\Models;

use Spiritix\LadaCache\Database\Model as LadaModel;
use Venturecraft\Revisionable\RevisionableTrait;

class cModel extends LadaModel
{
    use RevisionableTrait;
    protected $revisionEnabled = true;
    protected $revisionCreationsEnabled = true;
}

group model:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\SoftDeletes;

class Group extends cModel
{
    use SoftDeletes;
    protected $table = 'groups';
    protected $dates = ['deleted_at'];
    protected $fillable = ['*'];
    protected $primaryKey = 'id';
    public $timestamps = true;

    public function users()
    {
        return $this->belongsToMany('App\Models\User');
    }
}

user model:

<?php

namespace App\Models;

use Illuminate\Auth\Authenticatable;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Database\Eloquent\SoftDeletes;
use Zizaco\Entrust\Traits\EntrustUserTrait;

class User extends cModel implements AuthenticatableContract, CanResetPasswordContract
{
    use Authenticatable, CanResetPassword, SoftDeletes, EntrustUserTrait;
    protected $table = 'users';
    protected $hidden = ['password', 'remember_token'];
    protected $dates = ['deleted_at'];
    protected $fillable = ['*'];
    protected $primaryKey = 'id';
    public $timestamps = true;

    public function groups()
    {
        return $this->belongsToMany('App\Models\Group');
    }
    
    public function getNameAsLine()
    {
        return $this->first_name . " " . $this->last_name;
    }

    public function getAvatarURL()
    {
        $avatar = '/uploads/avatars/'.$this->getKey().'-160x160.png';
        if (file_exists(public_path() . $avatar))
        {
            return $avatar;
        } else {
            return '/img/user-avatar-blank.jpg';
        }
    }

    /**
     * Check if user has a permission by its name.
     *
     * @param string|array $permission Permission string or array of permissions.
     * @param bool         $requireAll All permissions in the array are required.
     *
     * @return bool
     */
    public function can($permission, $requireAll = false)
    {
        if ($this->hasRole('superadmin'))
            return true;
        if (is_array($permission)) {
            foreach ($permission as $permName) {
                $hasPerm = $this->can($permName);

                if ($hasPerm && !$requireAll) {
                    return true;
                } elseif (!$hasPerm && $requireAll) {
                    return false;
                }
            }

            // If we've made it this far and $requireAll is FALSE, then NONE of the perms were found
            // If we've made it this far and $requireAll is TRUE, then ALL of the perms were found.
            // Return the value of $requireAll;
            return $requireAll;
        } else {
            foreach ($this->cachedRoles() as $role) {
                // Validate against the Permission table
                foreach ($role->cachedPermissions() as $perm) {
                    if (str_is( $permission, $perm->name) ) {
                        return true;
                    }
                }
            }
        }

        return false;
    }
}

Group Controller Update

// Find the role
$group = Group::findOrFail(Input::get('groupID'));
// Grab the inputs and validate them

$validation = Validator::make(Input::all(), [
    'display_name' => 'required|string|min:6|unique:groups,display_name,'.$group->id,
]);

// Should the form validation pass, continue to attempt to add edit this role
if ($validation->passes()) {


    // If we found the group, restore it and set the
    // new values found in the post
    if($group)
    {
        // With the group object ready, work the update
        $group->display_name = Input::get('display_name');
        $group->description = Input::get('description');

        // remove all existing users and set only checked
        if (\Auth::User()->can('group-assign-user')) {
            $group->users()->detach();
            $new_users = (Array)Input::get('users');
            foreach ($new_users as $user) {
                $group->users()->attach($user);
            }
        }
        $group->save();

        Session::flash('success', 'Gruppe ' . Input::get('display_name') . ' wurde erfolgreich bearbeitet');
        return Redirect::action('GroupController@getAll');
    }
} else {
    return Redirect::back()
        ->withInput()
        ->withErrors($validation);
}

User Controller Update

// Grab the inputs and validate them

$validation = Validator::make(Input::all(), [
    'userID' => 'required|integer',
    'email' => 'required|email',
    'username' => 'required|min:6',
    'password'  => 'min:6|confirmed',
    'password_confirmation'  => 'min:6',
    'first_name' => 'required|string',
    'last_name' => 'required|string',
    'avatar' => 'image|image_size:160,160',
]);

// Should the form validation pass, continue to attempt to add this user
if ($validation->passes()) {

    // Find the User
    $user = User::findOrFail(Input::get('userID'));

    // If we found the user, restore it and set the
    // new values found in the post
    if($user)
    {
        // With the user object ready, work the update
        $user->email = Input::get('email');
        $user->username = Input::get('username');
        $user->password = bcrypt(Input::get('password'));
        $user->first_name = Input::get('first_name');
        $user->last_name = Input::get('last_name');

        // Only set pw if not empty
        if (Input::get('password')!=''){
            $user->password = bcrypt(Input::get('password'));
        }

        // Upload user Avatar
        if (Input::file('avatar'))
        {
            $avatar = Input::file('avatar');
            $upload_folder = '/uploads/avatars/';
            $filename = $user->getKey().'-160x160.png';
            $avatar->move(public_path() . $upload_folder, $filename);
        }


        $user->save();

        // remove all existing roles and set only checked
        if (\Auth::User()->can('user-assign-role')) {
            $user->detachRoles();
            $new_roles = (Array)Input::get('roles');
            foreach ($new_roles as $role) {
                $user->attachRole($role);
            }
        }

        // remove all existing groups and set only checked
        if (\Auth::User()->can('user-assign-group')) {
            $user->groups()->detach();
            $new_groups = (Array)Input::get('groups');
            foreach ($new_groups as $group) {
                $user->groups()->attach($group);
            }
        }

        Session::flash('success', 'Benutzer ' . Input::get('username') . ' wurde erfolgreich bearbeitet');
        return Redirect::action('UserController@getAll');
    }
} else {
    return Redirect::back()
        ->withInput()
        ->withErrors($validation);
}
0 likes
3 replies
OneNonlyNova's avatar

noone any idea? tried a couple of things and it seems that only the realationships cache doesn't get flushed as for example if i remove a user and change the name of a group together, the updated_at date shows correctly but the user still shows up... very frustrating... :/

OneNonlyNova's avatar

i dough through the code of lada-cache and he is using the following to invalidate the cache for the models:

    protected static function boot()
    {
        parent::boot();

        $manager = app()->make('LadaCache');

        static::created(function($model) use($manager) {
            $cache = $manager->resolve(new ModelReflector($model));
            $cache->invalidate();
        });

        static::updated(function($model) use($manager) {
            $cache = $manager->resolve(new ModelReflector($model));
            $cache->invalidate();
        });

        static::deleted(function($model) use($manager) {
            $cache = $manager->resolve(new ModelReflector($model));
            $cache->invalidate();
        });

        static::saved(function($model) use($manager) {
            $cache = $manager->resolve(new ModelReflector($model));
            $cache->invalidate();
        });
    }

how would one add the two missing ones for attach() and detach() from the BelongsToMany Relation? if we could figure that out i would send it as PR to lada-cache on git.

Please or to participate in this conversation.