Iliad Framework, the registration form

In the previous post we talked about checking emails addresses, just to show how we can use regexps in Pharo.

In this post we are returning to the Iliad Framework and we will be a registration form.

We start, as we have done for the login form, creating a component for the registration form. This component will then be integrated into the application and another controller will be build.

<span class="nc">ILWidget</span><span class="k"> subclass: </span><span class="ss">#PnCreateUser</span>
<span class="k">    instanceVariableNames: </span><span class="s">'email password password2 name surname errors'</span>
<span class="k">    classVariableNames: </span><span class="s">''</span>
<span class="k">    poolDictionaries: </span><span class="s">''</span>
<span class="k">    category: </span><span class="s">'LeonardoBlog'</span><span class="k">!</span>

As you can see the instance variable of this component, like what was happening in the registration form, are derived from the variable state of the component. We created an instance variable for every data that the user will enter and a errors fields that will be empty whenxb there are no errors.

The initialize method clear all the instance variables:

<span class="k">!</span><span class="nc">PnCreateUser</span><span class="k"> methodsFor: </span><span class="s">'initialization'</span><span class="k">!</span>
<span class="nf">initialize</span>
    <span class="bp">super</span> <span class="nf">initialize</span><span class="p">.</span>
    <span class="nv">name</span> <span class="o">:=</span> <span class="s">''</span><span class="p">.</span>
    <span class="nv">surname</span> <span class="o">:=</span> <span class="s">''</span><span class="p">.</span>
    <span class="nv">password</span> <span class="o">:=</span> <span class="s">''</span><span class="p">.</span>
    <span class="nv">password2</span> <span class="o">:=</span> <span class="s">''</span><span class="p">.</span>
    <span class="nv">email</span> <span class="o">:=</span> <span class="s">''</span><span class="p">.</span>
    <span class="nv">errors</span> <span class="o">:=</span> <span class="s">''</span><span class="p">.</span><span class="k">! !</span>

As you saw in the login form when you are programming in Smalltalk you usually create short methods, more short than the method you will be used to. This is an example:

<span class="k">!</span><span class="nc">PnCreateUser</span><span class="k"> methodsFor: </span><span class="s">'building'</span><span class="k">!</span>
<span class="nf">contents</span>
    <span class="o">^</span> [ <span class="o">:</span><span class="nv">e</span> <span class="o">|</span>
    <span class="nv">e</span> <span class="nf">h1</span> <span class="nf">text:</span> <span class="s">'Register your account'</span><span class="p">.</span>
    <span class="nv">e</span> <span class="nf">p</span>
        <span class="nf">text:</span>
            <span class="s">'You will use your email to login'</span><span class="p">.</span>
    <span class="nv">e</span> <span class="nf">form</span>
        <span class="nf">build:</span> [ <span class="o">:</span><span class="nv">form</span> <span class="o">|</span>
            <span class="bp">self</span> <span class="nf">buildEmailRow:</span> <span class="nv">form</span><span class="p">.</span>

            <span class="bp">self</span> <span class="nf">buildNameRow:</span> <span class="nv">form</span><span class="p">.</span>
            <span class="bp">self</span> <span class="nf">buildSurnameRow:</span> <span class="nv">form</span><span class="p">.</span>

            <span class="bp">self</span> <span class="nf">buildPasswordRow:</span> <span class="nv">form</span><span class="p">.</span>
            <span class="bp">self</span> <span class="nf">buildRepeatPasswordRow:</span> <span class="nv">form</span><span class="p">.</span>

            <span class="bp">self</span> <span class="nf">buildErrorMessageRow:</span> <span class="nv">form</span><span class="p">.</span>

            <span class="nv">form</span> <span class="nf">button</span>
                <span class="nf">class:</span> <span class="s">'btn btn-default'</span><span class="p">;</span>
                <span class="nf">text:</span> <span class="s">'Register to project notes'</span><span class="p">;</span>
                <span class="nf">action:</span> [ <span class="bp">self</span> <span class="nf">registerAction</span> ] ] ]<span class="k">! !</span>

<span class="k">!</span><span class="nc">PnCreateUser</span><span class="k"> methodsFor: </span><span class="s">'building'</span><span class="k">!</span>
<span class="nf">buildErrorMessageRow:</span> <span class="nv">aForm</span>
    <span class="nv">errors</span>
        <span class="nf">ifNotEmpty:</span> [ (<span class="nv">aForm</span> <span class="nf">div</span> <span class="nf">class:</span> <span class="s">'alert alert-warning'</span>) <span class="nf">ul</span>
        <span class="nf">build:</span> [ <span class="o">:</span><span class="nv">box</span> <span class="o">|</span> (<span class="nv">errors</span> <span class="nf">findTokens:</span> <span class="nc">String</span> <span class="nf">cr</span>) <span class="nf">do:</span> [ <span class="o">:</span><span class="nv">msg</span> <span class="o">|</span> <span class="nv">box</span> <span class="nf">li</span> <span class="nf">text:</span> <span class="nv">msg</span> ] ] ]<span class="k">! !</span>

<span class="k">!</span><span class="nc">PnCreateUser</span><span class="k"> methodsFor: </span><span class="s">'building'</span><span class="k">!</span>
<span class="nf">buildPasswordRow:</span> <span class="nv">aForm</span>
    <span class="nv">aForm</span> <span class="nf">div</span> <span class="nf">class:</span> (<span class="nv">errors</span> <span class="nf">ifNotNil:</span> [ <span class="s">'form-group has-error'</span> ] <span class="nf">ifNil:</span>  [ <span class="s">'form-group'</span> ])<span class="p">;</span>
            <span class="nf">build:</span> [ <span class="o">:</span> <span class="nv">row</span> <span class="o">|</span>
                <span class="nv">row</span> <span class="nf">label</span> <span class="nf">text:</span><span class="s">'Password: '</span><span class="p">.</span>
                <span class="nv">row</span> <span class="nf">input</span> <span class="nf">class:</span><span class="s">'form-control'</span><span class="p">;</span>  <span class="nf">type:</span> <span class="s">'password'</span><span class="p">;</span> <span class="nf">action:</span> [ <span class="o">:</span><span class="nv">text</span> <span class="o">|</span> <span class="nv">password</span> <span class="o">:=</span> <span class="nv">text</span> ]<span class="p">;</span> <span class="nf">value:</span><span class="s">''</span> ]<span class="k">! !</span>

<span class="k">!</span><span class="nc">PnCreateUser</span><span class="k"> methodsFor: </span><span class="s">'building'</span><span class="k">!</span>
<span class="nf">buildEmailRow:</span> <span class="nv">aForm</span>
    <span class="nv">aForm</span> <span class="nf">div</span> <span class="nf">class:</span> (<span class="nv">errors</span> <span class="nf">ifNotNil:</span> [ <span class="s">'form-group has-error'</span> ] <span class="nf">ifNil:</span>  [ <span class="s">'form-group'</span> ])<span class="p">;</span>
            <span class="nf">build:</span> [ <span class="o">:</span> <span class="nv">row</span> <span class="o">|</span>
                <span class="nv">row</span> <span class="nf">label</span> <span class="nf">text:</span><span class="s">'Email'</span><span class="p">.</span>
                <span class="nv">row</span> <span class="nf">input</span> <span class="nf">class:</span><span class="s">'form-control'</span><span class="p">;</span> <span class="nf">action:</span> [ <span class="o">:</span><span class="nv">text</span> <span class="o">|</span> <span class="err">email</span><span class="o">:=</span> <span class="nv">text</span> ]<span class="p">;</span> <span class="nf">value:</span><span class="nv">email</span>]<span class="k">! !</span>

<span class="k">!</span><span class="nc">PnCreateUser</span><span class="k"> methodsFor: </span><span class="s">'building'</span><span class="k">!</span>
<span class="nf">buildSurnameRow:</span> <span class="nv">aForm</span>
    <span class="nv">aForm</span> <span class="nf">div</span> <span class="nf">class:</span> (<span class="nv">errors</span> <span class="nf">ifNotNil:</span> [ <span class="s">'form-group has-error'</span> ] <span class="nf">ifNil:</span>  [ <span class="s">'form-group'</span> ])<span class="p">;</span>
            <span class="nf">build:</span> [ <span class="o">:</span> <span class="nv">row</span> <span class="o">|</span>
                <span class="nv">row</span> <span class="nf">label</span> <span class="nf">text:</span><span class="s">'Surname'</span><span class="p">.</span>
                <span class="nv">row</span> <span class="nf">input</span> <span class="nf">class:</span><span class="s">'form-control'</span><span class="p">;</span> <span class="nf">action:</span> [ <span class="o">:</span><span class="nv">text</span> <span class="o">|</span> <span class="err">surname</span><span class="o">:=</span> <span class="nv">text</span> ]<span class="p">;</span> <span class="nf">value:</span><span class="nv">email</span>]<span class="k">! !</span>

<span class="k">!</span><span class="nc">PnCreateUser</span><span class="k"> methodsFor: </span><span class="s">'building'</span><span class="k">!</span>
<span class="nf">buildRepeatPasswordRow:</span> <span class="nv">aForm</span>
    <span class="nv">aForm</span> <span class="nf">div</span> <span class="nf">class:</span> (<span class="nv">errors</span> <span class="nf">ifNotNil:</span> [ <span class="s">'form-group has-error'</span> ] <span class="nf">ifNil:</span>  [ <span class="s">'form-group'</span> ])<span class="p">;</span>
            <span class="nf">build:</span> [ <span class="o">:</span> <span class="nv">row</span> <span class="o">|</span>
                <span class="nv">row</span> <span class="nf">label</span> <span class="nf">text:</span><span class="s">'Repeat Password: '</span><span class="p">.</span>
                <span class="nv">row</span> <span class="nf">input</span> <span class="nf">class:</span><span class="s">'form-control'</span><span class="p">;</span> <span class="nf">type:</span> <span class="s">'password'</span><span class="p">;</span> <span class="nf">action:</span> [ <span class="o">:</span><span class="nv">text</span> <span class="o">|</span> <span class="nv">password2</span> <span class="o">:=</span> <span class="nv">text</span> ]<span class="p">;</span> <span class="nf">value:</span><span class="s">''</span>]<span class="k">! !</span>

<span class="k">!</span><span class="nc">PnCreateUser</span><span class="k"> methodsFor: </span><span class="s">'building'</span><span class="k">!</span>
<span class="nf">buildNameRow:</span> <span class="nv">aForm</span>
    <span class="nv">aForm</span> <span class="nf">div</span> <span class="nf">class:</span> (<span class="nv">errors</span> <span class="nf">ifNotNil:</span> [ <span class="s">'form-group has-error'</span> ] <span class="nf">ifNil:</span>  [ <span class="s">'form-group'</span> ])<span class="p">;</span>
            <span class="nf">build:</span> [ <span class="o">:</span> <span class="nv">row</span> <span class="o">|</span>
                <span class="nv">row</span> <span class="nf">label</span> <span class="nf">text:</span><span class="s">'Name'</span><span class="p">.</span>
                <span class="nv">row</span> <span class="nf">input</span> <span class="nf">class:</span><span class="s">'form-control'</span><span class="p">;</span> <span class="nf">action:</span> [ <span class="o">:</span><span class="nv">text</span> <span class="o">|</span> <span class="err">name</span><span class="o">:=</span> <span class="nv">text</span> ]<span class="p">;</span> <span class="nf">value:</span><span class="nv">email</span>]<span class="k">! !</span>

In the previous example there is nothing interesting: just creating a form like the login form but with more fields. This is the error checking method that we will be calling before the registration action:

<span class="k">!</span><span class="nc">PnCreateUser</span><span class="k"> methodsFor: </span><span class="s">'actions'</span><span class="k">!</span>
<span class="nf">checkErrors</span>
    <span class="nv">errors</span> <span class="o">:=</span> <span class="s">''</span><span class="p">.</span>
    <span class="nv">email</span> <span class="nf">ifEmpty:</span> [ <span class="nv">errors</span> <span class="o">:=</span> <span class="nv">errors</span><span class="nf">,</span> <span class="s">'The email must not be empty because you need to login in the system'</span><span class="nf">,</span> <span class="nc">String</span> <span class="nf">cr</span> ]<span class="p">.</span>
    (<span class="nc">PnUtils</span> <span class="nf">checkEmail:</span> <span class="nv">email</span>) <span class="nb">ifFalse:</span> [ <span class="nv">errors</span> <span class="o">:=</span> <span class="nv">errors</span><span class="nf">,</span> <span class="s">'This doesn''t look like a real email to me'</span><span class="nf">,</span> <span class="nc">String</span> <span class="nf">cr</span> ]<span class="p">.</span>
    <span class="nv">name</span> <span class="nf">ifEmpty:</span> [ <span class="nv">errors</span> <span class="o">:=</span> <span class="nv">errors</span><span class="nf">,</span> <span class="s">'The name is a required field'</span><span class="nf">,</span> <span class="nc">String</span> <span class="nf">cr</span> ]<span class="p">.</span>
    <span class="nv">surname</span> <span class="nf">ifEmpty:</span> [ <span class="nv">errors</span> <span class="o">:=</span> <span class="nv">errors</span><span class="nf">,</span> <span class="s">'The surname is a required field'</span><span class="nf">,</span> <span class="nc">String</span> <span class="nf">cr</span> ]<span class="p">.</span>
    (<span class="nv">password</span><span class="nf">,</span> <span class="nv">password2</span>) <span class="nf">ifEmpty:</span> [ <span class="nv">errors</span> <span class="o">:=</span> <span class="nv">errors</span><span class="nf">,</span> <span class="s">'You must enter a password'</span><span class="nf">,</span> <span class="nc">String</span> <span class="nf">cr</span> ]<span class="p">.</span>
    (<span class="nv">password</span> <span class="nf">=</span> <span class="nv">password2</span>) <span class="nb">ifFalse:</span> [ <span class="nv">errors</span> <span class="o">:=</span> <span class="nv">errors</span><span class="nf">,</span> <span class="s">'The password are not matching'</span><span class="nf">,</span> <span class="nc">String</span> <span class="nf">cr</span> ]<span class="p">.</span>
    <span class="k">! !</span>

As you see I only fill the errors instance variable with the error message and the row building methods will do the rest.

Now the registration action, that is more interesting:

<span class="k">!</span><span class="nc">PnCreateUser</span><span class="k"> methodsFor: </span><span class="s">'actions'</span><span class="k">!</span>
<span class="nf">registerAction</span>
    <span class="o">|</span><span class="nv"> u </span><span class="o">|</span>
    <span class="bp">self</span> <span class="nf">markDirty</span><span class="p">;</span> <span class="nf">checkErrors</span><span class="p">.</span>
    <span class="nv">errors</span> <span class="nf">ifNotEmpty:</span> [ <span class="o">^</span> <span class="bp">self</span><span class="p">.</span> ]<span class="p">.</span>

    <span class="nv">u</span> <span class="o">:=</span> <span class="nc">PnUser</span> <span class="nb">new</span> <span class="nf">realname:</span><span class="nv">name</span><span class="p">;</span> <span class="nf">surname:</span> <span class="nv">surname</span><span class="p">;</span> <span class="nf">email:</span> <span class="nv">email</span><span class="p">;</span> <span class="nf">password:</span> <span class="nv">password</span><span class="p">.</span>
    <span class="nc">PnUserDAO</span> <span class="nf">current</span> <span class="nf">register:</span><span class="nv">u</span><span class="p">.</span>
    <span class="bp">self</span> <span class="nf">show:</span>(<span class="nc">ILInformationWidget</span> <span class="nb">new</span> <span class="nf">informationString:</span> <span class="s">'We created an user for you. Click ok to go to the app.'</span>)
        <span class="nf">onAnswer:</span> [ <span class="o">:</span> <span class="nv">e</span> <span class="o">|</span> <span class="bp">self</span> <span class="nf">redirectToLocal:</span> <span class="s">'notes'</span> ]<span class="p">.</span><span class="k">! !</span>

The interesting bits are in the DAO usage, that “persist” the PnUser object, and the show:onAnswer: method.

The show:onAnswer: method of the ILWidget class can handle the control flow for you. In the next page rendering process the invoking widget will be substituted with the passed widget, in this case ILInformationWidget. When the shown widget (ILInformationWidget) will call the answer method the control flow will return to the block passed to show:onAnswer:.

This block redirect the browser to the notes controller, which will handle the notes creation and visualization proces.