Lompat ke konten Lompat ke sidebar Lompat ke footer

Membuat Framework Sendiri


Contoh Website Membuat Framework Sendiri





Hi sobat kali ini saya ingin berbagi ilmu pemograman yang berjudul Contoh Membuat Framework Sendiri dengan PHP. Seperti yang kita ketahui bahwa framework ini adalah kerangka kerja yang memudahkan kita dalam membangun website dari segi pemograman PHP atau lainnya.



Mungkin ini tidak ada apa apanya ketimbang kerangka kerja yang sudah populer seperti CodeIgniter, YiiFramework, Laravel dll, Kebetulan disini saya pribadi suka sekali ber-experiment mungkin ini bisa jadi bahan belajar untuk sobat yang lagi membutuhkannya atau yang mendalami sebuah kerangka kerja tersebut.



Baik saya akan langsung saja memberikan contoh kode membuat kerangka kerja tersebut dan seterusnya sobatlah yang memahaminya dan mengembangkannya



Pertama sobat siapkan software seperti :



  1. Xampp atau Wamp Server.

  2. Editor Sublime atau sejenisnya.

  3. Point penting sabar dalam menghadapi code error.


Buatlah struktur folder seperti gambar di bawah ini :



Saya akan terangkan sedikit tentang struktur folder ini :

Folder [apps] - Di folder ini adalah bagian dari aplikasi untuk membangun website sobat yang terdiri dari Models, Views & Controllers.

Folder [core] - Di folder ini adalah inti yang menjalankan MVC.

Folder [libs] - Di folder ini adalah librari class yang siap pakai. akan tetapi saya juga masih belajar jadi saya kosongkan saja. tapi jika sobat punya ide atau sudah paham bahasa PHP mungkin sobat bisa memodifikasi atau membuat class baru.

Folder [public] - Di folder ini untuk kumpulan bahan mendesain website seperti css, js, img, fonts-nya secara offline dan plugins, sebernanya untuk plugin yang tersedia di pihak ke 2 seperti bootstrap dll.

Folder [routes] - Di folder ini kumpulan rute URL untuk mengakses halaman website sobat pada saat di jalankan di browser.



Jika sudah siap sobat bisa copy & paste kode di bawah ini dan sama kan seperti gambar di atas.

File index.php

// ex : C:www/foo/bar/  
define('_BASEPATH_', dirname(realpath(__FILE__)) . '/' );
define('ENVIRONMENT', 'development');
if(defined('ENVIRONMENT'))
{
switch(ENVIRONMENT)
{
case 'development': error_reporting(E_ALL); break;
case 'production': error_reporting(0); break;
default: exit('The application environment is not set correctly.'); break;
}
}
// Autoload ( Init )
require _BASEPATH_ . 'loader.php';



File config.php

// Ex : Output Subfolder/  
define('_BASE_DIR_', basename(dirname($_SERVER['PHP_SELF'])) . '/');
// AUTO DETECT SUBFOLDER
// Jika Di URL terditeksi /subfolder/ or /subfolder
// ex output : subfolder/param/param [or] /subfolder/param/param
if( str_replace('/', '', _BASE_DIR_) ) {
// Variable Tetap
define('_BASEROOT_', str_replace('/', '/', _BASE_DIR_));
}
else {
// Variable Tetap
define('_BASEROOT_', str_replace('/', '', _BASE_DIR_));
}
// Jalur DIR application/
define('_APP_PATH_', _BASEPATH_ . 'apps/');
// Jalur DIR library/
define('_LIB_PATH_', _BASEPATH_ . 'libs/');
// Jalur DIR core/
define('_CORE_', _BASEPATH_ . 'core/');
// Automatis Menentukan Socket Menggunakan SSL Atau Tidak dan port
// Ex 1 : http://localhost/ atau http://localhost:8080/
// Ex 2 : https://localhost/ atau https://localhost:8080/
if(isset($_SERVER['SERVER_NAME'])) {
if($_SERVER["SERVER_PORT"] == '80') {
$server = sprintf("%s://%s%s", isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off' ? 'https' : 'http', $_SERVER['SERVER_NAME'], '/');
}
else {
$server = sprintf("%s://%s%s", isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off' ? 'https' : 'http', $_SERVER['SERVER_NAME'].':'.$_SERVER["SERVER_PORT"], '/');
}
}
else {
if($_SERVER["SERVER_PORT"] == '80') {
$server = sprintf("%s://%s%s", isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off' ? 'https' : 'http', $_SERVER['SERVER_ADDR'], '/');
}
else {
$server = sprintf("%s://%s%s", isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off' ? 'https' : 'http', $_SERVER['SERVER_ADDR'].':'.$_SERVER["SERVER_PORT"], '/');
}
}
// Ex : http://localhost/ | https://localhost/
define('_HOSTNAME_', $server);
// URL Standart | if exists subfolder
// output : http://localhost/subfolder
define('_BASE_URL_', _HOSTNAME_ . _BASEROOT_);
// URL API
// output : http://localhost/api/
define('_URL_API_', _HOSTNAME_ . _BASEROOT_ . 'api/');
// URL AJAX
// output : http://localhost/ajax/
define('_URL_AJAX_', _HOSTNAME_ . _BASEROOT_ . 'ajax/');
// Set Path Project untuk router
define('_BASE_PROJECT_', _BASEROOT_);
// Definisi String Connect To Database
define('DB_ENGINE', 'mysql');
define('DB_HOST', '127.0.0.1');
define('DB_USER', 'root');
define('DB_PASS', '');
define('DB_NAME', '');
define('DB_PORT', '3306');



File loader.php

// panggil file config  
require _BASEPATH_ . 'config.php';
// Autoload Class
function __autoload($class)
{
// Load semua class yang terdapat pada folder
if(file_exists( _CORE_ . $class . '.php'))
{
require _CORE_ . $class . '.php';
}
}
// menjalankan mvc system
$router = new Loader;
$router->init();



File .htaccess

  
# Menolak Pembacaan .htaccess

order allow,deny
deny from all


Options All -Indexes

RewriteEngine On
# DISINI TEMPAT PENGATURAN RUTE URL SERVER
#-------------------------------------------------------------------------
# Document Error
# jika disimpan di subfolder silahkan untuk ubah /404 to /subfolder/404
ErrorDocument 401 /subfolder-jika-ada/404
ErrorDocument 403 /subfolder-jika-ada/404
ErrorDocument 404 /subfolder-jika-ada/404
ErrorDocument 500 /subfolder-jika-ada/404
# Redirect Trailing Slashes If Not A Folder
# jika disimpan di subfolder silahkan untuk ubah /$1 to /subfolder/$1
#RewriteCond %{REQUEST_FILENAME} !-d
#RewriteRule ^(.*)/$ /subfolder-jika-ada/$1 [L,R=301]
# Redirect If User Make URL '/index.php/param/'
# jika disimpan di subfolder silahkan untuk ubah / to /subfolder/
#RewriteRule ^index\.php(.+)$ /subfolder-jika-ada/ [R,L,QSA]
#-------------------------------------------------------------------------
# Handle Front Controller
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]




Baik beberapa komponen untuk pembangunan framework sudah siap. Sekarang sobat buat folder core dan buatlah nama file dan sesuaikan dengan kode di bawah ini.



File Controller.php

class Controller   
{
var $controllerpath = _APP_PATH_ . 'controllers/';
/**
* initialize class
*/
function __construct()
{
// membuat objek untuk menghubungkan dengan class views
$this->view = new View();
// membuat objek untuk menghubungkan dengan class model
$this->model = new Model();
}
}



File Model.php


class Model   
{
var $modelpath = _APP_PATH_ . 'models/';
function __construct()
{
// buat objek jembatan koneksi ke database
// parameter constanta terdapat di file config.php
//$this->db = new Database(DB_ENGINE, DB_HOST = null, DB_USER, DB_PASS, DB_PORT);
}
function load($filename)
{
// cek file apakah ada
if(file_exists($this->modelpath . $filename . '_Model.php'))
{
require $this->modelpath . $filename . '_Model.php';
$modelname = $filename . '_Model';
$this->get = new $modelname();
}
}
}



File View.php


class View   
{
var $viewpath = _APP_PATH_ . 'views/';
public function get($filename)
{
// cek file apakah ada
if(file_exists($this->viewpath . $filename . '.php'))
{
require $this->viewpath . $filename . '.php';
}
}
}



File Router.php


class Router {  
/**
* @var array Array of all routes (incl. named routes).
*/
protected $routes = array();
/**
* @var array Array of all named routes.
*/
protected $namedRoutes = array();
/**
* @var string Can be used to ignore leading part of the Request URL (if main file lives in subdirectory of host)
*/
protected $basePath = '';
/**
* @var array Array of default match types (regex helpers)
*/
protected $matchTypes = array(
'i' => '[0-9]++',
'a' => '[0-9A-Za-z]++',
'h' => '[0-9A-Fa-f]++',
'*' => '.+?',
'**' => '.++',
'' => '[^/\.]++'
);
/**
* Create router in one call from config.
*
* @param array $routes
* @param string $basePath
* @param array $matchTypes
*/
public function __construct( $routes = array(), $basePath = '', $matchTypes = array() ) {
$this->addRoutes($routes);
$this->setBasePath($basePath);
$this->addMatchTypes($matchTypes);
}
/**
* Retrieves all routes.
* Useful if you want to process or display routes.
* @return array All routes.
*/
public function getRoutes() {
return $this->routes;
}
/**
* Add multiple routes at once from array in the following format:
*
* $routes = array(
* array($method, $route, $target, $name)
* );
*
* @param array $routes
* @return void
* @author Koen Punt
* @throws Exception
*/
public function addRoutes($routes){
if(!is_array($routes) && !$routes instanceof Traversable) {
throw new \Exception('Routes should be an array or an instance of Traversable');
}
foreach($routes as $route) {
call_user_func_array(array($this, 'map'), $route);
}
}
/**
* Set the base path.
* Useful if you are running your application from a subdirectory.
*/
public function setBasePath($basePath) {
$this->basePath = $basePath;
}
/**
* Add named match types. It uses array_merge so keys can be overwritten.
*
* @param array $matchTypes The key is the name and the value is the regex.
*/
public function addMatchTypes($matchTypes) {
$this->matchTypes = array_merge($this->matchTypes, $matchTypes);
}
/**
* Map a route to a target
*
* @param string $method One of 5 HTTP Methods, or a pipe-separated list of multiple HTTP Methods (GET|POST|PATCH|PUT|DELETE)
* @param string $route The route regex, custom regex must start with an @. You can use multiple pre-set regex filters, like [i:id]
* @param mixed $target The target where this route should point to. Can be anything.
* @param string $name Optional name of this route. Supply if you want to reverse route this url in your application.
* @throws Exception
*/
public function map($method, $route, $target, $name = null) {
$this->routes[] = array($method, $route, $target, $name);
if($name) {
if(isset($this->namedRoutes[$name])) {
throw new \Exception("Can not redeclare route '{$name}'");
} else {
$this->namedRoutes[$name] = $route;
}
}
return;
}
/**
* Reversed routing
*
* Generate the URL for a named route. Replace regexes with supplied parameters
*
* @param string $routeName The name of the route.
* @param array @params Associative array of parameters to replace placeholders with.
* @return string The URL of the route with named parameters in place.
* @throws Exception
*/
public function generate($routeName, array $params = array()) {
// Check if named route exists
if(!isset($this->namedRoutes[$routeName])) {
throw new \Exception("Route '{$routeName}' does not exist.");
}
// Replace named parameters
$route = $this->namedRoutes[$routeName];
// prepend base path to route url again
$url = $this->basePath . $route;
if (preg_match_all('`(/|\.|)\[([^:\]]*+)(?::([^:\]]*+))?\](\?|)`', $route, $matches, PREG_SET_ORDER)) {
foreach($matches as $match) {
list($block, $pre, $type, $param, $optional) = $match;
if ($pre) {
$block = substr($block, 1);
}
if(isset($params[$param])) {
$url = str_replace($block, $params[$param], $url);
} elseif ($optional) {
$url = str_replace($pre . $block, '', $url);
}
}
}
return $url;
}
/**
* Match a given Request Url against stored routes
* @param string $requestUrl
* @param string $requestMethod
* @return array|boolean Array with route information on success, false on failure (no match).
*/
public function match($requestUrl = null, $requestMethod = null) {
$params = array();
$match = false;
// set Request Url if it isn't passed as parameter
if($requestUrl === null) {
$requestUrl = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '/';
}
// strip base path from request url
$requestUrl = substr($requestUrl, strlen($this->basePath));
// Strip query string (?a=b) from Request Url
if (($strpos = strpos($requestUrl, '?')) !== false) {
$requestUrl = substr($requestUrl, 0, $strpos);
}
// set Request Method if it isn't passed as a parameter
if($requestMethod === null) {
$requestMethod = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'GET';
}
foreach($this->routes as $handler) {
list($methods, $route, $target, $name) = $handler;
$method_match = (stripos($methods, $requestMethod) !== false);
// Method did not match, continue to next route.
if (!$method_match) continue;
if ($route === '*') {
// * wildcard (matches all)
$match = true;
} elseif (isset($route[0]) && $route[0] === '@') {
// @ regex delimiter
$pattern = '`' . substr($route, 1) . '`u';
$match = preg_match($pattern, $requestUrl, $params) === 1;
} elseif (($position = strpos($route, '[')) === false) {
// No params in url, do string comparison
$match = strcmp($requestUrl, $route) === 0;
} else {
// Compare longest non-param string with url
if (strncmp($requestUrl, $route, $position) !== 0) {
continue;
}
$regex = $this->compileRoute($route);
$match = preg_match($regex, $requestUrl, $params) === 1;
}
if ($match) {
if ($params) {
foreach($params as $key => $value) {
if(is_numeric($key)) unset($params[$key]);
}
}
return array(
'target' => $target,
'params' => $params,
'name' => $name
);
}
}
return false;
}
/**
* Compile the regex for a given route (EXPENSIVE)
*/
private function compileRoute($route) {
if (preg_match_all('`(/|\.|)\[([^:\]]*+)(?::([^:\]]*+))?\](\?|)`', $route, $matches, PREG_SET_ORDER)) {
$matchTypes = $this->matchTypes;
foreach($matches as $match) {
list($block, $pre, $type, $param, $optional) = $match;
if (isset($matchTypes[$type])) {
$type = $matchTypes[$type];
}
if ($pre === '.') {
$pre = '\.';
}
//Older versions of PCRE require the 'P' in (?P)
$pattern = '(?:'
. ($pre !== '' ? $pre : null)
. '('
. ($param !== '' ? "?P<$param>" : null)
. $type
. '))'
. ($optional !== '' ? '?' : null);
$route = str_replace($block, $pattern, $route);
}
}
return "`^$route$`u";
}
}



File Loader.php


class Loader   
{
function __construct()
{
$this->router = new Router();
}
function init()
{
// Auto ditect direktori router
$this->router->setBasePath(_BASE_PROJECT_);
// manual set router
$dir = _APP_PATH_ . "controllers/";
$scan = array_diff(scandir($dir, 1), array('..', '.'));
foreach ($scan as $value)
{
require $dir . $value ;
}
// load router
require _BASEPATH_ . 'routes/web.php';
$match = $this->router->match();
if ($match === false) {
// here you can handle 404
}
else {
list( $controller, $action ) = explode( '#', $match['target'] );
if ( is_callable(array($controller, $action)) ) {
$obj = new $controller();
call_user_func_array(array($obj,$action), array($match['params']));
}
else {
// here your routes are wrong.
// Throw an exception in debug, send a 500 error in production
}
}
}
}



Sejauh ini sistem atau inti MVC sudah siap. Sekarang buat folder apps, controllers, models, dan views di dalamnya dan nanti masukan ke masing-masing folder atau file yang telah kamu buat pada kode di bawah ini.




File Example_Controller.php


class Example extends Controller  
{
public function __construct()
{
parent::__construct();
}
public function index()
{
$this->view->pagetitle = "Example";
$this->view->get('example');
$this->model->load('example');
$this->model->get->demo();
}
function post()
{
echo 'ini post';
}
}



File Example_Model.php


class Example_Model extends Model  
{
function __construct()
{
parent::__construct();
}
function demo()
{
echo 'ini modeling';
}
}



File example.php


<!DOCTYPE html>  
<html>
<head>
<title><?= $this->pagetitle; ?></title>
</head>
<body>
<h1>Ini Halaman Example</h1>
</body>
</html>




Selesai. Sekarang sobar coba jalankan di browser dengan akses URL : http://localhost/namafoldermu/ dan lihat outputnya.
Jika terjadi error atau belum jelas jangan segan untuk bertanya atau berkomentar. Terima kasih telah berkunjung.

https://github.com/wscdn/free-source

Posting Komentar untuk "Membuat Framework Sendiri"