Skip to content

Commit

Permalink
PHP MVC Framework
Browse files Browse the repository at this point in the history
  • Loading branch information
zinzinx8 committed Jul 25, 2021
0 parents commit 0b13b66
Show file tree
Hide file tree
Showing 22 changed files with 1,180 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/vendor/
105 changes: 105 additions & 0 deletions Application.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<?php
/**
* @link https://framework.iziweb.net
* @copyright Copyright (c) 2021 Izi Software LLC
* @license https://framework.iziweb.net/license
*/

namespace app\core;

use app\controllers\Controller;
use app\core\db\Database;
use app\core\db\DbModel;

/**
* Class Application
* @package app\core
* @author Giàng A Tỉn <vantruong1898@gmail.com>
* @since 1.0
* @var $userClass app\models\User
*/
class Application
{
public string $layout = 'main';
public string $userClass;
public static string $ROOT_DIR;
public Router $router;
public Request $request;
public Response $response;
public Session $session;
public Database $db;
public ?DbModel $user;
public ?Controller $controller = null;
public View $view;
public static Application $app;

public function __construct($rootPath, array $config)
{
self::$ROOT_DIR = $rootPath;
self::$app = $this;
$this->userClass = $config['user']['class'];
$this->request = new Request();
$this->response = new Response();
$this->session = new Session();
$this->router = new Router($this->request, $this->response);
$this->db = new Database($config['db']);
$this->view = new View();

$primaryValue = $this->session->get('user');
if($primaryValue){
$primaryKey = $this->userClass::primaryKey();
$this->user = $this->userClass::findOne([$primaryKey => $primaryValue]);
}else{
$this->user = null;
}

}

public function run()
{
try{
echo $this->router->resolve();
}catch (\Exception $e){
$this->response->setStatusCode($e->getCode());
echo $this->view->renderView('_error', [
'exception' => $e
]);
}
}

/**
* @return Controller
*/
public function getController(): Controller
{
return $this->controller;
}

/**
* @param Controller $controller
*/
public function setController(Controller $controller): void
{
$this->controller = $controller;
}

public function login(DbModel $user): bool
{
$this->user = $user;
$primaryKey = $user->primaryKey();
$primaryValue = $user->{$primaryKey};
$this->session->set('user', $primaryValue);
return true;
}

public function logout()
{
$this->user = null;
$this->session->remove('user');
}

public static function isGuest(): bool
{
return !self::$app->user;
}
}
168 changes: 168 additions & 0 deletions Model.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
<?php
/**
* @link https://framework.iziweb.net
* @copyright Copyright (c) 2021 Izi Software LLC
* @license https://framework.iziweb.net/license
*/

namespace app\core;

/**
* Class Model
*
* @package app\core
* @author Giang A Tin <vantruong1898@gmail.com>
* @since 1.0
*/
abstract class Model
{
public const RULE_REQUIRED = 'required';
public const RULE_EMAIL = 'email';
public const RULE_MIN = 'min';
public const RULE_MAX = 'max';
public const RULE_MATCH = 'match';
public const RULE_UNIQUE = 'unique';

abstract public function rules() : array;

/**
* @return array
*/
public function labels(): array
{
return [];
}

/**
* @param $attribute
* @return mixed
*/
public function getLabel($attribute)
{
return $this->labels()[$attribute] ?? $attribute;
}
/**
* @param array $data
*/
public function loadData(array $data)
{
foreach ($data as $key=>$value){
if(property_exists($this, $key)){
$this->{$key} = $value;
}
}
}

public array $errors = [];

/**
* @return bool
*/
public function validate(): bool
{
foreach ($this->rules() as $attribute => $rules){
$value = $this->{$attribute};
foreach ($rules as $rule){
$ruleName = $rule;
if(!is_string($ruleName)){
$ruleName = $rule[0];
}

if($ruleName === self::RULE_REQUIRED && !$value){
$this->addErrorForRule($attribute, self::RULE_REQUIRED);
}

if($ruleName === self::RULE_EMAIL && !filter_var($value, FILTER_VALIDATE_EMAIL)){
$this->addErrorForRule($attribute, self::RULE_EMAIL);
}

if($ruleName === self::RULE_MIN && strlen($value) < $rule['min']){
$this->addErrorForRule($attribute, self::RULE_MIN, $rule);
}

if($ruleName === self::RULE_MAX && strlen($value) > $rule['max']){
$this->addErrorForRule($attribute, self::RULE_MAX, $rule);
}
if($ruleName === self::RULE_MATCH && $value !== $this->{$rule['match']}){
$rule['match'] = $this->getLabel($rule['match']);
$this->addErrorForRule($attribute, self::RULE_MATCH, $rule);
}

if($ruleName === self::RULE_UNIQUE){
$className = $rule['class'];
$uniqueAttr = $rule['attribute'] ?? $attribute;
$tableName = $className::tableName();

$statement = Application::$app->db->prepare("SELECT * FROM $tableName WHERE $uniqueAttr = :attr");
$statement->bindValue(":attr", $value);
$statement->execute();
$record = $statement->fetchObject();
if($record){
$this->addErrorForRule($attribute, self::RULE_UNIQUE, ['field' => $this->getLabel($attribute)]);
}

}


}
}

return empty($this->errors);

}

/**
* @param string $attribute
* @param string $rule
* @param array $params
*/
private function addErrorForRule(string $attribute, string $rule, $params = [])
{
$message = $this->errorMessages()[$rule] ?? '';

foreach ($params as $key => $value){
$message = str_replace("{{$key}}","<b>$value</b>", $message);
}

$this->errors[$attribute][] = $message;
}

public function addError(string $attribute, string $message)
{
$this->errors[$attribute][] = $message;
}

/**
* @return string[]
*/
public function errorMessages(): array
{
return [
self::RULE_REQUIRED => 'This field is required',
self::RULE_EMAIL => 'This field must be valid email address',
self::RULE_MIN => 'Min length of this field must be {min}',
self::RULE_MAX => 'Max length of this field must be {max}',
self::RULE_MATCH => 'This field must be the same as {match}',
self::RULE_UNIQUE => 'Record with this field {field} already existed',
];
}


/**
* @param $attribute
* @return false|mixed
*/
public function hasError($attribute)
{
return $this->errors[$attribute] ?? false;
}

/**
* @param $attribute
* @return false|mixed
*/
public function getFirstError($attribute)
{
return $this->errors[$attribute][0] ?? false;
}
}
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# izi-framework
PHP MVC Framework
69 changes: 69 additions & 0 deletions Request.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php
/**
* @link https://framework.iziweb.net
* @copyright Copyright (c) 2021 Izi Software LLC
* @license https://framework.iziweb.net/license
*/

namespace app\core;

/**
* Class Request
*
* @package app\core
* @author Giang A Tin <vantruong1898@gmail.com>
* @since 1.0
*/
class Request
{
public function getPath()
{
$path = $_SERVER['REQUEST_URI'] ?? '/';
$position = strpos($path, '?');
if($position === false){
return $path;
}

return substr($path,0, $position);
}

public function method(): string
{
return strtolower($_SERVER['REQUEST_METHOD']);
}

/**
* @return bool
*/
public function isGet(): bool
{
return $this->method() === 'get';
}

/**
* @return bool
*/
public function isPost(): bool
{
return $this->method() === 'post';
}

public function getBody()
{
$body = [];
if($this->method() === 'get' && !empty($_GET)){
foreach ($_GET as $key => $value){
$body[$key] = filter_input(INPUT_GET, $key, FILTER_SANITIZE_SPECIAL_CHARS);
}
}

if($this->method() === 'post' && !empty($_POST)){
foreach ($_POST as $key => $value){
$body[$key] = filter_input(INPUT_POST, $key, FILTER_SANITIZE_SPECIAL_CHARS);
}
}


return $body;
}
}
28 changes: 28 additions & 0 deletions Response.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php
/**
* @link https://framework.iziweb.net
* @copyright Copyright (c) 2021 Izi Software LLC
* @license https://framework.iziweb.net/license
*/

namespace app\core;

/**
* Class Response
*
* @package app\core
* @author Giang A Tin <vantruong1898@gmail.com>
* @since 1.0
*/
class Response
{
public function setStatusCode(int $code)
{
http_response_code($code);
}

public function redirect(string $url, int $code = 302)
{
header("Location: $url", true, $code);
}
}
Loading

0 comments on commit 0b13b66

Please sign in to comment.