';
return join('', $string);
}
public function render(){return [[], $this->stringify($this->viewModel->getData(), true)];}
}
class FormView{
protected $viewModel;
public function __construct($viewModel){$this->viewModel = $viewModel;}
private function stringify($data){
$string = ['
'];
foreach($data as $key => $item){
$attr = '';
if (is_object($item) || is_array($item)){
$string[] = '
'.$key.': '.$this->stringify($item).'
';
} else {
$string[] = '
'.$key.': '.$item.'
';
}
}
$string[] = '
';
return join('', $string);
}
public function render(){
$result = '';
$data = $this->viewModel->getData();
$errors = $this->viewModel->getErrors();
$result .= $this->stringify($errors);
if (!is_null($data)){
foreach($data as $slug => $object){
if (!is_null($object)){
$method = $object['*']['method'];
$url = $object['*']['action'];
$result .= '';
}
}
}
return [[], $result];
}
}
trait ViewTrait {
protected $viewModel;
public function __construct($viewModel){
$this->viewModel = $viewModel;
}
}
class Session{
public function __construct($sessionName = ''){
if (!isset($_SESSION)) $_SESSION = [];
if (!empty($sessionName)) session_name($sessionName);
}
public function start(){
if (!$this->isActive()){
ini_set('session.use_trans_sid', false);
session_start();
}
}
public function get($key, $default = null){
$this->autostart();
if (array_key_exists($key, $_SESSION)){
$default = $_SESSION[$key];
}
return $default;
}
public function set($key, $value){
$this->autostart();
$_SESSION[$key] = $value;
}
public function remove($keys){
if (is_string($keys)){
$keys = [$keys];
}
foreach ($keys as $key){
unset($_SESSION[$key]);
}
}
public function isActive(){
return \PHP_SESSION_ACTIVE === session_status();
}
private function autostart(){
if (!$this->isActive()){
$this->start();
}
}
}
class Container{
protected $container = [];
protected $rules = [];
public function has($id){return class_exists($id)||isset($this->container[$this->getId($id)]);}
public function get($id, $args = []){
if ($this->has($this->getId($id).'_instance')){
return $this->get($this->getId($id).'_instance');
} else if (isset($this->container[$this->getId($id)])){
$get = $this->container[$this->getId($id)];
$instance = is_callable($get)?$get($this, $args):$get;
$this->setInstance($id, $instance);
return $instance;
} else if (class_exists($id)){
$instance = new $id($args);
$this->setInstance($id, $instance);
return $instance;
} else {
throw new \Exception($id.' not found');
}
}
public function getRule($id){return $this->rules[$id];}
public function set($id, $rules = array()){
$this->rules[$id] = $rules;
if (!$this->has($this->getId($id).'_class')) $this->container[$this->getId($id).'_class'] = $id;
$id = $this->getId($id);
foreach ($rules as $key => $rule){
switch($key){
case 'instanceOf':
$this->container[$id.'_class'] = $rule;
break;
case 'constructParams':
$this->container[$id.'_params'] = $rule;
break;
case 'call':
$this->container[$id.'_call'] = $rule;
break;
case 'shared':
$this->container[$id.'_shared'] = $rule;
break;
}
}
$this->container[$id] = function ($container, $params = []) use ($id){
$class = new \ReflectionClass($container->has($id.'_class') ? $container->get($id.'_class') : $id);
if ($container->has($id.'_params')){
$params = [];
foreach($container->get($id.'_params') as $param){
if (is_array($param) && isset($param['instance'])){
$params[] = $container->get($param['instance']);
} else {
$params[] = $param;
}
}
}
$instance = $class->newInstanceArgs($params);
if ($container->has($id.'_call')){
foreach($container->get($id.'_call') as $call){
call_user_func_array(array($instance, $call[0]), $call[1]);
}
}
return $instance;
};
}
private function getId($id){return ltrim(strtolower($id), '\\');}
private function setInstance($id, $instance){
if (isset($this->container[$this->getId($id).'_shared'])
&& $this->container[$this->getId($id).'_shared']){
$this->container[$this->getId($id).'_instance'] = $instance;
}
}
}
class RemoveFormAction{
use FormActionTrait;
private function saveEntity($entity){
$this->model->remove($entity);
$this->flush = true;
}
public function success($data){$this->traitSuccess($data);}
public function failure($data){$this->traitFailure($data);}
}
trait FormActionTrait {
private $model;
private $form;
private $request;
private $resetData;
private $flush = false;
public function __construct($model, $form, $request, $resetData = false){
$this->model = $model;
$this->form = $form;
$this->request = $request;
$this->resetData = $resetData;
}
public function traitSuccess($data){
if ($this->resetData) $this->model->remove();
$this->form->setFormData($data);
$data = $this->form->getData();
if (is_array($data)){
if (empty(array_filter(array_keys($data), 'is_int'))) $this->saveEntity($data);
else foreach($data as $entity) $this->saveEntity($entity);
} else {
$this->saveEntity($data);
}
if ($this->flush) $this->model->flush();
header('Location: '.$this->request->getSchemeAndHttpHost().$this->request->getBaseUrl());
}
public function traitFailure($data){
if (array_key_exists('_', $data)) $data = $data['_'];
$this->form->setData($data);
}
}
class PersistFormAction{
use FormActionTrait;
private function saveEntity($entity){
$this->model->persist($entity);
$this->flush = true;
}
public function success($data){$this->traitSuccess($data);}
public function failure($data){$this->traitFailure($data);}
}
class Request{
private $basePath = '';
private $baseUrl = '';
private $host = 'localhost';
private $method = 'GET';
private $pathInfo = '';
private $port = 80;
private $queryString = '';
private $requestUri = '';
private $scheme = 'http';
public function __construct($uri = null, $method = 'GET'){
if (is_null($uri)){
$this->initFromServer();
} else {
$this->initFromUri($uri, $method);
}
}
public function getBaseUrl(){return $this->baseUrl;}
public function getHost(){return $this->host;}
public function getPathInfo(){return $this->pathInfo;}
public function getPort(){return $this->port;}
public function getQueryString(){return $this->queryString;}
public function getScheme(){return $this->scheme;}
public function getMethod(){return $this->method;}
public function getRequest($request = null, $default = null){
if (is_null($request)) return $_POST;
return isset($_POST[$request])?$_POST[$request]:$default;
}
public function getQuery($query = null, $default = null){
if (is_null($query)) return $_GET;
return isset($_GET[$query])?$_GET[$query]:$default;
}
public function getRequestUri(){return $this->requestUri;}
public function setBaseUrl($baseUrl){$this->baseUrl = rtrim($baseUrl, '/');}
public function setPathInfo($pathInfo){$this->pathInfo = $pathInfo;}
public function setMethod($method){$this->method = strtoupper($method);}
public function setHost($host){$this->host = preg_replace('/:(.*)$/i', "", strtolower($host));}
public function setRequestUri($requestUri){$this->requestUri = $requestUri;}
public function setScheme($scheme){$this->scheme = strtolower($scheme);}
public function setPort($port){$this->port = (int) $port;}
public function setQueryString($queryString){$this->queryString = (string) $queryString;}
public function getUri(){
$queryString = $this->getQueryString();
$queryString = empty($queryString)?'':'?'.$queryString;
return $this->getSchemeAndHttpHost().$this->getBaseUrl().$this->getPathInfo().$queryString;
}
public function getSchemeAndHttpHost(){
$scheme = $this->getScheme();
$port = $this->getPort();
$defaultPort = $scheme.$port === 'http80' || $scheme.$port === 'https443';
return $scheme.'://'.$this->getHost().(($defaultPort)?'':':'.$port);
}
private function prepareRequestUri(){
$requestUri = '';
if (!empty($this->getServer('REQUEST_URI'))){
$requestUri = $this->getServer('REQUEST_URI');
$schemeAndHttpHost = $this->getSchemeAndHttpHost();
if (strpos($requestUri, $schemeAndHttpHost) === 0){
$requestUri = substr($requestUri, strlen($schemeAndHttpHost));
}
} elseif (!empty($this->getServer('ORIG_PATH_INFO'))){
$requestUri = $this->getServer('ORIG_PATH_INFO');
if ('' != $this->getQueryString()){
$requestUri .= '?'.$this->getQueryString();
}
}
return $requestUri;
}
private function prepareBaseUrl(){
$filename = basename($this->getServer('SCRIPT_FILENAME', ''));
$scriptName = $this->getServer('SCRIPT_NAME');
$phpSelf = $this->getServer('PHP_SELF');
$origScriptName = $this->getServer('ORIG_SCRIPT_NAME');
if (basename($scriptName) === $filename){
$baseUrl = $scriptName;
} elseif (basename($phpSelf) === $filename){
$baseUrl = $phpSelf;
} elseif (basename($origScriptName) === $filename){
$baseUrl = $origScriptName;
} else {
$baseUrl = '/';
$basename = $filename;
if ($basename){
$path = ($phpSelf ? trim($phpSelf, '/') : '');
$basePos = strpos($path, $basename) ?: 0;
$baseUrl .= substr($path, 0, $basePos) . $basename;
}
}
$requestUri = $this->getRequestUri();
if (0 === strpos($requestUri, $baseUrl)){
return $baseUrl;
}
$baseDir = str_replace('\\', '/', dirname($baseUrl));
if (0 === strpos($requestUri, $baseDir)){
return $baseDir;
}
$truncatedRequestUri = $requestUri;
if (false !== ($pos = strpos($requestUri, '?'))){
$truncatedRequestUri = substr($requestUri, 0, $pos);
}
$basename = basename($baseUrl);
if (empty($basename) || false === strpos($truncatedRequestUri, $basename)){
$baseUrl = '';
}
return $baseUrl;
}
private function preparePathInfo(){
$baseUrl = $this->getBaseUrl();
$requestUri = $this->getRequestUri();
if ($pos = strpos($requestUri, '?')){
$requestUri = substr($requestUri, 0, $pos);
}
$pathInfo = substr($requestUri, strlen($baseUrl));
return (string) $pathInfo;
}
private function initFromServer(){
$method = $this->getServer('REQUEST_METHOD', 'GET');
if (isset($_POST['_method']) && $method === 'POST') $method = $_POST['_method'];
$this->setMethod($method);
$this->setHost($this->getServer(
'HTTP_HOST',
$this->getServer(
'SERVER_NAME',
$this->getServer('SERVER_ADDR', $this->host))));
$isSecure = !empty($this->getServer('HTTPS')) && $this->getServer('HTTPS') == 'on';
$this->setScheme('http'.($isSecure?'s':''));
$this->setPort($this->getServer('SERVER_PORT', ($isSecure?'443':'80')));
$this->setQueryString($this->getServer('QUERY_STRING'));
$this->setRequestUri($this->prepareRequestUri());
$this->setBaseUrl($this->prepareBaseUrl());
$this->setPathInfo($this->preparePathInfo());
}
private function initFromUri($uri, $method){
$this->setMethod($method);
$components = parse_url($uri);
if (isset($components['host'])){
$this->setHost($components['host']);
}
if (isset($components['scheme'])){
$this->setScheme($components['scheme']);
if ('https' === $components['scheme']){
$this->setPort(443);
}
}
if (isset($components['port'])){
$this->setPort($components['port']);
}
if (isset($components['query'])){
$this->setQueryString($components['query']);
}
if (isset($components['path'])){
$queryString = $this->getQueryString();
$this->setRequestUri($components['path'].('' !== $queryString ? '?'.$queryString : ''));
}
$this->setBaseUrl($this->prepareBaseUrl());
$this->setPathInfo($this->preparePathInfo());
}
public function getServer($server = null, $default = null){
if (is_null($server)) return $_SERVER;
return isset($_SERVER[$server])?$_SERVER[$server]:$default;
}
}
trait ListControllerTrait {
private function listAction(){
$params = $this->router->getRouteParameters();
$criteria = [];
if (isset($params['id'])) $criteria = ['id' => (int)$params['id']];
$data = $this->request->getQuery();
if (isset($data['search'])){
$search = json_decode($data['search'], true);
if (is_null($search)) $search = json_decode('"'.$data['search'].'"');
$criteria = $search;
}
$orderBy = isset($data['order_by'])?$data['order_by']:null;
$offset = isset($data['offset'])?$data['offset']:null;
$limit = (int)(isset($data['limit'])?$data['limit']:24);
$page = isset($data['page'])?$data['page']:1;
if (is_null($offset)){ $offset = ($page-1)*$limit; }
$this->viewModel->setOrderBy($orderBy);
$this->viewModel->setOffset($offset);
$this->viewModel->setLimit($limit);
$this->viewModel->setCriteria($criteria);
}
}
trait FormControllerTrait {
private function formAction()
{
$data = $this->request->getRequest();
if ($this->viewModel->isValid($data)){$this->formAction->success($data);}
else {$this->formAction->failure($data);}
}
}
class FormController{
use FormControllerTrait;
protected $viewModel;
protected $request;
private $formAction;
public function __construct($viewModel, $request, $formAction){
$this->viewModel = $viewModel;
$this->request = $request;
$this->formAction = $formAction;
}
public function action(){$this->formAction();}
}
class FormListController{
use ListControllerTrait;
use FormControllerTrait;
private $formAction;
protected $viewModel;
protected $request;
protected $router;
public function __construct($viewModel, $request, $formAction, $router){
$this->formAction = $formAction;
$this->viewModel = $viewModel;
$this->request = $request;
$this->router = $router;
}
public function action(){
$this->listAction();
$this->formAction();
}
}
class ListController{
use ListControllerTrait;
protected $viewModel;
protected $request;
protected $router;
public function __construct($viewModel, $request, $router){
$this->viewModel = $viewModel;
$this->request = $request;
$this->router = $router;
}
public function action(){$this->listAction();}
}
class Form{
protected $rules;
protected $formatters;
protected $data;
protected $formData;
public function __construct($data = [], $method = 'GET', $action = ''){
$this->rules = [];
$this->setAction($action);
$this->setMethod($method);
$this->data = $data;
$this->formData = [];
$this->formatters = [];
}
private function updateCurrentData(&$data, $key, $value){
if (is_array($data)){$data[$key] = $value;}
else {$data->$key = $value;}
}
private function updateData(&$data, $formData){
foreach ($data as $key => $value){
if (array_key_exists($key, $formData) && $key !== 'id'){
if (is_object($value) || is_array($value)){
if (is_array($data)){
$this->updateData($data[$key], $formData[$key]);
} else {
$this->updateData($data->$key, $formData[$key]);
}
} else {
$value = $this->formatValue($key, $formData[$key]);
$this->updateCurrentData($data, $key, $value);
}
}
}
}
public function getData($name = ''){
$this->updateData($this->data, (empty($name)?$this->formData:$this->formData[$name]));
return $this->data;
}
public function setData($data){$this->data = $data;}
public function setFormatter($name, $fun){$this->formatters[$name] = $fun;}
private function setCurrentFormData(&$formData, $key, $value){
$pos = strpos($key, '[');
if ($pos === false){
if (empty($key) || $key === '_'){$formData = $value;}
else $formData[$key] = $value;
} else {
$currentKey = substr($key,0,$pos);
if (!array_key_exists($currentKey, $formData)){
$formData[$currentKey] = [];
}
$key = substr($key,$pos+1);
$pos = strpos($key, ']');
if ($pos !== false){
$key = substr_replace($key, '', $pos, 1);
}
if ($currentKey !== '_'){
$formData[$currentKey] = $this->setCurrentFormData($formData[$currentKey], $key, $value);
} else {
$formData = $this->setCurrentFormData($formData[$currentKey], $key, $value);
}
}
return $formData;
}
public function setFormData($formData){
$this->formData = [];
foreach ($formData as $key => $value){
$this->setCurrentFormData($this->formData, $key, $value);
}
}
public function getAction(){return $this->rules['*']['action'];}
public function setAction($action){$this->rules['*']['action'] = $action;}
public function getMethod(){
if (isset($this->rules['_method']))
return $this->rules['_method']['value'];
return $this->rules['*']['method'];
}
public function setMethod($method){
switch($method){
case 'GET':
$this->rules['*']['method'] = $method;
break;
case 'POST':
$this->rules['*']['method'] = $method;
break;
default:
$this->rules['*']['method'] = 'POST';
$this->rules['_method'] = [
'type' => 'hidden',
'value' => $method,
];
}
}
public function setRule($name, $rule){$this->rules[$name] = $rule;}
public function getRule($name){return array_key_exists($name, $this->rules)?$this->rules[$name]:[];}
public function generateRules($data, $name){
foreach($data as $key => $value){
if (is_numeric($key)){
$this->generateRules($value, (empty($name)?'_':$name).'['.$key.']');
} else {
$currentName = (empty($name)?'':$name.'[').$key.(empty($name)?'':']');
if (!array_key_exists($key, $this->rules)){
$this->rules[$currentName] = [];
}
if ($this->rules[$currentName] instanceOf Form){
$form = $this->rules[$currentName]->getForm();
foreach ($form as $sub => $rule){
$openingBracket = '[';
$closingBracket = ']';
if ($sub[0] === '_'){
$sub = substr($sub, 1);
$openingBracket = '';
$closingBracket = '';
}
if ($sub !== '*') $this->rules[$currentName.$openingBracket.$sub.$closingBracket] = $rule;
};
unset($this->rules[$currentName]);
} else {
if (!is_null($this->rules[$currentName])){
if (!array_key_exists('type', $this->rules[$currentName])){
$this->rules[$currentName]['type'] = 'text';
}
if (!array_key_exists('value', $this->rules[$currentName])){
$this->rules[$currentName]['value'] = $value;
}
}
}
}
}
}
public function getForm($name = ''){
$this->generateRules($this->data, $name);
return array_filter($this->rules);
}
private function formatValue($name, $value){
if (array_key_exists($name, $this->formatters)){
$value = $this->formatters[$name]($value, $this->formData);
}
return $value;
}
}
class BasicAuthentication{
private $passwordHash;
private $request;
private $session;
private $user;
private $userProvider;
public function __construct($userProvider, $request, $session, $passwordHash){
$this->passwordHash = $passwordHash;
$this->request = $request;
$this->session = $session;
$this->userProvider = $userProvider;
$this->user = null;
}
public function authenticate(){
if ($this->isAuthenticated()){
$this->user = $this->userProvider->loadUser(['username' => $this->session->get('username')]);
return 2;
}
$secretCaptcha = $this->session->get('secret_captcha', (new \DateTime())->format('is'));
$secret = $this->session->get('secret', $secretCaptcha);
$username = $this->request->getServer('PHP_AUTH_USER');
$password = $this->request->getServer('PHP_AUTH_PW');
if (is_null($username) || is_null($password)){
return 5;
}
$user = $this->userProvider->loadUser(['username' => $username]);
if (is_null($user)){
return 3;
}
$userPassword = null;
if (is_array($user)){ $userPassword = $user['password']; }
else { $userPassword = $user->password; }
if ($this->passwordHash->hash($password, $username) !== $userPassword){
return 4;
}
if ($secret !== $secretCaptcha){
$this->session->remove('secret');
return 5;
}
$this->user = $user;
$this->session->set('uid', sha1(uniqid('', true).'_'.mt_rand()));
$this->session->set('username', $username);
$this->session->set('secret', $secret);
return 1;
}
public function deauthenticate(){
$this->user = null;
$this->session->remove(['secret_captcha', 'uid']);
}
public function getUser(){
return $this->user;
}
public function isAuthenticated(){
return ((bool)$this->session->get('uid', false)) && ((bool)$this->session->get('username', false));
}
}
class UserProvider{
private $userModel;
public function __construct($userModel){$this->userModel = $userModel;}
public function loadUser($criteria){return $this->userModel->findOneBy($criteria);}
}
class SessionAuthentication{
private $passwordHash;
private $request;
private $session;
private $user = null;
private $userProvider;
private $inactivityTimeout = 3600;
private $sessionName = '';
private $disableSessionProtection = false;
public function __construct($userProvider, $request, $session, $passwordHash, $options = []){
$this->passwordHash = $passwordHash;
$this->request = $request;
$this->session = $session;
$this->userProvider = $userProvider;
$this->loadOptions($options);
$cookie = session_get_cookie_params();
$cookiedir = '';
if (dirname($this->request->getServer('SCRIPT_NAME', ''))!='/'){
$cookiedir = dirname($this->request->getServer('SCRIPT_NAME', '')).'/';
}
$ssl = true;
if ($this->request->getServer('HTTPS','') !== 'on'){
$ssl = false;
}
if (!session_id()){
session_set_cookie_params($cookie['lifetime'], $cookiedir, $this->request->getServer('HTTP_HOST'), $ssl);
ini_set('session.use_cookies', 1);
ini_set('session.use_only_cookies', 1);
ini_set('session.use_trans_sid', false);
if (!empty($this->sessionName)){
session_name($this->sessionName);
}
session_start();
}
}
public function authenticate(){
if ($this->isAuthenticated()){
$this->user = $this->userProvider->loadUser(['username' => $this->session->get('username')]);
return 2;
}
$request = $this->request->getRequest();
if (!array_key_exists('username', $request) || !array_key_exists('password', $request)){
return 5;
}
$username = $request['username'];
$password = $request['password'];
$user = $this->userProvider->loadUser(['username' => $username]);
if (is_null($user)){
return 3;
}
$userPassword = null;
if (is_array($user)){ $userPassword = $user['password']; }
else { $userPassword = $user->password; }
if ($userPassword !== $this->passwordHash->hash($password, $username)){
return 4;
}
$this->user = $user;
$this->session->set('uid', sha1(uniqid('', true).'_'.mt_rand()));
$this->session->set('ip', $this->allIPs());
$this->session->set('username', $username);
$this->session->set('expires_on', time() + $this->inactivityTimeout);
return 1;
}
public function deauthenticate(){
$this->user = null;
$this->session->remove(['uid', 'ip', 'expires_on']);
}
public function getUser(){return $this->user;}
public function isAuthenticated(){
if (!(bool)$this->session->get('uid', false)
|| ($this->disableSessionProtection === false
&& $this->session->get('ip') !== $this->allIPs())
|| time() >= $this->session->get('expires_on')){
$this->deauthenticate();
return false;
}
$this->session->set('expires_on', time() + $this->inactivityTimeout);
if (!empty($this->session->get('longlastingsession'))){
$this->session->set('expires_on', $this->session->get('expires_on') + $this->session->get('longlastingsession'));
}
return true;
}
private function allIPs(){
return $this->request->getServer('REMOTE_ADDR','')
.'_'.$this->request->getServer('HTTP_X_FORWARDED_FOR', '')
.'_'.$this->request->getServer('HTTP_CLIENT_IP', '');
}
private function loadOptions($options){
foreach($options as $key => $option){
if (in_array($key, ['disableSessionProtection', 'inactivityTimeout', 'sessionName'])){
$this->$key = $option;
}
}
}
}
class PrivateRequestAuthorization{
private $authentication;
private $request;
public function __construct($authentication, $request){
$this->authentication = $authentication;
$this->request = $request;
}
public function isGranted(){
if ($this->request->getPathInfo() == '/login/'){return true;}
else {return $this->authentication->isAuthenticated();}
}
}
class ProtectedRequestAuthorization{
private $authentication;
private $request;
public function __construct($authentication, $request){
$this->authentication = $authentication;
$this->request = $request;
}
public function isGranted(){
if ($this->request->getMethod() === 'GET'){return true;}
else {return $this->authentication->isAuthenticated();}
}
}
class HashPassword{
private $salt;
public function __construct($salt = 'a18c1239f19135e3072d931c1050603f4f405194'){
$this->$salt = $salt;
}
public function hash($password, $username = ''){
return sha1($password.$username.$this->salt);
}
}
class App{
private $container;
private $plugins = [];
private $configs = [];
public function __construct($container){
$this->container = $container;
$this->container->set('Request', [
'instanceOf' => 'Request',
'shared' => true,
]);
$this->container->set('Router', [
'instanceOf' => 'RequestRouter',
'shared' => true,
'constructParams' => [
['instance' => 'Request'],
],
]);
}
public function getContainer(){return $this->container;}
public function addPlugin($name){
call_user_func_array($name, [$this]);
$this->plugins[] = $name;
}
public function configPlugin($name, $config){$this->configs[$name] = $config;}
public function run(){
$container = $this->container;
$next = function() use ($container){
$request = $container->get('Request');
return $container->get('Router')->dispatch($request->getMethod(), $request->getPathInfo());
};
foreach($this->plugins as $plugin){
$params = [$this, $next];
if (array_key_exists($plugin, $this->configs)){
$params = array_merge($params, $this->configs[$plugin]);
}
$next = call_user_func_array($plugin, $params);
}
$response = $next();
$response->send();
}
}
class Validator{
private $errors = [];
private $constraints = [];
private function getProperty($data, $name){
$value = null;
if (is_array($data) && array_key_exists($name, $data)){
$value = $data[$name];
}
if (is_object($data) && isset($data->$name)){
$value = $data->$name;
}
return $value;
}
private function setConstraint($name, $rule, $params = [], $error = ''){
if (empty($error)) $error = $name.' '.$rule.' Error';
$this->constraints[$name][] = [$rule, $params, $error];
}
public function setConstraints($name, $constraints = []){
$this->constraints[$name] = [];
foreach ($constraints as $constraint){
call_user_func_array(array($this, 'setConstraint'), array_merge([$name], $constraint));
}
}
public function getConstraints($name){
return array_key_exists($name, $this->constraints)?$this->constraints[$name]:[];
}
public function isValid($data){
$this->errors = [];
foreach($this->constraints as $name => $constraints){
$value = $this->getProperty($data, $name);
foreach($constraints as $constraint){
list($rule, $params, $error) = $constraint;
switch($rule){
case 'email':
if (filter_var($value, FILTER_VALIDATE_EMAIL) === false && !is_null($value)){
$this->errors[$name][] = $error;
}
break;
case 'inArray':
if (!in_array($value, $params[0])){
$this->errors[$name][] = $error;
}
break;
case 'numMin':
if ($value < $params[0]){
$this->errors[$name][] = $error;
}
break;
case 'numMax':
if ($value > $params[0]){
$this->errors[$name][] = $error;
}
break;
case 'minLength':
if (strlen($value) < $params[0]){
$this->errors[$name][] = $error;
}
break;
case 'required':
if (is_null($value)){
$this->errors[$name][] = $error;
}
break;
case 'closure':
if (!$params[0]($value, $data)){
$this->errors[$name][] = $error;
}
break;
default:
throw new \Exception($rule.' validation is not defined');
}
}
}
return empty($this->errors);
}
public function getErrors(){
return $this->errors;
}
}
class Bang {
public $bang = '!?';
public $url = 'https://duckduckgo.com';
public $pattern = 'https://duckduckgo.com/?q=kriss_bang';
}
$app = new App(new Container());
$container = $app->getContainer();
$isUnique = function($value, $data) use ($container){
$model = $container->get('#bang_model');
$bang = $model->findOneBy(['bang' => $value]);
$validId = true;
if (!is_null($bang)){
$validId = false;
$refId = ((array)$bang);
$refId = $refId['id'];
$checkId = '';
if (isset($data['id'])) $checkId = (int)$data['id'];
else {
$params = $container->get('Router')->getRouteParameters();
$checkId = isset($params['id'])?((int)$params['id']):'';
};
$validId = ($refId === $checkId);
}
return $validId;
};
$container->set('$bang_validator', [
'instanceOf' => 'Validator',
'call' => [
['setConstraints', [
'bang', [['closure', [$isUnique], 'bang already exists']],
]],
],
]);
$routerRule = $container->getRule('Router');
$container->set('Router', [
'call' => array_merge([
['setRoute', [
'kriss_bang_index', 'GET', '/',
function () use ($container){
$request = $container->get('Request');
$query = $request->getQuery();
if (isset($query['bang'])){
$router = $container->get('Router');
if (empty($query['bang'])) return new RedirectResponse($router->generate('kriss_bang_index'));
$model = $container->get('#bang_model');
$str = null;
if (preg_match('/![^ ]*/', $query['bang'], $matches)){
$str = $matches[0];
} else {
$str = '!?';
}
$bang = $model->findOneBy(['bang' => $str]);
if (is_null($bang)){
$bang = $container->get('Bang');
$bang->pattern .= ' '.$str;
}
$search = trim(preg_replace('/![^ ]*/', '', $query['bang']));
if (empty($search)){
return new RedirectResponse($bang->url);
} else {
return new RedirectResponse(trim(preg_replace('/kriss_bang/', urlencode($search), $bang->pattern)));
}
}
$router = $container->get('Router');
$authLink = '';
if ($container->has('Authentication')){
$authentication = $container->get('Authentication');
$authUrl = $router->generate('login');
$auth = 'Login';
if ($authentication->isAuthenticated()){
$authUrl = $router->generate('logout');
$auth = 'Logout';
}
$authLink = ''.$auth.'';
}
$faviconUrl = $router->generate('kriss_bang_favicon');
$xmlUrl = $router->generate('kriss_bang_xml');
$updateCsvUrl = $router->generate('kriss_bang_update_csv');
$exportCsvUrl = $router->generate('kriss_bang_export_csv');
$indexUrl = $router->generate('kriss_bang_index');
$bangListUrl = $router->generate('autoroute_index', ['slug' => 'bang']);
$configUrl = $router->generate('autoroute_index', ['slug' => 'config']);
$adminUrl = $router->generate('autoroute_index', ['slug' => 'admin']);
$response = <<
KrISS bang
KrISS bang
Bang list Export CSV Upload CSV Config Admin
$authLink
html;
return new Response($response);
}
]],
['setRoute', [
'kriss_bang_favicon', 'GET', '/favicon.ico',
function () use ($container){
$favicon = <<get('Router');
$faviconUrl = $router->generate('kriss_bang_favicon', []);
$searchUrl = urldecode($router->generate('kriss_bang_index', ['bang' => '{searchTerms}']));
$response = <<KrISS bangKrISS bangbang$faviconUrl
xml;
return new Response($response, [['Content-Type', 'application/opensearchdescription+xml']]);
}
]],
['setRoute', [
'kriss_bang_update_csv', ['GET', 'POST'] ,'/update-csv/',
function () use ($container){
$request = $container->get('Request');
if ($request->getMethod() === 'GET'){
$router = $container->get('Router');
$faviconUrl = $router->generate('kriss_bang_favicon', []);
$indexUrl = $router->generate('kriss_bang_index');
$updateCsvUrl = $router->generate('kriss_bang_update_csv', []);
$response = <<
KrISS bang