Jump to content

FrontendUserLogin


pwFoo
 Share

Recommended Posts

FrontendUserLogin
 
Module to handle frontend user login / logout.

Also should work with Persistent login for users (mode: automatically) out of the box

Version

  • 0.3.1

Requires

Download

Usage

Module isn't available anymore, but it's planed to replace FrontendUserLogin and FrontendUserRegister with the new FrontendUser module which is not released yet.

A new support topic will be created after FrontendUser module is added to the PW module repo.

FrontendUser module

Edited by pwFoo
  • Like 7
Link to comment
Share on other sites

  • 1 month later...

Released version 0.1.0

  • minor changes
  • updated compatibility to FormHelper 0.3.2
  • moved render() out of the login() method to make the form changeable via public FormHelper class variable $this->fh->...
  • username sanitized by FormHelper (sanitizer set in username field array)

I would like to make the module flexible and extendable, but at the moment no addons / plugins implemented...

Link to comment
Share on other sites

  • 1 month later...

New branch with removed FormHelper dependency. Instead it uses the new form api array input support.

Works in my local test environment. Simple frontend login module with error handling.

After some time playing with JavaScript / ajax I should finish some basic modules *g*

Link to comment
Share on other sites

  • 1 month later...

FrontendUserLogin 0.3 released (dev / unstable)

Updated initial post. Tests and feedback welcome! :)

  • FormHelper dependency is removed
  • should work with Persistent login for users  (mode: automatically) out of the box
  • simple error handling (login failed, LoginThrottle, missing required value)

  • Strings translatable by using $this->_()

  • code optimized and some hookable methods removed (use PW Session methods instead!)
    Session::login
    Session::authenticate
    Session::logout
    Session::redirect
  • hookable methods to modify form fields and form process / validation. Also to extend module with plugins / addons.
    FrontendUserLogin::processForm
    FrontendUserLogin::buildLoginForm
    

ToDo

  • Change password field type to password (at the moment isn't supported by PW?!)
  • Remove (optional) field labels (seems not working after field is added to the form object?!)
  • maybe a default style and optional add custom css / js code
  • Change integration of Persistent login for users via plugin module (add Remember me checkbox and trigger PersistLogin manual mode)
  • Forgot Password core module integration?
Edited by pwFoo
Link to comment
Share on other sites

Login module should work, but the form is unstyled.

A plugin is a module with attach / detach during install / uninstall to the parent module.

Demo plugins (minimal tested!) are

  • persistLogin module integration (manual mode, remember me checkbox)
  • ProcessForgotPassword (core module) integration

https://bitbucket.org/pwFoo/frontenduserlogin/src/be5b84b78d24060872d0ae96f2e7631f50028099/FrontendUserLogin/?at=master

Edited by pwFoo
Link to comment
Share on other sites

  • 1 month later...

I have a local testing version with field callbacks ("prepare" before added to form and "process" after form "basic" process) and preLogin / postLogin callbacks

Possible usage:

// Integrate LoginPersist module (manual mode) after sucessfully logged in
$callback['postLogin'] = function ($fulObj) {
    if ($fulObj->attr('result')) {
        wire('modules')->get('LoginPersist')->persist();
    }
};

// optional login with email address instead of an username... (could also be done as username form field callback "process"! Just an example!!!)
$callback['preLogin'] = function ($fulObj) {
// callback defined outside the module class, so $this and private class attributes won't work!
// module object hand over as function param. Get / set attributes with the attr() method.
$email = $fulObj->attr('form')->get('username')->value;
$userObj = wire('users')->get("email={$email}");
if ($userObj instanceof User) $fulObj->attr('user', $userObj->name);
};

// login call with optional callback
echo $ful->login("{$config->urls->root}login", $callback)->render();

Internal field process callback (sanitize input value)

/**
 * Username form field
 * @return object Username field
 */
protected function fieldUsername() {
    $field = $this->modules->get('InputfieldText');
    $field->label = $this->_('Username');
    $field->attr('id+name', 'username');
    $field->required = 1;
    // Set a "callbackProcess" to sanitize the input value or a "callbackPrepare" executed just before the field will be added to the form
    $field->fulOption = array(
        'callbackProcess' => function ($field) {
//      'callbackProcess' => function ($field, $obj) { // to get module object also outside the module class use an additional param
            // callback defined inside the module class and $this will work here. Also wire() could be used
            $this->user = wire('sanitizer')->username($field->value);
        },
        'callbackPrepare' => function ($field) {
            // Your code here... will be executed before field added to form
        }
    );
    return $field;
}

What do you think about the change and usage of dynamic functions as callbacks?

Link to comment
Share on other sites

  • 3 weeks later...

Latest update to my local testing branch...

  • Moved totally from custom callbacks to PW hooks (core and module own hookable methods)
  • Have a working minimal FrontendUserLogin and FrontendUserRegister module.
  • Added FormHelper dependency again (instead of a extended wrapper FormHelper is changed to extend InputfieldForm object)

FrontendUserLogin / FrontendUserRegister (simple use)

// login
echo $modules->get('FrontendUserLogin')->render($redirectAfterLogin);

// register
echo $modules->get('FrontendUserRegister')->render($redirectAfterRegister);

The method render() is a shortcut. Long form with chance to modify parameters, form, ... 

$fu->form();
$fu->validate();
$fu->process($redirect);
$fu->renderForm();

How to add plugins?

After $fu->form() define the plugin field and needed processing validation code as a PW hook

RememberMe plugin to integrate LoginPersist module

    // RememberMe field / persistLogin integration
    $remember = $modules->get('InputfieldCheckboxes');
    $remember->name = 'persist';
    $remember->attr('id+name', 'persist');
    $remember->skipLabel = 4;
    $remember->addoption('persist', 'Remember me?');
    $remember->addHookAfter('processInput', function($event) {
        $field = $event->object;
        if (isset($field->value[0]) && $field->value[0] === 'persist') {
            wire()->addHookAfter('Session::login', function($event) {
                wire('modules')->get('LoginPersist')->persist();
            });
        }
    });
    $fu->attr('form')->add($remember);

Or an integration of core module ProcessForgotPassword

    // ForgotPassword integration
    $forgot = $modules->get('InputfieldMarkup');
    $forgot->value = "<a href='{$page->url}?forgot=1'>{$this->_('Forgot password?')}</a>";
    $fu->attr('form')->add($forgot);
    
    if ($input->get->forgot) {
        function processForgot($event) {
            wire('config')->styles->add('/pw/wire/modules/AdminTheme/AdminThemeDefault/styles/main-classic.css');
            $event->return = wire('modules')->get('ProcessForgotPassword')->execute();
            $event->replace = true;
        }
        $fu->addHookBefore('FrontendUserLogin::login', null, 'processForgot');
    }

Login with email address instead of username?

    // Email login instead of username
    $fieldUser = $fu->attr('form')->get('username');
    $fieldUser->addHookBefore('FrontendUserLogin::auth', function($event) {
        $fu = $event->object;
        $email = $fu->attr('form')->fhValue('username', 'email');
        $loginUser = wire('users')->get("email={$email}");
        if ($loginUser instanceof User && !$loginUser->isGuest()) {
            $event->arguments(0, $loginUser->name);
        }
    });

You have added a nickname field to user template? The plugin to use the nickname (sanitized text instead of username) to login

    // Nickname login instead of username
    $fieldUser = $fu->attr('form')->get('username');
    $fieldUser->addHookBefore('FrontendUserLogin::auth', function($event) {
        $fu = $event->object;
        $nick = $fu->attr('form')->fhValue('username', 'text');
        $loginUser = wire('users')->get("nickname={$nick}");
        if ($loginUser instanceof User && !$loginUser->isGuest()) {
            $event->arguments(0, $loginUser->name);
        }
    });

The plugins are tested and working fine, but I don't know how to ship plugins. At the moment it's code inside the template login.php, but should be moved to a separate plugin file or the FrontendUserLogin module...

Any suggestions?

*Added nickname login plugin and fixed a nickname / email login bug*

Edited by pwFoo
  • Like 4
Link to comment
Share on other sites

Here is a FrontendUserLogin screenshot with additional fields (PersistLogin, ProcessForgotPassword integration) and a basic style (removed list style), Form fields without label and placeholder instead.

Frontent_User_Login.jpg

Default css / js can be added inside the module directory. Custom styles will be loaded from templates/FrontendUserLogin/FrontendUserLogin.<css|js>.

FormHelper dependency could be replaced, but in version 0.7+ FormHelper isn't that big and no need to copy & paste form handling to each module with forms or file upload (FrontendUserLogin, FrontendUserRegister, contact form, ...).

  • Like 1
Link to comment
Share on other sites

FrontendUserLogin module deletion requested, because it's an old and deprecated version.

Last posts here reference to a redesigned and not compatible new module / branch.

I have deleted this module from the directory, but you should consider removing the link from your first post and explain to users what the alternative is.

Link to comment
Share on other sites

  • 2 weeks later...
  • 2 weeks later...

FrontendUser module handles login, logout and user registration.

I moved the complex email validation plugin, ProcessForgotPassword and LoginPersist module integration into the FrontendUser module for testing.

If anyone would do some tests...

Repo: https://bitbucket.org/pwFoo/frontenduser/overview

Doku: https://bitbucket.org/pwFoo/frontenduser/wiki/Documentation

Current download for testing: https://bitbucket.org/pwFoo/frontenduser/get/master.zip

  • Like 2
Link to comment
Share on other sites

  • 2 weeks later...

hi pwFoo,

i'm toying around with your great register module. I have a php fatal error and since i'm not-so in-depth to php/versions/objectoriented stuff, would you mind and confirm or not if this may be caused by me being forced to use PW in a php 5.3 environment?
PW (2.58) in itself runs fine; but I noticed from the earlier notes in your module that it needed php >5.5 (?). Anyhow the error looks like $this (no pun intented):

Fatal error: Using $this when not in object context in /var/www/<snipsnap>/site/modules/FrontendUser/FrontendUser.module on line 252

which refers to this line

$username = $this->form->fhValue($field->name);

in here:

protected function usernameRegister() {
        $field = $this->modules->get('InputfieldText');
        $field->label = $this->_('Username');
        $field->attr('id+name', 'username');
        $field->required = 1;
        $field->fhSanitizer = 'username';
        $field->addHookAfter('processInput', function($event) {
            $field = $event->object;
            $username = $this->form->fhValue($field->name);
            
            if (empty($username))   return;
            elseif (wire('users')->count("name={$username}") == 0) {
                $this->userObj->name = $username;
            }
            else {
                $field->error(__('Username already taken!'));  
            }
        });
        return $field;
    }

many thx for the module :-)

cheers
Tom

Link to comment
Share on other sites

Hello Tom,

thank You for your feedback here!

It's a anonymous function problem / missing feature. I have to add a PHP 5.4 dependency or find a workaround. I missed that because I tested it with a PHP 5.5.24. 

Version Description 5.4.0 $this can be used in anonymous functions. 5.3.0 Anonymous functions become available.

See here: http://php.net/manual/en/functions.anonymous.php

That could be a workaround...

    /**
     * Username form field
     * @return InputfieldText Username field
     */
    protected function usernameRegister() {
        $field = $this->modules->get('InputfieldText');
        $field->label = $this->_('Username');
        $field->attr('id+name', 'username');
        $field->required = 1;
        $field->fhSanitizer = 'username';

        // workaround PHP 5.3
        $fu = $this; 
        //$field->addHookAfter('processInput', function($event) {
        $field->addHookAfter('processInput', function($event) use ($fu) {
            $field = $event->object;
            // workaround PHP 5.3
            //$username = $this->form->fhValue($field->name);
            $username = $fu->attr('form')->fhValue($field->name);

            if (empty($username))   return;
            elseif (wire('users')->count("name={$username}") == 0) {
                // workaround PHP 5.3
                //$this->userObj->name = $username;
                $fu->attr('userObj')->name = $username;
            }
            else {
                $field->error(__('Username already taken!'));  
            }
        });
        return $field;
    }

I think some more changes like that have to be done to get it work with PHP 5.3

But I don't know if it make sense to make it PHP 5.3 compatible. But should be no problem if that's all...

P.S.:

Sorry for confusion of different topics *g*

The correct support topic is: https://processwire.com/talk/topic/9811-frontenduser-login-logout-and-register-users-members/

  • Like 1
Link to comment
Share on other sites

Guest
This topic is now closed to further replies.
 Share

×
×
  • Create New...