I need to store an additional piece of information for a user. It is a string, but may soon need to be an array of values. Regardless, it has nothing to do with user’s profile or any other existing fields for users or accounts in Nextcloud, it is so to speak completely custom/external data.
Good question. It could technically be stored in the user’s config for a specific app (or anywhere else you can store data for a user, for that matter), but there are a couple of factors to take into consideration:
The data will be stored by one application (app1) and accessed by a second application (app2). While the second app could do e.g. getUserValue(…, 'app1') it’s not very clean, as it shouldn’t be poking around in another app’s configuration storage for a user. But perhaps you know if this is an accepted thing in Nextcloud development nonetheless?
The data is not so much configuration as it is information about a user. To be more specific it is a list of names of groups in an external system the user is also part of. The string is like MainGroup;SubGroup1;SubGroup2;…;SubgroupN. The first app I mentioned will store this information, and the second app will read it and create corresponding groups in Nextcloud (simplified explanation). Anyway, my point is that the Nextcloud PHP API (master) stuff feels like being more about configuration values rather than user/account information. That’s why I opted for storing it in the Account. Put another way, it’s more about a user’s account data than it is about a specific app’s data for a user.
Yeah, with that context, I would rather not consider it a configuration in the first point.
In fact, you are asking about integration of two apps. Have you thought about creating in appA an interface and corresponding management classes (factory pattern) to access said classes in a more abstract level (an array e.g.)? Then, appB would just request the class/interface from appA and let appA handle all data access.
In that case, appA could decide to use a complete different storage system without prior notice. Also, there is a single source of truth regarding the parsing of the data etc.
The drawback is obviously that the two apps need to stay in sync in order to work. This needs some initial thoughts in order to get at least a clean error message out of the system in case of problems.
Yeah, it’s bordering that for sure. I will keep it just separate now and with the only common knowledge being where the data is stored and what it looks like, in part because I’m short on time and also it really doesn’t need more integration than that.
One could even draw parallels to the fact that e.g. a user’s e-mail display name is a piece of information that, like the one I have asked about here, is stored in one place (Account) but has several different consumers, that all know that 1) it is stored in Account, and 2) how it is formatted. Despite this, there is no more integration between all these consumers, they all just set and get this information by making use of the Account manager. So in this regard, the additional information I want to store, and the display name, are equal.
On a related note I will probably make another “sanity check” post once I have looked into the possibilities of programmatically creating group folders (the same as the app with that name creates and manages) from my new app. I imagine I will try to use the groupfolders app’s public methods to do it. But that’s for another thread
Using IAccount::setProperty() turned out to be a no-go for storing some additional/custom account information for a user. The comment for that method says “$property Must be one of the PROPERTY_ prefixed constants of \OCP\Accounts\IAccountManager”, effectively meaning that the information stored in the accounts table by this interface is meant only for the specific fields of the profile information for a user in Nextcloud and that you can’t add whatever property name you want.
Seeing as there is pretty much no documentation about these things and many other architectural/design related things for Nextcloud development, I am unable to find any other place where it would make some (some) sense to store information, other than IConfig::setUserValue(). The problem with storing it here though (effectively in the preferences table) is that the information is not a piece of configuration or preference, but rather contact-like information. So it doesn’t feel right. But what can you do, if the only other option is to create your own tables for this silly small need. Better to be pragmatic in this case.
EDIT: There is still the properties table in the database though, that I do’t know how it’s being used or by what. I will try to find out, maybe it’s a possibility.
EDIT EDIT: Looking in the code, the properties table is only used by CustomPropertiesBackend in the OCA\DAV\DAV, which makes me think it is a table specific to this app, that is used for DAV properties and should not be used for other things. It should probably have been better named to avoid confusion.