Skip to content

Getting Start With Pi

linzongshu edited this page Feb 22, 2013 · 2 revisions

This tutorial is intended to give an introduction to using Pi to develop a module with functions of user registration and login. We will show you how to create a Pi module, how to create a form and insert user information into database. At the end of the tutorial user identity authentication will also be introduced.

Configuring Development Environment

This tutorial assumes that you are running PHP 5.3 or higher with the Apache web server and MySQL, it also known as Win/Linux+Apache+MySQL+PHP. Meanwhile, a php_apc.dll extension is also required. We suggest you to install the WAMP integrated installation package. The WAMP and APC download page are show as follows:

WAMP:          http://www.wampserver.com/en/
APC extension dll: http://downloads.php.net/pierre/

If your WAMP is running in WinXP system, we suggest you to download apc extension for WinXP.

APC for WinXP: http://belsky.info/uploads/my/bugz/61984/php_apc-3.1.10-5.3-vc9-x86-xp.zip

When the wamp is installed (we install it in the d disk of win system, and php version is 5.3.13), then the php_apc.dll extension should be copy to the D:\wamp\bin\php\php5.3.13\ext folder. Then you must check the 'php_apc' menu in Wampserver to enable APC.

Moreover, your Apache installation must have the mod_rewrite extension installed and configured.

NOTE:

  1. The version of APC must be the same as that of PHP, or else you will fail to configure APC extension.

  2. The current available APC do not support 64 OS, you should configure your installation to 32 OS.

Acquired Pi source code

Pi group use SVN to management Pi source code, the code repository url is:

http://svn.xoopsengine.org/branches/Pi/

So we need to download a svn software to acquired it. The download url is:

http://subversion.apache.org/download/#recommended-release

After installed subversion, right click button in wamp/www folder, and choose the check out button, a checkout dialog will pop up. after enter the repository url, then the software will help you to download source code automatically.

Installing Pi

Put your installation package into the www directory after download it. Before install Pi you should create a database and configure its permission. Then you can start to install Pi.

The Pi installation page can be accessed using

localhost/Pi/www/setup/, the page is like this:

If you've configure development environment right, you will see a green check mark after 'Server setting detection' string. Then you can click 'Next' button and you'll see the following page:

Make sure path settings are right, and there is green mark after 'Persistent data container'.

Connection information of database is configured in this step, the database name is the database you create previous.

This step allowed you to create your administrator account to log in Pi's Admin Area. If you have installed successful, you'll see the page like this.

Now you can click 'your site' or browser localhost/Pi/www to visit Pi. You will see:

The Tutorial Application

The application we want to build is user registration and log in. These include form validation, form process, add user into database and user identity authentication. Here we use IndexController to achieve user log in, log in process and log out, RegisterController is used to achieve user registration.

Controller List page Description
IndexController Login This page will display a series of form for user to log in
Login success This page will display log in success information
Logout This page will display details when user log out
RegisterController Registration This page will display a series of form for user to register
Registration success This page will display user registration information when registered

A database is also needed to store user information. Only one table is needed and its fields are list as follows:

Field name Type Null Notes
id integer No Primary key, auto-increment
username varchar(32) No
password varchar(255) No
gender ENUM('male', 'female') No Default 'male'
email varchar(255) No
country varchar(32) No Default 'CHN'
message text No
photo varchar(255) No

Setting Up a Log in Modules

In this tutorial, I use 'login' as the name of the module. First, you should to create a login folder including several files under the usr/module folder, which is like this:

usr/
/module
    /login
        /asset
            /image
        /config
        /sql
        /src
            /Controller
                Front
            /Form
        /template
            /front

The function of these folders is:

Folders Function
asset This folder will be used to store js, css and images
config This folder will be used to store configure files
sql This folder includes sql file that is used to create tables
src/Controller/Front This folder includes controller files of front section
src/Form This folder includes files used to create, filter and validate form
template/front This folder includes .phtml files used to display HTML tags

Configurating Modules

Configure files allow user to define module navigation, route rules and basic information of the module, etc. Here we only configure navigation for our log in module. Create a module.php file under config folder, and add following codes:

module/login/config/module.php
<?php
return array(
    'meta'  => array(
        'title'         => 'Login Demo',
        'description'   => 'Examples and tests for developers.',
        'version'      => '1.0.0',
        'license'      => 'New BSD',
        'logo'        => 'image/logo.png',
        'readme'      => 'docs/readme.txt',
        'demo'        => 'http://demo.Pi.org/demo'
    ),
    'author'    => array(
        'name'      => 'your name',
        'email'      => 'your email',
        'website'    => 'website to provide this module',
        'credits'     => 'your team.'
    ),
    'maintenance'   => array(
        'resource'  => array(
            'database'  => array(
                'sqlfile'   => 'sql/mysql.sql',
                'schema'  => array(
                    'userinfo'          => 'table',
                ),
            ),
            'navigation'    => 'navigation.php',
        )
    )
);

This array includes three parts: basic module information, author information and configure file needed. Basic module information is described by meta array, fields of title, version and license are required, and fields of description, logo, readme and demo are optional.

Author information is described by 'author' array which includes fields of name, email, website and credits. Among these fields, name field is required, and the others are optional.

The configuration information is main described by maintenance array which contains a resource array. In this array, each configure file name is assign to a special field, for example,if you want to add a configure file to define the navigation of module, you can add a field such as 'navigation' => 'navigation.php'. File used to create database is defined in database array in resource array. The database array include sqlfile and schema two fields. sqlfile field describes the file name of SQL schema or data and schema field describes tables to be removed during uninstall.

Note:

The schema field is optional; in this field, name of key is table name, and value should be table. In our tutorial, we add a navigation field, and assign navigation.php to it. So we need to create a navigation.php file to configure module's navigation.

module/login/config/navigation.php
<?php
return array(
);

These codes tell Pi that there is no sub navigation of this module, and the main navigation will be set to default, which is IndexCotroller/indexAction. If you want to add a sub navigation, add following codes to the array:

return array(
    'front'   => array(
        'pagea'     => array(
            'label'         => __('No template'),
            'route'         => 'default',
            'controller'     => 'index',
            'action'        => 'index',
        ),
    ),
); 

You can also add an admin field if you want to create a sub navigation for administration section.

Creating Tables for Module

In the previous section, we have introduced the configuration of sql file, Pi will automatically search this file and executes its code to create tables for us. So the only thing we need to do is create a sql file in the sql folder and add codes to create table and its fields:

module/login/sql/mysql.sql
CREATE TABLE `{userinfo}` (
  `id`       int(10) unsigned         NOT NULL auto_increment,
  `username` varchar(32)              NOT NULL default '',
  `password` varchar(255)             NOT NULL default '',
  `gender`   ENUM('male', 'female')   NOT NULL default 'male',
  `email`    varchar(255)             NOT NULL default '',
  `country`  varchar(32)              NOT NULL default 'CHN',
  `message`  text,
  `photo`    varchar(255),

  PRIMARY KEY  (`id`)
);

**NOTE: **

All table names here must be quoted with { and }, and all system tables must be prefixed with core.

Creating Controller

We have all needed file prepared so far, now I will introduce you how to create a controller for user to log in. In the application function section, we have know that there are 5 pages to used, we will group them in two controllers as five actions. They will be:

Page Controller Action
Home/login IndexController index
Login success IndexController Will used in process
Logout IndexController logout
Register RegisterController index
Register success RegisterController Will used in process

Creating Forms for Log in

In order to create forms, we should create a file to add form attributes, this mechanism is refer to Zend Framework 2. So we should to create a Form folder and add the follow codes:

module/login/src/Controller/Form/LoginForm.php
<?php
namespace Module\Login\Form;

use Pi;
use Pi\Form\Form as BaseForm;
use Zend\Form\Form;
use Zend\Form\Element;

class LoginForm extends BaseForm
{
    public function init()
    {
        $this->add(array(
            'name'          => 'username',
            'attributes'    => array(
                'value' => 'root',
                'type'  => 'text',               
            ),
            'options' => array(
                'label' => __('Username'),
            ),
        ));

        $this->add(array(
            'name'          => 'password',
            'attributes'    => array(
                'type'  => 'password',
                'value' => '123456',                
            ),
            'options' => array(
                'label' => __('Password'),
            ),
        ));
        
        $this->add(array(
            'name'          => 'captcha',
            'type'          => 'captcha',
            'options'    => array(
                'label' => __('Input following letters '),
            ),
        ));

        $this->add(array(
            'name'          => 'submit',
            'attributes'    => array(
                'type'  => 'submit',
                'value' => 'Login',
            )
        ));
    }
}

You can assign different value for the type field in the code to create different form. Now we can instantiate this object in the controller file and display forms in the phtml file. You should to create a IndexController.php file in the Controller folder and add the following codes:

module/login/src/Controller/Front/IndexController.php
<?php
namespace Module\Login\Controller\Front;

use Pi\Mvc\Controller\ActionController;
use Module\Login\Form\LoginForm;
use Pi;

class IndexController extends ActionController
{    
    public function indexAction()
    {	
        $form = $this->getForm();
        $this->renderForm($form);
    }

    protected function renderForm($form)
    {
        $this->view()->setTemplate('login');
        $this->view()->assign('title', 'Please login');
        $this->view()->assign('form', $form);
    }

    protected function getForm()
    {
        $form = new loginForm('login');
        $form->setAttribute('action', $this->url('', array('action' => 'process')));

        return $form;
    }
}

In the code,we set the template name to login, so we should create a login.phtml file that include HTML tags in the template folder for displaying forms.

module/login/template/front/login.phtml
<h2><?php echo $title; ?></h2>

<?php echo $this->form()->openTag($form); ?>

<div id='username'>
<?php $element = $form->get('username'); ?>
    <div><?php echo $this->formLabel($element); ?></div>
    <div><?php
        echo $this->formInput($element); 
        echo $this->formElementErrors($element);
    ?></div>
</div>

<div id='password'>
<?php $element = $form->get('password'); ?>
    <div><?php echo $this->formLabel($element); ?></div>
    <div><?php
        echo $this->formPassword($element); 
        echo $this->formElementErrors($element);
    ?></div>
</div>

<div id='captcha'>
<?php $element = $form->get('captcha'); ?>
    <div><?php echo $this->formLabel($element); ?></div>
    <div><?php
        echo $this->formCaptcha($element); 
        echo $this->formElementErrors($element);
    ?></div>
</div>

<div id='submit'>
<?php $element = $form->get('submit'); ?>
    <div><?php 
        echo $this->formSubmit($element); 
        echo $this->formElementErrors($element);
    ?></div>
</div>

<?php echo $this->form()->closeTag(); ?>

So far, you have created a login page which include two text form, a captcha form and a submit form. But the only thing you can do is display it, if you click submit button, nothing will happen. Therefore, we should create a processing page to deal with the submit data. The login page is show as follows:

Processing Login Data

At the moment, we only introduce how to filter and validate submit data, we will introduce the user identity authentication base on database. Now let's create a LoginFilter.php in the Form folder and add:

module/login/src/Form/LoginFilter.php
<?php
namespace Module\Login\Form;

use Pi;
use Zend\InputFilter\InputFilter;
use Zend\Validator\StringLength;
use Zend\Validator\File;

class LoginFilter extends InputFilter
{
    public function __construct()
    {
        $this->add(array(
            'name'        => 'username',
            'required'      => true,
            'filters'        => array(
                array(
                    'name'        => 'StringTrim',
                ),
            ),
            'validators'    => array(
                array(
                    'name'         => 'Regex',
                    'options'      => array(
                        'pattern'       => '/^[a-zA-Z0-9][a-zA-Z0-9-_]{0,24}$/',
                    ), 
                ),
                new StringLength(array(
                    'min'          => '4',
                    'max'          => '25',
                )),
            ),
        ));
        
        $this->add(array(
            'name'          => 'password',
            'required'      => true,
            'filters'       => array(
                array(
                    'name'         => 'StringTrim',
                ),
            ),
            'validators'    => array(
                array(
                    'name'         => 'StringLength',
                    'options'      => array(
                        'min'           => '6',
                        'max'           => '20',
                    ),
                ),
            ),
        ));
    }
}

Then we should create a processAction to deal with the data, because we have set the form action to process in the getForm function. Open the IndexController.php and add a processAction function:

module/login/src/Controller/Front/IndexController.php
<?php
...
use Module\Login\Form\LoginFilter;
...
class IndexController extends ActionController
{
    ...
    public function processAction()
    {
        if(!$this->request->isPost())
            return $this->redirect()->toRoute('', array('action' => 'index'));
    
        $post = $this->request->getPost();
        $form = $this->getForm();
        $form->setData($post);
        $form->setInputFilter(new LoginFilter);
        if(!$form->isValid()) {
            $this->view()->assign('error', __('Invalid input, please try again.'));
            $this->renderForm($form);   
            return;
        }
        $values = $form->getData(); 
    
        $this->view()->setTemplate('login-success');
        $this->view()->assign('info', $values);
    }
    ...
}

According to the code, a login page will be used if data are invalid, or else it will turn to login-success page. So we should display error message in login page, and create a login-success page:

module/login/template/front/login.phtml
<h2><?php echo $title; ?></h2>

<?php if('' !== $error) {
    echo $error;
}
?>

<?php $this->registerForm(); ?>
...

module/login/template/front/login-success.phtml
<?php
$logoutUrl = $this->url('', array('controller' => 'index', 'action' => 'logout'));
$logoutString = sprintf('<a href="%s" title="%s">%s</a>', $logoutUrl, __('logout'), __('logout'));
echo sprintf(__('Welcome %s, you can click %s to logout.'), $info['username'], $logoutString);
?>

The page is:

User Identity Authentication

So far we have two page to deal with user data posted. But current pages nether identify a user nor store username into session. Therefore, we need to add follow codes:

module/login/src/front/IndexController.php
<?php
...
use Zend\Authentication\Adapter\DbTable;
use Zend\Authentication\AuthenticationService;
...
class IndexController extends ActionController
{
    protected $auth = null;

    public function indexAction()
    {
        $auth = $this->getAuthenticate();
        if ($auth->hasIdentity()) {
            $identity = $auth->getIdentity();
            $this->view()->setTemplate('login-success');
            $this->view()->assign('info', array('username' => $identity));
            return;
        }

        $form = $this->getForm();
        $this->renderForm($form);
    }

    public function processAction()
    {
        ....
        $values = $form->getData();
    
        if (!$this->authenticate($values['username'], $values['password'])) {
            $this->view()->assign('error', __('Invalid credentials provided, please try again.'));
            $this->renderForm($form);
            return;
        }
        ...
    }

    public function authenticate($identity, $credential)
    {
        $options = Pi::config()->load('service.database.php');
        $adapter = new \Zend\Db\Adapter\Adapter($options['connection']);
        $authAdapter = new DbTable($adapter, $options['table_prefix'] . 'login_userinfo', 'username', 'password');
        $authAdapter->setIdentity($identity)->setCredential($credential);
    
        $auth = $this->getAuthenticate();
	$result = $auth->authenticate($authAdapter);
        if (!$result->isValid()) {
            return false;
        }
       
        return true;
    }

    public function getAuthenticate()
    {
        if (null === $this->auth) {
            $this->auth = new AuthenticationService();
        }
        return $this->auth;
    }
}

Login page with wrong input is:

Logout Action

Final thing to do is add a logout page, we need to add a logoutAction to realize the function:

module/login/src/front/IndexController.php
<?php
...
class IndexController extends ActionController
{
    ....
    public function logoutAction()
    {
        $auth = $this->getAuthenticate();
        $auth->clearIdentity();
    
        $this->view()->setTemplate('logout-success');
        $this->view()->assign('logout', true);
    }
    ...
}

module/login/template/front/logout-success.php
<div><?php
$loginUrl = $this->url('', array('controller' => 'index', 'action' => 'index'));
$loginString = sprintf('<a href="%s" title="%s">%s</a>', $loginUrl, __('login'), __('login'));
echo sprintf(__('You can click %s to login.'), $loginString);
?></div>

Register Controller

In this section, we will introduce how to create a register page, which include function of operating database, creating different types of forms and validating upload file. Firstly, we should create a form file for display just as we do in the login controller section. Open the Form folder and create a RegisterForm.php:

module/login/src/Form/RegisterForm.php
<?php
namespace Module\Login\Form;

use Pi;
use Pi\Form\Form as BaseForm;
use Zend\Form\Form;
use Zend\Form\Element;

class RegisterForm extends BaseForm
{
    public function init()
    {
        $this->add(array(
            'name'          => 'username',
            'attributes'    => array(
                'value' => 'root',
                'type'  => 'text',
            ),
            'options'       => array(
                'label' => __('Username'),
            ),
        ));

        $this->add(array(
            'name'          => 'password',
            'attributes'    => array(
                'type'  => 'password',
                'value' => '123456',
            ),
            'options'       => array(
                'label' => __('Password'),
            ),
        ));

        $this->add(array(
            'name'          => 'gender',
            'attributes'    => array(
                'value'    => 'male',
                'options'  => array(
                    'male'   => __('Male'),
                    'female'  => __('Female'),
                ),
            ),
            'options'       => array(
                'label' => __('Gender'),
            ),
            'type'  => 'radio',
        ));

        $this->add(array(
            'name'          => 'upload',
            'attributes'    => array(
                'type'  => 'file',
            ),
            'options'       => array(
                'label' => __('Upload'),
            ),
        ));

        $this->add(array(
            'name'         => 'country',
            'attributes'   => array(
                'type'  => 'select',
                'options' => array(
                    'China' => 'CHN',
                    'United States'=> 'USA',
                ),
            ),
            'options'      => array(
                'label' => 'Your country',
            ),
        ));
        
        $this->add(array(
            'name'          => 'email',
            'attributes'    => array(
                'type'  => 'text',
                'value' => '[email protected]',
            ),
            'options'       => array(
                'label' => __('Email'),
            ),
        ));

        $this->add(array(
            'name'          => 'message',
            'attributes'    => array(
                'type'  => 'textarea',
                'cols'  => '50',
                'rows'  => '10',
                'value' => 'Please note whatever you want!',
            ),
            'options'       => array(
                'label' => __('Your details'),
            ),
        ));
        
        $this->add(array(
            'name'          => 'captcha',
            'type'          => 'captcha',
            'attributes'    => array(
            ),
        ));

        $this->add(array(
            'name'          => 'submit',
            'attributes'    => array(
                'type'  => 'submit',
                'value' => 'Register',
            )
        ));
    }
}

Now we need to create a RegisterController to process form class. Create a RegisterController.php in the Controller/Front folder, and add:

module/login/src/Controller/Front/RegisterController.php
<?php
namespace Module\Login\Controller\Front;

use Pi\Mvc\Controller\ActionController;
use Module\Login\Form\RegisterForm;
use Pi;

class RegisterController extends ActionController
{
    public function indexAction()
    {	
        $form = $this->getForm();
        $this->renderForm($form);
    }

    protected function renderForm($form)
    {
        $this->view()->setTemplate('register');
        $this->view()->assign('title', 'Please register your information');
        $this->view()->assign('form', $form);
    }

    public function getForm()
    {
        $form = new RegisterForm('register');
        $form->setAttribute('action', $this->url('', array('action' => 'process')));
        $form->setAttribute('enctype', 'multipart/form-data');

        return $form;
    }
}

Create a register.phtml file in the template/front folder, then you can display the forms:

module/login/template/front/register.phtml
<h2><?php echo $title; ?></h2>

<?php echo $this->form()->openTag($form); ?>

<div id='username'>
<?php $element = $form->get('username'); ?>
    <div><?php echo $this->formLabel($element); ?></div>
    <div><?php
        echo $this->formInput($element); 
        echo $this->formElementErrors($element);
    ?></div>
</div>

<div id='password'>
<?php $element = $form->get('password'); ?>
    <div><?php echo $this->formLabel($element); ?></div>
    <div><?php
        echo $this->formPassword($element); 
        echo $this->formElementErrors($element);
    ?></div>
</div>

<div id='male'>
<?php $element = $form->get('gender'); ?>
    <div><?php echo $this->formLabel($element); ?></div>
    <div><?php
        echo $this->formRadio($element);
        echo $this->formElementErrors($element);
    ?></div>
</div>

<div id='email'>
<?php $element = $form->get('email'); ?>
    <div><?php echo $this->formLabel($element); ?></div>
    <div><?php
        echo $this->formInput($element); 
        echo $this->formElementErrors($element);
    ?></div>
</div>

<div id='country'>
<?php $element = $form->get('country'); ?>
    <div><?php echo $this->formLabel($element); ?></div>
    <div><?php 
        echo $this->formSelect($element);
        echo $this->formElementErrors($element);
    ?></div>
</div>

<div id='message'>
<?php $element = $form->get('message'); ?>
    <div><?php echo $this->formLabel($element); ?></div>
    <div><?php
        echo $this->formTextarea($element); 
        echo $this->formElementErrors($element);
    ?></div>
</div>

<div id='upload'>
<?php $element = $form->get('upload'); ?>
    <div><?php echo $this->formLabel($element); ?></div>
    <div><?php
        echo $this->formFile($element); 
        //echo $this->formElementErrors($element);
        if($messages){
            echo $messages; 
        }
    ?></div>
</div>

<div id='captcha'>
<?php $element = $form->get('captcha'); ?>
    <div><?php
        echo $this->formCaptcha($element); 
        echo $this->formElementErrors($element);
    ?></div>
</div>

<div id='submit'>
<?php $element = $form->get('submit'); ?>
    <div><?php 
        echo $this->formSubmit($element); 
        echo $this->formElementErrors($element);
    ?></div>
</div>

<?php echo $this->form()->closeTag(); ?>

You can notice that, we use different APIs to display form accord to their types. You can also use formInput to display a submit form, but it will work wrong if you use this API to display a group of radios. The register page is:

Data Validation

As same as the login section, a filter file is needed for submit data validation.

module/login/src/Form/RegisterFilter.php
<?php
namespace Module\Login\Form;

use Pi;
use Zend\InputFilter\InputFilter;
use Zend\Validator\StringLength;
use Zend\Validator\File;

class RegisterFilter extends InputFilter
{
    public function __construct()
    {
        $this->add(array(
            'name'        => 'username',
            'required'      => true,
            'filters'       => array(
                array(
                    'name'        => 'StringTrim',
                ),
            ),
            'validators'    => array(
                array(
                    'name'         => 'Regex',
                    'options'      => array(
                        'pattern'       => '/^[a-zA-Z0-9][a-zA-Z0-9-_]{0,24}$/',
                    ), 
                ),
                new StringLength(array(
                    'min'          => '4',
                    'max'          => '25',
                )),
            ),
        ));
        
        $this->add(array(
            'name'          => 'password',
            'required'      => true,
            'filters'       => array(
                array(
                    'name'         => 'StringTrim',
                ),
            ),
            'validators'    => array(
                array(
                    'name'         => 'StringLength',
                    'options'      => array(
                        'min'           => '6',
                        'max'           => '20',
                    ),
                ),
            ),
        ));
        
        $this->add(array(
            'name'         => 'gender',
            'required'     => true,
        ));

        $this->add(array(
            'name'          => 'email',
            'required'      => true,
            'filters'       => array(
                array(
                    'name'  => 'StringTrim',
                ),
            ),
            'validators'    => array(
                array(
                    'name'      => 'EmailAddress',
                    'options'   => array(
                        'useDomainCheck'    => true,
                    ),
                ),
            ),
        ));
        
        $this->add(array(
            'name'          => 'country',
            'required'      => true,
        ));

        $this->add(array(
            'name'          => 'message',
            'required'      => true,
            'filters'       => array(
                array(
                    'name'      => 'StringTrim',
                ),
            ),
        ));
    }
}

There is a validate named Regex in the code, if you want to add another validate, you should create the object.

Register Data Process

This section has something different to login data process, we need to validate upload file, check whether the username is exist and finally insert data into database. Add following code into the RegisterController.php:

module/login/src/Controller/RegisterController.php
<?php
...
use Module\Login\Form\RegisterFilter;
use Pi;

class RegisterController extends ActionController
{
    ...
    public function processAction()
    {
        if(!$this->request->isPost())
            return $this->redirect()->toRoute('', array('action' => 'index'));
        
        $post = $this->request->getPost();
        $form = $this->getForm();
        
        $form->setData($post);
        $form->setInputFilter(new RegisterFilter);
        if(!$form->isValid()) {
            $this->view()->assign('error', __('Invalid input, please try again.'));
            $this->renderForm($form);   
            return;
        }
        $values = $form->getData();
        
        $this->view()->setTemplate('register-success');
        $this->view()->assign('info', $values);
}
}

module/login/template/front/register-success.phtml
<?php 
    echo "<h2>This is your register Infomation</h2>";
        
    echo "<p>Username: " . $info['username'] . "</p>";
    echo "<p>Gender: " . $info['gender'] . "</p>";
    echo "<p>Email: " . $info['email'] . "</p>";
    echo "<p>Country: " . $info['country'] . "</p>";
    echo "<p>Message: " . $info['message'] . "</p>";
?>
<div><img src="<?php echo $info['upload']; ?>" /></div>

Additional task is to validate the upload file, because we did not set the filter and validator in the filter file. So we should create a uploadValidator function and call it in the processAction:

module/login/src/Controller/RegisterController.php

....
protected $adapter = null;

public function uploadValidator()
{
    $destination = Pi::path('module') . "/login/asset/file";
    
    $adapter = $this->getAdapter();
    $adapter->setDestination($destination);
    $adapter->addValidator('Count', false, 1);
    $adapter->addValidator('Size', false, 204800);
    $adapter->addValidator('Extension', false, 'jpg,png,gif');
    
    $messages = null;
    if(!$adapter->receive()){
        $message_list = $adapter->getMessages();
        foreach($message_list as $tmp){
            $messages .= $tmp . "<br/>";
        }
    }

    return $messages;
}

public function processAction()
{
    ...
    $form->setInputFilter(new RegisterFilter);
    $messages = $this->uploadValidator();
    if(!$form->isValid() || $messages !== null) {
        $this->view()->assign('error', __('Invalid input, please try again.'));
        $this->view()->assign('messages', $messages);
        $this->renderForm($form);   
        return;
    }
    $values = $form->getData();
    $adapter = $this->getAdapter();
    $moduleUrl = preg_replace('/www/', '', Pi::url('www')) . 'usr/module';
    $values['upload'] = $moduleUrl . "/login/asset/file/" . basename($adapter->getFileName());
    ...
}

public function getAdapter()
{
    if(null === $this->adapter)
        $this->adapter = new \Zend\File\Transfer\Adapter\Http();
    
    return $this->adapter;
}

Database Operation

In the previous section, we have introduced creating table by sql file, Pi provides a series APIs for us to operate database, we can fetch or insert data conveniently by using these APIs. We still create two functions to insert and fetch data from userinfo table, and call these functions in the processAction.

module/login/src/Controller/RegisterController.php

public function writeIntoDb(array $value)
{
    $data = array(
        'username'       => $value['username'],
        'password'       => $value['password'],
        'gender'         => $value['gender'],
        'email'          => $value['email'],
        'country'        => $value['country'],
        'message'        => $value['message'],
        'photo'          => $value['upload'],
    );

    $row = Pi::model('login/userinfo')->createRow($data);
    $row->save();
    if(!$row->id) {
        return false;
    }
    
    return true;
}

public function checkUsername($username)
{
    $model = $this->getModel('userinfo');
    // Alternative
    $model = Pi::model('login/userinfo');
    
    $rowset = $model->select(array(
        'username' => $username,
    ));
    foreach($rowset as $row) {
        if($row['id']) {
            return false;
        }
    }
    
    return true;
}

public function processAction()
{
    ....
    $values = $form->getData();     
    $adapter = $this->getAdapter();
    $moduleUrl = preg_replace('/www/', '', Pi::url('www')) . 'usr/module';
    $values['upload'] = $moduleUrl . "/login/asset/file/" . basename($adapter->getFileName());
    
    if(!$this->checkUsername($values['username'])) {
        $this->view()->assign('error', __('Username has been register yet, please try again.'));
        $this->renderForm($form);
        return; 
    }
    
    if(!$this->writeIntoDb($values)) {
        $this->view()->assign('error', __('The account is not created in database, please try again.'));
        $this->renderForm($form);
        return;
    }

    $this->view()->setTemplate('preview');
    $this->view()->assign('info', $values);
}

Installing Module

So far we have finished the login module, but if you want to take the module into use, you first thing you need to do is install it. In this section we will introduce how to install a module in Pi. When you log in the admin Area and click the Module->Available menu, you will see the information of login module if you follow the steps as we introduced.

Click the Install link to install the module. And you will see the module installed when you return to front section.