Category: fat-free

Learning – Fat-Free PHP Framework (Bootstrap & Authentication)

Learning - Fat-Free PHP Framework (Bootstrap & Authentication)

Bootstrap & Authentication

Bootstrap

Front design, https://getbootstrap.com, includes CCS, Components, etc.

Getting start has examples, sign in page can be downloaded as well.

Bootstrap CDN - Content delivery network online

Content to be included

Include css into the head tag of the page

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">

Include the java script just before the closing of body tag

<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>

Create structure for login page

  • Create app/views/login.htm

  • Create app/models/User.php

  • Create app/controllers/UserController.php

  • Create app/css/signin.css or a static folder for this

  • Copy bootstrap login sample html to login.htm

  • Copy bootstrap login sample css to signin.css

Create page

  • Clean up login.htm

  • Create UserController.php

class UserController extends Controller {
    function render() {
        $template = new Template;

        echo $template->render('login.htm');
    }
}
  • Update routes.ini

Add

GET /login=UserController->render

The login page built as https://localhost:8088/login

Customize login page

Remove Remember me and change variable names, and name attribute for input fields

Authentication

Update routes.ini

Add following line

POST /authenticate=UserController->authenticate

Update form in login.htm

<form class="form-signin" method="POST" action="/authenticate">

Create table

Create table user with id, username, password.

Create password

$ php -a
echo password_hash('f3password', PASSWORD_DEFAULT);
$2y......

Add user and password

Add an user with username=f3user and the password=$2y......

Create model for user

Create User.php by modifying Messages.php

class User extends DB\SQL\Mapper {
    public function __construct(DB\SQL $db) {
        parent::__construct($db, 'user');
    }

    public function getByName() {
        $this->load(array('username=?', $name));
    }

    public function all() {
        $this->load();
        return $this->query;
    }

    ...

*Note: Function all() can be used to assign to a variable, getByName() is return the object itself.

Add authenticate function in UserController class

function authenticate() {
    $username = $this->f3->get('POST.username');
    $password = $this->f3->get('POST.password');

    $user = new User($this->db);
    $user->getByName($username);

    if ($user->dry()) {
        // echo 'User does not exist.';
        $this->f3->reroute('/login')
    }

    if (password_verify($password, $user->password)) {
        // echo 'password OK';
        $this->f3->reroute('/');
    }
    else {
        // echo 'password NOT OK';
        $this->f3->reroute('/login')
    }
}

Note: dry() is db function.

Create session

Look for Fat-Free Session Handler

  • Enable cache

Add following line in config.ini

CACHE=true
  • Update index.php
...
new Session();

$f3->run();
  • Add following line in function authenticate in UseController class
if (password_verify($password, $user->password)) {
    $this->f3->set('SESSION.user', $user->usename)'
    $this->f3->reroute('/');
}

Update function beforeroute in Controller class

function beforeroute() {
    if ($this->f3->get('SESSION.user') === null) {
        $this->f3->reroute('/login');
        exit;
    }
}

Update UserController class

Because this update is in Controller class, so every page will go thru the verification. To ignore this behavior for login.htm, update UserController class. Adding following empty function to overwrite beforeroute()

function beforeroute() {
}

References

Adding Bootstrap and User Authentication to Fatfree PHP MVC Project

Learning – Fat-Free PHP Framework (Template Hierarchy)

Learning - Fat-Free PHP Framework (Template Hierarchy)

Template Hierarchy

Copy from bootstrap

  • Go to https://getbootstrap.com/getting-started/#examples, select Dashboard.

  • Copy dashboard.htm to app/views/dashboard.htm

  • Copy dashboard.css into app/css/dashboard.css

  • Create app/views/header.htm

    • Move html header in dashboard.htm into header.htm
    • Delete unecessary javascript for IE8
    • Update bootstrap.min.css to CBN version
    • Update the path of dashboard.css
  • Create app/views/layout.htm

<include href="header.htm" />
<include href="{{ @view }}" />
  • Update MainController class
<?php

class MainController extends Controller {
    function render() {
        $this->f3->set(&#039;view&#039;, &#039;dashoboard.htm&#039;);
        $template = new Template;
        echo $template->render(&#039;layout.htm&#039;);
    }
}
  • Create nav.htm

Move the body contents before Dashboard div into file nav.htm

<body>
    ...
    ...
            <ui class="nav nav-sidebar">
                ...
            </ui>
        </div>

References

Template Hierarchy in Fat-Free PHP Framework Sample Project

Learning – Fat-Free PHP Framework – Posts List

Learning - Fat-Free PHP Framework - Posts List

This is the summary list of my posts during learning.

References

Learning - Fat-Free PHP Framework
Learning - Fat-Free PHP Framework (Bootstrap & Authentication)
Learning - Fat-Free PHP Framework (Template Hierarchy)
Learning - Fat-Free PHP Framework (Data Sets)

Learning – Fat-Free PHP Framework (Data Sets)

Learning - Fat-Free PHP Framework (Data Sets)

Data Sets

Do some RESTfull, serializable...

Display messages

  • Create Nav Sidebar Menu /messages
<li><a href="/messages">Messages on UI f3 template</a></li>
  • Update routes.ini

    Add following

GET /messages=MainController->displayMessages
  • Update MainController.php

    Add displayMessages in MainController class

class MainController extends Controller
{
    ...

    function displayMessages() {
        $messages = new Messages($this->db);

        $this->f3->set('messages', $messages-all());
        $this->f3->set('view', 'messages.htm');
        $template = new Template;
        echo $template->render('layout.htm');
    }
}
  • Create view messages.htm
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
    <h1 class="page-header">Messages UI from template</h1>

    <repeat group="{{ @messages }}" value="{{ @message }}">
        <p>{{ @message.id }} {{ @message.key }} {{ @message.message }}</p>
    </repeat>
</div>

Dipplay messages as JSON using AJAX call

  • Create Nav Sidebar Menu /api/messages
<li><a href="/api/messages">Messages JSON REST API</a></li>
  • Update routes.ini

    Add following

GET /api/messages=MainController->apiMessages
  • Update MainController.php

    Add displayMessages in MainController class

class MainController extends Controller
{
    ...

    function apiMessages() {
        $messages = new Messages($this->db);
        $data = $messages->all();

        $json = array();

        foreach ($data as $row)
            $items = array();

            foreach ($row as $key => $value) {
                $items[$key] = $value;
            }

            array_push($json, $items);
        }

        echo json_encode($json);
    }
}

Note: The echo json_encode($data); doesn't work, because $messages->all() from model has returned some non public attributes

*Note: As the output is the JSON data, no view need to be defined.

Display messsages using REST API

Create new display messages page utilizes the REST API.

  • Add menu in app/views/nav.htm
<li><a href="/messageajaxview">Message UI with AJAX</a></li>
  • Create route in routes.ini
GET /messageajaxview=MainController->displayMessagesAjaxView
  • Create function in app/controllers/MainController.php
function displayMessagesAjaxView() {
    $this->f3->set('view', 'messagesajax.htm');
    $template=new Template;
    echo $template->render('layout.htm');
}
  • Create template app/views/messageajx.htm
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
    <h1 class="page-header">Message UI with AJAX</h1>

    <button type="button" class="btn btn-default btn-lg">Fetch messages</button>

    <div id="msg-container"></div>
</div>
  • Create javascript file app/js/f3sample.js

  • Include jquery and javascript in app/views/header.htm

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script src="app/js/f3sample.js"></script>

Then the f3sample.js should be shown the resources in browser development tools.

References

Displaying data sets and creating a Rest API with the Fat-Free PHP Framework

Learning Fat-Free PHP Framework

Learning Fat-Free PHP Framework

Fat-Free PHP Framework is used to create MVC application.

Make Fat-Free work

Install composer

  • Go to https://getcomposer.org

  • Select Installation => Globally

  • Download installer and run it using php, then composer.phar is created

  • Move composer.phar to system directory

mv composer.phar /usr/local/bin/composer

Install Fat-Free

  • Create a new project folder

  • Init composer, and answer some questions, then composer.json is created

composer init
  • Go to http://getcomposer.org, select Browse Packages, then go to https://packagist.org.

  • Search fatfree to find out package name, bcosca/fatfree

  • Install bcosca/fatfree

    • by editing composer.json file

    Add following lines

      "require": {
        "bcosca/fatfree": 3.5.0
      }
    }

    Run composer update, to install fatfree in vendor directory, and composer.lock is created

    • by command
    composer require bcosca/fatfree

Autoload

There is an autoload.php file in vendor/composer directory, this is to load packages

In base.php

  • Singleton Base class extends from abstract class Prefab

  • $hive has all configuration, context

  • Function set is to set variables

  • Function get is to read variables

  • Function run needs to be called to make F3 work and running

Create index.html

require_once("vendor/autoload.php");

$f3 = Base::instance();

$f3->route('GET /',
  function() {
    echo 'Hello, world!';
  }
);

...

$f3->run();

Note, if don't use composer, then will be like

$f3 = require('path/to/base.php');
...
$f3->run();

Launch PHP server

php -S localhost:8088 -t .

Config, Controller, View

Set/get global variables

$f3->set('message', 'Hello, World!');

$f3->route('GET /',
  function($f3) {
    echo $f3->get('message');
  }
);

Create route class

class MainController {
  function render() {
    echo 'Hello, World!';
  }
}

$f3->route('GET /', 'MainController->render');

beforeroute and afterroute function

Mainly for session management

class Controller {
  function beforeroute() {
    echo 'before';
  }

  function afterroute() {
    echo 'after';
  }
}

class MainController extends Controller {

}

configuration variables

  • DEBUG

  • AUTOLAD - to load a folder which contains the classes

  • CACHE

  • UI - location of UI templates, separate folders using delimiter

$f3->set('DEBUG', 1);

Create config.ini

In config.ini file

[globals]

DEBUG=1
messagehello=Hello hello!

In index.php

$f3->config('config.ini');

class MainController extends Controller {
  function render($f3) {
    echo $f3->get('messagehello');
  }
}

Create routes.ini

In routes.ini

[routes]

GET /=MainController->render
GET /hello=MainController->sayhello
GET /about=AboutPage->render

In index.php

$f3->config('routes.ini');

Templates

In normal php

<p>Hello, <?php echo $name; ?>!</p>

In F3

<p>Hello, {{ @name }}!</p>

In index.php

  function render($f3) {
    $f3 ->set('name', 'world');
    $template = new Template;
    echo $template->render('template.htm');
  }

Template file template.htm

<!DOCTYPE html>
<html>
<head>
    <title>Tutorial page</title>
</head>
<body>
    <p>Hello, {{ @name }}!</p>
</body>
</html>

Create project structure

In project folder

project/index.php
project/config.ini
project/routes.ini
project/app
project/app/controllers
project/app/controllers/Controller.php
project/app/controllers/MainController.php
project/app/views
project/app/views/template.htm

In config.ini file

[globals]

DEBUG=3
UI=app/views/
AUTOLOAD=app/controllers/

In index.php file

<?php

require_once("vendor/autoload.php");

$f3 = Base::instance();

$f3->config('config.ini');
$f3->config('routes.ini');

$f3->run();

Model (database)

Create database

  • Install PHP development environment XAMPP or MAMP

  • Install MySQL workbench

apt install mysql-workbench
  • Create database

  • Create schema

database Connection

  • Update database info in config.ini
devdb = "mysql:host=127.0.0.1;port=3306;dbname=f3MVC"
devdbusername = "f3admin"
devdbpassword = "f3admin"

Update Controller class

class Controller {
    protected $f3;
    protected $db;

    function __construct() {
        $f3 = Base::instance();
        $this->f3 = $f3;

        $db = new DB\SQL(
            $f3->get('devdb'),
            $f3->get('devdbusename'),
            $f3->get('devdbpassword'),
            array( \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION )
        );

        $this->db = $db;
    }
}

For other classes

$this->f3

Create project models

Create folder and a file project/models/Messages.php, which is reading all data from messages table, and then create objects.

<?php

class Messages extends DB\SQL\Mapper {
    public function __construct(DB\SQL $db) {
        parent::__construct($db, 'messages');
    }

    public function all() {
        $this->load();
        return $this->query;
    }
}

Update config.ini

AUTOLOAD=app/controllers/|app/models/

Update render function in MainController class

$messages = new Messages($this->db);
$msg = $messages->all()[0];

$f3->set('msg', $msg);

Update template.htm

<p>Hello, {{ @msg.message }}</p>

Standard implementation of model

<?php

class Messages extends DB\SQL\Mapper {
    public function __construct(DB\SQL $db) {
        parent::__construct($db, 'messages');
    }

    public function all() {
        $this->load();
        return $this->query;
    }

    public function getById($id) {
        $this->load(array('id=?', $id));
        return $this->query;
    }

    public function add() {
        $this->copyFrom('POST');
        $this->save();
    }

    public function edit() {
        $this->load(array('id=?', $id))
        $this->copyFrom('POST');
        $this->update();
    }

    public function delete($id) {
        $this->load(array('id=?', $id))
        $this->erase();
    }
}

Note: copyFrom also can do from hashmap

Save record

$message = new Messages($this->db);
$message->key = 'Secondmessage';
$message->message = 'This is the second message inserted from code.';
$message->save();

Change global to class protected variable

This allow all functions in the class do not need to pass f3 as parameter

class Controller {
    ...
    protected $f3;

    ...
}

class MainController extends Controller {
    function render() {         // Don't need f3 as parameter
        ...
        $this->f3->set('msg', $msg);
        ...
    }
}

getById

$msg = $messages->getById(8)[0];

References

Fatfree PHP Framework Tutorial - 1
Fatfree PHP Framework Tutorial - 2
Fatfree PHP Framework Tutorial - 3
Fatfree PHP Framework Tutorial - 4