<?php
namespace gnomephp\mvc;
use gnomephp\cache\CatchedCacheException;
use gnomephp\Gnomephp;
use gnomephp\Configuration,
gnomephp\Url,
gnomephp\message\Message;
/**
* This is the view helper.
* It contains logic for the views.
*
* You have convenience methods like form generation, extending other views, importing views
* and so fourth.
*
* You can assign variables and render one or more specific views.
*
* @author peec
*
*/
class View{
/**
*
* Variables assigned to view.
* @var array
*/
protected $variables=array();
/**
* Global variables ( gets added in all extends and implements )
* @var array
*/
static public $globalVariables = array();
protected $viewname;
/**
*
* Instance of Url helper.
* @var gnomephp\Url
*/
public $url;
/**
* Holds the input class.
* @var gnomephp\input\Input
*/
public $input;
/**
* Holds the input class.
* @var gnomephp\helper\lang\Lang
*/
public $lang;
/**
* Holds the input class.
* @var gnomephp\Session
*/
public $session;
/**
* This will contain the view name the current view is extending.
* If extend() method is used $extendingView is set.
* @var string
*/
protected $extendingView = null;
protected $extendingViewAlias = null;
protected $extendingVars = array();
/**
* This will contain the implementation map if there are some view outputs
* that is currently implementing this specific view.
* @var array
*/
protected $implementsMap = array();
/**
* View cache queue.
*
* @var array Array of gnomephp\cache\ViewCache objects.
*/
protected $cacheQueue = array();
/**
* Constructs the view.
*
* @param unknown_type $input
* @param unknown_type $lang
* @param unknown_type $session
*/
public function __construct($input=null, $lang=null, $session=null){
$this->url = new Url;
$this->input = $input;
$this->lang = $lang;
$this->session = $session;
}
public function addImplementation($alias, $content){
$this->implementsMap[$alias] = $content;
}
public function getExtend($alias){
if (isset($this->implementsMap[$alias])){
return $this->implementsMap[$alias];
}else{
return null;
}
}
/**
*
* Assigns a variable to the view.
* @param string $var Variable name
* @param mixed $value Value of the variable, can be array, object, string boolean, etc... all types of variables is accepted.
*/
public function assign($var, $value){
$this->variables[$var] = $value;
}
/**
*
* Assigns a GLOBAL variable to all views.
* @param string $var Variable name
* @param mixed $value Value of the variable, can be array, object, string boolean, etc... all types of variables is accepted.
*/
public function assignGlobal($var, $value){
View::$globalVariables[$var] = $value;
}
/**
*
* Imports a view and creates a separate view for the specific view. Useful to use inside templates like:
* <? $view->import('header'); ?>
*
* @param string $view The view name, Can be in folder too, like template/header, . This will load view/template/header.php
* @param array $vars Array of variables to assign to this specific view. Key should be the variable name, Value can be anything.
* @param string $suffix The file extension of the view file. Default is .php.
*/
public function import($view, $vars=array(), $returnContent=false, $suffix='.php'){
$v = new View($this->input, $this->lang, $this->session);
foreach($vars as $k => $va){
$v->assign($k, $va);
}
$v->render($view, $returnContent, $suffix);
}
/**
* Let's you extend another view with alias and optional vars.
*
* @param string $view View file path
* @param string $alias Alias of the extend.
* @param array $vars Additional vars to pass to the other view.
* @return gnomephp\mvc\View
*/
public function extend($view, $alias=false, $vars=array()){
$this->extendingView = $view;
$this->extendingViewAlias = $alias ? $alias : $view;
$this->extendingVars = $vars;
return $this;
}
public function getRuntime(){
return \gnomephp\mvc\Dispatcher::getRuntime();
}
/**
*
* Gets a configuration value from a specific configuration file.
*
* @param string $file The configuration file inside the config folder. NOTICE! Do not include .yml extension, this will be added automatically.
* @param string $key The key to load, if not provided, it will load all configurations in an array in the config file.
* @param string $suffix The suffix of the config file. Default is .yml.
*/
public function getConfig($file, $key=null, $suffix='.yml'){
return \gnomephp\Configuration::get($file, $key, $suffix);
}
/**
* Gets message objects.
* @return array Array of MessageItem, check for what type of message with instanceof operator.
*/
public function getMessages(){
return Message::getMessages();
}
public function getViewPath(){
return GNOME_APP_PATH.DIRECTORY_SEPARATOR.'view'.DIRECTORY_SEPARATOR;
}
/**
* Creates a new form object.
* You can create the form in the controller and assign it to a variable.
* If you choose to provide a callback closure as listener it should be defined as:
* function ($input){
* // Do something with the input of the form.
* }
*
*
* @param string $id Unique id for the form. Example: 'contact_form'
* @param string $action The action of where to post the variables.
* @param string $method The method to use for posting the form, default is 'post'
* @param closure $listener A callback function to use if form is posted. This is not obligatory, but it's a good way of checking if this specific form was posted.
*/
public function createForm($id, $action, $method='post', $listener=null){
return new \gnomephp\form\Form($id, $this->url, $action, $method, $listener, $this->input);
}
/**
* Sends a specific view to the output.
*
* Can also return the content if $returnContent is set to true.
*
*
* @param string $viewName The view name, Can be in folder too, like template/header, . This will load view/template/header.php
* @param boolean $returnContent If you want to return the rendered output instead of echoing it out, you may set this to true.
* @param string $suffix The file extension of the view file. Default is .php.
* @param boolean $skipViewPath If you want to skip the view directory of the application running, set this to true. Note that you then need to set absolute path in $viewName.
*/
public function render($viewName, $returnContent=false, $suffix='.php', $skipViewPath = false){
// Assign variables to nice onces...
extract($this->variables);
// Also extract global variables!
extract(View::$globalVariables);
$this->viewname = $viewName;
if ($skipViewPath) $vpath = '';
else $vpath = GNOME_APP_PATH.DIRECTORY_SEPARATOR.'view' . DIRECTORY_SEPARATOR;
$view = $this;
ob_start();
// Include view.
require $vpath.$viewName.($suffix ?: $suffix);
$content = ob_get_contents();
ob_end_clean();
if ($this->extendingView !== null){
$v = new View($this->input, $this->lang, $this->session);
$v->addImplementation($this->extendingViewAlias, $content);
foreach($this->extendingVars as $k => $va){
$v->assign($k, $va);
}
$content = $v->render($this->extendingView, true, $suffix, $skipViewPath);
}
// Ok Lets see if we want to generate some caches
foreach($this->cacheQueue as $key => $viewcache){
if ($viewcache->getSuffix() == $suffix && $viewcache->getViewName() == $viewName){
// Write cache.
$viewcache->put($content);
unset($this->cacheQueue[$key]);
}
}
if ($returnContent){
return $content;
}else{
echo $content;
}
}
/**
* Tries to render a cached view.
* If the file was not cached, render() method will create a cached file.
* After next run cached file will be returned.
*
* This method is usually the first call in the controllers method when you call render() in the portion of the method.
*
*
* @param string $viewFile Path to view file
* @param int $timeout Timeout, default is 3600 (1 hour cache)
* @param boolean $returnContent If you want to return the content, notice if true - CatchedCacheException will not be thrown if got cache.
* @param string $suffix the suffix of the view file ( default : .php )
* @param boolean $skipViewPath If you want to skip the dir pattern of the application's view directory set this to true.
* @param mixed $salt If $salt === null the current activeRoute md5 hash will be used, this allows you to cache pages depending on the URL arguments and controller / method pattern. Default is null ( active router rule hash ). You can set this to your own salt if you want.
* @throws gnomephp\cache\CatchedCacheException if valid cache it throws Exception, this is automatically catched in the Dispatcher so you dont want to catch it.
*/
public function renderCache($viewFile, $timeout=3600, $returnContent=false, $suffix='.php', $skipViewPath = false, $salt = null){
if ($salt===null){
$salt = Dispatcher::getInstance()->activeRoute;
}
$obj = new \gnomephp\cache\ViewCache($viewFile, $suffix, GNOME_APP_PATH . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR . 'view', $salt);
$cachePath = $obj->getCacheFile();
// Return cached content ?
if (file_exists($cachePath) && ($timeout == 0 || filemtime($cachePath) > time()-$timeout)){
$c = $this->render($obj->getViewName(), $returnContent, $obj->getSuffix(), $skipViewPath);
if (!$returnContent)throw new \gnomephp\cache\CatchedCacheException("Got cache");
else return $c;
}
// Ok content is not cached, lets do some work.
$path = dirname($cachePath);
// try to make the dir
if (!file_exists($path))mkdir($path);
// Add it to the cache queue. $viewFile . $suffix
$this->cacheQueue[] = $obj;
}
/**
* Returns a view cache object based on variables.
*
* @param string $viewFile View file.
* @param string $salt Salt appendix, if null active router hash will be used.
* @param string $suffix Suffix
*
* @return gnomephp\cache\ViewCache
*/
public function getViewCache($viewFile, $salt = null, $suffix='.php'){
if ($salt===null){
$salt = Dispatcher::getInstance()->activeRoute;
}
$obj = new \gnomephp\cache\ViewCache($viewFile, $suffix, GNOME_APP_PATH . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR . 'view', $salt);
return $obj;
}
/**
* Deletes all the view cached files.
*
* Notice, deletes all files in cache/view apps directory.
*/
public function deleteAllViewCache(){
$iterator = new \DirectoryIterator(GNOME_APP_PATH . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR . 'view');
foreach ($iterator as $fileinfo) {
if ($fileinfo->isFile()) {
unlink($fileinfo->getPathname());
}
}
}
}