<?php
namespace Lia\Addon;
/**
* @todo enable fallback-namespacing when default namespace (null) is not set. So you can add view `lia:theme`, then load view `theme` and get `lia:theme`
* @warning conflictMode has a weird interaction with null-namespace views. If you add `ns:viewname`, then try to add `viewname` a conflict will now be generated because `ns:viewname` sets null-namespace `viewname`.
*/
class View extends \Lia\Addon {
/**
* Views to be loaded.
* @structure `['namespace'=>['view/name'=>$view_callable]]`
*/
public $views = [null=>[]];
/**
* Args to pass to every view
*
*/
public array $globalArgs = [];
/**
* What to do when there is a new view added where one already existed
*
* @option throw - throw an exception
* @option ignore - don't add the new view (use the old one)
* @option overwrite - replace the old view with the new one
*
*/
public string $conflictMode = 'throw';
public function __construct($lia=null, $name=null){
parent::__construct($lia, $name);
$this->props['views'] = &$this->views;
$this->props['conflictMode'] = $this->props['conflictMode'] ?? $this->conflictMode;
$this->conflictMode = &$this->props['conflictMode'];
$this->props['globalArgs'] = $this->props['globalArgs'] ?? $this->globalArgs;
$this->globalArgs = &$this->props['globalArgs'];
$this->methods['setViewConflictMode'] = [$this, 'setConflictMode'];
$this->methods['addViewCallable'] = [$this, 'addCallable'];
$this->methods['addView'] = [$this, 'addViewHandler'];
$this->methods['view'] = [$this, 'view'];
}
/**
* add a callable as a view
*
* @param $viewName the name of the view
* @param $callable a callable accepting 2 args: $view_name & $args
*
* @note The second arg passed to your callable `$args` is a key=>value array that contains args passed to the `view('view_name', $args)` call
*
* @example callable `function($view_name, $args)`
*
*/
public function addCallable($viewName, $callable, $args=[]){
$class = '\\Lia\\Obj\\ViewCallable';
$this->addViewHandler($class, $callable, $viewName, $args);
}
/**
* Add a view handler that will be called when a view is requested
*
* @note null-namespace refers to `$lia->view('view-name')`
* @note namespace refers to `$lia->view('namespace:view-name')`
* @note Always sets null-namespace view if it's not already set. (ignores conflictMode)
*
*/
public function addViewHandler($class, $dir, $viewName, $args=[]){
$vnCopy = $viewName;
$parts = explode(':', $viewName);
$name = $viewName = array_pop($parts);
$namespace = array_shift($parts);
if (isset($this->views[$namespace][$viewName])){
$cm = $this->conflictMode;
if ($cm=='ignore')return;
else if ($cm!='overwrite'){
throw new \Exception("View '$viewName' is already set.");
}
}
$viewData = [
'class'=>$class,
'dir'=>$dir,
'name'=>$vnCopy,
'namespace'=>$namespace,
'args'=>$args,
'lia'=>$this->_lia,
];
// var_dump($namespace);
// var_dump($viewName);
// exit;
$this->views[$namespace][$viewName] = $viewData;
$this->views[null][$viewName] = $this->views[null][$viewName] ?? $viewData;
}
/**
* get a view object
*/
public function view($name, $args=[]){
$parts = explode(':', $name);
$name = array_pop($parts);
$namespace = array_shift($parts);
$view_ns = $this->views[$namespace];
$viewData = $view_ns[$name];
// if ($viewData==null){
// $message="";
// $ext = strtolower(pathinfo($name,PATHINFO_EXTENSION));
// if ($ext=='php'||$ext=='html'){
// $message = "Do not include the file extension when calling view()";
// }
// throw new \Lia\Exception(". {$message}");
// }
$cn = $viewData['class'];
$dir = $viewData['dir'];
$name = $viewData['name'];
$setupArgs = $viewData['args'];
// $globalArgs = $this->lia->api('lia:globalparams.getAll');
// $viewData['globalArgs'] = $globalArgs;
$globalArgs = $this->globalArgs;
// print_r(array_keys($viewData));
if (in_array('Lia\\Obj\\IView',class_implements($cn,true))){
// print_r(array_keys($globalArgs));
// print_r(array_keys($setupArgs));
// print_r(array_keys($args));
//
// exit;
$allArgs = array_merge($globalArgs,$setupArgs,$args);
$view = new $cn($name, $dir, $allArgs);
} else {
$viewData['given_args'] = $args;
$view = new $cn($viewData);
}
return $view;
}
}