ViewRoot.php
<?php
namespace Fresh;
class ViewRoot {
use \Fresh\Readonly;
protected $file;
private $r_file;
protected $name;
private $r_name;
protected $src;
private $r_src;
protected $handler;
private $r_handler;
protected $compFile;
protected $passthru = [];
private $r_passthru;
protected $setupCode = [];
protected $component;
private $r_component;
/**
*
*
*/
public function __construct($component,$viewName,$passthru=[]){
$this->component = $component;
$this->file = $this->fileFor($viewName);
$this->name = $viewName;
$this->passthru = $passthru;
$this->handler = new \Fresh\Handler();
$this->addRuntimeHandler('compileAndAddResources',[$this,'compileResourcesAndOutsource']);
$this->src = file_get_contents($this->file);
$this->compFile = $this->compileFileFor($viewName);
$this->initialize();
}
public function compileResourcesAndOutsource(){
$c = 0;
$list = [
'css'=>[],
'js'=>[],
'php'=>[]
];
$name = basename($this->file);
// $name = pathinfo($this->name,PATHINFO_FILENAME);
$name = substr($name,0,strrpos($name,'.'));
$dir = dirname($this->file);
$path = $dir.'/'.$name;
$cssFile = $path.'.css';
if (file_exists($cssFile)){
$list['css'][] = $cssFile;
$c++;
}
$jsFile = $path.'.js';
if (file_exists($jsFile)){
$list['js'][] = $jsFile;
$c++;
}
$resourceDir = $path.'/';
if (is_dir($resourceDir)){
$rii = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($resourceDir));
$files = array();
foreach ($rii as $file) {
if ($file->isDir()){
continue;
}
$c++;
$list[$file->getExtension()][] = $file->getPathname();
}
}
if ($c>0){
/**
* If your view has any resources associated, you must register an addResources handler.
* - `addResources`: `function($viewObj, $resourcesList){...use your framework or whatever...}
* - `$resourcesList` is in the format ['php'=>$arrayOfFiles,'js'=>$arrayOfFiles,'css'...] & so on for EVERY file that is associated with your view.
* - These files are found at `YourViewNameView/some_file.EXTENSION`
* - I think you can do YourViewNameView.css and YourViewNameView.js as well
* - It also works with YourViewNameForm/files....
*
* @export(Handler.Runtime.addResources)
*/
$this->callHandler('addResources',$this,$list);
}
}
protected function fileFor($viewName){
if ($viewName=='')$viewName = 'View';
$file = $this->component->dir.'/view/'.$viewName.'.php';
return $file;
}
protected function compileFileFor($viewName){
return $this->component->dir.'/compiled/'.$viewName.'.php';
}
public function form(){
$form = $this->component->form($this->name);
return $form;
}
public function view(){
$view = $this->component->view($this->name);
return $view;
}
public function setPassthru($passthru){
$this->passthru = $passthru;
}
public function addFormatter($name,$callback){
$this->handler->setHandler('runtime','format_'.$name,$callback);
}
public function addQuery($xpath,$callable){
$this->handler->addHandler('query','all',['xpath'=>$xpath,'callback'=>$callable]);
}
public function addCompileHandler($name,$callable){
$this->handler->addHandler('compile',$name,$callable);
}
/**
* Calling $viewRoot->executeCompileHandlers($handlerName, ...$argsForHandler) will return an array of return values from the called handlers.
*
* @export(Internals.executeCompileHandlers)
*/
protected function executeCompileHandlers($handlerName, ...$args){
// throw new \Exception("working on handlers....");
$handlers = $this->handler->compile->$handlerName;//[$handlerName] ?? null;
// print_r($handlerName);
// throw new \Exception("execute compile handlers blah blah");
// exit;
if ($handlers===null)return;
$ret = [];
foreach ($handlers as $handler){
$ret[] = $handler(...$args);//$this,$rbAttrs,$prop,$attribute->value);
}
return $ret;
}
public function addRuntimeHandler($name,$callable){
$this->handler->addHandler('runtime',$name,$callable);
}
public function setRuntimeHandler($name,$callable){
$this->handler->setHandler('runtime',$name,$callable);
}
public function callHandler($method,...$args){
return $this->handler->callMethod('runtime',$method,$args);
}
public function compile($forceRecompile=false){
$file = $this->file;
$compFile = $this->compFile;
if (!$forceRecompile&&
true&&
file_exists($compFile)&&filemtime($file)<filemtime($compFile)){
return $compFile;
}
$viewContent = file_get_contents($file);
// echo $viewContent."\n\n";
$compiler = new \Taeluf\PHTML\Compiler();
$cleanSource = $compiler->cleanSource($viewContent);
$preDocHandlers = $this->handler->compile->preDoc ?? [];
foreach ($preDocHandlers as $handler){
$cleanSource = $handler($cleanSource,$viewContent,$compiler,$this);
}
$doc = new \Taeluf\PHTML($cleanSource);
$compiler->appendCode($doc);
$queryResults = [];
// foreach ($this->handler->query->all as $qi){
// echo $qi['xpath']."\n\n";
// }
// // print_r($this->handler->query->all);
// exit;
$qRes = [];
foreach ($this->handler->query->all as $queryInfo){
//TODO ...maybe... perform all queries before calling any handlers
$xpath = $queryInfo['xpath'];
$callback = $queryInfo['callback'];
// $xp = new \DOMXpath($doc);
// $nodeList = $xp->query($xpath);
$nodeList = $doc->xpath($xpath);
$qRes[] = [
'callback'=>$callback,
'xpath'=>$xpath,
'nodes'=>$nodeList
];
}
foreach ($qRes as $qi){
foreach ($qi['nodes'] as $node){
$qi['callback']($doc,$this,$compiler,$node);
}
}
// $output = $compiler->output();
// echo "output:\n\n";
// echo $output;
// echo "\n\n\n----done";
// exit;
$compiler->prependCode('<?php $this->callHandler(\'compileAndAddResources\');?>');
$compiler->writeTo($compFile,0660);
$this->writeSetupCode();
return $compFile;
}
/**
* Need to stop blindly extracting passthru, probably...
*
* @extract(TODO.ViewPassthru)
*/
protected function output(){
$compiledFile = $this->compile();
extract($this->passthru);
// var_dump($id);
// exit;
ob_start();
require($compiledFile);
return ob_get_clean();
}
public function __toString(){
$output = $this->output();
return $output;
}
public function writeSetupCode(){
$compDir = dirname($this->compFile).'/setup/';
$setupFile = $compDir.basename($this->compFile);
if (!is_dir($compDir)){
mkdir($compDir,0771,true);
}
file_put_contents($setupFile,implode('',$this->setupCode));
}
public function appendSetupCode($code){
$this->setupCode[] = trim($code);
}
public function setup($passthru=[]){
$compDir = dirname($this->compFile).'/setup/';
$setupFile = $compDir.basename($this->compFile);
extract($passthru);
if (file_exists($setupFile))require($setupFile);
}
}