Creating a Module

  • Getting started

    Here is a quick overview of how to build a module that actually does something.

    This module will send an email to the admin user whenever a new user clicks on the activate link that they were sent after completing the signup form.

    The module will "listen" for this even to happen, and when it does we'll do our work (i.e. send the email).
  • In order to easily browse different events that are triggered in the system, turn on developer mode in the global config section of the developer tools module. If you don't have the Developer Module installed, make sure you've installed it from your Marketplace before you continue.
  • turn on developer mode
  • Now that we have developer mode turned on, we are able to see what triggers are available to us on every modules Info tab.

    The one that interests us in this exercise is the jrUser module because it controls the user signup and activation.

    After turning on developer mode and navigating to the jrUser modules' Info tab, we see this extra info related to Triggers and Events.
  • A list of events fired by the jrUser module, a description, and modules that are currently listening for each event.
  • The one we are interested in is the 'signup_activated' as it has a description that matches when we want to fire our module.

    "Fired when a user successfully validates their account"

    We can also see that there is another module that is also listening for this event, and firing off the function: jrProfile_signup_activated_listener().

    If we take that information 'jrProfile_signup_activated_listener' and run it through our IDE and see where that function is used, it only shows up in 2 locations:
  • a search of the Jamroom codebase reveals 'jrProfile_signup_activated_listener' is used in 2 locations.
  • Of those 2 locations, one is the actual function definition of what the function does. So the other one must be how to fire that function.

    If we take a look at it it looks like this:
  • In the modules _init() function a listener is being registered.
  • The absolute minimum you need for a module is:
    * a module name prefixed with your unique prefix. (the jamroom network uses 'jr')
    * an include.php file.
  • Setting up our module structure

    Setting up our module structure
    So the first thing we do is create that structure with empty files, for now, I'll use 'xx' as a module prefix. The module will be called xxSignupNotify.

    Once the module structure is in place, you can start putting the needed functions in place to let Jamroom know that its a module.

    That means it needs a _meta() function and an _init() function in the include.php file.
  • So in our new module we need to do the following:

    * In the modules _init() function we are going to register an event listener for the 'signup_activated' event and add the name of the function we want to fire.

    * create the function that is going to be called when the event happens.

    That function is going to figure out what the admin's email is, then send them a message telling them they have a new user who just signed up.
  • Making the module do something

    Ok, so we have the modules structure in place, time to make it do something.

    The goal of this module has always been to "send an email to the admin when an new user activates their account". So lets get that working.
  • Simplest include.php file

    This is the simplest include.php file. It just contains a _meta() function and an _init() function.

    So far the module does nothing more than tell the Core that it is a module, and provides some meta information about the module (via the meta function).
    <?php
    /**
     * @copyright xxxxxx.
     */
    
    // make sure we are not being called directly
    
    defined('APP_DIR') or exit();
    
    /**
     * meta
     */
    function xxSignupNotify_meta()
    {
        $_tmp = array(
            'name'        => 'Signup Notify',
            'url'         => 'signupnotify',
            'version'     => '1.0.0',
            'developer'   => 'whoever developed this, ©' . strftime('%Y'),
            'description' => 'Send out an email to the system admin when a new user signs up.',
            'category'    => 'communication'
        );
        return $_tmp;
    }
    
    /**
     * init
     */
    function xxSignupNotify_init()
    {
        return true;
    }
  • First thing we need is to fire of a function when that happens.

    We do that by registering a function of ours to be fired when the 'signup_activated' event happens.

    That registration happens in our modules _init() function. We do that like this:
    /**
     * init
     */
    function xxSignupNotify_init()
    {
        //register event listeners   
    
     jrCore_register_event_listener('jrUser','signup_activated','xxSignupNotify_signup_activated_listener');
    
        return true;
    }
  • Thats it. We now have a function that fires when the 'signup_activated' event happens.

    The name we give the function to be fired could be anything, but to keep with convention, we used 'xxSignupNotify_signup_activated_listener'.

    That is (module_name)_(event being listened for)_listener.

    So now lets add that function definition. The easiest way to set it up is to copy another listener.

    The jrProfile_signup_activated_listener function looked like this:
    /**
     * Listens for when new users activate their account so it can
     * activate the associated user profile
     * @param $_data array Array of information from trigger
     * @param $_user array Current user
     * @param $_conf array Global Config
     * @param $_args array additional parameters passed in by trigger caller
     * @param $event string Triggered Event name
     * @return array
     */
    function jrProfile_signup_activated_listener($_data,$_user,$_conf,$_args,$event)
    {
    //....
    
    
  • Thats what were going to use as a base, just change jrProfile to xxSignupNotify and we're good to go.


    /**
     * Listens for when new users activate their account so it can
     * send a note to the admin users
     * @param $_data array Array of information from trigger
     * @param $_user array Current user
     * @param $_conf array Global Config
     * @param $_args array additional parameters passed in by trigger caller
     * @param $event string Triggered Event name
     * @return array
     */
    function xxSignupNotify_signup_activated_listener($_data,$_user,$_conf,$_args,$event)
    {
        
        return $_data;
    }
    
  • Whenever you use a listener to do something at any point in time, remember to always return the $_data so other modules can use it too.

    If you change that data in your module, it changes everywhere. If you don't return that $_data after you've finished using it, the system will break.
  • Get A debugger if you plan on doing development the easy way. A debugger allows you to set 'break points' in the code. When a break point is hit the debugger will stop at that point in your IDE and show you the values of all the variables that are available.

    IDE recommendation: PhpStorm by JetBrains
    debugger recommendation: xDebug
  • Figuring out what we have to work with

    Ok, so we are at the point of having a function fire when the new user confirms their signup, but what data do we have to work with.

    We have the function xxSignupNotify_signup_activated_listener() working, now we need to figure out how to make it send the admin an email.

    The absolute simplest way to see what we have to work with at this point is if you have a debugger setup with your IDE. If you do, then this part is a piece of cake.

    You would set a break point on the 'return $_data;' line and just look at all the stuff you can play with. Seriously recommend PhpStorm IDE and xDebug if you plan on doing serious development.

    Otherwise, we can log the incoming data to the debug log using fdebug() function.
  • Without a debugger

    Without a debugger, the process is a bit longer, but still possible.

    You want to see what data we have coming into our function, so we can send that all to the debug log in the admin panel.

    The function we use for that is fdebug().
    function xxSignupNotify_signup_activated_listener($_data, $_user, $_conf, $_args, $event)
    {
        //add in fdebug to see what we have in our incoming data
    
    
        //set each of the variables into an array
    
        $debug = array(
            'what'   => 'We are trying to see what info we have to work with when xxSignupNotify_signup_activated_listener() fires ',
            '$_data' => $_data,
            '$_user' => $_user,
            '$_conf' => $_conf,
            '$_args' => $_args,
            '$event' => $event
        );
        fdebug($debug);
    
        return $_data;
    }
  • See if it fires

    Now we need to sign up as a new user to see that it fires.

    What we expect to happen is: when a new user signs up and activates their account, we will get a bunch of info into our debug log in the admin panel.

    (So I'm going to create a new user now)
  • If you want this function to fire, make sure the module has been activated in the admin control panel.
  • available variables

    That worked fine, all the variables available found their way into the debug log.

    It looks like this:
    Array
    (
        [what] => We are trying to see what info we have to work with when xxSignupNotify_signup_activated_listener() fires 
        [$_data] => Array
            (
                [user_name] => eight
                ... lots of keys ...
                [profile_updated] => 1375516290
            )
    
        [$_user] => Array
            (
                [is_logged_in] => yes
                ... lots of keys ...
                [user_active_profile_id] => 1
            )
    
        [$_conf] => Array
            (
                [jrCore_base_url] => http://jr500.iixxii.cc
    
                ... lots of keys ...
                [_] => 
            )
    
        [$_args] => Array
            (
                [module] => jrUser
            )
    
        [$event] => signup_activated
    )
  • What you will see will be a lot longer, and contain a lot more information and keys in the arrays (we've cut it short here to prevent the page from being too long).

    This is what it would look like if you had a debugger:
  • variables in a debugger

    variables in a debugger
    Working with a debugger makes access to variables easy and development much simpler.
  • Using the Variables

    We know what variables we can use, so now lets use them to send out an email to the admin.

    Easier than figuring it all out on our own is looking in other locations to see how they do it, copy that way of doing it into our function.
  • Looking through the other modules, jrUser/templates has a number of files named with this pattern:
    email_(something)_message.tpl
    email_(something)_subject.tpl

    and the jrOneAll module also represents that same pattern in its file naming:
    jrOneAll/templates/email_password_message.tpl
    jrOneAll/templates/email_password_subject.tpl

    So using that middle section as a possible key, I run it through my IDE to find where it appears. I'm guessing that the jrOneAll module only fires one email, so that might be the clearest to help me understand how it works.

    The search term I use is 'password' as that is the center part of email_password_subject.tpl
  • Sending an email

    Sending an email
    Found an example of sending an email
  • Bingo! We now have an example of how to send an email. The structure is:

    * Setup an array with all the terms you want to pass into your email template
    * create 2 template files for the email, a _message and _subject file.
    * check that the email address you want to send the email to is a valid email address
    * send the email.

    So carried over to our function that would look like this:
  • Final function structure.

    Here is the final structure of our function that fires when a new user activates their account.
    function xxSignupNotify_signup_activated_listener($_data, $_user, $_conf, $_args, $event)
    {
    
        //email is set in the admin panel under 'Email Support' -> "From Email Address"
    
        $email = $_conf['jrMailer_from_email'];
        // Send system admin an email
    
        $_rp = array(
            'system_name'  => $_conf['jrCore_system_name'],
            'jamroom_url'  => $_conf['jrCore_base_url'],
            'user_name'    => $_data['user_name'],
            'user_email'   => $_data['user_email'],
            'profile_name' => $_data['profile_name'],
            'profile_url'  => $_data['profile_url']
        );
    
        list($sub, $msg) = jrCore_parse_email_templates('xxSignupNotify', 'new_user', $_rp);
        if (isset($email) && jrCore_checktype($email, 'email')) {
            jrCore_send_email($email, $sub, $msg);
        }
    
        return $_data;
    }
  • email subject template

    The email subject template looks like this:

    [{$system_name}] A new user has signed up! {$profile_name}
  • email message template

    The email message template looks like this:

    NOTE: that we can use the {$user_name} variables here because we put them into the $_rp array that we passed in.
    Hi Admin,
    
    A new user has signed up to your system {$system_name}!
    
    Their details are:
    user name: {$user_name}
    user email: {$user_email}
    profile name: {$profile_name}
    profile url: <a href="{$jamroom_url}/{$profile_url}">{$jamroom_url}/{$profile_url}</a>
    
    
  • Email Received

    Email Received
    Email received. Project Complete!
  • Download: xxSignupNotify.zip

    Download the finished source code for this module.

Tags