Extension.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. <?php
  2. /*
  3. * FecShop file.
  4. *
  5. * @link http://www.fecshop.com/
  6. * @copyright Copyright (c) 2016 FecShop Software LLC
  7. * @license http://www.fecshop.com/license/
  8. */
  9. namespace fecshop\services;
  10. //use fecshop\models\mysqldb\cms\StaticBlock;
  11. use Yii;
  12. use fecshop\services\Service;
  13. /**
  14. * @author Terry Zhao <2358269014@qq.com>
  15. * @since 1.0
  16. */
  17. class Extension extends Service
  18. {
  19. public $numPerPage = 20;
  20. // install status
  21. const INSTALLED_STATUS = 1;
  22. const INSTALL_INIT_STATUS = 2;
  23. const UNINSTALLED_STATUS = 3;
  24. // status
  25. const STATUS_ENABLE = 1;
  26. const STATUS_DISABLE = 2;
  27. // type
  28. const TYPE_INSTALL = 'online_installed';
  29. const TYPE_LOCAL_CREATED = 'local_created';
  30. protected $warnings;
  31. protected $_modelName = '\fecshop\models\mysqldb\Extension';
  32. protected $_model;
  33. public function init()
  34. {
  35. parent::init();
  36. list($this->_modelName, $this->_model) = Yii::mapGet($this->_modelName);
  37. }
  38. public function getTypeArr()
  39. {
  40. return [
  41. self::TYPE_INSTALL => Yii::$service->page->translate->__('Online Installed'),
  42. self::TYPE_LOCAL_CREATED => Yii::$service->page->translate->__('Local Created'),
  43. ];
  44. }
  45. public function isTypeLocalCreated($type)
  46. {
  47. return $type == self::TYPE_LOCAL_CREATED ? true : false;
  48. }
  49. public function getInstallStatusArr()
  50. {
  51. return [
  52. self::INSTALLED_STATUS => Yii::$service->page->translate->__('Installed'),
  53. self::INSTALL_INIT_STATUS => Yii::$service->page->translate->__('Install Init'),
  54. self::UNINSTALLED_STATUS => Yii::$service->page->translate->__('UNINSTALLED'),
  55. ];
  56. }
  57. public function getPrimaryKey()
  58. {
  59. return 'id';
  60. }
  61. public function getByPrimaryKey($primaryKey)
  62. {
  63. if ($primaryKey) {
  64. $one = $this->_model->findOne($primaryKey);
  65. return $one;
  66. } else {
  67. return new $this->_modelName();
  68. }
  69. }
  70. /**
  71. * @param $extension_name | string , 插件名称(唯一)
  72. * @return model
  73. */
  74. public function getByNamespace($extension_namespace)
  75. {
  76. return $this->_model->findOne(['namespace' => $extension_namespace]);
  77. }
  78. /*
  79. * example filter:
  80. * [
  81. * 'numPerPage' => 20,
  82. * 'pageNum' => 1,
  83. * 'orderBy' => ['_id' => SORT_DESC, 'sku' => SORT_ASC ],
  84. 'where' => [
  85. ['>','price',1],
  86. ['<=','price',10]
  87. * ['sku' => 'uk10001'],
  88. * ],
  89. * 'asArray' => true,
  90. * ]
  91. */
  92. public function coll($filter = '')
  93. {
  94. $query = $this->_model->find();
  95. $query = Yii::$service->helper->ar->getCollByFilter($query, $filter);
  96. $coll = $query->all();
  97. //var_dump($one);
  98. return [
  99. 'coll' => $coll,
  100. 'count'=> $query->limit(null)->offset(null)->count(),
  101. ];
  102. }
  103. /**
  104. * @param $one|array
  105. * save $data to cms model,then,add url rewrite info to system service urlrewrite.
  106. */
  107. public function save($one)
  108. {
  109. $currentDateTime = \fec\helpers\CDate::getCurrentDateTime();
  110. $primaryVal = isset($one[$this->getPrimaryKey()]) ? $one[$this->getPrimaryKey()] : '';
  111. if ($primaryVal) {
  112. $model = $this->_model->findOne($primaryVal);
  113. if (!$model) {
  114. Yii::$service->helper->errors->add('extension: {primaryKey} is not exist', ['primaryKey' => $this->getPrimaryKey()]);
  115. return;
  116. }
  117. } else {
  118. $model = new $this->_modelName();
  119. $model->created_at = time();
  120. }
  121. $model->updated_at = time();
  122. $primaryKey = $this->getPrimaryKey();
  123. $model = Yii::$service->helper->ar->save($model, $one);
  124. $primaryVal = $model[$primaryKey];
  125. return true;
  126. }
  127. public function remove($ids)
  128. {
  129. if (!$ids) {
  130. Yii::$service->helper->errors->add('remove id is empty');
  131. return false;
  132. }
  133. if (is_array($ids) && !empty($ids)) {
  134. foreach ($ids as $id) {
  135. $model = $this->_model->findOne($id);
  136. $model->delete();
  137. }
  138. } else {
  139. $id = $ids;
  140. $model = $this->_model->findOne($id);
  141. $model->delete();
  142. }
  143. return true;
  144. }
  145. /**
  146. * @param $ids | array, 应用id数组
  147. * 应用状态激活
  148. */
  149. public function enableAddons($ids)
  150. {
  151. foreach ($ids as $id) {
  152. $model = $this->_model->findOne($id);
  153. $model->status = self::STATUS_ENABLE;
  154. $model->updated_at = time();
  155. if (!$model->save()) {
  156. return false;
  157. }
  158. }
  159. return true;
  160. }
  161. /**
  162. * @param $ids | array, 应用id数组
  163. * 应用状态关闭
  164. */
  165. public function disableAddons($ids)
  166. {
  167. foreach ($ids as $id) {
  168. $model = $this->_model->findOne($id);
  169. $model->status = self::STATUS_DISABLE;
  170. $model->updated_at = time();
  171. if (!$model->save()) {
  172. return false;
  173. }
  174. }
  175. return true;
  176. }
  177. //const TYPE_INSTALL = 'installed';
  178. //const TYPE_LOCAL_CREATED = 'local_created';
  179. // 本地后台初始化的应用
  180. public function newLocalCreateInit($param)
  181. {
  182. $namespace = $param['namespaces'];
  183. //$package = $param['package'];
  184. //$name = $param['name'];
  185. //$config_file_path = $param['config_file_path'];
  186. //$version = $param['version'];
  187. if (!$namespace) {
  188. Yii::$service->helper->errors->add('namespace is empty');
  189. return false;
  190. }
  191. // 查看namespace 是否存在
  192. $modelOne = $this->_model->findOne(['namespace' => $namespace]);
  193. if ($modelOne['id']) {
  194. Yii::$service->helper->errors->add('this namespace is exist');
  195. return false;
  196. }
  197. $config_file_path = '@addons/' . $param['package'] . '/' . $param['addon_folder'] . '/config.php';
  198. $model = new $this->_modelName();
  199. $model['namespace'] = $param['namespaces'];
  200. $model['package'] = $param['package'];
  201. $model['folder'] = $param['addon_folder'];
  202. $model['name'] = $param['addon_name'];
  203. $model['version'] = '1.0.0';
  204. $model['config_file_path'] = $config_file_path;
  205. if (!$model->validate()) {
  206. $errors = $model->errors;
  207. Yii::$service->helper->errors->addByModelErrors($errors);
  208. return false;
  209. }
  210. $model->status = self::STATUS_ENABLE;
  211. $model->type = self::TYPE_LOCAL_CREATED;
  212. $model->created_at = time();
  213. $model->updated_at = time();
  214. $model->installed_status = self::INSTALLED_STATUS;
  215. $model->priority = 1;
  216. return $model->save();
  217. }
  218. // 新安装的插件,进行初始化
  219. public function newInstallInit($param)
  220. {
  221. $namespace = $param['namespace'];
  222. //$package = $param['package'];
  223. //$name = $param['name'];
  224. //$config_file_path = $param['config_file_path'];
  225. //$version = $param['version'];
  226. if (!$namespace) {
  227. Yii::$service->helper->errors->add('namespace is empty');
  228. return false;
  229. }
  230. // 查看namespace 是否存在
  231. $modelOne = $this->_model->findOne([
  232. 'namespace' => $namespace,
  233. 'installed_status' => self::INSTALLED_STATUS,
  234. ]);
  235. if ($modelOne['id']) {
  236. Yii::$service->helper->errors->add('this namespace is exist');
  237. return false;
  238. }
  239. $param['config_file_path'] = '@addons/' . $param['package'] . '/' . $param['folder'] . '/config.php';
  240. // 查看是否上次未安装存在记录,
  241. $model = $this->_model->findOne([
  242. 'namespace' => $namespace,
  243. 'package' => $param['package'],
  244. 'folder' => $param['folder'],
  245. ]);
  246. if (!$model['id']) {
  247. $model = new $this->_modelName();
  248. }
  249. $model->attributes = $param;
  250. if (!$model->validate()) {
  251. $errors = $model->errors;
  252. Yii::$service->helper->errors->addByModelErrors($errors);
  253. return false;
  254. }
  255. $model->status = self::STATUS_DISABLE;
  256. $model->type = self::TYPE_INSTALL;
  257. $model->created_at = time();
  258. $model->updated_at = time();
  259. $model->installed_status = self::INSTALL_INIT_STATUS;
  260. $model->priority = 1;
  261. return $model->save();
  262. }
  263. // 更新的插件,zip文件下载解压后,进行数据库初始化
  264. public function upgradeInit($param)
  265. {
  266. $namespace = $param['namespace'];
  267. //$package = $param['package'];
  268. //$name = $param['name'];
  269. //$config_file_path = $param['config_file_path'];
  270. //$version = $param['version'];
  271. if (!$namespace) {
  272. Yii::$service->helper->errors->add('namespace is empty');
  273. return false;
  274. }
  275. // 查看namespace 是否存在
  276. $modelOne = $this->_model->findOne(['namespace' => $namespace]);
  277. if (!$modelOne['id']) {
  278. Yii::$service->helper->errors->add('this namespace is exist');
  279. return false;
  280. }
  281. if (!$this->isInstalledStatus($modelOne['installed_status'])) {
  282. Yii::$service->helper->errors->add('addon status is not install status');
  283. return false;
  284. }
  285. $param['config_file_path'] = '@addons/' . $param['package'] . '/' . $param['folder'] . '/config.php';
  286. // $param['config_file_path'] = '@addons/' . $param['package'] . '/' . $param['config_file_path'] ;
  287. //$model = new $this->_modelName();
  288. $modelOne->attributes = $param;
  289. if (!$modelOne->validate()) {
  290. $errors = $modelOne->errors;
  291. Yii::$service->helper->errors->addByModelErrors($errors);
  292. return false;
  293. }
  294. //$modelOne->status = self::STATUS_ENABLE;
  295. //$modelOne->created_at = time();
  296. $modelOne->updated_at = time();
  297. //$modelOne->installed_status = self::INSTALL_INIT_STATUS;
  298. //$modelOne->priority = 1;
  299. return $modelOne->save();
  300. }
  301. // 从数据库中获取所有的namespace
  302. public function getAllNamespaces()
  303. {
  304. $filter = [
  305. 'asArray' => true,
  306. 'fetchAll' => true,
  307. ];
  308. $data = $this->coll($filter);
  309. $arr = [];
  310. if (is_array($data['coll'])) {
  311. foreach ($data['coll'] as $one) {
  312. $namespace = $one['namespace'];
  313. if ($namespace) {
  314. $arr[] = $namespace;
  315. }
  316. }
  317. }
  318. return $arr;
  319. }
  320. /**
  321. * @param $installed_status | int
  322. * @return boolean 插件是否已安装
  323. */
  324. public function isInstalledStatus($installed_status)
  325. {
  326. if ($installed_status == self::INSTALLED_STATUS) {
  327. return true;
  328. }
  329. return false;
  330. }
  331. // 添加警告信息
  332. public function addWarning($info)
  333. {
  334. $this->warnings[] = $info;
  335. return true;
  336. }
  337. // 得到警告信息
  338. public function getWarning()
  339. {
  340. return $this->warnings;
  341. }
  342. //protected $_installOb;
  343. /**
  344. * @param $installConfig | array
  345. * 进行应用的安装
  346. * 通过扩展配置中获取安装部分的配置,通过该函数执行安装。
  347. */
  348. public function installAddons($installConfig, $modelOne)
  349. {
  350. $installOb = Yii::createObject($installConfig);
  351. if (!$installOb->version) {
  352. Yii::$service->helper->errors->add("Extension Install Object must have property `version`");
  353. return false;
  354. }
  355. if (!($installOb instanceof \fecshop\services\extension\InstallInterface)) {
  356. Yii::$service->helper->errors->add("Extension install file must implements interface `\fecshop\services\extension\InstallInterface`");
  357. return false;
  358. }
  359. if (!$installOb->run()) {
  360. return false;
  361. }
  362. // 更新数据库-扩展的安装信息。
  363. $modelOne->installed_status = self::INSTALLED_STATUS;
  364. $modelOne->status = self::STATUS_ENABLE;
  365. $modelOne->installed_version = $installOb->version;
  366. $modelOne->updated_at = time();
  367. return $modelOne->save();
  368. }
  369. public function testInstallAddons($installConfig, $modelOne)
  370. {
  371. $installOb = Yii::createObject($installConfig);
  372. if (!$installOb->version) {
  373. Yii::$service->helper->errors->add("Extension Install Object must have property `version`");
  374. return false;
  375. }
  376. if (!($installOb instanceof \fecshop\services\extension\InstallInterface)) {
  377. Yii::$service->helper->errors->add("Extension install file must implements interface `\fecshop\services\extension\InstallInterface`");
  378. return false;
  379. }
  380. if (!$installOb->run()) {
  381. return false;
  382. }
  383. // 更新数据库-扩展的安装信息。
  384. $modelOne->installed_status = self::INSTALLED_STATUS;
  385. $modelOne->status = self::STATUS_ENABLE;
  386. $modelOne->installed_version = $installOb->version;
  387. $modelOne->updated_at = time();
  388. return $modelOne->save();
  389. }
  390. /**
  391. * @param $installConfig | array
  392. * 进行应用的升级
  393. * 通过扩展配置中获取安装部分的配置,通过该函数执行安装。
  394. */
  395. public function upgradeAddons($upgradeConfig, $modelOne)
  396. {
  397. $upgradeOb = Yii::createObject($upgradeConfig);
  398. if (!($upgradeOb instanceof \fecshop\services\extension\UpgradeInterface)) {
  399. Yii::$service->helper->errors->add("Extension upgrade file must implements interface `\fecshop\services\extension\UpgradeInterface`");
  400. return false;
  401. }
  402. $versions = $upgradeOb->versions;
  403. if (!empty($versions) && !is_array($versions)) {
  404. Yii::$service->helper->errors->add("Upgrade Object property `versions` must be array");
  405. return false;
  406. }
  407. $installed_version = $modelOne['installed_version'];
  408. $addon_remote_version = $modelOne['version'];
  409. $count = count($versions);
  410. for ($i = 0; $i < $count; $i++) {
  411. // 如果当前版本号 小于 此版本号
  412. if (version_compare($installed_version, $versions[$i] ,'<')
  413. && version_compare($versions[$i], $addon_remote_version,'<=') // 应用里面update更新的版本号,如果大于应用version,那么不生效(这样可以通过远程来控制最大版本号)
  414. ) {
  415. // 执行插件更新版本操作。
  416. if (!$upgradeOb->run($versions[$i])) {
  417. return false;
  418. }
  419. // 更新数据库插件安装版本信息
  420. $modelOne->installed_version = $versions[$i];
  421. $modelOne->updated_at = time();
  422. if (!$modelOne->save()) {
  423. return false;
  424. }
  425. }
  426. }
  427. // 查看升级后的install_version和version是否一致, 可能插件无更新(db,文件复制等)
  428. $modelOne->installed_version = $modelOne['version'];
  429. $modelOne->updated_at = time();
  430. if (!$modelOne->save()) {
  431. return false;
  432. }
  433. return true;
  434. }
  435. public function testUpgradeAddons($upgradeConfig, $modelOne)
  436. {
  437. $upgradeOb = Yii::createObject($upgradeConfig);
  438. if (!($upgradeOb instanceof \fecshop\services\extension\UpgradeInterface)) {
  439. Yii::$service->helper->errors->add("Extension upgrade file must implements interface `\fecshop\services\extension\UpgradeInterface`");
  440. return false;
  441. }
  442. $versions = $upgradeOb->versions;
  443. if (!empty($versions) && !is_array($versions)) {
  444. Yii::$service->helper->errors->add("Upgrade Object property `versions` must be array");
  445. return false;
  446. }
  447. $installed_version = $modelOne['installed_version'];
  448. $addon_remote_version = $modelOne['version'];
  449. $count = count($versions);
  450. for ($i = 0; $i < $count; $i++) {
  451. // 如果当前版本号 小于 此版本号
  452. if (version_compare($installed_version, $versions[$i] ,'<')
  453. && version_compare($versions[$i], $addon_remote_version,'<=') // 应用里面update更新的版本号,如果大于应用version,那么不生效(这样可以通过远程来控制最大版本号)
  454. ) {
  455. //echo $versions[$i];
  456. // 执行插件更新版本操作。
  457. if (!$upgradeOb->run($versions[$i])) {
  458. return false;
  459. }
  460. // 更新数据库插件安装版本信息
  461. $modelOne->installed_version = $versions[$i];
  462. $modelOne->updated_at = time();
  463. if (!$modelOne->save()) {
  464. return false;
  465. }
  466. }
  467. }
  468. // 查看升级后的install_version和version是否一致, 可能插件无更新(db,文件复制等)
  469. $modelOne->installed_version = $modelOne['version'];
  470. $modelOne->updated_at = time();
  471. if (!$modelOne->save()) {
  472. return false;
  473. }
  474. return true;
  475. }
  476. /**
  477. * @param $installConfig | array
  478. * 进行应用的卸载
  479. * 通过扩展配置中获取安装部分的配置,通过该函数执行安装。
  480. */
  481. public function uninstallAddons($unstallConfig, $modelOne)
  482. {
  483. $uninstallOb = Yii::createObject($unstallConfig);
  484. if (!($uninstallOb instanceof \fecshop\services\extension\UninstallInterface)) {
  485. Yii::$service->helper->errors->add("Extension unstall file must implements interface `\fecshop\services\extension\UninstallInterface`");
  486. return false;
  487. }
  488. if (!$uninstallOb->run()) {
  489. return false;
  490. }
  491. // 进行extension数据的删除
  492. return $modelOne->delete();
  493. }
  494. public function testUninstallAddons($unstallConfig, $modelOne)
  495. {
  496. $uninstallOb = Yii::createObject($unstallConfig);
  497. if (!($uninstallOb instanceof \fecshop\services\extension\UninstallInterface)) {
  498. Yii::$service->helper->errors->add("Extension unstall file must implements interface `\fecshop\services\extension\UninstallInterface`");
  499. return false;
  500. }
  501. if (!$uninstallOb->run()) {
  502. return false;
  503. }
  504. return true;
  505. // 进行extension数据的删除
  506. //return $modelOne->delete();
  507. }
  508. }