steeffeen/FancyManiaLinks

View on GitHub
FML/ManiaLink.php

Summary

Maintainability
D
1 day
Test Coverage
A
95%
<?php

namespace FML;

use FML\Elements\Dico;
use FML\Script\Script;
use FML\Stylesheet\Stylesheet;
use FML\Types\Renderable;
use FML\Types\ScriptFeatureable;

/**
 * Class representing a ManiaLink
 *
 * @author    steeffeen <mail@steeffeen.com>
 * @copyright FancyManiaLinks Copyright © 2017 Steffen Schröder
 * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3
 */
class ManiaLink
{

    /*
     * Constants
     */
    const VERSION_0           = 0;
    const VERSION_1           = 1;
    const VERSION_2           = 2;
    const VERSION_3           = 3;
    const BACKGROUND_0        = "0";
    const BACKGROUND_1        = "1";
    const BACKGROUND_STARS    = "stars";
    const BACKGROUND_STATIONS = "stations";
    const BACKGROUND_TITLE    = "title";
    const LAYER_NORMAL = "normal";
    const LAYER_SCREEN3D = "ScreenIn3d";
    const LAYER_SCORETABLE = "ScoreTable";
    const LAYER_ALTMENU = "altmenu";
    const LAYER_CUTSCENE = "cutscene";
    
    /**
     * @var string $maniaLinkId ManiaLink ID
     */
    protected $maniaLinkId = null;

    /**
     * @var int $defaultVersion Default ManiaLink version
     */
    static protected $defaultVersion = self::VERSION_1;

    /**
     * @var int $version ManiaLink version
     */
    protected $version = self::VERSION_1;

    /**
     * @var string $name ManiaLink name
     */
    protected $name = null;

    /**
     * @var string $background Background
     */
    protected $background = null;

    /**
     * @var bool $navigable3d 3d navigable
     */
    protected $navigable3d = true;

    /**
     * @var int $timeout Timeout
     */
    protected $timeout = null;

    /**
     * @var Renderable[] $children Children
     */
    protected $children = array();

    /**
     * @var Dico $dico Dictionary
     */
    protected $dico = null;

    /**
     * @var Stylesheet $stylesheet Style sheet
     */
    protected $stylesheet = null;

    /**
     * @var Script $script Script
     */
    protected $script = null;
    
    /**
     * @var null|string $layer layer to display contents with
     */
    protected $layer = null;
    
    /**
     * Create a new ManiaLink
     *
     * @api
     * @param string       $maniaLinkId (optional) ManiaLink ID
     * @param int          $version     (optional) Version
     * @param string       $name        (optional) Name
     * @param Renderable[] $children    (optional) Children
     * @return static
     */
    public static function create($maniaLinkId = null, $version = null, $name = null, array $children = null)
    {
        return new static($maniaLinkId, $version, $name, $children);
    }

    /**
     * Construct a new ManiaLink
     *
     * @api
     * @param string       $maniaLinkId (optional) ManiaLink ID
     * @param int          $version     (optional) Version
     * @param string       $name        (optional) Name
     * @param Renderable[] $children    (optional) Children
     */
    public function __construct($maniaLinkId = null, $version = null, $name = null, array $children = null)
    {
        if (is_string($version) && (!$name || is_array($name)) && !$children) {
            // backwards-compatibility (version has been introduced later, if it's a string it's supposed to be the name)
            $children = $name;
            $name     = $version;
            $version  = null;
        }
        if ($maniaLinkId) {
            $this->setId($maniaLinkId);
        }
        if ($version === null) {
            $this->setVersion(static::$defaultVersion);
        } else {
            $this->setVersion($version);
        }
        if ($name) {
            $this->setName($name);
        }
        if ($children) {
            $this->setChildren($children);
        }
    }

    /**
     * Get the ID
     *
     * @api
     * @return string
     */
    public function getId()
    {
        return $this->maniaLinkId;
    }

    /**
     * Set the ID
     *
     * @api
     * @param string $maniaLinkId ManiaLink ID
     * @return static
     */
    public function setId($maniaLinkId)
    {
        $this->maniaLinkId = (string)$maniaLinkId;
        if ($this->maniaLinkId && !$this->name) {
            $this->setName($this->maniaLinkId);
        }
        return $this;
    }

    /**
     * Get the default version
     *
     * @api
     * @return int
     */
    public static function getDefaultVersion()
    {
        return static::$defaultVersion;
    }

    /**
     * Get the version
     *
     * @api
     * @return int
     */
    public function getVersion()
    {
        return $this->version;
    }

    /**
     * Set the default version
     *
     * @api
     * @param int $defaultVersion Default ManiaLink version
     */
    public static function setDefaultVersion($defaultVersion)
    {
        static::$defaultVersion = (int)$defaultVersion;
    }

    /**
     * Set the version
     *
     * @api
     * @param int $version ManiaLink version
     * @return static
     */
    public function setVersion($version)
    {
        $this->version = (int)$version;
        return $this;
    }

    /**
     * Get the name
     *
     * @api
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Set the name
     *
     * @api
     * @param string $name ManiaLink Name
     * @return static
     */
    public function setName($name)
    {
        $this->name = (string)$name;
        return $this;
    }

     /**
     * Sets the layer to show contents
     *
     * @param string $layer layer to show contents with
     * @return $this
     */
    public function setLayer($layer)
    {
        $this->layer = $layer;

        return $this;
    }

    /**
     * Gets layer
     * @return null|string
     */
    public function getLayer()
    {
        return $this->layer;
    }
    
    /**
     * Get the background
     *
     * @api
     * @return string
     */
    public function getBackground()
    {
        return $this->background;
    }

    /**
     * Set the background
     *
     * @api
     * @param string $background Background value
     * @return static
     */
    public function setBackground($background)
    {
        $this->background = (string)$background;
        return $this;
    }

    /**
     * Get navigable3d
     *
     * @api
     * @return bool
     */
    public function getNavigable3d()
    {
        return $this->navigable3d;
    }

    /**
     * Set navigable3d
     *
     * @api
     * @param bool $navigable3d If the ManiaLink should be 3d navigable
     * @return static
     */
    public function setNavigable3d($navigable3d)
    {
        $this->navigable3d = (bool)$navigable3d;
        return $this;
    }

    /**
     * Get the timeout
     *
     * @api
     * @return int
     */
    public function getTimeout()
    {
        return $this->timeout;
    }

    /**
     * Set the timeout
     *
     * @api
     * @param int $timeout Timeout duration
     * @return static
     */
    public function setTimeout($timeout)
    {
        $this->timeout = (int)$timeout;
        return $this;
    }

    /**
     * Get children
     *
     * @api
     * @return Renderable[]
     */
    public function getChildren()
    {
        return $this->children;
    }

    /**
     * Add a child
     *
     * @api
     * @param Renderable $child Child Element to add
     * @return static
     * @deprecated Use addChild()
     * @see        ManiaLink::addChild()
     */
    public function add(Renderable $child)
    {
        return $this->addChild($child);
    }

    /**
     * Add a child
     *
     * @api
     * @param Renderable $child Child Element to add
     * @return static
     */
    public function addChild(Renderable $child)
    {
        if (!in_array($child, $this->children, true)) {
            array_push($this->children, $child);
        }
        return $this;
    }

    /**
     * Add children
     *
     * @api
     * @param Renderable[] $children Child Elements to add
     * @return static
     */
    public function addChildren(array $children)
    {
        foreach ($children as $child) {
            $this->addChild($child);
        }
        return $this;
    }

    /**
     * Set children
     *
     * @api
     * @param Renderable[] $children Child Elements
     * @return static
     */
    public function setChildren(array $children)
    {
        return $this->removeAllChildren()
                    ->addChildren($children);
    }

    /**
     * Remove all children
     *
     * @api
     * @return static
     * @deprecated Use removeAllChildren()
     * @see        ManiaLink::removeAllChildren()
     */
    public function removeChildren()
    {
        return $this->removeAllChildren();
    }

    /**
     * Remove all children
     *
     * @api
     * @return static
     */
    public function removeAllChildren()
    {
        $this->children = array();
        return $this;
    }

    /**
     * Get the Dictionary
     *
     * @api
     * @param bool $createIfEmpty (optional) If the Dico should be created if it doesn't exist yet
     * @return Dico
     */
    public function getDico($createIfEmpty = true)
    {
        if (!$this->dico && $createIfEmpty) {
            $this->setDico(new Dico());
        }
        return $this->dico;
    }

    /**
     * Set the Dictionary
     *
     * @api
     * @param Dico $dico Dictionary
     * @return static
     */
    public function setDico(Dico $dico = null)
    {
        $this->dico = $dico;
        return $this;
    }

    /**
     * Get the Stylesheet
     *
     * @api
     * @return Stylesheet
     */
    public function getStylesheet($createIfEmpty = true)
    {
        if (!$this->stylesheet && $createIfEmpty) {
            return $this->createStylesheet();
        }
        return $this->stylesheet;
    }

    /**
     * Set the Stylesheet
     *
     * @api
     * @param Stylesheet $stylesheet Stylesheet
     * @return static
     */
    public function setStylesheet(Stylesheet $stylesheet = null)
    {
        $this->stylesheet = $stylesheet;
        return $this;
    }

    /**
     * Create and assign a new Stylesheet if necessary
     *
     * @api
     * @return Stylesheet
     */
    public function createStylesheet()
    {
        if ($this->stylesheet) {
            return $this->stylesheet;
        }
        $stylesheet = new Stylesheet();
        $this->setStylesheet($stylesheet);
        return $this->stylesheet;
    }

    /**
     * Get the Script
     *
     * @api
     * @param bool $createIfEmpty (optional) Create the script if it's not set yet
     * @return Script
     */
    public function getScript($createIfEmpty = true)
    {
        if (!$this->script && $createIfEmpty) {
            return $this->createScript();
        }
        return $this->script;
    }

    /**
     * Set the Script
     *
     * @api
     * @param Script $script Script
     * @return static
     */
    public function setScript(Script $script = null)
    {
        $this->script = $script;
        return $this;
    }

    /**
     * Create and assign a new Script if necessary
     *
     * @api
     * @return Script
     */
    public function createScript()
    {
        if ($this->script) {
            return $this->script;
        }
        $script = new Script();
        $this->setScript($script);
        return $this->script;
    }

    /**
     * Render the ManiaLink
     *
     * @param bool         $echo        (optional) If the XML text should be echoed and the Content-Type header should be set
     * @param \DOMDocument $domDocument (optional) DOMDocument for which the ManiaLink should be rendered
     * @return \DOMDocument
     */
    public function render($echo = false, $domDocument = null)
    {
        $isChild = (bool)$domDocument;
        if (!$isChild) {
            $domDocument                = new \DOMDocument("1.0", "utf-8");
            $domDocument->xmlStandalone = true;
        }
        $maniaLink = $domDocument->createElement("manialink");
        if (!$isChild) {
            $domDocument->appendChild($maniaLink);
        }

        if ($this->maniaLinkId) {
            $maniaLink->setAttribute("id", $this->maniaLinkId);
        }
        if ($this->version > 0) {
            $maniaLink->setAttribute("version", $this->version);
        }
        if ($this->name) {
            $maniaLink->setAttribute("name", $this->name);
        }
        if ($this->background) {
            $maniaLink->setAttribute("background", $this->background);
        }
        if (!$this->navigable3d) {
            $maniaLink->setAttribute("navigable3d", "0");
        }
        if ($this->timeout) {
            $timeoutXml = $domDocument->createElement("timeout", $this->timeout);
            $maniaLink->appendChild($timeoutXml);
        }
        if ($this->dico) {
            $dicoXml = $this->dico->render($domDocument);
            $maniaLink->appendChild($dicoXml);
        }
        if ($this->layer) {
            $maniaLink->setAttribute("layer", $this->layer);
        }
        
        $scriptFeatures = array();
        foreach ($this->children as $child) {
            $childXml = $child->render($domDocument);
            $maniaLink->appendChild($childXml);
            if ($child instanceof ScriptFeatureable) {
                $scriptFeatures = array_merge($scriptFeatures, $child->getScriptFeatures());
            }
        }

        if ($this->stylesheet) {
            $stylesheetXml = $this->stylesheet->render($domDocument);
            $maniaLink->appendChild($stylesheetXml);
        }

        if ($scriptFeatures) {
            $this->createScript()
                 ->loadFeatures($scriptFeatures);
        }
        if ($this->script) {
            if ($this->script->needsRendering()) {
                $scriptXml = $this->script->render($domDocument);
                $maniaLink->appendChild($scriptXml);
            }
            $this->script->resetGenericScriptLabels();
        }

        if ($isChild) {
            return $maniaLink;
        }
        if ($echo) {
            header("Content-Type: application/xml; charset=utf-8;");
            echo $domDocument->saveXML();
        }
        return $domDocument;
    }

    /**
     * Get the string representation
     *
     * @return string
     */
    public function __toString()
    {
        return $this->render()
                    ->saveXML();
    }

}