Setting up the Database Migration

Another aspect of setup, is making sure that the access table is up to date. This of course must be done to set up Access Control for the first time, but it also must be done whenever you are adding a new Resource to Access Control or need to add new Boolean Types. If you need to know about writing database migrations in general, see our documentation for Migration Core on building migrations (link forthcoming), but you will need to make sure not to change the previous Access Up or Access Down commands for a new release, but rather make a new migration. This documentation assumes you know the basics of creating a new database migration. One additional note, however. accessUp and accessDown are not at this time reversible, so that means that if you are doing an Access Control documentation, you must use both the up and the down functions, rather than using the change function.

Note: It is very important that you have at least configured your resource information before attempting to run your Database migration. The reason for this is that the accessUp and accessDown command require the table information found within in order to make or change your current access table. Any type you add through the types array is also required to be fully set up in the types config, and have a column name override if it will be receiving one. So make sure you follow the documentation for setting up AC Config fully before attempting to write the migration.

MigrationUtils

Access Control has built in commands that it defines for you so that you are able to more easily build the access table to their specifications. In order to have access to these commands, all you need to do is import the AccessControl\MigrationUtils file and use. This will be needed in each separate migration, you desire to make changes to your Access Table in. Here is an example of what this would look like:

use AccessControl\MigrationUtils;
use MigrationCore\GroupControlMigration;

class Three extends GroupControlMigration {
    use MigrationUtils;
    // everything else
}

Notice the use statement both with the import and also as part of the class as well. The second line allows you to call the MigrationUtils functions just with a $this-> call.

Access Up

Access Up is the command that takes all of the resources and types you are adding to Access Control, and either creates a table (if there is no access table already in your database) or it adds the appropriate columns needed to the table (if there is). The function takes two arrays as parameters: the first parameter is types and the second parameter is resources. As suggested above, the name for resources or types you are adding must match their names exactly in the config for access-control. So, then running access up is fairly simple, and here is an example from Message Center:

// this adds the ten new Boolean Types listed and adds one new resource: channel
$this->accessUp(
    ['channelDelete', 'channelEdit', 'postThread', 'editThread', 'editAllThread', 'deleteThread',
    'deleteAllThread', 'unpinThread', 'unpinAllThread', 'manageNotifications'], ['channel']
);

Note: It is important to note that if this is the first time you are making an accessUp to create the access table, you will need to make sure that your type array includes any of the user types you intend to use (if you choose to leave any out, you will need to ensure that no user has access through permissions to edit them). If it is not the first time you are adding a access table, only include types and resources in accessUp that need to be added, not ones which already exist. In our Message Center example, we had already added the resource template and all the types that went with that resource, so we did not need to re-add it here.

Access Down

Access Down is the command that removes the resources and types you wish from the access table, and if desired, it will delete the whole table.

To delete the whole table (if this is the first migration in which you have added an access table), it is pretty simple, just pass in the boolean true to the accessDown function, and it will delete the table for you. This is what it would look like:

$this->accessDown(true);

If you wish to only delete certain resources or certain types, it is a little more complicated, but it still isn't too bad. In this, it mimics the accessUp command directly. It takes two arrays: the first parameter is types and the second is resources. This will delete the appropriate columns from the table for whichever types or resources you put into these parameters. In our Message Center example:

//this will delete the ten types listed and it will delete the resource: channel
$this->accessDown(
    ['channelDelete', 'channelEdit', 'postThread', 'editThread', 'editAllThread', 'deleteThread',
    'deleteAllThread', 'unpinThread', 'unpinAllThread', 'manageNotifications'], ['channel']
);

Access Set Booleans

There may be some times that you wish to automatically make certain permissions true on existing rules under certain conditions, when you are adding in Boolean Types that were not there before. For example, an app that has only one Boolean Type of edit may desire any number of other things. The problem is that there are already rules existing in the database. So you then need to as you are making your migration think about which permissions are being split, and set those Boolean Types in the database based on whether the person has access to the bigger permission. For example, maybe you want to split edit into edit (meaning edit permissions), editResource, and deleteResource. If you already have data in the access_table, you will want to give anyone who has edit currently, all three: edit, editResource, and deleteResource. This is just one of many examples of why you would need to set the Boolean columns directly on existing rules. This can be done, rather simply, with a function defined for you called accessSetBooleans.

This function takes three arrays: types, where, and roles. Only the first array is mandatory. These arrays all do the following:

  • The types array takes the list of Boolean Types to be set to true. If this is the only column defined, it will set all of these Boolean Types to true, otherwise, it will use the other arrays to define conditions for when this will be set to true (or else it will be false).
  • The where array takes a list of other Boolean Types which must already be true, in order to set all of the types in the types array to true.
  • The roles array takes a list of Group Control roles. It takes the typical role condition syntax we use in other places (double array is or, single array is and). So then a role array such as [['admin', 'supervisor']] will only allow the types array to be set to true if the user has either admin or supervisor. A role array such as ['admin', 'stats'] will only allow the types array to be set to true if the user has the roles of both admin and stats. Note: Because roles are on users, this roles array will only work with rules with the user type of user (so a group or department will not be changed if you require a specific role to be set).

The most complicated example of this is what is found in Service Stats, when we first added the different Boolean Types to Access Control, so here is an example of what it may look like in practice:

    // for all accessSetBooleans, order is bools to set, bools required, roles required
    // everyone gets entry add if they had permission before
    $this->accessSetBooleans(['entryAdd']);
    // admins with edit before could also delete/import entries
    $this->accessSetBooleans(['entryDelete', 'entryImport'], ['edit'], ['admin']);
    // if they had edit before, they can still edit entries and have the new stats permission
    $this->accessSetBooleans(['entryStats', 'entryEdit'], ['edit']);
    // if they had stats, admin, or supervisor, they get the new stats permission
    $this->accessSetBooleans(['entryStats'], [], [['admin', 'supervisor', 'stats']]);
    // admins with edit before could also edit services and delete/import entries
    $this->accessSetBooleans([
        'serviceEdit', 'serviceNotifications', 'serviceArrange',
        'entryDelete', 'entryImport'
    ], ['edit'], ['admin']);
    // all admins could pin, supervisors with edit could pin
    $this->accessSetBooleans(['entryPin'], ['edit'], ['supervisor']);
    $this->accessSetBooleans(['entryPin'], [], ['admin']);

Note: this will not need to be reversed, because all those new columns are deleted. So it will need to be only in the up or the down, but no reverse in the other. So if you are adding new Boolean Types, you will need to consider appropriate accessSetBooleans for the up function. If you are combining or removing certain Boolean Types, you will need to consider appropriate accessSetBooleans for the down function.

When to Use Access Up vs. Access Down

So at times it might be confusing as to when you should choose to use accessUp and when to use accessDown. Most of the time, accessUp will be used in your up function and accessDown would be used in your down function. But this is because most of the time, we will be adding to access control, rather than taking away from it. So then when your migration is seeking to add a resource, or other boolean types, this will always be done using the accessUp.

If however, you decide to take away something from the current access table going forward, this is when you will use accessDown in the up function rather than in the down function. So for example, if it is decided that some of the boolean types need to be removed going forward, then you would use the accessDown within the up function, and accessUp in the down function.