Source of file UpdateManager.php
Size: 12,628 Bytes - Last Modified: 2020-10-24T02:46:31+00:00
/home/travis/build/NextDom/nextdom-core/src/Managers/UpdateManager.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392 | <?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\DateFormat; use NextDom\Enums\LogTarget; use NextDom\Enums\NextDomObj; use NextDom\Enums\UpdateStatus; use NextDom\Helpers\DBHelper; use NextDom\Helpers\FileSystemHelper; use NextDom\Helpers\LogHelper; use NextDom\Managers\Parents\BaseManager; use NextDom\Managers\Parents\CommonManager; use NextDom\Model\Entity\Update; /** * Class UpdateManager * * Manage updates * * @package NextDom\Managers */ class UpdateManager extends BaseManager { use CommonManager; const REPO_CLASS_PATH = '\\NextDom\\Repo\\'; const DB_CLASS_NAME = '`update`'; const CLASS_NAME = Update::class; /** * Check all updates * * @param string $filter Type of update * @param bool $findNewObjects Find if new objects are presents * * @throws \Exception */ public static function checkAllUpdate($filter = '', $findNewObjects = true) { if ($findNewObjects) { self::findNewUpdateObject(); } $updatesList = self::all($filter); $updatesToCheckBySource = []; // Arrange updates by source if (is_array($updatesList)) { foreach ($updatesList as $update) { if ($update->getStatus() != UpdateStatus::HOLD) { $updateSource = $update->getSource(); if (!isset($updatesToCheckBySource[$updateSource])) { $updatesToCheckBySource[$updateSource] = []; } $updatesToCheckBySource[$updateSource][] = $update; } } } // Check all updates foreach ($updatesToCheckBySource as $source => $updates) { if (ConfigManager::byKey($source . '::enable') == 1) { $repoData = self::getRepoDataFromName($source); if (array_key_exists('phpClass', $repoData)) { $repoPhpClass = $repoData['phpClass']; if (class_exists($repoPhpClass) && method_exists($repoPhpClass, 'checkUpdate')) { $repoPhpClass::checkUpdate($updates); } } } } // Save last update in database ConfigManager::save('update::lastCheck', date(DateFormat::FULL)); } /** * Find if new items are presents (installed manually) * * @throws \Exception */ public static function findNewUpdateObject() { // Look for plugins foreach (PluginManager::listPlugin() as $plugin) { $pluginId = $plugin->getId(); $update = self::byTypeAndLogicalId(NextDomObj::PLUGIN, $pluginId); // Add update data if plugin not exists if (!is_object($update)) { $update = (new Update()) ->setLogicalId($pluginId) ->setType(NextDomObj::PLUGIN) ->setLocalVersion(date(DateFormat::FULL)); $update->save(); } $find = []; // Check for plugin with market if (method_exists($pluginId, 'listMarketObject')) { $pluginIdListMarketObject = $pluginId::listMarketObject(); // Check all object from this market foreach ($pluginIdListMarketObject as $logicalId) { $find[$logicalId] = true; $update = self::byTypeAndLogicalId($pluginId, $logicalId); // Add update if not exists if (!is_object($update)) { $update = (new Update()) ->setLogicalId($logicalId) ->setType($pluginId) ->setLocalVersion(date(DateFormat::FULL)); $update->save(); } } $byTypePluginId = self::byType($pluginId); foreach ($byTypePluginId as $update) { if (!isset($find[$update->getLogicalId()])) { $update->remove(); } } } else { // Remove all update if plugin is removed $params = [ 'type' => $pluginId, ]; $sql = 'DELETE FROM ' . self::DB_CLASS_NAME . ' WHERE `type` = :type'; DBHelper::exec($sql, $params); } } } /** * Get updates from their type and logicalId * * @param $type * @param $logicalId * * @return Update|null * * @throws \Exception */ public static function byTypeAndLogicalId($type, $logicalId) { return static::getOneByClauses(['logicalId' => $logicalId, 'type' => $type]); } /** * Get updates by type * * @param $type * * @return Update[]|null * * @throws \Exception */ public static function byType($type) { return static::getMultipleByClauses(['type' => $type]); } /** * Get all the updates. * * @param string $filter * * @return Update[]|null List of all objects * * @throws \Exception */ public static function all($filter = '') { $params = []; $sql = static::getBaseSQL() . ' '; if ($filter != '') { $params['type'] = $filter; $sql .= 'WHERE `type` = :type '; } $sql .= 'ORDER BY FIELD(`status`, "update", "ok", "depreciated") ASC, FIELD(`type`, "plugin", "core") DESC, `name` ASC'; return DBHelper::getAllObjects($sql, $params, self::CLASS_NAME); } /** * Get the class of the repo by the name * * @param string $name Name of the repo in jeedom format * * @return array Associative array * * @throws \Exception */ public static function getRepoDataFromName($name): array { $repoList = self::listRepo(); foreach ($repoList as $repoData) { if (ucfirst($repoData['name']) == ucfirst($name)) { return [ 'className' => str_replace(self::REPO_CLASS_PATH, '', $repoData['class']), 'phpClass' => $repoData['class'] ]; } } return []; } /** * List of repositories * * @return array Repositories data * * @throws \Exception */ public static function listRepo(): array { $result = []; foreach (FileSystemHelper::ls(NEXTDOM_ROOT . '/src/Repo/', '*.php') as $repoFile) { $repoClassName = str_replace('.php', '', $repoFile); $fullNameClass = self::REPO_CLASS_PATH . $repoClassName; if (class_exists($fullNameClass) && is_subclass_of($fullNameClass, '\\NextDom\\Interfaces\\BaseRepo')) { $repoCode = strtolower(str_replace('Repo', '', $repoClassName)); $result[$repoCode] = [ 'name' => $fullNameClass::$_name, 'class' => $fullNameClass, 'configuration' => $fullNameClass::$_configuration, 'scope' => $fullNameClass::$_scope, 'description' => $fullNameClass::$_description, 'icon' => $fullNameClass::$_icon ]; $result[$repoCode]['enable'] = ConfigManager::byKey($repoCode . '::enable'); } } return $result; } /** * Get a repo by its identifier * * @param string $id Repo identifier * * @return array Repo data * * @throws \Exception */ public static function repoById($id) { $repoClassData = self::getRepoDataFromName($id); $phpClass = $repoClassData['phpClass']; $result = [ 'name' => $phpClass::$_name, 'class' => $repoClassData['className'], 'configuration' => $phpClass::$_configuration, 'scope' => $phpClass::$_scope, 'description' => $phpClass::$_description, 'icon' => $phpClass::$_icon ]; $result['enable'] = ConfigManager::byKey($id . '::enable'); return $result; } /** * Update all items * * @param string $filter Type of updates * * @return bool True if all update pass * * @throws \NextDom\Exceptions\CoreException * @throws \Throwable */ public static function updateAll(string $filter = '') { $error = false; if ($filter == 'core') { foreach (self::byType($filter) as $update) { $update->doUpdate(); } } else { if ($filter == '') { $updatesList = self::all(); } else { $updatesList = self::byType($filter); } if (is_array($updatesList)) { foreach ($updatesList as $update) { if ($update->getStatus() != UpdateStatus::HOLD && $update->getStatus() == UpdateStatus::UPDATE && $update->getType() != 'core') { try { $update->doUpdate(); } catch (\Exception $e) { LogHelper::addUpdate(LogTarget::UPDATE, $e->getMessage()); $error = true; } } } } } return $error; } /** * Get updates by their status * * @param string $status Status of the update (@see UpdateStatus) * * @return Update[] List of updates of the required status * * @throws \Exception */ public static function byStatus($status) { return static::getMultipleByClauses(['status' => $status]); } /** * Get the bets from its logical identifier * * @param string $logicalId Logical Id of the update (plugin id) * * @return Update[]|null List of updates * * @throws \Exception */ public static function byLogicalId($logicalId) { return static::getOneByClauses(['logicalId' => $logicalId]); } /** * Get the number of pending updates * * @param string $filter Type filter * * @return int Count of pending updates * * @throws \NextDom\Exceptions\CoreException */ public static function nbNeedUpdate($filter = '') { $params = [ 'status' => 'update', 'configuration' => '%"doNotUpdate":"1"%' ]; $sql = 'SELECT count(*) FROM ' . self::DB_CLASS_NAME . ' WHERE `status` = :status AND `configuration` NOT LIKE :configuration'; if ($filter != '') { $params['type'] = $filter; $sql .= ' AND `type` = :type'; } $result = DBHelper::getOne($sql, $params); return $result['count(*)']; } /** * List core updates * * @return array List of updates */ public static function listCoreUpdate() { return FileSystemHelper::ls(NEXTDOM_ROOT . '/install/update', '*'); } } |