@@ -0,0 +1,3 @@ | |||
node_modules | |||
vendor | |||
.composer_lock |
@@ -0,0 +1,21 @@ | |||
The MIT License (MIT) | |||
Copyright (c) 2018 Martins Eglitis | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. |
@@ -0,0 +1,10 @@ | |||
# skeleton | |||
A simple MVC skeleton for php apps. | |||
## Requirements | |||
- php >= 5.6 | |||
- composer | |||
- npm | |||
- gulp |
@@ -0,0 +1,29 @@ | |||
{ | |||
"name": "", | |||
"description": "", | |||
"keywords": [], | |||
"license": "MIT", | |||
"homepage": "https://sitilge.id.lv", | |||
"support": { | |||
"issues": "https://sitilge.id.lv", | |||
"source": "https://sitilge.id.lv" | |||
}, | |||
"authors": [ | |||
{ | |||
"name": "Martins Eglitis", | |||
"email": "martins@sitilge.id.lv" | |||
} | |||
], | |||
"require": { | |||
"php": ">= 5.6", | |||
"nikic/fast-route": "*", | |||
"filp/whoops": "*" | |||
}, | |||
"require-dev" : { | |||
}, | |||
"autoload": { | |||
"psr-4": { | |||
"Project\\": "src/" | |||
} | |||
} | |||
} |
@@ -0,0 +1,174 @@ | |||
{ | |||
"_readme": [ | |||
"This file locks the dependencies of your project to a known state", | |||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", | |||
"This file is @generated automatically" | |||
], | |||
"content-hash": "bc575a9b191a15b1234f4813b1576987", | |||
"packages": [ | |||
{ | |||
"name": "filp/whoops", | |||
"version": "2.1.14", | |||
"source": { | |||
"type": "git", | |||
"url": "https://github.com/filp/whoops.git", | |||
"reference": "c6081b8838686aa04f1e83ba7e91f78b7b2a23e6" | |||
}, | |||
"dist": { | |||
"type": "zip", | |||
"url": "https://api.github.com/repos/filp/whoops/zipball/c6081b8838686aa04f1e83ba7e91f78b7b2a23e6", | |||
"reference": "c6081b8838686aa04f1e83ba7e91f78b7b2a23e6", | |||
"shasum": "" | |||
}, | |||
"require": { | |||
"php": "^5.5.9 || ^7.0", | |||
"psr/log": "^1.0.1" | |||
}, | |||
"require-dev": { | |||
"mockery/mockery": "0.9.*", | |||
"phpunit/phpunit": "^4.8.35 || ^5.7", | |||
"symfony/var-dumper": "^2.6 || ^3.0" | |||
}, | |||
"suggest": { | |||
"symfony/var-dumper": "Pretty print complex values better with var-dumper available", | |||
"whoops/soap": "Formats errors as SOAP responses" | |||
}, | |||
"type": "library", | |||
"extra": { | |||
"branch-alias": { | |||
"dev-master": "2.0-dev" | |||
} | |||
}, | |||
"autoload": { | |||
"psr-4": { | |||
"Whoops\\": "src/Whoops/" | |||
} | |||
}, | |||
"notification-url": "https://packagist.org/downloads/", | |||
"license": [ | |||
"MIT" | |||
], | |||
"authors": [ | |||
{ | |||
"name": "Filipe Dobreira", | |||
"homepage": "https://github.com/filp", | |||
"role": "Developer" | |||
} | |||
], | |||
"description": "php error handling for cool kids", | |||
"homepage": "https://filp.github.io/whoops/", | |||
"keywords": [ | |||
"error", | |||
"exception", | |||
"handling", | |||
"library", | |||
"throwable", | |||
"whoops" | |||
], | |||
"time": "2017-11-23T18:22:44+00:00" | |||
}, | |||
{ | |||
"name": "nikic/fast-route", | |||
"version": "v1.3.0", | |||
"source": { | |||
"type": "git", | |||
"url": "https://github.com/nikic/FastRoute.git", | |||
"reference": "181d480e08d9476e61381e04a71b34dc0432e812" | |||
}, | |||
"dist": { | |||
"type": "zip", | |||
"url": "https://api.github.com/repos/nikic/FastRoute/zipball/181d480e08d9476e61381e04a71b34dc0432e812", | |||
"reference": "181d480e08d9476e61381e04a71b34dc0432e812", | |||
"shasum": "" | |||
}, | |||
"require": { | |||
"php": ">=5.4.0" | |||
}, | |||
"require-dev": { | |||
"phpunit/phpunit": "^4.8.35|~5.7" | |||
}, | |||
"type": "library", | |||
"autoload": { | |||
"psr-4": { | |||
"FastRoute\\": "src/" | |||
}, | |||
"files": [ | |||
"src/functions.php" | |||
] | |||
}, | |||
"notification-url": "https://packagist.org/downloads/", | |||
"license": [ | |||
"BSD-3-Clause" | |||
], | |||
"authors": [ | |||
{ | |||
"name": "Nikita Popov", | |||
"email": "nikic@php.net" | |||
} | |||
], | |||
"description": "Fast request router for PHP", | |||
"keywords": [ | |||
"router", | |||
"routing" | |||
], | |||
"time": "2018-02-13T20:26:39+00:00" | |||
}, | |||
{ | |||
"name": "psr/log", | |||
"version": "1.0.2", | |||
"source": { | |||
"type": "git", | |||
"url": "https://github.com/php-fig/log.git", | |||
"reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" | |||
}, | |||
"dist": { | |||
"type": "zip", | |||
"url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", | |||
"reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", | |||
"shasum": "" | |||
}, | |||
"require": { | |||
"php": ">=5.3.0" | |||
}, | |||
"type": "library", | |||
"extra": { | |||
"branch-alias": { | |||
"dev-master": "1.0.x-dev" | |||
} | |||
}, | |||
"autoload": { | |||
"psr-4": { | |||
"Psr\\Log\\": "Psr/Log/" | |||
} | |||
}, | |||
"notification-url": "https://packagist.org/downloads/", | |||
"license": [ | |||
"MIT" | |||
], | |||
"authors": [ | |||
{ | |||
"name": "PHP-FIG", | |||
"homepage": "http://www.php-fig.org/" | |||
} | |||
], | |||
"description": "Common interface for logging libraries", | |||
"homepage": "https://github.com/php-fig/log", | |||
"keywords": [ | |||
"log", | |||
"psr", | |||
"psr-3" | |||
], | |||
"time": "2016-10-10T12:19:37+00:00" | |||
} | |||
], | |||
"packages-dev": [], | |||
"aliases": [], | |||
"minimum-stability": "stable", | |||
"stability-flags": [], | |||
"prefer-stable": false, | |||
"prefer-lowest": false, | |||
"platform": { | |||
"php": ">= 5.6" | |||
}, | |||
"platform-dev": [] | |||
} |
@@ -0,0 +1,41 @@ | |||
// Include gulp | |||
var gulp = require('gulp'); | |||
// Include Plugins | |||
var rename = require('gulp-rename'); | |||
var sass = require('gulp-sass'); | |||
var cssnano = require('gulp-cssnano'); | |||
var concatcss = require('gulp-concat-css'); | |||
var concatjs = require('gulp-concat'); | |||
var uglifyjs = require('gulp-uglify'); | |||
// Compile Sass | |||
gulp.task('sass', function() { | |||
return gulp.src('public/css/src/*.scss') | |||
.pipe(sass.sync()) | |||
.pipe(concatcss('main.css')) | |||
.pipe(cssnano()) | |||
.pipe(gulp.dest('public/css/dist')); | |||
}); | |||
// Concatenate & Minify JS | |||
gulp.task('js', function() { | |||
return gulp.src([ | |||
'public/js/src/jquery.js', | |||
'public/js/src/*.js']) | |||
.pipe(concatjs('main.js')) | |||
.pipe(uglifyjs()) | |||
.pipe(gulp.dest('public/js/dist')); | |||
}); | |||
// Watch Files For Changes | |||
gulp.task('watch', function() { | |||
gulp.watch(['public/css/src/*.scss'], ['sass']); | |||
gulp.watch(['public/js/src/*.js'], ['js']); | |||
}); | |||
// Default Task | |||
gulp.task('default', [ | |||
'sass', | |||
'js' | |||
]); |
@@ -0,0 +1,31 @@ | |||
{ | |||
"name": "", | |||
"version": "", | |||
"description": "", | |||
"main": "gulpfile.js", | |||
"directories": { | |||
"test": "tests" | |||
}, | |||
"devDependencies": { | |||
"gulp": "*", | |||
"gulp-concat": "*", | |||
"gulp-concat-css": "*", | |||
"gulp-cssnano": "*", | |||
"gulp-rename": "*", | |||
"gulp-sass": "*", | |||
"gulp-uglify": "*" | |||
}, | |||
"scripts": { | |||
"test": "echo \"Error: no test specified\" && exit 1" | |||
}, | |||
"repository": { | |||
"type": "git", | |||
"url": "" | |||
}, | |||
"author": "Martins Eglitis", | |||
"license": "MIT", | |||
"bugs": { | |||
"url": "" | |||
}, | |||
"homepage": "" | |||
} |
@@ -0,0 +1,9 @@ | |||
<?php | |||
$root = filter_input(INPUT_SERVER, "DOCUMENT_ROOT"); | |||
require $root."/../vendor/autoload.php"; | |||
$frontController = new \Project\Misc\Bootstrap(); | |||
$frontController->init(); |
@@ -0,0 +1,9 @@ | |||
<?php | |||
return [ | |||
"fqdn" => "/", | |||
"development" => true, | |||
"callable" => function($exception, $inspector, $run) { | |||
echo "Some error."; | |||
} | |||
]; |
@@ -0,0 +1,114 @@ | |||
<?php | |||
namespace Project\Misc; | |||
use FastRoute\RouteCollector; | |||
use Whoops\Handler\Handler; | |||
use Whoops\Handler\PrettyPageHandler; | |||
use Whoops\Handler\JsonResponseHandler; | |||
use Whoops\Run; | |||
class Bootstrap | |||
{ | |||
/** | |||
* The initial method called. | |||
*/ | |||
public function init() | |||
{ | |||
$this->initThrowable(); | |||
$this->initSession(); | |||
$this->initRoute(); | |||
} | |||
/** | |||
* Initialize the throwable. | |||
*/ | |||
private function initThrowable() | |||
{ | |||
$root = filter_input(INPUT_SERVER, "DOCUMENT_ROOT"); | |||
$config = require $root."/../src/Config/Main.php"; | |||
if (empty($config["development"])) { | |||
$this->initHandler(function($exception, $inspector, $run) use ($config) { | |||
call_user_func_array($config["callable"], [ | |||
$exception, | |||
$inspector, | |||
$run | |||
]); | |||
return Handler::DONE; | |||
}); | |||
return; | |||
} | |||
$server = filter_input_array(INPUT_SERVER); | |||
if (!empty($server["HTTP_X_REQUESTED_WITH"]) | |||
&& strtolower($server["HTTP_X_REQUESTED_WITH"]) == "xmlhttprequest") { | |||
$this->initHandler(new JsonResponseHandler()); | |||
return; | |||
} | |||
$this->initHandler(new PrettyPageHandler()); | |||
} | |||
/** | |||
* Initialize the throwable handler. | |||
*/ | |||
private function initSession() | |||
{ | |||
session_start(); | |||
} | |||
/** | |||
* Initialize the throwable handler. | |||
*/ | |||
private function initHandler(Handler $handler) | |||
{ | |||
$run = new Run(); | |||
$run->pushHandler($handler); | |||
$run->register(); | |||
} | |||
/** | |||
* Initialize the route handler. | |||
*/ | |||
private function initRoute() | |||
{ | |||
$root = filter_input(INPUT_SERVER, "DOCUMENT_ROOT"); | |||
$routes = require $root."/../src/Misc/Routes.php"; | |||
$dispatcher = \FastRoute\simpleDispatcher(function (RouteCollector $collector) use ($routes) { | |||
foreach ($routes as $route) { | |||
$collector->addRoute($route[0], $route[1], $route[2]); | |||
} | |||
}); | |||
$method = $_SERVER["REQUEST_METHOD"]; | |||
$uri = $_SERVER["REQUEST_URI"]; | |||
$route = $dispatcher->dispatch($method, $uri); | |||
switch ($route[0]) { | |||
case \FastRoute\Dispatcher::NOT_FOUND: | |||
throw new \ErrorException("Route $method $uri not found."); | |||
break; | |||
case \FastRoute\Dispatcher::METHOD_NOT_ALLOWED: | |||
throw new \ErrorException("Method $method not allowed."); | |||
break; | |||
case \FastRoute\Dispatcher::FOUND: | |||
$handler = $route[1]; | |||
$arguments = $route[2]; | |||
call_user_func_array($handler, $arguments); | |||
} | |||
} | |||
} |
@@ -0,0 +1,30 @@ | |||
<?php | |||
use Project\Models\Main\TemplateModel; | |||
use Project\Models\Main\UrlModel; | |||
use Project\Views\Main\MainView; | |||
$mainRoute = function() { | |||
return | |||
[ | |||
["GET", "POST"], | |||
"/", | |||
function(...$segments) { | |||
$templateModel = new TemplateModel(); | |||
$urlModel = new UrlModel(); | |||
$mainView = new MainView(); | |||
$mainView->segments = $segments; | |||
$mainView->templateModel = $templateModel; | |||
$mainView->urlModel = $urlModel; | |||
$mainView->manageOutput(); | |||
} | |||
]; | |||
}; | |||
return [ | |||
$mainRoute(), | |||
]; |
@@ -0,0 +1,70 @@ | |||
<?php | |||
namespace Project\Models\Main; | |||
class TemplateModel | |||
{ | |||
public $data = []; | |||
public $file = ""; | |||
/** | |||
* Set a file. | |||
*/ | |||
public function file($file) | |||
{ | |||
$this->file = $file; | |||
if (empty(pathinfo($file, PATHINFO_EXTENSION))) { | |||
$this->file .= ".php"; | |||
} | |||
return $this; | |||
} | |||
/** | |||
* Set a parameter. | |||
*/ | |||
public function set($key, $value = null) | |||
{ | |||
if (is_array($key)) { | |||
foreach ($key as $name => $value) { | |||
$this->data[$name] = $value; | |||
} | |||
return $this; | |||
} | |||
$this->data[$key] = $value; | |||
return $this; | |||
} | |||
/** | |||
* Get a parameter. | |||
*/ | |||
public function get($key) | |||
{ | |||
return isset($this->data[$key]) ? $this->data[$key] : null; | |||
} | |||
/** | |||
* Render a template. | |||
*/ | |||
public function render($input = null) | |||
{ | |||
ob_start(); | |||
extract($this->data, EXTR_SKIP); | |||
if (null !== $input) { | |||
echo $input; | |||
return ob_get_clean(); | |||
} | |||
require $this->file; | |||
return ob_get_clean(); | |||
} | |||
} |
@@ -0,0 +1,73 @@ | |||
<?php | |||
namespace Project\Models\Main; | |||
class UrlModel | |||
{ | |||
/** | |||
* Make a route. | |||
*/ | |||
public function makeUrl($segments = []) | |||
{ | |||
$root = filter_input(INPUT_SERVER, "DOCUMENT_ROOT"); | |||
$config = require $root."/../src/Config/Main.php"; | |||
$pattern = []; | |||
foreach ($segments as $index => $segment) { | |||
if ('' !== $segment) { | |||
$pattern[] = "%s"; | |||
} else { | |||
unset($segments[$index]); | |||
} | |||
} | |||
return rtrim($config["fqdn"], "/")."/".$this->prepare(implode("/", $pattern), $segments); | |||
} | |||
/** | |||
* Prepare a pattern. | |||
*/ | |||
private function prepare($pattern, $segments) | |||
{ | |||
foreach ($segments as &$argument) { | |||
$argument = preg_replace("#[^a-zA-Z0-9_\-]#", "", str_replace(" ", "_", $argument)); | |||
} | |||
return vsprintf($pattern, $segments); | |||
} | |||
/** | |||
* Get a segment. | |||
*/ | |||
public function getSegment($index = 0) | |||
{ | |||
$url = trim($this->getUrl(), '/'); | |||
$segments = explode("/", $url); | |||
$count = count($segments); | |||
if ($count <= $index || $index < 0) { | |||
return $segments[$count - 1]; | |||
} | |||
return $segments[$index]; | |||
} | |||
/** | |||
* Get the current url. | |||
*/ | |||
public function getUrl() | |||
{ | |||
$server = filter_input_array(INPUT_SERVER); | |||
if (!empty($server["PATH_INFO"])) { | |||
return rawurldecode(parse_url($server["PATH_INFO"], PHP_URL_PATH)); | |||
} elseif (!empty($server["REQUEST_URI"])) { | |||
return rawurldecode(parse_url($server["REQUEST_URI"], PHP_URL_PATH)); | |||
} | |||
return false; | |||
} | |||
} |
@@ -0,0 +1,18 @@ | |||
<!DOCTYPE html> | |||
<html prefix="og: http://ogp.me/ns#" lang="lv"> | |||
<head> | |||
<title></title> | |||
<meta charset="utf-8"> | |||
<meta content="IE=edge" http-equiv="X-UA-Compatible"> | |||
<meta content="width=device-width, initial-scale=1" name="viewport"> | |||
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags --> | |||
<meta content="" property="og:title"> | |||
<meta content="" property="og:image"> | |||
<meta content="" property="og:description"> | |||
<link rel="stylesheet" href="<?php echo $url->makeUrl(); ?>css/dist/container.css"> | |||
</head> | |||
<body> | |||
<h1>Hello, world!</h1> | |||
<script src="<?php echo $url->makeUrl(); ?>js/dist/container.js"></script> | |||
</body> | |||
</html> |
@@ -0,0 +1,41 @@ | |||
<?php | |||
namespace Project\Views\Main; | |||
use Project\Models\Main\TemplateModel; | |||
use Project\Models\Main\UrlModel; | |||
class MainView | |||
{ | |||
public $segments; | |||
/** | |||
* MainView constructor. | |||
*/ | |||
public function __construct( | |||
$segments = [], | |||
TemplateModel $templateModel = null, | |||
UrlModel $urlModel = null | |||
) { | |||
$this->segments = $segments; | |||
$this->templateModel = $templateModel; | |||
$this->urlModel = $urlModel; | |||
} | |||
/** | |||
* Manage the output. | |||
*/ | |||
public function manageOutput() | |||
{ | |||
$root = filter_input(INPUT_SERVER, "DOCUMENT_ROOT"); | |||
$config = require $root."/../src/Config/Main.php"; | |||
$post = filter_input_array(INPUT_POST); | |||
echo $template = $this->templateModel | |||
->set("url", $this->urlModel) | |||
->file($root."/../src/Templates/Container.php") | |||
->render(); | |||
} | |||
} |