First commit

master v0.1
sheychen 2017-06-10 17:22:33 +02:00
commit 0ca0c23cee
10 changed files with 542 additions and 0 deletions

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 sheychen
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.

2
README.md Normal file
View File

@ -0,0 +1,2 @@
# krutush
Pretty Simple PHP Framework

15
composer.json Normal file
View File

@ -0,0 +1,15 @@
{
"name": "krutush/krutush",
"license": "MIT",
"authors": [
{
"name": "sheychen",
"email": "contact@clementbois.fr"
}
],
"autoload": {
"psr-4": {
"Krutush\\": "src/"
}
}
}

84
src/App.php Normal file
View File

@ -0,0 +1,84 @@
<?php
namespace Krutush;
class App{
/**
* Current Router
* @var Router
*/
protected $router;
/**
* Get a copy of Router
* @return Router
*/
public function getRouter(): Router{
return clone $this->router;
}
/**
* Config storage
* @var array
*/
protected $config = array(
'namespace' => '',
'controller' => 'Controller',
'debug' => true
);
/**
* Needed config values
* @var array
*/
protected static $configMap = array(
'namespace' => true,
'controller' => false,
'debug' => false
);
public function __construct(array $data = array()){
foreach(static::$configMap as $var => $needed){
if(isset($data['app'][$var])){
$this->config[$var] = $data['app'][$var];
}else{
if($needed)
trigger_error('app.'.$var.' must be define in your app');
}
}
//TODO error handler
//if($this->config['debug'])
if(isset($data['path'])){
Path::sets($data['path']);
}else{
trigger_error('path.root must be define in your app');
}
$this->router = new Router(isset($data['router']) ? $data['router'] : Path::get('config').'/Routes.php');
}
public function run($uri = null, array $filters = array()){
$route = $this->router->run(($uri ?: $_SERVER['REQUEST_URI']), $filters);
if(!isset($route))
$this->error(new HttpException(404, 'Not Found'));
try{
$route->call($this, $this->config['namespace'], $this->config['controller']);
}catch(HttpException $e){
if(!$this->config['debug'])
$e = new HttpException($e->getHttpCode(), 'Server internal error');
$this->error($e);
}catch(\Exception $e){
$this->error(new HttpException(500, $this->config['debug'] ? $e->getMessage() : 'Server internal error'));
}
}
public function error(HttpException $e){
http_response_code($e->getHttpCode());
echo $e->getMessage();
exit;
}
}

5
src/Controller.php Normal file
View File

@ -0,0 +1,5 @@
<?php
namespace Krutush;
class Controller extends NeedApp{}

16
src/HttpException.php Normal file
View File

@ -0,0 +1,16 @@
<?php
namespace Krutush;
class HttpException extends \Exception{
private $httpCode;
public function __construct($httpCode = 500, $message = null){
$this->httpCode = $httpCode;
parent::__construct($message);
}
public function getHttpCode(){
return $this->httpCode;
}
}

9
src/NeedApp.php Normal file
View File

@ -0,0 +1,9 @@
<?php
namespace Krutush;
class NeedApp{
protected $app;
public function __construct(App $app){ $this->app = $app; }
}

133
src/Path.php Normal file
View File

@ -0,0 +1,133 @@
<?php
namespace Krutush;
class Path {
private static $paths = array();
private static $strict = false;
public static function sets(array $data){
foreach($data as $key => $value){
static::set($key, $value);
}
}
public static function get(string $key): string{
$key = strtoupper($key);
switch($key){
case 'ROOT':
if(isset(static::$paths['ROOT']))
return static::$paths['ROOT'];
case 'WWW':
case 'WEB':
case 'PUBLIC':
if(isset(static::$paths['WWW']))
return static::$paths['WWW'];
if(static::$strict == false)
return static::get('ROOT').'/public';
case 'SRC':
if(isset(static::$paths['SRC']))
return static::$paths['SRC'];
if(static::$strict == false)
return static::get('ROOT').'/src';
case 'CFG':
case 'CONF':
case 'CONFIG';
if(isset(static::$paths['CFG']))
return static::$paths['CFG'];
if(static::$strict == false)
return static::get('SRC').'/Config';
case 'TPL':
case 'TEMPLATE':
if(isset(static::$paths['TPL']))
return static::$paths['TPL'];
if(static::$strict == false)
return static::get('SRC').'/Template';
case 'TMP':
case 'CACHE':
if(isset(static::$paths['TPL']))
return static::$paths['TPL'];
if(static::$strict == false)
return static::get('SRC').'/Cache';
default:
trigger_error('Get Unknown key : '.$key);
return '';
}
}
public static function isset(string $key): bool{
$key = strtoupper($key);
switch($key){
case 'ROOT':
return isset(static::$paths['ROOT']);
case 'WWW':
case 'WEB':
case 'PUBLIC':
return isset(static::$paths['WWW']) ||
(static::$strict == false && static::isset('ROOT'));
case 'SRC':
return isset(static::$paths['SRC']) ||
(static::$strict == false && static::isset('ROOT'));
case 'CFG':
case 'CONF':
case 'CONFIG';
return isset(static::$paths['CFG']) ||
(static::$strict == false && static::isset('SRC'));
case 'TPL':
case 'TEMPLATE':
return isset(static::$paths['TPL']) ||
(static::$strict == false && static::isset('SRC'));
default:
return false;
}
}
public static function set(string $key, string $value): bool{
$key = strtoupper($key);
switch($key){
case 'ROOT':
static::$paths['ROOT'] = $value;
return true;
case 'WWW':
case 'WEB':
case 'PUBLIC':
static::$paths['WWW'] = $value;
return true;
case 'SRC':
static::$paths['SRC'] = $value;
return true;
case 'CFG':
case 'CONF':
case 'CONFIG';
static::$paths['CFG'] = $value;
return true;
case 'TPL':
case 'TEMPLATE':
static::$paths['TPL'] = $value;
return true;
default:
trigger_error('Set Unknown key : '.$key);
return false;
}
}
public static function setStrict(bool $value = true){
static::$strict = $value;
}
}

176
src/Route.php Normal file
View File

@ -0,0 +1,176 @@
<?php
namespace Krutush;
/** Based on Grafikart Router */
class Route{
/**
* Url
* @var string
*/
private $path;
/**
* Function to run or 'Controller#function'
* @var callable|string
*/
private $callable;
/** @var string */
private $name;
/**
* string[] Params in url
* @var array
*/
private $matches = array();
/**
* string[] regex Match for params
* @var array
*/
private $params = array();
/**
* Others things
* @var array
*/
private $filters = array();
/**
* Default value of $this->filters
* @var array
*/
private static $defaultFilters = array();
/**
* Register a new Route
* @param string $path Url from Root
* @param callable|string $callable Function to run or 'Controller#function'
*/
public function __construct(string $path, $callable){
$this->path = trim($path, '/');
$this->callable = $callable;
$this->filters = static::$defaultFilters;
}
/**
* My name is [...]
* @param string $name
* @return Route
*/
public function name(string $name): Route{
$this->name = $name;
return $this;
}
/**
* Add a filter
* @param string $name
* @param array $values
* @return Route
*/
public function filter(string $name, array $values): Route{
$this->filters[$name] = $values;
return $this;
}
/**
* Params match regex
* @param string $param
* @param string $regex
* @return Route
*/
public function with(string $param, string $regex): Route{
$this->params[$param] = str_replace('(', '(?:', $regex);
return $this;
}
/**
* Check url
* @param string $url
* @param array $filters
* @return bool
*/
public function match(string $url, array $filters = array()): bool{
//Check filters
foreach($filters as $key => $value){
if(!isset($this->filters[$key]))
return false;
if(!in_array($value, $this->filters[$key]))
return false;
}
//Check url
$url = trim($url, '/');
$path = preg_replace_callback('#:([\w]+)#', array($this, 'paramMatch'), $this->path);
$regex = "#^$path$#i";
if(!preg_match($regex, $url, $matches))
return false;
array_shift($matches);
$this->matches = $matches;
return true;
}
private function paramMatch($match){
if(isset($this->params[$match[1]])){
return '(' . $this->params[$match[1]] . ')';
}
return '([^/]+)';
}
/**
* Build Url with params
* @param array $params
* @return string
*/
public function getUrl(array $params = array()): string{
$path = $this->path;
foreach($params as $k => $v){
$path = str_replace(":$k", $v, $path);
}
return $path;
}
/**
* Check name
* @param string $name
* @return bool
*/
public function matchName(string $name): bool{
return $this->name == $name;
}
/**
* Run Route
* @param App $app
* @param string $namespace
* @param string $prefix
*/
public function call(App $app, string $namespace, string $prefix = "Controller"){
//is a Controller
if(is_string($this->callable)){
$params = explode('#', $this->callable);
$params[0] = ((isset($namespace) && strpos($params[0], '\\') === false) ? ($namespace.$params[0].$prefix) : $params[0]);
if(!class_exists($params[0]))
throw new HttpException(404, 'Class Not Found : '.$params[0]);
$controller = new $params[0]($app);
if(!method_exists($controller,$params[1]))
throw new HttpException(404, 'Function Not Found : '.$params[0].'::'.$params[1]);
return call_user_func_array(array($controller, $params[1]), $this->matches);
} else {
return call_user_func_array($this->callable, $this->matches);
}
}
/**
* Set default filters
* @param array $array
* @return void
*/
public static function filters(array $array = array()){
static::$defaultFilters = $array;
}
}

81
src/Router.php Normal file
View File

@ -0,0 +1,81 @@
<?php
namespace Krutush;
/**
* Load Controller From Url
*/
class Router{
/**
* Route[]
* @var array
*/
private $routes = array();
/**
* @param string $path
* Path to a list of routes.
* See exemple/src/Config/Routes.php
*/
public function __construct(string $path = null){
if(isset($path)){
$r = $this; //4 is too much
include($path); //unsafe...
}
}
/**
* Register a new Route
*
* @param string $path Url from Root
* @param callable|string $callable Function to run or 'Controller#function'
* @return Route
*/
public function add(string $path, $callable):Route{
$route = new Route($path, $callable);
$this->routes[] = $route;
return $route;
}
/**
* Get (first) Route matching url and filters
*
* @param string $url
* @param array $filters
* @return Route|null
*/
public function run(string $url, array $filters):?Route{
foreach($this->routes as $route){
if($route->match($url, $filters))
return $route;
}
return null;
}
/**
* Get (first) Route by name
*
* @param string $name
* @return Route|null
*/
public function get(string $name):?Route{
foreach($this->routes as $route){
if($route->matchName($name))
return $route;
}
return null;
}
/**
* Redirect helper
*
* @param string $url
* @param bool $stop
* @return void
*/
public static function redirect(string $url, bool $stop = true){
header('Location: '.$url);
if($stop)
exit();
}
}