5.8 KiB
title | date | excerpt | tags | ||||||
---|---|---|---|---|---|---|---|---|---|
Null Users and System Users in Drupal | 2018-08-16 | Announcing the Null User and System User modules. |
|
Have you ever needed to have a 'special user' to perform tasks on your Drupal site, such as performing actions based on an API request, or for sending an internal site message?
If you just create a new user, how do you identify that user going forward? Do you hard-code the 'magic' user ID in your custom code? What if the user has a different ID on different environments of your site? You could declare it in each environment’s settings file and retrieve it from there, but what then if you need to do the same on another site? That would mean some duplication of code - and something that could have been abstracted and re-used.
I had to do this recently, and rather than just duplicate the code I decided to make it into it’s own module - which then became two modules.
System users
The System User module provides a re-usable, generic way to denote users as 'system users', which is not specific to a certain site or environment as this is value is stored against each individual user in the database.
'System user' is a term used in Linux, which I thought also applies well to this scenario.
From https://www.ssh.com/iam/user/system-account:
A system account is a user account that is created by an operating system during installation and that is used for operating system defined purposes. System accounts often have predefiend user ids. Examples of system accounts include the root account in Linux.
A system user isn’t an account that we’d expect a person to log in with and perform routine tasks like updating content, but rather for the system (site) to use to perform tasks like the earlier examples.
Declaring a user as a system user
System User module adds a base field to Drupal’s User entity, which determines
whether or not each user is a system user - i.e. if this field is TRUE
, that
user is a system user. This means that users can easily be queried to identify
which are system users, without having to rely on magic, environment and site
specific user IDs. This also means that we can have multiple system users, if
needed.
In the Drupal 8 version of the module, a SystemUser
is a custom entity, that
contains it’s own create
method for creating new system users. This is a
essentially a wrapper around User::create()
that automatically sets the value
of the system user field as part of the creation.
The original intention is that system users would always be created manually in an custom install or update hook, however since releasing the module, I’ve also added an install hook to the module to automatically create a new system user when the module is installed, basing the username on the site name.
There is also an open issue to add a Drush command to create a new system user, and I’d imagine I’ll also add a Drupal Console command too.
Retrieving system users
Whilst you could easily write your own query that retrieves users based on the
value of the system user field, but the module contains a SystemUserManager
service that contains methods to do so. It also provides a static helper class
that determines if a specified user is a system user by checking the value of
the system user field.
// Retrieve the first system user.
$system_user = $this->systemUserManager->getFirst();
// Is the specified user a system user?
$is_system_user = SystemUserManager::isSystemUser($user);
But what do we return if there are no system users? You could return NULL
or
FALSE
, but I decided to take a different approach, which became the second
module.
Null users
The Null User module is an implementation of the null object pattern
for users in Drupal 8. In this case, a NullUser is an extension of Drupal’s
AnonymousUserSession
, which means that it inherits sensible defaults to return
for a non-existent User. Though, through inheritance, the id
, getRoles
and
hasPermission
methods are overridden to return relevant values.
use Drupal\Core\Session\AnonymousUserSession;
class NullUser extends AnonymousUserSession {
...
}
Null User module is a dependency of System User in Drupal 8, so When no system
user is found from the getFirst()
method, a NullUser
is returned. Whilst I
could alternatively have returned NULL
or FALSE
, we then would need to check
if the returned value was an object or not before calling methods on it.
$system_user = $this->systemUserManager->getFirst(); // Returns NULL or FALSE.
// Need to check if a user was returned or not.
if (!$system_user) {
return;
}
if ($system_user->isActive()) {
...
}
Because instead we’re returning a NullUser
, which through class inheritance
has the same methods and properties as a regular user, there is no need to do
the additional check as you will always receive a relevant object, and the
expected methods will always be present.
$system_user = $this->systemUserManager->getFirst(); // Returns a NullUser.
if ($system_user->isActive()) {
...
}
This means we have less code, which also is simpler and more readable.
System User module is the only one that I’m aware of that makes use of Null User, but I’ve added a list to the project page so let me know if you can think of any others.