Signup form with fixed role

aidanw - 5 months ago

I've got a custom user form to allow users to signup, I don't want them to pick their role, so 'roles' is not included in the fields. I would like to save the new user with a role preselected so am using a custom form handler which looks like this:

public function handle(CreateUserFormBuilder $builder)
    {
        if (!$builder->canSave()) {
            return;
        }

        $extraFields = [
            [
                'field' => 'username',
                'type' => 'anomaly.field_type.slug',
                'value' => $this->createUsername($builder)
            ],
            [
                'field' => 'display_name',
                'type' => 'anomaly.field_type.text',
                'value' => $builder->getFormValue('first_name').' '.$builder->getFormValue('last_name')
            ],
            [
                'field' => 'activated',
                'type' => 'anomaly.field_type.boolean',
                'value' => true
            ],
            [
                'field' => 'roles',
                'type' => 'anomaly.field_type.multiple',
                'value' => ['4'],
                'config' => [
                    'related' => 'Anomaly\UsersModule\Role\RoleModel',
                ]
            ]
        ];

        $builder->addFields($extraFields);

        foreach ($extraFields as $extraField) {
            $builder->addFormField($this->fieldFactory->make($extraField, $builder->getFormStream(), $builder->getFormEntry()));
            $builder->setFormValue($extraField['field'], $extraField['value']);
        }

        $builder->saveForm();
    }

The role isn't isn't being saved with the form, can anyone point me in the right direction or is there a simpler way to achieve this?

ryanthompson - 5 months ago

Hmm.. couple things:

  • The handler isn't the best spot for saving logic because your user isn't saved yet at this point.
  • Why do you have fields defined here?

Your fields above - the extra ones are not actually being included I don't think. Cause the form is long built by this point.

If we can assume you can determine the $role you want to assign maybe something like this (could also do this in your handler though it's oddly late in the request - but should work fine):

$builder->on('saved', function() use ($builder, $role) {

    $user = $builder->getFormEntry();

    $user->roles()->attach($role);
});

ryanthompson - 5 months ago

If you look at the way core does it it's a similar idea - just without the callback (manually fires save on the builder then does the work):

https://github.com/anomalylabs/users-module/blob/2.2/src/User/Register/RegisterFormHandler.php#L34

But that saveForm() means you have a saved user you can interact with now. And then I would just use native Laravel stuff rather than mocking fields in like that. No need ^_^

aidanw - 5 months ago

Hey Ryan

Cheers for the answers... Yeah I see we could do it with or callback or just in the handler now.

I'd set off down this route because had been doing some similar stuff with some step by step forms, where I've been saving data in session and then on the final save mocking in the fields, so then when save is called it will run through and fire any additional functionality provided by the field type. Do you see any draw backs with that approach? It doesn't seem to be working with the roles in the code I posted.

ryanthompson - 5 months ago

I would try moving your logic to mock fields up into the ready callback. Which could be defined on the builder class like onReady if you want for cleanliness. The reason being is that's the FIRST thing ran. So you can setup the builder proper like it normally would be (before all the building). Does that make sense?

ryanthompson - 5 months ago

It's partly I am sure because of the multiple FT being self handling. It runs last after saving and has a little more involved saving procedure.

aidanw - 5 months ago

Yep that does make sense will have a go. Thanks!