ice framework documentation ice doc v1.10.1
Class Ice Mvc

View

    
namespace Ice\Mvc;

use Ice\Arr;
use Ice\Exception;
use Ice\Mvc\View\Engine\Php;
use Ice\Mvc\View\ViewInterface;

/**
 * View is a class for working with the "view" portion of the model-view-controller pattern.
 *
 * @package     Ice/View
 * @category    Component
 * @author      Ice Team
 * @copyright   (c) 2014-2023 Ice Team
 * @license     http://iceframework.org/license
 */
class View extends Arr implements ViewInterface
{
    protected engines { set };
    protected content { set, get };
    protected mainView = "index" { set, get };
    protected layoutsDir = "layouts/" { set, get };
    protected partialsDir = "partials/" { set, get };
    protected viewsDir { set, get };
    protected file { set, get };
    protected silent = false { set };

    /**
     * View constructor. Set the file and vars.
     *
     * @param string file
     * @param array data
     */
    public function __construct(file = null, array data = [])
    {
        if file != null {
            let this->file = file;
        }
        parent::__construct(data);
    }

    /**
     * Get registered engines.
     */
    public function getEngines()
    {
        var ext, engine;

        if !this->engines {
            let this->engines[".phtml"] = new Php(this);
        } else {
            for ext, engine in this->engines {
                if typeof engine == "object" {
                    if engine instanceof \Closure {
                        let this->engines[ext] = call_user_func_array(engine, [this]);
                    }
                } else {
                    if typeof engine == "string" {
                        let this->engines[ext] = create_instance_params(engine, [this]);
                    } else {
                        throw new Exception(sprintf("Invalid template engine registration for '%s' extension", ext));
                    }
                }
            }
        }
        return this->engines;
    }

    /**
     * Try to render the view with vars for engines.
     *
     * @param string file
     * @param array data
     * @return string
     */
    public function render(file = null, array data = [])
    {
        var ext, engine, engines, path, dir, dirs, exists, content;

        let exists = false,
            content = null;

        if file !== null {
            let this->file = file;
        }

        if empty this->file {
            throw new Exception("You must set the file to use within your view before rendering");
        }

        let engines = this->getEngines();

        if typeof this->viewsDir == "array" {
            let dirs = this->viewsDir;
        } else {
            let dirs = [this->viewsDir];
        }

        let ext = pathinfo(this->file, PATHINFO_EXTENSION);

        if !empty ext {
            if fetch engine, engines["." . ext] {
                for dir in dirs {
                    let path = dir . this->file;
                    if file_exists(path) {
                        let exists = true;
                        this->merge(data);
                        let content = engine->render(path, this->all());
                        break;
                    }
                }
            }
        } else {
            for ext, engine in engines {
                for dir in dirs {
                    let path = dir . this->file . ext;
                    if file_exists(path) {
                        let exists = true;
                        this->merge(data);
                        let content = engine->render(path, this->all());
                        break;
                    }
                }
                // no need to lookup and parse the other view
                if exists {
                    break;
                }
            }
        }

        if !this->silent && !exists {
            throw new Exception(sprintf("The requested view %s could not be found", path));
        }
        return content;
    }

    /**
     * Load the view.
     *
     * @param string file Name of file without extension from the views dir
     * @param array data Vars to send
     * @return string
     */
    public function load(string! file, array data = [])
    {
        return this->render(file, data);
    }

    /**
     * Load the partial view.
     *
     * @param string file Name of file without extension from the partials dir
     * @param array data Vars to send
     * @return string
     */
    public function partial(string! file, array data = [])
    {
        return this->render(this->partialsDir . file, data);
    }

    /**
     * Load the layout view.
     *
     * @param string file Name of file without extension from the layouts dir
     * @param array data Vars to send
     * @return string
     */
    public function layout(var file = null, array data = [])
    {
        if !file {
            let file = this->mainView;
        }
        return this->render(this->layoutsDir . file, data);
    }

    /**
     * Set var to the view.
     *
     * @param string name
     * @param mixed value
     * @return object View
     */
    public function setVar(string! name, value)
    {
        this->set(name, value);

        return this;
    }

    /**
     * Set multiple vars to the view.
     *
     * @param array vars
     * @return object View
     */
    public function setVars(array! vars)
    {
        this->merge(vars);

        return this;
    }

    /**
     * Alias of the `setMainView` method.
     *
     * @param array vars
     * @return object View
     */
    public function setLayout(string layout)
    {
        this->setMainView(layout);

        return this;
    }

    /**
     * Magic toStrint, get the rendered view.
     */
    public function __toString()
    {
        return this->render();
    }
}