Source of file CmdManager.php

Size: 33,872 Bytes - Last Modified: 2020-10-24T02:46:31+00:00

/home/travis/build/NextDom/nextdom-core/src/Managers/CmdManager.php

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978
<?php

/* This file is part of Jeedom.
 *
 * Jeedom 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.
 *
 * Jeedom 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 Jeedom. If not, see <http://www.gnu.org/licenses/>.
 */

/* 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 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. If not, see <http://www.gnu.org/licenses/>.
 */

namespace NextDom\Managers;

use NextDom\Enums\CmdType;
use NextDom\Enums\Common;
use NextDom\Enums\DateFormat;
use NextDom\Enums\NextDomObj;
use NextDom\Exceptions\CoreException;
use NextDom\Helpers\DBHelper;
use NextDom\Helpers\FileSystemHelper;
use NextDom\Helpers\NextDomHelper;
use NextDom\Helpers\Utils;
use NextDom\Managers\Parents\BaseManager;
use NextDom\Managers\Parents\CastedObjectManager;
use NextDom\Model\Entity\Cmd;
use NextDom\Model\Entity\EqLogic;

/**
 * Manage command
 *
 * @package NextDom\Managers
 */
class CmdManager extends BaseManager {

    use CastedObjectManager;

    /** @var string Class of the commands */
    const CLASS_NAME = Cmd::class;

    /** @var string Table name of the class in database */
    const DB_CLASS_NAME = '`cmd`';

    /**
     * Get historized commands
     *
     * @return array List of historized commands
     *
     * @throws \Exception
     */
    public static function allHistoryCmd() {
        $sql = static::getPrefixedBaseSQL('c') . "
                INNER JOIN `eqLogic` el ON c.eqLogic_id = el.id
                INNER JOIN `object` ob ON el.object_id = ob.id
                WHERE `isHistorized` = 1
                AND `type` ='info'";
        $sql .= " ORDER BY ob.position, ob.name, el.name, c.name";
        $result1 = self::cast(DBHelper::getAllObjects($sql, [], self::CLASS_NAME));
        $sql = static::getPrefixedBaseSQL('c') . "
                INNER JOIN eqLogic el ON c.eqLogic_id = el.id
                WHERE el.object_id IS NULL
                AND `isHistorized` = 1
                AND `type` = 'info'";
        $sql .= " ORDER BY el.name, c.name";
        $result2 = self::cast(DBHelper::getAllObjects($sql, [], self::CLASS_NAME));
        return array_merge($result1, $result2);
    }

    /**
     * Cast a command from generic to plugin
     *
     * @param Cmd|Cmd[] $inputs Commands to cast
     * @param EqLogic $eqLogic Link to a specific EqLogic
     *
     * @return array|mixed Casted command
     */
    public static function cast($inputs, $eqLogic = null) {
        if (is_object($inputs)) {
            $targetClassName = $inputs->getEqType() . 'Cmd';
            if (class_exists($targetClassName)) {
                if ($eqLogic !== null) {
                    $inputs->_eqLogic = $eqLogic;
                }
                /** @var Cmd $target */
                $target = new $targetClassName();
                $target->castFromCmd($inputs);
                return $target;
            }
        }
        if (is_array($inputs)) {
            $result = [];
            foreach ($inputs as $input) {
                if ($eqLogic !== null) {
                    $input->_eqLogic = $eqLogic;
                }
                $result[] = self::cast($input);
            }
            return $result;
        }
        return $inputs;
    }

    /**
     * Get commands attached to eqLogic objects
     *
     * @param int|array $eqLogicId EqLogic object id or array of EqLogic id
     * @param string|null $_type
     * @param int|null $_visible Only visible if !== null
     * @param null $_eqLogic
     * @param null $_has_generic_type
     *
     * @return Cmd|Cmd[]
     *
     * @throws \Exception
     */
    public static function byEqLogicId($eqLogicId, $_type = null, $_visible = null, $_eqLogic = null, $_has_generic_type = null) {
        $values = [];
        $sql = static::getBaseSQL();
        if (is_array($eqLogicId)) {
            $sql .= 'WHERE `eqLogic_id` IN (' . trim(preg_replace('/[, ]{2,}/m', ',', implode(',', $eqLogicId)), ',') . ') ';
        } else {
            $values = [
                'eqLogic_id' => $eqLogicId,
            ];
            $sql .= 'WHERE `eqLogic_id` = :eqLogic_id ';
        }
        if ($_type !== null) {
            $values['type'] = $_type;
            $sql .= 'AND `type` = :type ';
        }
        if ($_visible !== null) {
            $sql .= 'AND `isVisible` = 1 ';
        }
        if ($_has_generic_type) {
            $sql .= 'AND `generic_type` IS NOT NULL ';
        }
        $sql .= 'ORDER BY `order`, `name`';
        return self::cast(DBHelper::getAllObjects($sql, $values, self::CLASS_NAME), $_eqLogic);
    }

    /**
     * Get command by logical id
     *
     * @param int $logicalId Filter by logical id
     * @param string $type Filter by type
     *
     * @return array|mixed
     *
     * @throws \Exception
     */
    public static function byLogicalId($logicalId, $type = null) {
        $clauses = ['logicalId' => $logicalId];
        if ($type !== null) {
            $clauses['type'] = $type;
        }
        return self::cast(static::getMultipleByClauses($clauses, 'order'));
    }

    /**
     * Get command by generic type (plugin)
     *
     * @param string $genericType Type of the command
     * @param int $eqLogicId Commands of eqLogic
     * @param bool $one Only the first
     *
     * @return Cmd|Cmd[]
     *
     * @throws \Exception
     */
    public static function byGenericType($genericType, $eqLogicId = null, $one = false) {
        $sql = static::getBaseSQL();
        if (is_array($genericType)) {
            $in = '';
            foreach ($genericType as $value) {
                $in .= "'" . $value . "',";
            }
            $values = [];
            $sql .= 'WHERE `generic_type` IN (' . trim(preg_replace('/[, ]{2,}/m', ',', $in), ',') . ')';
        } else {
            $values = [
                'generic_type' => $genericType,
            ];
            $sql .= 'WHERE `generic_type` = :generic_type';
        }
        if ($eqLogicId !== null) {
            $values['eqLogic_id'] = $eqLogicId;
            $sql .= ' AND `eqLogic_id` = :eqLogic_id';
        }
        $sql .= ' ORDER BY `order`';
        if ($one) {
            return self::cast(DBHelper::getOneObject($sql, $values, self::CLASS_NAME));
        }
        return self::cast(DBHelper::getAllObjects($sql, $values, self::CLASS_NAME));
    }
    
    public static function searchDisplay($_display, $_eqType = null) {
        if (!is_array($_display)) {
            $values = array(
                'display' => '%' . $_display . '%',
            );
            $sql = static::getBaseSQL() . '
            WHERE display LIKE :display';
        } else {
            $values = array(
                'display' => '%' . $_display[0] . '%',
            );
            $sql = static::getBaseSQL() . '
                        WHERE display LIKE :display';
            for ($i = 1; $i < count($_display); $i++) {
                $values['display' . $i] = '%' . $_display[$i] . '%';
                $sql .= ' OR display LIKE :display' . $i;
            }
        }
        if ($_eqType !== null) {
            $values['eqType'] = $_eqType;
            $sql .= ' AND eqType=:eqType ';
        }
        $sql .= ' ORDER BY name';
        return self::cast(DBHelper::getAllObjects($sql, $values, self::CLASS_NAME));
    }

    /**
     * Search in commands configuration
     *
     * @param string|array $configuration String to find
     * @param string $eqType Filter by EqLogic type
     *
     * @return Cmd[] List of commands
     *
     * @throws \Exception
     */
    public static function searchConfiguration($configuration, $eqType = null) {
        $sql = static::getBaseSQL() . '
                WHERE `configuration` LIKE :configuration';
        if (!is_array($configuration)) {
            $values = [
                'configuration' => '%' . $configuration . '%',
            ];
        } else {
            $values = [
                'configuration' => '%' . $configuration[0] . '%',
            ];
            for ($i = 1; $i < count($configuration); $i++) {
                $values['configuration' . $i] = '%' . $configuration[$i] . '%';
                $sql .= ' OR `configuration` LIKE :configuration' . $i;
            }
        }
        if ($eqType !== null) {
            $values['eqType'] = $eqType;
            $sql .= ' AND `eqType` = :eqType ';
        }
        $sql .= ' ORDER BY `name`';
        return self::cast(DBHelper::getAllObjects($sql, $values, self::CLASS_NAME));
    }

    /**
     * Search in commands configuration
     *
     * @param int $eqLogicId Filter by eqLogic
     * @param string $configuration String to find
     * @param string $type Command type
     *
     * @return Cmd[]
     *
     * @throws \Exception
     */
    public static function searchConfigurationEqLogic($eqLogicId, $configuration, $type = null) {
        $values = [
            'configuration' => '%' . $configuration . '%',
            'eqLogic_id' => $eqLogicId,
        ];
        $sql = static::getBaseSQL() . '
                WHERE `eqLogic_id` = :eqLogic_id';
        if ($type !== null) {
            $values['type'] = $type;
            $sql .= ' AND `type` = :type ';
        }
        $sql .= ' AND `configuration` LIKE :configuration';
        return self::cast(DBHelper::getAllObjects($sql, $values, self::CLASS_NAME));
    }

    /**
     * Search by template
     *
     * @param string $template Name of template
     * @param string $eqType Filter by eqLogic type
     * @param string $type Filter by type
     * @param string $subtype Filter by subtype
     *
     * @return array|mixed
     *
     * @throws \Exception
     */
    public static function searchTemplate($template, $eqType = null, $type = null, $subtype = null) {
        $params = [
            'template' => '%' . $template . '%',
        ];
        $sql = static::getBaseSQL() . '
                WHERE `template` LIKE :template';
        if ($eqType !== null) {
            $params['eqType'] = $eqType;
            $sql .= ' AND `eqType` = :eqType ';
        }
        if ($type !== null) {
            $params['type'] = $type;
            $sql .= ' AND `type` = :type ';
        }
        if ($subtype !== null) {
            $params['subType'] = $subtype;
            $sql .= ' AND `subType` = :subType ';
        }
        $sql .= ' ORDER BY `name`';
        return self::cast(DBHelper::getAllObjects($sql, $params, self::CLASS_NAME));
    }

    /**
     * Get all commands by eqLogic and command logicalId
     *
     * @param int $eqLogicId EqLogic Id owner
     * @param string $logicalId Command logicial id
     * @param bool $multiple Multiple results
     * @param string $type Filter by type of command
     *
     * @return array|mixed
     *
     * @throws \Exception
     */
    public static function byEqLogicIdAndLogicalId($eqLogicId, $logicalId, $multiple = false, $type = null) {
        $clauses = [
            'eqLogic_id' => $eqLogicId,
            'logicalId' => $logicalId,
        ];
        if ($type !== null) {
            $clauses['type'] = $type;
        }
        if ($multiple) {
            return self::cast(static::getMultipleByClauses($clauses));
        }
        return self::cast(static::getOneByClauses($clauses));
    }

    /**
     * Get all commands by eqLogic and generic type
     *
     * @param int $eqLogicId EqLogic Id owner
     * @param string $genericType Filter by generic type
     * @param bool $multiple Multiple results
     * @param string $type Filter by type
     *
     * @return Cmd|Cmd[]
     *
     * @throws \Exception
     */
    public static function byEqLogicIdAndGenericType($eqLogicId, $genericType, $multiple = false, $type = null) {
        $clauses = [
            'eqLogic_id' => $eqLogicId,
            'generic_type' => $genericType,
        ];
        if ($type !== null) {
            $clauses['type'] = $type;
        }
        if ($multiple) {
            return self::cast(static::getMultipleByClauses($clauses));
        }
        return self::cast(static::getOneByClauses($clauses));
    }

    /**
     * Get commands by value
     *
     * @param int|string $value Filter by value
     * @param string $type Filter by type
     * @param bool $onlyEnable Only enabled commands
     *
     * @return Cmd[]
     *
     * @throws \Exception
     */
    public static function byValue($value, $type = null, $onlyEnable = false) {
        $values = [
            'value' => $value,
            'search' => '%#' . $value . '#%',
        ];
        if (strpos($value, 'variable(') !== false) {
            $values['search'] = '%#' . $value . '%';
        }
        if ($onlyEnable) {
            $sql = static::getPrefixedBaseSQL('c') . '
                    INNER JOIN `eqLogic` el ON c.eqLogic_id = el.id
                    WHERE (`value` = :value OR `value` LIKE :search)
                    AND el.isEnable = 1
                    AND c.id != :value';
            if ($type !== null) {
                $values['type'] = $type;
                $sql .= ' AND c.type = :type ';
            }
        } else {
            $sql = static::getBaseSQL() . '
                    WHERE (`value` = :value OR `value` LIKE :search)
                    AND `id` != :value';
            if ($type !== null) {
                $values['type'] = $type;
                $sql .= ' AND `type` = :type ';
            }
        }
        return self::cast(DBHelper::getAllObjects($sql, $values, self::CLASS_NAME));
    }

    /**
     * Get commands by eqLogic type, eqLogic name and cmd name
     *
     * @param string $eqTypeName EqLogic type name
     * @param string $eqLogicName Eqlogic name
     * @param string $cmdName Command name
     *
     * @return Cmd[]
     *
     * @throws \Exception
     */
    public static function byTypeEqLogicNameCmdName($eqTypeName, $eqLogicName, $cmdName) {
        $values = [
            'eqType_name' => $eqTypeName,
            'eqLogic_name' => $eqLogicName,
            'cmd_name' => $cmdName,
        ];
        $sql = static::getPrefixedBaseSQL('c') . '
                INNER JOIN `eqLogic` el ON c.eqLogic_id=el.id
                WHERE c.name = :cmd_name
                AND el.name = :eqLogic_name
                AND el.eqType_name = :eqType_name';
        return self::cast(DBHelper::Prepare($sql, $values, DBHelper::FETCH_TYPE_ROW, \PDO::FETCH_CLASS, self::CLASS_NAME));
    }

    /**
     * Get commands by EqLogic Id and command name
     *
     * @param int $eqLogicId EqLogic id
     * @param string $cmdName Command name
     *
     * @return Cmd[]
     *
     * @throws \Exception
     */
    public static function byEqLogicIdCmdName($eqLogicId, $cmdName) {
        $values = [
            'eqLogic_id' => $eqLogicId,
            'cmd_name' => $cmdName,
        ];
        $sql = static::getPrefixedBaseSQL('c') . '
                WHERE c.name = :cmd_name
                AND c.eqLogic_id = :eqLogic_id';
        return self::cast(DBHelper::Prepare($sql, $values, DBHelper::FETCH_TYPE_ROW, \PDO::FETCH_CLASS, self::CLASS_NAME));
    }

    /**
     * Get commands by object and command name
     *
     * @param string $objectName Filter on object name
     * @param string $cmdName Filter by command name
     *
     * @return Cmd[]
     *
     * @throws \Exception
     */
    public static function byObjectNameCmdName($objectName, $cmdName) {
        $values = [
            'object_name' => $objectName,
            'cmd_name' => $cmdName,
        ];
        $sql = static::getPrefixedBaseSQL('c') . '
                INNER JOIN `eqLogic` el ON c.eqLogic_id = el.id
                INNER JOIN `object` ob ON el.object_id = ob.id
                WHERE c.name = :cmd_name
                AND ob.name = :object_name';
        return self::cast(DBHelper::getOneObject($sql, $values, self::CLASS_NAME));
    }

    /**
     * Get commands by type and subtype
     *
     * @param string $type Command type
     * @param string $subType Command subtype
     *
     * @return Cmd[]
     *
     * @throws \Exception
     */
    public static function byTypeSubType($type, $subType = '') {
        $values = [
            'type' => $type,
        ];
        $sql = static::getPrefixedBaseSQL('c') . '
                WHERE c.type = :type';
        if ($subType != '') {
            $values['subtype'] = $subType;
            $sql .= ' AND c.subtype = :subtype';
        }
        return self::cast(DBHelper::getAllObjects($sql, $values, self::CLASS_NAME));
    }

    /**
     * Convert command to human readable format
     *
     * @param Cmd|mixed $input Input data
     * @return string Human readable command
     * @throws \ReflectionException
     */
    public static function cmdToHumanReadable($input) {
        if (is_object($input)) {
            $reflections = [];
            $uuid = spl_object_hash($input);
            if (!isset($reflections[$uuid])) {
                $reflections[$uuid] = new \ReflectionClass($input);
            }
            $reflection = $reflections[$uuid];
            /** @var \ReflectionProperty[] $properties */
            $properties = $reflection->getProperties();
            foreach ($properties as $property) {
                $property->setAccessible(true);
                $value = $property->getValue($input);
                $property->setValue($input, self::cmdToHumanReadable($value));
                $property->setAccessible(false);
            }
            return $input;
        }
        if (is_array($input)) {
            return json_decode(self::cmdToHumanReadable(json_encode($input)), true);
        }
        $replace = [];
        preg_match_all("/#([0-9]*)#/", $input, $matches);
        if (count($matches[1]) == 0) {
            return $input;
        }
        $cmds = self::byIds($matches[1]);
        foreach ($cmds as $cmd) {
            if (isset($replace['#' . $cmd->getId() . '#'])) {
                continue;
            }
            $replace['#' . $cmd->getId() . '#'] = '#' . $cmd->getHumanName() . '#';
        }
        return str_replace(array_keys($replace), $replace, $input);
    }

    /**
     * Get list of commands by IDs
     *
     * @param array $idsList List of ID
     *
     * @return Cmd[]|null List of commands
     *
     * @throws \Exception
     */
    public static function byIds($idsList) {
        if (!is_array($idsList) || count($idsList) == 0) {
            return [];
        }
        $in = trim(preg_replace('/[, ]{2,}/m', ',', implode(',', $idsList)), ',');
        if ($in === '') {
            return [];
        }
        $sql = static::getBaseSQL() . '
                WHERE `id` IN (' . $in . ')';
        return self::cast(DBHelper::getAllObjects($sql, [], self::CLASS_NAME));
    }

    /**
     * Get commands by string in human readeable format
     *
     * @param string $needle String to search
     *
     * @return Cmd
     *
     * @throws \Exception
     */
    public static function byString($needle) {
        $cmd = self::byId(str_replace('#', '', self::humanReadableToCmd($needle)));
        if (!is_object($cmd)) {
            throw new CoreException(__('La commande n\'a pas pu être trouvée : ') . $needle . __(' => ') . self::humanReadableToCmd($needle));
        }
        return $cmd;
    }

    /**
     * Convert human readable format to command
     *
     * @param $input
     *
     * @return string
     *
     * @throws \Exception
     */
    public static function humanReadableToCmd($input) {
        $isJson = false;
        if (Utils::isJson($input)) {
            $isJson = true;
            $input = json_decode($input, true);
        }
        if (is_object($input)) {
            $reflections = [];
            $uuid = spl_object_hash($input);
            if (!isset($reflections[$uuid])) {
                $reflections[$uuid] = new \ReflectionClass($input);
            }
            $reflection = $reflections[$uuid];
            /** @var \ReflectionProperty[] $properties */
            $properties = $reflection->getProperties();
            foreach ($properties as $property) {
                $property->setAccessible(true);
                $value = $property->getValue($input);
                $property->setValue($input, self::humanReadableToCmd($value));
                $property->setAccessible(false);
            }
            return $input;
        }
        if (is_array($input)) {
            foreach ($input as $key => $value) {
                $input[$key] = self::humanReadableToCmd($value);
            }
            if ($isJson) {
                return json_encode($input, JSON_UNESCAPED_UNICODE);
            }
            return $input;
        }
        $replace = [];
        preg_match_all("/#\[(.*?)\]\[(.*?)\]\[(.*?)\]#/", $input, $matches);
        if (count($matches) == 4) {
            $countMatches = count($matches[0]);
            for ($i = 0; $i < $countMatches; $i++) {
                if (isset($replace[$matches[0][$i]])) {
                    continue;
                }
                if (isset($matches[1][$i]) && isset($matches[2][$i]) && isset($matches[3][$i])) {
                    $cmd = self::byObjectNameEqLogicNameCmdName($matches[1][$i], $matches[2][$i], $matches[3][$i]);
                    if (is_object($cmd)) {
                        $replace[$matches[0][$i]] = '#' . $cmd->getId() . '#';
                    }
                }
            }
        }
        return str_replace(array_keys($replace), $replace, $input);
    }

    /**
     * Get command by object name, eqLogic name and cmd name
     *
     * @param string $objectName Object name
     * @param string $eqLogicName EqLogic name
     * @param string $cmdName Command name
     *
     * @return Cmd
     *
     * @throws \Exception
     */
    public static function byObjectNameEqLogicNameCmdName($objectName, $eqLogicName, $cmdName) {
        $values = [
            'eqLogic_name' => $eqLogicName,
            'cmd_name' => (html_entity_decode($cmdName) != '') ? html_entity_decode($cmdName) : $cmdName,
        ];

        if ($objectName == __('Aucun')) {
            $sql = static::getPrefixedBaseSQL('c') . '
            INNER JOIN `eqLogic` el ON c.eqLogic_id=el.id
            WHERE c.name = :cmd_name
            AND el.name = :eqLogic_name
            AND el.object_id IS NULL';
        } else {
            $values['object_name'] = $objectName;
            $sql = static::getPrefixedBaseSQL('c') . '
            INNER JOIN `eqLogic` el ON c.eqLogic_id=el.id
            INNER JOIN `object` ob ON el.object_id=ob.id
            WHERE c.name = :cmd_name
            AND el.name = :eqLogic_name
            AND ob.name = :object_name';
        }
        return self::cast(DBHelper::getOneObject($sql, $values, self::CLASS_NAME));
    }

    /**
     * Convert command to value
     *
     * @param mixed $input Input data
     * @param bool $quote Quote result
     *
     * @return array|mixed
     *
     * @throws \NextDom\Exceptions\CoreException
     * @throws \ReflectionException
     */
    public static function cmdToValue($input, $quote = false) {
        if (is_object($input)) {
            $reflections = [];
            $uuid = spl_object_hash($input);
            if (!isset($reflections[$uuid])) {
                $reflections[$uuid] = new \ReflectionClass($input);
            }
            $reflection = $reflections[$uuid];
            /** @var \ReflectionProperty[] $properties */
            $properties = $reflection->getProperties();
            foreach ($properties as $property) {
                $property->setAccessible(true);
                $value = $property->getValue($input);
                $property->setValue($input, self::cmdToValue($value, $quote));
                $property->setAccessible(false);
            }
            return $input;
        }
        if (is_array($input)) {
            foreach ($input as $key => $value) {
                $input[$key] = self::cmdToValue($value, $quote);
            }
            return $input;
        }

        $replace = [];
        preg_match_all("/#([0-9]*)#/", $input, $matches);
        foreach ($matches[1] as $cmd_id) {
            if (isset($replace['#' . $cmd_id . '#'])) {
                continue;
            }
            $mc = CacheManager::byKey('cmdCacheAttr' . $cmd_id);
            $cmdCacheAttrValue = $mc->getValue();
            if (Utils::getJsonAttr($cmdCacheAttrValue, 'value', null) !== null) {
                $cmdCacheAttrValue = $mc->getValue();
                $collectDate = Utils::getJsonAttr($cmdCacheAttrValue, 'collectDate', date(DateFormat::FULL));
                $valueDate = Utils::getJsonAttr($cmdCacheAttrValue, 'valueDate', date(DateFormat::FULL));
                $cmd_value = Utils::getJsonAttr($cmdCacheAttrValue, 'value', '');
            } else {
                $cmd = self::byId($cmd_id);
                if (!is_object($cmd) || !$cmd->isType(CmdType::INFO)) {
                    continue;
                }
                $cmd_value = $cmd->execCmd(null, true, $quote);
                $collectDate = $cmd->getCollectDate();
                $valueDate = $cmd->getValueDate();
            }
            if ($quote && (strpos($cmd_value, ' ') !== false || preg_match("/[a-zA-Z#]/", $cmd_value) || $cmd_value === '')) {
                $cmd_value = '"' . trim($cmd_value, '"') . '"';
            }
            if (Utils::isJson($input)) {
                $replace['#' . $cmd_id . '#'] = trim(json_encode($cmd_value), '"');
                $replace['#valueDate' . $cmd_id . '#'] = trim(json_encode($valueDate), '"');
                $replace['#collectDate' . $cmd_id . '#'] = trim(json_encode($collectDate), '"');
            } else {
                $replace['"#' . $cmd_id . '#"'] = $cmd_value;
                $replace['#' . $cmd_id . '#'] = $cmd_value;
                $replace['#collectDate' . $cmd_id . '#'] = $collectDate;
                $replace['#valueDate' . $cmd_id . '#'] = $valueDate;
            }
        }
        return str_replace(array_keys($replace), $replace, $input);
    }

    /**
     * Get all used command types
     *
     * @return array|null All commands type
     *
     * @throws \Exception
     */
    public static function allType() {
        $sql = 'SELECT DISTINCT(`type`) as type
                FROM ' . self::DB_CLASS_NAME;
        return DBHelper::getAll($sql);
    }

    /**
     * Get all used command sub types
     *
     * @param string $type Filter by type
     *
     * @return array All subtype
     *
     * @throws \Exception
     */
    public static function allSubType($type = '') {
        $values = [];
        $sql = 'SELECT distinct(`subType`) as subtype';
        if ($type != '') {
            $values['type'] = $type;
            $sql .= ' WHERE `type` = :type';
        }
        $sql .= ' FROM ' . self::DB_CLASS_NAME;
        return DBHelper::getAll($sql, $values);
    }

    /**
     * Get all used unites
     *
     * @return array|mixed|null
     * @throws \Exception
     */
    public static function allUnite() {
        $sql = 'SELECT DISTINCT(`unite`) as unite
                FROM ' . self::DB_CLASS_NAME;
        return DBHelper::getAll($sql);
    }

    /**
     * Convert color to hexadecimal code
     *
     * @param string $color Color identification
     *
     * @return string Hexadecimal format color
     *
     * @throws \Exception
     */
    public static function convertColor($color) {
        $colors = ConfigManager::byKey('convertColor');
        if (isset($colors[$color])) {
            return $colors[$color];
        }
        throw new CoreException(__('Impossible de traduire la couleur en code hexadécimal :') . $color);
    }

    /**
     * Force command to return state by event
     *
     * @param array $options Options that contains command id
     *
     * @throws \Exception
     */
    public static function returnState($options) {
        $cmd = self::byId($options['cmd_id']);
        if (is_object($cmd)) {
            $cmd->event($cmd->getConfiguration('returnStateValue', 0));
        }
    }

    /**
     * List of dead commands
     *
     * @return array Description of all dead commands
     *
     * @throws \Exception
     */
    public static function deadCmd() {
        $result = [];
        $configToCheck = [
            'actionCheckCmd' => 'Action sur valeur',
            'nextdomPostExecCmd' => 'Post Exécution',
            'nextdomPreExecCmd' => 'Pré Exécution'
        ];
        foreach (self::all() as $cmd) {
            foreach ($configToCheck as $configCode => $message) {
                if (is_array($cmd->getConfiguration($configCode, ''))) {
                    foreach ($cmd->getConfiguration($configCode, '') as $actionCmd) {
                        if ($actionCmd['cmd'] != '' && strpos($actionCmd['cmd'], '#') !== false) {
                            if (!self::byId(str_replace('#', '', $actionCmd['cmd']))) {
                                $result[] = ['detail' => 'Commande ' . $cmd->getName() . ' de ' . $cmd->getEqLogicId()->getName() . ' (' . $cmd->getEqLogicId()->getEqType_name() . ')', 'help' => $message, 'who' => $actionCmd['cmd']];
                            }
                        }
                    }
                }
            }
        }
        return $result;
    }

    /**
     * Get all commands
     *
     * @return Cmd[] All commands
     *
     * @throws \Exception
     */
    public static function all() {
        $sql = static::getBaseSQL() . '
                ORDER BY `id`';
        return self::cast(DBHelper::getAllObjects($sql, [], self::CLASS_NAME));
    }

    /**
     * Execute command and alert this execution
     *
     * @param array $options Options that contains command id
     *
     * @throws \Exception
     */
    public static function cmdAlert($options) {
        $cmd = self::byId($options['cmd_id']);
        if (!is_object($cmd)) {
            return;
        }
        $value = $cmd->execCmd();
        $check = NextDomHelper::evaluateExpression($value . $cmd->getConfiguration('nextdomCheckCmdOperator') . $cmd->getConfiguration('nextdomCheckCmdTest'));
        if ($check == 1 || $check || $check == '1') {
            $cmd->executeAlertCmdAction();
        }
    }

    /**
     * Show command timeline
     *
     * @param array $event Event data
     *
     * @return array Timeline data
     *
     * @throws \Exception
     */
    public static function timelineDisplay($event) {
        $result = [];
        $result['date'] = $event['datetime'];
        $result['type'] = $event['type'];
        $result['group'] = $event['subtype'];
        $cmd = self::byId($event['id']);
        if (!is_object($cmd)) {
            return null;
        }
        $eqLogic = $cmd->getEqLogicId();
        $linkedObject = $eqLogic->getObject();
        $result['object'] = is_object($linkedObject) ? $linkedObject->getId() : 'aucun';
        $result['plugins'] = $eqLogic->getEqType_name();
        $result['category'] = $eqLogic->getCategory();

        if ($event['subtype'] == 'action') {
            $result['html'] = '<div class="timeline-item cmd" data-id="' . $event['id'] . '">'
                    . '<span class="time"><i class="fa fa-clock-o spacing-right"></i>' . trim(substr($event['datetime'], -9)) . '</span>'
                    . '<h3 class="timeline-header">' . $event['name'] . '</h3>'
                    . '<div class="timeline-body">'
                    . $event['options']
                    . '<div class="timeline-footer">'
                    . '</div>'
                    . '</div>';
        } else {
            $result['html'] = '<div class="timeline-item cmd" data-id="' . $event['id'] . '">'
                    . '<span class="time"><i class="fa fa-clock-o spacing-right"></i>' . trim(substr($event['datetime'], -9)) . '</span>'
                    . '<h3 class="timeline-header">' . $event['name'] . '</h3>'
                    . '<div class="timeline-body">'
                    . $event['value']
                    . '<div class="timeline-footer">'
                    . '</div>'
                    . '</div>';
        }
        return $result;
    }

    public static function checkAlertCmds($alertConfigKey, $alertType, $message, $logicalId) {
        if (ConfigManager::ByKey($alertConfigKey) == 1) {
            MessageManager::add('core', $message, '', $logicalId);
        }
        $cmds = explode(('&&'), ConfigManager::byKey($alertType));
        if (count($cmds) > 0 && trim(ConfigManager::byKey($alertType)) != '') {
            foreach ($cmds as $id) {
                $cmd = CmdManager::byId(str_replace('#', '', $id));
                if (is_object($cmd)) {
                    $cmd->execCmd([
                        'title' => '[NextDom]' . $message,
                        'message' => 'NextDom : ' . $message,
                    ]);
                }
            }
        }
    }

}