. */ /* * ***************************Includes********************************* */ require_once __DIR__ . '/../../core/php/core.inc.php'; class scenario { /* * *************************Attributs****************************** */ private $id; private $name; private $isActive = 1; private $group = ''; private $mode; private $schedule; private $scenarioElement; private $trigger; private $_log; private $timeout = 0; private $object_id = null; private $isVisible = 0; private $display; private $order = 9999; private $description; private $configuration; private static $_templateArray; private $_elements = array(); private $_changeState = false; private $_realTrigger = ''; private $_realTriggerValue = ''; /** @var bool */ private $_return = true; private $_tags = array(); private $_do = true; private $_changed = false; /* * ***********************Méthodes statiques*************************** */ /** * Renvoie un objet scenario * @param int $_id id du scenario voulu * @return scenario object scenario */ public static function byId($_id) { $values = array( 'id' => $_id, ); $sql = 'SELECT ' . DB::buildField(__CLASS__) . ' FROM scenario WHERE id=:id'; return DB::Prepare($sql, $values, DB::FETCH_TYPE_ROW, PDO::FETCH_CLASS, __CLASS__); } public static function byString($_string) { $scenario = self::byId(str_replace('#scenario', '', self::fromHumanReadable($_string))); if (!is_object($scenario)) { throw new Exception($GLOBALS['JEEDOM_SCLOG_TEXT']['unfoundCmd']['txt'] . ' : ' . $_string . ' => ' . self::fromHumanReadable($_string)); } return $scenario; } /** * Renvoie tous les objets scenario * @return [] scenario object scenario */ public static function all($_group = '') { $values = array(); if ($_group === '') { $sql = 'SELECT ' . DB::buildField(__CLASS__, 's') . ' FROM scenario s INNER JOIN object ob ON s.object_id=ob.id ORDER BY ob.name, s.group, s.name'; $result1 = DB::Prepare($sql, $values, DB::FETCH_TYPE_ALL, PDO::FETCH_CLASS, __CLASS__); if (!is_array($result1)) { $result1 = array(); } $sql = 'SELECT ' . DB::buildField(__CLASS__, 's') . ' FROM scenario s WHERE s.object_id IS NULL ORDER BY s.group, s.name'; $result2 = DB::Prepare($sql, $values, DB::FETCH_TYPE_ALL, PDO::FETCH_CLASS, __CLASS__); if (!is_array($result2)) { $result2 = array(); } $sql = 'SELECT ' . DB::buildField(__CLASS__, 's') . ' FROM scenario s LEFT JOIN object ob ON s.object_id=ob.id WHERE ob.id IS NULL AND s.object_id IS NOT NULL ORDER BY s.group, s.name'; $result3 = DB::Prepare($sql, $values, DB::FETCH_TYPE_ALL, PDO::FETCH_CLASS, __CLASS__); if (!is_array($result3)) { $result3 = array(); } return array_merge($result1, $result2,$result3); } elseif ($_group === null) { $sql = 'SELECT ' . DB::buildField(__CLASS__, 's') . ' FROM scenario s INNER JOIN object ob ON s.object_id=ob.id WHERE (`group` IS NULL OR `group` = "") ORDER BY s.group, s.name'; $result1 = DB::Prepare($sql, $values, DB::FETCH_TYPE_ALL, PDO::FETCH_CLASS, __CLASS__); if (!is_array($result1)) { $result1 = array(); } $sql = 'SELECT ' . DB::buildField(__CLASS__, 's') . ' FROM scenario s WHERE (`group` IS NULL OR `group` = "") AND s.object_id IS NULL ORDER BY s.name'; $result2 = DB::Prepare($sql, $values, DB::FETCH_TYPE_ALL, PDO::FETCH_CLASS, __CLASS__); if (!is_array($result2)) { $result2 = array(); } $sql = 'SELECT ' . DB::buildField(__CLASS__, 's') . ' FROM scenario s LEFT JOIN object ob ON s.object_id=ob.id WHERE (`group` IS NULL OR `group` = "") AND ob.id IS NULL AND s.object_id IS NOT NULL ORDER BY s.group, s.name'; $result3 = DB::Prepare($sql, $values, DB::FETCH_TYPE_ALL, PDO::FETCH_CLASS, __CLASS__); if (!is_array($result3)) { $result3 = array(); } return array_merge($result1, $result2,$result3); } else { $values = array( 'group' => $_group, ); $sql = 'SELECT ' . DB::buildField(__CLASS__, 's') . ' FROM scenario s INNER JOIN object ob ON s.object_id=ob.id WHERE `group`=:group ORDER BY ob.name,s.group, s.name'; $result1 = DB::Prepare($sql, $values, DB::FETCH_TYPE_ALL, PDO::FETCH_CLASS, __CLASS__); $sql = 'SELECT ' . DB::buildField(__CLASS__, 's') . ' FROM scenario s WHERE `group`=:group AND s.object_id IS NULL ORDER BY s.group, s.name'; $result2 = DB::Prepare($sql, $values, DB::FETCH_TYPE_ALL, PDO::FETCH_CLASS, __CLASS__); if (!is_array($result2)) { $result2 = array(); } $sql = 'SELECT ' . DB::buildField(__CLASS__, 's') . ' FROM scenario s LEFT JOIN object ob ON s.object_id=ob.id WHERE `group`=:group AND ob.id IS NULL AND s.object_id IS NOT NULL ORDER BY s.group, s.name'; $result3 = DB::Prepare($sql, $values, DB::FETCH_TYPE_ALL, PDO::FETCH_CLASS, __CLASS__); if (!is_array($result3)) { $result3 = array(); } return array_merge($result1, $result2,$result3); } } /** * return all scenarios ordered by [group][objectName][scenarioName] * @return [] array of scenario object */ public static function allOrderedByGroupObjectName($_asGroup = false) { $scenarioList = array(); $scenarios = array(); $scenarios[-1] = scenario::all(null); $scenarioListGroup = scenario::listGroup(); if (is_array($scenarioListGroup)) { foreach ($scenarioListGroup as $group) { $scenarios[$group['group']] = scenario::all($group['group']); } } if (count($scenarios[-1]) > 0) { foreach ($scenarios[-1] as $scenario) { array_push($scenarioList, $scenario); } } foreach ($scenarioListGroup as $group) { if ($group['group'] == '') continue; foreach ($scenarios[$group['group']] as $scenario) { array_push($scenarioList, $scenario); } } if ($_asGroup) { $scenarioGroupedList = array(); foreach ($scenarioListGroup as $group) { $groupName = $group['group']; if ($groupName == '') $groupName = __('Aucun', __FILE__); $scenarioGroupedList[$groupName] = array(); foreach ($scenarioList as $scenario) { $scGroup = $scenario->getGroup(); if ($scGroup == '') $scGroup = __('Aucun', __FILE__); if ($scGroup != $groupName) continue; array_push($scenarioGroupedList[$groupName], $scenario); } } return $scenarioGroupedList; } return $scenarioList; } /** * * @return scenario[] */ public static function schedule() { $sql = 'SELECT ' . DB::buildField(__CLASS__) . ' FROM scenario WHERE `mode` != "provoke" AND `mode` != "" AND `schedule` != "" AND isActive=1'; return DB::Prepare($sql, array(), DB::FETCH_TYPE_ALL, PDO::FETCH_CLASS, __CLASS__); } /** * * @param string $_group * @return scenario[] */ public static function listGroup($_group = null) { $values = array(); $sql = 'SELECT DISTINCT(`group`) FROM scenario'; if ($_group !== null) { $values['group'] = '%' . $_group . '%'; $sql .= ' WHERE `group` LIKE :group'; } $sql .= ' ORDER BY `group`'; return DB::Prepare($sql, $values, DB::FETCH_TYPE_ALL); } /** * * @param string $_cmd_id * @param bool $_onlyEnable * @return scenario[] */ public static function byTrigger($_cmd_id, $_onlyEnable = true) { $values = array( 'cmd_id' => '%#' . $_cmd_id . '#%', ); $sql = 'SELECT ' . DB::buildField(__CLASS__) . ' FROM scenario WHERE mode != "schedule"'; if ($_onlyEnable) { $sql .= ' AND isActive=1'; } $sql .= ' AND `trigger` LIKE :cmd_id'; return DB::Prepare($sql, $values, DB::FETCH_TYPE_ALL, PDO::FETCH_CLASS, __CLASS__); } /** * * @param string $_generic * @param object $_object * @param bool $_onlyEnable * @return scenario[] */ public static function byGenericTrigger($_generic, $_object, $_onlyEnable = true) { $values = array('trigger' => '%genericType(' . $_generic . ')%'); $sql = 'SELECT ' . DB::buildField(__CLASS__) . ' FROM scenario WHERE mode != "schedule" AND `trigger` LIKE :trigger'; if (is_object($_object)) { $values['triggerObject'] = '%genericType(' . $_generic . ',#object' . $_object->getId() . '#)%'; $sql .= ' OR `trigger` LIKE :triggerObject'; } if ($_onlyEnable) { $sql .= ' AND isActive=1'; } return DB::Prepare($sql, $values, DB::FETCH_TYPE_ALL, PDO::FETCH_CLASS, __CLASS__); } /** * * @param string $_element_id * @return scenario */ public static function byElement($_element_id) { $values = array( 'element_id' => '%"' . $_element_id . '"%', ); $sql = 'SELECT ' . DB::buildField(__CLASS__) . ' FROM scenario WHERE `scenarioElement` LIKE :element_id'; return DB::Prepare($sql, $values, DB::FETCH_TYPE_ROW, PDO::FETCH_CLASS, __CLASS__); } /** * * @param null|int $_object_id * @param bool $_onlyEnable * @param bool $_onlyVisible * @return scenario[] */ public static function byObjectId($_object_id, $_onlyEnable = true, $_onlyVisible = false) { $values = array(); $sql = 'SELECT ' . DB::buildField(__CLASS__) . ' FROM scenario'; if ($_object_id === null) { $sql .= ' WHERE object_id IS NULL'; } else { $values['object_id'] = $_object_id; $sql .= ' WHERE object_id=:object_id'; } if ($_onlyEnable) { $sql .= ' AND isActive = 1'; } if ($_onlyVisible) { $sql .= ' AND isVisible = 1'; } $sql .= ' ORDER BY `order`'; return DB::Prepare($sql, $values, DB::FETCH_TYPE_ALL, PDO::FETCH_CLASS, __CLASS__); } /** * * @param null|object|string $_event * @param bool $_forceSyncMode * @param null|string $_generic * @param null|object $_object * @param null|string $_value * @return void|true */ public static function check($_event = null, $_forceSyncMode = false, $_generic = null, $_object = null, $_value = null, $_options = null) { if (config::byKey('enableScenario') != 1) { return; } $message = ''; if ($_event !== null) { //check from a cmd event: $scenarios = array(); if (is_object($_event)) { $scenarios1 = self::byTrigger($_event->getId()); $trigger = '#' . $_event->getId() . '#'; $message = $GLOBALS['JEEDOM_SCLOG_TEXT']['startAutoOnEvent']['txt'] . $_event->getHumanName(); if ($_value !== null) { $message .= ' (' . $_value . ')'; } } else { $scenarios1 = self::byTrigger($_event); $trigger = $_event; $message = $GLOBALS['JEEDOM_SCLOG_TEXT']['startOnEvent']['txt'] . ' : #' . $_event . '#'; if ($_value !== null) { $message .= ' (' . $_value . ')'; } } //cmd generic trigger: if ($_generic) { $scenarios2 = self::byGenericTrigger($_generic, $_object, true); if (is_array($scenarios2) && count($scenarios2) > 0) { foreach ($scenarios2 as $scenario) { if ($scenario->testTrigger($trigger)) { $message = $GLOBALS['JEEDOM_SCLOG_TEXT']['startAutoOnEvent']['txt']; if (is_object($_object)) { $message .= ' genericType(' . $_generic . ',#[' . $_object->getName() . ']#) from ' . $_event->getHumanName(); } else { $message .= ' genericType(' . $_generic . ')' . ' from ' . $_event->getHumanName(); } $scenario->launch($trigger, $message, $_forceSyncMode); } } } } if (is_array($scenarios1) && count($scenarios1) > 0) { foreach ($scenarios1 as $scenario) { if ($scenario->testTrigger($trigger)) { $scenarios[] = $scenario; } } } } else { $message = $GLOBALS['JEEDOM_SCLOG_TEXT']['startAutoOnShedule']['txt']; $scenarios = scenario::schedule(); $trigger = 'schedule'; if (jeedom::isDateOk()) { foreach ($scenarios as $key => &$scenario) { if ($scenario->getState() == 'in progress' && $scenario->getConfiguration('allowMultiInstance', 0) == 0) { unset($scenarios[$key]); } else if (!$scenario->isDue()) { unset($scenarios[$key]); } } } } if (count($scenarios) > 0) { foreach ($scenarios as $scenario_) { $scenario_->launch($trigger, $message, $_forceSyncMode, $_options); } } return true; } public static function control() { foreach ((scenario::all()) as $scenario) { if ($scenario->getState() != 'in progress') { continue; } if (!$scenario->running()) { $scenario->setState('error'); continue; } $runtime = strtotime('now') - strtotime($scenario->getLastLaunch()); if (is_numeric($scenario->getTimeout()) && $scenario->getTimeout() != '' && $scenario->getTimeout() != 0 && $runtime > $scenario->getTimeout()) { $scenario->stop(); $scenario->setLog($GLOBALS['JEEDOM_SCLOG_TEXT']['stopTimeout']['txt'] . $scenario->getTimeout() . 's'); $scenario->persistLog(); log::add('scenario', 'info', $scenario->getHumanName() . ' ' . $GLOBALS['JEEDOM_SCLOG_TEXT']['stopTimeout']['txt'] . $scenario->getTimeout() . 's'); } } } /** * * @param array $_options * @return void */ public static function doIn($_options) { if (config::byKey('enableScenario') != 1) { return; } $scenario = self::byId($_options['scenario_id']); if (!is_object($scenario)) { return; } if ($scenario->getIsActive() == 0) { $scenario->setLog($GLOBALS['JEEDOM_SCLOG_TEXT']['disableNoSubtask']['txt']); $scenario->persistLog(); return; } $scenarioElement = scenarioElement::byId($_options['scenarioElement_id']); $scenario->setLog($GLOBALS['JEEDOM_SCLOG_TEXT']['startSubTask']['txt']); if (isset($_options['tags']) && is_array($_options['tags']) && count($_options['tags']) > 0) { $scenario->setTags($_options['tags']); $scenario->setLog(__('Tags :', __FILE__) . ' ' . json_encode($scenario->getTags())); } if (!is_object($scenarioElement) || !is_object($scenario)) { $scenario->setLog($GLOBALS['JEEDOM_SCLOG_TEXT']['toStartUnfound']['txt']); $scenario->persistLog(); return; } if (is_numeric($_options['second']) && $_options['second'] > intval(date('s'))) { sleep($_options['second'] - intval(date('s'))); } $scenarioElement->getSubElement('do')->execute($scenario); $scenario->setLog($GLOBALS['JEEDOM_SCLOG_TEXT']['endSubTask']['txt']); $scenario->persistLog(); } /** * */ public static function cleanTable() { $ids = array( 'element' => array(), 'subelement' => array(), 'expression' => array(), ); foreach ((scenario::all()) as $scenario) { foreach (($scenario->getElement()) as $element) { $result = $element->getAllId(); $ids['element'] = array_merge($ids['element'], $result['element']); $ids['subelement'] = array_merge($ids['subelement'], $result['subelement']); $ids['expression'] = array_merge($ids['expression'], $result['expression']); } } $sql = 'DELETE FROM scenarioExpression WHERE id NOT IN (-1'; foreach ($ids['expression'] as $expression_id) { $sql .= ',' . $expression_id; } $sql .= ')'; DB::Prepare($sql, array(), DB::FETCH_TYPE_ALL); $sql = 'DELETE FROM scenarioSubElement WHERE id NOT IN (-1'; foreach ($ids['subelement'] as $subelement_id) { $sql .= ',' . $subelement_id; } $sql .= ')'; DB::Prepare($sql, array(), DB::FETCH_TYPE_ALL); $sql = 'DELETE FROM scenarioElement WHERE id NOT IN (-1'; foreach ($ids['element'] as $element_id) { $sql .= ',' . $element_id; } $sql .= ')'; DB::Prepare($sql, array(), DB::FETCH_TYPE_ALL); } public static function consystencyCheck($_needsReturn = false) { $return = array(); $scenarios = self::all(); foreach ($scenarios as $scenario) { if ($scenario->getGroup() == '') { $group = __('Aucun', __FILE__); } else { $group = $scenario->getGroup(); } if ($scenario->getIsActive() != 1) { if (!$_needsReturn) { continue; } } //check scenario triggers: if ($scenario->getMode() == 'provoke' || $scenario->getMode() == 'all') { $trigger_list = ''; foreach (($scenario->getTrigger()) as $trigger) { $trigger_list .= cmd::cmdToHumanReadable($trigger) . '_'; } preg_match_all("/#([0-9]*)#/", $trigger_list, $matches); foreach ($matches[1] as $cmd_id) { if (is_numeric($cmd_id)) { if ($_needsReturn) { $return[] = array( 'detail' => '' . $scenario->getHumanName() . '', 'help' => __('Déclencheur', __FILE__), 'who' => '#' . $cmd_id . '#' ); } else { log::add('scenario', 'error', __('Un déclencheur du scénario :', __FILE__) . ' ' . $scenario->getHumanName() . ' ' . __('est introuvable', __FILE__)); } } } } //check scenario expressions: $expression_list = ''; $elements = $scenario->getElement(); foreach ($elements as $element) { $expression_list .= cmd::cmdToHumanReadable(json_encode($element->getAjaxElement())); } preg_match_all("/#([0-9]*)#/", $expression_list, $matches); foreach ($matches[1] as $cmd_id) { if (is_numeric($cmd_id)) { if ($_needsReturn) { $return[] = array( 'detail' => '' . $scenario->getHumanName() . '', 'help' => __('Expression', __FILE__), 'who' => '#' . $cmd_id . '#' ); } else { log::add('scenario', 'error', __('Une commande du scénario :', __FILE__) . ' ' . $scenario->getHumanName() . ' ' . __('est introuvable', __FILE__)); } } } } if ($_needsReturn) { return $return; } } /** * @param string $_object_name * @param string $_group_name * @param string $_scenario_name * @return scenario */ public static function byObjectNameGroupNameScenarioName($_object_name, $_group_name, $_scenario_name) { $values = array( 'scenario_name' => html_entity_decode($_scenario_name), ); if ($_object_name == __('Aucun', __FILE__)) { if ($_group_name == __('Aucun', __FILE__)) { $sql = 'SELECT ' . DB::buildField(__CLASS__, 's') . ' FROM scenario s WHERE s.name=:scenario_name AND (`group` IS NULL OR `group`="" OR `group`="Aucun" OR `group`="None") AND s.object_id IS NULL'; } else { $values['group_name'] = $_group_name; $sql = 'SELECT ' . DB::buildField(__CLASS__, 's') . ' FROM scenario s WHERE s.name=:scenario_name AND s.object_id IS NULL AND `group`=:group_name'; } } else { $values['object_name'] = $_object_name; if ($_group_name == __('Aucun', __FILE__)) { $sql = 'SELECT ' . DB::buildField(__CLASS__, 's') . ' FROM scenario s INNER JOIN object ob ON s.object_id=ob.id WHERE s.name=:scenario_name AND ob.name=:object_name AND (`group` IS NULL OR `group`="" OR `group`="Aucun" OR `group`="None")'; } else { $values['group_name'] = $_group_name; $sql = 'SELECT ' . DB::buildField(__CLASS__, 's') . ' FROM scenario s INNER JOIN object ob ON s.object_id=ob.id WHERE s.name=:scenario_name AND ob.name=:object_name AND `group`=:group_name'; } } return DB::Prepare($sql, $values, DB::FETCH_TYPE_ROW, PDO::FETCH_CLASS, __CLASS__); } /** * @name toHumanReadable() * @param object $_input * @return string */ public static function toHumanReadable($_input) { if (is_object($_input)) { $reflections = array(); $uuid = spl_object_hash($_input); if (!isset($reflections[$uuid])) { $reflections[$uuid] = new ReflectionClass($_input); } $reflection = $reflections[$uuid]; $properties = $reflection->getProperties(); foreach ($properties as $property) { $property->setAccessible(true); $value = $property->getValue($_input); $property->setValue($_input, self::toHumanReadable($value)); $property->setAccessible(false); } return $_input; } if (is_array($_input)) { foreach ($_input as $key => $value) { $_input[$key] = self::toHumanReadable($value); } return $_input; } $text = $_input; preg_match_all("/#scenario([0-9]*)#/", $text, $matches); foreach ($matches[1] as $scenario_id) { if (is_numeric($scenario_id)) { $scenario = self::byId($scenario_id); if (is_object($scenario)) { $text = str_replace('#scenario' . $scenario_id . '#', '#' . $scenario->getHumanName(true) . '#', $text); } } } return $text; } /** * * @param string|object|array $_input * @return string|object|array return value will depends on $_input received */ public static function fromHumanReadable($_input) { $isJson = false; if (is_json($_input)) { $isJson = true; $_input = json_decode($_input, true); } if (is_object($_input)) { $reflections = array(); $uuid = spl_object_hash($_input); if (!isset($reflections[$uuid])) { $reflections[$uuid] = new ReflectionClass($_input); } $reflection = $reflections[$uuid]; $properties = $reflection->getProperties(); foreach ($properties as $property) { $property->setAccessible(true); $value = $property->getValue($_input); $property->setValue($_input, self::fromHumanReadable($value)); $property->setAccessible(false); } return $_input; } if (is_array($_input)) { foreach ($_input as $key => $value) { $_input[$key] = self::fromHumanReadable($value); } if ($isJson) { return json_encode($_input, JSON_UNESCAPED_UNICODE); } return $_input; } $text = $_input; preg_match_all("/#\[(.*?)\]\[(.*?)\]\[(.*?)\]#/", $text, $matches); if (count($matches) == 4) { $countMatches = count($matches[0]); for ($i = 0; $i < $countMatches; $i++) { if (isset($matches[1][$i]) && isset($matches[2][$i]) && isset($matches[3][$i])) { $scenario = self::byObjectNameGroupNameScenarioName($matches[2][$i], $matches[1][$i], $matches[3][$i]); if (is_object($scenario)) { $text = str_replace($matches[0][$i], '#scenario' . $scenario->getId() . '#', $text); } } } } return $text; } /** * * @param array $searchs * @return array */ public static function searchByUse($searchs) { $return = array(); $expressions = array(); $scenarios = array(); foreach ($searchs as $search) { $_cmd_id = str_replace('#', '', $search['action']); $return = array_merge($return, self::byTrigger($_cmd_id, false)); if (!isset($search['and'])) { $search['and'] = false; } if (!isset($search['option'])) { $search['option'] = $search['action']; } $expressions = array_merge($expressions, scenarioExpression::searchExpression($search['action'], $search['option'], $search['and'])); } if (is_array($expressions) && count($expressions) > 0) { foreach ($expressions as $expression) { $scenarios[] = $expression->getSubElement()->getElement()->getScenario(); } } if (is_array($scenarios) && count($scenarios) > 0) { foreach ($scenarios as $scenario) { if (is_object($scenario)) { $find = false; foreach ($return as $existScenario) { if ($scenario->getId() == $existScenario->getId()) { $find = true; break; } } if (!$find) { $return[] = $scenario; } } } } return $return; } /** * * @param string $_search * @param null|string $_options * @param bool $_and * @return scenario[] */ public static function searchByTrigger($_search, $_options = null, $_and = true) { $values = array( 'search' => '%' . $_search . '%', ); $sql = 'SELECT ' . DB::buildField(__CLASS__) . ' FROM ' . __CLASS__ . ' WHERE `trigger` LIKE :search'; if ($_options !== null) { $values['options'] = '%' . $_options . '%'; if ($_and) { $sql .= ' AND options LIKE :options'; } else { $sql .= ' OR options LIKE :options'; } } return DB::Prepare($sql, $values, DB::FETCH_TYPE_ALL, PDO::FETCH_CLASS, __CLASS__); } public static function getTemplate() { $path = __DIR__ . '/../../data/scenario'; return ls($path, '*.json', false, array('files', 'quiet')); } /* * *********************Méthodes d'instance************************* */ /** * * @param string $_event * @return boolean */ public function testTrigger($_event) { foreach (($this->getTrigger()) as $trigger) { $trigger = str_replace(array('#variable(', ')#'), array('variable(', ')'), $trigger); $trigger = str_replace(array('#genericType(', ')#'), array('genericType(', ')'), $trigger); if ($trigger == $_event) { return true; } elseif (strpos($trigger, $_event) !== false && jeedom::evaluateExpression($trigger)) { return true; } elseif (strpos($trigger, 'genericType') !== false && jeedom::evaluateExpression($trigger) !== false) { return true; } } return false; } /** * * @param string $_trigger * @param string $_message * @param boolean $_forceSyncMode * @return boolean */ public function launch($_trigger = '', $_message = '', $_forceSyncMode = false, $_options = null) { if (config::byKey('enableScenario') != 1 || $this->getIsActive() != 1) { return false; } $state = $this->getState(); if ($state == 'starting') { //Scenario stuck into starting state. May be too much sql connections, refused connection, or scenario hangs. if (strtotime('now') - $this->getCache('startingTime') > 5) { log::add('scenario', 'error', __('La dernière exécution du scénario ne s\'est pas lancée. Vérifiez le log scenario_execution, ainsi que le log du scénario', __FILE__) . " \"" . $this->getName() . "\"."); $this->setLog(__('La dernière exécution du scénario ne s\'est pas lancée. Vérifiez le log scenario_execution pour l\'exécution à', __FILE__) . ' ' . date('Y-m-d H:i:s', $this->getCache('startingTime')) . "."); $this->persistLog(); } //Delay scenario start if another instance ever starting. if (($this->getCache('startingTime') + 2) > strtotime('now')) { $i = 0; while ($state == 'starting') { sleep(1); $state = $this->getState(); $i++; if ($i > 10) { break; } } if ($state == 'starting') { log::add('scenario', 'error', __('Trop d\'appels simultanés du scénario, il ne peut-être exécuté une nouvelle fois. Il est conseillé de réduire les appels au scénario', __FILE__) . " \"" . $this->getName() . "\"."); $this->setLog(__('Trop d\'appels simultanés du scénario, il ne peut-être exécuté une nouvelle fois. Il est conseillé de réduire les appels à ce scénario', __FILE__) . "."); $this->persistLog(); return false; } } } if ($state == 'in progress' && $this->getConfiguration('allowMultiInstance', 0) == 0) { return false; } if (is_array($_options) && count($_options) > 0) { $tags = $this->getTags(); if (!is_array($tags)) { $tags = array(); } foreach ($_options as $key => $value) { $tags[$key] = $value; } $this->setTags($tags); } $this->setCache(array('startingTime' => strtotime('now'), 'state' => 'starting')); if ($this->getConfiguration('syncmode') == 1 || $_forceSyncMode) { $this->setLog($GLOBALS['JEEDOM_SCLOG_TEXT']['launchScenarioSync']['txt']); return $this->execute($_trigger, $_message); } else { if (count($this->getTags()) > 0) { $this->setCache('tags', $this->getTags()); } $cmd = __DIR__ . '/../../core/php/jeeScenario.php '; $cmd .= ' scenario_id=' . $this->getId(); $cmd .= ' trigger=' . escapeshellarg($_trigger); $cmd .= ' "message=' . escapeshellarg(sanitizeAccent(addslashes($_message))) . '"'; $cmd .= ' >> ' . log::getPathToLog('scenario_execution') . ' 2>&1 &'; system::php($cmd); } return true; } /** * * @param string $_trigger * @param string $_message */ public function execute($_trigger = '', $_message = '') { if (config::byKey('enableScenario') != 1) { return; } $tags = $this->getCache('tags'); if ($tags != '') { $this->setTags($tags); $this->setCache('tags', ''); } if ($this->getIsActive() != 1) { $this->setLog($GLOBALS['JEEDOM_SCLOG_TEXT']['disableScenario']['txt'] . $this->getHumanName() . ' ' . __('sur :', __FILE__) . ' ' . $_message . ' ' . __('car il est désactivé', __FILE__)); $this->setState('stop'); $this->setPID(); $this->persistLog(); return; } if ($this->getConfiguration('timeDependency', 0) == 1) { if (!jeedom::isDateOk() || (((new DateTime('today midnight +1 day'))->format('I') - (new DateTime('today midnight'))->format('I')) == -1 && date('I') == 1 && date('Gi') > 159)) { $this->setLog($GLOBALS['JEEDOM_SCLOG_TEXT']['launchScenario']['txt'] . $this->getHumanName() . ' ' . __('annulé car il utilise une condition de type temporelle et que la date système n\'est pas OK (ou que l\'on est en changement d\'heure négatif)', __FILE__)); $this->setState('stop'); $this->setPID(); $this->persistLog(); return; } } $cmd = cmd::byId(str_replace('#', '', $_trigger)); if (is_object($cmd)) { log::add('event', 'info', __('Exécution du scénario', __FILE__) . ' ' . $this->getHumanName() . ' ' . __('déclenché par :', __FILE__) . ' ' . $cmd->getHumanName()); if ($this->getConfiguration('timeline::enable')) { $timeline = new timeline(); $timeline->setType('scenario'); $timeline->setFolder($this->getConfiguration('timeline::folder')); $timeline->setLink_id($this->getId()); $timeline->setName($this->getHumanName(true, true, true, true)); $timeline->setOptions(array('trigger' => $cmd->getHumanName(true))); $timeline->save(); } $_triggerValue = $cmd->execCmd(); } else { log::add('event', 'info', __('Exécution du scénario', __FILE__) . ' ' . $this->getHumanName() . ' ' . __('déclenché par :', __FILE__) . ' ' . $_trigger); if ($this->getConfiguration('timeline::enable')) { $timeline = new timeline(); $timeline->setType('scenario'); $timeline->setFolder($this->getConfiguration('timeline::folder')); $timeline->setLink_id($this->getId()); $timeline->setName($this->getHumanName(true, true, true, true)); $timeline->setOptions(array('trigger' => ($_trigger == 'schedule') ? 'programmation' : $_trigger)); $timeline->save(); } $_triggerValue = 'none'; } if ($this->getState() == 'in progress' && $this->getConfiguration('allowMultiInstance', 0) == 0) { return; } if (count($this->getTags()) == 0) { $this->setLog($GLOBALS['JEEDOM_SCLOG_TEXT']['start']['txt'] . ' ' . trim($_message, "'") . '.'); } else { $this->setLog($GLOBALS['JEEDOM_SCLOG_TEXT']['start']['txt'] . ' ' . trim($_message, "'") . '. Tags : ' . json_encode($this->getTags())); } $this->setLastLaunch(date('Y-m-d H:i:s')); $this->setState('in progress'); $this->setPID(getmypid()); $this->setRealTrigger($_trigger); $this->setRealTriggerValue($_triggerValue); foreach (($this->getElement()) as $element) { if (!$this->getDo()) { break; } $element->execute($this); } $this->setState('stop'); $this->setPID(); $this->setLog($GLOBALS['JEEDOM_SCLOG_TEXT']['finishOk']['txt']); $this->persistLog(); return $this->getReturn(); } /** * * @param string $_name * @return \scenario */ public function copy($_name) { $scenarioCopy = clone $this; $scenarioCopy->setName($_name); $scenarioCopy->setId(''); $scenario_element_list = array(); foreach (($this->getElement()) as $element) { $scenario_element_list[] = $element->copy(); } $scenarioCopy->setScenarioElement($scenario_element_list); $scenarioCopy->setLog(''); $scenarioCopy->save(); if (file_exists(__DIR__ . '/../../log/scenarioLog/scenario' . $scenarioCopy->getId() . '.log')) { unlink(__DIR__ . '/../../log/scenarioLog/scenario' . $scenarioCopy->getId() . '.log'); } return $scenarioCopy; } /** * * @param string $_version * @return string */ public function toHtml($_version) { if (!$this->hasRight('r')) { return ''; } if (config::byKey('widget::disableCache', 'core', 0) == 0) { $mc = cache::byKey('scenarioHtml' . $_version . $this->getId()); if ($mc->getValue() != '') { return $mc->getValue(); } } $version = jeedom::versionAlias($_version); $name = ($this->getDisplay('name') != '') ? $this->getDisplay('name') : $this->getName(); $replace = array( '#id#' => $this->getId(), '#state#' => $this->getState(), '#isActive#' => $this->getIsActive(), '#name#' => $name, '#icon#' => $this->getIcon(), '#lastLaunch#' => $this->getLastLaunch(), '#scenarioLink#' => $this->getLinkToConfiguration(), '#version#' => $_version, '#height#' => $this->getDisplay('height', 'auto'), '#width#' => $this->getDisplay('width', 'auto'), "#group#" => $this->getGroup(), ); if ($replace['#height#'] == 'auto') { $replace['#height#'] = '110px'; } if ($replace['#width#'] == 'auto') { $replace['#width#'] = '185px'; } if (!isset(self::$_templateArray)) { self::$_templateArray = array(); } if (!isset(self::$_templateArray[$version])) { self::$_templateArray[$version] = getTemplate('core', $version, 'scenario'); } if (config::byKey('interface::advance::vertCentering', 'core', 0) == 1) { $replace['#isVerticalAlign#'] = 'verticalAlign'; } $html = template_replace($replace, self::$_templateArray[$version]); $html = translate::exec($html, 'core/template/widgets.html'); if (config::byKey('widget::disableCache', 'core', 0) == 0) { cache::set('scenarioHtml' . $version . $this->getId(), $html); } return $html; } /** * */ public function emptyCacheWidget() { $mc = cache::byKey('scenarioHtmldashboard' . $this->getId()); $mc->remove(); $mc = cache::byKey('scenarioHtmlmobile' . $this->getId()); $mc->remove(); } /** * * @param bool $_only_class * @return string */ public function getIcon($_only_class = false) { if ($_only_class) { switch ($this->getState()) { case 'starting': return 'fas fa-hourglass-start'; case 'in progress': return 'fas fa-spinner fa-spin'; case 'error': return 'fas fa-exclamation-triangle'; default: if (strpos($this->getDisplay('icon'), '', '>'), '', $this->getDisplay('icon')); } return 'fas fa-check'; } return 'fas fa-times'; } switch ($this->getState()) { case 'starting': return ' '; case 'in progress': return ''; case 'error': return ''; default: if ($this->getDisplay('icon') != '') { return $this->getDisplay('icon'); } return ''; } return ''; } public function getLinkToConfiguration() { return 'index.php?v=d&p=scenario&id=' . $this->getId(); } /** * * @throws Exception */ public function preSave() { if ($this->getTimeout() == '' || !is_numeric($this->getTimeout())) { $this->setTimeout(0); } if ($this->getName() == '') { throw new Exception('Le nom du scénario ne peut pas être vide.'); } if (($this->getMode() == 'schedule' || $this->getMode() == 'all') && $this->getSchedule() == '') { throw new Exception(__('Le scénario est de type programmé mais la programmation est vide', __FILE__)); } if ($this->getConfiguration('has_return', 0) == 1) { $this->setConfiguration('syncmode', 1); } if ($this->getConfiguration('logmode') == '') { $this->setConfiguration('logmode', 'default'); } } public function postInsert() { $this->setState('stop'); $this->setPID(); } public function save() { if ($this->getLastLaunch() == '' && ($this->getMode() == 'schedule' || $this->getMode() == 'all')) { $calculateScheduleDate = $this->calculateScheduleDate(); $this->setLastLaunch($calculateScheduleDate['prevDate']); } DB::save($this); $this->emptyCacheWidget(); if ($this->_changeState) { $this->_changeState = false; event::add('scenario::update', array('scenario_id' => $this->getId(), 'isActive' => $this->getIsActive(), 'state' => $this->getState(), 'lastLaunch' => $this->getLastLaunch(), 'name' => $this->getName(), 'icon' => $this->getIcon())); } return true; } public function refresh() { DB::refresh($this); } public function remove() { viewData::removeByTypeLinkId('scenario', $this->getId()); dataStore::removeByTypeLinkId('scenario', $this->getId()); foreach (($this->getElement()) as $element) { $element->remove(); } $this->emptyCacheWidget(); if (file_exists(__DIR__ . '/../../log/scenarioLog/scenario' . $this->getId() . '.log')) { unlink(__DIR__ . '/../../log/scenarioLog/scenario' . $this->getId() . '.log'); } cache::delete('scenarioCacheAttr' . $this->getId()); jeedom::addRemoveHistory(array('id' => $this->getId(), 'name' => $this->getHumanName(), 'date' => date('Y-m-d H:i:s'), 'type' => 'scenario')); return DB::remove($this); } /** * * @param string $_key * @param bool $_private * @return bool */ public function removeData($_key, $_private = false) { if ($_private) { $dataStore = dataStore::byTypeLinkIdKey('scenario', $this->getId(), $_key); } else { $dataStore = dataStore::byTypeLinkIdKey('scenario', -1, $_key); } if (is_object($dataStore)) { return $dataStore->remove(); } return true; } /** * * @param string $_key * @param string $_value * @param bool $_private * @return true */ public function setData($_key, $_value, $_private = false) { $dataStore = new dataStore(); $dataStore->setType('scenario'); $dataStore->setKey($_key); $dataStore->setValue($_value); if ($_private) { $dataStore->setLink_id($this->getId()); } else { $dataStore->setLink_id(-1); } $dataStore->save(); return true; } public function getData($_key, $_private = false, $_default = '') { if ($_private) { $dataStore = dataStore::byTypeLinkIdKey('scenario', $this->getId(), $_key); } else { $dataStore = dataStore::byTypeLinkIdKey('scenario', -1, $_key); } if (is_object($dataStore)) { return $dataStore->getValue($_default); } return $_default; } public function calculateScheduleDate() { $calculatedDate = array('prevDate' => '', 'nextDate' => ''); if (is_array($this->getSchedule())) { $calculatedDate_tmp = array('prevDate' => '', 'nextDate' => ''); foreach (($this->getSchedule()) as $schedule) { try { $c = new Cron\CronExpression(checkAndFixCron($schedule), new Cron\FieldFactory); $calculatedDate_tmp['prevDate'] = $c->getPreviousRunDate()->format('Y-m-d H:i:s'); $calculatedDate_tmp['nextDate'] = $c->getNextRunDate()->format('Y-m-d H:i:s'); } catch (Exception $exc) { } catch (Error $exc) { } if ($calculatedDate['prevDate'] == '' || strtotime($calculatedDate['prevDate']) < strtotime($calculatedDate_tmp['prevDate'])) { $calculatedDate['prevDate'] = $calculatedDate_tmp['prevDate']; } if ($calculatedDate['nextDate'] == '' || strtotime($calculatedDate['nextDate']) > strtotime($calculatedDate_tmp['nextDate'])) { $calculatedDate['nextDate'] = $calculatedDate_tmp['nextDate']; } } } else { try { $c = new Cron\CronExpression(checkAndFixCron($this->getSchedule()), new Cron\FieldFactory); $calculatedDate['prevDate'] = $c->getPreviousRunDate()->format('Y-m-d H:i:s'); $calculatedDate['nextDate'] = $c->getNextRunDate()->format('Y-m-d H:i:s'); } catch (Exception $exc) { } catch (Error $exc) { } } return $calculatedDate; } /** * * @return boolean */ public function isDue() { if (((new DateTime('today midnight +1 day'))->format('I') - (new DateTime('today midnight'))->format('I')) == -1 && date('G') > 0 && date('G') < 4) { return false; } $last = strtotime($this->getLastLaunch()); $now = time(); $now = ($now - $now % 60); $last = ($last - $last % 60); if ($now == $last) { return false; } if (is_array($this->getSchedule())) { foreach (($this->getSchedule()) as $schedule) { try { $c = new Cron\CronExpression(checkAndFixCron($schedule), new Cron\FieldFactory); try { if ($c->isDue()) { return true; } } catch (Exception $e) { } catch (Error $e) { } try { $prev = $c->getPreviousRunDate()->getTimestamp(); } catch (Exception $e) { continue; } catch (Error $e) { continue; } $lastCheck = strtotime($this->getLastLaunch()); $diff = abs((strtotime('now') - $prev) / 60); if ($lastCheck <= $prev && $diff <= config::byKey('maxCatchAllow') || config::byKey('maxCatchAllow') == -1) { return true; } } catch (Exception $e) { } catch (Error $e) { } } } else { try { $c = new Cron\CronExpression(checkAndFixCron($this->getSchedule()), new Cron\FieldFactory); try { if ($c->isDue()) { return true; } } catch (Exception $e) { } catch (Error $e) { } try { $prev = $c->getPreviousRunDate()->getTimestamp(); } catch (Exception $e) { return false; } catch (Error $e) { return false; } $lastCheck = strtotime($this->getLastLaunch()); $diff = abs((strtotime('now') - $prev) / 60); if ($lastCheck <= $prev && $diff <= config::byKey('maxCatchAllow') || config::byKey('maxCatchAllow') == -1) { return true; } } catch (Exception $exc) { } catch (Error $exc) { } } return false; } /** * * @return boolean */ public function running() { if (intval($this->getPID()) > 0 && posix_getsid(intval($this->getPID())) && (!file_exists('/proc/' . $this->getPID() . '/cmdline') || strpos(file_get_contents('/proc/' . $this->getPID() . '/cmdline'), 'scenario_id=' . $this->getId()) !== false)) { return true; } if (count(system::ps('scenario_id=' . $this->getId() . ' ', array(getmypid()))) > 0) { return true; } return false; } /** * * @return boolean * @throws Exception */ public function stop() { $crons = cron::searchClassAndFunction('scenario', 'doIn', '"scenario_id":' . $this->getId()); if (is_array($crons)) { foreach ($crons as $cron) { if ($cron->getState() == 'run') { try { $cron->halt(); $cron->remove(); } catch (Exception $e) { log::add('scenario', 'info', __('Impossible d\'arrêter la sous tâche :', __FILE__) . ' ' . json_encode($cron->getOption())); } } } } if ($this->running()) { if ($this->getPID() > 0) { system::kill($this->getPID()); $retry = 0; while ($this->running() && $retry < 10) { sleep(1); system::kill($this->getPID()); $retry++; } } if ($this->running()) { system::kill("scenario_id=" . $this->getId() . ' '); sleep(1); if ($this->running()) { system::kill("scenario_id=" . $this->getId() . ' '); sleep(1); } } if ($this->running()) { throw new Exception(__('Impossible d\'arrêter le scénario :', __FILE__) . ' ' . $this->getHumanName() . '. ' . __('PID :', __FILE__) . ' ' . $this->getPID()); } } $this->setState('stop'); return true; } public function getElement() { if (count($this->_elements) > 0) { return $this->_elements; } $return = array(); $elements = $this->getScenarioElement(); if (is_array($elements)) { foreach (($this->getScenarioElement()) as $element_id) { $element = scenarioElement::byId($element_id); if (is_object($element)) { $return[] = $element; } } $this->_elements = $return; return $return; } if ($elements != '') { $element = scenarioElement::byId($elements); if (is_object($element)) { $return[] = $element; $this->_elements = $return; return $return; } } return array(); } /** * * @param string $_mode accepted value: ['text'|'array'] * @return string|array depending $_mode parameter */ public function export($_mode = 'text') { if ($_mode == 'text') { $return = ''; $return .= '- Nom du scénario : ' . $this->getName() . "\n"; if (is_numeric($this->getObject_id())) { $return .= '- Objet parent : ' . $this->getObject()->getName() . "\n"; } $return .= '- Mode du scénario : ' . $this->getMode() . "\n"; $schedules = $this->getSchedule(); if ($this->getMode() == 'schedule' || $this->getMode() == 'all') { if (is_array($schedules)) { foreach ($schedules as $schedule) { $return .= ' - Programmation : ' . $schedule . "\n"; } } else { if ($schedules != '') { $return .= ' - Programmation : ' . $schedules . "\n"; } } } if ($this->getMode() == 'provoke' || $this->getMode() == 'all') { foreach (($this->getTrigger()) as $trigger) { $return .= ' - Evènement : ' . jeedom::toHumanReadable($trigger) . "\n"; } } $return .= "\n"; $return .= $this->getDescription(); $return .= "\n\n"; foreach (($this->getElement()) as $element) { $exports = explode("\n", $element->export()); foreach ($exports as $export) { $return .= " " . $export . "\n"; } } } if ($_mode == 'array') { $return = utils::o2a($this); $return['trigger'] = jeedom::toHumanReadable($return['trigger']); $return['elements'] = array(); foreach (($this->getElement()) as $element) { $return['elements'][] = $element->getAjaxElement('array'); } if (isset($return['id'])) { unset($return['id']); } if (isset($return['lastLaunch'])) { unset($return['lastLaunch']); } if (isset($return['log'])) { unset($return['log']); } if (isset($return['hlogs'])) { unset($return['hlogs']); } if (isset($return['object_id'])) { unset($return['object_id']); } if (isset($return['state'])) { unset($return['state']); } if (isset($return['lastLaunch'])) { unset($return['lastLaunch']); } if (isset($return['pid'])) { unset($return['pid']); } if (isset($return['scenarioElement'])) { unset($return['scenarioElement']); } if (isset($return['_templateArray'])) { unset($return['_templateArray']); } if (isset($return['_templateArray'])) { unset($return['_templateArray']); } if (isset($return['_changeState'])) { unset($return['_changeState']); } if (isset($return['_realTrigger'])) { unset($return['_realTrigger']); } if (isset($return['_realTriggerValue'])) { unset($return['_realTriggerValue']); } if (isset($return['_templateArray'])) { unset($return['_templateArray']); } if (isset($return['_elements'])) { unset($return['_elements']); } } return $return; } /** * * @return object */ public function getObject() { return jeeObject::byId($this->object_id); } /** * * @param bool $_complete * @param bool $_noGroup * @param bool $_tag * @param bool $_prettify * @param bool $_withoutScenarioName * @return string */ public function getHumanName($_complete = true, $_noGroup = false, $_tag = false, $_prettify = false, $_withoutScenarioName = false, $_object_name = true) { //$_complete : add None if no tag or no group //$_noGroup: add group name //$_tag: html label with custom color $name = ''; if (!$_noGroup) { $groupName = $this->getGroup() != '' ? $this->getGroup() : __('Aucun', __FILE__); if ($_tag) { $name .= '' . $groupName . ' '; } else { $name .= '[' . $groupName . ']'; } } if ($_object_name && is_numeric($this->getObject_id()) && is_object($this->getObject())) { $object = $this->getObject(); if ($_tag) { if ($object->getConfiguration('useCustomColor') == 1) { $name .= '' . $object->getName() . ''; } else { $name .= '' . $object->getName() . ''; } } else { $name .= '[' . $object->getName() . ']'; } } else { if ($_complete) { if ($_tag) { $name .= '' . __('Aucun', __FILE__) . ''; } else { $name .= '[' . __('Aucun', __FILE__) . ']'; } } } if ($_prettify) { $name .= '
'; } if (!$_withoutScenarioName) { if ($_tag) { $name .= ' ' . $this->getName(); } else { $name .= '[' . $this->getName() . ']'; } } if ($_prettify) { $name .= ''; } return $name; } /** * * @param string $_right * @return boolean */ public function hasRight($_right, $_user = null) { if ($_user != null) { if ($_user->getProfils() == 'admin' || $_user->getProfils() == 'user') { return true; } if (strpos($_user->getRights('scenario' . $this->getId()), $_right) !== false) { return true; } return false; } if (!isConnect()) { return false; } if (isConnect('admin') || isConnect('user')) { return true; } if (strpos($_SESSION['user']->getRights('scenario' . $this->getId()), $_right) !== false) { return true; } return false; } public function persistLog($_partial = false) { if ($this->getConfiguration('logmode', 'default') == 'none') { return; } $path = __DIR__ . '/../../log/scenarioLog'; if (!file_exists($path)) { mkdir($path); } $path .= '/scenario' . $this->getId() . '.log'; if ($_partial) { file_put_contents($path, $this->getLog(), FILE_APPEND); } else { file_put_contents($path, "------------------------------------\n" . $this->getLog(), FILE_APPEND); } } public function toArray() { $return = utils::o2a($this, true); $cache = $this->getCache(array('state', 'lastLaunch')); $return['state'] = $cache['state']; $return['lastLaunch'] = $cache['lastLaunch']; return $return; } /** * * @param array $_data * @param int $_level * @param null|int $_drill * @return array */ public function getLinkData(&$_data = array('node' => array(), 'link' => array()), $_level = 0, $_drill = null) { if ($_drill === null) { $_drill = config::byKey('graphlink::scenario::drill'); } if (isset($_data['node']['scenario' . $this->getId()])) { return; } if ($_level > 2) { return $_data; } $_level++; if ($_level > $_drill) { return $_data; } $_data['node']['scenario' . $this->getId()] = array( 'id' => 'scenario' . $this->getId(), 'name' => $this->getName(), 'type' => __('Scénario', __FILE__), 'fontweight' => ($_level == 1) ? 'bold' : 'normal', 'shape' => 'rect', 'width' => 40, 'height' => 40, 'color' => 'green', 'image' => 'core/img/scenario.png', 'isActive' => $this->getIsActive(), 'title' => $this->getHumanName(), 'url' => 'index.php?v=d&p=scenario&id=' . $this->getId(), ); $use = $this->getUse(); $usedBy = $this->getUsedBy(); addGraphLink($this, 'scenario', $this->getObject(), 'object', $_data, $_level + 1, $_drill, array('dashvalue' => '1,0', 'lengthfactor' => 0.6)); addGraphLink($this, 'scenario', $use['cmd'], 'cmd', $_data, $_level, $_drill); addGraphLink($this, 'scenario', $use['scenario'], 'scenario', $_data, $_level, $_drill); addGraphLink($this, 'scenario', $use['eqLogic'], 'eqLogic', $_data, $_level, $_drill); addGraphLink($this, 'scenario', $use['dataStore'], 'dataStore', $_data, $_level, $_drill); addGraphLink($this, 'scenario', $use['view'], 'view', $_data, $_level, $_drill); addGraphLink($this, 'scenario', $use['plan'], 'plan', $_data, $_level, $_drill); addGraphLink($this, 'scenario', $use['plan3d'], 'plan3d', $_data, $_level, $_drill); if (isset($usedBy['plugin']) && is_array($usedBy['plugin']) && count($usedBy['plugin']) > 0) { foreach ($usedBy['plugin'] as $key => $value) { addGraphLink($this, 'eqLogic', $value, $key, $_data, $_level, $_drill); } } addGraphLink($this, 'scenario', $usedBy['cmd'], 'cmd', $_data, $_level, $_drill); addGraphLink($this, 'scenario', $usedBy['scenario'], 'scenario', $_data, $_level, $_drill); addGraphLink($this, 'scenario', $usedBy['eqLogic'], 'eqLogic', $_data, $_level, $_drill); addGraphLink($this, 'scenario', $usedBy['interactDef'], 'interactDef', $_data, $_level, $_drill, array('dashvalue' => '2,6', 'lengthfactor' => 0.6)); addGraphLink($this, 'scenario', $usedBy['plan'], 'plan', $_data, $_level, $_drill, array('dashvalue' => '2,6', 'lengthfactor' => 0.6)); addGraphLink($this, 'scenario', $usedBy['plan3d'], 'plan3d', $_data, $_level, $_drill, array('dashvalue' => '2,6', 'lengthfactor' => 0.6)); addGraphLink($this, 'scenario', $usedBy['view'], 'view', $_data, $_level, $_drill, array('dashvalue' => '2,6', 'lengthfactor' => 0.6)); return $_data; } public function getUse() { $json = jeedom::fromHumanReadable(json_encode($this->export('array'))); return jeedom::getTypeUse($json); } public function getUsedBy($_array = false) { $return = array('cmd' => array(), 'eqLogic' => array(), 'scenario' => array(), 'plan' => array(), 'view' => array()); $return['cmd'] = cmd::searchConfiguration(array('#scenario' . $this->getId() . '#', '"scenario_id":"' . $this->getId() . '"')); $return['eqLogic'] = eqLogic::searchConfiguration(array('#scenario' . $this->getId() . '#', '"scenario_id":"' . $this->getId() . '"')); $return['interactDef'] = interactDef::searchByUse(array('#scenario' . $this->getId() . '#', '"scenario_id":"' . $this->getId() . '"')); $return['scenario'] = scenario::searchByUse(array( array('action' => 'scenario', 'option' => 'scenario_id":"' . $this->getId() . '"', 'and' => true), array('action' => '#scenario' . $this->getId() . '#'), )); $return['view'] = view::searchByUse('scenario', $this->getId()); $return['plan'] = planHeader::searchByUse('scenario', $this->getId()); $return['plan3d'] = plan3dHeader::searchByUse('scenario', $this->getId()); foreach (plugin::listPlugin(true, false, true, true) as $plugin) { if (method_exists($plugin, 'customUsedBy')) { $return['plugin'][$plugin] = $plugin::customUsedBy('scenario', $this->getId()); } } if ($_array) { foreach ($return as &$value) { $value = utils::o2a($value); } } return $return; } public function clearLog() { $this->_log = ''; } public function resetRepeatIfStatus() { foreach (($this->getElement()) as $element) { $element->resetRepeatIfStatus(); } } /* * **********************Getteur Setteur*************************** */ /** * * @return int */ public function getId() { return $this->id; } /** * * @return string */ public function getName() { return $this->name; } public function getState() { return $this->getCache('state'); } /** * * @return bool */ public function getIsActive() { return $this->isActive; } public function getGroup() { return $this->group; } public function getLastLaunch() { return $this->getCache('lastLaunch'); } /** * * @param int $id * @return $this */ public function setId($_id) { $this->_changed = utils::attrChanged($this->_changed, $this->id, $_id); $this->id = $_id; return $this; } /** * * @param string $name * @return $this */ public function setName($_name) { $_name = cleanComponanteName($_name); if ($_name != $this->getName()) { $this->_changeState = true; $this->_changed = true; } $this->name = $_name; return $this; } /** * * @param bool $isActive * @return $this */ public function setIsActive($_isActive) { if ($_isActive != $this->getIsActive()) { $this->_changeState = true; $this->_changed = true; } $this->isActive = $_isActive; return $this; } /** * * @param string $group * @return $this */ public function setGroup($_group) { if ($_group != $this->getGroup()) { $this->_changeState = true; $this->_changed = true; } $this->group = $_group; return $this; } /** * * @param string $state */ public function setState($state) { if ($this->getCache('state') != $state) { $this->emptyCacheWidget(); event::add('scenario::update', array('scenario_id' => $this->getId(), 'state' => $state, 'lastLaunch' => $this->getLastLaunch())); } $this->setCache('state', $state); } /** * * @param string $lastLaunch */ public function setLastLaunch($lastLaunch) { $this->setCache('lastLaunch', $lastLaunch); } public function getMode() { return $this->mode; } /** * * @param mixed $_mode * @return $this */ public function setMode($_mode) { $this->_changed = utils::attrChanged($this->_changed, $this->mode, $_mode); $this->mode = $_mode; return $this; } public function getOrder() { return $this->order; } /** * * @param mixed $_order * @return $this */ public function setOrder($_order) { $this->_changed = utils::attrChanged($this->_changed, $this->order, $_order); $this->order = $_order; return $this; } /** * * @return string/object */ public function getSchedule() { return is_json($this->schedule, $this->schedule); } /** * * @param array|string $_schedule * @return $this */ public function setSchedule($_schedule) { if (is_array($_schedule)) { $_schedule = json_encode($_schedule, JSON_UNESCAPED_UNICODE); } $this->_changed = utils::attrChanged($this->_changed, $this->schedule, $_schedule); $this->schedule = $_schedule; return $this; } public function getPID() { return $this->getCache('pid'); } public function setPID($pid = '') { $this->setCache('pid', $pid); } public function getScenarioElement() { return is_json($this->scenarioElement, $this->scenarioElement); } public function setScenarioElement($_scenarioElement) { if (is_array($_scenarioElement)) { $_scenarioElement = json_encode($_scenarioElement, JSON_UNESCAPED_UNICODE); } $this->_changed = utils::attrChanged($this->_changed, $this->scenarioElement, $_scenarioElement); $this->scenarioElement = $_scenarioElement; return $this; } public function getTrigger() { return is_json($this->trigger, array($this->trigger)); } public function setTrigger($_trigger) { if (is_array($_trigger)) { $_trigger = json_encode($_trigger, JSON_UNESCAPED_UNICODE); } $_trigger = cmd::humanReadableToCmd($_trigger); $_trigger = jeeObject::fromHumanReadable($_trigger); $this->_changed = utils::attrChanged($this->_changed, $this->trigger, $_trigger); $this->trigger = $_trigger; return $this; } /** * * @return string */ public function getLog() { return $this->_log; } /** * * @param string $log */ public function setLog($log) { $this->_log .= '[' . date('Y-m-d H:i:s') . '][SCENARIO] ' . $log . "\n"; if ($this->getConfiguration('logmode', 'default') == 'realtime') { $this->persistLog(true); $this->_log = ''; } } /** * * @param int $_default * @return int */ public function getTimeout($_default = 0) { return $this->timeout; } /** * * @param string|int $timeout * @return $this */ public function setTimeout($_timeout) { if ($_timeout === '' || !is_numeric($_timeout) || $_timeout < 1) { $_timeout = 0; } $this->_changed = utils::attrChanged($this->_changed, $this->timeout, $_timeout); $this->timeout = $_timeout; return $this; } public function getObject_id($_default = null) { if ($this->object_id == '' || !is_numeric($this->object_id)) { return $_default; } return $this->object_id; } /** * * @param int $_default * @return int */ public function getIsVisible($_default = 0) { if ($this->isVisible == '' || !is_numeric($this->isVisible)) { return $_default; } return $this->isVisible; } /** * * @param mixed $object_id * @return $this */ public function setObject_id($object_id = null) { if ($object_id != $this->getObject_id()) { $this->_changeState = true; $this->_changed = true; } $this->object_id = (!is_numeric($object_id)) ? null : $object_id; return $this; } /** * * @param int $_isVisible * @return $this */ public function setIsVisible($_isVisible) { $this->_changed = utils::attrChanged($this->_changed, $this->isVisible, $_isVisible); $this->isVisible = $_isVisible; return $this; } /** * * @param string $_key * @param string $_default * @return mixed */ public function getDisplay($_key = '', $_default = '') { return utils::getJsonAttr($this->display, $_key, $_default); } /** * * @param string $_key * @param string $_value * @return $this */ public function setDisplay($_key, $_value) { $display = utils::setJsonAttr($this->display, $_key, $_value); $this->_changed = utils::attrChanged($this->_changed, $this->display, $display); $this->display = $display; return $this; } /** * * @return string */ public function getDescription() { return $this->description; } /** * * @param string $description * @return $this */ public function setDescription($_description) { $this->_changed = utils::attrChanged($this->_changed, $this->description, $_description); $this->description = $_description; return $this; } /** * * @param string $_key * @param string $_default * @return mixed */ public function getConfiguration($_key = '', $_default = '') { return utils::getJsonAttr($this->configuration, $_key, $_default); } /** * * @param string $_key * @param string $_value * @return $this */ public function setConfiguration($_key, $_value) { $configuration = utils::setJsonAttr($this->configuration, $_key, $_value); $this->_changed = utils::attrChanged($this->_changed, $this->configuration, $configuration); $this->configuration = $configuration; return $this; } /** * * @return string */ public function getRealTrigger() { return $this->_realTrigger; } /** * * @param string $_realTrigger * @return $this */ public function setRealTrigger($_realTrigger) { $this->_realTrigger = $_realTrigger; return $this; } /** * * @return string */ public function getRealTriggerValue() { return $this->_realTriggerValue; } /** * * @param string $_realTriggerValue * @return $this */ public function setRealTriggerValue($_realTriggerValue) { $this->_realTriggerValue = $_realTriggerValue; return $this; } /** * getReturn * * @return bool */ public function getReturn() { return $this->_return; } /** * * @param bool $_return * @return $this */ public function setReturn($_return) { $this->_return = $_return; return $this; } /** * getTags * * @return array */ public function getTags() { return $this->_tags; } /** * setTags * * @param array $_tags * @return $this */ public function setTags($_tags) { $this->_tags = $_tags; return $this; } /** * getDo * * @return bool */ public function getDo() { return $this->_do; } /** * * @param bool $_do * @return $this */ public function setDo($_do) { $this->_do = $_do; return $this; } public function getCache($_key = '', $_default = '') { $cache = cache::byKey('scenarioCacheAttr' . $this->getId())->getValue(); return utils::getJsonAttr($cache, $_key, $_default); } /** * * @param string $_key * @param mixed $_value */ public function setCache($_key, $_value = null) { cache::set('scenarioCacheAttr' . $this->getId(), utils::setJsonAttr(cache::byKey('scenarioCacheAttr' . $this->getId())->getValue(), $_key, $_value)); } public function getChanged() { return $this->_changed; } public function setChanged($_changed) { $this->_changed = $_changed; return $this; } }