Minggu 17 November 2019
This commit is contained in:
commit
4d29a48f79
59
README.md
Normal file
59
README.md
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
# Metaforums
|
||||||
|
An online web-based discussion forum application
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
This project is separated between the frontend and the backend application.
|
||||||
|
- backend/
|
||||||
|
The backend of this application is written in PHP, and is API focused.
|
||||||
|
- index.php
|
||||||
|
The main handler of backend functions. Handles routing, loading of Mitsumine services, and conversion of array responses to JSON.
|
||||||
|
- Mitsumine/
|
||||||
|
Mitsumine is a set of custom-written helper classes to consolidate frequently used code.
|
||||||
|
- Mitsumine/HTTP
|
||||||
|
Mitsumine HTTP contains a number of abstractions for HTTP, such as Request class
|
||||||
|
- Mitsumine/Services
|
||||||
|
Mitsumine Services contains a number of service classes for common functionality such as Database and Session.
|
||||||
|
- Application/
|
||||||
|
Application contains classes that are the core of the application itself
|
||||||
|
- Controllers/
|
||||||
|
Controllers contain controllers that return HTTP responses
|
||||||
|
- frontend/
|
||||||
|
The frontend of this application, written in HTML and utilizes T
|
||||||
|
- index.php
|
||||||
|
This index file allows serving both frontend and backend from one endpoint.
|
||||||
|
|
||||||
|
## Software Stack
|
||||||
|
|
||||||
|
The software is tested on the Apache server and PHP 7.3 on Arch Linux.
|
||||||
|
|
||||||
|
## Backend
|
||||||
|
|
||||||
|
The database used is MariaDB 10.4.8
|
||||||
|
|
||||||
|
## External frontend libraries used
|
||||||
|
|
||||||
|
### Vue.js
|
||||||
|
|
||||||
|
Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web
|
||||||
|
|
||||||
|
Vue.js allows for interactivity while being less cumbersome than manipulating the DOM manually e.g. with jQuery.
|
||||||
|
|
||||||
|
[Project Website](https://vuejs.org)
|
||||||
|
|
||||||
|
### jQuery
|
||||||
|
|
||||||
|
jQuery is a feature-rich JavaScript library.
|
||||||
|
|
||||||
|
Here, jQuery is mainly used for its AJAX functionality.
|
||||||
|
|
||||||
|
[Project Website](https://jquery.com)
|
||||||
|
|
||||||
|
## CSS Frameworks and Styles used
|
||||||
|
|
||||||
|
### Tailwind
|
||||||
|
|
||||||
|
Tailwind is a utility-first CSS framework for rapidly building custom designs
|
||||||
|
|
||||||
|
[Project Website](https://tailwindcss.com)
|
||||||
|
|
||||||
|
## Additional Development
|
12
backend/Application/Controllers/IndexController.php
Normal file
12
backend/Application/Controllers/IndexController.php
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
namespace Application\Controllers;
|
||||||
|
|
||||||
|
use Mitsumine\HTTP\Request;
|
||||||
|
|
||||||
|
class IndexController {
|
||||||
|
public function index(Request $request) {
|
||||||
|
return [
|
||||||
|
'mitsumine' => 'yuika'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
6
backend/Mitsumine/HTTP/Request.php
Normal file
6
backend/Mitsumine/HTTP/Request.php
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?php
|
||||||
|
namespace Mitsumine\HTTP;
|
||||||
|
|
||||||
|
class Request {
|
||||||
|
|
||||||
|
}
|
12
backend/Mitsumine/Services/Config.php
Normal file
12
backend/Mitsumine/Services/Config.php
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
namespace Mitsumine\Services;
|
||||||
|
|
||||||
|
class Config {
|
||||||
|
private $configs;
|
||||||
|
public function __construct() {
|
||||||
|
$this->configs = require 'backend/config.php';
|
||||||
|
}
|
||||||
|
public function __call($name, $args) {
|
||||||
|
return $this->configs[$name];
|
||||||
|
}
|
||||||
|
}
|
12
backend/Mitsumine/Services/Database.php
Normal file
12
backend/Mitsumine/Services/Database.php
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
namespace Mitsumine\Services;
|
||||||
|
|
||||||
|
use Mitsumine\Services\ServiceContainer;
|
||||||
|
|
||||||
|
class Database {
|
||||||
|
private $conn;
|
||||||
|
public function __construct() {
|
||||||
|
$config = ServiceContainer::Config();
|
||||||
|
$this->conn = mysqli_connect($config->db_host(),$config->db_user(),$config->db_pass(),$config->db_name());
|
||||||
|
}
|
||||||
|
}
|
21
backend/Mitsumine/Services/ServiceContainer.php
Normal file
21
backend/Mitsumine/Services/ServiceContainer.php
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
namespace Mitsumine\Services;
|
||||||
|
|
||||||
|
class ServiceContainer{
|
||||||
|
private static $services = [];
|
||||||
|
public static function get($service) {
|
||||||
|
if(!isset(self::$services[$service])) {
|
||||||
|
self::load($service);
|
||||||
|
}
|
||||||
|
return self::$services[$service];
|
||||||
|
}
|
||||||
|
public static function load($service) {
|
||||||
|
$class = 'Mitsumine\\Services\\'.$service;
|
||||||
|
self::$services[$service] = new $class();
|
||||||
|
}
|
||||||
|
public static function __callStatic($name, $args) {
|
||||||
|
// Allow services to be referenced as ServiceContainer::Service()
|
||||||
|
|
||||||
|
return self::get($name);
|
||||||
|
}
|
||||||
|
}
|
14
backend/autoload.php
Normal file
14
backend/autoload.php
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
autoload.php
|
||||||
|
|
||||||
|
Contains a simple autoloader function
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
function mitsumine_autoloader($class) {
|
||||||
|
$file = str_replace('\\',DIRECTORY_SEPARATOR,$class);
|
||||||
|
require $file.'.php';
|
||||||
|
}
|
||||||
|
spl_autoload_register('mitsumine_autoloader');
|
7
backend/config.php
Normal file
7
backend/config.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
return [
|
||||||
|
'db_name' => 'metaforums',
|
||||||
|
'db_host' => '127.0.0.1',
|
||||||
|
'db_user' => 'root',
|
||||||
|
'db_pass' => '',
|
||||||
|
];
|
48
backend/index.php
Normal file
48
backend/index.php
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require 'autoload.php';
|
||||||
|
|
||||||
|
// Use helper classes from Mitsumine
|
||||||
|
use Mitsumine\HTTP\Request;
|
||||||
|
use Mitsumine\Services\ServiceContainer;
|
||||||
|
|
||||||
|
ServiceContainer::Database();
|
||||||
|
|
||||||
|
// Get all routes
|
||||||
|
$routes = require 'routes.php';
|
||||||
|
|
||||||
|
// Get request URI
|
||||||
|
$uri = $_SERVER['PHP_SELF'];
|
||||||
|
// Cut off index.php
|
||||||
|
$uri = substr($uri,strlen('/index.php'),strlen($uri)-strlen('/index.php'));
|
||||||
|
|
||||||
|
// Build request object to pass to controller
|
||||||
|
$request = new Request();
|
||||||
|
|
||||||
|
$request_method = $_SERVER['REQUEST_METHOD'];
|
||||||
|
|
||||||
|
// Get current route from uri
|
||||||
|
$route = $routes[$request_method.':'.$uri];
|
||||||
|
|
||||||
|
|
||||||
|
// Duar (actually, split the method string to class name and method name)
|
||||||
|
$method_part = explode("@",$route['controller']);
|
||||||
|
|
||||||
|
// Get class name and method name
|
||||||
|
$class = $method_part[0];
|
||||||
|
$method = $method_part[1];
|
||||||
|
|
||||||
|
// Get fully qualified class name of route
|
||||||
|
$fqcn = 'Application\\Controllers\\'.$class;
|
||||||
|
$controller = new $fqcn();
|
||||||
|
|
||||||
|
// Execute method specified in route
|
||||||
|
$result = $controller->$method($request);
|
||||||
|
|
||||||
|
// Convert array to JSON
|
||||||
|
if(is_array($result)) {
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
$result = json_encode($result);
|
||||||
|
}
|
||||||
|
echo $result;
|
||||||
|
|
6
backend/routes.php
Normal file
6
backend/routes.php
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?php
|
||||||
|
return [
|
||||||
|
'GET:/api' => [
|
||||||
|
'controller' => 'IndexController@index',
|
||||||
|
],
|
||||||
|
];
|
18
frontend/index.html
Normal file
18
frontend/index.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app">
|
||||||
|
{{ message }}
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
var app = new Vue({
|
||||||
|
el: '#app',
|
||||||
|
data: {
|
||||||
|
message: 'Yuika!'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
18
index.php
Normal file
18
index.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
// Get request URI
|
||||||
|
$uri = $_SERVER['PHP_SELF'];
|
||||||
|
// Cut off index.php
|
||||||
|
$uri = substr($uri,strlen('/index.php'),strlen($uri)-strlen('/index.php'));
|
||||||
|
if(strpos($uri,'/api') !== false && strpos($uri,'/api') == 0) {
|
||||||
|
include 'backend/index.php';
|
||||||
|
} else {
|
||||||
|
// Remove trailing slashes
|
||||||
|
if(substr($uri,strlen($uri)-1,1) == '/') {
|
||||||
|
$uri = substr($uri,0,strlen($uri)-1);
|
||||||
|
}
|
||||||
|
$file = 'frontend'.$uri.'.html';
|
||||||
|
if(!file_exists($file)) {
|
||||||
|
$file = 'frontend'.$uri.'/index.html';
|
||||||
|
}
|
||||||
|
readfile($file);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user