src/AppBundle/Controller/OpenCourseController.php line 156

Open in your IDE?
  1. <?php
  2. namespace AppBundle\Controller;
  3. use AppBundle\Common\ArrayToolkit;
  4. use AppBundle\Common\Paginator;
  5. use AppBundle\Component\MediaParser\ParserProxy;
  6. use Biz\Course\MaterialException;
  7. use Biz\Course\Service\CourseService;
  8. use Biz\Course\Service\CourseSetService;
  9. use Biz\Course\Service\MaterialService;
  10. use Biz\Favorite\Service\FavoriteService;
  11. use Biz\File\Service\UploadFileService;
  12. use Biz\Goods\Service\GoodsService;
  13. use Biz\OpenCourse\OpenCourseException;
  14. use Biz\OpenCourse\Service\OpenCourseRecommendedService;
  15. use Biz\System\Service\SettingService;
  16. use Biz\Taxonomy\Service\TagService;
  17. use Biz\Thread\Service\ThreadService;
  18. use Biz\User\Service\AuthService;
  19. use Biz\User\Service\TokenService;
  20. use Biz\User\Service\UserService;
  21. use Biz\User\UserException;
  22. use Symfony\Component\HttpFoundation\Cookie;
  23. use Symfony\Component\HttpFoundation\Request;
  24. use Symfony\Component\HttpFoundation\Response;
  25. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  26. class OpenCourseController extends BaseOpenCourseController
  27. {
  28.     public function createAction(Request $request)
  29.     {
  30.         $course $request->request->all();
  31.         unset($course['buyable']);
  32.         $course $this->getOpenCourseService()->createCourse($course);
  33.         return $this->redirect($this->generateUrl('open_course_manage', ['id' => $course['id']]));
  34.     }
  35.     public function showAction(Request $request$courseId$lessonId)
  36.     {
  37.         $course $this->getOpenCourseService()->getCourse($courseId);
  38.         $preview $request->query->get('as');
  39.         $isWxPreview 'preview' === $request->query->get('as') && 'wx' === $request->query->get('previewType');
  40.         $tags $this->getTagService()->findTagsByOwner(['ownerType' => 'openCourse''ownerId' => $courseId]);
  41.         $tagIds ArrayToolkit::column($tags'id');
  42.         if ($isWxPreview || $this->isWxClient()) {
  43.             $template 'open-course/mobile/open-course-show.html.twig';
  44.         } else {
  45.             $template 'open-course/open-course-show.html.twig';
  46.         }
  47.         if ('preview' === $preview) {
  48.             $this->getOpenCourseService()->tryManageOpenCourse($courseId);
  49.             return $this->render($template, [
  50.                 'tagIds' => $tagIds,
  51.                 'course' => $course,
  52.                 'lessonId' => $lessonId,
  53.                 'wxPreviewUrl' => $this->getWxPreviewQrCodeUrl($course['id']),
  54.             ]);
  55.         }
  56.         $result $this->_checkCourseStatus($courseId);
  57.         if (!$result['status']) {
  58.             return $this->createMessageResponse('error'$result['message']);
  59.         }
  60.         $this->_memberOperate($request$courseId);
  61.         $course $this->getOpenCourseService()->waveCourse($courseId'hitNum', +1);
  62.         $response $this->renderView($template, [
  63.             'tagIds' => $tagIds,
  64.             'course' => $course,
  65.             'lessonId' => $lessonId,
  66.         ]);
  67.         $response = new Response($response);
  68.         if (!$request->cookies->get('uv')) {
  69.             $expire strtotime(date('Y-m-d').' 23:59:59');
  70.             $response->headers->setCookie(new Cookie('uv'uniqid($prefix 'refererToken'), $expire));
  71.             //$response->send();
  72.         }
  73.         if ('liveOpen' != $course['type']) {
  74.             $this->createRefererLog($request$course);
  75.         }
  76.         return $response;
  77.     }
  78.     public function lessonShowAction(Request $request$courseId$lessonId)
  79.     {
  80.         $lesson $this->getOpenCourseService()->getLesson($lessonId);
  81.         if (!$lesson) {
  82.             return $this->createMessageResponse('error''该课时不存在!');
  83.         }
  84.         if ($lesson['mediaId'] && 'self' == $lesson['mediaSource']) {
  85.             $file $this->getUploadFileService()->getFile($lesson['mediaId']);
  86.             if (!$file) {
  87.                 return $this->createJsonResponse(['mediaError' => '该课时为无效课时,不能播放']);
  88.             }
  89.         } elseif (== $lesson['mediaId'] && 'self' == $lesson['mediaSource']) {
  90.             return $this->createJsonResponse(['mediaError' => '该课时为无效课时,不能播放']);
  91.         }
  92.         $lesson $this->_getLessonVedioInfo($request$lesson);
  93.         return $this->createJsonResponse($lesson);
  94.     }
  95.     /**
  96.      * Block Actions.
  97.      */
  98.     public function headerAction(Request $request$course$lessonId)
  99.     {
  100.         $isWxPreview 'preview' === $request->query->get('as') && 'wx' === $request->query->get('previewType');
  101.         if ($isWxPreview || $this->isWxClient()) {
  102.             $template 'open-course/mobile/open-course-header.html.twig';
  103.         } else {
  104.             $template 'open-course/open-course-header.html.twig';
  105.         }
  106.         if ($lessonId) {
  107.             $lesson $this->getOpenCourseService()->getCourseLesson($course['id'], $lessonId);
  108.             if (!$lesson || ('preview' !== $request->query->get('as') && 'published' != $lesson['status'])) {
  109.                 $lesson = [];
  110.             }
  111.         } else {
  112.             $lesson $this->_checkPublishedLessonExists($course['id']);
  113.         }
  114.         $lesson $lesson $this->_getLessonVedioInfo($request$lesson) : [];
  115.         //$nextLesson = $this->getOpenCourseService()->getNextLesson($course['id'], $lesson['id']);
  116.         $member $this->_getMember($course['id']);
  117.         if ($lesson) {
  118.             $lesson['replays'] = $this->_getLiveReplay($lesson);
  119.         }
  120.         $notifyNum $this->getOpenCourseService()->countMembers(['courseId' => $course['id'], 'isNotified' => 1]);
  121.         return $this->render($template, [
  122.             'course' => $course,
  123.             'lesson' => $lesson,
  124.             'member' => $member,
  125.             'notifyNum' => $notifyNum,
  126.             // 'nextLesson' => $nextLesson
  127.         ]);
  128.     }
  129.     public function teachersAction($courseId)
  130.     {
  131.         $course $this->getOpenCourseService()->getCourse($courseId);
  132.         $teachersNoSort $this->getUserService()->findUsersByIds($course['teacherIds']);
  133.         $teachers = [];
  134.         if (!empty($course['teacherIds'][0])) {
  135.             foreach ($course['teacherIds'] as $key => $teacherId) {
  136.                 $teachers[$teacherId] = $teachersNoSort[$teacherId];
  137.             }
  138.         }
  139.         $profiles $this->getUserService()->findUserProfilesByIds($course['teacherIds']);
  140.         return $this->render('open-course/open-course-teacher-block.html.twig', [
  141.             'course' => $course,
  142.             'teachers' => $teachers,
  143.             'profiles' => $profiles,
  144.         ]);
  145.     }
  146.     public function infoBarAction(Request $request$courseId$lessonId)
  147.     {
  148.         $course $this->getOpenCourseService()->getCourse($courseId);
  149.         $lesson = empty($lessonId) ? [] : $this->getOpenCourseService()->getCourseLesson($courseId$lessonId);
  150.         $member $this->_getMember($course['id']);
  151.         $memberFavorite $this->getFavoriteService()->getUserFavorite($this->getCurrentUser()->getId(), 'openCourse'$courseId);
  152.         return $this->render('open-course/info-bar-block.html.twig', [
  153.             'course' => $course,
  154.             'member' => $member,
  155.             'memberFavorite' => $memberFavorite,
  156.             'lesson' => $lesson,
  157.         ]);
  158.     }
  159.     public function likeAction(Request $request$id)
  160.     {
  161.         $result $this->_checkCourseStatus($id);
  162.         if (!$result['status']) {
  163.             return $this->createJsonResponse(['result' => false]);
  164.         }
  165.         $course $this->getOpenCourseService()->waveCourse($id'likeNum', +1);
  166.         return $this->createJsonResponse(['result' => true'number' => $course['likeNum']]);
  167.     }
  168.     public function unlikeAction(Request $request$id)
  169.     {
  170.         $result $this->_checkCourseStatus($id);
  171.         if (!$result['status']) {
  172.             return $this->createJsonResponse(['result' => false]);
  173.         }
  174.         $course $this->getOpenCourseService()->waveCourse($id'likeNum', -1);
  175.         return $this->createJsonResponse(['result' => true'number' => $course['likeNum']]);
  176.     }
  177.     protected function getWxPreviewQrCodeUrl($id)
  178.     {
  179.         $user $this->getUserService()->getCurrentUser();
  180.         $token $this->getTokenService()->makeToken('qrcode', [
  181.             'userId' => $user['id'],
  182.             'data' => [
  183.                 'url' => $this->generateUrl(
  184.                     'open_course_show',
  185.                     [
  186.                         'courseId' => $id,
  187.                         'as' => 'preview',
  188.                     ],
  189.                     UrlGeneratorInterface::ABSOLUTE_URL),
  190.                 'appUrl' => '',
  191.             ],
  192.             'times' => 0,
  193.             'duration' => 3600,
  194.         ]);
  195.         $url $this->generateUrl('common_parse_qrcode', ['token' => $token['token']], UrlGeneratorInterface::ABSOLUTE_URL);
  196.         return $url;
  197.     }
  198.     public function commentAction(Request $request$courseId)
  199.     {
  200.         $course $this->getOpenCourseService()->getCourse($courseId);
  201.         if (!$course) {
  202.             return $this->createMessageResponse('error''课程不存在,或未发布。');
  203.         }
  204.         $conditions = [
  205.             'targetId' => $course['id'],
  206.             'targetType' => 'openCourse',
  207.             'parentId' => 0,
  208.             'excludeAuditStatus' => 'illegal',
  209.         ];
  210.         $paginator = new Paginator(
  211.             $request,
  212.             $this->getThreadService()->searchPostsCount($conditions),
  213.             10
  214.         );
  215.         $posts $this->getThreadService()->searchPosts(
  216.             $conditions,
  217.             ['createdTime' => 'ASC'],
  218.             $paginator->getOffsetCount(),
  219.             $paginator->getPerPageCount()
  220.         );
  221.         $users $this->getUserService()->findUsersByIds(ArrayToolkit::column($posts'userId'));
  222.         $isWxPreview 'preview' === $request->query->get('as') && 'wx' === $request->query->get('previewType');
  223.         if ($isWxPreview || $this->isWxClient()) {
  224.             $template 'open-course/mobile/open-course-comment.html.twig';
  225.         } else {
  226.             $template 'open-course/open-course-comment.html.twig';
  227.         }
  228.         return $this->render($template, [
  229.             'course' => $course,
  230.             'posts' => $posts,
  231.             'users' => $users,
  232.             'paginator' => $paginator,
  233.             'service' => $this->getThreadService(),
  234.             'goto' => $this->generateUrl('open_course_show', ['courseId' => $course['id']]),
  235.         ]);
  236.     }
  237.     public function postAction(Request $request$id)
  238.     {
  239.         $result $this->_checkCourseStatus($id);
  240.         if (!$result['status']) {
  241.             return $this->createMessageResponse('error'$result['message']);
  242.         }
  243.         return $this->forward('AppBundle:Thread:postSave', [
  244.             'request' => $request,
  245.             'targetType' => 'openCourse',
  246.             'targetId' => $id,
  247.         ]);
  248.     }
  249.     public function postReplyAction(Request $request$id$postId)
  250.     {
  251.         $result $this->_checkCourseStatus($id);
  252.         if (!$result['status']) {
  253.             return $this->createMessageResponse('error'$result['message']);
  254.         }
  255.         $fields $request->request->all();
  256.         if(!$this->checkDragCaptchaToken($request$fields['_dragCaptchaToken'])){
  257.             return $this->createJsonResponse(['error' => ['code'=> 403'message' => $this->trans("exception.form..drag.expire")]], 403);
  258.         }
  259.         unset($fields['_dragCaptchaToken']);
  260.             
  261.         $fields['content'] = $this->autoParagraph($fields['content']);
  262.         $fields['targetId'] = $id;
  263.         $fields['parentId'] = $postId;
  264.         $fields['targetType'] = 'openCourse';
  265.         $post $this->getThreadService()->createPost($fields);
  266.         return $this->render('thread/subpost-item.html.twig', [
  267.             'post' => $post,
  268.             'author' => $this->getCurrentUser(),
  269.             'service' => $this->getThreadService(),
  270.         ]);
  271.     }
  272.     public function memberSmsAction(Request $request$id)
  273.     {
  274.         $course $this->getOpenCourseService()->getCourse($id);
  275.         $user $this->getCurrentUser();
  276.         if (!$course) {
  277.             return $this->createJsonResponse(['result' => false'message' => '该课程不存在或已删除!']);
  278.         }
  279.         $smsSetting $this->setting('cloud_sms', []);
  280.         if (!$user->isLogin() && !$smsSetting['sms_enabled']) {
  281.             $this->createNewException(UserException::PERMISSION_DENIED());
  282.         }
  283.         if ('POST' == $request->getMethod()) {
  284.             $member $this->_memberOperate($request$id);
  285.             $fields $request->request->all();
  286.             $fields['isNotified'] = 1;
  287.             $member $this->getOpenCourseService()->updateMember($member['id'], $fields);
  288.             $this->_loginMemberMobileBind($fields['mobile']);
  289.             $memberNum $this->getOpenCourseService()->countMembers(['courseId' => $id'isNotified' => 1]);
  290.             return $this->createJsonResponse(['result' => true'number' => $memberNum]);
  291.         }
  292.         return $this->render('open-course/member-sms-modal.html.twig', [
  293.             'course' => $course,
  294.         ]);
  295.     }
  296.     public function createMemberAction(Request $request$id)
  297.     {
  298.         $result $this->_checkExistsMember($request$id);
  299.         if (!$result['result']) {
  300.             return $this->createJsonResponse($result);
  301.         }
  302.         if ('POST' == $request->getMethod()) {
  303.             $fields $request->request->all();
  304.             $fields['ip'] = $request->getClientIp();
  305.             $fields['courseId'] = $id;
  306.             $member $this->getOpenCourseService()->createMember($fields);
  307.             $memberNum $this->getOpenCourseService()->countMembers(['courseId' => $id]);
  308.             return $this->createJsonResponse(['result' => true'number' => $memberNum]);
  309.         }
  310.     }
  311.     public function playerAction(Request $request$courseId$lessonId)
  312.     {
  313.         $lesson $this->getOpenCourseService()->getCourseLesson($courseId$lessonId);
  314.         if (empty($lesson)) {
  315.             $this->createNewException(OpenCourseException::NOTFOUND_LESSON());
  316.         }
  317.         if ('liveOpen' == $lesson['type'] && 'videoGenerated' == $lesson['replayStatus']) {
  318.             if (empty($lesson['replayEnable'])) {
  319.                 return $this->createMessageResponse('error''直播回放被设置为不允许观看!');
  320.             }
  321.             $course $this->getOpenCourseService()->getCourse($courseId);
  322.             $this->createRefererLog($request$course);
  323.         }
  324.         return $this->forward('AppBundle:Player:show', [
  325.             'id' => $lesson['mediaId'],
  326.             'context' => ['hideBeginning' => 1'hideQuestion' => 1],
  327.         ]);
  328.     }
  329.     public function materialListAction(Request $request$id)
  330.     {
  331.         $course $this->getOpenCourseService()->getCourse($id);
  332.         $conditions = [
  333.             'courseId' => $id,
  334.             'excludeLessonId' => 0,
  335.             'source' => 'opencoursematerial',
  336.             'type' => 'openCourse',
  337.         ];
  338.         $materials $this->getMaterialService()->searchMaterials(
  339.             $conditions,
  340.             ['createdTime' => 'DESC'],
  341.             0,
  342.             PHP_INT_MAX
  343.         );
  344.         $lessons $this->getOpenCourseService()->findLessonsByCourseId($course['id']);
  345.         $lessons ArrayToolkit::index($lessons'id');
  346.         return $this->render('open-course/open-course-material-block.html.twig', [
  347.             'course' => $course,
  348.             'lessons' => $lessons,
  349.             'materials' => $materials,
  350.         ]);
  351.     }
  352.     public function materialDownloadAction(Request $request$courseId$materialId)
  353.     {
  354.         $course $this->getOpenCourseService()->getCourse($courseId);
  355.         $material $this->getMaterialService()->getMaterial($courseId$materialId);
  356.         if (empty($material)) {
  357.             $this->createNewException(MaterialException::NOTFOUND_MATERIAL());
  358.         }
  359.         if ('opencourselesson' == $material['source'] || !$material['lessonId']) {
  360.             return $this->createMessageResponse('error''无权下载该资料');
  361.         }
  362.         return $this->forward('AppBundle:UploadFile:download', ['fileId' => $material['fileId']]);
  363.     }
  364.     public function mobileCheckAction(Request $request$courseId)
  365.     {
  366.         $user $this->getCurrentUser();
  367.         $response = ['success' => true'message' => ''];
  368.         $mobile $request->query->get('value''');
  369.         $member $this->getOpenCourseService()->getCourseMemberByMobile($courseId$mobile);
  370.         if ($member && $member['isNotified']) {
  371.             return $this->createJsonResponse(['success' => false'message' => '该手机号已报名']);
  372.         }
  373.         if ($user->isLogin()) {
  374.             list($result$message) = $this->getAuthService()->checkMobile($mobile);
  375.             if ('success' != $result) {
  376.                 return $this->createJsonResponse(['success' => false'message' => $message]);
  377.             }
  378.         }
  379.         return $this->createJsonResponse($response);
  380.     }
  381.     public function adModalRecommendCourseAction(Request $request$id)
  382.     {
  383.         $num $request->query->get('num'3);
  384.         $goodses $this->getOpenCourseRecommendedService()->findRandomRecommendGoods($id$num);
  385.         $goodses array_values($goodses);
  386.         $conditions = [
  387.             [
  388.                 'status' => 'published',
  389.                 'recommendedTime_GT' => 0,
  390.             ],
  391.             [
  392.                 'status' => 'published',
  393.             ],
  394.         ];
  395.         $orderBys = [
  396.             [
  397.                 'recommendWeight' => 'ASC',
  398.                 'recommendedTime' => 'DESC',
  399.             ],
  400.             [],
  401.         ];
  402.         //数量不够 凑数
  403.         foreach ($conditions as $key => $condition) {
  404.             if (count($goodses) < $num) {
  405.                 $needNum $num count($goodses);
  406.                 $condition['excludeIds'] = ArrayToolkit::column($goodses'id');
  407.                 $newGoodses $this->getGoodsService()->searchGoods($condition$orderBys[$key], 0$needNum);
  408.                 $goodses array_merge($goodses$newGoodses);
  409.             }
  410.         }
  411.         $self $this;
  412.         $goodses array_map(function ($goods) use ($self) {
  413.             foreach (['small''middle''large'] as $coverType) {
  414.                 $picturePath = empty($goods['images'][$coverType]) ? '' $goods['images'][$coverType];
  415.                 $goods['cover'][$coverType] = $self->get('web.twig.extension')->getFpath($picturePath'course.png');
  416.             }
  417.             return $goods;
  418.         }, $goodses);
  419.         return $this->createJsonResponse($goodses);
  420.     }
  421.     private function _getMember($courseId)
  422.     {
  423.         $user $this->getCurrentUser();
  424.         $member = [];
  425.         if ($user->isLogin()) {
  426.             $member $this->getOpenCourseService()->getCourseMember($courseId$user['id']);
  427.         } /* else {
  428.         $member = $this->getOpenCourseService()->getCourseMemberByIp($courseId, $user['currentIp']);
  429.         }*/
  430.         return $member;
  431.     }
  432.     private function _getLessonVedioInfo(Request $request$lesson)
  433.     {
  434.         $lesson['videoWatermarkEmbedded'] = 0;
  435.         if (('video' == $lesson['type'] || ('liveOpen' == $lesson['type'] && 'videoGenerated' == $lesson['replayStatus'])) && 'self' == $lesson['mediaSource']) {
  436.             $file $this->getUploadFileService()->getFullFile($lesson['mediaId']);
  437.             if ($file) {
  438.                 $lesson['convertStatus'] = empty($file['convertStatus']) ? 'none' $file['convertStatus'];
  439.                 $lesson['storage'] = $file['storage'];
  440.             }
  441.         } elseif (in_array($lesson['mediaSource'], ['youku''NeteaseOpenCourse''qqvideo'])) {
  442.             $proxy = new ParserProxy();
  443.             $lesson $proxy->prepareMediaUri($lesson);
  444.         }
  445.         if ('liveOpen' == $lesson['type']) {
  446.             if ($lesson['startTime'] > time()) {
  447.                 $lesson['startTimeLeft'] = $lesson['startTime'] - time();
  448.             }
  449.         }
  450.         return $lesson;
  451.     }
  452.     private function _checkCourseStatus($courseId)
  453.     {
  454.         $course $this->getOpenCourseService()->getCourse($courseId);
  455.         if (empty($course)) {
  456.             return ['status' => false'message' => '课程已删除,请联系管理员再试。'];
  457.         }
  458.         if ('published' != $course['status']) {
  459.             return ['status' => false'message' => '课程已关闭,请联系管理员再试。'];
  460.         }
  461.         return ['status' => true'message' => ''];
  462.     }
  463.     private function _checkPublishedLessonExists($courseId)
  464.     {
  465.         $lessons $this->getOpenCourseService()->searchLessons([
  466.             'courseId' => $courseId,
  467.             'status' => 'published',
  468.         ],
  469.             ['seq' => 'ASC'], 01
  470.         );
  471.         if (!$lessons) {
  472.             return false;
  473.         }
  474.         return $lessons[0];
  475.     }
  476.     protected function autoParagraph($text)
  477.     {
  478.         if ('' !== trim($text)) {
  479.             $text htmlspecialchars($textENT_NOQUOTES'UTF-8');
  480.             $text preg_replace("/\n\n+/""\n\n"str_replace(["\r\n""\r"], "\n"$text));
  481.             $texts preg_split('/\n\s*\n/'$text, -1PREG_SPLIT_NO_EMPTY);
  482.             $text '';
  483.             foreach ($texts as $txt) {
  484.                 $text .= '<p>'.nl2br(trim($txt"\n"))."</p>\n";
  485.             }
  486.             $text preg_replace('|<p>\s*</p>|'''$text);
  487.         }
  488.         return $text;
  489.     }
  490.     private function _getLiveReplay($lesson)
  491.     {
  492.         $replays = [];
  493.         if (in_array($lesson['type'], ['liveOpen''replay'])) {
  494.             $replays $this->getLiveReplayService()->searchReplays([
  495.                 'courseId' => $lesson['courseId'],
  496.                 'lessonId' => $lesson['id'],
  497.                 'hidden' => 0,
  498.                 'type' => 'liveOpen',
  499.             ], ['createdTime' => 'DESC'], 0PHP_INT_MAX);
  500.         }
  501.         return $replays;
  502.     }
  503.     private function _loginMemberMobileBind($userMobile)
  504.     {
  505.         $user $this->getCurrentUser();
  506.         if ($user->isLogin() && empty($user['verifiedMobile'])) {
  507.             $this->getUserService()->changeMobile($user['id'], $userMobile);
  508.         }
  509.         return true;
  510.     }
  511.     protected function findCourseTeachers($courses)
  512.     {
  513.         if (!$courses) {
  514.             return [];
  515.         }
  516.         $userIds = [];
  517.         foreach ($courses as $key => $course) {
  518.             $userIds array_merge($userIds$course['teacherIds']);
  519.         }
  520.         return $this->getUserService()->findUsersByIds($userIds);
  521.     }
  522.     /**
  523.      * @return UserService
  524.      */
  525.     protected function getUserService()
  526.     {
  527.         return $this->createService('User:UserService');
  528.     }
  529.     /**
  530.      * @return TagService
  531.      */
  532.     protected function getTagService()
  533.     {
  534.         return $this->createService('Taxonomy:TagService');
  535.     }
  536.     /**
  537.      * @return CourseSetService
  538.      */
  539.     protected function getCourseSetService()
  540.     {
  541.         return $this->createService('Course:CourseSetService');
  542.     }
  543.     /**
  544.      * @return CourseService
  545.      */
  546.     protected function getCourseService()
  547.     {
  548.         return $this->getBiz()->service('Course:CourseService');
  549.     }
  550.     /**
  551.      * @return SettingService
  552.      */
  553.     protected function getSettingService()
  554.     {
  555.         return $this->createService('System:SettingService');
  556.     }
  557.     /**
  558.      * @return UploadFileService
  559.      */
  560.     protected function getUploadFileService()
  561.     {
  562.         return $this->createService('File:UploadFileService');
  563.     }
  564.     /**
  565.      * @return TokenService
  566.      */
  567.     protected function getTokenService()
  568.     {
  569.         return $this->createService('User:TokenService');
  570.     }
  571.     /**
  572.      * @return ThreadService
  573.      */
  574.     protected function getThreadService()
  575.     {
  576.         return $this->createService('Thread:ThreadService');
  577.     }
  578.     /**
  579.      * @return MaterialService
  580.      */
  581.     protected function getMaterialService()
  582.     {
  583.         return $this->createService('Course:MaterialService');
  584.     }
  585.     /**
  586.      * @return AuthService
  587.      */
  588.     protected function getAuthService()
  589.     {
  590.         return $this->createService('User:AuthService');
  591.     }
  592.     /**
  593.      * @return OpenCourseRecommendedService
  594.      */
  595.     protected function getOpenCourseRecommendedService()
  596.     {
  597.         return $this->createService('OpenCourse:OpenCourseRecommendedService');
  598.     }
  599.     protected function getLiveReplayService()
  600.     {
  601.         return $this->createService('Course:LiveReplayService');
  602.     }
  603.     /**
  604.      * @return FavoriteService
  605.      */
  606.     protected function getFavoriteService()
  607.     {
  608.         return $this->createService('Favorite:FavoriteService');
  609.     }
  610.     /**
  611.      * @return GoodsService
  612.      */
  613.     protected function getGoodsService()
  614.     {
  615.         return $this->createService('Goods:GoodsService');
  616.     }
  617. }