Currently I am working on a simple MVC framework of mine. So my Core library loads the controller and method based on the URL with the given parameters. This happens in the following way:
localhost/application/controller/method/param1/param2
Core: Code for loading controller and method
class Core {
protected $currentController = "Pages";
protected $currentMethod = "Index";
protected $params = [];
public function __construct() {
$url = $this->getURL();
// Look in controllers/ for first value
if(!is_null($url)) {
if(file_exists("../app/controllers/".ucwords($url[0]).".php")) {
// Set as Controller
$this->currentController = ucwords($url[0]);
// Unset 0th index
unset($url[0]);
}
}
// Require Controller
require_once '../app/controllers/'.$this->currentController.'.php';
// Instantiate Controller
$this->currentController = new $this->currentController;
// Check for second part of URL
if(isset($url[1])) {
// If method exists in controller
if(method_exists($this->currentController, $url[1])) {
$this->currentMethod = $url[1];
unset($url[1]);
}
}
}
public function getURL() {
if(isset($_GET['url'])) {
$url = rtrim($_GET['url'], '/');
$url = filter_var($url, FILTER_SANITIZE_URL);
$url = explode('/', $url);
return $url;
}
}
}
The parameters are an array after exploding the URL. This is done by using call_user_func_array([$controller, $method], $params)
. To prevent user from passing incorrect parameters in URL I came up with the following solution using Reflection to check whether correct number and types of parameters are passed.
Core
class Core {
public function __construct(){
$url = $this->getUrl();
// After loading correct Model and Controller (and called method)...
// Get params - Any values left over in url are params
$this->params = $url ? array_values($url) : [];
$this->params = $this->correctURLTypes($this->params);
$r = new ReflectionMethod($this->currentController, $this->currentMethod);
$requiredArgs = $this->numberOfRequiredArgs(); // Only Required params not optional
$totalArgs = $r->getNumberOfParameters(); // Total no. of params in method (required + optional)
$givenArgs = count($this->params);
if($givenArgs >= $requiredArgs && $givenArgs <= $totalArgs) {
// get params at index 1, 2, 3 ... $givenArgs
for ($i = 0; $i < $givenArgs; $i++) {
$param = new ReflectionParameter(array($this->currentController, $this->currentMethod), $i);
$paramType = $param->getType();
if($paramType == 'string') $this->params[$i] = (string) $this->params[$i];
// cast int/bool/float if expecting string
$givenType = Utils::typeOf($this->params[$i]); // static function to return type of variable
if(!is_null($paramType) && $paramType != $givenType) { // if type specified and dont match
die("Types dont match");
}
}
call_user_func_array([$this->currentController, $this->currentMethod], $this->params);
} else {
die("Arg count incorrect");
}
}
public function getUrl(){
if(isset($_GET['url'])){
$url = rtrim($_GET['url'], '/');
$url = filter_var($url, FILTER_SANITIZE_URL);
$url = explode('/', $url);
return $url;
}
}
public function correctURLTypes($arr) {
foreach ($arr as $key => $value) {
// string, int, float, bool ONLY
if(is_numeric($value)) {
if(ctype_digit($value)) {
$arr[$key] = (int) $value;
} else {
$val = $value+0;
if(is_float($val)) {
$arr[$key] = (float) $value;
}
}
} else {
if(in_array($value, ['true', 'false'])) {
if($value == 'true')
$arr[$key] = true;
else
$arr[$key] = false;
} else {
$arr[$key] = (string) $value;
}
}
}
return $arr;
}
public function numberOfRequiredArgs() {
$r = new ReflectionMethod($this->currentController, $this->currentMethod);
$required = 0;
foreach ($r->getParameters() as $key => $val) {
if(!$val->isDefaultValueAvailable()) $required++;
}
return $required;
}
}
So a method can be called which has required type specified and may have optional parameters like: public function show(int $id, bool $edit = true) {
I was unsure if this is a good way of doing it and if its a hack. I wanted feedback and suggestions for loading the methods and parameters in such a way. Complete Core: Core
Aucun commentaire:
Enregistrer un commentaire