XF 2.0 How can I copy the register_form into a other page? + Custom Thread Field with img?

Hey, guys,
I've been working very hard on my forum lately, so I have a few questions to answer.
The first question: I am currently trying to display the content of register_form on a different page. (So that people can register on another page where they also have their login). So I simply tried to copy the code of the register_form file into my _page_node, but unfortunately I had to notice that problems occur here, but sadly I don't know how to fix them either.
Here is a picture of the error code:

Screenshot-2018-3-29 Register.webp


Second question: I am trying to create a custom thread field. Works the way it's supposed to. But it is possible to (1) create a custom display location (not before a message, after a message or in the thread status block) (2) upload an image as a field type (something like the type if you upload an avatar, so with maximum size etc.)


Screenshot-2018-3-29 Edit field Hintergrund Craftonia net - Admin control panel.webp


Thank you very much for your help!
 
I've searched a bit in the code and it seems so that the variabels are just available in the register_form template file.

Code:
{{ $regForm.getFieldName('username') }}
{{ $regForm.getFieldName('email_hp') }}
{{ $regForm.getFieldName('email') }}
{{ $regForm.getFieldName('password') }}
{{ $regForm.getUniqueKey() }}
{{ $regForm.getFieldName('timezone') }}

How can I make these variables available in an other page?
Can someone help me with that? @Chris D or anyone here who knows how I can make the register work on a custom node? :)
 
Last edited:
@yoloswaggerino
Now I have extended a class as written in the tutorial. The concept is now clear to me, but how do I know what the controller (probably the page node?) is called? (the one which i have to extend..) And what do I have to write If I want to use the variable {{ $regForm.getFieldName('username') }} in my page node?

I am in php unfortunately a total beginner ^^ :oops:
I've been more into HTML and css stuff so far...


PHP:
<?php

namespace Demo\Portal\XF\Pub\Controller;

class Member extends XFCP_Member [*Here were the regForm is (class?)]
{
    public function actionHelloWorld()  [*Here the Variable I want to display in a other page?]
    {
        return $this->message('Hello world!');
    }
}

- Thanks Justus
 
Last edited:
Check the routes section in your ACP.
/admin.php?routes/
Every route maps to a controller.
So let's say you want members/. You'll notice there is a route called members/ which maps to XF:Member. This is the "infix" version of /src/XF/Pub/Controller/Member.php.
Now, if an action is triggered, it is appended at the end of the url after the route parameters. For example, the about page in my profile /members/yoloswaggerino.160419/about triggers the actionAbout() method. This is the controller action where your parameters for your templates come from for that specific page.
https://xenforo.com/xf2-docs/dev/routing-basics/
 
Last edited:
Now that is much more clear to me... @yoloswaggerino
So I've created a addon which extends the /src/XF/Pub/Controller/Page.php because I wanted to extend my Custom Page with the Variables which couldn't get called. Now I've thought how I could expose the variables from the register Page to the custom Page. And I've found throught the routes section that the /register Page is linked with src\XF\Pub\Controller\Register.php. I thought If i would copy the code of the Register.php into my addon which extends the src\XF\Pub\Controller\Page.php It would solve my problem (That the variables couldn't get called) like I described in #1.
Unfortunately it didn't worked... :/ It just gave me a new error...err.webp

Somehow I'm thinking that this isn't the right way to get the Variables work in the custom Pagenode.. (Here is the code which I use in my "addon":


PHP:
<?php

namespace Demo\Portal\XF\Pub\Controller;

use XF\ConnectedAccount\Provider\AbstractProvider;
use XF\ConnectedAccount\ProviderData\AbstractProviderData;
use XF\Mvc\ParameterBag;

class Page extends XFCP_Page
{
    public function actionIndex()
    {
        if (\XF::visitor()->user_id)
        {
            return $this->redirect($this->getDynamicRedirectIfNot($this->buildLink('register')), '');
        }

        $this->assertRegistrationActive();

        $fields = [];
        if ($login = $this->filter('login', 'str'))
        {
            if ($this->app->validator('Email')->isValid($login))
            {
                $fields['email'] = $login;
            }
            else
            {
                $fields['username'] = $login;
            }
        }

        /** @var \XF\Service\User\RegisterForm $regForm */
        $regForm = $this->service('XF:User\RegisterForm');
        $regForm->saveStateToSession($this->session());

        $viewParams = [
            'fields' => $fields,
            'regForm' => $regForm,
            'providers' => $this->repository('XF:ConnectedAccount')->getUsableProviders(true)
        ];
        return $this->view('XF:Register\Form', 'register_form', $viewParams);
    }

    public function actionConnectedAccount(ParameterBag $params)
    {
        $provider = $this->assertProviderExists($params->provider_id);
        $handler = $provider->getHandler();

        $redirect = $this->getDynamicRedirect();
        $visitor = \XF::visitor();

        if ($visitor->user_id && $provider->isAssociated($visitor))
        {
            return $this->redirect($redirect);
        }

        $storageState = $handler->getStorageState($provider, $visitor);

        if ($this->filter('setup', 'bool'))
        {
            $storageState->clearToken();
            return $handler->handleAuthorization($this, $provider, $redirect);
        }

        $session = $this->session();
        $connectedAccountRequest = $session->get('connectedAccountRequest');

        if (!is_array($connectedAccountRequest) || !isset($connectedAccountRequest['provider']))
        {
            if ($visitor->user_id)
            {
                // user may have just logged in while in the middle of a request
                // so just redirect to the index without showing an error.
                return $this->redirect($this->buildLink('index'));
            }
            else
            {
                return $this->error(\XF::phrase('there_is_no_valid_connected_account_request_available'));
            }
        }

        if ($connectedAccountRequest['provider'] !== $provider->provider_id)
        {
            $session->remove('connectedAccountRequest');
            $session->save();
            return $this->error(\XF::phrase('there_is_no_valid_connected_account_request_available'));
        }

        if (!$storageState->getProviderToken() || empty($connectedAccountRequest['tokenStored']))
        {
            return $this->error(\XF::phrase('error_occurred_while_connecting_with_x', ['provider' => $provider->title]));
        }

        $redirect = $connectedAccountRequest['returnUrl'];

        $providerData = $handler->getProviderData($storageState);

        // If we find this provider account is associated with a local account, we'll log into it.
        $connectedRepo = $this->getConnectedAccountRepo();
        $userConnected = $connectedRepo->getUserConnectedAccountFromProviderData($providerData);
        if ($userConnected && $userConnected->User)
        {
            if ($visitor->user_id)
            {
                return $this->error(\XF::phrase('this_account_is_already_associated_with_another_member'));
            }

            // otherwise, just log into that account
            $userConnected->extra_data = $providerData->extra_data;
            $userConnected->save();

            $associatedUser = $userConnected->User;

            /** @var \XF\ControllerPlugin\Login $loginPlugin */
            $loginPlugin = $this->plugin('XF:Login');
            $loginPlugin->triggerIfTfaConfirmationRequired(
                $associatedUser,
                $this->buildLink('login/two-step', null, [
                    '_xfRedirect' => $redirect,
                    'remember' => 1
                ])
            );
            $loginPlugin->completeLogin($associatedUser, true);

            return $this->redirect($redirect, '');
        }

        // We know the account isn't associated, but if its email matches someone else, we can't continue.
        // (If it matches our current account, we just disregard it.)
        if ($providerData->email)
        {
            $emailUser = $this->em()->findOne('XF:User', ['email' => $providerData->email]);
            if ($emailUser && $emailUser->user_id != $visitor->user_id)
            {
                return $this->error(\XF::phrase('this_accounts_email_is_already_associated_with_another_member'));
            }
        }

        $viewParams = [
            'provider' => $provider,
            'providerData' => $providerData,
            'redirect' => $redirect
        ];

        if ($visitor->user_id)
        {
            return $this->getConnectedAssociateResponse($viewParams);
        }
        else
        {
            return $this->getConnectedRegisterResponse($viewParams);
        }
    }

    protected function getConnectedAssociateResponse(array $viewParams)
    {
        $this->assertBoardActive(null);

        $visitor = \XF::visitor();

        /** @var \XF\Entity\UserAuth $auth */
        $auth = $visitor->Auth;
        if (!$auth || !$auth->getAuthenticationHandler()->hasPassword())
        {
            /** @var \XF\Service\User\PasswordReset $passwordConfirmation */
            $passwordConfirmation = $this->service('XF:User\PasswordReset', $visitor);
            $passwordConfirmation->triggerConfirmation();

            $passwordEmailed = true;
        }
        else
        {
            $passwordEmailed = false;
        }

        $viewParams['passwordEmailed'] = $passwordEmailed;

        return $this->view('XF:Account\ConnectedAssociate', 'account_connected_associate', $viewParams);
    }

    protected function getConnectedRegisterResponse(array $viewParams)
    {
        $this->assertBoardActive(null);

        return $this->view('XF:Register\ConnectedAccount', 'register_connected_account', $viewParams);
    }

    public function actionConnectedAccountAssociate(ParameterBag $params)
    {
        $this->assertPostOnly();

        $redirect = $this->getDynamicRedirect(null, false);

        $visitor = \XF::visitor();
        if (!$visitor->user_id)
        {
            return $this->redirect($redirect);
        }

        $provider = $this->assertProviderExists($params->provider_id);
        $handler = $provider->getHandler();

        $storageState = $handler->getStorageState($provider, $visitor);
        $providerData = $handler->getProviderData($storageState);

        if (!$storageState->getProviderToken())
        {
            return $this->error(\XF::phrase('error_occurred_while_connecting_with_x', ['provider' => $provider->title]));
        }

        if (!$visitor->user_id)
        {
            return $this->error(\XF::phrase('to_associate_existing_account_first_log_in'));
        }

        $userConnected = $this->getConnectedAccountRepo()->getUserConnectedAccountFromProviderData($providerData);
        if ($userConnected && $userConnected->user_id != $visitor->user_id)
        {
            return $this->error(\XF::phrase('this_account_is_already_associated_with_another_member'));
        }

        /** @var \XF\Service\User\Login $loginService */
        $loginService = $this->service('XF:User\Login', $visitor->username, $this->request->getIp());
        if ($loginService->isLoginLimited())
        {
            return $this->error(\XF::phrase('your_account_has_temporarily_been_locked_due_to_failed_login_attempts'));
        }

        $password = $this->filter('password', 'str');
        $user = $loginService->validate($password, $error);
        if (!$user)
        {
            return $this->error(\XF::phrase('your_existing_password_is_not_correct'));
        }

        $this->getConnectedAccountRepo()->associateConnectedAccountWithUser($visitor, $providerData);

        return $this->redirect($redirect);
    }

    public function actionConnectedAccountRegister(ParameterBag $params)
    {
        $this->assertRegistrationActive();
        $this->assertPostOnly();

        $redirect = $this->getDynamicRedirect(null, false);

        $visitor = \XF::visitor();
        if ($visitor->user_id)
        {
            return $this->redirect($redirect);
        }

        $provider = $this->assertProviderExists($params->provider_id);
        $handler = $provider->getHandler();

        $storageState = $handler->getStorageState($provider, $visitor);
        $providerData = $handler->getProviderData($storageState);

        if (!$storageState->getProviderToken())
        {
            return $this->error(\XF::phrase('error_occurred_while_connecting_with_x', ['provider' => $provider->title]));
        }

        $userConnected = $this->getConnectedAccountRepo()->getUserConnectedAccountFromProviderData($providerData);
        if ($userConnected && $userConnected->User)
        {
            return $this->error(\XF::phrase('this_account_is_already_associated_with_another_member'));
        }

        $input = $this->getConnectedRegistrationInput($providerData);
        $registration = $this->setupConnectedRegistration($input, $providerData);
        $registration->checkForSpam();

        if (!$registration->validate($errors))
        {
            return $this->error($errors);
        }

        $user = $registration->save();

        $this->getConnectedAccountRepo()->associateConnectedAccountWithUser($user, $providerData);

        $this->finalizeRegistration($user);

        return $this->redirect($this->buildLink('register/complete'));
    }

    protected function getConnectedRegistrationInput(AbstractProviderData $providerData)
    {
        $input = $this->filter([
            'username' => 'str',
            'email' => 'str',
            'timezone' => 'str',
            'location' => 'str',
            'dob_day' => 'uint',
            'dob_month' => 'uint',
            'dob_year' => 'uint',
            'custom_fields' => 'array',
        ]);

        $filterer = $this->app->inputFilterer();

        if ($providerData->email)
        {
            $input['email'] = $filterer->cleanString($providerData->email);
        }
        if ($providerData->location)
        {
            $input['location'] = $filterer->cleanString($providerData->location);
        }
        if ($providerData->dob)
        {
            $dob = $providerData->dob;
            $input['dob_day'] = $dob['dob_day'];
            $input['dob_month'] = $dob['dob_month'];
            $input['dob_year'] = $dob['dob_year'];
        }

        return $input;
    }

    protected function setupConnectedRegistration(array $input, AbstractProviderData $providerData)
    {
        /** @var \XF\Service\User\Registration $registration */
        $registration = $this->service('XF:User\Registration');
        $registration->setFromInput($input);
        $registration->setNoPassword();

        if ($providerData->email)
        {
            $registration->skipEmailConfirmation();
        }

        $avatarUrl = $providerData->avatar_url;
        if ($avatarUrl)
        {
            $registration->setAvatarUrl($avatarUrl);
        }

        return $registration;
    }

    public function actionRegister()
    {
        $this->assertPostOnly();
        $this->assertRegistrationActive();

        /** @var \XF\Service\User\RegisterForm $regForm */
        $regForm = $this->service('XF:User\RegisterForm', $this->session());
        if (!$regForm->isValidRegistrationAttempt($this->request(), $error))
        {
            // they failed something that a legit user shouldn't fail, redirect so the key is different
            $regForm->clearStateFromSession($this->session());
            return $this->redirect($this->buildLink('register'));
        }

        if (!$this->captchaIsValid())
        {
            return $this->error(\XF::phrase('did_not_complete_the_captcha_verification_properly'));
        }

        $input = $this->getRegistrationInput($regForm);
        $registration = $this->setupRegistration($input);
        $registration->checkForSpam();

        if (!$registration->validate($errors))
        {
            return $this->error($errors);
        }

        $user = $registration->save();
        $this->finalizeRegistration($user);

        return $this->redirect($this->buildLink('register/complete'));
    }

    protected function getRegistrationInput(\XF\Service\User\RegisterForm $regForm)
    {
        $input = $regForm->getHashedInputValues($this->request);
        $input += $this->request->filter([
            'location' => 'str',
            'dob_day' => 'uint',
            'dob_month' => 'uint',
            'dob_year' => 'uint',
            'custom_fields' => 'array',
        ]);

        return $input;
    }

    protected function setupRegistration(array $input)
    {
        /** @var \XF\Service\User\Registration $registration */
        $registration = $this->service('XF:User\Registration');
        $registration->setFromInput($input);

        return $registration;
    }

    protected function finalizeRegistration(\XF\Entity\User $user)
    {
        $this->session()->changeUser($user);
        \XF::setVisitor($user);

        /** @var \XF\ControllerPlugin\Login $loginPlugin */
        $loginPlugin = $this->plugin('XF:Login');
        $loginPlugin->createVisitorRememberKey();
    }

    public function actionComplete()
    {
        $visitor = \XF::visitor();
        if (!$visitor->user_id || $visitor->register_date < \XF::$time - 3600)
        {
            return $this->redirect($this->buildLink('index'));
        }

        $viewParams = [
            'redirect' => $this->filter('redirect', 'str')
        ];
        return $this->view('XF:Register\Complete', 'register_complete', $viewParams);
    }

    protected function assertRegistrationActive()
    {
        if (!$this->options()->registrationSetup['enabled'])
        {
            throw $this->exception(
                $this->error(\XF::phrase('new_registrations_currently_not_being_accepted'))
            );
        }

        // prevent discouraged IP addresses from registering
        if ($this->options()->preventDiscouragedRegistration && $this->isDiscouraged())
        {
            throw $this->exception(
                $this->error(\XF::phrase('new_registrations_currently_not_being_accepted'))
            );
        }
    }

    /**
     * @return \XF\Repository\User
     */
    protected function getUserRepo()
    {
        return $this->repository('XF:User');
    }

    /**
     * @param string $id
     * @param array|string|null $with
     * @param null|string $phraseKey
     *
     * @return \XF\Entity\ConnectedAccountProvider
     */
    protected function assertProviderExists($id, $with = null, $phraseKey = null)
    {
        return $this->assertRecordExists('XF:ConnectedAccountProvider', $id, $with, $phraseKey);
    }

    /**
     * @return \XF\Repository\ConnectedAccount
     */
    protected function getConnectedAccountRepo()
    {
        return $this->repository('XF:ConnectedAccount');
    }

    public function assertViewingPermissions($action) {}
    public function assertTfaRequirement($action) {}

    public function assertBoardActive($action)
    {
        switch (strtolower($action))
        {
            case 'connectedaccount':
                break;

            default:
                parent::assertBoardActive($action);
        }
    }

    public static function getActivityDetails(array $activities)
    {
        return \XF::phrase('registering');
    }
}

Is that the right way to get the Variables work?
Thank you very, very much for your good Help! :)
 
Last edited:
Top Bottom