Quick Start Guide

On this quick start guide we will guide you how to use Seme Framework. Start by installing XAMPP, git, and others. After that, we will create a new database on phpmyadmin, then create a new table on there. Then, we will code how to create a administrator page for that one with its menu. Also, we will integrate UI Theme and Implement Datatable with its form to create or update the data as well.

Prepare your environment

First thing first is you need to make sure you have Powershell on windows or Terminal on MacOS or Linux. secondly, you need to download install XAMPP, you can skip this part if you already have XAMPP installed. Then you need Git installed on your computer to download Seme Framework. Also you need text editor like VSCode. After all of that, we can proceed to next step.

Run the XAMPP

You can find the XAMPP Control Panel on start menu (Windows) or from launchpad (Linux / Mac). Click on start button for Apache and MySQL.

Download The Seme Framework

After git and XAMPP was installed, now we can download the Seme Framework through powershell. Please open powershell (Windows), then type:

C:
cd \xampp\htdocs
git clone git@github.com:drosanda/seme-framework.git seme_framework
                

Now, the Seme Framework was installed inside htdocs folder seme_framework.

Check The Seme Framework is Run or Not

Open browser like Google Chrome or Firefox, and then fill the address bar with http://localhost/seme_framework. It should be show a line of text like this: "Thank you for using Seme Framework".

The PhpMyAdmin

PhpMyAdmin is a free open source software tool used to manage SQL databases that already installed when you using XAMPP. You can open the PhpMyAdmin by opening http://localhost/phpmyadmin in your browser.

Developing The Database

After we started service for Apache and MySQL, we will create the tables using phpmyadmin, since we will save all data on there. On Seme Framework, we don't have feature to create table on the fly (like using table migration or command line interface). So, we need to create or develop our own database and tables manually through phpmyadmin. But, before that we need to know about the table naming convention.

Create a database called seme_framework

Open Google Chrome or Firefox, fill the address bar with localhost/phpmyadmin it should open the phpmyadmin page. Then, create a new database on there and name it seme_framework. After that, select on seme_framework database. Likewise with the data rows in the tables, we can create, modify or delete them using SQL. You can change the name of database later to represent your application.

Table naming convention on Seme Framework

All tables on Seme Framework should be created with prefix starts from a_ to z_. The a_ prefix will indicates the table are on top of hierarchy. it's mean, the table values will be used on another table or in another term that table is working independently. The b_ through x_ will indicates the table are on middle of hierarchy. The z_ prefix will indicates the table are on bottom of hierarchy.

Table a_pengguna

Table a_modules will be hold data for list of administrator users. On that table we will store email, password, and etc. Here is the SQL, you can copy and paste on phpmyadmin sql

SET FOREIGN_KEY_CHECKS=0;
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";

DROP TABLE IF EXISTS `a_pengguna`;
CREATE TABLE `a_pengguna` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(64) CHARACTER SET latin1 COLLATE latin1_swedish_ci DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL ON UPDATE current_timestamp(),
  PRIMARY KEY (`id`),
  UNIQUE KEY `a_pengguna_un` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
SET FOREIGN_KEY_CHECKS=1
                  

After we created the structure we need to insert a sample data for administrator user. Here is the SQL.

insert into `a_pengguna`( id, username, password, created_at, updated_at)
values( null, 'mimind', md5('admin123*'), NOW(), null);
                    

How Seme Framework interact with MySQL?

Seme Framework and MySQL will interacted each other using SQL. SQL is structured query language. It is a standard language used by many database management systems. We can use SQL code to create table, modify table or delete table.

Understanding of Seme Framework File Structure

Seme Framework is a MVC based framework. It has 3 main components. Controller, Model and View. Controller is a place where we put our business logic. Model is a place where we put our database related code. and View is a place where we put our view that contains HTML, CSS, and JavaScript. Also Seme Framework has dedicated file configuration that we can adjusted for our requirement later. Beside of that, Seme Framework can be integrated with external library via composer.

The Seme Framework File Structure

Here is the Seme Framework file Structure.

├── app
│   ├── config
│   │   └── development.php
│   ├── core
│   │   ├── ji_controller.php
│   │   └── ji_model.php
│   ├── controller
│   │   ├── admin
│   │   │   ├── login.php
│   │   │   └── home.php
│   │   └── home.php
│   ├── model
│   │   └── a_pengguna_model.php
│   └── view
│       ├── front
│       │   ├── page
│       │   │   ├── html
│       │   │   │   ├── head.php
│       │   │   │   └── header.php
│       │   │   └── col-1.php
│       │   ├── script.json
│       │   └── theme.json
│       └── admin
│           ├── dashboard
│           │   ├── home.php
│           │   ├── home_modal.php
│           │   └── home_bottom.php
│           ├── login
│           │   ├── home.php
│           │   ├── home_modal.php
│           │   └── home_bottom.php
│           ├── page
│           │   ├── html
│           │   │   ├── head.php
│           │   │   └── header.php
│           │   └── col-1.php
│           ├── script.json
│           └── theme.json
├── media
├── skin
│   └── front
├── kero
│   ├── lib
│   ├── bin
│   └── sine
└── index.php
                  

Configuration

The Seme Framework configuration file is located at app/config/development.php. It contains the configuration for database, base_url and other.

Controller

The Seme Framework contoller file is located at app/controller. It contains the logic that will be executed. The execution of controller will be determined by the URL. The controller will be called based on the URL. Here is the pattern of URL.

http://localhost/seme_framework/controller_class/method/parameter1/parameter2/.../parameterN
                  

Default class name is home.php and the default method is index. So, if the controller_class is not specify on url, it will call the default class. Also, if the controller_class is specify on url, but the method is not specify on url, it will call the default method.

Model

The Seme Framework model is a file that will contains query builder or SQL that related to a table. The model will have name same as the table name with _model.php suffix. Here is the filename pattern for model class.

table_name_model.php
                  

Let's say for this example, the table that we have created before is a_pengguna. So, the model will be a_pengguna_model.php as well as the class name will be A_Pengguna_Model.

View

The view is contains many html files and 2 json files that will be used to display the application. The pattern of view we split is by point of view. Lets say, in our application there will be general user and administrator user. So, for the view we will splitted it by point of view. Here is the example of directory structure.

app/view/admin
app/view/front
                  

Create the Administrator Page Layout and Theme

On first view we will create from administrator user. On this section, we will create a special theme and layout for administrator page that based on Bootstrap 3 Framework. And will do copy paste from each files that we have created on this document.

Seme Framework Theme Requirements

First we need to create a folder called admin under app/view. After that we need to create css loader and javascript loader.

CSS Loader

Please create a file called theme.json under app/view/admin. And then copy paste this code.

{
    "link": [
        {
            "rel": "stylesheet",
            "href": "https://skin-cenah.b-cdn.net/css/bootstrap.min.css"
        },
        {
            "rel": "stylesheet",
            "href": "https://skin-cenah.b-cdn.net/css/plugins.css"
        },
        {
            "rel": "stylesheet",
            "href": "https://skin-cenah.b-cdn.net/css/main.css"
        },
        {
            "rel": "stylesheet",
            "href": "https://skin-cenah.b-cdn.net/css/themes.css"
        },
        {
            "rel": "stylesheet",
            "href": "https://skin-cenah.b-cdn.net/css/themes/erplite.css"
        }
    ]
}
                    

Javascript Loader

Please create a file called script.json under app/view/admin. And then copy paste this code.

{
  "script": [
    {
      "src": "https://skin-cenah.b-cdn.net/js/vendor/jquery.min.js"
    },
    {
      "src": "https://skin-cenah.b-cdn.net/js/vendor/bootstrap.min.js"
    },
    {
      "src": "https://skin-cenah.b-cdn.net/js/plugins.js?v=0.0.2"
    },
    {
      "src": "https://skin-cenah.b-cdn.net/js/app.js"
    }
  ]
}
                    

Create the HTML Layout or HTML outer wrapper

The HTML outer wrapper will be used as a template for all the pages. So we can focused on the html content in the future.

Single Column Layout

Single column layout will be demonstrated as a html template layout for login page. To do so, please create a new file in app/view/admin/page/col-1.php and put this code.

<!DOCTYPE html>
<html class="no-js" lang="en">
	<?php $this->getThemeElement("page/html/head",$__forward); ?>
	<body>
		<!-- Main Container -->
		<?php $this->getThemeContent(); ?>
		<!-- Main Container End -->
		<!-- jQuery, Bootstrap.js, jQuery plugins and Custom JS code -->
		<?php $this->getJsFooter(); ?>
		<!-- Load and execute javascript code used only in this page -->
		<script>
		var base_url = '<?=base_url_admin()?>';
		var Login = function(){
			return {
				init: function(){
				}
			}
		}();
			$(document).ready(function(e){
				<?php $this->getJsReady(); ?>
			});
			<?php $this->getJsContent(); ?>
		</script>
	</body>
</html>
                    

Dual Column Layout with Menu on Side Left

Then we will create the second layout for the admin that can hold main view after login. In the after login page, the menu will be on the side left of web page. To do so, please create a new file in app/view/admin/page/col-2-left.php and put this code.

<!DOCTYPE html>
<html class="no-js" lang="en">
	<?php $this->getThemeElement("page/html/head",$__forward); ?>
	<body>
		<!-- Page Wrapper -->
		<div id="page-wrapper" class="page-loading">
			<!-- Preloader -->
			<div class="preloader themed-background">
				<h1 class="push-top-bottom text-light text-center" ><strong><?=$this->config->semevar->app_name;?></strong><br><small>Loading...</small></h1>
				<div class="inner">
					<h3 class="text-light visible-lt-ie10"><strong>Loading..</strong></h3>
					<div class="preloader-spinner hidden-lt-ie10"></div>
				</div>
			</div>
			<!-- END Preloader -->
			<div id="page-container" class="sidebar-mini sidebar-visible-lg-mini">
				<!-- Alternative Sidebar -->
				<?php $this->getThemeElement("page/html/sidebar_alt",$__forward); ?>
				<!-- END Alternative Sidebar -->
				<!-- Main Sidebar -->
				<?php $this->getThemeElement("page/html/sidebar",$__forward); ?>
				<!-- END Main Sidebar -->
				<!-- Main Container -->
				<div id="main-container">
					<!-- Header -->
					<?php $this->getThemeElement("page/html/header",$__forward); ?>
					<!-- END Header -->
					<!-- Main Container -->
					<!-- Global Message -->
					<?php $this->getThemeElement("page/html/global_message",$__forward); ?>
					<!-- Global Message -->
					<?php $this->getThemeContent(); ?>
					<!-- Main Container End -->
					<!-- Footer -->
					<?php $this->getThemeElement("page/html/footer",$__forward); ?>
					<!-- End Footer -->
				</div>
				<!-- End Main Container -->
			</div>
			<!-- End Page Container -->
		</div>
		<!-- End Page Wrapper -->
		<!-- Foot -->
		<?php $this->getThemeElement("page/html/foot",$__forward); ?>
		<!-- End Foot -->
		<div id="modal-preloader" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true">
			<div class="modal-dialog slideInDown animated">
				<div class="modal-content" style="background-color: #000;color: #fff;">
					<!-- Modal Header -->
					<div class="modal-header text-center" style="border: none;">
						<h2 class="modal-title"><i class="fa fa-spin fa-refresh"></i> Loading...</h2>
					</div>
					<!-- END Modal Header -->
				</div>
			</div>
		</div>
		<!-- jQuery, Bootstrap.js, jQuery plugins and Custom JS code -->
		<?php $this->getJsFooter(); ?>
		<!-- Load and execute javascript code used only in this page -->
		<script>
			var from_user_id = '';
			var from_user_nama = '';
			var to_user_id = '';
			var to_user_nama = '';
			var chat_active = 1;
			var last_pesan_id = 0;
			var iterator = 1;
			var base_url = '<?=base_url_admin()?>';
			$(document).ready(function(e){
				<?php $this->getJsReady(); ?>
			});
			<?php $this->getJsContent(); ?>
		</script>
	</body>
</html>
                    

HTML Component inside Head Tags

As you can see in the previous example, we have added some Javascript code inside the head tag. but, we not defined the html component for that one. To do so, we will create a new file again under app/view/admin/page/html/ called head.php. Copy paste code below to that file.

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title><?=$this->getTitle()?></title>
    <meta name="description" content="<?=$this->getDescription()?>">
    <meta name="keyword" content="<?=$this->getKeyword()?>"/>
    <meta name="author" content="<?=$this->getAuthor()?>">
    <meta name="robots" content="<?=$this->getRobots()?>" />
    <!-- Icons -->
    <!-- The following icons can be replaced with your own, they are used by desktop and mobile browsers -->
    <link rel="shortcut icon" href="<?=$this->getIcon()?>" />
    <!-- END Icons -->
    <!-- Stylesheets -->
    <!-- END Stylesheets -->
    <?php $this->getAdditionalBefore()?>
    <?php $this->getAdditional()?>
    <?php $this->getAdditionalAfter()?>
    <!-- Modernizr (browser feature detection library) -->
    <script src="https://skin.cenah.co.id/js/vendor/modernizr.min.js"></script>
</head>
                    

HTML View Components

After we completed the basic HTML Layout. Now, we will add more components to HTML that visible to user via web page.

Create Top Bar HTML Component

Now we will create html component for hold the top bar. To do so, please create a new file in views folder named app/view/admin/page/html/header.php.

                  
<?php
	$admin_foto = '';
	if(isset($sess->admin->foto))$admin_foto = $sess->admin->foto;
	if(empty($admin_foto)) $admin_foto = 'media/user-default.png';
	$admin_foto = $this->cdn_url($admin_foto);
?>
<header class="navbar navbar-default">
	<!-- Left Header Navigation -->
	<ul class="nav navbar-nav-custom">
		<!-- Main Sidebar Toggle Button -->
		<li>
			<a href="javascript:void(0)" onclick="App.sidebar('toggle-sidebar');this.blur();">
				<i class="fa fa-bars fa-fw"></i>
			</a>
		</li>
		<!-- END Main Sidebar Toggle Button -->
		<!-- Template Options -->
		<!-- Change Options functionality can be found in js/app.js - templateOptions() -->
		<li class="dropdown" style="display:none;">
			<a href="javascript:void(0)" class="dropdown-toggle" data-toggle="dropdown">
				<i class="gi gi-settings"></i>
			</a>
			<ul class="dropdown-menu dropdown-custom dropdown-options">
				<li class="dropdown-header text-center">Header Style</li>
				<li>
					<div class="btn-group btn-group-justified btn-group-sm">
						<a href="javascript:void(0)" class="btn btn-primary" id="options-header-default">Light</a>
						<a href="javascript:void(0)" class="btn btn-primary" id="options-header-inverse">Dark</a>
					</div>
				</li>
				<li class="dropdown-header text-center">Page Style</li>
				<li>
					<div class="btn-group btn-group-justified btn-group-sm">
						<a href="javascript:void(0)" class="btn btn-primary" id="options-main-style">Default</a>
						<a href="javascript:void(0)" class="btn btn-primary" id="options-main-style-alt">Alternative</a>
					</div>
				</li>
			</ul>
		</li>
		<!-- END Template Options -->
	</ul>
	<!-- END Left Header Navigation -->
	<!-- Search Form -->
	<form id="fmenu_cari" action="<?=base_url_admin('cari/'); ?>" method="post" class="navbar-form-custom" onsubmit="return false;">
		<div class="form-group">
			<input id="top-search" type="text" name="keyword" class="form-control" placeholder="Cari menu/modul..">
		</div>
	</form>
	<!-- END Search Form -->
	<!-- Right Header Navigation -->
	<ul class="nav navbar-nav-custom pull-right">
		<!-- Alternative Sidebar Toggle Button -->
		<!-- chat toggle -->
		<li>
			<!-- If you do not want the main sidebar to open when the alternative sidebar is closed, just remove the second parameter: App.sidebar('toggle-sidebar-alt'); -->
			<a href="javascript:void(0)" onclick="App.sidebar('toggle-sidebar-alt', 'toggle-other');this.blur();">
				<i class="fa fa-comments"></i>
				<span id="chat-online-count" class="label label-primary label-indicator animation-floating">0</span>
			</a>
		</li>
		<!-- end chat toggle -->
		<!-- User Dropdown -->
		<li class="dropdown">
			<a href="javascript:void(0)" class="dropdown-toggle" data-toggle="dropdown">
				<img src="<?=$admin_foto?>" alt="avatar" onerror="this.onerror=null;this.src='https://seme-framework-storage.b-cdn.net/images/user-default.png';"> <i class="fa fa-angle-down"></i>
			</a>
			<ul class="dropdown-menu dropdown-custom dropdown-menu-right">
				<li class="dropdown-header text-center">Account</li>
				<li>
					<a href="<?=base_url_admin('profil')?>" title="Profil">
						<i class="fa fa-user fa-fw pull-right"></i>
						Profil
					</a>
				</li>
				<li class="divider"></li>
				<li>
					<a href="<?=base_url_admin('logout'); ?>"><i class="fa fa-ban fa-fw pull-right"></i> Logout</a>
				</li>
			</ul>
		</li>
		<!-- END User Dropdown -->
	</ul>
	<!-- END Right Header Navigation -->
</header>
                    

Create Global Message HTML Component

Now we will create html component for hold the top bar. To do so, please create a new file in views folder named app/view/admin/page/html/header.php.

                  
<div id="global_message_danger" class="alert alert-danger" role="alert" style="display:none;">
    <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
    <span class="sr-only">Error:</span>
    <span id="global_message_danger_text">Enter a valid email address</span>
</div>
<div id="global_message_info" class="alert alert-info" role="alert" style="display:none;">
    <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
    <span class="sr-only">Info:</span>
    <span id="global_message_info_text">Enter a valid email address</span>
</div>
<div id="global_message_success" class="alert alert-success" role="alert" style="display:none;">
    <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
    <span class="sr-only">Success:</span>
    <span id="global_message_success_text">Enter a valid email address</span>
</div>
                    

Create Navigation Bar HTML Component

Now we will create html component for navigation bar. The navigation bar will be put as set top of side menu bar. To do so, please create a new file in views folder named app/view/admin/page/html/header.php.

                  
<nav class="navbar navbar-default">
  <div class="container-fluid">
    <!-- Brand and toggle get grouped for better mobile display -->
    <div class="navbar-header">
      <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navbar" aria-expanded="true" aria-controls="navbar">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
    </div>
    
    <!-- Collect the nav links, forms, and other content for toggling -->
    <div id="navbar" class="collapse navbar-collapse" >
      <ul class="nav navbar-nav">
        <li class="active">
          <a href="#" class="btn-sidebar-toggle"><i class="fa fa-list"></i></a>
        </li>
      </ul>
      <form id="form_module_search" action="<?=base_url_admin("modules")?>" method="get" class="navbar-form navbar-left">
        <div class="form-group">
          <input id="fmsfilter" name="filter" type="text" class="form-control" placeholder="Cari Modul" minlength="0" />
        </div>
        <button type="submit" class="btn btn-default"><i class="fa fa-search"></i></button>
      </form>
      <ul class="nav navbar-nav navbar-right">
        <li><a href="#"><i class="fa fa-bell-o"></i> Notification <label class="label label-info">0</label></a></li>
        <li class="dropdown">
          <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><?=$sess->admin->nama?>  <span class="caret"></span></a>
          <ul class="dropdown-menu">
            <li><a href="<?=base_url_admin("profil")?>" title="View my profile">Profil</a></li>
            <li role="separator" class="divider"></li>
            <li><a href="<?=base_url_admin("logout")?>" title="Logout <?=$this->site_name_admin?>">Logout</a></li>
          </ul>
        </li>
        <li><a id="btn-header-show" href="#" ><i class="fa fa-ravelry"></i></a></li>
      </ul>
    </div><!-- /.navbar-collapse -->
  </div><!-- /.container-fluid -->
</nav>
                    

Create Side Menu HTML Component

Now we will create html component for side menu bar. The purpose of this menu is for listing all modules that existed in our application. To do so, please create a new file in views folder named app/view/admin/page/html/sidebar.php.

                  
<?php
	$admin_name = $sess->admin->username ?? '';
	if(isset($sess->admin->nama)) if(strlen($sess->admin->nama)>1) $admin_name = $sess->admin->nama;
	if(!isset($this->current_page)) $this->current_page = "";
	if(!isset($this->current_parent)) $this->current_parent = "";
	$current_page = $this->current_page;
	$current_parent = $this->current_parent;
	$parent = array();
	foreach(($sess->admin->menus->left ?? []) as $key=>$v){
		$parent[$v->identifier] = 0;
		if(count($v->childs)>0){
			foreach($v->childs as $f){
				if($current_page==$f->identifier){
					$current_page = $v->identifier;
					$parent[$v->identifier] = 1;
				}
			}
		}
	}
	$admin_foto = '';
	if(isset($sess->admin->foto))$admin_foto = $sess->admin->foto;
	if(empty($admin_foto)) $admin_foto = 'media/user-default.png';
	$admin_foto = $this->cdn_url($admin_foto);
    $admin_logo_url = '';
    if (isset($this->config->semevar->admin_logo) && strlen($this->config->semevar->admin_logo) > 4) {
        $admin_logo_url = $this->cdn_url($this->config->semevar->admin_logo);
    }
?>
<div id="sidebar">
	<!-- Wrapper for scrolling functionality -->
	<div id="sidebar-scroll">
		<!-- Sidebar Content -->
		<div class="sidebar-content">
			<!-- Brand -->
			<a href="<?=base_url_admin(); ?>" class="sidebar-brand">
				<img src="<?=$admin_logo_url?>" onerror="this.onerror=null;this.src='';" style="width: 90%;" />
			</a>
			<!-- END Brand -->
			<!-- User Info -->
			<div class="sidebar-section sidebar-user clearfix sidebar-nav-mini-hide">
				<div class="sidebar-user-avatar">
					<a href="<?=base_url_admin('profil'); ?>">
						<img src="<?=$admin_foto?>" alt="avatar" onerror="this.onerror=null;this.src='https://seme-framework-storage.b-cdn.net/images/user-default.png';" />
					</a>
				</div>
				<div class="sidebar-user-name"><?=$admin_name; ?></div>
				<div class="sidebar-user-links">
					<a href="<?=base_url_admin('profil'); ?>" data-toggle="tooltip" data-placement="bottom" title="Profile"><i class="gi gi-user"></i></a>
					<a href="<?=base_url_admin("logout"); ?>" data-toggle="tooltip" data-placement="bottom" title="Logout"><i class="gi gi-exit"></i></a>
				</div>
			</div>
			<!-- END User Info -->
			<!-- Sidebar Navigation -->
			<ul class="sidebar-nav">
				<li class="">
					<a href="<?=base_url_admin('')?>" class=" ">
						<i class=" sidebar-nav-mini-hide"></i>
						<i class="fa fa-home sidebar-nav-icon"></i>
						<span class="sidebar-nav-mini-hide">Dashboard</span>
					</a>
				</li>
				<li class="">
					<a href="#" class="sidebar-nav-menu ">
						<i class="fa fa-angle-left sidebar-nav-indicator sidebar-nav-mini-hide"></i>
						<i class="fa fa-cog fa-spin sidebar-nav-icon"></i>
						<span class="sidebar-nav-mini-hide">Perusahaan</span>
					</a>
					<ul class="">
						<li>
							<a href="<?=base_url_admin('perusahaan/master/')?>" class="">
								Data Master Perusahaan
							</a>
						</li>
					</ul>
				</li>
			</ul>
			<!-- END Sidebar Navigation -->
		</div>
		<!-- END Sidebar Content -->
	</div>
	<!-- END Wrapper for scrolling functionality -->
</div>
                    

Create Additional Side Bar

This component was optional, but for now we will create empty html skeleton for future usage. To do so, please create a new file under app/view/admin/page/html/sidebar_alt.php

                  
<div id="sidebar-alt">
	<!-- Wrapper for scrolling functionality -->
	<div id="sidebar-alt-scroll">
		<!-- Sidebar Content -->
		<div class="sidebar-content">
		</div>
		<!-- END Sidebar Content -->
	</div>
	<!-- END Wrapper for scrolling functionality -->
</div>
                    

Create Footer HTML Component

This component will show footer that represent a bar on bottom of application. To do so, please create a new file under app/view/admin/page/html/footer.php

<footer class="clearfix">
	<div class="rainbow pull-right">
		Made with <i class="fa fa-heart text-danger"></i> by <a href="https://cenah.co.id" target="_blank">cenah.co.id</a>. 
	</div>
	<div class="pull-left">
		Seme Framework version 4 - Admin &copy; <?=date("Y")?>
	</div>
</footer>

                    

Create Bottom HTML Component

On this component we will put scroll to top button and then the example modal To do so, please create a new file under app/view/admin/page/html/foot.php

<!-- Scroll to top link, initialized in js/app.js - scrollToTop() -->
<a href="#" id="to-top"><i class="fa fa-angle-double-up"></i></a>
<!-- User Settings, modal which opens from Settings link (found in top right user menu) and the Cog link (found in sidebar user info) -->
<div id="modal-user-settings" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true">
	<div class="modal-dialog">
		<div class="modal-content">
			<!-- Modal Header -->
			<div class="modal-header text-center">
				<h2 class="modal-title"><i class="fa fa-pencil"></i> Settings</h2>
			</div>
			<!-- END Modal Header -->
			<!-- Modal Body -->
			<div class="modal-body">
				<form action="index.html" method="post" enctype="multipart/form-data" class="form-horizontal form-bordered" onsubmit="return false;">
					<fieldset>
						<legend>Vital Info</legend>
						<div class="form-group">
							<label class="col-md-4 control-label">Username</label>
							<div class="col-md-8">
								<p class="form-control-static">Admin</p>
							</div>
						</div>
						<div class="form-group">
							<label class="col-md-4 control-label" for="user-settings-email">Email</label>
							<div class="col-md-8">
								<input type="email" id="user-settings-email" name="user-settings-email" class="form-control" value="admin@example.com">
							</div>
						</div>
						<div class="form-group">
							<label class="col-md-4 control-label" for="user-settings-notifications">Email Notifications</label>
							<div class="col-md-8">
								<label class="switch switch-primary">
								<input type="checkbox" id="user-settings-notifications" name="user-settings-notifications" value="1" checked>
								<span></span>
								</label>
							</div>
						</div>
					</fieldset>
					<fieldset>
						<legend>Password Update</legend>
						<div class="form-group">
							<label class="col-md-4 control-label" for="user-settings-password">New Password</label>
							<div class="col-md-8">
								<input type="password" id="user-settings-password" name="user-settings-password" class="form-control" placeholder="Please choose a complex one..">
							</div>
						</div>
						<div class="form-group">
							<label class="col-md-4 control-label" for="user-settings-repassword">Confirm New Password</label>
							<div class="col-md-8">
								<input type="password" id="user-settings-repassword" name="user-settings-repassword" class="form-control" placeholder="..and confirm it!">
							</div>
						</div>
					</fieldset>
					<div class="form-group form-actions">
						<div class="col-xs-12 text-right">
							<button type="button" class="btn btn-sm btn-default" data-dismiss="modal">Close</button>
							<button type="submit" class="btn btn-sm btn-primary">Save Changes</button>
						</div>
					</div>
				</form>
			</div>
			<!-- END Modal Body -->
		</div>
	</div>
</div>
<!-- END User Settings -->
                    

Login Administrator Implementation

Now we will implementation login for administrator point of view. On this section we will adjusting the configuration, creating core classes for controller and model. After that we will continue to creating model, view and controller.

The Core Classes

The Core classes is intended for put all reusable method or properties. We will create 2 classes. One for Controller and one for Model. And then after that, we will adjust the configuration to load the core classes.

Core Class for Controller

At first step we will create the core class for controller. This class will extends from SENE_Controller class which is the default controller class from Seme Framework. To do so, we will create new file under application/core/ folder and name it JI_Controller.php.

<?php
/**
 * Core class for all controller
 *   contains general purpose methods that nice to have in all controllers
 *
 * @version 1.0.0
 *
 * @package Core\Controller
 * @since 1.0.0
 */
class JI_Controller extends \SENE_Controller
{
    protected $user_login = false;
    protected $admin_login = false;
    private $session_current = null;
    
    public function __construct()
    {
        parent::__construct();
        $this->session_current_check();
    }

    public function session_current_check()
    {
        $session = $this->session_current;
        if (!is_null($session) && isset($session->user->id) && isset($session->admin->id)) {
            return  $session;
        }

        $session = $this->getKey();
        if (!is_object($session)) {
            $session = new stdClass();
            $session->user = new stdClass();
            $session->admin = new stdClass();
        }
        if (!isset($session->user)) {
            $session->user = new stdClass();
        }
        if (isset($session->user->id)) {
            $this->user_login = true;
        }

        if (!isset($session->admin)) {
            $this->sessions->admin = new stdClass();
        }
        if (isset($session->admin->id)) {
            $this->admin_login = true;
        }
        $this->session_current = $session;

        return $this;
    }

    protected function config_semevar($key, $default='')
    {
        if (isset($this->config->semevar->{$key})) {
            return $this->config->semevar->{$key};
        } else {
            return $default;
        }
    }

    public function __init()
    {
        $data = array();
        $data['sess'] = $this->session_current;

        return $data;
    }

    public function index() { }
}
                    

Core Class for Model

At first step we will create the core class for model. This class will extends from SENE_Model class which is the default model class from Seme Framework. To do so, we will create new file under application/core/ folder and name it JI_Model.php.

<?php
/**
* Define all general method for all tables
*   For class models
*
* @package Core\Model
* @since 1.0
*/
class JI_Model extends \SENE_Model
{
    /** @var string  */
    public $tbl;

    /** @var string  */
    public $tbl_as;

    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Insert a row data
     *
     * @param  array   $d   Contain associative array that represent the pair of column and value
     * @return int          Return last ID if succeed, otherwise will return 0
     */
    public function set($d)
    {
        $this->db->insert($this->tbl, $d, 0, 0);
        return $this->db->last_id;
    }

    /**
     * Update a row data by supplied ID
     *
     * @param  int      $id    Positive integer
     * @return boolean         True if succeed, otherwise false
     */
    public function update($id, $d)
    {
        $this->db->where("id", $id);
        return $this->db->update($this->tbl, $d, 0);
    }

    /**
     * Delete row data by ID
     *
     * @param  int      $id    Positive integer
     * @return boolean         True if succeed, otherwise false
     */
    public function del($id)
    {
        $this->db->where("id", $id);
        return $this->db->delete($this->tbl);
    }

    /**
     * Get single row data by ID
     *
     * @param  int      $id     Positive integer
     * @return stdClass         Will return single row object, otherwise will return empty object
     */
    public function id($id)
    {
        $this->db->where("id", $id);
        return $this->db->from($this->tbl, $this->tbl_as)->get_first('', 0);
    }

    /**
     * Open the database transaction session
     * @return boolean True if succeed, otherwise false
     */
    public function trans_start()
    {
        $r = $this->db->autocommit(0);
        if ($r) {
            return $this->db->begin();
        }
        return false;
    }

    /**
     * Execute `commit` SQL command
     * @return boolean True if succeed, otherwise false
     */
    public function trans_commit()
    {
        return $this->db->commit();
    }

    /**
     * Rollback the database transaction session
     * @return boolean True if succeed, otherwise false
     */
    public function trans_rollback()
    {
        return $this->db->rollback();
    }

    /**
     * Finalize the database transaction session
     * @return boolean True if succeed, otherwise false
     */
    public function trans_end()
    {
        return $this->db->autocommit(1);
    }
}
                    

Load the Core Classes

Now, we will load the core classes by adjusting the configuration on app/config/development.php. Please search this text below, and adjust the values.

$core_prefix = 'ji_';
$core_controller = 'controller';
$core_model = 'model';
                    

Model and Concern Class

The Concern class is likely with JI_Model class but it specific for current table. So, let's say we want to create a global method only for a_pengguna table then the method will be existed on a_pengguna_concern.php. Why we split up the Concern class? Because we want to make it easier to extend and maintain the method grouped by a table.

Create Concern Class

Now, we will create the concern class for table a_pengguna under app/model and save it with a_pengguna_concern.php filename.

<?php
namespace Model;

register_namespace(__NAMESPACE__);
/**
 * Define all general method(s) and constant(s) for a_pengguna table,
 *   can be inherited a Concern class also can be reffered as class constants
 *
 * @version 1.0.0
 *
 * @package Model\Concern
 * @since 1.0.0
 */
class A_Pengguna_Concern extends \JI_Model
{
    public $tbl = 'a_pengguna';
    public $tbl_as = 'ap';

    public function __construct()
    {
        parent::__construct();
        $this->db->from($this->tbl, $this->tbl_as);
    }

    public function username($username)
    {
        return $this->db
            ->from($this->tbl, $this->tbl_as)
            ->where("$this->tbl_as.username", $username, 'AND', 'LIKE')
            ->get_first('object', 0);
    }
}
                    

Create Model Class

Now we will create a model inside the app/model/admin folder called a_pengguna_model.php.

<?php
namespace Model\Admin;

register_namespace(__NAMESPACE__);
/**
 * Scoped `admin` model for `a_pengguna` table
 *
 * @version 1.0.0
 *
 * @package Model\Admin
 * @since 1.0.0
 */
class A_Pengguna_Model extends \Model\A_Pengguna_Concern
{

    public function __construct()
    {
        parent::__construct();
    }
}
                    

Create a new Table

Now we will create a new table called a_pengguna by executing the following SQL command in PhpMyAdmin.

SET FOREIGN_KEY_CHECKS=0;
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";

DROP TABLE IF EXISTS `a_pengguna`;
CREATE TABLE `a_pengguna` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(64) CHARACTER SET latin1 COLLATE latin1_swedish_ci DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL ON UPDATE current_timestamp(),
  PRIMARY KEY (`id`),
  UNIQUE KEY `a_pengguna_un` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
SET FOREIGN_KEY_CHECKS=1;
                    

Create View

After creating the model, we will create a view to show the login form and an empty dashboard page after login was success.

Create new layout for login page

Now we will create a new file under app/view/admin/page/login.php

<!DOCTYPE html>
<html class="no-js" lang="en">
	<?php $this->getThemeElement("page/html/head",$__forward); ?>
	<body>
		<!-- Main Container -->
		<?php $this->getThemeContent(); ?>
		<!-- Main Container End -->

		<!-- jQuery, Bootstrap.js, jQuery plugins and Custom JS code -->
		<?php $this->getJsFooter(); ?>

		<!-- Load and execute javascript code used only in this page -->
		<script>
		var base_url = '<?=base_url_admin()?>';
		var Login = function(){
			return {
				init: function(){

				}
			}
		}();
			$(document).ready(function(e){
				<?php $this->getJsReady(); ?>
			});
			<?php $this->getJsContent(); ?>
		</script>
	</body>
</html>
                    

Login Form

Now, we will create a login form html. this file will be loaded through the controller and injected into login layout. To create this file, please create new file under app/view/admin/login/login/home.php.

<!-- Login Full Background -->
<!-- For best results use an image with a resolution of 1280x1280 pixels (prefer a blurred image for smaller file size) -->
<img src="https://seme-framework-storage.b-cdn.net/images/background-login-3.jpg" alt="Login Full Background" class="full-bg animation-pulseSlow">
<!-- END Login Full Background -->

<!-- Login Container -->
<div id="login-container" class="animation-fadeIn">
    <!-- Login Title -->
    <div class="login-title text-center">
        <img src="https://seme-framework-storage.b-cdn.net/images/seme-framework-logo.png" class="img-responsive" />
    </div>
    <!-- END Login Title -->

    <!-- Login Block -->
    <div class="block push-bit">
        <div id="flogin_info" class="alert alert-info" role="alert" style="<?php if(!isset($login_message)) echo 'display:none'; ?>"><?php if(isset($login_message)) echo $login_message; ?></div>
        <!-- Login Form -->
        <form action="<?=base_url_admin("login/authentication/"); ?>" method="post" id="form-login" class="form-horizontal form-bordered form-control-borderless">
            <div class="form-group">
                <div class="col-xs-12">
                    <div class="input-group">
                        <span class="input-group-addon"><i class="gi gi-user"></i></span>
                        <input type="text" id="iusername" name="username" class="form-control input-lg" placeholder="Username" />
                    </div>
                </div>
            </div>
            <div class="form-group">
                <div class="col-xs-12">
                    <div class="input-group">
                        <span class="input-group-addon"><i class="gi gi-asterisk"></i></span>
                        <input type="password" id="ipassword" name="password" class="form-control input-lg" placeholder="Password">
                        <input type="hidden" id="ireff" name="reff" value="<?=$reff ?? ''?>" />
                    </div>
                </div>
            </div>
            <div class="form-group form-actions">
                <div class="col-xs-6">
                    <?=$this->config_semevar('admin_site_title')?> <label class="" style="color: grey; font-weight: lighter; font-size: smaller;">version <?=$this->config_semevar('site_version')?></label>
                </div>
                <div class="col-xs-6 text-right">
                    <button type="submit" class="btn btn-sm btn-primary btn-submit">Login <i id="icon-submit" class="fa fa-angle-right"></i></button>
                </div>
            </div>
        </form>
        <!-- END Login Form -->
    </div>
    <!-- END Login Block -->
</div>
<!-- END Login Container -->
                    

javascript for Login Form

For javascript logic, on Seme Framework need to be put on _bottom.php prefix. So, for this case we will create a new file under app/view/admin/login/home_bottom.php.

var login_try = 0;
$(function(){ Login.init(); });

function gritter(pesan,judul="info"){
	$.bootstrapGrowl(pesan, {
		type: judul,
		delay: 3456,
		allow_dismiss: true
	});
}

$("#form-login").on("submit",function(evt){
	evt.preventDefault();
	console.log('login')
	login_try++;
	var url = '<?=base_url_admin('login/auth'); ?>';
	var fd = {};
	fd.username = $("#iusername").val();
	fd.password = $("#ipassword").val();
	if(fd.username.length<=3){
		$("#iusername").focus();
		gritter("<h4>Info</h4><p>Email belum diisi atau terlalu pendek</p>",'info');
		return false;
	}
	if(fd.password.length<=4){
		$("#ipassword").focus();
		gritter("<h4>Info</h4><p>Kata sandi terlalu pendek</p>",'info');
		return false;
	}
	NProgress.start();
	$("#iusername").prop("disabled",true);
	$("#ipassword").prop("disabled",true);
	$(".btn-submit").prop("disabled",true);
	$("#icon-submit").removeClass("fa-chevron-right");
	$("#icon-submit").addClass("fa-circle-o-notch");
	$("#icon-submit").addClass("fa-spin");
	$.post(url,fd).done(function(dt){
		NProgress.set(0.6);
		if(dt.status == 200){
			gritter("<h4>Sukses</h4><p>Harap tunggu sementara mengarahkan ke dasbor</p>",'success');
			setTimeout(function(){
				NProgress.set(0.7)
			},2000);
			setTimeout(function(){
				NProgress.done();
				window.location =  '<?=base_url_admin('')?>';
			},3000);
		}else{
			$("#iusername").prop("disabled",false);
			$("#ipassword").prop("disabled",false);
			$(".btn-submit").prop("disabled",false);
			$("#icon-submit").addClass("fa-chevron-right");
			$("#icon-submit").removeClass("fa-circle-o-notch");
			$("#icon-submit").removeClass("fa-spin");
			NProgress.done();
			gritter("<h4>Gagal</h4><p>"+dt.message+"</p>",'danger');
			setTimeout(function(){
				$("#bsubmit").removeClass("fa-spin");
				if(login_try>2){
					window.location = '<?=base_url_admin('login')?>';
				}
			},3000);
		}
	}).error(function(){
		$("#iusername").prop("disabled",false);
		$("#ipassword").prop("disabled",false);
		$(".btn-submit").prop("disabled",false);
		$("#icon-submit").addClass("fa-chevron-right");
		$("#icon-submit").removeClass("fa-circle-o-notch");
		$("#icon-submit").removeClass("fa-spin");
		gritter("<h4>Error</h4><p>tidak dapat login sekarang, silahkan coba lagi nanti</p>",'warning');
		NProgress.done();
	});
});

                    

Empty Dashboard Page

After that, we will create an empty dashboard page for future use. This view, will hold the first page after login was success. Please create new file inside app/view/admin/home/home.php

<div id="page-content">
	<!-- Static Layout Header -->
	<div class="content-header">
		<div class="header-section">
			<h1>
				<i class="gi gi-show_big_thumbnails"></i>Static Layout<br><small>This is the default layout</small>
			</h1>
		</div>
	</div>
	<ul class="breadcrumb breadcrumb-top">
		<li>Admin</li>
		<li><a href="<?=base_url_admin()?>">Home</a></li>
		<li><a href="<?=base_url_admin()?>">Example</a></li>
	</ul>
	<!-- END Static Layout Header -->
	
	<!-- Dummy Content -->
	<div class="block full block-alt-noborder">
		<h3 class="sub-header text-center"><strong>Dummy Content</strong> for layout demostration</h3>
		<div class="row">
			<div class="col-md-10 col-md-offset-1 col-lg-8 col-lg-offset-2">
				<article>
					<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas ultrices, justo vel imperdiet gravida, urna ligula hendrerit nibh, ac cursus nibh sapien in purus. Mauris tincidunt tincidunt turpis in porta. Integer fermentum tincidunt auctor. Vestibulum ullamcorper, odio sed rhoncus imperdiet, enim elit sollicitudin orci, eget dictum leo mi nec lectus. Nam commodo turpis id lectus scelerisque vulputate. Integer sed dolor erat. Fusce erat ipsum, varius vel euismod sed, tristique et lectus? Etiam egestas fringilla enim, id convallis lectus laoreet at. Fusce purus nisi, gravida sed consectetur ut, interdum quis nisi. Quisque egestas nisl id lectus facilisis scelerisque?</p>
					<p>Proin rhoncus dui at ligula vestibulum ut facilisis ante sodales! Suspendisse potenti. Aliquam tincidunt sollicitudin sem nec ultrices. Sed at mi velit. Ut egestas tempor est, in cursus enim venenatis eget! Nulla quis ligula ipsum. Donec vitae ultrices dolor? Donec lacinia venenatis metus at bibendum? In hac habitasse platea dictumst. Proin ac nibh rutrum lectus rhoncus eleifend. Sed porttitor pretium venenatis. Suspendisse potenti. Aliquam quis ligula elit. Aliquam at orci ac neque semper dictum. Sed tincidunt scelerisque ligula, et facilisis nulla hendrerit non. Suspendisse potenti. Pellentesque non accumsan orci. Praesent at lacinia dolor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
					<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas ultrices, justo vel imperdiet gravida, urna ligula hendrerit nibh, ac cursus nibh sapien in purus. Mauris tincidunt tincidunt turpis in porta. Integer fermentum tincidunt auctor. Vestibulum ullamcorper, odio sed rhoncus imperdiet, enim elit sollicitudin orci, eget dictum leo mi nec lectus. Nam commodo turpis id lectus scelerisque vulputate. Integer sed dolor erat. Fusce erat ipsum, varius vel euismod sed, tristique et lectus? Etiam egestas fringilla enim, id convallis lectus laoreet at. Fusce purus nisi, gravida sed consectetur ut, interdum quis nisi. Quisque egestas nisl id lectus facilisis scelerisque?</p>
					<p>Proin rhoncus dui at ligula vestibulum ut facilisis ante sodales! Suspendisse potenti. Aliquam tincidunt sollicitudin sem nec ultrices. Sed at mi velit. Ut egestas tempor est, in cursus enim venenatis eget! Nulla quis ligula ipsum. Donec vitae ultrices dolor? Donec lacinia venenatis metus at bibendum? In hac habitasse platea dictumst. Proin ac nibh rutrum lectus rhoncus eleifend. Sed porttitor pretium venenatis. Suspendisse potenti. Aliquam quis ligula elit. Aliquam at orci ac neque semper dictum. Sed tincidunt scelerisque ligula, et facilisis nulla hendrerit non. Suspendisse potenti. Pellentesque non accumsan orci. Praesent at lacinia dolor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
					<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas ultrices, justo vel imperdiet gravida, urna ligula hendrerit nibh, ac cursus nibh sapien in purus.</p>
				</article>
			</div>
		</div>
	</div>
	<!-- END Dummy Content -->
</div>
                    

Controller Class

The Controller class will be taking part as main logic for all activity in our application. We will create several controller classes that represent the login form, authentication method, logout and dashboard page.

Main controller for Administrator Point of View

First we will create a main controller for administrator point of view. Please create a new file under app/controller/admin/home.php, and copy paste the code below.

<?php
/**
* Main Controller Class
*   for Admin
* Mostly for this controller will resulting HTTP Body Content in HTML format
*
* @version 1.0.0
*
* @package Controller\Admin
* @since 1.0.0
*/
class Home extends \JI_Controller
{
    public function __construct()
    {
        parent::__construct();
        $this->setTheme('admin');
    }
    public function index()
    {
        $data = $this->__init();
        if (!$this->admin_login) {
            redir(base_url_admin('login'));

            return false;
        }
        
        $this->setTitle("Home Admin");
        
        $this->putJsContent("home/home_bottom", $data);
        $this->putThemeContent("home/home", $data);

        $this->loadLayout('col-2-left', $data);
        $this->render();
    }
}
                    

Login controller for Administrator Point of View

Then we will create a login controller for administrator point of view. Please create a new file under app/controller/admin/login.php, and copy paste the code below.

<?php

class Login extends \JI_Controller
{
    public function __construct()
    {
        parent::__construct();
        $this->setTheme('admin');
        $this->load('a_pengguna_concern');
        $this->load('admin/a_pengguna_model', 'apm');
    }

    private function validate_input($key, $min_length = 3)
    {
        $value = $this->input->request($key, '');
        if (strlen($value) <= $min_length) {
            $value = false;
        }

        return $value;
    }

    private function validate_admin_session()
    {
        if (isset($this->admin_login) && $this->admin_login == true) {
            return true;
        }

        return false;
    }

    private function validate_username()
    {
        return $this->validate_input('username');
    }

    private function validate_password()
    {
        return $this->validate_input('password');
    }

    private function validate_password_md5($apm, $password)
    {
        if (md5($password) == $apm->password) {
            return true;
        } else {
            return false;
        }
    }

    private function session_current_update($data_initial, $apm)
    {
        $session_current = new stdClass();
        if (!isset($data_initial['sess']->admin)) {
            $this->session_current_check();
        }

        $data_initial['sess']->admin = $apm;
        $this->setKey($data_initial['sess']);

        return $data_initial;
    }

    public function index()
    {
        $data = $this->__init();
        if ($this->validate_admin_session()) {
            redir(base_url_admin('login/authorization/'));

            return true;
        }

        $this->setTitle('Login ' . $this->config_semevar('admin_site_title_suffix'));

        $failed_flag = intval($this->input->request('failed', 0));
        if ($failed_flag > 0) {
            $data['login_message'] = 'Invalid username or password';
        }

        $this->putThemeContent("login/home", $data);
        $this->putJsContent('login/home_bottom', $data);
        $this->loadLayout('login', $data);
        $this->render();
    }

    public function authentication()
    {
        //init
        $data = array();
        $initial_data = $this->__init();
        if ($this->validate_admin_session() == true) {
            redir(base_url_admin('login/authorization/'));

            return false;
        }

        $username = $this->validate_username();
        if (!$username) {
            redir(base_url_admin('login/?failed=1'));
            return false;
        }

        $password = $this->validate_password();
        if (!$password) {
            redir(base_url_admin('login/?failed=2'));
            return false;
        }

        $apm = $this->apm->username($username);
        if (!isset($apm->id)) {
            redir(base_url_admin('login/?failed=3'));
            return false;
        }

        if (!$this->validate_password_md5($apm, $password)) {
            redir(base_url_admin('login/?failed=4'));
            return false;
        }

        $this->session_current_update($initial_data, $apm);

        redir(base_url_admin('login/authorization/'));
        return true;
    }

    public function authorization()
    {
        $data = $this->__init();
        if ($this->validate_admin_session()) {
            redir(base_url_admin());

            return true;
        } else {
            redir(base_url_admin('login'));

            return false;
        }
    }
}
                    

Logout Controller for Administrator Point of View

Then we will create a new controller for logout to clear current session. Please create a new file under app/controller/admin/logout.php, and copy paste the code below.

<?php
/**
* Controller Class
*   for Admin
* Main objective of this class is to clear session for admin
*
* @version 1.0.0
*
* @package Controller\Admin
* @since 1.0.0
*/
class Logout extends \JI_Controller
{
    public function __construct()
    {
        parent::__construct();
        $this->setTheme('admin');
    }

    public function index()
    {
        $initial_data = $this->__init();
        if (!isset($initial_data['sess']->user->admin)) {
            $this->session_current_check();
            $initial_data = $this->__init();
        }
        $initial_data['sess']->admin = new stdClass();
        $this->login_admin = false;
        $this->setKey($initial_data['sess']);

        flush();
        redir(base_url_admin("login"), 0, 1);
    }
}