Kirby user as DB entries

Im on a project in which i will have a lot of pages and also users. I did already a topic for the pages and i was able to solve this via DB solution. https://forum.getkirby.com/t/performance-createchild-vs-pageobject/18431/4

now. im in the same situation as i was in the pages problem. as soon the user count is more than 2000 users, the loading time in some situations are not so good. there is already a frontend login part, and im using kirby user session to upload/modificate content on the page/db. users are just for frontend login/auth, no panel login needed.

this is all working find but speed and scalability matters. because the project will be public i need a solution to handle this, so the user-part should also be scaleable. my best guess is switching to DB.

  • Saving all users would be an easy task over an api and DB integration.
  • My problem/question is, how can i highjack the way kirby is loading the users from DB instead of the filesystem? Because this is an important part of the system, im prefer not to hack this in some way but looking to an more official way to do so.

Maybe someone have advice how this can be done? @bastianallgeier
Thanks!

You should be able to create a users collection from the database using Users::factory(). But what I’m asking myself is how these users could be registered in a plugin, unless you create your own class that inherits everything from the Users class. If its just about the frontend, that should actually work.

im not sure i get this right, so maybe extra help needed here ;=)

i was able to create a one dummy user with the factory, just to test… but this is now just an object, which is not part of the $kirby->users() object right?

$usr = User::factory([
        'name'      => 'dbuser',
        'email'     => 'dbuser@db.com',
        'id'        => 'uiftzhju',
        'password'  => '12341234',
        'language'  => 'en',
        'role'      => 'editor'
    ]);

is there a way to add factory users to the $kirby->users() collection?

i do just need the frontend part, so i can login and have access to the logged in user, like a real kirby user.

EDIT:
ok, i was now able to login with the testuser with a form in the frontend:

$user = $usr;
    if ($user and $user->login($password)) {
     // session with factory user-id is created
 }

i can also access the $kirby->user object like:

$user = $kirby->user();
echo $user->username();  // correct factory user

But as soon as i reload the page or switch to another site the object $kirby->user() is no longer valid. so it seems to me the factory user is then kind of destroy or $kirby->user() is not able to take care of the session fo the factory user.

do i understand this the correct way how it should work or im complete off?

EDIT2:

I got it now to work but im not sure this is legit.

$kirby = kirby();
$usr = User::factory([
        'name'      => 'dbuser',
        'email'     => 'dbuser@db.com',
        'id'        => 'uiftzhju',
        'password'  => '12341234',
        'language'  => 'en',
        'role'      => 'editor'
]);
$users = $kirby->users();
$users->add($usr);

the new user is now also in $kirby->users object and session e.g. login works.

  • im calling this code in a plugin, is this a good place or is there a better place? the system has to add the new users every reload/page, so is there a better place this is just called once?
  • in general, is this a proper way to add a virtual user to the kirby user object?

Yes, according to @distantnative that is the way to go.

metrics:

  • 500 user +/-100ms (page/object)
  • 10000 user +/-350ms (page/object) rendered page in 1s

thanks @texnixe @distantnative for the help!

As @bastianallgeier pointed out, there is an alternative way to register users from other sources

  1. Extend the Kirby class in a custom class in which you override the users method
  2. Adapt the index.php to load and render this new class
<?php

use Kirby\Cms\Users;

class CustomKirby extends Kirby
{

  public function users()
  {
    if (is_a($this->users, 'Kirby\Cms\Users') === true) {
      return $this->users;
    }
    $users = Users::Factory([
      [
        'name'      => 'user1',
        'email'     => 'user1@example.com',
        'id'        => 'uiftzhju',
        'password'  => User::hashPassword('12345677'),
        'language'  => 'en',
        'role'      => 'admin'
      ],
      [
        'name'      => 'user2',
        'email'     => 'user2@example.com',
        'id'        => 'uihzzhop',
        'password'  => User::hashPassword('12345678'),
        'language'  => 'en',
        'role'      => 'editor'
      ],
      [
        'name'      => 'user3',
        'email'     => 'user3@example.com',
        'id'        => 'lphzzhop',
        'password'  => User::hashPassword('12345679'),
        'language'  => 'en',
        'role'      => 'editor'
      ]
    ], []);
    return $this->users = $users;
  }
}

index.php

<?php

require __DIR__ . '/kirby/bootstrap.php';
// load the file with the custom class
require __DIR__ . '/site/plugins/users/index.php';

$kirby = new CustomKirby();

echo $kirby->render();

Both versions working for me:

add:
With the first solution ($users->add) you’re adding users to the existing kirby user object, so you can kind of mix users from DB and Accounts. e.g. admins from accounts and editors from DB. but you have to check/add users in different situations, by your own.

extend:
Second solution is replacing the kirby users object with the extended on. so the accounts folder is not more needed, and all users are from the DB source. i think this is cleaner because all users are from one spot and you have all users by initiation.

Panel works in both versions, also frontend login.

1 Like