Files
OMS/app/base/lib/application/manage.php
2026-01-04 19:08:31 +08:00

511 lines
18 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* Copyright 2012-2026 ShopeX (https://www.shopex.cn)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class base_application_manage{
//应用程序资源探测器。
//想添加自己的探测器? 注册服务: app_content_detector
static function content_detector($app_id=null){
$content_detectors = array(
'list'=>array(
'base_application_dbtable',
'base_application_service',
'base_application_lang',
'base_application_cache_expires',
//'base_application_imgbundle',
)
);
if($app_id!='base'){
$content_detectors_addons = app::get('base')->model('app_content')->getlist('content_path,app_id',array(
'content_type'=>'service',
'content_name'=>'app_content_detector',
'disabled'=>'false',
));
foreach($content_detectors_addons as $row){
$content_detectors['list'][$row['content_path']] = $row['content_path'];
}
}
return new service($content_detectors);
}
/**
* uninstall_queue
* @param mixed $apps apps
* @return mixed 返回值
*/
public function uninstall_queue($apps){
if(is_string($apps)){
$apps = array($apps);
}
$rows = kernel::database()->select('select app_id,app_name from sdb_base_apps where status != "uninstalled"');
$depends_apps_map = array();
foreach($rows as $row){
$namemap[$row['app_id']] = $row['app_name'];
$depends_apps = app::get($row['app_id'])->define('depends/app');
if($depends_apps){
foreach($depends_apps as $dep_app){
$depends_apps_map[$dep_app['value']][] = $row;
}
}
}
foreach($apps as $app_id){
$this->check_depends_uninstall($app_id, $depends_apps_map,$queue);
}
foreach($apps as $app_id){
$queue[$app_id] = array($namemap[$app_id],0);
}
return $queue;
}
/**
* active_queue
* @param mixed $apps apps
* @return mixed 返回值
*/
public function active_queue($apps)
{
if(is_string($apps)){
$apps = array($apps);
}
foreach($apps as $app_id){
$this->check_active_install($app_id, $queue);
$queue[$app_id] = app::get($app_id)->define();
}
return $queue;
}//End Function
private function check_active_install($app_id, &$queue){
$depends_app = app::get($app_id)->define('depends/app');
foreach((array)$depends_app as $depend_app_id){
$this->check_active_install($depend_app_id['value'], $queue);
}
if(app::get($app_id)->status() == 'uninstalled' || app::get($app_id)->status() == 'paused'){
$queue[$app_id] = app::get($app_id)->define();
}
}
/**
* pause_queue
* @param mixed $apps apps
* @return mixed 返回值
*/
public function pause_queue($apps)
{
if(is_string($apps)){
$apps = array($apps);
}
$rows = kernel::database()->select('select app_id,app_name from sdb_base_apps where status = "active"');
$depends_apps_map = array();
foreach($rows as $row){
$namemap[$row['app_id']] = $row['app_name'];
$depends_apps = app::get($row['app_id'])->define('depends/app');
if($depends_apps){
foreach($depends_apps as $dep_app){
$depends_apps_map[$dep_app['value']][] = $row;
}
}
}
foreach($apps as $app_id){
$this->check_depends_uninstall($app_id, $depends_apps_map,$queue);
}
foreach($apps as $app_id){
$queue[$app_id] = array($namemap[$app_id],0);
}
return $queue;
}//End Function
private function check_depends_uninstall($app_id,$depends_apps_map, &$queue){
if(isset($depends_apps_map[$app_id])){
foreach($depends_apps_map[$app_id] as $to_delete){
$this->check_depends_uninstall($to_delete['app_id'],$depends_apps_map,$queue);
$queue[$to_delete['app_id']] = array($to_delete['app_name'],1);
}
}
}
/**
* install_queue
* @param mixed $apps apps
* @param mixed $force_install force_install
* @return mixed 返回值
*/
public function install_queue($apps,$force_install=false){
if(is_string($apps)){
$apps = array($apps);
}
foreach($apps as $app_id){
$this->check_depends_install($app_id, $queue);
if($force_install){
$queue[$app_id] = app::get($app_id)->define();
}
}
return $queue;
}
/**
* has_conflict_apps
* @param mixed $apps apps
* @param mixed $conflict_apps conflict_apps
* @return mixed 返回值
*/
public function has_conflict_apps($apps, &$conflict_apps)
{
if(!kernel::is_online()) return false;
if(is_string($apps)){
$apps = array($apps);
}
$queue = array();
$installed_queue = array();
$install_apps = array();
$installed_apps = array();
foreach($apps AS $app_id){
$install_apps[$app_id] = array();
$this->check_conflicts_install($app_id, $queue);
}
$rows = [];
$isExist = kernel::database()->select("SHOW TABLES LIKE 'sdb_base_apps'");
if ($isExist){
$rows = kernel::database()->select('select app_id from sdb_base_apps where status != "uninstalled"');
}
foreach($rows AS $row){
$installed_apps[$row['app_id']] = array();
$this->check_conflicts_install($row['app_id'], $installed_queue);
}
$conflict_one = array_intersect_key($queue, $installed_apps);
$conflict_two = array_intersect_key($installed_queue, $install_apps);
$conflict_apps = array_merge($conflict_one, $conflict_two);
return (count($conflict_apps)) ? true : false;
}//End Function
private function check_conflicts_install($app_id, &$queue)
{
$conflicts_app = app::get($app_id)->define('conflicts/app');
foreach((array)$conflicts_app AS $conflict_app){
$conflict_app_id = $conflict_app['value'];
$queue[$conflict_app_id] = app::get($app_id)->define();
}
}//End Function
private function check_depends_install($app_id, &$queue){
$depends_app = app::get($app_id)->define('depends/app');
foreach((array)$depends_app as $depend_app_id){
$this->check_depends_install($depend_app_id['value'], $queue);
}
if(app::get($app_id)->status() == 'uninstalled'){
$queue[$app_id] = app::get($app_id)->define();
}
}
/**
* install
* @param mixed $app_id ID
* @param mixed $options 选项
* @param mixed $auto_enable auto_enable
* @return mixed 返回值
*/
public function install($app_id,$options=null,$auto_enable=1){
$app = app::get($app_id);
if(!file_exists(APP_DIR.'/'.$app_id.'/app.xml')){
kernel::log('Application package not found: '.$app_id);
return false;
}
$app_info = $app->define('main_app');
$app_exclusion = app::get('base')->getConf('system.main_app');
if($app_info['value'] == 'true'){
if($app_info['exclusion'] == 'true'){
if($app_exclusion['value'] == 'true' && $app_exclusion['exclusion'] == 'true' && $app_exclusion['app_id'] != $app_id){
kernel::log('Application '.$app_id.' exclusioned '.$app_exclusion['app_id'].'.');
return false;
}
}
$app_info['app_id'] = $app_id;
$app_exclusion = app::get('base')->setConf('system.main_app', $app_info);
}
$app_self_detector = null;
$app->runtask('pre_install',$options);
kernel::single('base_application_dbtable')->clear_by_app($app_id); //清除冗余表信息
foreach($this->content_detector($app_id) as $detector){
foreach($detector->detect($app) as $name=>$item){
$item->install();
}
kernel::set_online(true);
base_kvstore::instance('system')->store(
'service_last_modified.'.get_class($detector).'.'.$app_id ,
$detector->last_modified($app_id));
}
//todo:clear service cache... 如果以后做了缓存的话...
//用自己新安装的资源探测器,安装自己的资源
foreach(kernel::servicelist('app_content_detector') as $k=>$detector){
if($detector->app->app_id==$app_id){
//遍历所有已经安装的app
foreach($detector->detect($app) as $name=>$item){
$item->install();
}
base_kvstore::instance('system')->store(
'service_last_modified.'.get_class($detector).'.'.$app_id ,
$detector->last_modified($app_id));
}
}
app::get('base')->model('apps')->replace(
array('status'=>'installed','app_id'=>$app_id, 'dbver'=>$app->define('version'))
,array('app_id'=>$app_id)
);
$deploy_info = base_setup_config::deploy_info();
foreach((array)$deploy_info['setting'] as $set){
if($set['app']==$app_id){
$app->setConf($set['key'],$set['value']);
}
}
$app->runtask('post_install',$options);
if($auto_enable){
$this->enable($app_id);
}
//app submit servicelist
$params['certificate_id'] = $app_id;
$params['app_id'] = $app_id;
// $rst = app::get($app_id)->matrix()->set_callback('dev_sandbox','show',array(1,2,3,'aa'=>time()))
// ->call('node.addshop',$app_id);
kernel::log('Application '.$app_id.' installed... ok.');
}
/**
* uninstall
* @param mixed $app_id ID
* @return mixed 返回值
*/
public function uninstall($app_id){
$this->disable($app_id);
$app = app::get($app_id);
$app->runtask('pre_uninstall');
//对于BASE, 只要删除数据库即可 删无可删,无需再删
if($app_id=='base'){
kernel::single('base_application_dbtable')->clear_by_app('base');
}else{
foreach($this->content_detector($app_id) as $detector){
$detector->clear_by_app($app_id);
}
app::get('base')->model('app_content')->delete(array('app_id'=>$app_id));
$app->runtask('post_uninstall');
/*
app::get('base')->model('apps')->update(
array('status'=>'uninstalled')
,array('app_id'=>$app_id)
);
*/
//todo:应要求暂时在app卸载时把app信息一同抹去需要手工运行检查更新
//modify by edwin.lzh@gmail.com 2011/3/24
app::get('base')->model('apps')->delete(array('app_id'=>$app_id));
$app_ext = app::get('base')->getConf('system.main_app');
if($app_id == $app_ext['app_id']){
app::get('base')->setConf('system.main_app', array());
}
}
kernel::log('Application '.$app_id.' removed');
}
/**
* pause
* @param mixed $app_id ID
* @return mixed 返回值
*/
public function pause($app_id)
{
if($app_id == 'base'){
kernel::log('Appication base can\'t be paused');
}else{
$row = kernel::database()->select('select app_id from sdb_base_apps where app_id = "'.$app_id.'" AND status = "active"');
if(empty($row)){
kernel::log('Application ' . $app_id . ' don\'t be pause');
return ;
}
$this->disable($app_id);
$app = app::get($app_id);
foreach($this->content_detector($app_id) as $detector){
$detector->pause_by_app($app_id);
}
app::get('base')->model('app_content')->delete(array('app_id'=>$app_id));
app::get('base')->model('apps')->update(
array('status'=>'paused')
,array('app_id'=>$app_id)
);
kernel::log('Application '.$app_id.' paused');
}
}//End Function
/**
* active
* @param mixed $app_id ID
* @return mixed 返回值
*/
public function active($app_id)
{
$row = kernel::database()->selectrow('select status from sdb_base_apps where app_id = "'.$app_id.'" AND status IN ("uninstalled", "paused") ');
switch($row['status'])
{
case 'paused':
$this->enable($app_id);
$app = app::get($app_id);
foreach($this->content_detector($app_id) as $detector){
$detector->active_by_app($app_id);
}
//用自己新启用的资源探测器,启用自己的资源
foreach(kernel::servicelist('app_content_detector') as $k=>$detector){
if($detector->app->app_id==$app_id){
//遍历所有已经安装的app
$detector->active_by_app($app_id);
}
}
app::get('base')->model('apps')->update(
array('status'=>'active')
,array('app_id'=>$app_id)
);
kernel::log('Application '.$app_id.' actived');
return;
case 'uninstalled':
$this->install($app_id);
return;
default:
kernel::log('Application ' . $app_id . ' don\'t be active');
return ;
}
}//End Function
/**
* enable
* @param mixed $app_id ID
* @return mixed 返回值
*/
public function enable($app_id){
$app = app::get($app_id);
$app->runtask('pre_enable');
app::get('base')->model('app_content')->update(
array('disabled'=>'false')
,array('app_id'=>$app_id)
);
app::get('base')->model('apps')->update(
array('status'=>'active')
,array('app_id'=>$app_id)
);
$app->runtask('post_enable');
}
/**
* disable
* @param mixed $app_id ID
* @return mixed 返回值
*/
public function disable($app_id){
$app = app::get($app_id);
$app->runtask('pre_disable');
app::get('base')->model('app_content')->update(
array('disabled'=>'true')
,array('app_id'=>$app_id)
);
app::get('base')->model('apps')->update(
array('status'=>'installed')
,array('app_id'=>$app_id)
);
$app->runtask('post_disable');
}
/**
* 更新_app_content
* @param mixed $app_id ID
* @param mixed $autofix autofix
* @return mixed 返回值
*/
public function update_app_content($app_id,$autofix=true){
foreach($this->content_detector($app_id) as $k=>$detector){
$last_modified = $detector->last_modified($app_id);
if($last_modified == -1 || base_kvstore::instance('system')->fetch('service_last_modified.'.get_class($detector).'.'.$app_id, $current_define_modified) == false || $last_modified != $current_define_modified){
kernel::log('Updating '.$k.'@'.$app_id.'.');
if($autofix){
$detector->update($app_id);
if ($last_modified!=-1) {
base_kvstore::instance('system')->store(
'service_last_modified.'.get_class($detector).'.'.$app_id ,
$last_modified);
}
}
}
}
}
private function update_local_app_info($app_id){
$app = app::get($app_id)->define();
$data = array(
'app_id'=>$app_id,
'app_name'=>$app['name'],
'local_ver'=>$app['version'],
'description'=>$app['description'],
'author_name'=>$app['author']['name'],
'author_url'=>$app['author']['url'],
'author_email'=>$app['author']['email'],
);
app::get('base')->model('apps')->replace($data,array('app_id'=>$app_id));
}
/**
* 更新_local
* @return mixed 返回值
*/
public function update_local(){
kernel::log('Scanning local Applications... ',1);
if ($handle = opendir(APP_DIR)) {
while (false !== ($file = readdir($handle))) {
if($file[0]!='.' && is_dir(APP_DIR.'/'.$file) && file_exists(APP_DIR.'/'.$file.'/app.xml')){
$this->update_local_app_info($file);
}
}
closedir($handle);
}
kernel::log('ok.');
return $this->_list;
}
}