A super easy PHP Framework for web development!
https://github.com/exacti/phacil-framework
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
425 lines
12 KiB
425 lines
12 KiB
<?php
|
|
/*
|
|
* Copyright © 2021 ExacTI Technology Solutions. All rights reserved.
|
|
* GPLv3 General License.
|
|
* https://exacti.com.br
|
|
* Phacil PHP Framework - https://github.com/exacti/phacil-framework
|
|
*/
|
|
|
|
namespace Phacil\Framework;
|
|
|
|
use Phacil\Framework\Config;
|
|
use Phacil\Framework\Registry;
|
|
|
|
/**
|
|
* Extend this class to create interation with your module controller to Phacil engine controller.
|
|
*
|
|
* Use as:
|
|
* <code>
|
|
* <?php
|
|
* namespace YourPrefix\Path\Controller;
|
|
* class YouClass extends \Phacil\Framework\Controller {
|
|
* public function index() {
|
|
* #Your code
|
|
* }
|
|
* }
|
|
* </code>
|
|
*
|
|
* You can use the __construct function on call the \Phacil\Framework\Register object inside parent.
|
|
*
|
|
* <code>
|
|
* public funcion __construct(\Phacil\Framework\Registry $registry){ parent::__construct($registry); YOUR_CODE; }
|
|
* </code>
|
|
*
|
|
* @abstract
|
|
* @package Phacil\Framework
|
|
* @since 0.1.0
|
|
* @api
|
|
*/
|
|
abstract class Controller implements \Phacil\Framework\Interfaces\Controller {
|
|
/**
|
|
*
|
|
* @var Registry
|
|
*/
|
|
protected $registry;
|
|
|
|
/**
|
|
*
|
|
* @var int
|
|
*/
|
|
protected $id;
|
|
|
|
/**
|
|
*
|
|
* @var mixed
|
|
*/
|
|
protected $layout;
|
|
|
|
/**
|
|
* The template path
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $template;
|
|
|
|
/**
|
|
* The childrens parts of the controller
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $children = array();
|
|
|
|
/**
|
|
* The variables of controller
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $data = array();
|
|
|
|
/**
|
|
* The twig aditional funcions created by your!
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $twig = array();
|
|
|
|
/**
|
|
* The errors array
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $error = array();
|
|
|
|
/**
|
|
* The rendered output
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $output;
|
|
|
|
/**
|
|
* The original route of childrens
|
|
* @var string
|
|
*/
|
|
public $routeOrig;
|
|
|
|
/**
|
|
* The output content type
|
|
*
|
|
* @var string
|
|
*/
|
|
public $contentType = 'text/html; charset=utf-8';
|
|
|
|
/**
|
|
* Implements constructor.
|
|
*
|
|
* If you use this, don't forget the parent::__construct($registry);
|
|
*
|
|
* @param \Phacil\Framework\Registry $registry
|
|
* @return void
|
|
*/
|
|
public function __construct(\Phacil\Framework\Registry $registry = null) {
|
|
if (!$registry) {
|
|
|
|
/**
|
|
* @var \Phacil\Framework\Registry
|
|
*/
|
|
$registry = \Phacil\Framework\Registry::getInstance();
|
|
}
|
|
$this->registry = &$registry;
|
|
}
|
|
|
|
/** @return void */
|
|
private function __getRegistryClass(){
|
|
$this->registry = \Phacil\Framework\startEngineExacTI::getRegistry();
|
|
}
|
|
|
|
/**
|
|
*
|
|
* {@inheritdoc}
|
|
*/
|
|
static public function getInstance() {
|
|
$class = get_called_class();
|
|
return \Phacil\Framework\Registry::getAutoInstance((new $class()));
|
|
}
|
|
|
|
/**
|
|
* @param string $key
|
|
* @return object
|
|
* @final
|
|
*/
|
|
final public function __get($key) {
|
|
if (!$this->registry) {
|
|
$this->__getRegistryClass();
|
|
}
|
|
|
|
return $this->registry->get($key);
|
|
}
|
|
|
|
/**
|
|
* @param string $key
|
|
* @return object
|
|
* @final
|
|
* @todo Not yet...
|
|
*/
|
|
/* final public function __call($key, array $arguments) {
|
|
if (!$this->registry) {
|
|
$this->__getRegistryClass();
|
|
}
|
|
|
|
return $this->registry->get($key);
|
|
} */
|
|
|
|
/**
|
|
*
|
|
* @param string $key
|
|
* @param object $value
|
|
* @return void
|
|
* @final
|
|
*/
|
|
final public function __set($key, $value) {
|
|
if(!$this->registry) {
|
|
$this->__getRegistryClass();
|
|
}
|
|
|
|
$this->registry->set($key, $value);
|
|
}
|
|
|
|
/**
|
|
* @param string $route
|
|
* @param array $args
|
|
* @return \Phacil\Framework\Interfaces\Action
|
|
* @final
|
|
*/
|
|
final protected function forward($route, array $args = array()) {
|
|
return new Action($route, $args);
|
|
}
|
|
|
|
/**
|
|
* Send redirect HTTP header to specified URL
|
|
*
|
|
* Use the \Phacil\Framework\Response::redirect() registered object.
|
|
*
|
|
* @param string $url
|
|
* @param int $status
|
|
* @return never
|
|
* @final
|
|
*/
|
|
final protected function redirect($url, $status = 302) {
|
|
$this->registry->response->redirect($url, $status);
|
|
}
|
|
|
|
/**
|
|
* Get and load the childrens controller classes
|
|
*
|
|
* @final
|
|
* @param string $child
|
|
* @param array $args
|
|
* @return object
|
|
*/
|
|
final protected function getChild($child, array $args = array()) {
|
|
$action = new Action($child, $args);
|
|
$file = $action->getFile();
|
|
$class = $action->getClass();
|
|
$classAlt = $action->getClassAlt();
|
|
$method = $action->getMethod();
|
|
|
|
if ($file && file_exists($file)) {
|
|
require_once($file);
|
|
|
|
foreach($classAlt as $classController){
|
|
try {
|
|
if(class_exists($classController)){
|
|
$this->registry->routeOrig = $child;
|
|
$controller = $this->registry->injectionClass($classController);
|
|
//$controller = new $classController($this->registry);
|
|
if (is_callable([$controller, $method])) {
|
|
call_user_func_array(array($controller, $method), $args);
|
|
} else {
|
|
throw new \Phacil\Framework\Exception("Error Processing Request", 1);
|
|
}
|
|
|
|
break;
|
|
}
|
|
} catch (\Phacil\Framework\Exception\Throwable $th) {
|
|
throw $th;
|
|
}
|
|
}
|
|
|
|
$this->registry->routeOrig = null;
|
|
|
|
return $controller->output;
|
|
|
|
} elseif (!$file && isset($classAlt['class']) && !empty($classAlt['class']) && class_exists($classAlt['class'])) {
|
|
try {
|
|
$this->registry->routeOrig = $child;
|
|
$controller = $this->registry->injectionClass($classAlt['class']);
|
|
if (is_callable(array($controller, $method))) {
|
|
call_user_func_array(array($controller, $method), $args);
|
|
} else {
|
|
throw new \Phacil\Framework\Exception("Error Processing Request", 1);
|
|
}
|
|
|
|
$this->registry->routeOrig = null;
|
|
|
|
return $controller->output;
|
|
} catch (\Phacil\Framework\Exception\Throwable $th) {
|
|
throw ($th);
|
|
}
|
|
} else {
|
|
throw new Exception("Could not load controller " . $child . '!', 1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Render template
|
|
*
|
|
* @return string
|
|
* @throws TypeError
|
|
* @throws Exception
|
|
* @final
|
|
*/
|
|
protected function render() {
|
|
|
|
foreach ($this->children as $child) {
|
|
$this->data[basename($child)] = $this->getChild($child);
|
|
}
|
|
|
|
/**
|
|
* @var \Phacil\Framework\Render
|
|
*/
|
|
$tpl = $this->registry->getInstance("Phacil\Framework\Render");
|
|
|
|
$pegRout = explode("/", ($this->registry->routeOrig)?: \Phacil\Framework\startEngineExacTI::getRoute());
|
|
|
|
if($this->template === NULL) {
|
|
$thema = ($this->config->get("config_template") != NULL) ? $this->config->get("config_template") : "default";
|
|
|
|
$noCaseFunction = function ($str) {
|
|
return \Phacil\Framework\Registry::case_insensitive_pattern($str);
|
|
};
|
|
|
|
//Just template not set manual
|
|
$routePatterned = array_map($noCaseFunction, $pegRout);
|
|
$routeWithoutLastPatterned = $routePatterned;
|
|
$lastRoutePatterned = array_pop($routeWithoutLastPatterned);
|
|
//$routeWithoutFirstPatterned = $routePatterned;
|
|
//$firstRoutePatterned = array_shift($routeWithoutFirstPatterned);
|
|
|
|
$structure = [];
|
|
|
|
if ($thema != "default")
|
|
$structure[self::TEMPLATE_AREA_THEME][] = $thema . '/' . implode("/", $routePatterned);
|
|
|
|
$structure[self::TEMPLATE_AREA_THEME][] = 'default/' . implode("/", $routePatterned);
|
|
|
|
$positions = 2;
|
|
|
|
for ($i=1; $i <= $positions; $i++) {
|
|
if(count($routePatterned) <= ($i)) break;
|
|
|
|
$mount = $routePatterned;
|
|
array_splice($mount, $i, 0, 'View');
|
|
$structure[self::TEMPLATE_AREA_MODULAR][] = implode("/", $mount);
|
|
|
|
if(($i+1) < count($routePatterned))
|
|
$structure[self::TEMPLATE_AREA_MODULAR][] = implode("/", array_slice($mount, 0, -1)). "_" .end($mount);
|
|
}
|
|
|
|
if (count($routePatterned) > 2) {
|
|
//Old compatibility
|
|
if($thema != "default")
|
|
$structure[self::TEMPLATE_AREA_THEME][] = $thema . '/' . implode("/", $routeWithoutLastPatterned) . '_' . $lastRoutePatterned ;
|
|
|
|
$structure[self::TEMPLATE_AREA_THEME][] = 'default/' . implode("/", $routeWithoutLastPatterned) . '_' . $lastRoutePatterned;
|
|
}
|
|
|
|
//Check if theme exists
|
|
$findThemeFile = (function(array $structure, $pathArea) use ($tpl) {
|
|
foreach ($structure as $themefile) {
|
|
$types = [
|
|
'modular' => $pathArea . $themefile,
|
|
];
|
|
$files['modular'] = null;
|
|
foreach ($types as $type => $globs) {
|
|
foreach ($tpl->getTemplateTypes() as $extensionTemplate) {
|
|
$files[$type] = glob($globs . "." . $extensionTemplate, GLOB_BRACE);
|
|
if (count($files[$type]) > 0) break;
|
|
}
|
|
}
|
|
if (empty($files['modular'])) continue;
|
|
if (!empty($files['modular'])) {
|
|
foreach ($files['modular'] as $modular) {
|
|
$this->template = str_replace($pathArea, "", $modular);
|
|
return $templatePath = $pathArea;
|
|
break;
|
|
}
|
|
}
|
|
if (!empty($this->template)) break;
|
|
}
|
|
});
|
|
|
|
$templatePath = $findThemeFile($structure[self::TEMPLATE_AREA_THEME], Config::DIR_TEMPLATE()) ?: $findThemeFile($structure[self::TEMPLATE_AREA_MODULAR], Config::DIR_APP_MODULAR());
|
|
} else {
|
|
if(file_exists(Config::DIR_APP_MODULAR(). $pegRout[0] ."/View/" .$this->template)){
|
|
$templatePath = Config::DIR_APP_MODULAR(). $pegRout[0] ."/View/";
|
|
} else {
|
|
$filesSeted = glob(
|
|
Config::DIR_APP_MODULAR() .
|
|
\Phacil\Framework\Registry::case_insensitive_pattern($pegRout[0])
|
|
. "/View/" . $this->template,
|
|
GLOB_BRACE
|
|
);
|
|
|
|
if (count($filesSeted) > 0) {
|
|
$templatePath = str_replace($this->template, "", $filesSeted[0]);
|
|
}
|
|
}
|
|
|
|
if(file_exists(Config::DIR_TEMPLATE() .$this->template)){
|
|
$templatePath = Config::DIR_TEMPLATE();
|
|
}
|
|
}
|
|
|
|
if(empty($this->template)) {
|
|
throw new Exception('Error: template not seted!');
|
|
}
|
|
|
|
if (is_readable($templatePath . $this->template)) {
|
|
|
|
$templateFileInfo = pathinfo($templatePath .$this->template);
|
|
$templateType = $templateFileInfo['extension'];
|
|
|
|
$tpl->setTemplate($templateType, $templatePath, $this->template, $this->data, $this->twig);
|
|
|
|
$this->registry->response->addHeader('Content-Type', $this->contentType);
|
|
|
|
$this->output = $tpl->render();
|
|
|
|
unset($tpl);
|
|
|
|
return $this->output;
|
|
|
|
} else {
|
|
throw new Exception('Error: Could not load template ' . $templatePath . $this->template . '!');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param bool $commonChildren (optional) Whether to include the common children
|
|
* @return \Phacil\Framework\Response
|
|
* @throws Exception
|
|
* @since 1.1.0
|
|
*/
|
|
protected function out ($commonChildren = true) {
|
|
if($commonChildren === true){
|
|
$this->children = array_merge(array(
|
|
'common/footer',
|
|
'common/header'), $this->children
|
|
);
|
|
}
|
|
|
|
return $this->response->setOutput($this->render());
|
|
}
|
|
}
|
|
|
|
|