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

NaderH's avatar

Foreign key on update cascade with condition (or where value = value)

I made a foreign key in a table(B) with a reference to another table(A) (I want to block a group of users at once, depending on their role instead of blocking them one by one) table(A) is for roles and it contains the role_name(admin etc..) and the role_status(blocked or not) and the table(B) is for users which containes the username, user_role and the user_role_status.

Now If I wanted to block a group of users(editors) I will change the role_status in the roles table and it will replicate to or change the user_role_status in the users table, But the problem is that when I do this it changes the user_role_status for all users with any role and block all of them.

The question is ( is there any way to prevent that and change only the value of the group I want to block ?? something like UPDATE CASCADE with condition (or where user_role in users table = role_name in roles table) or something like that.

ALTER TABLE users ADD CONSTRAINT fk_user_role_status FOREIGN KEY (user_role_status) REFERENCES roles(role_status) ON UPDATE CASCADE;
COMMIT;
  /*--------------------------------------------------------------*/
  /* Find role status
  /*--------------------------------------------------------------*/
  function find_by_current_roleStatus($user_role_status)
    {
      global $db;
      $sql = "SELECT user_role_status FROM users WHERE user_role_status = '{$db->escape($user_role_status)}' LIMIT 1";
      $result = $db->query($sql);
      return($db->num_rows($result) === 0 ? true : false);
    }
  /*--------------------------------------------------------------*/
  /* Function for checking if user role status banned or allowed
  /*--------------------------------------------------------------*/
  function login_require_roleStatus($require_user_role_status){
     global $session;
     $current_user = current_user();
     $role_status = find_by_current_roleStatus($current_user['user_role_status']);
      //if Role status banned 
    if ($current_user['user_role_status'] === '0'):
          $session->msg('d','banned ');
          redirect('home.php',false);
          //if user group allowed
      elseif($current_user['user_role_status'] === '1'):
        return true;
        endif;
     }
0 likes
16 replies
AungHtetPaing__'s avatar

I think you are using 'on update cascade' on wrong way. As far as I know on update cascade is for primary key and foreign key (updating primary key of parent table will update all related foreign key in child table). But you are trying to use it with role_status that is boolean (0 is blocked, 1 is not blocked).

You don't need to use 'on update cascade' for your situation. Update role status on 'roles' table and check that status with relationship from user. something like this

select role_status from roles join users on users.role_id = roles.id where users.id = 3

Don't take my query seriously because I don't write plain sql since I use laravel.

NaderH's avatar

@AungHtetPaing__ , Ok.. but how to write the function which will block a group of users according to their group status ?

AungHtetPaing__'s avatar

@NaderH logic is something like this.

function login_require_roleStatus($require_user_role_status){
     global $session;
     global $db;
     $current_user = current_user();
     $statement = $db->prepare(‘ select roles.role_status from users left join roles on users.role_id=roles.id where users.id=:id’);
     $result = $statement->execute([
         ‘:id’ => $current_user[‘id’]
    ]);
      //if Role status banned
     if ($result->role_status === '0'):
          $session->msg('d','banned ');
          redirect('home.php',false);
          //if user group allowed
      else:
        return true;
        endif;
     }
NaderH's avatar

@AungHtetPaing__ , using sql query didn't help, it's all about the function that will use that query to process what I want.

NaderH's avatar

@AungHtetPaing__ , I am sorry I didn't notice that you wrote the function, I wrote that sql query with your function

$sql = "SELECT user_role_status FROM users JOIN roles ON roles.role_level = users.user_level WHERE roles.role_status = '{$db->escape($user_role_status)}' LIMIT 1";

and I executed that query in my phpmyadmin and it worked, but I still when I change the status of a role from the roles table I got all the user_role_status column from the users changed then I got all the users blocked although not all roles in roles table blocked only the role I changed its status, so why all the user_role_status column in the users table change and block all users when I change only one role status from the roles table?

NaderH's avatar

@AungHtetPaing__ , role_level and user_level are the int of the role or user level, Admin role = 1, Editor role = 2, User role = 3, So when the user_level is 1, it means he is an admin and so on, I am using it as a relation .. The issue is when I change the editor role status to be blocked in the roles table to block all editors in once, I got all users with all roles blocked because instead of changing only the usere with the editor role in the user_roles_status column in the users table it changes the whole column (it means all users), the whole column references to the value I changed not only the the cells with the editor role in that column.

AungHtetPaing__'s avatar

@NaderH emm your query is not what I mean. please check my example query and function. You just need to get role status from roles table (nothing to do with users table) and check the role status and do what you want (block that user or something). All the users who have their role status block will be blocked.

user and role table relationship

  • user belong to role (one user has one role)
  • role has many user (role primary key id will be foreign key in users table)

I am not sure why it is so complicating or am I misunderstanding your question? I can’t explain better than this. Sorry :)

NaderH's avatar

@AungHtetPaing__ , May be I can't explain well what exactly happens, shortly all functions and all sql queries are working well and they do what I want exactly, they are totally functional, the issue is when I change a value in the roles table it affects on a whole column in the users table not only the value which references to the one I changed.

// user_role_status in users table is a fk refers to role_status in roles table
// and role_status in roles table is a fk refers to id in statuses table.

statuses_table
id       is_active             
0         no                        
1         ok                        

roles_table
id       role              role_status
1        Admins                1
2        Editors               1
3        Users                 1

users_table
id       user_name       user_level       user_role_status
1        Admin             1                   1              
2        Editor1           2                   1               
3        User1             3                   1                
4        Editor2           2                   1               
5        User2             3                   1                
6        User3             3                   1                

I think this will make it more clear, when I change the status of the Editors (role_id='2') role in roles table to '0' to block any one with the user_level '2' (user_id=2,4) in the users table, I should got only the users with the id=2 and 4 became with a user_role_status = '0' but instead of that I got the whole column of the user_role_status changed to '0' and that means all users are blocked. that's the problem I have. and this is the sql query I use

ALTER TABLE users ADD CONSTRAINT fk_user_role_status FOREIGN KEY (user_role_status) REFERENCES roles(role_status) ON UPDATE CASCADE;
COMMIT;

I don't have any problem with the functions because they are already execute the blocking for the users whose user_role_status is '0'.

AungHtetPaing__'s avatar

@NaderH

that I got the whole column of the user_role_status changed to '0'

that is because you are using 'on update cascade' with 'role_status' column and 'user_role_status' column. changing 'role_status' will update all of the 'user_role_status' column value. I already explained about that in my first reply and you are still doing that.

foreign key should link with primary key column of parent table (not other column basically) https://www.w3schools.com/sql/sql_foreignkey.asp.

NaderH's avatar

@AungHtetPaing__ , Ok.. I will make user_role_status refer to the id of the roles table but how to make sure that it will be related to the role_status not to the role itself ( I mean the permission of the role), I will try that change and check what will happen.

NaderH's avatar

@AungHtetPaing__ , Well, I tried what you said and now the whole user_role_status refers to the Admin role not to the user_role_status and If I changed the role_stataus for any role, nothing happens and no user_role_status will be blocked or changes to '0".

NaderH's avatar

@AungHtetPaing__ , The problem here is that I can't make the role_status column a unique key because all of its values are duplicated ('1') by default.

dkroft's avatar

Have you considered using Policies?

Please or to participate in this conversation.