tags:

views:

895

answers:

7

I'm building a form to do the following:

  • Print a table of users and permissions, pulling from MySQL. Each permission a user has is a checked box, and each one they lack is an unchecked box.
  • Allow an administrator to check and uncheck boxes to grant or remove permissions.
  • When the form is submitted, show a confirmation page with ONLY the users whose permissions will be changed, highlighting the specific changes.
  • When the changes are confirmed, modify the database accordingly.

To do this, I'm creating two arrays of user permissions: one according to what the database shows, and one according to what the form shows.

If a user lacks a permission in MySQL, it will be shown as a 0. If they lack a permission in the form submission, it simply won't exist.

Here are two simple examples of the arrays:

Database array

[User1] => Array ([public] => 1
                [private] => 1
                [secret] => 1
               ) 
[User2] => Array ([public] => 1
                [private] => 0
                [secret] => 0
               )

Form submission array (revoking "secret" from User1 and giving it to User2)

[User1] => Array ([public] => 1
                [private] => 1 
               )

[User2] => Array ([public] => 1
                  [secret] => 1
                 )

Question

How can I elegantly combine these two arrays to make a "changes" array, such that:

  • Users with identical permissions in both are omitted
  • Remaining users have all permissions - public, private and secret - set to either 0 or 1.
  • Each permission is 0 if it was missing from the form submission array, and 1 if it was in the form submission array

For example, combining the above would give:

[User1] => Array ([public] => 1
                [private] => 1
                [secret] => 0
               ) 
[User2] => Array ([public] => 1
                [private] => 0
                [secret] => 1
               )

Attempts so far

  • As a first step, I have tried using array_merge() with the forms array listed second, thinking it would overwrite the database array where they differed. Instead, it deleted elements that differed.
  • I have tried setting up a foreach() statement to compare the two arrays, but it's becoming complicated, and I think there must be a simpler way

UPDATE

Whew! A new answer drew my attention back to this old question. I got this working, but later I scrapped this crazy code - it was way too complicated to go back and work with. Instead, I wrote a PHP back end script to change one permission at a time, then wrote an AJAX front end to send changes over it. Much simpler code, and the changes are instantaneous for the user. A highlight effect gives instant, on-page feedback about what has changed.

+2  A: 

This might be what you are looking for: array_diff()

Andy
+2  A: 

You can find what you need by referring to the PHP: Arrays manual. You've documented the question quite well but I still can't make it out clearly what is it that you need.

Specifically you should be looking at using the array_diff() and array_intersect(), to compute the difference or intersection of two arrays.

kRON
+2  A: 

The post data only contains the permissions you should grant. So, set up a "baseline" with all the permissions set to 0. Then merge with the submission.

$empty_perms = array("public" => 0, "private" => 0, "secret" => 0);

$new_user1_perms = array_merge($empty_perms, $_POST['User1']);
$new_user2_perms = array_merge($empty_perms, $_POST['User2']);

Now update the database using the merged arrays. This way you will set correct permissions for all elements.

gnud
A: 

I wonder if some sort of variation on differential execution would help.

Brian
A: 

gnud's solution is helpful - it gets me an array with all the correct permissions.

However, all the users are listed, not just those who will be changed. array_diff() is not helpful here, because it

Returns an array containing all the entries from array1 that are not present in any of the other arrays.

...whereas what I want is an array of all the entries from array1 that are DIFFERENT in array2.

Something like:

if (array1 => nested => item != array2 => nested => item) {
   add it to "differences array";
}
Nathan Long
Intersect seems to check for the existence of array items. I want to compare the values of array items.
Nathan Long
Well, if the array_diff_assoc() between the current data from database and the submitted data is empty, no change has been made. If it's nonemtpy, update the DB using the post data.
gnud
+1  A: 

Let's try to combine gnud's solution with comparing by value. I've added one more key "member" to show zero permission being unchanged.

// empty permissions
$empty_perms = array("public" => 0, "private" => 0, "secret" => 0, "member" => 0);

// original permissions (please note that it MUST contain ALL keys)
$old_perms = array("public" => 1, "private" => 0, "secret" => 1, "member" => 0);

// POST data container
$post_data = array("public" => 1, "private" => 1);

// apply new user permissions - put them into db
$new_perms = array_merge($empty_perms, $post_data);

// differences to show
$diff_perms = array();

// compare new and old permissions
foreach($empty_perms as $k => $v) {
    $diff_perms[$k] = (int)($old_perms[$k] !== $new_perms[$k]);
}

This example should give you following results (old, new, changes):

Array
(
    [public] => 1
    [private] => 0
    [secret] => 1
    [member] => 0
)

Array
(
    [public] => 1
    [private] => 1
    [secret] => 0
    [member] => 0
)

Array
(
    [public] => 0
    [private] => 1
    [secret] => 1
    [member] => 0
)

Hope this helps.

Sergii
A: 

To use array_diff() the first argument must be the superset, or the larger of the two arrays. To use array_diff() when you are not sure which array is larger simply:

  //start with the superset of for array_diff to return differences
  if(count($prev_wholesaler_assignments) > count($wholesalers)){
      $perm_diff = array_diff($prev_wholesaler_assignments,$wholesalers);  
  } elseif (count($prev_wholesaler_assignments) < count($wholesalers)){
      $perm_diff = array_diff($wholesalers,$prev_wholesaler_assignments);
  }

This returns the disjunction regardless of which array happens to be larger.

woland