src/AppBundle/Twig/WebExtension.php line 635

Open in your IDE?
  1. <?php
  2. namespace AppBundle\Twig;
  3. use ApiBundle\Api\Util\AssetHelper;
  4. use AppBundle\Common\ArrayToolkit;
  5. use AppBundle\Common\ConvertIpToolkit;
  6. use AppBundle\Common\DeviceToolkit;
  7. use AppBundle\Common\ExtensionManager;
  8. use AppBundle\Common\FileToolkit;
  9. use AppBundle\Common\LoginToolkit;
  10. use AppBundle\Common\MathToolkit;
  11. use AppBundle\Common\NumberToolkit;
  12. use AppBundle\Common\PluginVersionToolkit;
  13. use AppBundle\Common\SimpleValidator;
  14. use AppBundle\Component\DeviceDetector\DeviceDetectorAdapter;
  15. use AppBundle\Component\ShareSdk\WeixinShare;
  16. use AppBundle\Util\CategoryBuilder;
  17. use AppBundle\Util\CdnUrl;
  18. use AppBundle\Util\UploadToken;
  19. use Biz\Account\Service\AccountProxyService;
  20. use Biz\CloudPlatform\CloudAPIFactory;
  21. use Biz\CloudPlatform\Service\ResourceFacadeService;
  22. use Biz\Lms\Service\LmsService;
  23. use Biz\ReviewCenter\Service\ReviewCenterService;
  24. use Biz\Taxonomy\Service\TagService;
  25. use Biz\User\Service\TokenService;
  26. use Codeages\Biz\Framework\Context\Biz;
  27. use Codeages\Biz\Framework\Service\Exception\ServiceException;
  28. use Common\CloudSchoolLevelConstant;
  29. use Common\CloudSchoolLevelHelper;
  30. use CorporateTrainingBundle\Biz\User\Service\UserService;
  31. use Symfony\Component\DependencyInjection\ContainerInterface;
  32. use Topxia\Service\Common\ServiceKernel;
  33. use Twig\Extension\AbstractExtension;
  34. class WebExtension extends AbstractExtension
  35. {
  36.     /**
  37.      * @var ContainerInterface
  38.      */
  39.     protected $container;
  40.     /**
  41.      * @var Biz
  42.      */
  43.     protected $biz;
  44.     protected $pageScripts;
  45.     protected $locale;
  46.     protected $defaultCloudSdkHost;
  47.     public function __construct($containerBiz $biz)
  48.     {
  49.         $this->container $container;
  50.         $this->biz $biz;
  51.     }
  52.     public function getFilters()
  53.     {
  54.         return [
  55.             new \Twig\TwigFilter('smart_time', [$this'smarttimeFilter']),
  56.             new \Twig\TwigFilter('date_format', [$this'dateformatFilter']),
  57.             new \Twig\TwigFilter('time_range', [$this'timeRangeFilter']),
  58.             new \Twig\TwigFilter('time_diff', [$this'timeDiffFilter']),
  59.             new \Twig\TwigFilter('remain_time', [$this'remainTimeFilter']),
  60.             new \Twig\TwigFilter('time_formatter', [$this'timeFormatterFilter']),
  61.             new \Twig\TwigFilter('location_text', [$this'locationTextFilter']),
  62.             new \Twig\TwigFilter('tags_html', [$this'tagsHtmlFilter'], ['is_safe' => ['html']]),
  63.             new \Twig\TwigFilter('file_size', [$this'fileSizeFilter']),
  64.             new \Twig\TwigFilter('plain_text', [$this'plainTextFilter'], ['is_safe' => ['html']]),
  65.             new \Twig\TwigFilter('sub_text', [$this'subTextFilter'], ['is_safe' => ['html']]),
  66.             new \Twig\TwigFilter('mb_substr', [$this'mb_substr'], ['is_safe' => ['html']]),
  67.             new \Twig\TwigFilter('duration', [$this'durationFilter']),
  68.             new \Twig\TwigFilter('duration_text', [$this'durationTextFilter']),
  69.             new \Twig\TwigFilter('format_ms_hms', [$this'formatMsToHmsFilter']),
  70.             new \Twig\TwigFilter('tags_join', [$this'tagsJoinFilter']),
  71.             new \Twig\TwigFilter('navigation_url', [$this'navigationUrlFilter']),
  72.             new \Twig\TwigFilter('chr', [$this'chrFilter']),
  73.             new \Twig\TwigFilter('bbCode2Html', [$this'bbCode2HtmlFilter']),
  74.             new \Twig\TwigFilter('score_text', [$this'scoreTextFilter']),
  75.             new \Twig\TwigFilter('simple_template', [$this'simpleTemplateFilter']),
  76.             new \Twig\TwigFilter('fill_question_stem_text', [$this'fillQuestionStemTextFilter']),
  77.             new \Twig\TwigFilter('fill_question_stem_html', [$this'fillQuestionStemHtmlFilter']),
  78.             new \Twig\TwigFilter('get_course_id', [$this'getCourseidFilter']),
  79.             new \Twig\TwigFilter('purify_html', [$this'getPurifyHtml']),
  80.             new \Twig\TwigFilter('purify_and_trim_html', [$this'getPurifyAndTrimHtml']),
  81.             new \Twig\TwigFilter('file_type', [$this'getFileType']),
  82.             new \Twig\TwigFilter('at', [$this'atFilter']),
  83.             new \Twig\TwigFilter('copyright_less', [$this'removeCopyright']),
  84.             new \Twig\TwigFilter('array_merge', [$this'arrayMerge']),
  85.             new \Twig\TwigFilter('space2nbsp', [$this'spaceToNbsp']),
  86.             new \Twig\TwigFilter('number_to_human', [$this'numberFilter']),
  87.             new \Twig\TwigFilter('array_column', [$this'arrayColumn']),
  88.             new \Twig\TwigFilter('rename_locale', [$this'renameLocale']),
  89.             new \Twig\TwigFilter('cdn', [$this'cdn']),
  90.             new \Twig\TwigFilter('wrap', [$this'wrap']),
  91.             new \Twig\TwigFilter('convert_absolute_url', [$this'convertAbsoluteUrl']),
  92.             new \Twig\TwigFilter('days_of_week', [$this'daysOfWeek']),
  93.             new \Twig\TwigFilter('filter_keys', [$this'filterArrayKeys']),
  94.             new \Twig\TwigFilter('exam_score', [$this'examScore']),
  95.             new \Twig\TwigFilter('learn_time_format', [$this'formatLearnTime']),
  96.             new \Twig\TwigFilter('group_by', [$this'groupBy']),
  97.         ];
  98.     }
  99.     public function getFunctions()
  100.     {
  101.         return [
  102.             new \Twig\TwigFunction('theme_global_script', [$this'getThemeGlobalScript']),
  103.             new \Twig\TwigFunction('file_uri_parse', [$this'parseFileUri']),
  104.             // file_path 即将废弃,不要再使用
  105.             new \Twig\TwigFunction('file_path', [$this'getFilePath']),
  106.             // default_path 即将废弃,不要再使用
  107.             new \Twig\TwigFunction('default_path', [$this'getDefaultPath']),
  108.             // file_url 即将废弃,不要再使用
  109.             new \Twig\TwigFunction('file_url', [$this'getFileUrl']),
  110.             // system_default_path,即将废弃,不要再使用
  111.             new \Twig\TwigFunction('system_default_path', [$this'getSystemDefaultPath']),
  112.             new \Twig\TwigFunction('fileurl', [$this'getFurl']),
  113.             new \Twig\TwigFunction('filepath', [$this'getFpath']),
  114.             new \Twig\TwigFunction('lazy_img', [$this'makeLazyImg'], ['is_safe' => ['html']]),
  115.             new \Twig\TwigFunction('avatar_path', [$this'avatarPath']),
  116.             new \Twig\TwigFunction('object_load', [$this'loadObject']),
  117.             new \Twig\TwigFunction('setting', [$this'getSetting']),
  118.             new \Twig\TwigFunction('set_price', [$this'getSetPrice']),
  119.             new \Twig\TwigFunction('percent', [$this'calculatePercent']),
  120.             new \Twig\TwigFunction('rate_format', [$this'rateFormat']),
  121.             new \Twig\TwigFunction('category_choices', [$this'getCategoryChoices']),
  122.             new \Twig\TwigFunction('category_choices_with_category_empty', [$this'getCategoryChoicesWithCategoryEmpty']),
  123.             new \Twig\TwigFunction('upload_max_filesize', [$this'getUploadMaxFilesize']),
  124.             new \Twig\TwigFunction('js_paths', [$this'getJsPaths']),
  125.             new \Twig\TwigFunction('is_plugin_installed', [$this'isPluginInstalled']),
  126.             new \Twig\TwigFunction('plugin_version', [$this'getPluginVersion']),
  127.             new \Twig\TwigFunction('version_compare', [$this'versionCompare']),
  128.             new \Twig\TwigFunction('is_exist_in_subarray_by_id', [$this'isExistInSubArrayById']),
  129.             new \Twig\TwigFunction('context_value', [$this'getContextValue']),
  130.             new \Twig\TwigFunction('is_feature_enabled', [$this'isFeatureEnabled']),
  131.             new \Twig\TwigFunction('parameter', [$this'getParameter']),
  132.             new \Twig\TwigFunction('upload_token', [$this'makeUpoadToken']),
  133.             new \Twig\TwigFunction('countdown_time', [$this'getCountdownTime']),
  134.             new \Twig\TwigFunction('can_show_classroom', [$this'canShowClassRoom']),
  135.             new \Twig\TwigFunction('can_show_article_group', [$this'canShowArticleGroup']),
  136.             new \Twig\TwigFunction('can_show_article', [$this'canShowArticle']),
  137.             new \Twig\TwigFunction('can_show_mobile_app', [$this'canShowMobileApp']),
  138.             new \Twig\TwigFunction('can_show_offline_activity', [$this'canShowOfflineActivity']),
  139.             //todo covertIP 要删除
  140.             new \Twig\TwigFunction('convertIP', [$this'getConvertIP']),
  141.             new \Twig\TwigFunction('convert_ip', [$this'getConvertIP']),
  142.             new \Twig\TwigFunction('new_convert_ip', [$this'getNewConverIP']),
  143.             new \Twig\TwigFunction('isHide', [$this'isHideThread']),
  144.             new \Twig\TwigFunction('user_coin_amount', [$this'userCoinAmount']),
  145.             new \Twig\TwigFunction('user_balance', [$this'getBalance']),
  146.             new \Twig\TwigFunction('blur_user_name', [$this'blurUserName']),
  147.             new \Twig\TwigFunction('blur_phone_number', [$this'blur_phone_number']),
  148.             new \Twig\TwigFunction('blur_idcard_number', [$this'blur_idcard_number']),
  149.             new \Twig\TwigFunction('blur_number', [$this'blur_number']),
  150.             new \Twig\TwigFunction('sub_str', [$this'subStr']),
  151.             new \Twig\TwigFunction('convert_encoding_sub_str', [$this'convertEncodingSubStr']),
  152.             new \Twig\TwigFunction('load_script', [$this'loadScript']),
  153.             new \Twig\TwigFunction('export_scripts', [$this'exportScripts']),
  154.             new \Twig\TwigFunction('order_payment', [$this'getOrderPayment']),
  155.             new \Twig\TwigFunction('classroom_permit', [$this'isPermitRole']),
  156.             new \Twig\TwigFunction('crontab_next_executed_time', [$this'getNextExecutedTime']),
  157.             new \Twig\TwigFunction('finger_print', [$this'getFingerprint']),
  158.             new \Twig\TwigFunction('get_parameters_from_url', [$this'getParametersFromUrl']),
  159.             new \Twig\TwigFunction('is_trial', [$this'isTrial']),
  160.             new \Twig\TwigFunction('timestamp', [$this'timestamp']),
  161.             new \Twig\TwigFunction('get_user_vip_level', [$this'getUserVipLevel']),
  162.             new \Twig\TwigFunction('is_without_network', [$this'isWithoutNetwork']),
  163.             new \Twig\TwigFunction('get_admin_roles', [$this'getAdminRoles']),
  164.             new \Twig\TwigFunction('render_notification', [$this'renderNotification']),
  165.             new \Twig\TwigFunction('route_exsit', [$this'routeExists']),
  166.             new \Twig\TwigFunction('is_micro_messenger', [$this'isMicroMessenger']),
  167.             new \Twig\TwigFunction('wx_js_sdk_config', [$this'weixinConfig']),
  168.             new \Twig\TwigFunction('plugin_update_notify', [$this'pluginUpdateNotify']),
  169.             new \Twig\TwigFunction('tag_equal', [$this'tagEqual']),
  170.             new \Twig\TwigFunction('get_tag', [$this'getTag']),
  171.             new \Twig\TwigFunction('array_index', [$this'arrayIndex']),
  172.             new \Twig\TwigFunction('cdn', [$this'getCdn']),
  173.             new \Twig\TwigFunction('is_show_mobile_page', [$this'isShowMobilePage']),
  174.             new \Twig\TwigFunction('is_mobile_client', [$this'isMobileClient']),
  175.             new \Twig\TwigFunction('is_allow_browse', [$this'isAllowBrowse']),
  176.             new \Twig\TwigFunction('is_ES_copyright', [$this'isESCopyright']),
  177.             new \Twig\TwigFunction('get_classroom_name', [$this'getClassroomName']),
  178.             new \Twig\TwigFunction('pop_reward_point_notify', [$this'popRewardPointNotify']),
  179.             new \Twig\TwigFunction('array_filter', [$this'arrayFilter']),
  180.             new \Twig\TwigFunction('base_path', [$this'basePath']),
  181.             new \Twig\TwigFunction('get_login_email_address', [$this'getLoginEmailAddress']),
  182.             new \Twig\TwigFunction('cloud_sdk_url', [$this'getCloudSdkUrl']),
  183.             new \Twig\TwigFunction('math_format', [$this'mathFormat']),
  184.             new \Twig\TwigFunction('parse_user_agent', [$this'parseUserAgent']),
  185.             new \Twig\TwigFunction('wechat_login_bind_enabled', [$this'isWechatLoginBind']),
  186.             new \Twig\TwigFunction('can_send_message', [$this'canSendMessage']),
  187.             new \Twig\TwigFunction('is_hidden_video_header', [$this'isHiddenVideoHeader']),
  188.             new \Twig\TwigFunction('arrays_key_convert', [$this'arraysKeyConvert']),
  189.             new \Twig\TwigFunction('make_local_media_file_token', [$this'makeLocalMediaFileToken']),
  190.             new \Twig\TwigFunction('online_advisory_auth_info', [$this'onlineAdvisoryAuthInfo']),
  191.             new \Twig\TwigFunction('question_html_filter', [$this'questionHtmlFilter']),
  192.             new \Twig\TwigFunction('uniqid', [$this'uniqid']),
  193.             new \Twig\TwigFunction('can_operate_question', [$this'canOperateQuestion']),
  194.             new \Twig\TwigFunction('sync_mode_dict', [$this'getSyncModeDict']),
  195.             new \Twig\TwigFunction('show_feedback_bar', [$this'showFeedbackBar']),
  196.             new \Twig\TwigFunction('is_saas', [$this'isSaaS']),
  197.             new \Twig\TwigFunction('member_deadline', [$this'handleDeadline']),
  198.             new \Twig\TwigFunction('get_course_market_url', [$this'getCourseMarketUrl']),
  199.             new \Twig\TwigFunction('org_msg', [$this'getOrgMsg']),
  200.             new \Twig\TwigFunction('get_category_name', [$this'getCategoryName']),
  201.             new \Twig\TwigFunction('get_category_ids_by_categories', [$this'getCategoryIdsByCategories']),
  202.             new \Twig\TwigFunction('get_review_pending_total_num', [$this'getReviewPendingTotalNum']),
  203.             new \Twig\TwigFunction('get_remember_me_deadline_range_text', [$this'getRememberMeDeadlineRangeText']),
  204.             new \Twig\TwigFunction('is_question_answered', [$this'isQuestionAnswered']),
  205.             new \Twig\TwigFunction('is_enabled_lms', [$this'isEnabledLms']),
  206.             new \Twig\TwigFunction('is_lms_version_supported', [$this'isLmsVersionSupported']),
  207.             new \Twig\TwigFunction('main_request_route', [$this'mainRequestRoute']),
  208.             new \Twig\TwigFunction('has_live_tasks', [$this'hasLiveTasks']),
  209.         ];
  210.     }
  211.     public function getCourseMarketUrl()
  212.     {
  213.         return ServiceKernel::instance()->getParameter('security.course_market.url');
  214.     }
  215.     public function parseUserAgent($userAgent)
  216.     {
  217.         $deviceDetector = new DeviceDetectorAdapter($userAgent);
  218.         return [
  219.             'device' => $deviceDetector->getDevice(),
  220.             'client' => $deviceDetector->getClient(),
  221.             'os' => $deviceDetector->getOs(),
  222.         ];
  223.     }
  224.     public function handleDeadline($deadline$issueDate 0)
  225.     {
  226.         if (== $deadline) {
  227.             return 0;
  228.         }
  229.         if (== $issueDate) {
  230.             $time time();
  231.         } else {
  232.             $time $issueDate;
  233.         }
  234.         if (($deadline $time) < 0) {
  235.             return -1;
  236.         }
  237.         return floor(($deadline $time) / 3600 24);
  238.     }
  239.     public function arrayFilter($data$filterName)
  240.     {
  241.         if (empty($data) || !is_array($data)) {
  242.             return [];
  243.         }
  244.         return array_filter($data, function ($value) use ($filterName) {
  245.             foreach ($filterName as $name) {
  246.                 if ('' === $value[$name]) {
  247.                     return false;
  248.                 }
  249.             }
  250.             return true;
  251.         });
  252.     }
  253.     public function getReviewPendingTotalNum()
  254.     {
  255.         $user $this->getUserService()->getCurrentUser();
  256.         $reviewPendingCount $this->getReviewCenterService()->getPendingTabbar($user['id']);
  257.         return array_sum(array_column($reviewPendingCount'pendingCount'));
  258.     }
  259.     public function isShowMobilePage()
  260.     {
  261.         $wapSetting $this->getSetting('wap', []);
  262.         if (empty($wapSetting['enabled'])) {
  263.             return false;
  264.         }
  265.         $pcVersion $this->container->get('request_stack')->getMainRequest()->cookies->get('PCVersion'0);
  266.         if ($pcVersion) {
  267.             return false;
  268.         }
  269.         return DeviceToolkit::isMobileClient();
  270.     }
  271.     public function isMobileClient()
  272.     {
  273.         return DeviceToolkit::isMobileClient();
  274.     }
  275.     public function isAllowBrowse()
  276.     {
  277.         $userAgent $this->container->get('request_stack')->getMainRequest()->headers->get('User-Agent');
  278.         $allowedBrowse = ['MicroMessenger''wxwork''DingTalk''Feishu'];
  279.         $allow false;
  280.         foreach ($allowedBrowse as $browse) {
  281.             if (false !== strpos($userAgent$browse)) {
  282.                 $allow true;
  283.                 break;
  284.             }
  285.         }
  286.         return $allow;
  287.     }
  288.     public function isESCopyright()
  289.     {
  290.         $copyright $this->getSetting('copyright');
  291.         $request $this->container->get('request_stack')->getMainRequest();
  292.         $host $request->getHttpHost();
  293.         if ($copyright) {
  294.             $result = !(
  295.                 isset($copyright['owned'])
  296.                 && isset($copyright['thirdCopyright'])
  297.                 && != $copyright['thirdCopyright']
  298.                 && isset($copyright['licenseDomains'])
  299.                 && in_array($hostexplode(';'$copyright['licenseDomains']))
  300.                 || (isset($copyright['thirdCopyright']) && == $copyright['thirdCopyright'])
  301.             );
  302.             return $result;
  303.         }
  304.         return true;
  305.     }
  306.     public function getClassroomName()
  307.     {
  308.         return $this->getSetting('classroom.name'$this->container->get('translator')->trans('site.default.classroom'));
  309.     }
  310.     public function tagEqual($tags$targetTagId$targetTagGroupId)
  311.     {
  312.         foreach ($tags as $groupId => $tagId) {
  313.             if ($groupId == $targetTagGroupId && $tagId == $targetTagId) {
  314.                 return true;
  315.             }
  316.         }
  317.         return false;
  318.     }
  319.     public function getTag($tagId)
  320.     {
  321.         if (empty($tagId)) {
  322.             return null;
  323.         }
  324.         return $this->getTagService()->getTag($tagId);
  325.     }
  326.     public function arrayIndex($array$key)
  327.     {
  328.         if (empty($array) || !is_array($array)) {
  329.             return [];
  330.         }
  331.         return ArrayToolkit::index($array$key);
  332.     }
  333.     public function timeFormatterFilter($time)
  334.     {
  335.         $hour floor($time 3600);
  336.         $minute floor(($time 3600) / 60);
  337.         $second $time 60;
  338.         if ($hour 0) {
  339.             if ($minute && $second 0) {
  340.                 return $this->trans('site.twig.extension.time_interval.hour_minute_second', [
  341.                     '%diff_hour%' => $hour,
  342.                     '%diff_minute%' => $minute,
  343.                     '%diff_second%' => $second,
  344.                 ]);
  345.             }
  346.             if ($minute 0) {
  347.                 return $this->trans('site.twig.extension.time_interval.hour_minute', [
  348.                     '%diff_hour%' => $hour,
  349.                     '%diff_minute%' => $minute,
  350.                 ]);
  351.             }
  352.             if ($second 0) {
  353.                 return $this->trans('site.twig.extension.time_interval.hour_second', [
  354.                     '%diff_hour%' => $hour,
  355.                     '%diff_second%' => $second,
  356.                 ]);
  357.             }
  358.             return $this->trans('site.twig.extension.time_interval.hour', [
  359.                 '%diff%' => $hour,
  360.             ]);
  361.         }
  362.         if ($minute 0) {
  363.             if ($second 0) {
  364.                 return $this->trans('site.twig.extension.time_interval.minute_second', [
  365.                     '%diff_minute%' => $minute,
  366.                     '%diff_second%' => $second,
  367.                 ]);
  368.             }
  369.             return $this->trans('site.twig.extension.time_interval.minute', [
  370.                 '%diff%' => $minute,
  371.             ]);
  372.         }
  373.         return $this->trans('site.twig.extension.time_interval.second', [
  374.             '%diff%' => $second,
  375.         ]);
  376.     }
  377.     public function pluginUpdateNotify()
  378.     {
  379.         $count $this->getAppService()->findAppCount();
  380.         $apps $this->getAppService()->findApps(0$count);
  381.         $apps array_filter($apps, function ($app) {
  382.             return 'EduSoho官方' == $app['developerName'];
  383.         });
  384.         $notifies array_reduce(
  385.             $apps,
  386.             function ($notifies$app) {
  387.                 if (!PluginVersionToolkit::dependencyVersion($app['code'], $app['version'])) {
  388.                     $notifies[$app['type']][] = $app['name'];
  389.                 } elseif ('TRAININGMAIN' !== $app['code'] && $app['protocol'] < 3) {
  390.                     $notifies[$app['type']][] = $app['name'];
  391.                 }
  392.                 return $notifies;
  393.             },
  394.             []
  395.         );
  396.         return $notifies;
  397.     }
  398.     public function getAdminRoles()
  399.     {
  400.         return $this->createService('Role:RoleService')->searchRoles([], 'created'01000);
  401.     }
  402.     public function getCdn($type 'default')
  403.     {
  404.         $cdn = new CdnUrl();
  405.         $cdnUrl $cdn->get($type);
  406.         return $cdnUrl;
  407.     }
  408.     public function cdn($content)
  409.     {
  410.         $cdn = new CdnUrl();
  411.         $cdnUrl $cdn->get('content');
  412.         if ($cdnUrl) {
  413.             $publicUrlPath $this->container->getParameter('topxia.upload.public_url_path');
  414.             $themeUrlPath $this->container->getParameter('topxia.web_themes_url_path');
  415.             $assetUrlPath $this->container->getParameter('topxia.web_assets_url_path');
  416.             $bundleUrlPath $this->container->getParameter('topxia.web_bundles_url_path');
  417.             $staticDistUrlPath $this->container->getParameter('front_end.web_static_dist_url_path');
  418.             preg_match_all('/<img[^>]*src=[\'"]?([^>\'"\s]*)[\'"]?[^>]*>/i'$content$imgs);
  419.             if ($imgs) {
  420.                 foreach ($imgs[1] as $img) {
  421.                     if (=== strpos($img$publicUrlPath)
  422.                         || === strpos($img$themeUrlPath)
  423.                         || === strpos($img$assetUrlPath)
  424.                         || === strpos($img$bundleUrlPath)
  425.                         || === strpos($img$staticDistUrlPath)) {
  426.                         $content str_replace('"'.$img'"'.$cdnUrl.$img$content);
  427.                     }
  428.                 }
  429.             }
  430.         }
  431.         return $content;
  432.     }
  433.     public function weixinConfig()
  434.     {
  435.         $weixinmob_enabled $this->getSetting('login_bind.weixinmob_enabled');
  436.         if (!(bool) $weixinmob_enabled) {
  437.             return null;
  438.         }
  439.         $jsApiTicket $this->createService('User:TokenService')->getTokenByType('jsapi.ticket');
  440.         $key $this->getSetting('login_bind.weixinmob_key');
  441.         $secret $this->getSetting('login_bind.weixinmob_secret');
  442.         if (empty($jsApiTicket)) {
  443.             $config = ['key' => $key'secret' => $secret];
  444.             $weixinshare = new WeixinShare($config);
  445.             $token $weixinshare->getJsApiTicket();
  446.             if (empty($token)) {
  447.                 return [];
  448.             }
  449.             $jsApiTicket $this->createService('User:TokenService')->makeToken(
  450.                 'jsapi.ticket',
  451.                 ['data' => $token'duration' => $token['expires_in']]
  452.             );
  453.         }
  454.         $config = [
  455.             'appId' => $key,
  456.             'timestamp' => time(),
  457.             'nonceStr' => uniqid($prefix 'edusoho'),
  458.             'jsApiList' => ['onMenuShareTimeline''onMenuShareAppMessage''onMenuShareQZone''onMenuShareQQ'],
  459.         ];
  460.         $jsapi_ticket $jsApiTicket['data']['ticket'];
  461.         $url $this->container->get('request_stack')->getMainRequest()->getUri();
  462.         $string 'jsapi_ticket='.$jsapi_ticket.'&noncestr='.$config['nonceStr'].'&timestamp='.$config['timestamp'].'&url='.$url;
  463.         $config['string'] = $string;
  464.         $config['signature'] = sha1($string);
  465.         return json_encode($config);
  466.     }
  467.     public function renderNotification($notification)
  468.     {
  469.         if ($notification) {
  470.             $manager ExtensionManager::instance();
  471.             $notification['message'] = $manager->renderNotification($notification);
  472.         }
  473.         return $notification;
  474.     }
  475.     public function routeExists($name)
  476.     {
  477.         $router $this->container->get('router');
  478.         return (null === $router->getRouteCollection()->get($name)) ? false true;
  479.     }
  480.     public function isWithoutNetwork()
  481.     {
  482.         $network $this->getSetting('developer.without_network'$default false);
  483.         return (bool) $network;
  484.     }
  485.     public function getUserVipLevel($userId)
  486.     {
  487.         return $this->createService('VipPlugin:Vip:VipService')->getMemberByUserId($userId);
  488.     }
  489.     public function getParametersFromUrl($url)
  490.     {
  491.         $BaseUrl parse_url($url);
  492.         if (isset($BaseUrl['query'])) {
  493.             if (strstr($BaseUrl['query'], '&')) {
  494.                 $parameter explode('&'$BaseUrl['query']);
  495.                 $parameters = [];
  496.                 foreach ($parameter as $key => $value) {
  497.                     $parameters[$key] = explode('='$value);
  498.                 }
  499.             } else {
  500.                 $parameter explode('='$BaseUrl['query']);
  501.                 $parameters = [];
  502.                 $parameters[0] = $parameter;
  503.             }
  504.         } else {
  505.             return null;
  506.         }
  507.         return $parameters;
  508.     }
  509.     public function spaceToNbsp($content)
  510.     {
  511.         $content str_replace(' ''&nbsp;'$content);
  512.         return $content;
  513.     }
  514.     public function isMicroMessenger()
  515.     {
  516.         return false !== strpos($this->container->get('request_stack')->getMainRequest()->headers->get('User-Agent'), 'MicroMessenger');
  517.     }
  518.     public function renameLocale($locale)
  519.     {
  520.         $locale strtolower($locale);
  521.         $locale str_replace('_''-'$locale);
  522.         return 'zh-cn' == $locale '' '-'.$locale;
  523.     }
  524.     public function getFingerprint()
  525.     {
  526.         $user $this->getUserService()->getCurrentUser();
  527.         if (!$user->isLogin()) {
  528.             return '';
  529.         }
  530.         $user $this->getUserService()->getUser($user['id']);
  531.         // @todo 如果配置用户的关键信息,这个方法存在信息泄漏风险,更换新播放器后解决这个问题。
  532.         $pattern $this->getSetting('magic.video_fingerprint');
  533.         if ($pattern) {
  534.             $fingerprint $this->parsePattern($pattern$user);
  535.         } else {
  536.             $request $this->container->get('request_stack')->getMainRequest();
  537.             $host $request->getHttpHost();
  538.             $fingerprint "{$host} {$user['nickname']}";
  539.         }
  540.         return $fingerprint;
  541.     }
  542.     public function popRewardPointNotify()
  543.     {
  544.         $session $this->container->get('session');
  545.         if (empty($session)) {
  546.             return '';
  547.         }
  548.         $message $session->get('Reward-Point-Notify');
  549.         $session->remove('Reward-Point-Notify');
  550.         return $message;
  551.     }
  552.     protected function parsePattern($pattern$user)
  553.     {
  554.         $profile $this->getUserService()->getUserProfile($user['id']);
  555.         $values array_merge($user$profile);
  556.         $values array_filter(
  557.             $values,
  558.             function ($value) {
  559.                 return !is_array($value);
  560.             }
  561.         );
  562.         return $this->simpleTemplateFilter($pattern$values);
  563.     }
  564.     public function subStr($text$start$length)
  565.     {
  566.         $text trim($text);
  567.         $length = (int) $length;
  568.         if (($length 0) && (mb_strlen($text) > $length)) {
  569.             $text mb_substr($text$start$length'UTF-8');
  570.         }
  571.         return $text;
  572.     }
  573.     public function convertEncodingSubStr($text$start$length)
  574.     {
  575.         $strlen = (strlen($text) + mb_strlen($text'UTF-8')) / 2;
  576.         if ($strlen <= $length) {
  577.             return $text;
  578.         }
  579.         $text mb_strcut(mb_convert_encoding($text'GBK''UTF-8'), 0$length'GBK');
  580.         return mb_convert_encoding($text'UTF-8''GBK').'...';
  581.     }
  582.     public function userCoinAmount($type$userId$startDateTime null$endDateTime null)
  583.     {
  584.         // 支付模块已移除,返回默认值
  585.         return 0;
  586.     }
  587.     public function getBalance($userId)
  588.     {
  589.         // 支付模块已移除,返回默认值
  590.         return ['amount' => 0'user_id' => $userId];
  591.     }
  592.     /**
  593.      * @return UserService
  594.      */
  595.     private function getUserService()
  596.     {
  597.         return $this->createService('User:UserService');
  598.     }
  599.     public function isExistInSubArrayById($currentTarget$targetArray)
  600.     {
  601.         foreach ($targetArray as $target) {
  602.             if ($currentTarget['id'] == $target['id']) {
  603.                 return true;
  604.             }
  605.         }
  606.         return false;
  607.     }
  608.     public function getThemeGlobalScript()
  609.     {
  610.         $theme $this->getSetting('theme.uri''default');
  611.         $filePath realpath(
  612.             $this->container->getParameter('kernel.root_dir')."/../web/themes/{$theme}/js/global-script.js"
  613.         );
  614.         if ($filePath) {
  615.             return 'theme/global-script';
  616.         }
  617.         return '';
  618.     }
  619.     public function isPluginInstalled($name)
  620.     {
  621.         return $this->container->get('kernel')->getPluginConfigurationManager()->isPluginInstalled($name);
  622.     }
  623.     public function canShowClassRoom()
  624.     {
  625.         return CloudSchoolLevelHelper::canShowClassRoom();
  626.     }
  627.     public function canShowArticle()
  628.     {
  629.         return CloudSchoolLevelHelper::canShowArticle();
  630.     }
  631.     public function canShowOfflineActivity()
  632.     {
  633.         return CloudSchoolLevelHelper::canShowOfflineActivity();
  634.     }
  635.     public function canShowMobileApp()
  636.     {
  637.         return CloudSchoolLevelHelper::canShowMobileApp();
  638.     }
  639.     public function canShowArticleGroup()
  640.     {
  641.         return CloudSchoolLevelHelper::canShowArticleGroup();
  642.     }
  643.     public function getPluginVersion($name)
  644.     {
  645.         $plugins $this->container->get('kernel')->getPlugins();
  646.         foreach ($plugins as $plugin) {
  647.             if (strtolower($plugin['code']) == strtolower($name)) {
  648.                 return $plugin['version'];
  649.             }
  650.         }
  651.         return null;
  652.     }
  653.     public function versionCompare($version1$version2$operator)
  654.     {
  655.         return version_compare($version1$version2$operator);
  656.     }
  657.     public function getJsPaths($excludedCdnResources = [])
  658.     {
  659.         $cdnUrl = new CdnUrl();
  660.         $basePath $cdnUrl->get();
  661.         if (empty($basePath)) {
  662.             $basePath $this->container->get('request_stack')->getMainRequest()->getBasePath();
  663.         }
  664.         $theme $this->getSetting('theme.uri''default');
  665.         $plugins $this->container->get('kernel')->getPlugins();
  666.         $names = [];
  667.         $newPluginNames = [];
  668.         foreach ($plugins as $plugin) {
  669.             if (is_array($plugin)) {
  670.                 if ('plugin' != $plugin['type']) {
  671.                     continue;
  672.                 }
  673.                 if (isset($plugin['protocol']) && == $plugin['protocol']) {
  674.                     $newPluginNames[] = $plugin['code'].'plugin';
  675.                 } else {
  676.                     $names[] = $plugin['code'];
  677.                 }
  678.             } else {
  679.                 $names[] = $plugin;
  680.             }
  681.         }
  682.         $names[] = 'customweb';
  683.         $names[] = 'customadmin';
  684.         $names[] = 'custom';
  685.         $names[] = 'topxiaweb';
  686.         $names[] = 'topxiaadmin';
  687.         $names[] = 'classroom';
  688.         $names[] = 'materiallib';
  689.         $names[] = 'sensitiveword';
  690.         $names[] = 'permission';
  691.         $names[] = 'org';
  692.         $names[] = 'corporatetraining';
  693.         $paths = [
  694.             'common' => 'common',
  695.             'theme' => "{$basePath}/themes/{$theme}/js",
  696.         ];
  697.         foreach ($names as $name) {
  698.             $name strtolower($name);
  699.             if (!empty($excludedCdnResources) && in_array($name$excludedCdnResources)) {
  700.                 $paths["{$name}bundle"] = "/bundles/{$name}/js";
  701.             } else {
  702.                 $paths["{$name}bundle"] = "{$basePath}/bundles/{$name}/js";
  703.             }
  704.         }
  705.         foreach ($newPluginNames as $newPluginName) {
  706.             $newPluginName strtolower($newPluginName);
  707.             if (!empty($excludedCdnResources) && in_array($newPluginName$excludedCdnResources)) {
  708.                 $paths["{$newPluginName}"] = "/bundles/{$newPluginName}/js";
  709.             } else {
  710.                 $paths["{$newPluginName}"] = "{$basePath}/bundles/{$newPluginName}/js";
  711.             }
  712.         }
  713.         // $paths['balloon-video-player'] = 'http://player-cdn.edusoho.net/balloon-video-player';
  714.         return $paths;
  715.     }
  716.     public function getContextValue($context$key)
  717.     {
  718.         $keys explode('.'$key);
  719.         $value $context;
  720.         foreach ($keys as $key) {
  721.             if (!isset($value[$key])) {
  722.                 throw new \InvalidArgumentException(sprintf('Key `%s` is not in context with %s'$keyimplode(array_keys($context), ', ')));
  723.             }
  724.             $value $value[$key];
  725.         }
  726.         return $value;
  727.     }
  728.     public function isFeatureEnabled($feature)
  729.     {
  730.         $features $this->container->hasParameter('enabled_features') ? $this->container->getParameter(
  731.             'enabled_features'
  732.         ) : [];
  733.         return in_array($feature$features);
  734.     }
  735.     public function getParameter($name$default null)
  736.     {
  737.         if (!$this->container->hasParameter($name)) {
  738.             return $default;
  739.         }
  740.         return $this->container->getParameter($name);
  741.     }
  742.     public function makeUpoadToken($group$type 'image'$duration 18000)
  743.     {
  744.         $maker = new UploadToken();
  745.         return $maker->make($group$type$duration);
  746.     }
  747.     public function getConvertIP($ip)
  748.     {
  749.         if (!empty($ip)) {
  750.             $location ConvertIpToolkit::convertIp($ip);
  751.             if ('INNA' === $location) {
  752.                 return '未知区域';
  753.             }
  754.             return $location;
  755.         }
  756.         return '';
  757.     }
  758.     public function getNewConverIP($ip)
  759.     {
  760.         if (!empty($ip)) {
  761.             $location ConvertIpToolkit::newConvertIp($ip);
  762.             if ('INNA' === $location) {
  763.                 return '未知区域';
  764.             }
  765.             $location array_filter($location);
  766.             return implode(' '$location);
  767.         }
  768.         return '';
  769.     }
  770.     public function dateformatFilter($time$format '')
  771.     {
  772.         if (empty($time)) {
  773.             return;
  774.         }
  775.         if (empty($format)) {
  776.             return date('Y-m-d H:i'$time);
  777.         }
  778.         return date($format$time);
  779.     }
  780.     public function smarttimeFilter($time)
  781.     {
  782.         $diff time() - $time;
  783.         if ($diff 0) {
  784.             return $this->trans('site.twig.extension.smarttime.future');
  785.         }
  786.         if (== $diff) {
  787.             return $this->trans('site.twig.extension.smarttime.hardly');
  788.         }
  789.         if ($diff 60) {
  790.             return $this->trans('site.twig.extension.smarttime.previous_second', ['%diff%' => $diff]);
  791.         }
  792.         if ($diff 3600) {
  793.             return $this->trans('site.twig.extension.smarttime.previous_minute', ['%diff%' => round($diff 60)]);
  794.         }
  795.         if ($diff 86400) {
  796.             return $this->trans('site.twig.extension.smarttime.previous_hour', ['%diff%' => round($diff 3600)]);
  797.         }
  798.         if ($diff 2592000) {
  799.             return $this->trans('site.twig.extension.smarttime.previous_day', ['%diff%' => round($diff 86400)]);
  800.         }
  801.         if ($diff 31536000) {
  802.             return date('m-d'$time);
  803.         }
  804.         return date('Y-m-d'$time);
  805.     }
  806.     public function remainTimeFilter($value$timeType '')
  807.     {
  808.         $remainTime = [];
  809.         $remain $value time();
  810.         if ($remain <= && empty($timeType)) {
  811.             return $remainTime['second'] = '0'.$this->trans('site.date.minute');
  812.         }
  813.         if ($remain <= 3600 && empty($timeType)) {
  814.             return $remainTime['minutes'] = round($remain 60).$this->trans('site.date.minute');
  815.         }
  816.         if ($remain 86400 && empty($timeType)) {
  817.             return $remainTime['hours'] = round($remain 3600).$this->trans('site.date.hour');
  818.         }
  819.         $remainTime['day'] = round(($remain $remain) / 86400).$this->trans('site.date.day');
  820.         if (!empty($timeType)) {
  821.             return $remainTime[$timeType];
  822.         } else {
  823.             return $remainTime['day'];
  824.         }
  825.     }
  826.     public function getCountdownTime($value)
  827.     {
  828.         $countdown = ['days' => 0'hours' => 0'minutes' => 0'seconds' => 0];
  829.         $remain $value time();
  830.         if ($remain <= 0) {
  831.             return $countdown;
  832.         }
  833.         $countdown['days'] = intval($remain 86400);
  834.         $remain $remain 86400 $countdown['days'];
  835.         $countdown['hours'] = intval($remain 3600);
  836.         $remain $remain 3600 $countdown['hours'];
  837.         $countdown['minutes'] = intval($remain 60);
  838.         $remain $remain 60 $countdown['minutes'];
  839.         $countdown['seconds'] = $remain;
  840.         return $countdown;
  841.     }
  842.     public function durationFilter($value)
  843.     {
  844.         $minutes intval($value 60);
  845.         $seconds $value $minutes 60;
  846.         return sprintf('%02d'$minutes).':'.sprintf('%02d'$seconds);
  847.     }
  848.     public function durationTextFilter($value)
  849.     {
  850.         $minutes intval($value 60);
  851.         $seconds $value $minutes 60;
  852.         if (=== $minutes) {
  853.             return $seconds.$this->trans('site.date.second');
  854.         }
  855.         return $this->trans('site.twig.extension.time_interval.minute_second', ['%diff_minute%' => $minutes'%diff_second%' => $seconds]);
  856.     }
  857.     /**
  858.      * 毫秒转 HH:MM:SS 格式,用于 segment 视频展示名等
  859.      */
  860.     public function formatMsToHmsFilter($ms)
  861.     {
  862.         $ms = (int) $ms;
  863.         $s = (int) floor($ms 1000);
  864.         $h = (int) floor($s 3600);
  865.         $m = (int) floor(($s 3600) / 60);
  866.         $s $s 60;
  867.         return sprintf('%02d:%02d:%02d'$h$m$s);
  868.     }
  869.     public function timeRangeFilter($start$end)
  870.     {
  871.         $range date('Y-n-d H:i'$start).' - ';
  872.         if ($this->container->get('topxia.timemachine')->inSameDay($start$end)) {
  873.             $range .= date('H:i'$end);
  874.         } else {
  875.             $range .= date('Y年n月d日 H:i'$end);
  876.         }
  877.         return $range;
  878.     }
  879.     public function timeDiffFilter($endTime$diffDay 0$startTime '')
  880.     {
  881.         $endSecond strtotime(date('Y-m-d'$endTime));
  882.         $startSecond = empty($startTime) ? strtotime(date('Y-m-d'time())) : $startTime;
  883.         $diffDay round(($endSecond $startSecond) / 864000PHP_ROUND_HALF_DOWN); // 丢弃小数点
  884.         return $diffDay $diffDay 0;
  885.     }
  886.     public function tagsJoinFilter($tagIds)
  887.     {
  888.         if (empty($tagIds) || !is_array($tagIds)) {
  889.             return '';
  890.         }
  891.         $tags $this->createService('Taxonomy:TagService')->findTagsByIds($tagIds);
  892.         $names ArrayToolkit::column($tags'name');
  893.         return join($names',');
  894.     }
  895.     public function navigationUrlFilter($url)
  896.     {
  897.         $url = (string) $url;
  898.         if (strpos($url'://')) {
  899.             return $url;
  900.         }
  901.         if (!empty($url[0]) && ('/' == $url[0])) {
  902.             return $url;
  903.         }
  904.         return $this->container->get('request_stack')->getMainRequest()->getBaseUrl().'/'.$url;
  905.     }
  906.     /**
  907.      *                            P -> 省全称,     p -> 省简称
  908.      *                            C -> 城市全称,    c -> 城市简称
  909.      *                            D -> 区全称,     d -> 区简称.
  910.      *
  911.      * @param [type] $districeId [description]
  912.      * @param string $format 格式,默认格式'P C D'
  913.      *
  914.      * @return [type] [description]
  915.      */
  916.     public function locationTextFilter($districeId$format 'P C D')
  917.     {
  918.         $text '';
  919.         $names $this->createService('Taxonomy:LocationService')->getLocationFullName($districeId);
  920.         $len strlen($format);
  921.         for ($i 0$i $len; ++$i) {
  922.             switch ($format[$i]) {
  923.                 case 'P':
  924.                     $text .= $names['province'];
  925.                     break;
  926.                 case 'p':
  927.                     $text .= $this->mb_trim($names['province'], '省');
  928.                     break;
  929.                 case 'C':
  930.                     $text .= $names['city'];
  931.                     break;
  932.                 case 'c':
  933.                     $text .= $this->mb_trim($names['city'], '市');
  934.                     break;
  935.                 case 'D':
  936.                 case 'd':
  937.                     $text .= $names['district'];
  938.                     break;
  939.                 default:
  940.                     $text .= $format[$i];
  941.                     break;
  942.             }
  943.         }
  944.         return $text;
  945.     }
  946.     public function tagsHtmlFilter($tags$class '')
  947.     {
  948.         $links = [];
  949.         $tags $this->createService('Taxonomy:TagService')->findTagsByIds($tags);
  950.         foreach ($tags as $tag) {
  951.             $url $this->container->get('router')->generate('course_explore', ['tagId' => $tag['id']]);
  952.             $links[] = "<a href=\"{$url}\" class=\"{$class}\">{$tag['name']}</a>";
  953.         }
  954.         return implode(' '$links);
  955.     }
  956.     public function parseFileUri($uri)
  957.     {
  958.         $kernel ServiceKernel::instance();
  959.         return $kernel->createService('Content:FileService')->parseFileUri($uri);
  960.     }
  961.     public function getFilePath($uri$default ''$absolute false)
  962.     {
  963.         $assets $this->container->get('assets.default_package_util');
  964.         $request $this->container->get('request_stack')->getMainRequest();
  965.         if (empty($uri)) {
  966.             $url $assets->getUrl('assets/img/default/'.$default);
  967.             // $url = $request->getBaseUrl() . '/assets/img/default/' . $default;
  968.             if ($absolute) {
  969.                 $url $request->getSchemeAndHttpHost().$url;
  970.             }
  971.             return $url;
  972.         }
  973.         if (false !== strpos($uri'http://')) {
  974.             return $uri;
  975.         }
  976.         $uri $this->parseFileUri($uri);
  977.         if ('public' == $uri['access']) {
  978.             $url rtrim($this->container->getParameter('topxia.upload.public_url_path'), ' /').'/'.$uri['path'];
  979.             $url ltrim($url' /');
  980.             $url $assets->getUrl($url);
  981.             if ($absolute) {
  982.                 $url $request->getSchemeAndHttpHost().$url;
  983.             }
  984.             return $url;
  985.         }
  986.     }
  987.     public function getDefaultPath($category$uri ''$size ''$absolute false)
  988.     {
  989.         $assets $this->container->get('assets.default_package_util');
  990.         $request $this->container->get('request_stack')->getMainRequest();
  991.         if (empty($uri)) {
  992.             $publicUrlpath 'assets/img/default/';
  993.             $url $assets->getUrl($publicUrlpath.$size.$category);
  994.             $defaultSetting $this->createService('System:SettingService')->get('default', []);
  995.             $key 'default'.ucfirst($category);
  996.             $fileName $key.'FileName';
  997.             if (array_key_exists($key$defaultSetting) && array_key_exists($fileName$defaultSetting)) {
  998.                 if (== $defaultSetting[$key]) {
  999.                     $url $assets->getUrl($publicUrlpath.$size.$defaultSetting[$fileName]);
  1000.                 }
  1001.             } elseif (array_key_exists($key$defaultSetting) && $defaultSetting[$key]) {
  1002.                 $uri $defaultSetting[$size.'Default'.ucfirst($category).'Uri'];
  1003.             } else {
  1004.                 return $url;
  1005.             }
  1006.             if ($absolute) {
  1007.                 $url $request->getSchemeAndHttpHost().$url;
  1008.             }
  1009.             return $url;
  1010.         }
  1011.         return $this->parseUri($uri$absolute);
  1012.     }
  1013.     public function avatarPath($user$type 'middle'$package 'user')
  1014.     {
  1015.         $avatar = !empty($user[$type.'Avatar']) ? $user[$type.'Avatar'] : null;
  1016.         if (empty($avatar)) {
  1017.             $avatar $this->getSetting('avatar.png');
  1018.         }
  1019.         return $this->getFpath($avatar'avatar.png'$package);
  1020.     }
  1021.     private function parseUri($uri$absolute false$package 'content')
  1022.     {
  1023.         if (false !== strpos($uri'http://') || false !== strpos($uri'https://')) {
  1024.             return $uri;
  1025.         }
  1026.         $assets $this->container->get('assets.default_package_util');
  1027.         $request $this->container->get('request_stack')->getMainRequest();
  1028.         if (strpos($uri'://')) {
  1029.             $uri $this->parseFileUri($uri);
  1030.             $url '';
  1031.             if ('public' == $uri['access']) {
  1032.                 $url $uri['path'];
  1033.             }
  1034.             if ('themes' == $uri['access']) {
  1035.                 return $this->addHost('/'.$uri['access'].'/'.$uri['path'], $absolute$package);
  1036.             }
  1037.         } else {
  1038.             $url $uri;
  1039.         }
  1040.         $url rtrim($this->container->getParameter('topxia.upload.public_url_path'), ' /').'/'.$url;
  1041.         return $this->addHost($url$absolute$package);
  1042.     }
  1043.     public function getSystemDefaultPath($defaultKey$absolute false)
  1044.     {
  1045.         $assets $this->container->get('assets.default_package_util');
  1046.         $defaultSetting $this->getSetting('default', []);
  1047.         if (array_key_exists($defaultKey$defaultSetting)
  1048.             && $defaultSetting[$defaultKey]
  1049.         ) {
  1050.             $path $defaultSetting[$defaultKey];
  1051.             return $this->parseUri($path$absolute);
  1052.         } else {
  1053.             $path $assets->getUrl('assets/img/default/'.$defaultKey);
  1054.             return $this->addHost($path$absolute);
  1055.         }
  1056.     }
  1057.     public function makeLazyImg($src$class ''$alt ''$img 'lazyload_course.png')
  1058.     {
  1059.         $imgpath $path $this->container->get('assets.default_package_util')->getUrl('assets/img/default/'.$img);
  1060.         return sprintf('<img src="%s" alt="%s" class="%s" data-echo="%s" />'$imgpath$alt$class$src);
  1061.     }
  1062.     public function loadScript($js)
  1063.     {
  1064.         $js is_array($js) ? $js : [$js];
  1065.         if ($this->pageScripts) {
  1066.             $this->pageScripts array_merge($this->pageScripts$js);
  1067.         } else {
  1068.             $this->pageScripts $js;
  1069.         }
  1070.     }
  1071.     public function exportScripts()
  1072.     {
  1073.         if (empty($this->pageScripts)) {
  1074.             $this->pageScripts = [];
  1075.         }
  1076.         return array_values(array_unique($this->pageScripts));
  1077.     }
  1078.     public function getFileUrl($uri$default ''$absolute false)
  1079.     {
  1080.         $assets $this->container->get('assets.default_package_util');
  1081.         $request $this->container->get('request_stack')->getMainRequest();
  1082.         if (empty($uri)) {
  1083.             $url $assets->getUrl('assets/img/default/'.$default);
  1084.             if ($absolute) {
  1085.                 $url $request->getSchemeAndHttpHost().$url;
  1086.             }
  1087.             return $url;
  1088.         }
  1089.         $url rtrim($this->container->getParameter('topxia.upload.public_url_path'), ' /').'/'.$uri;
  1090.         $url ltrim($url' /');
  1091.         $url $assets->getUrl($url);
  1092.         if ($absolute) {
  1093.             $url $request->getSchemeAndHttpHost().$url;
  1094.         }
  1095.         return $url;
  1096.     }
  1097.     public function getFurl($path$defaultKey false$package 'content')
  1098.     {
  1099.         return $this->getPublicFilePath($path$defaultKeytrue$package);
  1100.     }
  1101.     public function getFpath($path$defaultKey false$package 'content')
  1102.     {
  1103.         return $this->getPublicFilePath($path$defaultKeyfalse$package);
  1104.     }
  1105.     private function getPublicFilePath($path$defaultKey false$absolute false$package 'content')
  1106.     {
  1107.         $assets $this->container->get('assets.default_package_util');
  1108.         if (empty($path)) {
  1109.             $defaultSetting $this->getSetting('default', []);
  1110.             if ('user_avatar.png' == $defaultKey) {
  1111.                 $defaultKey 'avatar.png';
  1112.             }
  1113.             if ((('course.png' == $defaultKey && array_key_exists(
  1114.                             'defaultCoursePicture',
  1115.                             $defaultSetting
  1116.                         ) && == $defaultSetting['defaultCoursePicture'])
  1117.                     || ('avatar.png' == $defaultKey && array_key_exists(
  1118.                             'defaultAvatar',
  1119.                             $defaultSetting
  1120.                         ) && == $defaultSetting['defaultAvatar']))
  1121.                 && (array_key_exists($defaultKey$defaultSetting)
  1122.                     && $defaultSetting[$defaultKey])
  1123.             ) {
  1124.                 $path $defaultSetting[$defaultKey];
  1125.                 return $this->parseUri($path$absolute$package);
  1126.             } else {
  1127.                 return $this->addHost('/assets/img/default/'.$defaultKey$absolute$package);
  1128.             }
  1129.         }
  1130.         return $this->parseUri($path$absolute$package);
  1131.     }
  1132.     private function addHost($path$absolute$package 'content')
  1133.     {
  1134.         $cdn = new CdnUrl();
  1135.         $cdnUrl $cdn->get($package);
  1136.         if ($cdnUrl) {
  1137.             $isSecure $this->container->get('request_stack')->getMainRequest()->isSecure();
  1138.             $protocal $isSecure 'https:' 'http:';
  1139.             $path $protocal.$cdnUrl.$path;
  1140.         } elseif ($absolute) {
  1141.             $request $this->container->get('request_stack')->getMainRequest();
  1142.             $path $request->getSchemeAndHttpHost().$path;
  1143.         }
  1144.         return $path;
  1145.     }
  1146.     public function basePath($package 'content')
  1147.     {
  1148.         $cdn = new CdnUrl();
  1149.         $cdnUrl $cdn->get($package);
  1150.         if ($cdnUrl) {
  1151.             $isSecure $this->container->get('request_stack')->getMainRequest()->isSecure();
  1152.             $protocal $isSecure 'https:' 'http:';
  1153.             $path $protocal.$cdnUrl;
  1154.         } else {
  1155.             $request $this->container->get('request_stack')->getMainRequest();
  1156.             $path $request->getSchemeAndHttpHost();
  1157.         }
  1158.         return $path;
  1159.     }
  1160.     public function fileSizeFilter($size)
  1161.     {
  1162.         $currentValue $currentUnit null;
  1163.         $unitExps = ['B' => 0'KB' => 1'MB' => 2'GB' => 3];
  1164.         foreach ($unitExps as $unit => $exp) {
  1165.             $divisor pow(1024$exp);
  1166.             $currentUnit $unit;
  1167.             $currentValue $size $divisor;
  1168.             if ($currentValue 1024) {
  1169.                 break;
  1170.             }
  1171.         }
  1172.         return sprintf('%.2f'$currentValue).$currentUnit;
  1173.     }
  1174.     public function numberFilter($number)
  1175.     {
  1176.         if ($number <= 1000) {
  1177.             return $number;
  1178.         }
  1179.         $currentValue $currentUnit null;
  1180.         $unitExps = ['千' => 3'万' => 4'亿' => 8];
  1181.         foreach ($unitExps as $unit => $exp) {
  1182.             $divisor pow(10$exp);
  1183.             $currentUnit $unit;
  1184.             $currentValue $number $divisor;
  1185.             if ($currentValue 10) {
  1186.                 break;
  1187.             }
  1188.         }
  1189.         return sprintf('%.0f'$currentValue).$currentUnit;
  1190.     }
  1191.     public function loadObject($type$id)
  1192.     {
  1193.         $kernel ServiceKernel::instance();
  1194.         switch ($type) {
  1195.             case 'user':
  1196.                 return $kernel->createService('User:UserService')->getUser($id);
  1197.             case 'category':
  1198.                 return $this->getCategoryService()->getCategory($id);
  1199.             case 'course':
  1200.                 return $kernel->createService('Course:CourseService')->getCourse($id);
  1201.             case 'file_group':
  1202.                 return $kernel->createService('Content:FileService')->getFileGroup($id);
  1203.             default:
  1204.                 return null;
  1205.         }
  1206.     }
  1207.     public function plainTextFilter($text$length null)
  1208.     {
  1209.         $text strip_tags($text);
  1210.         $text str_replace(["\n""\r""\t"], ''$text);
  1211.         $text str_replace('&nbsp;'' '$text);
  1212.         $text trim($text);
  1213.         $length = (int) $length;
  1214.         if (($length 0) && (mb_strlen($text'UTF-8') > $length)) {
  1215.             $text mb_substr($text0$length'UTF-8');
  1216.             $text .= '...';
  1217.         }
  1218.         return $text;
  1219.     }
  1220.     public function subTextFilter($text$length null)
  1221.     {
  1222.         $text strip_tags($text);
  1223.         $text str_replace(["\n""\r""\t"], ''$text);
  1224.         $text str_replace('&nbsp;'' '$text);
  1225.         $text trim($text);
  1226.         $length = (int) $length;
  1227.         if (($length 0) && (mb_strlen($text'utf-8') > $length)) {
  1228.             $text mb_substr($text0$length'UTF-8');
  1229.             $text .= '...';
  1230.         }
  1231.         return $text;
  1232.     }
  1233.     public function mb_substr($text$length null)
  1234.     {
  1235.         $text strip_tags($text);
  1236.         $text str_replace(["\n""\r""\t"], ''$text);
  1237.         $text str_replace('&nbsp;'' '$text);
  1238.         $text trim($text);
  1239.         $length = (int) $length;
  1240.         if (($length 0) && (mb_strlen($text'utf-8') > $length)) {
  1241.             $text mb_substr($text0$length'UTF-8');
  1242.         }
  1243.         return $text;
  1244.     }
  1245.     public function getFileType($fileName$string null)
  1246.     {
  1247.         $fileName explode('.'$fileName);
  1248.         if ($string) {
  1249.             $name strtolower($fileName[count($fileName) - 1]).$string;
  1250.         }
  1251.         return $name;
  1252.     }
  1253.     public function getOrgMsg($orgId)
  1254.     {
  1255.         $orgService $this->createService('CorporateTrainingBundle:Org:OrgService');
  1256.         $org $orgService->getOrg($orgId);
  1257.         return $org;
  1258.     }
  1259.     public function getCategoryName($categoryId)
  1260.     {
  1261.         $categoryService $this->getCategoryService();
  1262.         if (empty($categoryId)) {
  1263.             return '';
  1264.         }
  1265.         $category $categoryService->getCategory($categoryId);
  1266.         if (empty($category)) {
  1267.             return '';
  1268.         }
  1269.         return $category['name'];
  1270.     }
  1271.     public function getCategoryIdsByCategories(array $categories)
  1272.     {
  1273.         if (empty($categories)) {
  1274.             return [];
  1275.         }
  1276.         return array_column($categories'id');
  1277.     }
  1278.     public function chrFilter($index)
  1279.     {
  1280.         return chr($index);
  1281.     }
  1282.     public function isHideThread($id)
  1283.     {
  1284.         $need $this->createService('Group:ThreadService')->sumGoodsCoinsByThreadId($id);
  1285.         $thread $this->createService('Group:ThreadService')->getThread($id);
  1286.         $data explode('[/hide]'$thread['content']);
  1287.         foreach ($data as $key => $value) {
  1288.             $value ' '.$value;
  1289.             sscanf($value'%[^[][hide=reply]%[^$$]'$replyContent$replyHideContent);
  1290.             if ($replyHideContent) {
  1291.                 return true;
  1292.             }
  1293.         }
  1294.         if ($need) {
  1295.             return true;
  1296.         }
  1297.         return false;
  1298.     }
  1299.     public function bbCode2HtmlFilter($bbCode)
  1300.     {
  1301.         $ext $this;
  1302.         $bbCode preg_replace_callback(
  1303.             '/\[image\](.*?)\[\/image\]/i',
  1304.             function ($matches) use ($ext) {
  1305.                 $src $ext->getFileUrl($matches[1]);
  1306.                 return "<img src='{$src}' />";
  1307.             },
  1308.             $bbCode
  1309.         );
  1310.         $bbCode preg_replace_callback(
  1311.             '/\[audio.*?id="(\d+)"\](.*?)\[\/audio\]/i',
  1312.             function ($matches) {
  1313.                 return "<span class='audio-play-trigger' href='javascript:;' data-file-id=\"{$matches[1]}\" data-file-type=\"audio\"></span>";
  1314.             },
  1315.             $bbCode
  1316.         );
  1317.         return $bbCode;
  1318.     }
  1319.     public function scoreTextFilter($text)
  1320.     {
  1321.         $text number_format($text1'.''');
  1322.         if ((int) $text == $text) {
  1323.             return (string) (int) $text;
  1324.         }
  1325.         return $text;
  1326.     }
  1327.     public function simpleTemplateFilter($text$variables)
  1328.     {
  1329.         foreach ($variables as $key => $value) {
  1330.             $text str_replace('{{'.$key.'}}'$value$text);
  1331.         }
  1332.         return $text;
  1333.     }
  1334.     public function fillQuestionStemTextFilter($stem)
  1335.     {
  1336.         return preg_replace('/\[\[.+?\]\]+/''____'$stem);
  1337.     }
  1338.     public function fillQuestionStemHtmlFilter($stem)
  1339.     {
  1340.         $index 0;
  1341.         $stem preg_replace_callback(
  1342.             '/\[\[.+?\]\]+/',
  1343.             function ($matches) use (&$index) {
  1344.                 ++$index;
  1345.                 return "<span class='question-stem-fill-blank'>({$index})</span>";
  1346.             },
  1347.             $stem
  1348.         );
  1349.         return $stem;
  1350.     }
  1351.     public function getCourseidFilter($target)
  1352.     {
  1353.         $target explode('/'$target);
  1354.         $target explode('-'$target[0]);
  1355.         return $target[1];
  1356.     }
  1357.     public function getPurifyHtml($html$trusted false)
  1358.     {
  1359.         if (empty($html)) {
  1360.             return '';
  1361.         }
  1362.         $biz $this->container->get('biz');
  1363.         return $biz['html_helper']->purify($html$trusted);
  1364.     }
  1365.     public function atFilter($text$ats = [])
  1366.     {
  1367.         if (empty($ats) || !is_array($ats)) {
  1368.             return $text;
  1369.         }
  1370.         $router $this->container->get('router');
  1371.         foreach ($ats as $nickname => $userId) {
  1372.             $path $router->generate('user_show', ['id' => $userId]);
  1373.             $html "<a href=\"{$path}\" data-uid=\"{$userId}\" target=\"_blank\">@{$nickname}</a>";
  1374.             $text preg_replace("/@{$nickname}/ui"$html$text);
  1375.         }
  1376.         return $text;
  1377.     }
  1378.     public function removeCopyright($source)
  1379.     {
  1380.         if ($this->getSetting('copyright.owned'false)) {
  1381.             $source str_ireplace('edusoho'''$source);
  1382.         }
  1383.         return $source;
  1384.     }
  1385.     public function getSetting($name$default null)
  1386.     {
  1387.         $names explode('.'$name);
  1388.         $name array_shift($names);
  1389.         if (empty($name)) {
  1390.             return $default;
  1391.         }
  1392.         $value $this->createService('System:SettingService')->get($name);
  1393.         if (!isset($value)) {
  1394.             return $default;
  1395.         }
  1396.         if (empty($names)) {
  1397.             return $value;
  1398.         }
  1399.         $result $value;
  1400.         foreach ($names as $name) {
  1401.             if (!isset($result[$name])) {
  1402.                 return $default;
  1403.             }
  1404.             $result $result[$name];
  1405.         }
  1406.         return $result;
  1407.     }
  1408.     public function getOrderPayment($order$default null)
  1409.     {
  1410.         $coinSettings $this->createService('System:SettingService')->get('coin', []);
  1411.         if (!isset($coinSettings['price_type'])) {
  1412.             $coinSettings['price_type'] = 'RMB';
  1413.         }
  1414.         if (!isset($coinSettings['coin_enabled'])) {
  1415.             $coinSettings['coin_enabled'] = 0;
  1416.         }
  1417.         if (!= $coinSettings['coin_enabled'] || 'coin' != $coinSettings['price_type']) {
  1418.             if ($order['coinAmount'] > && == $order['amount']) {
  1419.                 $default '余额支付';
  1420.             } else {
  1421.                 $dictExtension $this->container->get('codeages_plugin.dict_twig_extension');
  1422.                 $default $dictExtension->getDictText('payment'$order['payment']);
  1423.             }
  1424.         }
  1425.         return $default;
  1426.     }
  1427.     public function isPermitRole($classroomId$permission$isStudentOrAuditor false)
  1428.     {
  1429.         $funcName 'can'.$permission.'Classroom';
  1430.         if ($isStudentOrAuditor) {
  1431.             return $this->createService('Classroom:ClassroomService')->$funcName($classroomId$isStudentOrAuditor);
  1432.         }
  1433.         return $this->createService('Classroom:ClassroomService')->$funcName($classroomId);
  1434.     }
  1435.     public function calculatePercent($number$total)
  1436.     {
  1437.         if (== $number || == $total) {
  1438.             return '0%';
  1439.         }
  1440.         if ($number >= $total) {
  1441.             return '100%';
  1442.         }
  1443.         return round($number $total 100).'%';
  1444.     }
  1445.     public function rateFormat($rate$precision 0)
  1446.     {
  1447.         return round($rate$precision);
  1448.     }
  1449.     public function arrayMerge($text$content)
  1450.     {
  1451.         return array_merge($text$content);
  1452.     }
  1453.     public function getSetPrice($price)
  1454.     {
  1455.         return NumberToolkit::roundUp($price);
  1456.     }
  1457.     public function getCategoryChoices($groupCode$isFilter false$indent ' ')
  1458.     {
  1459.         $builder = new CategoryBuilder();
  1460.         return $builder->buildChoices($groupCode$isFilter$indent);
  1461.     }
  1462.     public function getCategoryChoicesWithCategoryEmpty($groupName$isFilter false$indent ' ')
  1463.     {
  1464.         $builder = new CategoryBuilder();
  1465.         $choices $builder->buildChoices($groupName$isFilter$indent);
  1466.         $newChoices[-1] = '未分类';
  1467.         return $newChoices $choices;
  1468.     }
  1469.     public function getNextExecutedTime()
  1470.     {
  1471.         return $this->createService('Crontab:CrontabService')->getNextExcutedTime();
  1472.     }
  1473.     public function getUploadMaxFilesize($formated true)
  1474.     {
  1475.         $max FileToolkit::getMaxFilesize();
  1476.         if ($formated) {
  1477.             return FileToolkit::formatFileSize($max);
  1478.         }
  1479.         return $max;
  1480.     }
  1481.     public function isTrial()
  1482.     {
  1483.         if (file_exists($this->container->getParameter('kernel.root_dir').'/data/trial.lock')) {
  1484.             return true;
  1485.         }
  1486.         return false;
  1487.     }
  1488.     public function timestamp()
  1489.     {
  1490.         return time();
  1491.     }
  1492.     public function blurUserName($name)
  1493.     {
  1494.         return mb_substr($name01'UTF-8').'**';
  1495.     }
  1496.     public function blur_phone_number($phoneNum)
  1497.     {
  1498.         $head substr($phoneNum03);
  1499.         $tail substr($phoneNum, -44);
  1500.         return $head.'****'.$tail;
  1501.     }
  1502.     public function blur_idcard_number($idcardNum)
  1503.     {
  1504.         $head substr($idcardNum04);
  1505.         $tail substr($idcardNum, -22);
  1506.         return $head.'************'.$tail;
  1507.     }
  1508.     public function blur_number($string)
  1509.     {
  1510.         if (SimpleValidator::email($string)) {
  1511.             $head substr($string01);
  1512.             $tail substr($stringstrpos($string'@'));
  1513.             return $head.'***'.$tail;
  1514.         } elseif (SimpleValidator::mobile($string)) {
  1515.             $head substr($string03);
  1516.             $tail substr($string, -44);
  1517.             return $head.'****'.$tail;
  1518.         } elseif (SimpleValidator::bankCardId($string)) {
  1519.             $tail substr($string, -44);
  1520.             return '**** **** **** '.$tail;
  1521.         } elseif (SimpleValidator::idcard($string)) {
  1522.             $head substr($string04);
  1523.             $tail substr($string, -22);
  1524.             return $head.'************'.$tail;
  1525.         }
  1526.     }
  1527.     public function mathFormat($number$multiplicator)
  1528.     {
  1529.         $number *= $multiplicator;
  1530.         return $number;
  1531.     }
  1532.     protected function createService($alias)
  1533.     {
  1534.         return $this->biz->service($alias);
  1535.     }
  1536.     protected function getAppService()
  1537.     {
  1538.         return $this->createService('CloudPlatform:AppService');
  1539.     }
  1540.     public function getPurifyAndTrimHtml($html)
  1541.     {
  1542.         $html strip_tags($html'');
  1543.         return preg_replace("/(\s|\&nbsp\;| |\xc2\xa0)/"''$html);
  1544.     }
  1545.     public function arrayColumn($array$column)
  1546.     {
  1547.         return ArrayToolkit::column($array$column);
  1548.     }
  1549.     private function trans($key$parameters = [])
  1550.     {
  1551.         return $this->container->get('translator')->trans($key$parameters);
  1552.     }
  1553.     public function mb_trim($string$charlist '\\\\s'$ltrim true$rtrim true)
  1554.     {
  1555.         $bothEnds $ltrim && $rtrim;
  1556.         $charClassInner preg_replace(
  1557.             ['/[\^\-\]\\\]/S''/\\\{4}/S'],
  1558.             ['\\\\\\0''\\'],
  1559.             $charlist
  1560.         );
  1561.         $workHorse '['.$charClassInner.']+';
  1562.         $ltrim && $leftPattern '^'.$workHorse;
  1563.         $rtrim && $rightPattern $workHorse.'$';
  1564.         if ($bothEnds) {
  1565.             $patternMiddle $leftPattern.'|'.$rightPattern;
  1566.         } elseif ($ltrim) {
  1567.             $patternMiddle $leftPattern;
  1568.         } else {
  1569.             $patternMiddle $rightPattern;
  1570.         }
  1571.         return preg_replace("/$patternMiddle/usSD"''$string);
  1572.     }
  1573.     public function wrap($object$type)
  1574.     {
  1575.         return $this->container->get('web.wrapper')->handle($object$type);
  1576.     }
  1577.     public function convertAbsoluteUrl($html)
  1578.     {
  1579.         $html preg_replace_callback('/src=[\'\"]\/(.*?)[\'\"]/', function ($matches) {
  1580.             $cdn = new CdnUrl();
  1581.             $cdnUrl $cdn->get('content');
  1582.             if (!empty($cdnUrl)) {
  1583.                 $absoluteUrl AssetHelper::getScheme().':'.rtrim($cdnUrl'/').'/'.ltrim($matches[1], '/');
  1584.             } else {
  1585.                 $absoluteUrl AssetHelper::uriForPath('/'.ltrim($matches[1], '/'));
  1586.             }
  1587.             return "src=\"{$absoluteUrl}\"";
  1588.         }, $html);
  1589.         return $html;
  1590.     }
  1591.     public function getLoginEmailAddress($email)
  1592.     {
  1593.         $dress explode('@'$email);
  1594.         $dress strtolower($dress[1]);
  1595.         $emailAddressMap = [
  1596.             'gmail.com' => 'mail.google.com',
  1597.             'vip.qq.com' => 'mail.qq.com',
  1598.             'vip.163.com' => 'vip.163.com',
  1599.             'vip.sina.com' => 'mail.sina.com.cn',
  1600.             'foxmail.com' => 'mail.qq.com',
  1601.             'hotmail.com' => 'www.hotmail.com',
  1602.             '188.com' => 'www.188.com',
  1603.             '139.com' => 'mail.10086.cn',
  1604.             '126.com' => 'www.126.com',
  1605.             'yeah.net' => 'yeah.net',
  1606.         ];
  1607.         if (!empty($emailAddressMap[$dress])) {
  1608.             return 'http://'.$emailAddressMap[$dress];
  1609.         }
  1610.         return 'http://mail.'.$dress;
  1611.     }
  1612.     public function getCloudSdkUrl($type)
  1613.     {
  1614.         return $this->getResourceFacadeService()->getFrontPlaySDKPathByType($type);
  1615.     }
  1616.     public function isWechatLoginBind()
  1617.     {
  1618.         $wechat $this->isMicroMessenger();
  1619.         $loginBind $this->getSetting('login_bind');
  1620.         return $wechat && !empty($loginBind['enabled']) && !empty($loginBind['weixinmob_enabled']);
  1621.     }
  1622.     public function makeLocalMediaFileToken($file)
  1623.     {
  1624.         $token $this->makeToken('local.media'$file['id']);
  1625.         return $token['token'];
  1626.     }
  1627.     /**
  1628.      * 获取在线咨询授权信息
  1629.      *
  1630.      * @return array
  1631.      */
  1632.     public function onlineAdvisoryAuthInfo()
  1633.     {
  1634.         $info = [
  1635.             'isCustom' => 'none',
  1636.         ];
  1637.         try {
  1638.             $api CloudAPIFactory::create('root');
  1639.             $info $api->get('/me');
  1640.             $displayLevel = ['personal''basic''medium''advanced''gold''custom'];
  1641.             if (is_array($info) && isset($info['level']) && in_array($info['level'], $displayLevel)) {
  1642.                 $info['isCustom'] = ('custom' == $info['level']) ? '是' '否';
  1643.             } else {
  1644.                 $info['isCustom'] = 'none';
  1645.             }
  1646.         } catch (\RuntimeException $e) {
  1647.         }
  1648.         return $info;
  1649.     }
  1650.     public function getSyncModeDict()
  1651.     {
  1652.         $dict = [
  1653.             'closed' => $this->trans('admin.sync-account-docking.btn.closed_btn'),
  1654.             'dingtalk' => $this->trans('admin.sync-account-docking.btn.dingtalk_btn'),
  1655.         ];
  1656.         if ($this->isPluginInstalled('WorkWechat')) {
  1657.             $dict['work_wechat'] = $this->trans('admin.sync-account-docking.btn.work_wechat_btn');
  1658.         }
  1659.         if ($this->isPluginInstalled('FeiShu')) {
  1660.             $dict['feishu'] = $this->trans('admin.sync-account-docking.btn.feishu_btn');
  1661.         }
  1662.         if ($this->isPluginInstalled('LDAP')) {
  1663.             $dict['LDAP'] = 'LDAP';
  1664.         }
  1665.         return $dict;
  1666.     }
  1667.     protected function makeToken($type$fileId$context = [])
  1668.     {
  1669.         $times = ('local.media' == $type) ? 100 10;
  1670.         $duration = ('local.media' == $type) ? 7200 3600;
  1671.         $fields = [
  1672.             'data' => [
  1673.                 'id' => $fileId,
  1674.             ],
  1675.             'times' => $times,
  1676.             'duration' => $duration,
  1677.             'userId' => $this->biz['user']['id'],
  1678.         ];
  1679.         if (isset($context['watchTimeLimit'])) {
  1680.             $fields['data']['watchTimeLimit'] = $context['watchTimeLimit'];
  1681.         }
  1682.         if (isset($context['hideBeginning'])) {
  1683.             $fields['data']['hideBeginning'] = $context['hideBeginning'];
  1684.         }
  1685.         return $this->getTokenService()->makeToken($type$fields);
  1686.     }
  1687.     public function isHiddenVideoHeader($isHidden false)
  1688.     {
  1689.         $storage $this->getSetting('storage');
  1690.         if (!empty($storage) && array_key_exists('video_header'$storage) && $storage['video_header'] && !$isHidden) {
  1691.             return false;
  1692.         }
  1693.         return true;
  1694.     }
  1695.     public function canSendMessage($userId)
  1696.     {
  1697.         $user $this->biz['user'];
  1698.         if (!$user->isLogin()) {
  1699.             return false;
  1700.         }
  1701.         if (in_array('ROLE_ADMIN'$user['roles']) || $user->isSuperAdmin()) {
  1702.             return true;
  1703.         }
  1704.         $toUser $this->getUserService()->getUser($userId);
  1705.         if ($user['id'] == $toUser['id']) {
  1706.             return false;
  1707.         }
  1708.         if (in_array('ROLE_ADMIN'$toUser['roles']) || in_array('ROLE_SUPER_ADMIN'$toUser['roles'])) {
  1709.             return true;
  1710.         }
  1711.         $messageSetting $this->getSetting('message', []);
  1712.         if (empty($messageSetting['teacherToStudent']) && $this->isTeacher($user['roles']) && $this->isOnlyStudent($toUser['roles'])) {
  1713.             return false;
  1714.         }
  1715.         if (empty($messageSetting['studentToStudent']) && $this->isOnlyStudent($user['roles']) && $this->isOnlyStudent($toUser['roles'])) {
  1716.             return false;
  1717.         }
  1718.         if (empty($messageSetting['studentToTeacher']) && $this->isOnlyStudent($user['roles']) && $this->isTeacher($toUser['roles'])) {
  1719.             return false;
  1720.         }
  1721.         return true;
  1722.     }
  1723.     public function daysOfWeek($day)
  1724.     {
  1725.         $weekName = ['日''一''二''三''四''五''六'];
  1726.         if (isset($weekName[$day])) {
  1727.             return $weekName[$day];
  1728.         }
  1729.         return false;
  1730.     }
  1731.     public function filterArrayKeys($array$keys)
  1732.     {
  1733.         foreach ($keys as $key) {
  1734.             unset($array[$key]);
  1735.         }
  1736.         return $array;
  1737.     }
  1738.     public function examScore($score)
  1739.     {
  1740.         return $score $score 0;
  1741.     }
  1742.     public function formatLearnTime($learnTime)
  1743.     {
  1744.         if ($learnTime 3600) {
  1745.             return round($learnTime 60).$this->trans('site.data.minute');
  1746.         }
  1747.         return round($learnTime 36001).$this->trans('site.date.hour');
  1748.     }
  1749.     public function groupBy($array$key)
  1750.     {
  1751.         return ArrayToolkit::group($array$key);
  1752.     }
  1753.     private function isTeacher($roles)
  1754.     {
  1755.         return in_array('ROLE_TEACHER'$roles);
  1756.     }
  1757.     private function isOnlyStudent($roles)
  1758.     {
  1759.         return in_array('ROLE_USER'$roles) && !in_array('ROLE_TEACHER'$roles) && !in_array('ROLE_ADMIN'$roles) && !in_array('ROLE_SUPER_ADMIN'$roles);
  1760.     }
  1761.     public function arraysKeyConvert($arrays$beforeKey$afterKey)
  1762.     {
  1763.         foreach ($arrays as $key => $value) {
  1764.             if ($value == $beforeKey) {
  1765.                 $arrays[$key][$afterKey] = $arrays[$key][$beforeKey];
  1766.                 unset($arrays[$key][$beforeKey]);
  1767.             }
  1768.         }
  1769.         return $arrays;
  1770.     }
  1771.     public function questionHtmlFilter($html$allowed '')
  1772.     {
  1773.         if (!isset($html)) {
  1774.             return '';
  1775.         }
  1776.         $html preg_replace('/(<img .*?src=")(.*?)(".*?>)/is''[图片]'$html);
  1777.         $security $this->getSettingService()->get('security');
  1778.         if (!empty($security['safe_iframe_domains'])) {
  1779.             $safeDomains $security['safe_iframe_domains'];
  1780.         } else {
  1781.             $safeDomains = [];
  1782.         }
  1783.         $config = [
  1784.             'cacheDir' => $this->biz['cache_directory'].'/htmlpurifier',
  1785.             'safeIframeDomains' => $safeDomains,
  1786.         ];
  1787.         $this->warmUp($config['cacheDir']);
  1788.         $htmlConfig = \HTMLPurifier_Config::createDefault();
  1789.         $htmlConfig->set('Cache.SerializerPath'$config['cacheDir']);
  1790.         $htmlConfig->set('HTML.Allowed'$allowed);
  1791.         $htmlpurifier = new \HTMLPurifier($htmlConfig);
  1792.         return $htmlpurifier->purify($html);
  1793.     }
  1794.     public function uniqid()
  1795.     {
  1796.         return MathToolkit::uniqid();
  1797.     }
  1798.     public function canOperateQuestion($user$question)
  1799.     {
  1800.         $currentUser $this->biz['user'];
  1801.         if ($currentUser->hasPermission('admin_question_gather_manage')) {
  1802.             return true;
  1803.         }
  1804.         if (in_array('ROLE_SUPER_ADMIN'$user['roles'])) {
  1805.             return true;
  1806.         }
  1807.         if (in_array('ROLE_TRAINING_ADMIN'$user['roles']) && $question['createdUserId'] === $user['id']) {
  1808.             return true;
  1809.         }
  1810.         return false;
  1811.     }
  1812.     public function showFeedbackBar($route)
  1813.     {
  1814.         if (in_array($route, [
  1815.             'course_teacher_evaluate_list',
  1816.             'project_plan_create',
  1817.             'project_plan_offline_course_homework_list',
  1818.             'survey_result_statistics',
  1819.         ])) {
  1820.             return true;
  1821.         }
  1822.         $allowedRoutes = [
  1823.             'course_set_manage',
  1824.             'course_manage',
  1825.             'classroom_manage',
  1826.             'offline_course_manage',
  1827.             'project_plan_study_data',
  1828.             'questionnaire_manage',
  1829.             'offline_activity_manage',
  1830.             'project_plan',
  1831.             'survey',
  1832.             'admin',
  1833.         ];
  1834.         foreach ($allowedRoutes as $allowedRoute) {
  1835.             if (!== stripos($route$allowedRoute)) {
  1836.                 continue;
  1837.             }
  1838.             if (!in_array($allowedRoute, ['project_plan''survey'])) {
  1839.                 return true;
  1840.             }
  1841.             if (false !== stripos($route'manage')) {
  1842.                 return true;
  1843.             }
  1844.         }
  1845.         if (false !== stripos($route'verify_list')) {
  1846.             return true;
  1847.         }
  1848.         return false;
  1849.     }
  1850.     public function isSaaS()
  1851.     {
  1852.         if ($this->isWithoutNetwork()) {
  1853.             return false;
  1854.         }
  1855.         $site $this->getSetting('site');
  1856.         if (empty($site['level']) || ($site['levelExpired'] ?? 0) < time()) {
  1857.             try {
  1858.                 $api CloudAPIFactory::create('root');
  1859.                 $info $api->get('/me');
  1860.             } catch (\RuntimeException $e) {
  1861.                 $info = [];
  1862.             }
  1863.             $site['level'] = $info['level'] ?? '';
  1864.             $site['levelExpired'] = time() + 7200;
  1865.             $this->getSettingService()->set('site'$site);
  1866.         }
  1867.         return in_array($this->getSetting('site.level'), $this->getSaaSLevels());
  1868.     }
  1869.     public function getSaaSLevels()
  1870.     {
  1871.         return CloudSchoolLevelConstant::SAAS_LEVELS;
  1872.     }
  1873.     public function getRememberMeDeadlineRangeText()
  1874.     {
  1875.         $rememberMeLifetime LoginToolkit::getRememberMeLifetime();
  1876.         if ($rememberMeLifetime 60 60) {
  1877.             return (int) ($rememberMeLifetime 60).$this->trans('site.data.minute');
  1878.         }
  1879.         if ($rememberMeLifetime 24 60 60) {
  1880.             return (int) ($rememberMeLifetime / (60 60)).$this->trans('site.date.hour');
  1881.         }
  1882.         return (int) ($rememberMeLifetime / (24 60 60)).$this->trans('site.date.day');
  1883.     }
  1884.     protected function warmUp($cacheDir)
  1885.     {
  1886.         if (!@mkdir($cacheDir0777true) && !is_dir($cacheDir)) {
  1887.             throw new ServiceException('mkdir cache dir error');
  1888.         }
  1889.         if (!is_writable($cacheDir)) {
  1890.             chmod($cacheDir0777);
  1891.         }
  1892.     }
  1893.     public function isQuestionAnswered($id)
  1894.     {
  1895.         $question $this->getQuestionService()->get($id);
  1896.         if (empty($question)) {
  1897.             return 0;
  1898.         }
  1899.         $count $this->getTestpaperService()->countItemResults(['questionId' => $question['id']]);
  1900.         if ($count) {
  1901.             return 1;
  1902.         }
  1903.         if ($this->isPluginInstalled('Exam')) {
  1904.             $count $this->getExamPluginTestPaperService()->countTestPaperItemResults(['questionId' => $question['id']]);
  1905.             if ($count) {
  1906.                 return 1;
  1907.             }
  1908.         }
  1909.         return 0;
  1910.     }
  1911.     public function isEnabledLms()
  1912.     {
  1913.         return $this->getLmsService()->isEnabledLms();
  1914.     }
  1915.     public function isLmsVersionSupported($version)
  1916.     {
  1917.         return $this->getLmsService()->isLmsVersionSupported($version);
  1918.     }
  1919.     public function mainRequestRoute()
  1920.     {
  1921.         return $this->container->get('request_stack')->getMainRequest()->attributes->get('_route');
  1922.     }
  1923.     public function hasLiveTasks($courseId)
  1924.     {
  1925.         $tasks $this->getTaskService()->findTasksByCourseId($courseId);
  1926.         $hasLiveTasks ArrayToolkit::some($tasks, function ($task) {
  1927.             return 'live' === $task['type'];
  1928.         });
  1929.         return $hasLiveTasks;
  1930.     }
  1931.     /**
  1932.      * @return LmsService
  1933.      */
  1934.     protected function getLmsService()
  1935.     {
  1936.         return $this->createService('Lms:LmsService');
  1937.     }
  1938.     protected function getSettingService()
  1939.     {
  1940.         return $this->biz->service('System:SettingService');
  1941.     }
  1942.     /**
  1943.      * @return ResourceFacadeService
  1944.      */
  1945.     protected function getResourceFacadeService()
  1946.     {
  1947.         return $this->createService('CloudPlatform:ResourceFacadeService');
  1948.     }
  1949.     /**
  1950.      * @return TagService
  1951.      */
  1952.     protected function getTagService()
  1953.     {
  1954.         return $this->createService('Taxonomy:TagService');
  1955.     }
  1956.     /**
  1957.      * @return TokenService
  1958.      */
  1959.     protected function getTokenService()
  1960.     {
  1961.         return $this->createService('User:TokenService');
  1962.     }
  1963.     /**
  1964.      * @return mixed
  1965.      */
  1966.     public function getCategoryService()
  1967.     {
  1968.         return $this->createService('Taxonomy:CategoryService');
  1969.     }
  1970.     /**
  1971.      * @return ReviewCenterService
  1972.      */
  1973.     protected function getReviewCenterService()
  1974.     {
  1975.         return $this->createService('ReviewCenter:ReviewCenterService');
  1976.     }
  1977.     protected function getQuestionService()
  1978.     {
  1979.         return $this->createService('Question:QuestionService');
  1980.     }
  1981.     protected function getTestpaperService()
  1982.     {
  1983.         return $this->createService('Testpaper:TestpaperService');
  1984.     }
  1985.     protected function getExamPluginTestPaperService()
  1986.     {
  1987.         return $this->createService('ExamPlugin:TestPaper:TestPaperService');
  1988.     }
  1989.     /**
  1990.      * @return TaskService
  1991.      */
  1992.     protected function getTaskService()
  1993.     {
  1994.         return $this->createService('Task:TaskService');
  1995.     }
  1996. }