Source of file JeeObject.php

Size: 21,094 Bytes - Last Modified: 2020-10-24T02:46:31+00:00

/home/travis/build/NextDom/nextdom-core/src/Model/Entity/JeeObject.php

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
<?php

/* This file is part of NextDom Software.
 *
 * NextDom is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * NextDom Software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with NextDom Software. If not, see <http://www.gnu.org/licenses/>.
 */

namespace NextDom\Model\Entity;

use NextDom\Enums\Common;
use NextDom\Enums\ConfigKey;
use NextDom\Enums\DateFormat;
use NextDom\Enums\NextDomObj;
use NextDom\Exceptions\CoreException;
use NextDom\Helpers\DBHelper;
use NextDom\Helpers\NextDomHelper;
use NextDom\Helpers\Utils;
use NextDom\Managers\CacheManager;
use NextDom\Managers\CmdManager;
use NextDom\Managers\ConfigManager;
use NextDom\Managers\DataStoreManager;
use NextDom\Managers\EqLogicManager;
use NextDom\Managers\JeeObjectManager;
use NextDom\Managers\ScenarioManager;
use NextDom\Model\Entity\Parents\BaseEntity;
use NextDom\Model\Entity\Parents\ConfigurationEntity;
use NextDom\Model\Entity\Parents\DisplayEntity;
use NextDom\Model\Entity\Parents\IsVisibleEntity;
use NextDom\Model\Entity\Parents\NameEntity;
use NextDom\Model\Entity\Parents\PositionEntity;
use NextDom\Model\Entity\Parents\ImageEntity;

/**
 * Object for eqLogic group
 *
 * @ORM\Table(name="object", uniqueConstraints={@ORM\UniqueConstraint(name="name_UNIQUE", columns={"name"})}, indexes={@ORM\Index(name="fk_object_object1_idx1", columns={"father_id"}), @ORM\Index(name="position", columns={"position"})})
 * @ORM\Entity
 */
class JeeObject extends BaseEntity {

    const CLASS_NAME = JeeObject::class;
    const DB_CLASS_NAME = '`object`';
    const TABLE_NAME = NextDomObj::OBJECT;
    const IMG_DIR_NAME = NextDomObj::OBJECT;

    use ConfigurationEntity,
        DisplayEntity,
        NameEntity,
        ImageEntity,
        IsVisibleEntity,
        PositionEntity;

    /**
     * @var int
     *
     * @ORM\ManyToOne(targetEntity="NextDom\Model\Entity\Object")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="father_id", referencedColumnName="id")
     * })
     */
    protected $father_id = null;
    protected $_child = [];

    /**
     * Get visibility value
     *
     * @param null $default Default value if state is not set
     *
     * @return int|null
     */
    public function getIsVisible($default = null) {
        if ($this->isVisible == '' || !is_numeric($this->isVisible)) {
            return $default;
        }
        return $this->isVisible;
    }

    /**
     * Get object position
     *
     * @param int|null $default Default value if position is not set
     *
     * @return int|null Object position
     */
    public function getPosition($default = null) {
        if ($this->position == '' || !is_numeric($this->position)) {
            return $default;
        }
        return $this->position;
    }

    /**
     * Get tree under this object
     *
     * @return JeeObject[]
     *
     * @throws \Exception
     */
    public function getChilds() {
        $tree = [];
        foreach ($this->getChild() as $child) {
            $tree[] = $child;
            $tree = array_merge($tree, $child->getChilds());
        }
        return $tree;
    }

    /**
     * Get direct children
     *
     * @param bool $_visible
     * @return JeeObject[]
     *
     * @throws \Exception
     */
    public function getChild($_visible = true) {
        if (!isset($this->_child[$_visible])) {
            $this->_child[$_visible] = JeeObjectManager::getChildren($this->id, $_visible);
        }
        return $this->_child[$_visible];
    }

    /**
     * Method called before save. Check error and set default values
     *
     * @throws \Exception
     */
    public function preSave() {
        if (is_numeric($this->getFather_id()) && $this->getFather_id() === $this->getId()) {
            throw new CoreException(__('L\'objet ne peut pas être son propre père'));
        }
        $this->checkTreeConsistency();

        $this->setConfiguration('parentNumber', $this->parentNumber());
        if ($this->getConfiguration('tagColor') == '') {
            $this->setConfiguration('tagColor', '#000000');
        }
        if ($this->getConfiguration('tagTextColor') == '') {
            $this->setConfiguration('tagTextColor', '#FFFFFF');
        }
        if ($this->getConfiguration('desktop::summaryTextColor') == '') {
            $this->setConfiguration('desktop::summaryTextColor', '');
        }
        if ($this->getConfiguration('mobile::summaryTextColor') == '') {
            $this->setConfiguration('mobile::summaryTextColor', '');
        }
    }

    /**
     * Get father object id
     *
     * @param int|null $default Default value if object as no father
     *
     * @return int|null Father object id
     */
    public function getFather_id($default = null) {
        if ($this->father_id == '' || !is_numeric($this->father_id)) {
            return $default;
        }
        return $this->father_id;
    }

    /**
     * Set father object id
     *
     * @param int|null $_father_id Set father object id or null for root object
     *
     * @return $this
     */
    public function setFather_id($_father_id = null) {
        $_father_id = ($_father_id == '') ? null : $_father_id;
        $this->updateChangeState($this->father_id, $_father_id);
        $this->father_id = $_father_id;
        return $this;
    }

    /**
     * Check that the object tree does not have a loop.
     *
     * @param array $ancestors List of all objects ancestors
     *
     * @throws \Exception
     */
    public function checkTreeConsistency($ancestors = []) {
        $father = $this->getFather();
        // If object as a father
        if (is_object($father)) {
            // Check if the object is in ancestors (loop)
            if (in_array($this->getFather_id(), $ancestors)) {
                throw new CoreException(__('Problème dans l\'arbre des objets'));
            }
            $ancestors[] = $this->getId();

            $father->checkTreeConsistency($ancestors);
        }
    }

    /**
     * Get father
     *
     * @return JeeObject Father jeeObject
     *
     * @throws \Exception
     */
    public function getFather() {
        return JeeObjectManager::byId($this->getFather_id());
    }

    /**
     * Get number of parents
     *
     * @return int Number of parents
     *
     * @throws \Exception
     */
    public function parentNumber() {
        $father = $this->getFather();
        if (!is_object($father)) {
            return 0;
        }
        $fatherNumber = 0;
        while ($fatherNumber < 50) {
            $fatherNumber++;
            $father = $father->getFather();
            if (!is_object($father)) {
                return $fatherNumber;
            }
        }
        return 0;
    }

    /**
     * Method called before remove
     *
     * @throws \Exception
     */
    public function preRemove() {
        DataStoreManager::removeByTypeLinkId(NextDomObj::OBJECT, $this->getId());
        $params = ['object_id' => $this->getId()];
        $sql = 'UPDATE ' . EqLogicManager::DB_CLASS_NAME . ' SET `object_id = NULL WHERE `object_id` = :object_id';
        DBHelper::exec($sql, $params);
        $sql = 'UPDATE ' . ScenarioManager::DB_CLASS_NAME . ' SET `object_id` = NULL WHERE `object_id` = :object_id';
        DBHelper::exec($sql, $params);
    }

    /**
     * Remove object from the database
     *
     * @return bool True on success
     *
     * @throws \NextDom\Exceptions\CoreException
     * @throws \ReflectionException
     */
    public function remove() {
        NextDomHelper::addRemoveHistory([Common::ID => $this->getId(), Common::NAME => $this->getName(), Common::DATE => date(DateFormat::FULL), Common::TYPE => NextDomObj::OBJECT]);
        return parent::remove();
    }

    /**
     * Set object name
     *
     * @param string $name Object name
     *
     * @return $this
     */
    public function setName($name) {
        $name = str_replace(['&', '#', ']', '[', '%'], '', $name);
        $this->updateChangeState($this->name, $name);
        $this->name = $name;
        return $this;
    }

    /**
     * Get eqLogic used in the summary
     *
     * @param string $summary Name of the summary
     * @param bool $onlyEnable Filter only enabled
     * @param bool $onlyVisible Filter only visible
     * @param string $eqTypeName Filter by eqTypeName (plugin)
     * @param string $logicalId Filter by logicalId
     *
     * @return EqLogic[] List of eqLogics
     *
     * @throws \Exception
     */
    public function getEqLogicBySummary($summary = '', $onlyEnable = true, $onlyVisible = false, $eqTypeName = null, $logicalId = null) {
        $def = ConfigManager::byKey(ConfigKey::OBJECT_SUMMARY);
        if ($summary == '' || !isset($def[$summary])) {
            return null;
        }
        $summaries = $this->getConfiguration(Common::SUMMARY);
        if (!isset($summaries[$summary])) {
            return [];
        }
        $eqLogics = EqLogicManager::byObjectId($this->getId(), $onlyEnable, $onlyVisible, $eqTypeName, $logicalId);
        $eqLogics_id = [];
        foreach ($summaries[$summary] as $infos) {
            if ($infos['enable'] != 1) {
                continue;
            }
            $cmd = CmdManager::byId(str_replace('#', '', $infos[NextDomObj::CMD]));
            if (is_object($cmd)) {
                $eqLogics_id[$cmd->getEqLogic_id()] = $cmd->getEqLogic_id();
            }
        }
        $result = [];
        if (is_array($eqLogics)) {
            foreach ($eqLogics as $eqLogic) {
                if (isset($eqLogics_id[$eqLogic->getId()])) {
                    $eqLogic->setObject($this);
                    $result[] = $eqLogic;
                }
            }
        }
        return $result;
    }

    /**
     * Get summary in HTML format
     *
     * @param string $version Render version
     *
     * @return string
     *
     * @throws \NextDom\Exceptions\CoreException
     * @throws \ReflectionException
     */
    public function getHtmlSummary($version = 'desktop') {
        if (trim($this->getCache('summaryHtml' . $version)) != '') {
            return $this->getCache('summaryHtml' . $version);
        }
        $result = '<span class="objectSummary' . $this->getId() . '" data-version="' . $version . '">';
        $def = ConfigManager::byKey(ConfigKey::OBJECT_SUMMARY);
        $summaryResult = '';
        if (!empty($def)) {
            foreach ($def as $key => $value) {
                if ($this->getConfiguration('summary::hide::' . $version . '::' . $key, 0) == 1) {
                    continue;
                }
                $summaryResult = $this->getSummary($key);
                if ($summaryResult !== null) {
                    $style = '';
                    if ($version == 'desktop') {
                        $style = 'color:' . $this->getDisplay($version . '::summaryTextColor', '#000000') . ';';
                    }
                    $allowDisplayZero = $value['allowDisplayZero'];
                    if ($value['calcul'] == 'text') {
                        $allowDisplayZero = 1;
                    }
                    if ($allowDisplayZero == 0 && $summaryResult == 0) {
                        $style = 'display:none;';
                    }
                    $result .= '<span style="' . $style . '" class="objectSummaryParent cursor" data-summary="' . $key . '" data-object_id="' . $this->getId() . '" data-displayZeroValue="' . $allowDisplayZero . '">' . $value[Common::ICON] . ' <sup><span class="objectSummary' . $key . '">' . $summaryResult . '</span> ' . $value['unit'] . '</span></sup>';
                }
            }
        }
        $result = trim($result) . '</span>';
        $this->setCache('summaryHtml' . $version, $result);
        return $result;
    }

    /**
     * Get cache information of this object
     *
     * @param string $key Name of the information
     * @param mixed $default Default value
     *
     * @return mixed Value of the asked information or $default
     * @throws \Exception
     */
    public function getCache(string $key = '', $default = '') {
        $cache = CacheManager::byKey('objectCacheAttr' . $this->getId())->getValue();
        return Utils::getJsonAttr($cache, $key, $default);
    }

    /**
     * Get summary of the object
     *
     * @param string $summaryKey Summary key
     * @param bool $raw Get raw data
     *
     * @return mixed
     *
     * @throws \NextDom\Exceptions\CoreException
     * @throws \ReflectionException
     */
    public function getSummary($summaryKey = '', $raw = false) {
        $def = ConfigManager::byKey(ConfigKey::OBJECT_SUMMARY);
        if ($summaryKey == '' || !isset($def[$summaryKey])) {
            return null;
        }
        $summaries = $this->getConfiguration(Common::SUMMARY);
        if (!isset($summaries[$summaryKey])) {
            return null;
        }
        $values = [];
        foreach ($summaries[$summaryKey] as $infos) {
            if (isset($infos['enable']) && $infos['enable'] == 0) {
                continue;
            }
            $value = CmdManager::cmdToValue($infos[NextDomObj::CMD]);
            if (isset($infos['invert']) && $infos['invert'] == 1) {
                $value = !$value;
            }
            if (isset($def[$summaryKey]['count']) && $def[$summaryKey]['count'] == 'binary' && $value > 1) {
                $value = 1;
            }
            $values[] = $value;
        }
        if (count($values) == 0) {
            return null;
        }
        if ($raw) {
            return $values;
        }
        if ($def[$summaryKey]['calcul'] == 'text') {
            return trim(implode(',', $values), ',');
        }
        return round(NextDomHelper::calculStat($def[$summaryKey]['calcul'], $values), 1);
    }

    /**
     * Store information of this object in cache
     *
     * @param string $key Name of the information to store
     * @param mixed $value Default value
     * @throws \Exception
     */
    public function setCache(string $key, $value = null) {
        CacheManager::set('objectCacheAttr' . $this->getId(), Utils::setJsonAttr(CacheManager::byKey('objectCacheAttr' . $this->getId())->getValue(), $key, $value));
    }

    /**
     * Get graph data
     *
     * @param array $data Graph data
     * @param int $level Current level in graph
     * @param int $drill Level limit
     *
     * @return array
     *
     * @throws \ReflectionException
     */
    public function getLinkData(&$data = [Common::NODE => [], Common::LINK => []], $level = 0, $drill = null) {
        if ($drill === null) {
            $drill = ConfigManager::byKey('graphlink::object::drill');
        }
        if (isset($data[Common::NODE][NextDomObj::OBJECT . $this->getId()])) {
            return null;
        }
        $level++;
        if ($level > $drill) {
            return $data;
        }
        $icon = Utils::findCodeIcon($this->getDisplay(Common::ICON));
        $data[Common::NODE][NextDomObj::OBJECT . $this->getId()] = [
            'id' => NextDomObj::OBJECT . $this->getId(),
            'name' => $this->getName(),
            'icon' => $icon[Common::ICON],
            'fontfamily' => $icon['fontfamily'],
            'fontweight' => ($level == 1) ? 'bold' : 'normal',
            'fontsize' => '4em',
            'texty' => -35,
            'textx' => 0,
            'title' => $this->getHumanName(),
            'url' => 'index.php?v=d&p=object&id=' . $this->getId(),
        ];
        $use = $this->getUse();
        Utils::addGraphLink($this, NextDomObj::OBJECT, $this->getEqLogic(), NextDomObj::EQLOGIC, $data, $level, $drill, [Common::DASH_VALUE => '1,0', Common::LENGTH_FACTOR => 0.6]);
        Utils::addGraphLink($this, NextDomObj::OBJECT, $use[NextDomObj::CMD], NextDomObj::CMD, $data, $level, $drill);
        Utils::addGraphLink($this, NextDomObj::OBJECT, $use[NextDomObj::SCENARIO], NextDomObj::SCENARIO, $data, $level, $drill);
        Utils::addGraphLink($this, NextDomObj::OBJECT, $use[NextDomObj::EQLOGIC], NextDomObj::EQLOGIC, $data, $level, $drill);
        Utils::addGraphLink($this, NextDomObj::OBJECT, $use[NextDomObj::DATASTORE], NextDomObj::DATASTORE, $data, $level, $drill);
        Utils::addGraphLink($this, NextDomObj::OBJECT, $this->getChild(), NextDomObj::OBJECT, $data, $level, $drill, [Common::DASH_VALUE => '1,0', Common::LENGTH_FACTOR => 0.6]);
        Utils::addGraphLink($this, NextDomObj::OBJECT, $this->getScenario(false), NextDomObj::SCENARIO, $data, $level, $drill, [Common::DASH_VALUE => '1,0', Common::LENGTH_FACTOR => 0.6]);
        return $data;
    }

    /**
     * Get object human name
     *
     * @param bool $tag With tag
     * @param bool $prettify In HTML format
     *
     * @return string
     */
    public function getHumanName($tag = false, $prettify = false) {
        if ($tag) {
            $tagIcon = '<i class="fas fa-tag"></i>';
            $spacingRight = '<i class="spacing-right"></i>';
            if ($prettify) {
                if ($this->getDisplay('tagColor') != '') {
                    return '<span class="label" style="text-shadow:none;background-color:' . $this->getDisplay('tagColor') . ' !important;color:' . $this->getDisplay('tagTextColor', 'white') . ' !important">' . $this->getDisplay(Common::ICON, $tagIcon) . $spacingRight . $this->getName() . '</span>';
                } else {
                    return '<span class="label label-primary">' . $this->getDisplay(Common::ICON, $tagIcon) . $spacingRight . $this->getName() . '</span>';
                }
            } else {
                return $this->getDisplay(Common::ICON, $tagIcon) . $spacingRight . $this->getName();
            }
        } else {
            return $this->getName();
        }
    }

    /**
     * Get object usage in string
     *
     * @return array List of usage
     *
     * @throws \ReflectionException
     */
    public function getUse() {
        $json = NextDomHelper::fromHumanReadable(json_encode(Utils::o2a($this)));
        return NextDomHelper::getTypeUse($json);
    }

    /**
     * Get eqLogics attached to the object
     *
     * @param bool $onlyEnable Filter only enabled eqLogics
     * @param bool $onlyVisible Filter only visible eqLogics
     * @param null $eqTypeName Filter by name
     * @param null $logicalId Filter by logicalId
     * @param bool $searchOnchild Search also in object childs
     *
     * @return EqLogic[]
     *
     * @throws \Exception
     */
    public function getEqLogic($onlyEnable = true, $onlyVisible = false, $eqTypeName = null, $logicalId = null, $searchOnchild = false) {
        $eqLogics = EqLogicManager::byObjectId($this->getId(), $onlyEnable, $onlyVisible, $eqTypeName, $logicalId);
        if (is_array($eqLogics)) {
            foreach ($eqLogics as &$eqLogic) {
                $eqLogic->setObject($this);
            }
        }
        if ($searchOnchild) {
            $childObjects = JeeObjectManager::buildTree($this);
            if (count($childObjects) > 0) {
                foreach ($childObjects as $childObject) {
                    $eqLogics = array_merge($eqLogics, $childObject->getEqLogic($onlyEnable, $onlyVisible, $eqTypeName, $logicalId));
                }
            }
        }
        return $eqLogics;
    }

    /**
     * Get scenario linked to the object
     *
     * @param bool $onlyEnable Filter only enabled scenario
     * @param bool $onlyVisible Filter only visible scenario
     *
     * @return Scenario[] List of scenarios
     *
     * @throws \Exception
     */
    public function getScenario($onlyEnable = true, $onlyVisible = false) {
        return ScenarioManager::byObjectId($this->getId(), $onlyEnable, $onlyVisible);
    }

    /**
     * Save object in database
     *
     * @return bool True if save works
     * @throws \NextDom\Exceptions\CoreException
     * @throws \ReflectionException
     */
    public function save() {
        if ($this->_changed) {
            CacheManager::set('globalSummaryHtmldashboard', '');
            CacheManager::set('globalSummaryHtmlmobile', '');
            $this->setCache('summaryHtmldashboard', '');
            $this->setCache('summaryHtmlmobile', '');
        }
        DBHelper::save($this);
        return true;
    }

    public function cleanSummary(){
        $def = ConfigManager::byKey('object:summary');
        $summaries = $this->getConfiguration('summary');
        foreach ($summaries as $summaryKey => $value) {
            if(!isset($def[$summaryKey])){
                unset($summaries[$summaryKey]);
            }
        }
        $this->setConfiguration('summary', $summaries);
        $this->save();
    }
}