Re-add old blog posts from Astro
This commit is contained in:
parent
076239fa25
commit
051e154c65
178 changed files with 13479 additions and 7 deletions
155
source/_posts/null-users-system-users-drupal.md
Normal file
155
source/_posts/null-users-system-users-drupal.md
Normal file
|
@ -0,0 +1,155 @@
|
|||
---
|
||||
title: Null Users and System Users in Drupal
|
||||
date: 2018-08-16
|
||||
excerpt: Announcing the Null User and System User modules.
|
||||
tags:
|
||||
- drupal
|
||||
- drupal-7
|
||||
- drupal-8
|
||||
- drupal-modules
|
||||
- drupal-planet
|
||||
- php
|
||||
---
|
||||
|
||||
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][1] 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.
|
||||
|
||||
{.border
|
||||
.p-1}
|
||||
|
||||
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][2] is an implementation of the [null object pattern][3]
|
||||
for users in Drupal 8. In this case, a [NullUser][4] 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.
|
||||
|
||||
```php
|
||||
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.
|
||||
|
||||
```php
|
||||
$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.
|
||||
|
||||
```php
|
||||
$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][2] so let me know if you can
|
||||
think of any others.
|
||||
|
||||
## Resources
|
||||
|
||||
- [Null object pattern][3]
|
||||
- [Null User module][2]
|
||||
- [System User module][1]
|
||||
|
||||
[1]: https://www.drupal.org/project/system_user
|
||||
[2]: https://www.drupal.org/project/null_user
|
||||
[3]: https://en.wikipedia.org/wiki/Null_object_pattern
|
||||
[4]: http://cgit.drupalcode.org/null_user/tree/src/NullUser.php?h=8.x-1.x
|
Loading…
Add table
Add a link
Reference in a new issue