Sunday, August 6, 2017

Add log-in feature to the website (or webapp)

CakePHP
1. Setting up CakePHP3 with CentOS

2. Bake and Migration

3. Add log-in feature to the website

4. Add a calendar page

5. Use "contain"

6. Use find('list')

Add some other features to CakePHP webpage


Please see here for the related cookbook page.
We added a page in the last post. The page was like this:


Click "New Product" from the side menu.

You will see this. Write something is the "Name" and "Description" and click "Submit".



You will see that the product data was added on the table. From the "Actions" column, you can do some other actions like "view (the detail)", "Edit" and "Delete".

Make a table in database


We will create a log-in feature now.
At first, we need a new table in the database to store users' information. Open your tera-term (or some other console that you are using to connect to the virtual machine) and run these commands:
$ bin/cake bake migration CreateUsers username:string password:string role:string created modified
$ bin/cake migrations migrate

And check if the table was added for sure:
$ mysql -u root -proot
mysql> use test
mysql> SHOW TABLES;    
If you can see "users" in the table list, that means you successfully did it.

Now exit from mysql.


mysql> exit

bake controller, model and view for user


At first, we will bake:
$ bin/cake bake all users

Then new page will be created here: http://192.168.33.10/cake/users
The page name will be decided automatically and the page name is always same as the table name. The table name is "users", so the page name is also users.

New page would look like this:


Add a new user from the side.


I will use "test" for the username, the password and the role. If you finish inputting them, click "Submit".


The user was added:



Now we will implement the log-in feature. Open UsersTable.php. The directory should be something like this:
C:\MyVM\MyCentOS\cake\src\Model\Table\UsersTable.php


You will find a validationDefault method. This is used to define default validation that is used to validate input information when adding a new user.

Change it like this:
    public function validationDefault(Validator $validator)
    {
        return $validator
            ->notEmpty('username', 'A username is required')
            ->notEmpty('password', 'A password is required')
            ->notEmpty('role', 'A role is required');
    }

Save and close it. Now all of "username", "password" and "role" inputs are required to fill when you register a user. Therefore they can't be empty when you submit the information.

Now open UsersController.php. The directory should be something like this:
C:\MyVM\MyCentOS\cake\src\Controller\UsersController.php

Open the UsersController.php and add this line under "use App\Controller\AppController;":
use Cake\Event\Event;

And add the following under "class UsersController extends AppController{":
    public function beforeFilter(Event $event)
    {
        parent::beforeFilter($event);
        // Allow users to register and logout.
        // You should not add the "login" action to allow list. Doing so would
        // cause problems with normal functioning of AuthComponent.
        $this->Auth->allow(['add', 'logout']);
    }

    public function login()
    {
        if ($this->request->is('post')) {
            $user = $this->Auth->identify();
            if ($user) {
                $this->Auth->setUser($user);
                return $this->redirect($this->Auth->redirectUrl());
            }
            $this->Flash->error(__('Invalid username or password, try again'));
        }
    }

    public function logout()
    {
        return $this->redirect($this->Auth->logout());
    }

It would look like this:

Save and close it.
Now open AppController.php. The directory should be something like this:
C:\MyVM\MyCentOS\cake\src\Controller

Change the initialize method in AppController.php:
    public function initialize()
    {
        $this->loadComponent('Flash');
        $this->loadComponent('Auth', [
            'loginRedirect' => [
                'controller' => 'Products', //After logging in, you will be redirected to here.
                'action' => 'index'
            ],
            'logoutRedirect' => [
                'controller' => 'Pages', //After logging out, you will be redirected to here.
                'action' => 'display',
                'home'
            ]
        ]);
    }

If you want to allow users to access some pages without login, you can make a "white list" this way:
    public function beforeFilter(Event $event)
    {
        //These index, view, display actions of each controller will be executed without login.
        $this->Auth->allow(['index', 'view', 'display']); 
    }
But we don't use this white list feature here.

It would look like this:

Save and close it.

Open Model/Entity/User.php to add a function to hash the password.
Add this line to use DefaultPasswordHasher.
use Cake\Auth\DefaultPasswordHasher;

Add this function at the end of the User class:
    protected function _setPassword($password)
    {
        if (strlen($password) > 0) {
            return (new DefaultPasswordHasher)->hash($password);
        }
    }

It would look like this:




We will add a view for the login page. Open Users folder in Template. The directory should be something like this:
C:\MyVM\MyCentOS\cake\src\Template\Users

Then add a .txt file.

Change the file to "login.ctp". (To do so, just rename the file along with the file extension.)

Open the login.ctp, and copy and paste the following into the file:
<!-- File: src/Template/Users/login.ctp -->

<div class="users form">
<?= $this->Flash->render() ?>
<?= $this->Form->create() ?>
    <fieldset>
        <legend><?= __('Please enter your username and password') ?></legend>
        <?= $this->Form->control('username') ?>
        <?= $this->Form->control('password') ?>
    </fieldset>
<?= $this->Form->button(__('Login')); ?>
<?= $this->Form->end() ?>
</div>

Save and close it.

Login test


Now access the cakephp from your browser: http://192.168.33.10/cake/products
You will be required to login to access the page.

The test account which we created before implementing the login feature can't be used because the password in the database is not hashed. Create a new user in http://192.168.33.10/cake/users/add.
The directory "cake/users/add" can be accessed without login because we allowed users to access the page and it is written in UsersController.php.

Create a new account like "test2" as shown below. You can login with this new account.



To logout, access http://192.168.33.10/cake/users/logout.

You can see a new user is added. By the way, you can customize this page by customizing "index.ctp" in Template folder.

The directory should be something like this:
C:\MyVM\MyCentOS\cake\src\Template\Users\index.ctp

But when you logout, the warning says "You are not authorized to see that location" because we didn't allow users to see the home.ctp. Now we will authorize users to see home.ctp.

Open "PagesController.php". The directory should be something like this:
C:\MyVM\MyCentOS\cake\src\Controller\PagesController.php

Then add this line to use Event class:
use Cake\Event\Event;

Add this function to the class.
    public function beforeFilter(Event $event)
    {
        parent::beforeFilter($event);
        $this->Auth->allow(['action' => 'display', 'home']);
    }

It would look like this:

Save and close it.

Now you can see you will be redirected to the home.ctp after logging out.

home.ctp

You can customize the Products pages and the Users pages by customizing ctp files in Template folder.

Open these files...

...to edit the view.