mirror of
https://gitee.com/koogua/course-tencent-cloud.git
synced 2025-06-22 11:41:27 +08:00
Merge branch 'develop'
# Conflicts: # LICENSE
This commit is contained in:
commit
bfe66b00d0
10
.gitignore
vendored
10
.gitignore
vendored
@ -1,3 +1,11 @@
|
||||
/.idea
|
||||
/vendor
|
||||
/config/config.php
|
||||
/vendor
|
||||
/config/xs.course.ini
|
||||
/config/xs.group.ini
|
||||
/config/xs.user.ini
|
||||
/config/alipay/*.crt
|
||||
/config/wxpay/*.pem
|
||||
/public/robots.txt
|
||||
/public/sitemap.xml
|
||||
*KgTest*
|
||||
|
97
README.md
97
README.md
@ -1,39 +1,82 @@
|
||||
# course-tencent-cloud
|
||||
## 酷瓜云课堂
|
||||
|
||||
#### 介绍
|
||||
{**以下是码云平台说明,您可以替换此简介**
|
||||
码云是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台
|
||||
无论是个人、团队、或是企业,都能够用码云实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)}
|
||||
#### 项目介绍
|
||||
|
||||
#### 软件架构
|
||||
软件架构说明
|
||||
酷瓜云课堂,依托腾讯云基础服务架构,采用 C 扩展框架 Phalcon 开发,致力网络教育软件。
|
||||
|
||||
#### 系统功能
|
||||
|
||||
#### 安装教程
|
||||
实现了点播、直播、专栏、会员、微聊等,是一个完整的产品,具体功能我也不想写一大堆,自己体验吧!
|
||||
|
||||
1. xxxx
|
||||
2. xxxx
|
||||
3. xxxx
|
||||
- [前台演示](https://ctc.koogua.com)
|
||||
- [后台演示](https://ctc.koogua.com/admin)
|
||||
|
||||
#### 使用说明
|
||||
帐号:100015@163.com / 123456 (前后台通用)
|
||||
|
||||
1. xxxx
|
||||
2. xxxx
|
||||
3. xxxx
|
||||
友情提示:
|
||||
|
||||
#### 参与贡献
|
||||
- 系统配置低(1核 1G 1M 跑多个容器),切莫压测
|
||||
- 课程数据来源于网络(无实质内容),切莫购买
|
||||
- 管理后台已禁止数据提交,私密配置已过滤
|
||||
|
||||
1. Fork 本仓库
|
||||
2. 新建 Feat_xxx 分支
|
||||
3. 提交代码
|
||||
4. 新建 Pull Request
|
||||
#### 项目组件
|
||||
|
||||
- 后台框架:[phalcon 3.4.5](https://phalcon.io)
|
||||
- 前端框架:[layui 2.5.6](https://layui.com), [layim 3.9.5](https://www.layui.com/layim)(已授权)
|
||||
- 全文检索:[xunsearch 1.4.9](http://www.xunsearch.com)
|
||||
- 即时通讯:[workerman 3.5.22](https://workerman.net)
|
||||
- 基础依赖:[php7.3](https://php.net), [mysql5.7](https://mysql.com), [redis5.0](https://redis.io)
|
||||
|
||||
#### 码云特技
|
||||
#### 使用协议
|
||||
|
||||
虽然尝试了解过开源协议,但是理解的模棱两可,干脆用自己的协议吧。
|
||||
|
||||
1. 本系统属于强业务类型,非通用类库框架,不适合再次衍生发布。
|
||||
2. 在保留我们版权标识的前提下,用户可以修改以满足自己的需求,可以用于商业用途。
|
||||
3. 有限社区支持,用户对自己的行为负责。
|
||||
|
||||
#### 安装指南
|
||||
|
||||
- [运行环境搭建](https://gitee.com/koogua/course-tencent-cloud-docker)
|
||||
- [系统服务配置](https://gitee.com/koogua/course-tencent-cloud/wikis)
|
||||
|
||||
#### 开发计划
|
||||
|
||||
- 桌面端:进行中
|
||||
- 移动端:待启动
|
||||
- 小程序:待启动
|
||||
|
||||
#### 意见反馈
|
||||
|
||||
- [在线反馈](https://gitee.com/koogua/course-tencent-cloud/issues)(推荐)
|
||||
- QQ邮箱: 76632555@qq.com
|
||||
- QQ群组: 787363898
|
||||
|
||||
#### 加入我们
|
||||
|
||||
这是一个创业项目,个人能力和精力有限,要兼顾产品规划以及开发,还要处理很多琐碎事情。目前在南山科技园某个众创空间,希望有 **深圳前端同学** 加入我们。
|
||||
|
||||
联系邮箱:76632555@qq.com
|
||||
|
||||
#### 通过这个项目能学到什么?
|
||||
|
||||
- 项目规划,phalcon,缓存,JWT,即时通讯,全文检索
|
||||
- docker,supervisor,devops
|
||||
- git,linux,php,mysql,redis,nginx
|
||||
|
||||
#### 有阿里云版吗?
|
||||
|
||||
阿里云版规划中,之前阿里云服务过期未续费,所以腾讯云版本先出。
|
||||
|
||||
#### 代码有加密吗?
|
||||
|
||||
所有代码都公开(授权代码除外,例如layim),没有所谓的商业版和付费插件。
|
||||
|
||||
#### 有商业服务吗?
|
||||
|
||||
生存才能发展,我们目前提供的服务包括:
|
||||
|
||||
- 系统安装
|
||||
- 系统定制
|
||||
- 企业授权
|
||||
|
||||
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
|
||||
2. 码云官方博客 [blog.gitee.com](https://blog.gitee.com)
|
||||
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解码云上的优秀开源项目
|
||||
4. [GVP](https://gitee.com/gvp) 全称是码云最有价值开源项目,是码云综合评定出的优秀开源项目
|
||||
5. 码云官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
|
||||
6. 码云封面人物是一档用来展示码云会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
|
15
app/Builders/Builder.php
Normal file
15
app/Builders/Builder.php
Normal file
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace App\Builders;
|
||||
|
||||
use Phalcon\Mvc\User\Component;
|
||||
|
||||
class Builder extends Component
|
||||
{
|
||||
|
||||
public function objects(array $items)
|
||||
{
|
||||
return kg_array_object($items);
|
||||
}
|
||||
|
||||
}
|
77
app/Builders/CategoryTreeList.php
Normal file
77
app/Builders/CategoryTreeList.php
Normal file
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace App\Builders;
|
||||
|
||||
use App\Models\Category as CategoryModel;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class CategoryTreeList extends Builder
|
||||
{
|
||||
|
||||
public function handle($type)
|
||||
{
|
||||
$topCategories = $this->findChildCategories($type, 0);
|
||||
|
||||
if ($topCategories->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$list = [];
|
||||
|
||||
foreach ($topCategories as $category) {
|
||||
$list[] = [
|
||||
'id' => $category->id,
|
||||
'name' => $category->name,
|
||||
'children' => $this->handleChildren($category),
|
||||
];
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
protected function handleChildren(CategoryModel $category)
|
||||
{
|
||||
$subCategories = $this->findChildCategories($category->type, $category->id);
|
||||
|
||||
if ($subCategories->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$list = [];
|
||||
|
||||
foreach ($subCategories as $category) {
|
||||
$list[] = [
|
||||
'id' => $category->id,
|
||||
'name' => $category->name,
|
||||
];
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @param int $parentId
|
||||
* @return ResultsetInterface|Resultset|CategoryModel[]
|
||||
*/
|
||||
protected function findChildCategories($type = 'course', $parentId = 0)
|
||||
{
|
||||
$query = CategoryModel::query();
|
||||
|
||||
$query->where('published = 1');
|
||||
|
||||
if ($type) {
|
||||
$query->andWhere('type = :type:', ['type' => $type]);
|
||||
}
|
||||
|
||||
if ($parentId) {
|
||||
$query->andWhere('parent_id = :parent_id:', ['parent_id' => $parentId]);
|
||||
}
|
||||
|
||||
$query->orderBy('priority ASC');
|
||||
|
||||
return $query->execute();
|
||||
}
|
||||
|
||||
}
|
88
app/Builders/ConsultList.php
Normal file
88
app/Builders/ConsultList.php
Normal file
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace App\Builders;
|
||||
|
||||
use App\Repos\Chapter as ChapterRepo;
|
||||
use App\Repos\Course as CourseRepo;
|
||||
use App\Repos\User as UserRepo;
|
||||
|
||||
class ConsultList extends Builder
|
||||
{
|
||||
|
||||
public function handleCourses(array $consults)
|
||||
{
|
||||
$courses = $this->getCourses($consults);
|
||||
|
||||
foreach ($consults as $key => $consult) {
|
||||
$consults[$key]['course'] = $courses[$consult['course_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $consults;
|
||||
}
|
||||
|
||||
public function handleUsers(array $consults)
|
||||
{
|
||||
$users = $this->getUsers($consults);
|
||||
|
||||
foreach ($consults as $key => $consult) {
|
||||
$consults[$key]['owner'] = $users[$consult['owner_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $consults;
|
||||
}
|
||||
|
||||
public function getCourses(array $consults)
|
||||
{
|
||||
$ids = kg_array_column($consults, 'course_id');
|
||||
|
||||
$courseRepo = new CourseRepo();
|
||||
|
||||
$courses = $courseRepo->findByIds($ids, ['id', 'title']);
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($courses->toArray() as $course) {
|
||||
$result[$course['id']] = $course;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getChapters(array $consults)
|
||||
{
|
||||
$ids = kg_array_column($consults, 'chapter_id');
|
||||
|
||||
$chapterRepo = new ChapterRepo();
|
||||
|
||||
$chapters = $chapterRepo->findByIds($ids, ['id', 'title']);
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($chapters->toArray() as $chapter) {
|
||||
$result[$chapter['id']] = $chapter;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getUsers(array $consults)
|
||||
{
|
||||
$ids = kg_array_column($consults, 'owner_id');
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$users = $userRepo->findByIds($ids, ['id', 'name', 'avatar']);
|
||||
|
||||
$baseUrl = kg_cos_url();
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($users->toArray() as $user) {
|
||||
$user['avatar'] = $baseUrl . $user['avatar'];
|
||||
$result[$user['id']] = $user;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
102
app/Builders/CourseChapterList.php
Normal file
102
app/Builders/CourseChapterList.php
Normal file
@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace App\Builders;
|
||||
|
||||
use App\Models\Chapter as ChapterModel;
|
||||
use App\Models\Course as CourseModel;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class CourseChapterList extends Builder
|
||||
{
|
||||
|
||||
/**
|
||||
* @param int $courseId
|
||||
* @return array
|
||||
*/
|
||||
public function handle($courseId)
|
||||
{
|
||||
$list = [];
|
||||
|
||||
$chapters = $this->findChapters($courseId);
|
||||
|
||||
if ($chapters->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
foreach ($chapters as $chapter) {
|
||||
$list[] = [
|
||||
'id' => $chapter->id,
|
||||
'title' => $chapter->title,
|
||||
'model' => $chapter->model,
|
||||
'children' => $this->handleChildren($chapter),
|
||||
];
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ChapterModel $chapter
|
||||
* @return array
|
||||
*/
|
||||
protected function handleChildren(ChapterModel $chapter)
|
||||
{
|
||||
$lessons = $this->findLessons($chapter->id);
|
||||
|
||||
if ($lessons->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$list = [];
|
||||
|
||||
foreach ($lessons as $lesson) {
|
||||
|
||||
/**
|
||||
* @var $attrs array
|
||||
*/
|
||||
$attrs = $lesson->attrs;
|
||||
|
||||
if ($chapter->model == CourseModel::MODEL_VOD) {
|
||||
unset($attrs['file_id'], $attrs['file_status']);
|
||||
}
|
||||
|
||||
$list[] = [
|
||||
'id' => $lesson->id,
|
||||
'title' => $lesson->title,
|
||||
'model' => $lesson->model,
|
||||
'free' => $lesson->free,
|
||||
'attrs' => $attrs,
|
||||
];
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $courseId
|
||||
* @return ResultsetInterface|Resultset|ChapterModel[]
|
||||
*/
|
||||
protected function findChapters($courseId)
|
||||
{
|
||||
return ChapterModel::query()
|
||||
->where('course_id = :course_id:', ['course_id' => $courseId])
|
||||
->andWhere('parent_id = 0 AND deleted = 0')
|
||||
->orderBy('priority ASC, id ASC')
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $chapterId
|
||||
* @return ResultsetInterface|Resultset|ChapterModel[]
|
||||
*/
|
||||
protected function findLessons($chapterId)
|
||||
{
|
||||
return ChapterModel::query()
|
||||
->where('parent_id = :parent_id:', ['parent_id' => $chapterId])
|
||||
->andWhere('deleted = 0')
|
||||
->orderBy('priority ASC, id ASC')
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
84
app/Builders/CourseFavoriteList.php
Normal file
84
app/Builders/CourseFavoriteList.php
Normal file
@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace App\Builders;
|
||||
|
||||
use App\Repos\Course as CourseRepo;
|
||||
use App\Repos\User as UserRepo;
|
||||
|
||||
class CourseFavoriteList extends Builder
|
||||
{
|
||||
|
||||
public function handleCourses(array $relations)
|
||||
{
|
||||
$courses = $this->getCourses($relations);
|
||||
|
||||
foreach ($relations as $key => $value) {
|
||||
$relations[$key]['course'] = $courses[$value['course_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $relations;
|
||||
}
|
||||
|
||||
public function handleUsers(array $relations)
|
||||
{
|
||||
$users = $this->getUsers($relations);
|
||||
|
||||
foreach ($relations as $key => $value) {
|
||||
$relations[$key]['user'] = $users[$value['user_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $relations;
|
||||
}
|
||||
|
||||
public function getCourses(array $relations)
|
||||
{
|
||||
$ids = kg_array_column($relations, 'course_id');
|
||||
|
||||
$courseRepo = new CourseRepo();
|
||||
|
||||
$columns = [
|
||||
'id', 'title', 'cover',
|
||||
'market_price', 'vip_price',
|
||||
'rating', 'model', 'level', 'attrs',
|
||||
'user_count', 'lesson_count', 'review_count', 'favorite_count',
|
||||
];
|
||||
|
||||
$courses = $courseRepo->findByIds($ids, $columns);
|
||||
|
||||
$baseUrl = kg_cos_url();
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($courses->toArray() as $course) {
|
||||
$course['cover'] = $baseUrl . $course['cover'];
|
||||
$course['market_price'] = (float)$course['market_price'];
|
||||
$course['vip_price'] = (float)$course['vip_price'];
|
||||
$course['rating'] = (float)$course['rating'];
|
||||
$course['attrs'] = json_decode($course['attrs'], true);
|
||||
$result[$course['id']] = $course;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getUsers(array $relations)
|
||||
{
|
||||
$ids = kg_array_column($relations, 'user_id');
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$users = $userRepo->findByIds($ids, ['id', 'name', 'avatar']);
|
||||
|
||||
$baseUrl = kg_cos_url();
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($users->toArray() as $user) {
|
||||
$user['avatar'] = $baseUrl . $user['avatar'];
|
||||
$result[$user['id']] = $user;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
76
app/Builders/CourseList.php
Normal file
76
app/Builders/CourseList.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Builders;
|
||||
|
||||
use App\Caches\CategoryList as CategoryListCache;
|
||||
use App\Models\Category as CategoryModel;
|
||||
use App\Repos\User as UserRepo;
|
||||
|
||||
class CourseList extends Builder
|
||||
{
|
||||
|
||||
public function handleCategories(array $courses)
|
||||
{
|
||||
$categories = $this->getCategories();
|
||||
|
||||
foreach ($courses as $key => $course) {
|
||||
$courses[$key]['category'] = $categories[$course['category_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $courses;
|
||||
}
|
||||
|
||||
public function handleTeachers(array $courses)
|
||||
{
|
||||
$teachers = $this->getTeachers($courses);
|
||||
|
||||
foreach ($courses as $key => $course) {
|
||||
$courses[$key]['teacher'] = $teachers[$course['teacher_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $courses;
|
||||
}
|
||||
|
||||
public function getCategories()
|
||||
{
|
||||
$cache = new CategoryListCache();
|
||||
|
||||
$items = $cache->get(CategoryModel::TYPE_COURSE);
|
||||
|
||||
if (empty($items)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($items as $item) {
|
||||
$result[$item['id']] = [
|
||||
'id' => $item['id'],
|
||||
'name' => $item['name'],
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getTeachers($courses)
|
||||
{
|
||||
$ids = kg_array_column($courses, 'teacher_id');
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$users = $userRepo->findByIds($ids, ['id', 'name', 'avatar']);
|
||||
|
||||
$baseUrl = kg_cos_url();
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($users->toArray() as $user) {
|
||||
$user['avatar'] = $baseUrl . $user['avatar'];
|
||||
$result[$user['id']] = $user;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
78
app/Builders/CourseTopicList.php
Normal file
78
app/Builders/CourseTopicList.php
Normal file
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace App\Builders;
|
||||
|
||||
use App\Repos\Course as CourseRepo;
|
||||
use App\Repos\Topic as TopicRepo;
|
||||
|
||||
class CourseTopicList extends Builder
|
||||
{
|
||||
|
||||
public function handleCourses($relations)
|
||||
{
|
||||
$courses = $this->getCourses($relations);
|
||||
|
||||
foreach ($relations as $key => $value) {
|
||||
$relations[$key]['course'] = $courses[$value['course_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $relations;
|
||||
}
|
||||
|
||||
public function handleTopics($relations)
|
||||
{
|
||||
$topics = $this->getTopics($relations);
|
||||
|
||||
foreach ($relations as $key => $value) {
|
||||
$relations[$key]['topic'] = $topics[$value['topic_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $relations;
|
||||
}
|
||||
|
||||
public function getCourses($relations)
|
||||
{
|
||||
$ids = kg_array_column($relations, 'course_id');
|
||||
|
||||
$courseRepo = new CourseRepo();
|
||||
|
||||
$columns = [
|
||||
'id', 'title', 'cover',
|
||||
'market_price', 'vip_price',
|
||||
'rating', 'model', 'level', 'attrs',
|
||||
'user_count', 'lesson_count',
|
||||
];
|
||||
|
||||
$courses = $courseRepo->findByIds($ids, $columns);
|
||||
|
||||
$baseUrl = kg_cos_url();
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($courses->toArray() as $course) {
|
||||
$course['cover'] = $baseUrl . $course['cover'];
|
||||
$course['attrs'] = json_decode($course['attrs'], true);
|
||||
$result[$course['id']] = $course;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getTopics($relations)
|
||||
{
|
||||
$ids = kg_array_column($relations, 'topic_id');
|
||||
|
||||
$topicRepo = new TopicRepo();
|
||||
|
||||
$topics = $topicRepo->findByIds($ids, ['id', 'title', 'summary']);
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($topics->toArray() as $topic) {
|
||||
$result[$topic['id']] = $topic;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Transformers;
|
||||
namespace App\Builders;
|
||||
|
||||
use App\Repos\Course as CourseRepo;
|
||||
use App\Repos\User as UserRepo;
|
||||
|
||||
class CourseUserList extends Transformer
|
||||
class CourseUserList extends Builder
|
||||
{
|
||||
|
||||
public function handleCourses($relations)
|
||||
@ -13,7 +13,7 @@ class CourseUserList extends Transformer
|
||||
$courses = $this->getCourses($relations);
|
||||
|
||||
foreach ($relations as $key => $value) {
|
||||
$relations[$key]['course'] = $courses[$value['course_id']];
|
||||
$relations[$key]['course'] = $courses[$value['course_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $relations;
|
||||
@ -24,40 +24,54 @@ class CourseUserList extends Transformer
|
||||
$users = $this->getUsers($relations);
|
||||
|
||||
foreach ($relations as $key => $value) {
|
||||
$relations[$key]['user'] = $users[$value['user_id']];
|
||||
$relations[$key]['user'] = $users[$value['user_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $relations;
|
||||
}
|
||||
|
||||
protected function getCourses($relations)
|
||||
public function getCourses($relations)
|
||||
{
|
||||
$ids = kg_array_column($relations, 'course_id');
|
||||
|
||||
$courseRepo = new CourseRepo();
|
||||
|
||||
$courses = $courseRepo->findByIds($ids, ['id', 'title', 'cover'])->toArray();
|
||||
$columns = [
|
||||
'id', 'title', 'cover',
|
||||
'market_price', 'vip_price',
|
||||
'rating', 'model', 'level', 'attrs',
|
||||
'user_count', 'lesson_count', 'review_count', 'favorite_count',
|
||||
];
|
||||
|
||||
$courses = $courseRepo->findByIds($ids, $columns);
|
||||
|
||||
$baseUrl = kg_cos_url();
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($courses as $course) {
|
||||
foreach ($courses->toArray() as $course) {
|
||||
$course['cover'] = $baseUrl . $course['cover'];
|
||||
$course['attrs'] = json_decode($course['attrs'], true);
|
||||
$result[$course['id']] = $course;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function getUsers($relations)
|
||||
public function getUsers($relations)
|
||||
{
|
||||
$ids = kg_array_column($relations, 'user_id');
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$users = $userRepo->findByIds($ids, ['id', 'name', 'avatar'])->toArray();
|
||||
$users = $userRepo->findByIds($ids, ['id', 'name', 'avatar']);
|
||||
|
||||
$baseUrl = kg_cos_url();
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($users as $user) {
|
||||
foreach ($users->toArray() as $user) {
|
||||
$user['avatar'] = $baseUrl . $user['avatar'];
|
||||
$result[$user['id']] = $user;
|
||||
}
|
||||
|
99
app/Builders/DanmuList.php
Normal file
99
app/Builders/DanmuList.php
Normal file
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace App\Builders;
|
||||
|
||||
use App\Repos\Chapter as ChapterRepo;
|
||||
use App\Repos\Course as CourseRepo;
|
||||
use App\Repos\User as UserRepo;
|
||||
|
||||
class DanmuList extends Builder
|
||||
{
|
||||
|
||||
public function handleCourses(array $danmus)
|
||||
{
|
||||
$courses = $this->getCourses($danmus);
|
||||
|
||||
foreach ($danmus as $key => $danmu) {
|
||||
$danmus[$key]['course'] = $courses[$danmu['course_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $danmus;
|
||||
}
|
||||
|
||||
public function handleChapters(array $danmus)
|
||||
{
|
||||
$chapters = $this->getChapters($danmus);
|
||||
|
||||
foreach ($danmus as $key => $danmu) {
|
||||
$danmus[$key]['chapter'] = $chapters[$danmu['chapter_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $danmus;
|
||||
}
|
||||
|
||||
public function handleUsers(array $danmus)
|
||||
{
|
||||
$users = $this->getUsers($danmus);
|
||||
|
||||
foreach ($danmus as $key => $danmu) {
|
||||
$danmus[$key]['owner'] = $users[$danmu['owner_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $danmus;
|
||||
}
|
||||
|
||||
public function getCourses(array $danmus)
|
||||
{
|
||||
$ids = kg_array_column($danmus, 'course_id');
|
||||
|
||||
$courseRepo = new CourseRepo();
|
||||
|
||||
$courses = $courseRepo->findByIds($ids, ['id', 'title']);
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($courses->toArray() as $course) {
|
||||
$result[$course['id']] = $course;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getChapters(array $danmus)
|
||||
{
|
||||
$ids = kg_array_column($danmus, 'chapter_id');
|
||||
|
||||
$chapterRepo = new ChapterRepo();
|
||||
|
||||
$chapters = $chapterRepo->findByIds($ids, ['id', 'title']);
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($chapters->toArray() as $chapter) {
|
||||
$result[$chapter['id']] = $chapter;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getUsers(array $danmus)
|
||||
{
|
||||
$ids = kg_array_column($danmus, 'owner_id');
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$users = $userRepo->findByIds($ids, ['id', 'name', 'avatar']);
|
||||
|
||||
$baseUrl = kg_cos_url();
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($users->toArray() as $user) {
|
||||
$user['avatar'] = $baseUrl . $user['avatar'];
|
||||
$result[$user['id']] = $user;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
44
app/Builders/HelpList.php
Normal file
44
app/Builders/HelpList.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Builders;
|
||||
|
||||
use App\Caches\CategoryList as CategoryListCache;
|
||||
use App\Models\Category as CategoryModel;
|
||||
|
||||
class HelpList extends Builder
|
||||
{
|
||||
|
||||
public function handleCategories(array $helps)
|
||||
{
|
||||
$categories = $this->getCategories();
|
||||
|
||||
foreach ($helps as $key => $help) {
|
||||
$helps[$key]['category'] = $categories[$help['category_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $helps;
|
||||
}
|
||||
|
||||
public function getCategories()
|
||||
{
|
||||
$cache = new CategoryListCache();
|
||||
|
||||
$items = $cache->get(CategoryModel::TYPE_HELP);
|
||||
|
||||
if (empty($items)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($items as $item) {
|
||||
$result[$item['id']] = [
|
||||
'id' => $item['id'],
|
||||
'name' => $item['name'],
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
46
app/Builders/ImFriendUserList.php
Normal file
46
app/Builders/ImFriendUserList.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace App\Builders;
|
||||
|
||||
use App\Repos\User as UserRepo;
|
||||
|
||||
class ImFriendUserList extends Builder
|
||||
{
|
||||
|
||||
public function handleFriends(array $relations)
|
||||
{
|
||||
$users = $this->getFriends($relations);
|
||||
|
||||
foreach ($relations as $key => $value) {
|
||||
$relations[$key]['friend'] = $users[$value['friend_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $relations;
|
||||
}
|
||||
|
||||
public function getFriends(array $relations)
|
||||
{
|
||||
$ids = kg_array_column($relations, 'friend_id');
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$columns = [
|
||||
'id', 'name', 'avatar', 'title', 'about', 'vip',
|
||||
'gender', 'area', 'active_time',
|
||||
];
|
||||
|
||||
$users = $userRepo->findByIds($ids, $columns);
|
||||
|
||||
$baseUrl = kg_cos_url();
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($users->toArray() as $user) {
|
||||
$user['avatar'] = $baseUrl . $user['avatar'];
|
||||
$result[$user['id']] = $user;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
70
app/Builders/ImGroupList.php
Normal file
70
app/Builders/ImGroupList.php
Normal file
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace App\Builders;
|
||||
|
||||
use App\Repos\Course as CourseRepo;
|
||||
use App\Repos\User as UserRepo;
|
||||
|
||||
class ImGroupList extends Builder
|
||||
{
|
||||
|
||||
public function handleCourses(array $groups)
|
||||
{
|
||||
$courses = $this->getCourses($groups);
|
||||
|
||||
foreach ($groups as $key => $group) {
|
||||
$groups[$key]['course'] = $courses[$group['course_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $groups;
|
||||
}
|
||||
|
||||
public function handleUsers(array $groups)
|
||||
{
|
||||
$users = $this->getUsers($groups);
|
||||
|
||||
foreach ($groups as $key => $group) {
|
||||
$groups[$key]['owner'] = $users[$group['owner_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $groups;
|
||||
}
|
||||
|
||||
public function getCourses(array $groups)
|
||||
{
|
||||
$ids = kg_array_column($groups, 'course_id');
|
||||
|
||||
$courseRepo = new CourseRepo();
|
||||
|
||||
$courses = $courseRepo->findByIds($ids, ['id', 'title']);
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($courses->toArray() as $course) {
|
||||
$result[$course['id']] = $course;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getUsers(array $groups)
|
||||
{
|
||||
$ids = kg_array_column($groups, 'owner_id');
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$users = $userRepo->findByIds($ids, ['id', 'name', 'avatar']);
|
||||
|
||||
$baseUrl = kg_cos_url();
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($users->toArray() as $user) {
|
||||
$user['avatar'] = $baseUrl . $user['avatar'];
|
||||
$result[$user['id']] = $user;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
100
app/Builders/ImGroupUserList.php
Normal file
100
app/Builders/ImGroupUserList.php
Normal file
@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace App\Builders;
|
||||
|
||||
use App\Repos\ImGroup as ImGroupRepo;
|
||||
use App\Repos\User as UserRepo;
|
||||
|
||||
class ImGroupUserList extends Builder
|
||||
{
|
||||
|
||||
public function handleGroups(array $relations)
|
||||
{
|
||||
$groups = $this->getGroups($relations);
|
||||
|
||||
foreach ($relations as $key => $value) {
|
||||
$relations[$key]['group'] = $groups[$value['group_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $relations;
|
||||
}
|
||||
|
||||
public function handleUsers(array $relations)
|
||||
{
|
||||
$users = $this->getUsers($relations);
|
||||
|
||||
foreach ($relations as $key => $value) {
|
||||
$relations[$key]['user'] = $users[$value['user_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $relations;
|
||||
}
|
||||
|
||||
public function getUsers(array $relations)
|
||||
{
|
||||
$ids = kg_array_column($relations, 'user_id');
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$columns = ['id', 'name', 'avatar', 'title', 'about', 'vip'];
|
||||
|
||||
$users = $userRepo->findByIds($ids, $columns);
|
||||
|
||||
$baseUrl = kg_cos_url();
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($users->toArray() as $user) {
|
||||
$user['avatar'] = $baseUrl . $user['avatar'];
|
||||
$result[$user['id']] = $user;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getGroups(array $relations)
|
||||
{
|
||||
$ids = kg_array_column($relations, 'group_id');
|
||||
|
||||
$groupRepo = new ImGroupRepo();
|
||||
|
||||
$columns = ['id', 'type', 'name', 'avatar', 'about', 'owner_id', 'user_count', 'msg_count'];
|
||||
|
||||
$groups = $groupRepo->findByIds($ids, $columns);
|
||||
|
||||
$users = $this->getGroupOwners($groups->toArray());
|
||||
|
||||
$baseUrl = kg_cos_url();
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($groups->toArray() as $group) {
|
||||
$group['avatar'] = $baseUrl . $group['avatar'];
|
||||
$group['owner'] = $users[$group['owner_id']] ?? new \stdClass();
|
||||
unset($group['owner_id']);
|
||||
$result[$group['id']] = $group;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function getGroupOwners(array $groups)
|
||||
{
|
||||
$ids = kg_array_column($groups, 'owner_id');
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$users = $userRepo->findByIds($ids, ['id', 'name']);
|
||||
|
||||
$result = [];
|
||||
|
||||
if ($users->count() > 0) {
|
||||
foreach ($users->toArray() as $user) {
|
||||
$result[$user['id']] = $user;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
41
app/Builders/ImMessageList.php
Normal file
41
app/Builders/ImMessageList.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Builders;
|
||||
|
||||
use App\Repos\User as UserRepo;
|
||||
|
||||
class ImMessageList extends Builder
|
||||
{
|
||||
|
||||
public function handleSenders(array $messages)
|
||||
{
|
||||
$users = $this->getSenders($messages);
|
||||
|
||||
foreach ($messages as $key => $message) {
|
||||
$messages[$key]['sender'] = $users[$message['sender_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $messages;
|
||||
}
|
||||
|
||||
public function getSenders(array $messages)
|
||||
{
|
||||
$ids = kg_array_column($messages, 'sender_id');
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$users = $userRepo->findByIds($ids, ['id', 'name', 'avatar']);
|
||||
|
||||
$baseUrl = kg_cos_url();
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($users->toArray() as $user) {
|
||||
$user['avatar'] = $baseUrl . $user['avatar'];
|
||||
$result[$user['id']] = $user;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace App\Transformers;
|
||||
namespace App\Builders;
|
||||
|
||||
use App\Repos\Course as CourseRepo;
|
||||
use App\Repos\Chapter as ChapterRepo;
|
||||
use App\Repos\Course as CourseRepo;
|
||||
use App\Repos\User as UserRepo;
|
||||
|
||||
class LearningList extends Transformer
|
||||
class LearningList extends Builder
|
||||
{
|
||||
|
||||
public function handleCourses($relations)
|
||||
@ -14,7 +14,7 @@ class LearningList extends Transformer
|
||||
$courses = $this->getCourses($relations);
|
||||
|
||||
foreach ($relations as $key => $value) {
|
||||
$relations[$key]['course'] = $courses[$value['course_id']];
|
||||
$relations[$key]['course'] = $courses[$value['course_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $relations;
|
||||
@ -25,7 +25,7 @@ class LearningList extends Transformer
|
||||
$chapters = $this->getChapters($relations);
|
||||
|
||||
foreach ($relations as $key => $value) {
|
||||
$relations[$key]['chapter'] = $chapters[$value['chapter_id']];
|
||||
$relations[$key]['chapter'] = $chapters[$value['chapter_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $relations;
|
||||
@ -36,7 +36,7 @@ class LearningList extends Transformer
|
||||
$users = $this->getUsers($relations);
|
||||
|
||||
foreach ($relations as $key => $value) {
|
||||
$relations[$key]['user'] = $users[$value['user_id']];
|
||||
$relations[$key]['user'] = $users[$value['user_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $relations;
|
||||
@ -48,11 +48,11 @@ class LearningList extends Transformer
|
||||
|
||||
$courseRepo = new CourseRepo();
|
||||
|
||||
$courses = $courseRepo->findByIds($ids, ['id', 'title', 'cover'])->toArray();
|
||||
$courses = $courseRepo->findByIds($ids, ['id', 'title']);
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($courses as $course) {
|
||||
foreach ($courses->toArray() as $course) {
|
||||
$result[$course['id']] = $course;
|
||||
}
|
||||
|
||||
@ -65,11 +65,11 @@ class LearningList extends Transformer
|
||||
|
||||
$chapterRepo = new ChapterRepo();
|
||||
|
||||
$chapters = $chapterRepo->findByIds($ids, ['id', 'title'])->toArray();
|
||||
$chapters = $chapterRepo->findByIds($ids, ['id', 'title']);
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($chapters as $chapter) {
|
||||
foreach ($chapters->toArray() as $chapter) {
|
||||
$result[$chapter['id']] = $chapter;
|
||||
}
|
||||
|
||||
@ -82,11 +82,11 @@ class LearningList extends Transformer
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$users = $userRepo->findByIds($ids, ['id', 'name', 'avatar'])->toArray();
|
||||
$users = $userRepo->findByIds($ids, ['id', 'name']);
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($users as $user) {
|
||||
foreach ($users->toArray() as $user) {
|
||||
$result[$user['id']] = $user;
|
||||
}
|
||||
|
83
app/Builders/NavTreeList.php
Normal file
83
app/Builders/NavTreeList.php
Normal file
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace App\Builders;
|
||||
|
||||
use App\Models\Nav as NavModel;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class NavTreeList extends Builder
|
||||
{
|
||||
|
||||
public function handle($position = 'top')
|
||||
{
|
||||
$topNavs = $this->findTopNavs($position);
|
||||
|
||||
if ($topNavs->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$list = [];
|
||||
|
||||
foreach ($topNavs as $nav) {
|
||||
$list[] = [
|
||||
'id' => $nav->id,
|
||||
'name' => $nav->name,
|
||||
'target' => $nav->target,
|
||||
'url' => $nav->url,
|
||||
'children' => $this->handleChildren($nav),
|
||||
];
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
protected function handleChildren(NavModel $nav)
|
||||
{
|
||||
$subNavs = $this->findSubNavs($nav->id);
|
||||
|
||||
if ($subNavs->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$list = [];
|
||||
|
||||
foreach ($subNavs as $nav) {
|
||||
$list[] = [
|
||||
'id' => $nav->id,
|
||||
'name' => $nav->name,
|
||||
'target' => $nav->target,
|
||||
'url' => $nav->url,
|
||||
];
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $navId
|
||||
* @return ResultsetInterface|Resultset|NavModel[]
|
||||
*/
|
||||
protected function findSubNavs($navId)
|
||||
{
|
||||
return NavModel::query()
|
||||
->where('parent_id = :parent_id:', ['parent_id' => $navId])
|
||||
->andWhere('published = 1')
|
||||
->orderBy('priority ASC')
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $position
|
||||
* @return ResultsetInterface|Resultset|NavModel[]
|
||||
*/
|
||||
protected function findTopNavs($position)
|
||||
{
|
||||
return NavModel::query()
|
||||
->where('position = :position:', ['position' => $position])
|
||||
->andWhere('level = 1 AND published = 1')
|
||||
->orderBy('priority ASC')
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
148
app/Builders/OrderList.php
Normal file
148
app/Builders/OrderList.php
Normal file
@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
namespace App\Builders;
|
||||
|
||||
use App\Models\Order as OrderModel;
|
||||
use App\Repos\User as UserRepo;
|
||||
|
||||
class OrderList extends Builder
|
||||
{
|
||||
|
||||
protected $imgBaseUrl;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->imgBaseUrl = kg_cos_url();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $orders
|
||||
* @return array
|
||||
*/
|
||||
public function handleUsers(array $orders)
|
||||
{
|
||||
$users = $this->getUsers($orders);
|
||||
|
||||
foreach ($orders as $key => $order) {
|
||||
$orders[$key]['owner'] = $users[$order['owner_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $orders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $orders
|
||||
* @return array
|
||||
*/
|
||||
public function handleItems(array $orders)
|
||||
{
|
||||
foreach ($orders as $key => $order) {
|
||||
$itemInfo = $this->handleItem($order);
|
||||
$orders[$key]['item_info'] = $itemInfo;
|
||||
}
|
||||
|
||||
return $orders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $order
|
||||
* @return array|mixed
|
||||
*/
|
||||
public function handleItem(array $order)
|
||||
{
|
||||
$itemInfo = [];
|
||||
|
||||
switch ($order['item_type']) {
|
||||
case OrderModel::ITEM_COURSE:
|
||||
$itemInfo = $this->handleCourseInfo($order['item_info']);
|
||||
break;
|
||||
case OrderModel::ITEM_PACKAGE:
|
||||
$itemInfo = $this->handlePackageInfo($order['item_info']);
|
||||
break;
|
||||
case OrderModel::ITEM_VIP:
|
||||
$itemInfo = $this->handleVipInfo($order['item_info']);
|
||||
break;
|
||||
}
|
||||
|
||||
return $itemInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $itemInfo
|
||||
* @return mixed
|
||||
*/
|
||||
protected function handleCourseInfo($itemInfo)
|
||||
{
|
||||
if (!empty($itemInfo) && is_string($itemInfo)) {
|
||||
$itemInfo = json_decode($itemInfo, true);
|
||||
$itemInfo['course']['cover'] = $this->imgBaseUrl . $itemInfo['course']['cover'];
|
||||
}
|
||||
|
||||
return $itemInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $itemInfo
|
||||
* @return mixed
|
||||
*/
|
||||
protected function handlePackageInfo($itemInfo)
|
||||
{
|
||||
if (!empty($itemInfo) && is_string($itemInfo)) {
|
||||
$itemInfo = json_decode($itemInfo, true);
|
||||
foreach ($itemInfo['courses'] as $key => $course) {
|
||||
$itemInfo['courses'][$key]['cover'] = $this->imgBaseUrl . $course['cover'];
|
||||
}
|
||||
}
|
||||
|
||||
return $itemInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $itemInfo
|
||||
* @return mixed
|
||||
*/
|
||||
protected function handleRewardInfo($itemInfo)
|
||||
{
|
||||
if (!empty($itemInfo) && is_string($itemInfo)) {
|
||||
$itemInfo = json_decode($itemInfo, true);
|
||||
$itemInfo['course']['cover'] = $this->imgBaseUrl . $itemInfo['course']['cover'];
|
||||
}
|
||||
|
||||
return $itemInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $itemInfo
|
||||
* @return mixed
|
||||
*/
|
||||
protected function handleVipInfo($itemInfo)
|
||||
{
|
||||
if (!empty($itemInfo) && is_string($itemInfo)) {
|
||||
$itemInfo = json_decode($itemInfo, true);
|
||||
}
|
||||
|
||||
return $itemInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $orders
|
||||
* @return array
|
||||
*/
|
||||
protected function getUsers(array $orders)
|
||||
{
|
||||
$ids = kg_array_column($orders, 'owner_id');
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$users = $userRepo->findByIds($ids, ['id', 'name']);
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($users->toArray() as $user) {
|
||||
$result[$user['id']] = $user;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
67
app/Builders/RefundList.php
Normal file
67
app/Builders/RefundList.php
Normal file
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace App\Builders;
|
||||
|
||||
use App\Repos\Order as OrderRepo;
|
||||
use App\Repos\User as UserRepo;
|
||||
|
||||
class RefundList extends Builder
|
||||
{
|
||||
|
||||
public function handleOrders(array $trades)
|
||||
{
|
||||
$orders = $this->getOrders($trades);
|
||||
|
||||
foreach ($trades as $key => $trade) {
|
||||
$trades[$key]['order'] = $orders[$trade['order_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $trades;
|
||||
}
|
||||
|
||||
public function handleUsers(array $refunds)
|
||||
{
|
||||
$users = $this->getUsers($refunds);
|
||||
|
||||
foreach ($refunds as $key => $refund) {
|
||||
$refunds[$key]['owner'] = $users[$refund['owner_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $refunds;
|
||||
}
|
||||
|
||||
public function getOrders(array $trades)
|
||||
{
|
||||
$ids = kg_array_column($trades, 'order_id');
|
||||
|
||||
$orderRepo = new OrderRepo();
|
||||
|
||||
$orders = $orderRepo->findByIds($ids, ['id', 'sn', 'subject', 'amount']);
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($orders->toArray() as $order) {
|
||||
$result[$order['id']] = $order;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getUsers(array $refunds)
|
||||
{
|
||||
$ids = kg_array_column($refunds, 'owner_id');
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$users = $userRepo->findByIds($ids, ['id', 'name']);
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($users->toArray() as $user) {
|
||||
$result[$user['id']] = $user;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
@ -1,63 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace App\Transformers;
|
||||
namespace App\Builders;
|
||||
|
||||
use App\Repos\Course as CourseRepo;
|
||||
use App\Repos\User as UserRepo;
|
||||
|
||||
class ReviewList extends Transformer
|
||||
class ReviewList extends Builder
|
||||
{
|
||||
|
||||
public function handleCourses($reviews)
|
||||
public function handleCourses(array $reviews)
|
||||
{
|
||||
$courses = $this->getCourses($reviews);
|
||||
|
||||
foreach ($reviews as $key => $review) {
|
||||
$reviews[$key]['course'] = $courses[$review['course_id']];
|
||||
$reviews[$key]['course'] = $courses[$review['course_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $reviews;
|
||||
}
|
||||
|
||||
public function handleUsers($reviews)
|
||||
public function handleUsers(array $reviews)
|
||||
{
|
||||
$users = $this->getUsers($reviews);
|
||||
|
||||
foreach ($reviews as $key => $review) {
|
||||
$reviews[$key]['user'] = $users[$review['user_id']];
|
||||
$reviews[$key]['owner'] = $users[$review['owner_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $reviews;
|
||||
}
|
||||
|
||||
protected function getCourses($reviews)
|
||||
public function getCourses(array $reviews)
|
||||
{
|
||||
$ids = kg_array_column($reviews, 'course_id');
|
||||
|
||||
$courseRepo = new CourseRepo();
|
||||
|
||||
$courses = $courseRepo->findByIds($ids, ['id', 'title'])->toArray();
|
||||
$courses = $courseRepo->findByIds($ids, ['id', 'title']);
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($courses as $course) {
|
||||
foreach ($courses->toArray() as $course) {
|
||||
$result[$course['id']] = $course;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function getUsers($reviews)
|
||||
public function getUsers(array $reviews)
|
||||
{
|
||||
$ids = kg_array_column($reviews, 'user_id');
|
||||
$ids = kg_array_column($reviews, 'owner_id');
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$users = $userRepo->findByIds($ids, ['id', 'name', 'avatar'])->toArray();
|
||||
$users = $userRepo->findByIds($ids, ['id', 'name', 'avatar']);
|
||||
|
||||
$baseUrl = kg_cos_url();
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($users as $user) {
|
||||
foreach ($users->toArray() as $user) {
|
||||
$user['avatar'] = $baseUrl . $user['avatar'];
|
||||
$result[$user['id']] = $user;
|
||||
}
|
||||
|
67
app/Builders/TradeList.php
Normal file
67
app/Builders/TradeList.php
Normal file
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace App\Builders;
|
||||
|
||||
use App\Repos\Order as OrderRepo;
|
||||
use App\Repos\User as UserRepo;
|
||||
|
||||
class TradeList extends Builder
|
||||
{
|
||||
|
||||
public function handleOrders(array $trades)
|
||||
{
|
||||
$orders = $this->getOrders($trades);
|
||||
|
||||
foreach ($trades as $key => $trade) {
|
||||
$trades[$key]['order'] = $orders[$trade['order_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $trades;
|
||||
}
|
||||
|
||||
public function handleUsers($trades)
|
||||
{
|
||||
$users = $this->getUsers($trades);
|
||||
|
||||
foreach ($trades as $key => $trade) {
|
||||
$trades[$key]['owner'] = $users[$trade['owner_id']] ?? new \stdClass();
|
||||
}
|
||||
|
||||
return $trades;
|
||||
}
|
||||
|
||||
public function getOrders($trades)
|
||||
{
|
||||
$ids = kg_array_column($trades, 'order_id');
|
||||
|
||||
$orderRepo = new OrderRepo();
|
||||
|
||||
$orders = $orderRepo->findByIds($ids, ['id', 'sn', 'subject', 'amount']);
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($orders->toArray() as $order) {
|
||||
$result[$order['id']] = $order;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getUsers($trades)
|
||||
{
|
||||
$ids = kg_array_column($trades, 'owner_id');
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$users = $userRepo->findByIds($ids, ['id', 'name']);
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($users->toArray() as $user) {
|
||||
$result[$user['id']] = $user;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
@ -1,14 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Transformers;
|
||||
namespace App\Builders;
|
||||
|
||||
use App\Models\User as UserModel;
|
||||
use App\Repos\Role as RoleRepo;
|
||||
|
||||
class UserList extends Transformer
|
||||
class UserList extends Builder
|
||||
{
|
||||
|
||||
public function handleAdminRoles($users)
|
||||
public function handleUsers(array $users)
|
||||
{
|
||||
$baseUrl = kg_cos_url();
|
||||
|
||||
foreach ($users as $key => $user) {
|
||||
$users[$key]['avatar'] = $baseUrl . $user['avatar'];
|
||||
}
|
||||
|
||||
return $users;
|
||||
}
|
||||
|
||||
public function handleAdminRoles(array $users)
|
||||
{
|
||||
$roles = $this->getAdminRoles($users);
|
||||
|
||||
@ -19,9 +30,9 @@ class UserList extends Transformer
|
||||
return $users;
|
||||
}
|
||||
|
||||
public function handleEduRoles($users)
|
||||
public function handleEduRoles(array $users)
|
||||
{
|
||||
$roles = $this->getEduRoles($users);
|
||||
$roles = $this->getEduRoles();
|
||||
|
||||
foreach ($users as $key => $user) {
|
||||
$users[$key]['edu_role'] = $roles[$user['edu_role']] ?? ['id' => 0, 'name' => 'N/A'];
|
||||
@ -30,26 +41,26 @@ class UserList extends Transformer
|
||||
return $users;
|
||||
}
|
||||
|
||||
private function getAdminRoles($users)
|
||||
protected function getAdminRoles(array $users)
|
||||
{
|
||||
$ids = kg_array_column($users, 'admin_role');
|
||||
|
||||
$roleRepo = new RoleRepo();
|
||||
|
||||
$roles = $roleRepo->findByIds($ids, ['id', 'name'])->toArray();
|
||||
$roles = $roleRepo->findByIds($ids, ['id', 'name']);
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($roles as $role) {
|
||||
foreach ($roles->toArray() as $role) {
|
||||
$result[$role['id']] = $role;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function getEduRoles()
|
||||
protected function getEduRoles()
|
||||
{
|
||||
$result = [
|
||||
return [
|
||||
UserModel::EDU_ROLE_STUDENT => [
|
||||
'id' => UserModel::EDU_ROLE_STUDENT,
|
||||
'name' => '学员',
|
||||
@ -59,8 +70,6 @@ class UserList extends Transformer
|
||||
'name' => '讲师',
|
||||
],
|
||||
];
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
@ -2,36 +2,41 @@
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use Phalcon\Mvc\User\Component as UserComponent;
|
||||
use Phalcon\Cache\Backend\Redis as RedisCache;
|
||||
use Phalcon\Mvc\User\Component;
|
||||
|
||||
abstract class Cache extends UserComponent
|
||||
abstract class Cache extends Component
|
||||
{
|
||||
|
||||
/**
|
||||
* @var \Phalcon\Cache\Backend
|
||||
* @var RedisCache
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->cache = $this->getDI()->get('cache');
|
||||
$this->cache = $this->getDI()->getShared('cache');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存内容
|
||||
*
|
||||
* @param mixed $params
|
||||
* @param mixed $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($params = null)
|
||||
public function get($id = null)
|
||||
{
|
||||
$key = $this->getKey($params);
|
||||
$content = $this->cache->get($key);
|
||||
$lifetime = $this->getLifetime();
|
||||
$key = $this->getKey($id);
|
||||
|
||||
if (!$this->cache->exists($key)) {
|
||||
|
||||
$content = $this->getContent($id);
|
||||
|
||||
$lifetime = $this->getLifetime();
|
||||
|
||||
if (!$content) {
|
||||
$content = $this->getContent($params);
|
||||
$this->cache->save($key, $content, $lifetime);
|
||||
|
||||
} else {
|
||||
$content = $this->cache->get($key);
|
||||
}
|
||||
|
||||
@ -41,35 +46,48 @@ abstract class Cache extends UserComponent
|
||||
/**
|
||||
* 删除缓存内容
|
||||
*
|
||||
* @param mixed $params
|
||||
* @param mixed $id
|
||||
*/
|
||||
public function delete($params = null)
|
||||
public function delete($id = null)
|
||||
{
|
||||
$key = $this->getKey($params);
|
||||
$key = $this->getKey($id);
|
||||
|
||||
$this->cache->delete($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重建缓存内容
|
||||
*
|
||||
* @param mixed $id
|
||||
*/
|
||||
public function rebuild($id = null)
|
||||
{
|
||||
$this->delete($id);
|
||||
|
||||
$this->get($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存有效期
|
||||
*
|
||||
* @return integer
|
||||
* @return int
|
||||
*/
|
||||
abstract protected function getLifetime();
|
||||
abstract public function getLifetime();
|
||||
|
||||
/**
|
||||
* 获取键值
|
||||
*
|
||||
* @param mixed $params
|
||||
* @param mixed $id
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getKey($params = null);
|
||||
abstract public function getKey($id = null);
|
||||
|
||||
/**
|
||||
* 获取原始内容
|
||||
*
|
||||
* @param mixed $params
|
||||
* @param mixed $id
|
||||
* @return mixed
|
||||
*/
|
||||
abstract protected function getContent($params = null);
|
||||
abstract public function getContent($id = null);
|
||||
|
||||
}
|
||||
|
@ -1,57 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Library\Cache;
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Category as CategoryModel;
|
||||
use App\Exceptions\NotFound as ModelNotFoundException;
|
||||
use App\Repos\Category as CategoryRepo;
|
||||
|
||||
class Category extends \Phalcon\Di\Injectable
|
||||
class Category extends Cache
|
||||
{
|
||||
|
||||
private $lifetime = 86400 * 30;
|
||||
|
||||
public function getOrFail($id)
|
||||
{
|
||||
$result = $this->getById($id);
|
||||
|
||||
if (!$result) {
|
||||
throw new ModelNotFoundException('category.not_found');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function get($id)
|
||||
{
|
||||
$cacheOptions = [
|
||||
'key' => $this->getKey($id),
|
||||
'lifetime' => $this->getLifetime(),
|
||||
];
|
||||
|
||||
$result = CategoryModel::query()
|
||||
->where('id = :id:', ['id' => $id])
|
||||
->cache($cacheOptions)
|
||||
->execute()
|
||||
->getFirst();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function delete($id)
|
||||
{
|
||||
$key = $this->getKey($id);
|
||||
|
||||
$this->modelsCache->delete($key);
|
||||
}
|
||||
|
||||
public function getKey($id)
|
||||
{
|
||||
return "category:{$id}";
|
||||
}
|
||||
protected $lifetime = 365 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return "category:{$id}";
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$categoryRepo = new CategoryRepo();
|
||||
|
||||
$category = $categoryRepo->findById($id);
|
||||
|
||||
return $category ?: null;
|
||||
}
|
||||
|
||||
}
|
||||
|
45
app/Caches/CategoryList.php
Normal file
45
app/Caches/CategoryList.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Category as CategoryModel;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
|
||||
class CategoryList extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 365 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($type = null)
|
||||
{
|
||||
return "category_list:{$type}";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $type
|
||||
* @return array
|
||||
*/
|
||||
public function getContent($type = null)
|
||||
{
|
||||
/**
|
||||
* @var Resultset $categories
|
||||
*/
|
||||
$categories = CategoryModel::query()
|
||||
->columns(['id', 'parent_id', 'name', 'priority', 'level', 'path'])
|
||||
->where('type = :type:', ['type' => $type])
|
||||
->andWhere('published = 1')
|
||||
->execute();
|
||||
|
||||
if ($categories->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $categories->toArray();
|
||||
}
|
||||
|
||||
}
|
31
app/Caches/CategoryTreeList.php
Normal file
31
app/Caches/CategoryTreeList.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Builders\CategoryTreeList as CategoryTreeListBuilder;
|
||||
|
||||
class CategoryTreeList extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 365 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($type = null)
|
||||
{
|
||||
return "category_tree_list:{$type}";
|
||||
}
|
||||
|
||||
public function getContent($type = null)
|
||||
{
|
||||
$builder = new CategoryTreeListBuilder();
|
||||
|
||||
$list = $builder->handle($type);
|
||||
|
||||
return $list ?: [];
|
||||
}
|
||||
|
||||
}
|
31
app/Caches/Chapter.php
Normal file
31
app/Caches/Chapter.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Repos\Chapter as ChapterRepo;
|
||||
|
||||
class Chapter extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 1 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return "chapter:{$id}";
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$chapterRepo = new ChapterRepo();
|
||||
|
||||
$chapter = $chapterRepo->findById($id);
|
||||
|
||||
return $chapter ?: null;
|
||||
}
|
||||
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Repos\Config as ConfigRepo;
|
||||
|
||||
class Config extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 365 * 86400;
|
||||
|
||||
/**
|
||||
* 获取某组配置项
|
||||
*
|
||||
* @param string $section
|
||||
* @return \stdClass|null
|
||||
*/
|
||||
public function getSectionConfig($section)
|
||||
{
|
||||
$items = $this->get();
|
||||
|
||||
if (!$items) return;
|
||||
|
||||
$result = new \stdClass();
|
||||
|
||||
foreach ($items as $item) {
|
||||
if ($item->section == $section) {
|
||||
$result->{$item->item_key} = $item->item_value;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某个配置项的值
|
||||
*
|
||||
* @param string $section
|
||||
* @param string $key
|
||||
* @return string|null
|
||||
*/
|
||||
public function getItemValue($section, $key)
|
||||
{
|
||||
$config = $this->getSectionConfig($section);
|
||||
|
||||
$result = $config->{$key} ?? null;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
protected function getKey($params = null)
|
||||
{
|
||||
return 'site_config';
|
||||
}
|
||||
|
||||
protected function getContent($params = null)
|
||||
{
|
||||
$configRepo = new ConfigRepo();
|
||||
|
||||
$items = $configRepo->findAll();
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
}
|
139
app/Caches/Counter.php
Normal file
139
app/Caches/Counter.php
Normal file
@ -0,0 +1,139 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Library\Cache\Backend\Redis as RedisCache;
|
||||
use Phalcon\Mvc\User\Component;
|
||||
|
||||
abstract class Counter extends Component
|
||||
{
|
||||
|
||||
/**
|
||||
* @var RedisCache
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* @var \Redis
|
||||
*/
|
||||
protected $redis;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->cache = $this->getDI()->getShared('cache');
|
||||
|
||||
$this->redis = $this->cache->getRedis();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存内容
|
||||
*
|
||||
* @param mixed $id
|
||||
* @return array
|
||||
*/
|
||||
public function get($id = null)
|
||||
{
|
||||
$key = $this->getKey($id);
|
||||
|
||||
$content = $this->redis->hGetAll($key);
|
||||
|
||||
if (!$this->cache->exists($key)) {
|
||||
|
||||
$content = $this->getContent($id);
|
||||
$lifetime = $this->getLifetime();
|
||||
|
||||
$this->redis->hMSet($key, $content);
|
||||
$this->redis->expire($key, $lifetime);
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存内容
|
||||
*
|
||||
* @param mixed $id
|
||||
*/
|
||||
public function delete($id = null)
|
||||
{
|
||||
$key = $this->getKey($id);
|
||||
|
||||
$this->cache->delete($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重建缓存内容
|
||||
*
|
||||
* @param mixed $id
|
||||
*/
|
||||
public function rebuild($id = null)
|
||||
{
|
||||
$this->delete($id);
|
||||
|
||||
$this->get($id);
|
||||
}
|
||||
|
||||
public function hGet($id, $hashKey)
|
||||
{
|
||||
$key = $this->getKey($id);
|
||||
|
||||
if (!$this->redis->exists($key)) {
|
||||
$this->get($id);
|
||||
}
|
||||
|
||||
return $this->redis->hGet($key, $hashKey);
|
||||
}
|
||||
|
||||
public function hDel($id, $hashKey)
|
||||
{
|
||||
$key = $this->getKey($id);
|
||||
|
||||
return $this->redis->hDel($key, $hashKey);
|
||||
}
|
||||
|
||||
public function hIncrBy($id, $hashKey, $value = 1)
|
||||
{
|
||||
$key = $this->getKey($id);
|
||||
|
||||
if (!$this->redis->exists($key)) {
|
||||
$this->get($id);
|
||||
}
|
||||
|
||||
$this->redis->hIncrBy($key, $hashKey, $value);
|
||||
}
|
||||
|
||||
public function hDecrBy($id, $hashKey, $value = 1)
|
||||
{
|
||||
$key = $this->getKey($id);
|
||||
|
||||
if (!$this->redis->exists($key)) {
|
||||
$this->get($id);
|
||||
}
|
||||
|
||||
$this->redis->hIncrBy($key, $hashKey, 0 - $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存有效期
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
abstract public function getLifetime();
|
||||
|
||||
/**
|
||||
* 获取键值
|
||||
*
|
||||
* @param mixed $id
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getKey($id = null);
|
||||
|
||||
/**
|
||||
* 获取原始内容
|
||||
*
|
||||
* @param mixed $id
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function getContent($id = null);
|
||||
|
||||
}
|
@ -1,57 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Library\Cache;
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Course as CourseModel;
|
||||
use App\Exceptions\NotFound as ModelNotFoundException;
|
||||
use App\Repos\Course as CourseRepo;
|
||||
|
||||
class Course extends \Phalcon\Di\Injectable
|
||||
class Course extends Cache
|
||||
{
|
||||
|
||||
private $lifetime = 86400;
|
||||
|
||||
public function getOrFail($id)
|
||||
{
|
||||
$result = $this->getById($id);
|
||||
|
||||
if (!$result) {
|
||||
throw new ModelNotFoundException('course.not_found');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function get($id)
|
||||
{
|
||||
$cacheOptions = [
|
||||
'key' => $this->getKey($id),
|
||||
'lifetime' => $this->getLifetime(),
|
||||
];
|
||||
|
||||
$result = CourseModel::query()
|
||||
->where('id = :id:', ['id' => $id])
|
||||
->cache($cacheOptions)
|
||||
->execute()
|
||||
->getFirst();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function delete($id)
|
||||
{
|
||||
$key = $this->getKey($id);
|
||||
|
||||
$this->modelsCache->delete($key);
|
||||
}
|
||||
|
||||
public function getKey($id)
|
||||
{
|
||||
return "course:{$id}";
|
||||
}
|
||||
protected $lifetime = 1 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return "course:{$id}";
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$courseRepo = new CourseRepo();
|
||||
|
||||
$course = $courseRepo->findById($id);
|
||||
|
||||
return $course ?: null;
|
||||
}
|
||||
|
||||
}
|
||||
|
54
app/Caches/CourseCategoryList.php
Normal file
54
app/Caches/CourseCategoryList.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Category as CategoryModel;
|
||||
use App\Repos\Course as CourseRepo;
|
||||
|
||||
class CourseCategoryList extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 1 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return "course_category_list:{$id}";
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$courseRepo = new CourseRepo();
|
||||
|
||||
$categories = $courseRepo->findCategories($id);
|
||||
|
||||
if ($categories->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->handleContent($categories);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CategoryModel[] $categories
|
||||
* @return array
|
||||
*/
|
||||
public function handleContent($categories)
|
||||
{
|
||||
$result = [];
|
||||
|
||||
foreach ($categories as $category) {
|
||||
$result[] = [
|
||||
'id' => $category->id,
|
||||
'name' => $category->name,
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
31
app/Caches/CourseChapterList.php
Normal file
31
app/Caches/CourseChapterList.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Builders\CourseChapterList as CourseChapterListBuilder;
|
||||
|
||||
class CourseChapterList extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 7 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return "course_chapter_list:{$id}";
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$builder = new CourseChapterListBuilder();
|
||||
|
||||
$list = $builder->handle($id);
|
||||
|
||||
return $list ?: [];
|
||||
}
|
||||
|
||||
}
|
57
app/Caches/CoursePackageList.php
Normal file
57
app/Caches/CoursePackageList.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Package as PackageModel;
|
||||
use App\Repos\Course as CourseRepo;
|
||||
|
||||
class CoursePackageList extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 1 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return "course_package_list:{$id}";
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$courseRepo = new CourseRepo();
|
||||
|
||||
$packages = $courseRepo->findPackages($id);
|
||||
|
||||
if ($packages->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->handleContent($packages);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PackageModel[] $packages
|
||||
* @return array
|
||||
*/
|
||||
protected function handleContent($packages)
|
||||
{
|
||||
$result = [];
|
||||
|
||||
foreach ($packages as $package) {
|
||||
$result[] = [
|
||||
'id' => $package->id,
|
||||
'title' => $package->title,
|
||||
'course_count' => $package->course_count,
|
||||
'market_price' => $package->market_price,
|
||||
'vip_price' => $package->vip_price,
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
74
app/Caches/CourseRecommendedList.php
Normal file
74
app/Caches/CourseRecommendedList.php
Normal file
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Course as CourseModel;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class CourseRecommendedList extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 1 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return "course_recommended_list:{$id}";
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$courses = $this->findCourses(5);
|
||||
|
||||
if ($courses->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->handleContent($courses);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CourseModel[] $courses
|
||||
* @return array
|
||||
*/
|
||||
public function handleContent($courses)
|
||||
{
|
||||
$result = [];
|
||||
|
||||
foreach ($courses as $course) {
|
||||
|
||||
$result[] = [
|
||||
'id' => $course->id,
|
||||
'title' => $course->title,
|
||||
'cover' => $course->cover,
|
||||
'market_price' => $course->market_price,
|
||||
'vip_price' => $course->vip_price,
|
||||
'model' => $course->model,
|
||||
'level' => $course->level,
|
||||
'user_count' => $course->user_count,
|
||||
'lesson_count' => $course->lesson_count,
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|CourseModel[]
|
||||
*/
|
||||
public function findCourses($limit = 5)
|
||||
{
|
||||
return CourseModel::query()
|
||||
->where('published = 1 AND market_price > 0')
|
||||
->orderBy('RAND()')
|
||||
->limit($limit)
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
62
app/Caches/CourseRelatedList.php
Normal file
62
app/Caches/CourseRelatedList.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Course as CourseModel;
|
||||
use App\Repos\Course as CourseRepo;
|
||||
|
||||
class CourseRelatedList extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 1 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return "course_related_list:{$id}";
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$courseRepo = new CourseRepo();
|
||||
|
||||
$courses = $courseRepo->findRelatedCourses($id);
|
||||
|
||||
if ($courses->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->handleContent($courses);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CourseModel[] $courses
|
||||
* @return array
|
||||
*/
|
||||
public function handleContent($courses)
|
||||
{
|
||||
$result = [];
|
||||
|
||||
foreach ($courses as $course) {
|
||||
|
||||
$result[] = [
|
||||
'id' => $course->id,
|
||||
'title' => $course->title,
|
||||
'cover' => $course->cover,
|
||||
'market_price' => $course->market_price,
|
||||
'vip_price' => $course->vip_price,
|
||||
'model' => $course->model,
|
||||
'level' => $course->level,
|
||||
'user_count' => $course->user_count,
|
||||
'lesson_count' => $course->lesson_count,
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
57
app/Caches/CourseTeacherList.php
Normal file
57
app/Caches/CourseTeacherList.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\User as UserModel;
|
||||
use App\Repos\Course as CourseRepo;
|
||||
|
||||
class CourseTeacherList extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 1 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return "course_teacher_list:{$id}";
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$courseRepo = new CourseRepo();
|
||||
|
||||
$users = $courseRepo->findTeachers($id);
|
||||
|
||||
if ($users->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->handleContent($users);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UserModel[] $users
|
||||
* @return array
|
||||
*/
|
||||
public function handleContent($users)
|
||||
{
|
||||
$result = [];
|
||||
|
||||
foreach ($users as $user) {
|
||||
$result[] = [
|
||||
'id' => $user->id,
|
||||
'name' => $user->name,
|
||||
'avatar' => $user->avatar,
|
||||
'title' => $user->title,
|
||||
'about' => $user->about,
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
67
app/Caches/CourseTopicList.php
Normal file
67
app/Caches/CourseTopicList.php
Normal file
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Topic as TopicModel;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class CourseTopicList extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 1 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return "course_topic_list:{$id}";
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$topics = $this->findTopics(5);
|
||||
|
||||
if ($topics->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->handleContent($topics);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TopicModel[] $topics
|
||||
* @return array
|
||||
*/
|
||||
public function handleContent($topics)
|
||||
{
|
||||
$result = [];
|
||||
|
||||
foreach ($topics as $topic) {
|
||||
|
||||
$result[] = [
|
||||
'id' => $topic->id,
|
||||
'title' => $topic->title,
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|TopicModel[]
|
||||
*/
|
||||
public function findTopics($limit = 5)
|
||||
{
|
||||
return TopicModel::query()
|
||||
->where('published = 1')
|
||||
->orderBy('RAND()')
|
||||
->limit($limit)
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
31
app/Caches/Help.php
Normal file
31
app/Caches/Help.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Repos\Help as HelpRepo;
|
||||
|
||||
class Help extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 7 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return "help:{$id}";
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$helpRepo = new HelpRepo();
|
||||
|
||||
$help = $helpRepo->findById($id);
|
||||
|
||||
return $help ?: null;
|
||||
}
|
||||
|
||||
}
|
89
app/Caches/HelpList.php
Normal file
89
app/Caches/HelpList.php
Normal file
@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Category as CategoryModel;
|
||||
use App\Models\Help as HelpModel;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class HelpList extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 365 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'help_list';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
|
||||
$categories = $this->findCategories();
|
||||
|
||||
if ($categories->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($categories as $category) {
|
||||
|
||||
$item = [];
|
||||
|
||||
$item['category'] = [
|
||||
'id' => $category->id,
|
||||
'name' => $category->name,
|
||||
];
|
||||
|
||||
$item['helps'] = [];
|
||||
|
||||
$helps = $this->findHelps($category->id);
|
||||
|
||||
if ($helps->count() > 0) {
|
||||
foreach ($helps as $help) {
|
||||
$item['helps'][] = [
|
||||
'id' => $help->id,
|
||||
'title' => $help->title,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$result[] = $item;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ResultsetInterface|Resultset|CategoryModel[]
|
||||
*/
|
||||
protected function findCategories()
|
||||
{
|
||||
return CategoryModel::query()
|
||||
->where('type = :type:', ['type' => CategoryModel::TYPE_HELP])
|
||||
->andWhere('level = 1 AND published = 1')
|
||||
->orderBy('priority ASC')
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $categoryId
|
||||
* @return ResultsetInterface|Resultset|CategoryModel[]
|
||||
*/
|
||||
protected function findHelps($categoryId)
|
||||
{
|
||||
return HelpModel::query()
|
||||
->where('category_id = :category_id:', ['category_id' => $categoryId])
|
||||
->andWhere('published = 1')
|
||||
->orderBy('priority ASC')
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
85
app/Caches/ImActiveGroupList.php
Normal file
85
app/Caches/ImActiveGroupList.php
Normal file
@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\ImMessage;
|
||||
use App\Models\ImMessage as ImMessageModel;
|
||||
use App\Models\User as UserModel;
|
||||
use App\Repos\ImGroup as ImGroupRepo;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class ImActiveGroupList extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 1 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'im_active_group_list';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$groups = $this->findGroups();
|
||||
|
||||
if (empty($groups)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($groups as $group) {
|
||||
$result[] = [
|
||||
'id' => $group->id,
|
||||
'type' => $group->type,
|
||||
'name' => $group->name,
|
||||
'avatar' => $group->avatar,
|
||||
'about' => $group->about,
|
||||
'user_count' => $group->user_count,
|
||||
'msg_count' => $group->msg_count,
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $days
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|UserModel[]
|
||||
*/
|
||||
protected function findGroups($days = 7, $limit = 12)
|
||||
{
|
||||
$result = [];
|
||||
|
||||
$startTime = strtotime("-{$days} days");
|
||||
$endTime = time();
|
||||
|
||||
$rows = ImMessageModel::query()
|
||||
->columns(['receiver_id', 'total_count' => 'count(receiver_id)'])
|
||||
->groupBy('receiver_id')
|
||||
->orderBy('total_count DESC')
|
||||
->where('receiver_type = :type:', ['type' => ImMessageModel::TYPE_GROUP])
|
||||
->betweenWhere('create_time', $startTime, $endTime)
|
||||
->limit($limit)
|
||||
->execute();
|
||||
|
||||
if ($rows->count() > 0) {
|
||||
|
||||
$ids = kg_array_column($rows->toArray(), 'receiver_id');
|
||||
|
||||
$groupRepo = new ImGroupRepo();
|
||||
|
||||
$result = $groupRepo->findByIds($ids);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
82
app/Caches/ImActiveUserList.php
Normal file
82
app/Caches/ImActiveUserList.php
Normal file
@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\ImMessage as ImMessageModel;
|
||||
use App\Models\User as UserModel;
|
||||
use App\Repos\User as UserRepo;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class ImActiveUserList extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 1 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'im_active_user_list';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$users = $this->findUsers($id);
|
||||
|
||||
if (empty($users)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($users as $user) {
|
||||
$result[] = [
|
||||
'id' => $user->id,
|
||||
'name' => $user->name,
|
||||
'avatar' => $user->avatar,
|
||||
'title' => $user->title,
|
||||
'about' => $user->about,
|
||||
'vip' => $user->vip,
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $days
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|UserModel[]
|
||||
*/
|
||||
protected function findUsers($days = 7, $limit = 12)
|
||||
{
|
||||
$result = [];
|
||||
|
||||
$startTime = strtotime("-{$days} days");
|
||||
$endTime = time();
|
||||
|
||||
$rows = ImMessageModel::query()
|
||||
->columns(['sender_id', 'total_count' => 'count(sender_id)'])
|
||||
->groupBy('sender_id')
|
||||
->orderBy('total_count DESC')
|
||||
->betweenWhere('create_time', $startTime, $endTime)
|
||||
->limit($limit)
|
||||
->execute();
|
||||
|
||||
if ($rows->count() > 0) {
|
||||
|
||||
$ids = kg_array_column($rows->toArray(), 'sender_id');
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$result = $userRepo->findByIds($ids);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
31
app/Caches/ImGroup.php
Normal file
31
app/Caches/ImGroup.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Repos\ImGroup as ImGroupRepo;
|
||||
|
||||
class ImGroup extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 365 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return "im_group:{$id}";
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$groupRepo = new ImGroupRepo();
|
||||
|
||||
$group = $groupRepo->findById($id);
|
||||
|
||||
return $group ?: null;
|
||||
}
|
||||
|
||||
}
|
85
app/Caches/ImGroupActiveUserList.php
Normal file
85
app/Caches/ImGroupActiveUserList.php
Normal file
@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\ImMessage as ImMessageModel;
|
||||
use App\Models\User as UserModel;
|
||||
use App\Repos\User as UserRepo;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class ImGroupActiveUserList extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 1 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return "im_group_active_user_list:{$id}";
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$users = $this->findUsers($id);
|
||||
|
||||
if (empty($users)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($users as $user) {
|
||||
$result[] = [
|
||||
'id' => $user->id,
|
||||
'name' => $user->name,
|
||||
'avatar' => $user->avatar,
|
||||
'title' => $user->title,
|
||||
'about' => $user->about,
|
||||
'vip' => $user->vip,
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $groupId
|
||||
* @param int $days
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|UserModel[]
|
||||
*/
|
||||
protected function findUsers($groupId, $days = 7, $limit = 5)
|
||||
{
|
||||
$result = [];
|
||||
|
||||
$startTime = strtotime("-{$days} days");
|
||||
$endTime = time();
|
||||
|
||||
$rows = ImMessageModel::query()
|
||||
->columns(['sender_id', 'total_count' => 'count(sender_id)'])
|
||||
->groupBy('sender_id')
|
||||
->orderBy('total_count DESC')
|
||||
->where('receiver_id = :group_id:', ['group_id' => $groupId])
|
||||
->andWhere('receiver_type = :type:', ['type' => ImMessageModel::TYPE_GROUP])
|
||||
->betweenWhere('create_time', $startTime, $endTime)
|
||||
->limit($limit)
|
||||
->execute();
|
||||
|
||||
if ($rows->count() > 0) {
|
||||
|
||||
$ids = kg_array_column($rows->toArray(), 'sender_id');
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$result = $userRepo->findByIds($ids);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
73
app/Caches/ImNewGroupList.php
Normal file
73
app/Caches/ImNewGroupList.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\ImGroup as ImGroupModel;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class ImNewGroupList extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 1 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'im_new_group_list';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$limit = 12;
|
||||
|
||||
$groups = $this->findGroups($limit);
|
||||
|
||||
if ($groups->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->handleContent($groups);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ImGroupModel[] $groups
|
||||
* @return array
|
||||
*/
|
||||
protected function handleContent($groups)
|
||||
{
|
||||
$result = [];
|
||||
|
||||
foreach ($groups as $group) {
|
||||
$result[] = [
|
||||
'id' => $group->id,
|
||||
'type' => $group->type,
|
||||
'name' => $group->name,
|
||||
'avatar' => $group->avatar,
|
||||
'about' => $group->about,
|
||||
'user_count' => $group->user_count,
|
||||
'msg_count' => $group->msg_count,
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|ImGroupModel[]
|
||||
*/
|
||||
public function findGroups($limit = 12)
|
||||
{
|
||||
return ImGroupModel::query()
|
||||
->where('published = 1')
|
||||
->orderBy('id DESC')
|
||||
->limit($limit)
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
72
app/Caches/ImNewUserList.php
Normal file
72
app/Caches/ImNewUserList.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\User as UserModel;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class ImNewUserList extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 1 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'im_new_user_list';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$limit = 12;
|
||||
|
||||
$users = $this->findUsers($limit);
|
||||
|
||||
if ($users->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->handleContent($users);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UserModel[] $users
|
||||
* @return array
|
||||
*/
|
||||
protected function handleContent($users)
|
||||
{
|
||||
$result = [];
|
||||
|
||||
foreach ($users as $user) {
|
||||
$result[] = [
|
||||
'id' => $user->id,
|
||||
'name' => $user->name,
|
||||
'avatar' => $user->avatar,
|
||||
'title' => $user->title,
|
||||
'about' => $user->about,
|
||||
'vip' => $user->vip,
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|UserModel[]
|
||||
*/
|
||||
public function findUsers($limit = 12)
|
||||
{
|
||||
return UserModel::query()
|
||||
->where('deleted = 0')
|
||||
->orderBy('id DESC')
|
||||
->limit($limit)
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
118
app/Caches/IndexFreeCourseList.php
Normal file
118
app/Caches/IndexFreeCourseList.php
Normal file
@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Category as CategoryModel;
|
||||
use App\Models\Course as CourseModel;
|
||||
use App\Services\Category as CategoryService;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
/**
|
||||
* 免费课程
|
||||
*/
|
||||
class IndexFreeCourseList extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 1 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'index_free_course_list';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$categoryLimit = 5;
|
||||
|
||||
$courseLimit = 8;
|
||||
|
||||
$categories = $this->findCategories($categoryLimit);
|
||||
|
||||
if ($categories->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($categories as $category) {
|
||||
|
||||
$item = [];
|
||||
|
||||
$item['category'] = [
|
||||
'id' => $category->id,
|
||||
'name' => $category->name,
|
||||
];
|
||||
|
||||
$item['courses'] = [];
|
||||
|
||||
$courses = $this->findCategoryCourses($category->id, $courseLimit);
|
||||
|
||||
if ($courses->count() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$categoryCourses = [];
|
||||
|
||||
foreach ($courses as $course) {
|
||||
$categoryCourses[] = [
|
||||
'id' => $course->id,
|
||||
'title' => $course->title,
|
||||
'cover' => $course->cover,
|
||||
'market_price' => $course->market_price,
|
||||
'vip_price' => $course->vip_price,
|
||||
'model' => $course->model,
|
||||
'level' => $course->level,
|
||||
'user_count' => $course->user_count,
|
||||
'lesson_count' => $course->lesson_count,
|
||||
];
|
||||
}
|
||||
|
||||
$item['courses'] = $categoryCourses;
|
||||
|
||||
$result[] = $item;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|CategoryModel[]
|
||||
*/
|
||||
protected function findCategories($limit = 5)
|
||||
{
|
||||
return CategoryModel::query()
|
||||
->where('type = :type:', ['type' => CategoryModel::TYPE_COURSE])
|
||||
->andWhere('level = 1 AND published = 1')
|
||||
->orderBy('priority ASC')
|
||||
->limit($limit)
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $categoryId
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|CourseModel[]
|
||||
*/
|
||||
protected function findCategoryCourses($categoryId, $limit = 8)
|
||||
{
|
||||
$categoryService = new CategoryService();
|
||||
|
||||
$categoryIds = $categoryService->getChildCategoryIds($categoryId);
|
||||
|
||||
return CourseModel::query()
|
||||
->inWhere('category_id', $categoryIds)
|
||||
->andWhere('published = 1')
|
||||
->andWhere('market_price = 0')
|
||||
->orderBy('score DESC')
|
||||
->limit($limit)
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
124
app/Caches/IndexLiveList.php
Normal file
124
app/Caches/IndexLiveList.php
Normal file
@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\ChapterLive as ChapterLiveModel;
|
||||
use App\Repos\Chapter as ChapterRepo;
|
||||
use App\Repos\Course as CourseRepo;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
|
||||
/**
|
||||
* 直播课程
|
||||
*/
|
||||
class IndexLiveList extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 1 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'index_live_list';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
/**
|
||||
* 限制输出多少天数(一维限额)
|
||||
*/
|
||||
$dayLimit = 3;
|
||||
|
||||
/**
|
||||
* 限制每天维度下的输出数(二维限额)
|
||||
*/
|
||||
$perDayLimit = 10;
|
||||
|
||||
$beginTime = strtotime('today');
|
||||
$endTime = strtotime("+30 days");
|
||||
|
||||
/**
|
||||
* @var Resultset|ChapterLiveModel[] $lives
|
||||
*/
|
||||
$lives = ChapterLiveModel::query()
|
||||
->betweenWhere('start_time', $beginTime, $endTime)
|
||||
->orderBy('start_time ASC')
|
||||
->execute();
|
||||
|
||||
if ($lives->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
$chapterIds = kg_array_column($lives->toArray(), 'chapter_id');
|
||||
|
||||
$chapterRepo = new ChapterRepo();
|
||||
|
||||
$chapters = $chapterRepo->findByIds($chapterIds);
|
||||
|
||||
$chapterMapping = [];
|
||||
|
||||
foreach ($chapters as $chapter) {
|
||||
$chapterMapping[$chapter->id] = $chapter;
|
||||
}
|
||||
|
||||
$courseIds = kg_array_column($lives->toArray(), 'course_id');
|
||||
|
||||
$courseRepo = new CourseRepo();
|
||||
|
||||
$courses = $courseRepo->findByIds($courseIds);
|
||||
|
||||
$courseMapping = [];
|
||||
|
||||
foreach ($courses as $course) {
|
||||
$courseMapping[$course->id] = $course;
|
||||
}
|
||||
|
||||
foreach ($lives as $live) {
|
||||
|
||||
if (count($result) >= $dayLimit) {
|
||||
break;
|
||||
}
|
||||
|
||||
$day = date('y-m-d', $live->start_time);
|
||||
|
||||
if (isset($result[$day]) && count($result[$day]) >= $perDayLimit) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$chapter = $chapterMapping[$live->chapter_id];
|
||||
$course = $courseMapping[$chapter->course_id];
|
||||
|
||||
$chapterInfo = [
|
||||
'id' => $chapter->id,
|
||||
'title' => $chapter->title,
|
||||
'start_time' => $live->start_time,
|
||||
'end_time' => $live->end_time,
|
||||
];
|
||||
|
||||
$courseInfo = [
|
||||
'id' => $course->id,
|
||||
'title' => $course->title,
|
||||
'cover' => $course->cover,
|
||||
'market_price' => $course->market_price,
|
||||
'vip_price' => $course->vip_price,
|
||||
'model' => $course->model,
|
||||
'level' => $course->level,
|
||||
'user_count' => $course->user_count,
|
||||
'lesson_count' => $course->lesson_count,
|
||||
];
|
||||
|
||||
$result[$day][] = [
|
||||
'course' => $courseInfo,
|
||||
'chapter' => $chapterInfo,
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
117
app/Caches/IndexNewCourseList.php
Normal file
117
app/Caches/IndexNewCourseList.php
Normal file
@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Category as CategoryModel;
|
||||
use App\Models\Course as CourseModel;
|
||||
use App\Services\Category as CategoryService;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
/**
|
||||
* 新上课程
|
||||
*/
|
||||
class IndexNewCourseList extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 1 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'index_new_course_list';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$categoryLimit = 5;
|
||||
|
||||
$courseLimit = 8;
|
||||
|
||||
$categories = $this->findCategories($categoryLimit);
|
||||
|
||||
if ($categories->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($categories as $category) {
|
||||
|
||||
$item = [];
|
||||
|
||||
$item['category'] = [
|
||||
'id' => $category->id,
|
||||
'name' => $category->name,
|
||||
];
|
||||
|
||||
$item['courses'] = [];
|
||||
|
||||
$courses = $this->findCategoryCourses($category->id, $courseLimit);
|
||||
|
||||
if ($courses->count() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$categoryCourses = [];
|
||||
|
||||
foreach ($courses as $course) {
|
||||
$categoryCourses[] = [
|
||||
'id' => $course->id,
|
||||
'title' => $course->title,
|
||||
'cover' => $course->cover,
|
||||
'market_price' => $course->market_price,
|
||||
'vip_price' => $course->vip_price,
|
||||
'model' => $course->model,
|
||||
'level' => $course->level,
|
||||
'user_count' => $course->user_count,
|
||||
'lesson_count' => $course->lesson_count,
|
||||
];
|
||||
}
|
||||
|
||||
$item['courses'] = $categoryCourses;
|
||||
|
||||
$result[] = $item;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|CategoryModel[]
|
||||
*/
|
||||
protected function findCategories($limit = 5)
|
||||
{
|
||||
return CategoryModel::query()
|
||||
->where('type = :type:', ['type' => CategoryModel::TYPE_COURSE])
|
||||
->andWhere('level = 1 AND published = 1')
|
||||
->orderBy('priority ASC')
|
||||
->limit($limit)
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $categoryId
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|CourseModel[]
|
||||
*/
|
||||
protected function findCategoryCourses($categoryId, $limit = 8)
|
||||
{
|
||||
$categoryService = new CategoryService();
|
||||
|
||||
$categoryIds = $categoryService->getChildCategoryIds($categoryId);
|
||||
|
||||
return CourseModel::query()
|
||||
->inWhere('category_id', $categoryIds)
|
||||
->andWhere('published = 1')
|
||||
->orderBy('id DESC')
|
||||
->limit($limit)
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
70
app/Caches/IndexSimpleFreeCourseList.php
Normal file
70
app/Caches/IndexSimpleFreeCourseList.php
Normal file
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Course as CourseModel;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
/**
|
||||
* 简版免费课程
|
||||
*/
|
||||
class IndexSimpleFreeCourseList extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 1 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'index_simple_free_course_list';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$limit = 8;
|
||||
|
||||
$courses = $this->findCourses($limit);
|
||||
|
||||
if ($courses->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($courses as $course) {
|
||||
$result[] = [
|
||||
'id' => $course->id,
|
||||
'title' => $course->title,
|
||||
'cover' => $course->cover,
|
||||
'market_price' => $course->market_price,
|
||||
'vip_price' => $course->vip_price,
|
||||
'model' => $course->model,
|
||||
'level' => $course->level,
|
||||
'user_count' => $course->user_count,
|
||||
'lesson_count' => $course->lesson_count,
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|CourseModel[]
|
||||
*/
|
||||
protected function findCourses($limit = 8)
|
||||
{
|
||||
return CourseModel::query()
|
||||
->where('published = 1')
|
||||
->andWhere('market_price = 0')
|
||||
->orderBy('score DESC')
|
||||
->limit($limit)
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
69
app/Caches/IndexSimpleNewCourseList.php
Normal file
69
app/Caches/IndexSimpleNewCourseList.php
Normal file
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Course as CourseModel;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
/**
|
||||
* 简版新上课程
|
||||
*/
|
||||
class IndexSimpleNewCourseList extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 1 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'index_simple_new_course_list';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$limit = 8;
|
||||
|
||||
$courses = $this->findCourses($limit);
|
||||
|
||||
if ($courses->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($courses as $course) {
|
||||
$result[] = [
|
||||
'id' => $course->id,
|
||||
'title' => $course->title,
|
||||
'cover' => $course->cover,
|
||||
'market_price' => $course->market_price,
|
||||
'vip_price' => $course->vip_price,
|
||||
'model' => $course->model,
|
||||
'level' => $course->level,
|
||||
'user_count' => $course->user_count,
|
||||
'lesson_count' => $course->lesson_count,
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|CourseModel[]
|
||||
*/
|
||||
protected function findCourses($limit = 8)
|
||||
{
|
||||
return CourseModel::query()
|
||||
->where('published = 1')
|
||||
->orderBy('id DESC')
|
||||
->limit($limit)
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
70
app/Caches/IndexSimpleVipCourseList.php
Normal file
70
app/Caches/IndexSimpleVipCourseList.php
Normal file
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Course as CourseModel;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
/**
|
||||
* 简版会员课程
|
||||
*/
|
||||
class IndexSimpleVipCourseList extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 1 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'index_simple_vip_course_list';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$limit = 8;
|
||||
|
||||
$courses = $this->findCourses($limit);
|
||||
|
||||
if ($courses->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($courses as $course) {
|
||||
$result[] = [
|
||||
'id' => $course->id,
|
||||
'title' => $course->title,
|
||||
'cover' => $course->cover,
|
||||
'market_price' => $course->market_price,
|
||||
'vip_price' => $course->vip_price,
|
||||
'model' => $course->model,
|
||||
'level' => $course->level,
|
||||
'user_count' => $course->user_count,
|
||||
'lesson_count' => $course->lesson_count,
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|CourseModel[]
|
||||
*/
|
||||
protected function findCourses($limit = 8)
|
||||
{
|
||||
return CourseModel::query()
|
||||
->where('published = 1')
|
||||
->andWhere('vip_price >= 0')
|
||||
->orderBy('score DESC')
|
||||
->limit($limit)
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
71
app/Caches/IndexSlideList.php
Normal file
71
app/Caches/IndexSlideList.php
Normal file
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Slide as SlideModel;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class IndexSlideList extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 365 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'index_slide_list';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$limit = 5;
|
||||
|
||||
$slides = $this->findSlides($limit);
|
||||
|
||||
if ($slides->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->handleContent($slides);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SlideModel[] $slides
|
||||
* @return array
|
||||
*/
|
||||
protected function handleContent($slides)
|
||||
{
|
||||
$result = [];
|
||||
|
||||
foreach ($slides as $slide) {
|
||||
$result[] = [
|
||||
'id' => $slide->id,
|
||||
'title' => $slide->title,
|
||||
'cover' => $slide->cover,
|
||||
'target' => $slide->target,
|
||||
'content' => $slide->content,
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|SlideModel[]
|
||||
*/
|
||||
public function findSlides($limit = 5)
|
||||
{
|
||||
return SlideModel::query()
|
||||
->where('published = 1')
|
||||
->orderBy('priority ASC')
|
||||
->limit($limit)
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
118
app/Caches/IndexVipCourseList.php
Normal file
118
app/Caches/IndexVipCourseList.php
Normal file
@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Category as CategoryModel;
|
||||
use App\Models\Course as CourseModel;
|
||||
use App\Services\Category as CategoryService;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
/**
|
||||
* 会员特价课程
|
||||
*/
|
||||
class IndexVipCourseList extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 1 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'index_vip_course_list';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$categoryLimit = 5;
|
||||
|
||||
$courseLimit = 8;
|
||||
|
||||
$categories = $this->findCategories($categoryLimit);
|
||||
|
||||
if ($categories->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($categories as $category) {
|
||||
|
||||
$item = [];
|
||||
|
||||
$item['category'] = [
|
||||
'id' => $category->id,
|
||||
'name' => $category->name,
|
||||
];
|
||||
|
||||
$item['courses'] = [];
|
||||
|
||||
$courses = $this->findCategoryCourses($category->id, $courseLimit);
|
||||
|
||||
if ($courses->count() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$categoryCourses = [];
|
||||
|
||||
foreach ($courses as $course) {
|
||||
$categoryCourses[] = [
|
||||
'id' => $course->id,
|
||||
'title' => $course->title,
|
||||
'cover' => $course->cover,
|
||||
'market_price' => $course->market_price,
|
||||
'vip_price' => $course->vip_price,
|
||||
'model' => $course->model,
|
||||
'level' => $course->level,
|
||||
'user_count' => $course->user_count,
|
||||
'lesson_count' => $course->lesson_count,
|
||||
];
|
||||
}
|
||||
|
||||
$item['courses'] = $categoryCourses;
|
||||
|
||||
$result[] = $item;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|CategoryModel[]
|
||||
*/
|
||||
protected function findCategories($limit = 5)
|
||||
{
|
||||
return CategoryModel::query()
|
||||
->where('type = :type:', ['type' => CategoryModel::TYPE_COURSE])
|
||||
->andWhere('level = 1 AND published = 1')
|
||||
->orderBy('priority ASC')
|
||||
->limit($limit)
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $categoryId
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|CourseModel[]
|
||||
*/
|
||||
protected function findCategoryCourses($categoryId, $limit = 8)
|
||||
{
|
||||
$categoryService = new CategoryService();
|
||||
|
||||
$categoryIds = $categoryService->getChildCategoryIds($categoryId);
|
||||
|
||||
return CourseModel::query()
|
||||
->inWhere('category_id', $categoryIds)
|
||||
->andWhere('published = 1')
|
||||
->andWhere('vip_price >= 0')
|
||||
->orderBy('score DESC')
|
||||
->limit($limit)
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
29
app/Caches/MaxCategoryId.php
Normal file
29
app/Caches/MaxCategoryId.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Category as CategoryModel;
|
||||
|
||||
class MaxCategoryId extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 365 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'max_category_id';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$category = CategoryModel::findFirst(['order' => 'id DESC']);
|
||||
|
||||
return $category->id ?? 0;
|
||||
}
|
||||
|
||||
}
|
29
app/Caches/MaxChapterId.php
Normal file
29
app/Caches/MaxChapterId.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Chapter as ChapterModel;
|
||||
|
||||
class MaxChapterId extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 365 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'max_chapter_id';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$chapter = ChapterModel::findFirst(['order' => 'id DESC']);
|
||||
|
||||
return $chapter->id ?? 0;
|
||||
}
|
||||
|
||||
}
|
29
app/Caches/MaxCourseId.php
Normal file
29
app/Caches/MaxCourseId.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Course as CourseModel;
|
||||
|
||||
class MaxCourseId extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 365 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'max_course_id';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$course = CourseModel::findFirst(['order' => 'id DESC']);
|
||||
|
||||
return $course->id ?? 0;
|
||||
}
|
||||
|
||||
}
|
29
app/Caches/MaxHelpId.php
Normal file
29
app/Caches/MaxHelpId.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Help as HelpModel;
|
||||
|
||||
class MaxHelpId extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 365 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'max_help_id';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$help = HelpModel::findFirst(['order' => 'id DESC']);
|
||||
|
||||
return $help->id ?? 0;
|
||||
}
|
||||
|
||||
}
|
29
app/Caches/MaxImGroupId.php
Normal file
29
app/Caches/MaxImGroupId.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\ImGroup as ImGroupModel;
|
||||
|
||||
class MaxImGroupId extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 365 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'max_im_group_id';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$group = ImGroupModel::findFirst(['order' => 'id DESC']);
|
||||
|
||||
return $group->id ?? 0;
|
||||
}
|
||||
|
||||
}
|
29
app/Caches/MaxPackageId.php
Normal file
29
app/Caches/MaxPackageId.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Package as PackageModel;
|
||||
|
||||
class MaxPackageId extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 365 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'max_package_id';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$package = PackageModel::findFirst(['order' => 'id DESC']);
|
||||
|
||||
return $package->id ?? 0;
|
||||
}
|
||||
|
||||
}
|
29
app/Caches/MaxPageId.php
Normal file
29
app/Caches/MaxPageId.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Page as PageModel;
|
||||
|
||||
class MaxPageId extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 365 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'max_page_id';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$page = PageModel::findFirst(['order' => 'id DESC']);
|
||||
|
||||
return $page->id ?? 0;
|
||||
}
|
||||
|
||||
}
|
29
app/Caches/MaxTopicId.php
Normal file
29
app/Caches/MaxTopicId.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Topic as TopicModel;
|
||||
|
||||
class MaxTopicId extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 365 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'max_topic_id';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$topic = TopicModel::findFirst(['order' => 'id DESC']);
|
||||
|
||||
return $topic->id ?? 0;
|
||||
}
|
||||
|
||||
}
|
29
app/Caches/MaxUserId.php
Normal file
29
app/Caches/MaxUserId.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\User as UserModel;
|
||||
|
||||
class MaxUserId extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 365 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'max_user_id';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$user = UserModel::findFirst(['order' => 'id DESC']);
|
||||
|
||||
return $user->id ?? 0;
|
||||
}
|
||||
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Repos\Nav as NavRepo;
|
||||
|
||||
class Nav extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 365 * 86400;
|
||||
|
||||
public function getTopNav()
|
||||
{
|
||||
$items = $this->get();
|
||||
|
||||
if (!$items) return;
|
||||
|
||||
$result = new \stdClass();
|
||||
|
||||
foreach ($items as $item) {
|
||||
if ($item->position == 'top') {
|
||||
$result->{$item->item_key} = $item->item_value;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getBottomNav()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
protected function getKey($params = null)
|
||||
{
|
||||
return 'nav';
|
||||
}
|
||||
|
||||
protected function getContent($params = null)
|
||||
{
|
||||
$navRepo = new NavRepo();
|
||||
|
||||
$items = $navRepo->findAll();
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
}
|
33
app/Caches/NavTreeList.php
Normal file
33
app/Caches/NavTreeList.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Builders\NavTreeList as NavTreeListBuilder;
|
||||
use App\Models\Nav as NavModel;
|
||||
|
||||
class NavTreeList extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 365 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'nav_tree_list';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$builder = new NavTreeListBuilder();
|
||||
|
||||
return [
|
||||
'top' => $builder->handle(NavModel::POS_TOP),
|
||||
'bottom' => $builder->handle(NavModel::POS_BOTTOM),
|
||||
];
|
||||
}
|
||||
|
||||
}
|
31
app/Caches/Package.php
Normal file
31
app/Caches/Package.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Repos\Package as PackageRepo;
|
||||
|
||||
class Package extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 7 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return "package:{$id}";
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$packageRepo = new PackageRepo();
|
||||
|
||||
$package = $packageRepo->findById($id);
|
||||
|
||||
return $package ?: null;
|
||||
}
|
||||
|
||||
}
|
61
app/Caches/PackageCourseList.php
Normal file
61
app/Caches/PackageCourseList.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Course as CourseModel;
|
||||
use App\Repos\Package as PackageRepo;
|
||||
|
||||
class PackageCourseList extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 1 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return "package_course_list:{$id}";
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$packageRepo = new PackageRepo();
|
||||
|
||||
$courses = $packageRepo->findCourses($id);
|
||||
|
||||
if ($courses->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->handleContent($courses);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CourseModel[] $courses
|
||||
* @return array
|
||||
*/
|
||||
public function handleContent($courses)
|
||||
{
|
||||
$result = [];
|
||||
|
||||
foreach ($courses as $course) {
|
||||
$result[] = [
|
||||
'id' => $course->id,
|
||||
'title' => $course->title,
|
||||
'cover' => $course->cover,
|
||||
'market_price' => $course->market_price,
|
||||
'vip_price' => $course->vip_price,
|
||||
'model' => $course->model,
|
||||
'level' => $course->level,
|
||||
'user_count' => $course->user_count,
|
||||
'lesson_count' => $course->lesson_count,
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
31
app/Caches/Page.php
Normal file
31
app/Caches/Page.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Repos\Page as PageRepo;
|
||||
|
||||
class Page extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 7 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return "page:{$id}";
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$pageRepo = new PageRepo();
|
||||
|
||||
$page = $pageRepo->findById($id);
|
||||
|
||||
return $page ?: null;
|
||||
}
|
||||
|
||||
}
|
65
app/Caches/SaleTrend.php
Normal file
65
app/Caches/SaleTrend.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Order as OrderModel;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class SaleTrend extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 2 * 3600;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'sale_trend';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OrderModel[] $sales
|
||||
* @param int $days
|
||||
* @return array
|
||||
*/
|
||||
protected function handleSales($sales, $days = 7)
|
||||
{
|
||||
$result = [];
|
||||
|
||||
foreach (array_reverse(range(1, $days)) as $num) {
|
||||
$date = date('Y-m-d', strtotime("-{$num} days"));
|
||||
$result[$date] = 0;
|
||||
}
|
||||
|
||||
foreach ($sales as $sale) {
|
||||
$date = date('Y-m-d', $sale->create_time);
|
||||
$result[$date] += $sale->amount;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $days
|
||||
* @return ResultsetInterface|Resultset|OrderModel[]
|
||||
*/
|
||||
protected function findSales($days = 7)
|
||||
{
|
||||
$time = strtotime("-{$days} days");
|
||||
|
||||
return OrderModel::query()
|
||||
->where('status = :status:', ['status' => OrderModel::STATUS_FINISHED])
|
||||
->andWhere('create_time > :time:', ['time' => $time])
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
41
app/Caches/Setting.php
Normal file
41
app/Caches/Setting.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Repos\Setting as SettingRepo;
|
||||
|
||||
class Setting extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 365 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return "setting:{$id}";
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$settingRepo = new SettingRepo();
|
||||
|
||||
$items = $settingRepo->findAll(['section' => $id]);
|
||||
|
||||
if ($items->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($items as $item) {
|
||||
$result[$item->item_key] = $item->item_value;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
52
app/Caches/SiteGlobalStat.php
Normal file
52
app/Caches/SiteGlobalStat.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Repos\Consult as ConsultRepo;
|
||||
use App\Repos\Course as CourseRepo;
|
||||
use App\Repos\ImGroup as GroupRepo;
|
||||
use App\Repos\Order as OrderRepo;
|
||||
use App\Repos\Package as PackageRepo;
|
||||
use App\Repos\Review as ReviewRepo;
|
||||
use App\Repos\Topic as TopicRepo;
|
||||
use App\Repos\User as UserRepo;
|
||||
|
||||
class SiteGlobalStat extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 2 * 3600;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'site_global_stat';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$courseRepo = new CourseRepo();
|
||||
$consultRepo = new ConsultRepo();
|
||||
$groupRepo = new GroupRepo();
|
||||
$orderRepo = new OrderRepo();
|
||||
$packageRepo = new PackageRepo();
|
||||
$reviewRepo = new ReviewRepo();
|
||||
$topicRepo = new TopicRepo();
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
return [
|
||||
'course_count' => $courseRepo->countCourses(),
|
||||
'consult_count' => $consultRepo->countConsults(),
|
||||
'group_count' => $groupRepo->countGroups(),
|
||||
'order_count' => $orderRepo->countOrders(),
|
||||
'package_count' => $packageRepo->countPackages(),
|
||||
'review_count' => $reviewRepo->countReviews(),
|
||||
'topic_count' => $topicRepo->countTopics(),
|
||||
'user_count' => $userRepo->countUsers(),
|
||||
];
|
||||
}
|
||||
|
||||
}
|
63
app/Caches/SiteTodayStat.php
Normal file
63
app/Caches/SiteTodayStat.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\Order as OrderModel;
|
||||
use App\Models\User as UserModel;
|
||||
|
||||
class SiteTodayStat extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 1 * 3600;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'site_today_stat';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
return [
|
||||
'user_count' => $this->countUsers(),
|
||||
'order_count' => $this->countOrders(),
|
||||
'sale_amount' => $this->sumSales(),
|
||||
];
|
||||
}
|
||||
|
||||
protected function countUsers()
|
||||
{
|
||||
return (int)UserModel::count([
|
||||
'conditions' => 'create_time > :time:',
|
||||
'bind' => ['time' => strtotime('today')],
|
||||
]);
|
||||
}
|
||||
|
||||
protected function countOrders()
|
||||
{
|
||||
return (int)OrderModel::count([
|
||||
'conditions' => 'create_time > :time: AND status = :status:',
|
||||
'bind' => [
|
||||
'time' => strtotime('today'),
|
||||
'status' => OrderModel::STATUS_FINISHED,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
protected function sumSales()
|
||||
{
|
||||
return (float)OrderModel::sum([
|
||||
'column' => 'amount',
|
||||
'conditions' => 'create_time > :time: AND status = :status:',
|
||||
'bind' => [
|
||||
'time' => strtotime('today'),
|
||||
'status' => OrderModel::STATUS_FINISHED,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
31
app/Caches/Topic.php
Normal file
31
app/Caches/Topic.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Repos\Topic as TopicRepo;
|
||||
|
||||
class Topic extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 7 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return "topic:{$id}";
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$topicRepo = new TopicRepo();
|
||||
|
||||
$topic = $topicRepo->findById($id);
|
||||
|
||||
return $topic ?: null;
|
||||
}
|
||||
|
||||
}
|
@ -1,57 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Library\Cache;
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\User as UserModel;
|
||||
use App\Exceptions\NotFound as ModelNotFoundException;
|
||||
use App\Repos\User as UserRepo;
|
||||
|
||||
class User extends \Phalcon\Di\Injectable
|
||||
class User extends Cache
|
||||
{
|
||||
|
||||
private $lifetime = 86400 * 30;
|
||||
|
||||
public function getOrFail($id)
|
||||
{
|
||||
$result = $this->getById($id);
|
||||
|
||||
if (!$result) {
|
||||
throw new ModelNotFoundException('user.not_found');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function get($id)
|
||||
{
|
||||
$cacheOptions = [
|
||||
'key' => $this->getKey($id),
|
||||
'lifetime' => $this->getLifetime(),
|
||||
];
|
||||
|
||||
$result = UserModel::query()
|
||||
->where('id = :id:', ['id' => $id])
|
||||
->cache($cacheOptions)
|
||||
->execute()
|
||||
->getFirst();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function delete($id)
|
||||
{
|
||||
$key = $this->getKey($id);
|
||||
|
||||
$this->modelsCache->delete($key);
|
||||
}
|
||||
|
||||
public function getKey($id)
|
||||
{
|
||||
return "user:{$id}";
|
||||
}
|
||||
protected $lifetime = 1 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return "user:{$id}";
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$user = $userRepo->findById($id);
|
||||
|
||||
return $user ?: null;
|
||||
}
|
||||
|
||||
}
|
||||
|
34
app/Caches/UserDailyCounter.php
Normal file
34
app/Caches/UserDailyCounter.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
class UserDailyCounter extends Counter
|
||||
{
|
||||
|
||||
protected $lifetime = 1 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
$tomorrow = strtotime('tomorrow');
|
||||
|
||||
return $tomorrow - time();
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return "user_daily_counter:{$id}";
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
return [
|
||||
'danmu_count' => 0,
|
||||
'consult_count' => 0,
|
||||
'order_count' => 0,
|
||||
'chapter_like_count' => 0,
|
||||
'consult_like_count' => 0,
|
||||
'review_like_count' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
}
|
@ -2,8 +2,6 @@
|
||||
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use Phalcon\Cli\Task;
|
||||
|
||||
class CleanLogTask extends Task
|
||||
{
|
||||
|
||||
@ -11,15 +9,18 @@ class CleanLogTask extends Task
|
||||
{
|
||||
$this->cleanCommonLog();
|
||||
$this->cleanConsoleLog();
|
||||
$this->cleanHttpLog();
|
||||
$this->cleanSqlLog();
|
||||
$this->cleanListenerLog();
|
||||
$this->cleanListenLog();
|
||||
$this->cleanCaptchaLog();
|
||||
$this->cleanMailerLog();
|
||||
$this->cleanSmserLog();
|
||||
$this->cleanMailLog();
|
||||
$this->cleanSmsLog();
|
||||
$this->cleanVodLog();
|
||||
$this->cleanLiveLog();
|
||||
$this->cleanStorageLog();
|
||||
$this->cleanAlipayLog();
|
||||
$this->cleanWxpayLog();
|
||||
$this->cleanOrderLog();
|
||||
$this->cleanRefundLog();
|
||||
}
|
||||
|
||||
@ -31,6 +32,14 @@ class CleanLogTask extends Task
|
||||
$this->cleanLog('common', 7);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理Http日志
|
||||
*/
|
||||
protected function cleanHttpLog()
|
||||
{
|
||||
$this->cleanLog('http', 7);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理Console日志
|
||||
*/
|
||||
@ -48,11 +57,11 @@ class CleanLogTask extends Task
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理监听者日志
|
||||
* 清理监听日志
|
||||
*/
|
||||
protected function cleanListenerLog()
|
||||
protected function cleanListenLog()
|
||||
{
|
||||
$this->cleanLog('listener', 7);
|
||||
$this->cleanLog('listen', 7);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -71,6 +80,14 @@ class CleanLogTask extends Task
|
||||
$this->cleanLog('vod', 7);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理直播服务日志
|
||||
*/
|
||||
protected function cleanLiveLog()
|
||||
{
|
||||
$this->cleanLog('live', 7);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理存储服务日志
|
||||
*/
|
||||
@ -82,17 +99,17 @@ class CleanLogTask extends Task
|
||||
/**
|
||||
* 清理短信服务日志
|
||||
*/
|
||||
protected function cleanSmserLog()
|
||||
protected function cleanSmsLog()
|
||||
{
|
||||
$this->cleanLog('smser', 7);
|
||||
$this->cleanLog('sms', 7);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理邮件服务日志
|
||||
*/
|
||||
protected function cleanMailerLog()
|
||||
protected function cleanMailLog()
|
||||
{
|
||||
$this->cleanLog('mailer', 7);
|
||||
$this->cleanLog('mail', 7);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -111,6 +128,14 @@ class CleanLogTask extends Task
|
||||
$this->cleanLog('wxpay', 30);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理订单日志
|
||||
*/
|
||||
protected function cleanOrderLog()
|
||||
{
|
||||
$this->cleanLog('order', 30);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理退款日志
|
||||
*/
|
||||
@ -123,7 +148,7 @@ class CleanLogTask extends Task
|
||||
* 清理日志文件
|
||||
*
|
||||
* @param string $prefix
|
||||
* @param integer $keepDays 保留天数
|
||||
* @param int $keepDays 保留天数
|
||||
* @return mixed
|
||||
*/
|
||||
protected function cleanLog($prefix, $keepDays)
|
||||
@ -138,9 +163,9 @@ class CleanLogTask extends Task
|
||||
if (strtotime($today) - strtotime($date) >= $keepDays * 86400) {
|
||||
$deleted = unlink($file);
|
||||
if ($deleted) {
|
||||
echo "Delete {$file} success" . PHP_EOL;
|
||||
echo "delete {$file} success" . PHP_EOL;
|
||||
} else {
|
||||
echo "Delete {$file} failed" . PHP_EOL;
|
||||
echo "delete {$file} failed" . PHP_EOL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
43
app/Console/Tasks/CleanSessionTask.php
Normal file
43
app/Console/Tasks/CleanSessionTask.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
class CleanSessionTask extends Task
|
||||
{
|
||||
|
||||
public function mainAction()
|
||||
{
|
||||
$config = $this->getConfig();
|
||||
$redis = $this->getRedis();
|
||||
|
||||
$redis->select($config->path('session.db'));
|
||||
|
||||
$keys = $this->querySessionKeys(10000);
|
||||
|
||||
if (count($keys) == 0) return;
|
||||
|
||||
$lifetime = $config->path('session.lifetime');
|
||||
|
||||
foreach ($keys as $key) {
|
||||
$ttl = $redis->ttl($key);
|
||||
$content = $redis->get($key);
|
||||
if (empty($content) && $ttl < $lifetime * 0.5) {
|
||||
$redis->del($key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找待清理会话
|
||||
*
|
||||
* @param int $limit
|
||||
* @return array
|
||||
*/
|
||||
protected function querySessionKeys($limit)
|
||||
{
|
||||
$cache = $this->getCache();
|
||||
|
||||
return $cache->queryKeys('_PHCR', $limit);
|
||||
}
|
||||
|
||||
}
|
@ -3,7 +3,8 @@
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use App\Models\Order as OrderModel;
|
||||
use Phalcon\Cli\Task;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class CloseOrderTask extends Task
|
||||
{
|
||||
@ -25,22 +26,20 @@ class CloseOrderTask extends Task
|
||||
/**
|
||||
* 查找待关闭订单
|
||||
*
|
||||
* @param integer $limit
|
||||
* @return \Phalcon\Mvc\Model\ResultsetInterface
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|OrderModel[]
|
||||
*/
|
||||
protected function findOrders($limit = 1000)
|
||||
{
|
||||
$status = OrderModel::STATUS_PENDING;
|
||||
|
||||
$createdAt = time() - 12 * 3600;
|
||||
$createTime = time() - 12 * 3600;
|
||||
|
||||
$orders = OrderModel::query()
|
||||
return OrderModel::query()
|
||||
->where('status = :status:', ['status' => $status])
|
||||
->andWhere('created_at < :created_at:', ['created_at' => $createdAt])
|
||||
->andWhere('create_time < :create_time:', ['create_time' => $createTime])
|
||||
->limit($limit)
|
||||
->execute();
|
||||
|
||||
return $orders;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,8 +3,10 @@
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use App\Models\Trade as TradeModel;
|
||||
use App\Services\Alipay as AlipayService;
|
||||
use Phalcon\Cli\Task;
|
||||
use App\Services\Pay\Alipay as AlipayService;
|
||||
use App\Services\Pay\Wxpay as WxpayService;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class CloseTradeTask extends Task
|
||||
{
|
||||
@ -19,52 +21,82 @@ class CloseTradeTask extends Task
|
||||
|
||||
foreach ($trades as $trade) {
|
||||
if ($trade->channel == TradeModel::CHANNEL_ALIPAY) {
|
||||
$this->closeAlipayTrade($trade);
|
||||
$this->handleAlipayTrade($trade);
|
||||
} elseif ($trade->channel == TradeModel::CHANNEL_WXPAY) {
|
||||
$this->closeWxpayTrade($trade);
|
||||
$this->handleWxpayTrade($trade);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭支付宝交易
|
||||
* 处理支付宝交易
|
||||
*
|
||||
* @param TradeModel $trade
|
||||
*/
|
||||
protected function closeAlipayTrade($trade)
|
||||
protected function handleAlipayTrade(TradeModel $trade)
|
||||
{
|
||||
$service = new AlipayService();
|
||||
$allowClosed = true;
|
||||
|
||||
$alyOrder = $service->findOrder($trade->sn);
|
||||
$alipay = new AlipayService();
|
||||
|
||||
if ($alyOrder) {
|
||||
if ($alyOrder->trade_status == 'WAIT_BUYER_PAY') {
|
||||
$service->closeOrder($trade->sn);
|
||||
$alipayTrade = $alipay->find($trade->sn);
|
||||
|
||||
if ($alipayTrade) {
|
||||
|
||||
/**
|
||||
* 异步通知接收异常,补救漏网
|
||||
*/
|
||||
if ($alipayTrade->trade_status == 'TRADE_SUCCESS') {
|
||||
|
||||
$this->eventsManager->fire('pay:afterPay', $this, $trade);
|
||||
|
||||
$allowClosed = false;
|
||||
|
||||
} elseif ($alipayTrade->trade_status == 'WAIT_BUYER_PAY') {
|
||||
|
||||
$allowClosed = $alipay->close($trade->sn);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$allowClosed) return;
|
||||
|
||||
$trade->status = TradeModel::STATUS_CLOSED;
|
||||
|
||||
$trade->update();
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭微信交易
|
||||
* 处理微信交易
|
||||
*
|
||||
* @param TradeModel $trade
|
||||
*/
|
||||
protected function closeWxpayTrade($trade)
|
||||
protected function handleWxpayTrade(TradeModel $trade)
|
||||
{
|
||||
$service = new WxpayService();
|
||||
$allowClosed = true;
|
||||
|
||||
$wxOrder = $service->findOrder($trade->sn);
|
||||
$wxpay = new WxpayService();
|
||||
|
||||
if ($wxOrder) {
|
||||
if ($wxOrder->trade_state == 'NOTPAY') {
|
||||
$service->closeOrder($trade->sn);
|
||||
$wxpayTrade = $wxpay->find($trade->sn);
|
||||
|
||||
if ($wxpayTrade) {
|
||||
|
||||
/**
|
||||
* 异步通知接收异常,补救漏网
|
||||
*/
|
||||
if ($wxpayTrade->trade_state == 'SUCCESS') {
|
||||
|
||||
$this->eventsManager->fire('pay:afterPay', $this, $trade);
|
||||
|
||||
$allowClosed = false;
|
||||
|
||||
} elseif ($wxpayTrade->trade_state == 'NOTPAY') {
|
||||
|
||||
$allowClosed = $wxpay->close($trade->sn);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$allowClosed) return;
|
||||
|
||||
$trade->status = TradeModel::STATUS_CLOSED;
|
||||
|
||||
$trade->update();
|
||||
@ -73,22 +105,20 @@ class CloseTradeTask extends Task
|
||||
/**
|
||||
* 查找待关闭交易
|
||||
*
|
||||
* @param integer $limit
|
||||
* @return \Phalcon\Mvc\Model\ResultsetInterface
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|TradeModel[]
|
||||
*/
|
||||
protected function findTrades($limit = 5)
|
||||
protected function findTrades($limit = 50)
|
||||
{
|
||||
$status = TradeModel::STATUS_PENDING;
|
||||
|
||||
$createdAt = time() - 15 * 60;
|
||||
$createTime = time() - 15 * 60;
|
||||
|
||||
$trades = TradeModel::query()
|
||||
return TradeModel::query()
|
||||
->where('status = :status:', ['status' => $status])
|
||||
->andWhere('created_at < :created_at:', ['created_at' => $createdAt])
|
||||
->andWhere('create_time < :create_time:', ['create_time' => $createTime])
|
||||
->limit($limit)
|
||||
->execute();
|
||||
|
||||
return $trades;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use App\Repos\Category as CategoryRepo;
|
||||
use Phalcon\Cli\Task;
|
||||
|
||||
class CourseCountTask extends Task
|
||||
{
|
||||
|
||||
public function mainAction()
|
||||
{
|
||||
$repo = new CategoryRepo();
|
||||
|
||||
$mapping = [];
|
||||
|
||||
$subCategories = $repo->findAll(['level' => 2, 'deleted' => 0]);
|
||||
|
||||
foreach ($subCategories as $category) {
|
||||
|
||||
$courseCount = $repo->countCourses($category->id);
|
||||
$category->course_count = $courseCount;
|
||||
$category->update();
|
||||
|
||||
$parentId = $category->parent_id;
|
||||
|
||||
if (isset($mapping[$parentId])) {
|
||||
$mapping[$parentId] += $courseCount;
|
||||
} else {
|
||||
$mapping[$parentId] = $courseCount;
|
||||
}
|
||||
}
|
||||
|
||||
$topCategories = $repo->findAll(['level' => 1, 'deleted' => 0]);
|
||||
|
||||
foreach ($topCategories as $category) {
|
||||
if (isset($mapping[$category->id])) {
|
||||
$category->course_count = $mapping[$category->id];
|
||||
$category->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
125
app/Console/Tasks/CourseIndexTask.php
Normal file
125
app/Console/Tasks/CourseIndexTask.php
Normal file
@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use App\Models\Course as CourseModel;
|
||||
use App\Services\Search\CourseDocument;
|
||||
use App\Services\Search\CourseSearcher;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class CourseIndexTask extends Task
|
||||
{
|
||||
|
||||
/**
|
||||
* 搜索测试
|
||||
*
|
||||
* @command: php console.php course_index search {query}
|
||||
* @param array $params
|
||||
* @throws \XSException
|
||||
*/
|
||||
public function searchAction($params)
|
||||
{
|
||||
$query = $params[0] ?? null;
|
||||
|
||||
if (!$query) {
|
||||
exit('please special a query word' . PHP_EOL);
|
||||
}
|
||||
|
||||
$result = $this->searchCourses($query);
|
||||
|
||||
var_export($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空索引
|
||||
*
|
||||
* @command: php console.php course_index clean
|
||||
*/
|
||||
public function cleanAction()
|
||||
{
|
||||
$this->cleanCourseIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* 重建索引
|
||||
*
|
||||
* @command: php console.php course_index rebuild
|
||||
*/
|
||||
public function rebuildAction()
|
||||
{
|
||||
$this->rebuildCourseIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空索引
|
||||
*/
|
||||
protected function cleanCourseIndex()
|
||||
{
|
||||
$handler = new CourseSearcher();
|
||||
|
||||
$index = $handler->getXS()->getIndex();
|
||||
|
||||
echo 'start clean index' . PHP_EOL;
|
||||
|
||||
$index->clean();
|
||||
|
||||
echo 'end clean index' . PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重建索引
|
||||
*/
|
||||
protected function rebuildCourseIndex()
|
||||
{
|
||||
$courses = $this->findCourses();
|
||||
|
||||
if ($courses->count() == 0) return;
|
||||
|
||||
$handler = new CourseSearcher();
|
||||
|
||||
$documenter = new CourseDocument();
|
||||
|
||||
$index = $handler->getXS()->getIndex();
|
||||
|
||||
echo 'start rebuild index' . PHP_EOL;
|
||||
|
||||
$index->beginRebuild();
|
||||
|
||||
foreach ($courses as $course) {
|
||||
$document = $documenter->setDocument($course);
|
||||
$index->add($document);
|
||||
}
|
||||
|
||||
$index->endRebuild();
|
||||
|
||||
echo 'end rebuild index' . PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索课程
|
||||
*
|
||||
* @param string $query
|
||||
* @return array
|
||||
* @throws \XSException
|
||||
*/
|
||||
protected function searchCourses($query)
|
||||
{
|
||||
$handler = new CourseSearcher();
|
||||
|
||||
return $handler->search($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找课程
|
||||
*
|
||||
* @return ResultsetInterface|Resultset|CourseModel[]
|
||||
*/
|
||||
protected function findCourses()
|
||||
{
|
||||
return CourseModel::query()
|
||||
->where('published = 1')
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
262
app/Console/Tasks/DeliverTask.php
Normal file
262
app/Console/Tasks/DeliverTask.php
Normal file
@ -0,0 +1,262 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use App\Models\CourseUser as CourseUserModel;
|
||||
use App\Models\ImGroupUser as ImGroupUserModel;
|
||||
use App\Models\Order as OrderModel;
|
||||
use App\Models\Refund as RefundModel;
|
||||
use App\Models\Task as TaskModel;
|
||||
use App\Models\Trade as TradeModel;
|
||||
use App\Repos\ImGroup as ImGroupRepo;
|
||||
use App\Repos\ImGroupUser as ImGroupUserRepo;
|
||||
use App\Repos\Order as OrderRepo;
|
||||
use App\Repos\User as UserRepo;
|
||||
use App\Services\Sms\Order as OrderSms;
|
||||
use Phalcon\Mvc\Model;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class DeliverTask extends Task
|
||||
{
|
||||
|
||||
const TRY_COUNT = 3;
|
||||
|
||||
public function mainAction()
|
||||
{
|
||||
$logger = $this->getLogger('order');
|
||||
|
||||
$tasks = $this->findTasks();
|
||||
|
||||
if ($tasks->count() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$orderRepo = new OrderRepo();
|
||||
|
||||
foreach ($tasks as $task) {
|
||||
|
||||
/**
|
||||
* @var array $itemInfo
|
||||
*/
|
||||
$itemInfo = $task->item_info;
|
||||
|
||||
$order = $orderRepo->findById($itemInfo['order']['id']);
|
||||
|
||||
if (!$order) continue;
|
||||
|
||||
try {
|
||||
|
||||
switch ($order->item_type) {
|
||||
case OrderModel::ITEM_COURSE:
|
||||
$this->handleCourseOrder($order);
|
||||
break;
|
||||
case OrderModel::ITEM_PACKAGE:
|
||||
$this->handlePackageOrder($order);
|
||||
break;
|
||||
case OrderModel::ITEM_VIP:
|
||||
$this->handleVipOrder($order);
|
||||
break;
|
||||
}
|
||||
|
||||
$this->finishOrder($order);
|
||||
|
||||
$task->status = TaskModel::STATUS_FINISHED;
|
||||
|
||||
$task->update();
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
$task->try_count += 1;
|
||||
$task->priority += 1;
|
||||
|
||||
if ($task->try_count > self::TRY_COUNT) {
|
||||
$task->status = TaskModel::STATUS_FAILED;
|
||||
}
|
||||
|
||||
$task->update();
|
||||
|
||||
$logger->info('Order Process Exception ' . kg_json_encode([
|
||||
'code' => $e->getCode(),
|
||||
'message' => $e->getMessage(),
|
||||
'task' => $task->toArray(),
|
||||
]));
|
||||
}
|
||||
|
||||
if ($task->status == TaskModel::STATUS_FINISHED) {
|
||||
$this->handleOrderNotice($order);
|
||||
} elseif ($task->status == TaskModel::STATUS_FAILED) {
|
||||
$this->handleOrderRefund($order);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function finishOrder(OrderModel $order)
|
||||
{
|
||||
$order->status = OrderModel::STATUS_FINISHED;
|
||||
|
||||
if ($order->update() === false) {
|
||||
throw new \RuntimeException('Finish Order Failed');
|
||||
}
|
||||
}
|
||||
|
||||
protected function handleCourseOrder(OrderModel $order)
|
||||
{
|
||||
/**
|
||||
* @var array $itemInfo
|
||||
*/
|
||||
$itemInfo = $order->item_info;
|
||||
|
||||
$courseUser = new CourseUserModel();
|
||||
|
||||
$courseUser->user_id = $order->owner_id;
|
||||
$courseUser->course_id = $order->item_id;
|
||||
$courseUser->expiry_time = $itemInfo['course']['study_expiry_time'];
|
||||
$courseUser->role_type = CourseUserModel::ROLE_STUDENT;
|
||||
$courseUser->source_type = CourseUserModel::SOURCE_CHARGE;
|
||||
|
||||
if ($courseUser->create() === false) {
|
||||
throw new \RuntimeException('Create Course User Failed');
|
||||
}
|
||||
|
||||
$groupRepo = new ImGroupRepo();
|
||||
|
||||
$group = $groupRepo->findByCourseId($order->item_id);
|
||||
|
||||
$groupUserRepo = new ImGroupUserRepo();
|
||||
|
||||
$groupUser = $groupUserRepo->findGroupUser($group->id, $order->owner_id);
|
||||
|
||||
if ($groupUser) return;
|
||||
|
||||
$groupUser = new ImGroupUserModel();
|
||||
|
||||
$groupUser->group_id = $group->id;
|
||||
$groupUser->user_id = $order->owner_id;
|
||||
|
||||
if ($groupUser->create() === false) {
|
||||
throw new \RuntimeException('Create Group User Failed');
|
||||
}
|
||||
}
|
||||
|
||||
protected function handlePackageOrder(OrderModel $order)
|
||||
{
|
||||
/**
|
||||
* @var array $itemInfo
|
||||
*/
|
||||
$itemInfo = $order->item_info;
|
||||
|
||||
foreach ($itemInfo['courses'] as $course) {
|
||||
|
||||
$courseUser = new CourseUserModel();
|
||||
|
||||
$courseUser->user_id = $order->owner_id;
|
||||
$courseUser->course_id = $course['id'];
|
||||
$courseUser->expiry_time = $course['study_expiry_time'];
|
||||
$courseUser->role_type = CourseUserModel::ROLE_STUDENT;
|
||||
$courseUser->source_type = CourseUserModel::SOURCE_CHARGE;
|
||||
|
||||
if ($courseUser->create() === false) {
|
||||
throw new \RuntimeException('Create Course User Failed');
|
||||
}
|
||||
|
||||
$groupRepo = new ImGroupRepo();
|
||||
|
||||
$group = $groupRepo->findByCourseId($course['id']);
|
||||
|
||||
$groupUserRepo = new ImGroupUserRepo();
|
||||
|
||||
$groupUser = $groupUserRepo->findGroupUser($group->id, $order->owner_id);
|
||||
|
||||
if ($groupUser) continue;
|
||||
|
||||
$groupUser = new ImGroupUserModel();
|
||||
|
||||
$groupUser->group_id = $group->id;
|
||||
$groupUser->user_id = $order->owner_id;
|
||||
|
||||
if ($groupUser->create() === false) {
|
||||
throw new \RuntimeException('Create Group User Failed');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function handleVipOrder(OrderModel $order)
|
||||
{
|
||||
/**
|
||||
* @var array $itemInfo
|
||||
*/
|
||||
$itemInfo = $order->item_info;
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$user = $userRepo->findById($order->owner_id);
|
||||
|
||||
$user->vip_expiry_time = $itemInfo['vip']['expiry_time'];
|
||||
|
||||
if ($user->update() === false) {
|
||||
throw new \RuntimeException('Update Vip Expiry Failed');
|
||||
}
|
||||
}
|
||||
|
||||
protected function handleOrderNotice(OrderModel $order)
|
||||
{
|
||||
$sms = new OrderSms();
|
||||
|
||||
$sms->handle($order);
|
||||
}
|
||||
|
||||
protected function handleOrderRefund(OrderModel $order)
|
||||
{
|
||||
$trade = $this->findFinishedTrade($order->id);
|
||||
|
||||
if (!$trade) return;
|
||||
|
||||
$refund = new RefundModel();
|
||||
|
||||
$refund->owner_id = $order->owner_id;
|
||||
$refund->order_id = $order->id;
|
||||
$refund->trade_id = $trade->id;
|
||||
$refund->subject = $order->subject;
|
||||
$refund->amount = $order->amount;
|
||||
$refund->apply_note = '开通服务失败,自动退款';
|
||||
$refund->review_note = '自动操作';
|
||||
|
||||
$refund->create();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $orderId
|
||||
* @return Model|TradeModel
|
||||
*/
|
||||
protected function findFinishedTrade($orderId)
|
||||
{
|
||||
$status = TradeModel::STATUS_FINISHED;
|
||||
|
||||
return TradeModel::findFirst([
|
||||
'conditions' => ['order_id = :order_id: AND status = :status:'],
|
||||
'bind' => ['order_id' => $orderId, 'status' => $status],
|
||||
'order' => 'id DESC',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|TaskModel[]
|
||||
*/
|
||||
protected function findTasks($limit = 100)
|
||||
{
|
||||
$itemType = TaskModel::TYPE_DELIVER;
|
||||
$status = TaskModel::STATUS_PENDING;
|
||||
$tryCount = self::TRY_COUNT;
|
||||
|
||||
return TaskModel::query()
|
||||
->where('item_type = :item_type:', ['item_type' => $itemType])
|
||||
->andWhere('status = :status:', ['status' => $status])
|
||||
->andWhere('try_count < :try_count:', ['try_count' => $tryCount + 1])
|
||||
->orderBy('priority ASC')
|
||||
->limit($limit)
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
125
app/Console/Tasks/GroupIndexTask.php
Normal file
125
app/Console/Tasks/GroupIndexTask.php
Normal file
@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use App\Models\ImGroup as GroupModel;
|
||||
use App\Services\Search\GroupDocument;
|
||||
use App\Services\Search\GroupSearcher;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class GroupIndexTask extends Task
|
||||
{
|
||||
|
||||
/**
|
||||
* 搜索测试
|
||||
*
|
||||
* @command: php console.php group_index search {query}
|
||||
* @param array $params
|
||||
* @throws \XSException
|
||||
*/
|
||||
public function searchAction($params)
|
||||
{
|
||||
$query = $params[0] ?? null;
|
||||
|
||||
if (!$query) {
|
||||
exit('please special a query word' . PHP_EOL);
|
||||
}
|
||||
|
||||
$result = $this->searchGroups($query);
|
||||
|
||||
var_export($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空索引
|
||||
*
|
||||
* @command: php console.php group_index clean
|
||||
*/
|
||||
public function cleanAction()
|
||||
{
|
||||
$this->cleanGroupIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* 重建索引
|
||||
*
|
||||
* @command: php console.php group_index rebuild
|
||||
*/
|
||||
public function rebuildAction()
|
||||
{
|
||||
$this->rebuildGroupIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空索引
|
||||
*/
|
||||
protected function cleanGroupIndex()
|
||||
{
|
||||
$handler = new GroupSearcher();
|
||||
|
||||
$index = $handler->getXS()->getIndex();
|
||||
|
||||
echo 'start clean index' . PHP_EOL;
|
||||
|
||||
$index->clean();
|
||||
|
||||
echo 'end clean index' . PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重建索引
|
||||
*/
|
||||
protected function rebuildGroupIndex()
|
||||
{
|
||||
$groups = $this->findGroups();
|
||||
|
||||
if ($groups->count() == 0) return;
|
||||
|
||||
$handler = new GroupSearcher();
|
||||
|
||||
$documenter = new GroupDocument();
|
||||
|
||||
$index = $handler->getXS()->getIndex();
|
||||
|
||||
echo 'start rebuild index' . PHP_EOL;
|
||||
|
||||
$index->beginRebuild();
|
||||
|
||||
foreach ($groups as $group) {
|
||||
$document = $documenter->setDocument($group);
|
||||
$index->add($document);
|
||||
}
|
||||
|
||||
$index->endRebuild();
|
||||
|
||||
echo 'end rebuild index' . PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索课程
|
||||
*
|
||||
* @param string $query
|
||||
* @return array
|
||||
* @throws \XSException
|
||||
*/
|
||||
protected function searchGroups($query)
|
||||
{
|
||||
$handler = new GroupSearcher();
|
||||
|
||||
return $handler->search($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找课程
|
||||
*
|
||||
* @return ResultsetInterface|Resultset|GroupModel[]
|
||||
*/
|
||||
protected function findGroups()
|
||||
{
|
||||
return GroupModel::query()
|
||||
->where('published = 1')
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use App\Models\Course;
|
||||
use App\Services\Storage;
|
||||
use Phalcon\Cli\Task;
|
||||
use Phalcon\Text;
|
||||
|
||||
class ImageSyncTask extends Task
|
||||
{
|
||||
|
||||
public function mainAction()
|
||||
{
|
||||
$courses = Course::query()
|
||||
->where('id = 42')
|
||||
->execute();
|
||||
|
||||
$storage = new Storage();
|
||||
|
||||
foreach ($courses as $course) {
|
||||
$cover = $course->cover;
|
||||
if (Text::startsWith($cover, '//')) {
|
||||
$cover = 'http:' . $cover;
|
||||
}
|
||||
$url = str_replace('-240-135', '', $cover);
|
||||
|
||||
$fileName = parse_url($url, PHP_URL_PATH);
|
||||
$filePath = tmp_path() . $fileName;
|
||||
$content = file_get_contents($url);
|
||||
file_put_contents($filePath, $content);
|
||||
$keyName = $this->getKeyName($filePath);
|
||||
$remoteUrl = $storage->putFile($keyName, $filePath);
|
||||
if ($remoteUrl) {
|
||||
$course->cover = $keyName;
|
||||
$course->update();
|
||||
echo "upload cover of course {$course->id} success" . PHP_EOL;
|
||||
} else {
|
||||
echo "upload cover of course {$course->id} failed" . PHP_EOL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function getKeyName($filePath)
|
||||
{
|
||||
$ext = pathinfo($filePath, PATHINFO_EXTENSION);
|
||||
return '/img/cover/' . date('YmdHis') . rand(1000, 9999) . '.' . $ext;
|
||||
}
|
||||
|
||||
}
|
@ -1,139 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use App\Models\Learning as LearningModel;
|
||||
use App\Repos\Chapter as ChapterRepo;
|
||||
use App\Repos\ChapterUser as ChapterUserRepo;
|
||||
use App\Repos\Course as CourseRepo;
|
||||
use App\Repos\CourseUser as CourseUserRepo;
|
||||
use App\Repos\Learning as LearningRepo;
|
||||
use Phalcon\Cli\Task;
|
||||
|
||||
class LearningTask extends Task
|
||||
{
|
||||
|
||||
/**
|
||||
* @var \App\Library\Cache\Backend\Redis
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
public function mainAction()
|
||||
{
|
||||
$this->cache = $this->getDI()->get('cache');
|
||||
|
||||
$keys = $this->cache->queryKeys('learning:');
|
||||
|
||||
if (empty($keys)) return;
|
||||
|
||||
$keys = array_slice($keys, 0, 500);
|
||||
|
||||
$prefix = $this->cache->getPrefix();
|
||||
|
||||
foreach ($keys as $key) {
|
||||
/**
|
||||
* 去掉前缀,避免重复加前缀导致找不到缓存
|
||||
*/
|
||||
if ($prefix) {
|
||||
$key = str_replace($prefix, '', $key);
|
||||
}
|
||||
$this->handleLearning($key);
|
||||
}
|
||||
}
|
||||
|
||||
protected function handleLearning($key)
|
||||
{
|
||||
$content = $this->cache->get($key);
|
||||
|
||||
if (empty($content->user_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($content->client_ip)) {
|
||||
$region = kg_ip2region($content->client_ip);
|
||||
$content->country = $region->country;
|
||||
$content->province = $region->province;
|
||||
$content->city = $region->city;
|
||||
}
|
||||
|
||||
$learningRepo = new LearningRepo();
|
||||
|
||||
$learning = $learningRepo->findByRequestId($content->request_id);
|
||||
|
||||
if (!$learning) {
|
||||
$learning = new LearningModel();
|
||||
$data = kg_object_array($content);
|
||||
$learning->create($data);
|
||||
} else {
|
||||
$learning->duration += $content->duration;
|
||||
$learning->update();
|
||||
}
|
||||
|
||||
$this->updateChapterUser($content->chapter_id, $content->user_id, $content->duration, $content->position);
|
||||
$this->updateCourseUser($content->course_id, $content->user_id, $content->duration);
|
||||
|
||||
$this->cache->delete($key);
|
||||
}
|
||||
|
||||
protected function updateChapterUser($chapterId, $userId, $duration = 0, $position = 0)
|
||||
{
|
||||
$chapterUserRepo = new ChapterUserRepo();
|
||||
|
||||
$chapterUser = $chapterUserRepo->findChapterUser($chapterId, $userId);
|
||||
|
||||
if (!$chapterUser) return false;
|
||||
|
||||
$chapterRepo = new ChapterRepo();
|
||||
|
||||
$chapter = $chapterRepo->findById($chapterId);
|
||||
|
||||
if (!$chapter) return false;
|
||||
|
||||
$chapter->duration = $chapter->attrs['duration'] ?: 0;
|
||||
|
||||
$chapterUser->duration += $duration;
|
||||
$chapterUser->position = floor($position);
|
||||
|
||||
/**
|
||||
* 观看时长超过视频时长80%标记完成学习
|
||||
*/
|
||||
if ($chapterUser->duration > $chapter->duration * 0.8) {
|
||||
if ($chapterUser->finished == 0) {
|
||||
$chapterUser->finished = 1;
|
||||
$this->updateCourseProgress($chapterUser->course_id, $chapterUser->user_id);
|
||||
}
|
||||
}
|
||||
|
||||
$chapterUser->update();
|
||||
}
|
||||
|
||||
protected function updateCourseUser($courseId, $userId, $duration)
|
||||
{
|
||||
$courseUserRepo = new CourseUserRepo();
|
||||
|
||||
$courseUser = $courseUserRepo->findCourseUser($courseId, $userId);
|
||||
|
||||
if ($courseUser) {
|
||||
$courseUser->duration += $duration;
|
||||
$courseUser->update();
|
||||
}
|
||||
}
|
||||
|
||||
protected function updateCourseProgress($courseId, $userId)
|
||||
{
|
||||
$courseUserRepo = new CourseUserRepo();
|
||||
|
||||
$courseUser = $courseUserRepo->findCourseUser($courseId, $userId);
|
||||
|
||||
$courseRepo = new CourseRepo();
|
||||
|
||||
$course = $courseRepo->findById($courseId);
|
||||
|
||||
if ($courseUser) {
|
||||
$count = $courseUserRepo->countFinishedChapters($courseId, $userId);
|
||||
$courseUser->progress = intval(100 * $count / $course->lesson_count);
|
||||
$courseUser->update();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
81
app/Console/Tasks/LiveNotifyTask.php
Normal file
81
app/Console/Tasks/LiveNotifyTask.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use App\Models\CourseUser as CourseUserModel;
|
||||
use App\Repos\Chapter as ChapterRepo;
|
||||
use App\Services\LiveNotify as LiveNotifyService;
|
||||
use App\Services\Sms\Live as LiveSms;
|
||||
|
||||
class LiveNotifyTask extends Task
|
||||
{
|
||||
|
||||
public function mainAction()
|
||||
{
|
||||
$redis = $this->getRedis();
|
||||
|
||||
$service = new LiveNotifyService();
|
||||
|
||||
$key = $service->getNotifyKey();
|
||||
|
||||
$chapterIds = $redis->sMembers($key);
|
||||
|
||||
if (!$chapterIds) return;
|
||||
|
||||
$sentKey = $service->getSentNotifyKey();
|
||||
|
||||
$sentChapterIds = $redis->sMembers($sentKey);
|
||||
|
||||
foreach ($chapterIds as $chapterId) {
|
||||
if (!in_array($chapterId, $sentChapterIds)) {
|
||||
$this->sendNotification($chapterId);
|
||||
} else {
|
||||
$redis->sAdd($sentKey, $chapterId);
|
||||
}
|
||||
}
|
||||
|
||||
if ($redis->sCard($sentKey) == 1) {
|
||||
$redis->expire($sentKey, 86400);
|
||||
}
|
||||
}
|
||||
|
||||
protected function sendNotification($chapterId)
|
||||
{
|
||||
$chapterRepo = new ChapterRepo();
|
||||
|
||||
$chapterLive = $chapterRepo->findChapterLive($chapterId);
|
||||
|
||||
if (!$chapterLive) return;
|
||||
|
||||
$targetUserIds = $this->findTargetUserIds($chapterLive->course_id);
|
||||
|
||||
if (!$targetUserIds) return;
|
||||
|
||||
$sms = new LiveSms();
|
||||
|
||||
foreach ($targetUserIds as $userId) {
|
||||
$sms->handle($chapterId, $userId, $chapterLive->start_time);
|
||||
}
|
||||
}
|
||||
|
||||
protected function findTargetUserIds($courseId)
|
||||
{
|
||||
$sourceTypes = [
|
||||
CourseUserModel::SOURCE_CHARGE,
|
||||
CourseUserModel::SOURCE_VIP,
|
||||
];
|
||||
|
||||
$rows = CourseUserModel::query()
|
||||
->where('course_id = :course_id:', ['course_id' => $courseId])
|
||||
->andWhere('role_type = :role_type:', ['role_type' => CourseUserModel::ROLE_STUDENT])
|
||||
->inWhere('source_type', $sourceTypes)
|
||||
->execute();
|
||||
|
||||
if ($rows->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return kg_array_column($rows->toArray(), 'user_id');
|
||||
}
|
||||
|
||||
}
|
@ -2,8 +2,6 @@
|
||||
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use App\Models\Chapter;
|
||||
|
||||
class MainTask extends Task
|
||||
{
|
||||
|
||||
@ -12,13 +10,4 @@ class MainTask extends Task
|
||||
echo "You are now flying with Phalcon CLI!";
|
||||
}
|
||||
|
||||
public function okAction()
|
||||
{
|
||||
$chapter = Chapter::findFirstById(15224);
|
||||
|
||||
$chapter->duration = 123;
|
||||
|
||||
echo $chapter->duration;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,36 +2,99 @@
|
||||
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use Phalcon\Cli\Task;
|
||||
use App\Caches\IndexFreeCourseList as IndexFreeCourseListCache;
|
||||
use App\Caches\IndexNewCourseList as IndexNewCourseListCache;
|
||||
use App\Caches\IndexVipCourseList as IndexVipCourseListCache;
|
||||
use App\Http\Admin\Services\Setting as SettingService;
|
||||
use App\Library\Utils\Password as PasswordUtil;
|
||||
use App\Validators\Account as AccountValidator;
|
||||
|
||||
class MaintainTask extends Task
|
||||
{
|
||||
|
||||
public function mainAction()
|
||||
/**
|
||||
* 重建首页课程缓存
|
||||
*
|
||||
* @param array $params
|
||||
* @command: php console.php maintain reset_index_course_cache
|
||||
*/
|
||||
public function rebuildIndexCourseCacheAction($params)
|
||||
{
|
||||
$section = $params[0] ?? null;
|
||||
|
||||
}
|
||||
if (!$section || $section == 'new_course') {
|
||||
$cache = new IndexNewCourseListCache();
|
||||
$cache->rebuild();
|
||||
}
|
||||
|
||||
public function resetAnnotationsAction()
|
||||
{
|
||||
$dir = cache_path('annotations');
|
||||
if (!$section || $section == 'free_course') {
|
||||
$cache = new IndexFreeCourseListCache();
|
||||
$cache->rebuild();
|
||||
}
|
||||
|
||||
foreach (scandir($dir) as $file) {
|
||||
if (strpos($file, '.php')) {
|
||||
unlink($dir . '/' . $file);
|
||||
}
|
||||
if (!$section || $section == 'vip_course') {
|
||||
$cache = new IndexVipCourseListCache();
|
||||
$cache->rebuild();
|
||||
}
|
||||
}
|
||||
|
||||
public function resetModelsMetaDataAction()
|
||||
/**
|
||||
* 修改密码
|
||||
*
|
||||
* @param array $params
|
||||
* @command: php console.php maintain reset_password 13507083515 123456
|
||||
*/
|
||||
public function resetPasswordAction($params)
|
||||
{
|
||||
$dir = cache_path('metadata');
|
||||
|
||||
foreach (scandir($dir) as $file) {
|
||||
if (strpos($file, '.php')) {
|
||||
unlink($dir . '/' . $file);
|
||||
}
|
||||
if (empty($params[0])) {
|
||||
echo 'account is required' . PHP_EOL;
|
||||
}
|
||||
|
||||
if (empty($params[1])) {
|
||||
echo 'password is required' . PHP_EOL;
|
||||
}
|
||||
|
||||
$validator = new AccountValidator();
|
||||
|
||||
$account = $validator->checkAccount($params[0]);
|
||||
|
||||
$salt = PasswordUtil::salt();
|
||||
$hash = PasswordUtil::hash($params[1], $salt);
|
||||
|
||||
$account->salt = $salt;
|
||||
$account->password = $hash;
|
||||
|
||||
$account->update();
|
||||
|
||||
echo 'reset password success' . PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭验证码
|
||||
*
|
||||
* @command: php console.php maintain disable_captcha
|
||||
*/
|
||||
public function disableCaptchaAction()
|
||||
{
|
||||
$service = new SettingService();
|
||||
|
||||
$service->updateSettings('captcha', ['enabled' => 0]);
|
||||
|
||||
echo 'disable captcha success' . PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用验证码
|
||||
*
|
||||
* @command: php console.php maintain enable_captcha
|
||||
*/
|
||||
public function enableCaptchaAction()
|
||||
{
|
||||
$service = new SettingService();
|
||||
|
||||
$service->updateSettings('captcha', ['enabled' => 1]);
|
||||
|
||||
echo 'enable captcha success' . PHP_EOL;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -10,13 +10,20 @@ use App\Repos\CourseUser as CourseUserRepo;
|
||||
use App\Repos\Order as OrderRepo;
|
||||
use App\Repos\Refund as RefundRepo;
|
||||
use App\Repos\Trade as TradeRepo;
|
||||
use App\Services\Alipay as AlipayService;
|
||||
use App\Services\Wxpay as WxpayService;
|
||||
use App\Repos\User as UserRepo;
|
||||
use App\Services\Pay\Alipay as AlipayService;
|
||||
use App\Services\Pay\Wxpay as WxpayService;
|
||||
use App\Services\Sms\Refund as RefundSms;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class RefundTask extends Task
|
||||
{
|
||||
|
||||
const TRY_COUNT = 5;
|
||||
/**
|
||||
* 重试次数
|
||||
*/
|
||||
const TRY_COUNT = 3;
|
||||
|
||||
public function mainAction()
|
||||
{
|
||||
@ -34,15 +41,32 @@ class RefundTask extends Task
|
||||
|
||||
foreach ($tasks as $task) {
|
||||
|
||||
$refund = $refundRepo->findBySn($task->item_info['refund']['sn']);
|
||||
$trade = $tradeRepo->findBySn($task->item_info['refund']['trade_sn']);
|
||||
$order = $orderRepo->findBySn($task->item_info['refund']['order_sn']);
|
||||
/**
|
||||
* @var array $itemInfo
|
||||
*/
|
||||
$itemInfo = $task->item_info;
|
||||
|
||||
$refund = $refundRepo->findById($itemInfo['refund']['id']);
|
||||
$trade = $tradeRepo->findById($itemInfo['refund']['trade_id']);
|
||||
$order = $orderRepo->findById($itemInfo['refund']['order_id']);
|
||||
|
||||
if (!$refund || !$trade || !$order) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款存在延迟,给取消退款调解机会
|
||||
*/
|
||||
if (isset($itemInfo['deadline']) && $itemInfo['deadline'] > time()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
$this->db->begin();
|
||||
|
||||
$this->handleTradeRefund($trade, $refund);
|
||||
|
||||
$this->handleOrderRefund($order);
|
||||
|
||||
$refund->status = RefundModel::STATUS_FINISHED;
|
||||
@ -71,25 +95,32 @@ class RefundTask extends Task
|
||||
|
||||
$this->db->commit();
|
||||
|
||||
$this->handleRefundNotice($refund);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
$this->db->rollback();
|
||||
|
||||
$task->try_count += 1;
|
||||
$task->priority += 1;
|
||||
|
||||
if ($task->try_count > self::TRY_COUNT) {
|
||||
$task->status = TaskModel::STATUS_FAILED;
|
||||
$refund->status = RefundModel::STATUS_FAILED;
|
||||
$refund->update();
|
||||
}
|
||||
|
||||
$task->update();
|
||||
|
||||
$logger->info('Refund Task Exception ' . kg_json_encode([
|
||||
'code' => $e->getCode(),
|
||||
'message' => $e->getMessage(),
|
||||
'task' => $task->toArray(),
|
||||
]));
|
||||
}
|
||||
|
||||
if ($task->status == TaskModel::STATUS_FAILED) {
|
||||
$refund->status = RefundModel::STATUS_FAILED;
|
||||
$refund->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,24 +135,20 @@ class RefundTask extends Task
|
||||
$response = false;
|
||||
|
||||
if ($trade->channel == TradeModel::CHANNEL_ALIPAY) {
|
||||
|
||||
$alipay = new AlipayService();
|
||||
$response = $alipay->refundOrder([
|
||||
'out_trade_no' => $trade->sn,
|
||||
'out_request_no' => $refund->sn,
|
||||
'refund_amount' => $refund->amount,
|
||||
]);
|
||||
|
||||
$response = $alipay->refund($refund);
|
||||
|
||||
} elseif ($trade->channel == TradeModel::CHANNEL_WXPAY) {
|
||||
|
||||
$wxpay = new WxpayService();
|
||||
$response = $wxpay->refundOrder([
|
||||
'out_trade_no' => $trade->sn,
|
||||
'out_refund_no' => $refund->sn,
|
||||
'total_fee' => 100 * $trade->order_amount,
|
||||
'refund_fee' => 100 * $refund->amount,
|
||||
]);
|
||||
|
||||
$response = $wxpay->refund($refund);
|
||||
}
|
||||
|
||||
if (!$response) {
|
||||
throw new \RuntimeException('Payment Refund Failed');
|
||||
throw new \RuntimeException('Pay Refund Failed');
|
||||
}
|
||||
}
|
||||
|
||||
@ -133,19 +160,19 @@ class RefundTask extends Task
|
||||
protected function handleOrderRefund(OrderModel $order)
|
||||
{
|
||||
switch ($order->item_type) {
|
||||
case OrderModel::TYPE_COURSE:
|
||||
case OrderModel::ITEM_COURSE:
|
||||
$this->handleCourseOrderRefund($order);
|
||||
break;
|
||||
case OrderModel::TYPE_PACKAGE:
|
||||
case OrderModel::ITEM_PACKAGE:
|
||||
$this->handlePackageOrderRefund($order);
|
||||
break;
|
||||
case OrderModel::TYPE_REWARD:
|
||||
$this->handleRewardOrderRefund($order);
|
||||
break;
|
||||
case OrderModel::TYPE_VIP:
|
||||
case OrderModel::ITEM_VIP:
|
||||
$this->handleVipOrderRefund($order);
|
||||
break;
|
||||
case OrderModel::TYPE_TEST:
|
||||
case OrderModel::ITEM_REWARD:
|
||||
$this->handleRewardOrderRefund($order);
|
||||
break;
|
||||
case OrderModel::ITEM_TEST:
|
||||
$this->handleTestOrderRefund($order);
|
||||
break;
|
||||
}
|
||||
@ -160,10 +187,12 @@ class RefundTask extends Task
|
||||
{
|
||||
$courseUserRepo = new CourseUserRepo();
|
||||
|
||||
$courseUser = $courseUserRepo->findCourseStudent($order->item_id, $order->user_id);
|
||||
$courseUser = $courseUserRepo->findCourseStudent($order->item_id, $order->owner_id);
|
||||
|
||||
if ($courseUser) {
|
||||
|
||||
$courseUser->deleted = 1;
|
||||
|
||||
if ($courseUser->update() === false) {
|
||||
throw new \RuntimeException('Delete Course User Failed');
|
||||
}
|
||||
@ -179,10 +208,19 @@ class RefundTask extends Task
|
||||
{
|
||||
$courseUserRepo = new CourseUserRepo();
|
||||
|
||||
foreach ($order->item_info['courses'] as $course) {
|
||||
$courseUser = $courseUserRepo->findCourseStudent($course['id'], $order->user_id);
|
||||
/**
|
||||
* @var array $itemInfo
|
||||
*/
|
||||
$itemInfo = $order->item_info;
|
||||
|
||||
foreach ($itemInfo['courses'] as $course) {
|
||||
|
||||
$courseUser = $courseUserRepo->findCourseStudent($course['id'], $order->owner_id);
|
||||
|
||||
if ($courseUser) {
|
||||
|
||||
$courseUser->deleted = 1;
|
||||
|
||||
if ($courseUser->update() === false) {
|
||||
throw new \RuntimeException('Delete Course User Failed');
|
||||
}
|
||||
@ -199,26 +237,19 @@ class RefundTask extends Task
|
||||
{
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$user = $userRepo->findById($order->user_id);
|
||||
$user = $userRepo->findById($order->owner_id);
|
||||
|
||||
$baseTime = $user->vip_expiry;
|
||||
/**
|
||||
* @var array $itemInfo
|
||||
*/
|
||||
$itemInfo = $order->item_info;
|
||||
|
||||
switch ($order->item_info['vip']['duration']) {
|
||||
case 'one_month':
|
||||
$user->vip_expiry = strtotime('-1 months', $baseTime);
|
||||
break;
|
||||
case 'three_month':
|
||||
$user->vip_expiry = strtotime('-3 months', $baseTime);
|
||||
break;
|
||||
case 'six_month':
|
||||
$user->vip_expiry = strtotime('-6 months', $baseTime);
|
||||
break;
|
||||
case 'twelve_month':
|
||||
$user->vip_expiry = strtotime('-12 months', $baseTime);
|
||||
break;
|
||||
}
|
||||
$diffTime = "-{$itemInfo['vip']['expiry']} months";
|
||||
$baseTime = $itemInfo['vip']['expiry_time'];
|
||||
|
||||
if ($user->vip_expiry < time()) {
|
||||
$user->vip_expiry_time = strtotime($diffTime, $baseTime);
|
||||
|
||||
if ($user->vip_expiry_time < time()) {
|
||||
$user->vip = 0;
|
||||
}
|
||||
|
||||
@ -228,7 +259,7 @@ class RefundTask extends Task
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理打赏订单退款
|
||||
* 处理测试订单退款
|
||||
*
|
||||
* @param OrderModel $order
|
||||
*/
|
||||
@ -248,26 +279,32 @@ class RefundTask extends Task
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找退款任务
|
||||
*
|
||||
* @param integer $limit
|
||||
* @return \Phalcon\Mvc\Model\ResultsetInterface
|
||||
* @param RefundModel $refund
|
||||
*/
|
||||
protected function findTasks($limit = 5)
|
||||
protected function handleRefundNotice(RefundModel $refund)
|
||||
{
|
||||
$sms = new RefundSms();
|
||||
|
||||
$sms->handle($refund);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|TaskModel[]
|
||||
*/
|
||||
protected function findTasks($limit = 30)
|
||||
{
|
||||
$itemType = TaskModel::TYPE_REFUND;
|
||||
$status = TaskModel::STATUS_PENDING;
|
||||
$tryCount = self::TRY_COUNT;
|
||||
|
||||
$tasks = TaskModel::query()
|
||||
return TaskModel::query()
|
||||
->where('item_type = :item_type:', ['item_type' => $itemType])
|
||||
->andWhere('status = :status:', ['status' => $status])
|
||||
->andWhere('try_count < :try_count:', ['try_count' => $tryCount])
|
||||
->orderBy('priority ASC,try_count DESC')
|
||||
->andWhere('try_count < :try_count:', ['try_count' => $tryCount + 1])
|
||||
->orderBy('priority ASC')
|
||||
->limit($limit)
|
||||
->execute();
|
||||
|
||||
return $tasks;
|
||||
}
|
||||
|
||||
}
|
||||
|
43
app/Console/Tasks/RevokeVipTask.php
Normal file
43
app/Console/Tasks/RevokeVipTask.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use App\Models\User as UserModel;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class RevokeVipTask extends Task
|
||||
{
|
||||
|
||||
public function mainAction()
|
||||
{
|
||||
$users = $this->findUsers();
|
||||
|
||||
if ($users->count() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($users as $user) {
|
||||
$user->vip = 0;
|
||||
$user->update();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找待解锁用户
|
||||
*
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|UserModel[]
|
||||
*/
|
||||
protected function findUsers($limit = 1000)
|
||||
{
|
||||
$time = time();
|
||||
|
||||
return UserModel::query()
|
||||
->where('vip = 1')
|
||||
->andWhere('vip_expiry_time < :time:', ['time' => $time])
|
||||
->limit($limit)
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
162
app/Console/Tasks/SitemapTask.php
Normal file
162
app/Console/Tasks/SitemapTask.php
Normal file
@ -0,0 +1,162 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use App\Library\Sitemap;
|
||||
use App\Models\Course as CourseModel;
|
||||
use App\Models\Help as HelpModel;
|
||||
use App\Models\ImGroup as ImGroupModel;
|
||||
use App\Models\Page as PageModel;
|
||||
use App\Models\Topic as TopicModel;
|
||||
use App\Models\User as UserModel;
|
||||
use App\Services\Service as AppService;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
|
||||
class SitemapTask extends Task
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $siteUrl;
|
||||
|
||||
/**
|
||||
* @var Sitemap
|
||||
*/
|
||||
protected $sitemap;
|
||||
|
||||
public function mainAction()
|
||||
{
|
||||
$this->siteUrl = $this->getSiteUrl();
|
||||
|
||||
$this->sitemap = new Sitemap();
|
||||
|
||||
$filename = public_path('sitemap.xml');
|
||||
|
||||
$this->addIndex();
|
||||
$this->addCourses();
|
||||
$this->addTeachers();
|
||||
$this->addTopics();
|
||||
$this->addImGroups();
|
||||
$this->addHelps();
|
||||
$this->addPages();
|
||||
$this->addOthers();
|
||||
|
||||
$this->sitemap->build($filename);
|
||||
}
|
||||
|
||||
protected function getSiteUrl()
|
||||
{
|
||||
$service = new AppService();
|
||||
|
||||
$settings = $service->getSettings('site');
|
||||
|
||||
return $settings['url'] ?? '';
|
||||
}
|
||||
|
||||
protected function addIndex()
|
||||
{
|
||||
$this->sitemap->addItem($this->siteUrl, 1);
|
||||
}
|
||||
|
||||
protected function addCourses()
|
||||
{
|
||||
/**
|
||||
* @var Resultset|CourseModel[] $courses
|
||||
*/
|
||||
$courses = CourseModel::query()->where('published = 1')->execute();
|
||||
|
||||
if ($courses->count() == 0) return;
|
||||
|
||||
foreach ($courses as $course) {
|
||||
$loc = sprintf('%s/course/%s', $this->siteUrl, $course->id);
|
||||
$this->sitemap->addItem($loc, 0.8);
|
||||
}
|
||||
}
|
||||
|
||||
protected function addTeachers()
|
||||
{
|
||||
/**
|
||||
* @var Resultset|UserModel[] $teachers
|
||||
*/
|
||||
$teachers = UserModel::query()->where('edu_role = 2')->execute();
|
||||
|
||||
if ($teachers->count() == 0) return;
|
||||
|
||||
foreach ($teachers as $teacher) {
|
||||
$loc = sprintf('%s/teacher/%s', $this->siteUrl, $teacher->id);
|
||||
$this->sitemap->addItem($loc, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
protected function addTopics()
|
||||
{
|
||||
/**
|
||||
* @var Resultset|TopicModel[] $topics
|
||||
*/
|
||||
$topics = TopicModel::query()->where('published = 1')->execute();
|
||||
|
||||
if ($topics->count() == 0) return;
|
||||
|
||||
foreach ($topics as $topic) {
|
||||
$loc = sprintf('%s/topic/%s', $this->siteUrl, $topic->id);
|
||||
$this->sitemap->addItem($loc, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
protected function addImGroups()
|
||||
{
|
||||
/**
|
||||
* @var Resultset|ImGroupModel[] $groups
|
||||
*/
|
||||
$groups = ImGroupModel::query()->where('published = 1')->execute();
|
||||
|
||||
if ($groups->count() == 0) return;
|
||||
|
||||
foreach ($groups as $group) {
|
||||
$loc = sprintf('%s/im/group/%s', $this->siteUrl, $group->id);
|
||||
$this->sitemap->addItem($loc, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
protected function addPages()
|
||||
{
|
||||
/**
|
||||
* @var Resultset|PageModel[] $pages
|
||||
*/
|
||||
$pages = PageModel::query()->where('published = 1')->execute();
|
||||
|
||||
if ($pages->count() == 0) return;
|
||||
|
||||
foreach ($pages as $page) {
|
||||
$loc = sprintf('%s/page/%s', $this->siteUrl, $page->id);
|
||||
$this->sitemap->addItem($loc, 0.7);
|
||||
}
|
||||
}
|
||||
|
||||
protected function addHelps()
|
||||
{
|
||||
/**
|
||||
* @var Resultset|HelpModel[] $helps
|
||||
*/
|
||||
$helps = HelpModel::query()->where('published = 1')->execute();
|
||||
|
||||
if ($helps->count() == 0) return;
|
||||
|
||||
foreach ($helps as $help) {
|
||||
$loc = sprintf('%s/help/%s', $this->siteUrl, $help->id);
|
||||
$this->sitemap->addItem($loc, 0.7);
|
||||
}
|
||||
}
|
||||
|
||||
protected function addOthers()
|
||||
{
|
||||
$this->sitemap->addItem('/course/list', 0.6);
|
||||
$this->sitemap->addItem('/im/group/list', 0.6);
|
||||
$this->sitemap->addItem('/teacher/list', 0.6);
|
||||
$this->sitemap->addItem('/vip', 0.6);
|
||||
$this->sitemap->addItem('/help', 0.6);
|
||||
$this->sitemap->addItem('/search', 0.6);
|
||||
}
|
||||
|
||||
}
|
@ -1,282 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use App\Models\Chapter as ChapterModel;
|
||||
use App\Models\Course as CourseModel;
|
||||
use App\Models\User as UserModel;
|
||||
use Phalcon\Cli\Task;
|
||||
use QL\QueryList;
|
||||
|
||||
class SpiderTask extends Task
|
||||
{
|
||||
|
||||
public function testAction()
|
||||
{
|
||||
$subject = '1-1 课程简介(01:40)开始学习';
|
||||
preg_match('/(\d{1,}-\d{1,})\s{1,}(.*?)\((.*?)\)/', $subject, $matches);
|
||||
dd($matches);
|
||||
}
|
||||
|
||||
public function courseListAction($params)
|
||||
{
|
||||
$category = $params[0] ?? 'html';
|
||||
$page = $params[1] ?? 1;
|
||||
|
||||
$categoryId = $this->getCategoryId($category);
|
||||
|
||||
if (empty($categoryId)) {
|
||||
throw new \Exception('invalid category');
|
||||
}
|
||||
|
||||
$url = "http://www.imooc.com/course/list?c={$category}&page={$page}";
|
||||
|
||||
$data = QueryList::get($url)->rules([
|
||||
'link' => ['a.course-card', 'href'],
|
||||
'title' => ['h3.course-card-name', 'text'],
|
||||
'cover' => ['img.course-banner', 'data-original'],
|
||||
'summary' => ['p.course-card-desc', 'text'],
|
||||
'level' => ['.course-card-info>span:even', 'text'],
|
||||
'user_count' => ['.course-card-info>span:odd', 'text'],
|
||||
])->query()->getData();
|
||||
|
||||
if ($data->count() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($data->all() as $item) {
|
||||
$course = [
|
||||
'id' => substr($item['link'], 7),
|
||||
'category_id' => $categoryId,
|
||||
'title' => $item['title'],
|
||||
'cover' => $item['cover'],
|
||||
'summary' => $item['summary'],
|
||||
'user_count' => $item['user_count'],
|
||||
'level' => $this->getLevel($item['level']),
|
||||
];
|
||||
$model = new CourseModel();
|
||||
$model->save($course);
|
||||
}
|
||||
|
||||
echo sprintf("saved: %d course", $data->count());
|
||||
}
|
||||
|
||||
public function courseAction()
|
||||
{
|
||||
$courses = CourseModel::query()
|
||||
->where('1 = 1')
|
||||
->andWhere('id > :id:', ['id' => 1128])
|
||||
->orderBy('id asc')
|
||||
->execute();
|
||||
|
||||
$baseUrl = 'http://www.imooc.com/learn';
|
||||
|
||||
$instance = QueryList::getInstance();
|
||||
|
||||
foreach ($courses as $course) {
|
||||
$url = $baseUrl . '/' . $course->id;
|
||||
$ql = $instance->get($url);
|
||||
$result = $this->handleCourseInfo($course, $ql);
|
||||
if (!$result) {
|
||||
continue;
|
||||
}
|
||||
$this->handleCourseChapters($course, $ql);
|
||||
echo "finished course " . $course->id . PHP_EOL;
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
public function teacherAction()
|
||||
{
|
||||
$courses = CourseModel::query()
|
||||
->where('1 = 1')
|
||||
->groupBy('user_id')
|
||||
->execute();
|
||||
|
||||
foreach ($courses as $course) {
|
||||
$this->handleTeacherInfo($course->user_id);
|
||||
echo "finished teacher: {$course->user_id}" . PHP_EOL;
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
public function userAction()
|
||||
{
|
||||
$users = UserModel::query()
|
||||
->where('1 = 1')
|
||||
->andWhere('name = :name:', ['name' => ''])
|
||||
->execute();
|
||||
|
||||
foreach ($users as $user) {
|
||||
$this->handleUserInfo($user->id);
|
||||
echo "finished user: {$user->id}" . PHP_EOL;
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
protected function handleUserInfo($id)
|
||||
{
|
||||
$url = 'http://www.imooc.com/u/'. $id;
|
||||
|
||||
$ql = QueryList::getInstance()->get($url);
|
||||
|
||||
$data = [];
|
||||
|
||||
$data['id'] = $id;
|
||||
$data['avatar'] = $ql->find('.user-pic-bg>img')->attr('src');
|
||||
$data['name'] = $ql->find('h3.user-name>span')->text();
|
||||
$data['about'] = $ql->find('p.user-desc')->text();
|
||||
|
||||
$user = new UserModel();
|
||||
|
||||
$user->save($data);
|
||||
}
|
||||
|
||||
protected function handleTeacherInfo($id)
|
||||
{
|
||||
$url = 'http://www.imooc.com/t/'. $id;
|
||||
|
||||
$ql = QueryList::getInstance()->get($url);
|
||||
|
||||
$data = [];
|
||||
|
||||
$data['id'] = $id;
|
||||
$data['avatar'] = $ql->find('img.tea-header')->attr('src');
|
||||
$data['name'] = $ql->find('p.tea-nickname')->text();
|
||||
$data['title'] = $ql->find('p.tea-professional')->text();
|
||||
$data['about'] = $ql->find('p.tea-desc')->text();
|
||||
|
||||
$user = new UserModel();
|
||||
|
||||
$user->create($data);
|
||||
}
|
||||
|
||||
protected function handleCourseInfo(CourseModel $course, QueryList $ql)
|
||||
{
|
||||
$data = [];
|
||||
|
||||
$data['user_id'] = $ql->find('img.js-usercard-dialog')->attr('data-userid');
|
||||
$data['description'] = $ql->find('.course-description')->text();
|
||||
$data['duration'] = $ql->find('.static-item:eq(1)>.meta-value')->text();
|
||||
$data['score'] = $ql->find('.score-btn>.meta-value')->text();
|
||||
|
||||
if (empty($data['user_id'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$data['duration'] = $this->getCourseDuration($data['duration']);
|
||||
|
||||
return $course->update($data);
|
||||
}
|
||||
|
||||
protected function handleCourseChapters(CourseModel $course, QueryList $ql)
|
||||
{
|
||||
$topChapters = $ql->rules([
|
||||
'title' => ['.chapter>h3', 'text'],
|
||||
'sub_chapter_html' => ['.chapter>.video', 'html'],
|
||||
])->query()->getData();
|
||||
|
||||
if ($topChapters->count() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($topChapters->all() as $item) {
|
||||
$data = [
|
||||
'course_id' => $course->id,
|
||||
'title' => $item['title'],
|
||||
];
|
||||
|
||||
// create top chapter
|
||||
$chapter = new ChapterModel();
|
||||
$chapter->create($data);
|
||||
|
||||
// create sub chapter
|
||||
if (!empty($item['sub_chapter_html'])) {
|
||||
$this->handleSubChapters($chapter, $item['sub_chapter_html']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function handleSubChapters(ChapterModel $topChapter, $subChapterHtml)
|
||||
{
|
||||
$ql = QueryList::html($subChapterHtml);
|
||||
|
||||
$chapters = $ql->find('li')->texts();
|
||||
|
||||
if ($chapters->count() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($chapters->all() as $item) {
|
||||
preg_match('/(\d{1,}-\d{1,})\s{1,}(.*?)\((.*?)\)/s', $item, $matches);
|
||||
if (!isset($matches[3]) || empty($matches[3])) {
|
||||
continue;
|
||||
}
|
||||
$data = [
|
||||
'course_id' => $topChapter->course_id,
|
||||
'parent_id' => $topChapter->id,
|
||||
'title' => $matches[2],
|
||||
'duration' => $this->getChapterDuration($matches[3]),
|
||||
];
|
||||
$model = new ChapterModel();
|
||||
$model->create($data);
|
||||
}
|
||||
}
|
||||
|
||||
protected function getCourseDuration($duration)
|
||||
{
|
||||
$hours = 0;
|
||||
$minutes = 0;
|
||||
|
||||
if (preg_match('/(.*?)小时(.*?)分/s', $duration, $matches)) {
|
||||
$hours = trim($matches[1]);
|
||||
$minutes = trim($matches[2]);
|
||||
} elseif (preg_match('/(.*?)分/s', $duration, $matches)) {
|
||||
$minutes = trim($matches[1]);
|
||||
}
|
||||
|
||||
return 3600 * $hours + 60 * $minutes;
|
||||
}
|
||||
|
||||
protected function getChapterDuration($duration)
|
||||
{
|
||||
if (strpos($duration, ':') === false) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
list($minutes, $seconds) = explode(':', trim($duration));
|
||||
|
||||
return 60 * $minutes + $seconds;
|
||||
}
|
||||
|
||||
protected function getLevel($type)
|
||||
{
|
||||
$mapping = [
|
||||
'入门' => CourseModel::LEVEL_ENTRY,
|
||||
'初级' => CourseModel::LEVEL_JUNIOR,
|
||||
'中级' => CourseModel::LEVEL_MIDDLE,
|
||||
'高级' => CourseModel::LEVEL_SENIOR,
|
||||
];
|
||||
|
||||
return $mapping[$type] ?? CourseModel::LEVEL_ENTRY;
|
||||
}
|
||||
|
||||
protected function getCategoryId($type)
|
||||
{
|
||||
$mapping = [
|
||||
'html' => 1, 'javascript' => 2, 'vuejs' => 10, 'reactjs' => 19,
|
||||
'angular' => 18, 'nodejs' => 16, 'jquery' => 15,
|
||||
'bootstrap' => 17, 'sassless' => 21, 'webapp' => 22, 'fetool' => 23,
|
||||
'html5' => 13, 'css3' => 14,
|
||||
'php' => 24, 'java' => 25, 'python' => 26, 'c' => 27, 'cplusplus' => 28, 'ruby' => 29, 'go' => 30, 'csharp' => 31,
|
||||
'android' => 32, 'ios' => 33,
|
||||
'mysql' => 36, 'mongodb' => 37, 'redis' => 38, 'oracle' => 39, 'pgsql' => 40,
|
||||
'cloudcomputing' => 42, 'bigdata' => 43,
|
||||
'unity3d' => 34, 'cocos2dx' => 35,
|
||||
'dxdh' => 46, 'uitool' => 47, 'uijc' => 48,
|
||||
];
|
||||
|
||||
return $mapping[$type] ?? 0;
|
||||
}
|
||||
|
||||
}
|
60
app/Console/Tasks/SyncCourseIndexTask.php
Normal file
60
app/Console/Tasks/SyncCourseIndexTask.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use App\Repos\Course as CourseRepo;
|
||||
use App\Services\Search\CourseDocument;
|
||||
use App\Services\Search\CourseSearcher;
|
||||
use App\Services\Sync\CourseIndex as CourseIndexSync;
|
||||
|
||||
class SyncCourseIndexTask extends Task
|
||||
{
|
||||
|
||||
public function mainAction()
|
||||
{
|
||||
$redis = $this->getRedis();
|
||||
|
||||
$key = $this->getSyncKey();
|
||||
|
||||
$courseIds = $redis->sRandMember($key, 1000);
|
||||
|
||||
if (!$courseIds) return;
|
||||
|
||||
$courseRepo = new CourseRepo();
|
||||
|
||||
$courses = $courseRepo->findByIds($courseIds);
|
||||
|
||||
if ($courses->count() == 0) return;
|
||||
|
||||
$document = new CourseDocument();
|
||||
|
||||
$handler = new CourseSearcher();
|
||||
|
||||
$index = $handler->getXS()->getIndex();
|
||||
|
||||
$index->openBuffer();
|
||||
|
||||
foreach ($courses as $course) {
|
||||
|
||||
$doc = $document->setDocument($course);
|
||||
|
||||
if ($course->published == 1) {
|
||||
$index->update($doc);
|
||||
} else {
|
||||
$index->del($course->id);
|
||||
}
|
||||
}
|
||||
|
||||
$index->closeBuffer();
|
||||
|
||||
$redis->sRem($key, ...$courseIds);
|
||||
}
|
||||
|
||||
protected function getSyncKey()
|
||||
{
|
||||
$sync = new CourseIndexSync();
|
||||
|
||||
return $sync->getSyncKey();
|
||||
}
|
||||
|
||||
}
|
60
app/Console/Tasks/SyncGroupIndexTask.php
Normal file
60
app/Console/Tasks/SyncGroupIndexTask.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use App\Repos\ImGroup as GroupRepo;
|
||||
use App\Services\Search\GroupDocument;
|
||||
use App\Services\Search\GroupSearcher;
|
||||
use App\Services\Sync\GroupIndex as GroupIndexSync;
|
||||
|
||||
class SyncGroupIndexTask extends Task
|
||||
{
|
||||
|
||||
public function mainAction()
|
||||
{
|
||||
$redis = $this->getRedis();
|
||||
|
||||
$key = $this->getSyncKey();
|
||||
|
||||
$groupIds = $redis->sRandMember($key, 1000);
|
||||
|
||||
if (!$groupIds) return;
|
||||
|
||||
$groupRepo = new GroupRepo();
|
||||
|
||||
$groups = $groupRepo->findByIds($groupIds);
|
||||
|
||||
if ($groups->count() == 0) return;
|
||||
|
||||
$document = new GroupDocument();
|
||||
|
||||
$handler = new GroupSearcher();
|
||||
|
||||
$index = $handler->getXS()->getIndex();
|
||||
|
||||
$index->openBuffer();
|
||||
|
||||
foreach ($groups as $group) {
|
||||
|
||||
$doc = $document->setDocument($group);
|
||||
|
||||
if ($group->published == 1) {
|
||||
$index->update($doc);
|
||||
} else {
|
||||
$index->del($group->id);
|
||||
}
|
||||
}
|
||||
|
||||
$index->closeBuffer();
|
||||
|
||||
$redis->sRem($key, ...$groupIds);
|
||||
}
|
||||
|
||||
protected function getSyncKey()
|
||||
{
|
||||
$sync = new GroupIndexSync();
|
||||
|
||||
return $sync->getSyncKey();
|
||||
}
|
||||
|
||||
}
|
177
app/Console/Tasks/SyncLearningTask.php
Normal file
177
app/Console/Tasks/SyncLearningTask.php
Normal file
@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use App\Models\Course as CourseModel;
|
||||
use App\Models\Learning as LearningModel;
|
||||
use App\Repos\Chapter as ChapterRepo;
|
||||
use App\Repos\ChapterUser as ChapterUserRepo;
|
||||
use App\Repos\Course as CourseRepo;
|
||||
use App\Repos\CourseUser as CourseUserRepo;
|
||||
use App\Repos\Learning as LearningRepo;
|
||||
use App\Services\Sync\Learning as LearningSync;
|
||||
|
||||
class SyncLearningTask extends Task
|
||||
{
|
||||
|
||||
public function mainAction()
|
||||
{
|
||||
$redis = $this->getRedis();
|
||||
|
||||
$sync = new LearningSync();
|
||||
|
||||
$syncKey = $sync->getSyncKey();
|
||||
|
||||
$requestIds = $redis->sMembers($syncKey);
|
||||
|
||||
if (!$requestIds) return;
|
||||
|
||||
foreach ($requestIds as $requestId) {
|
||||
|
||||
$itemKey = $sync->getItemKey($requestId);
|
||||
|
||||
$this->handleLearning($itemKey);
|
||||
|
||||
$redis->sRem($syncKey, $requestId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $itemKey
|
||||
*/
|
||||
protected function handleLearning($itemKey)
|
||||
{
|
||||
/**
|
||||
* @var LearningModel $cacheLearning
|
||||
*/
|
||||
$cacheLearning = $this->cache->get($itemKey);
|
||||
|
||||
if (!$cacheLearning) return;
|
||||
|
||||
$learningRepo = new LearningRepo();
|
||||
|
||||
$dbLearning = $learningRepo->findByRequestId($cacheLearning->request_id);
|
||||
|
||||
if (!$dbLearning) {
|
||||
|
||||
$cacheLearning->create();
|
||||
|
||||
$this->updateChapterUser($cacheLearning);
|
||||
|
||||
} else {
|
||||
|
||||
$dbLearning->duration += $cacheLearning->duration;
|
||||
$dbLearning->position = $cacheLearning->position;
|
||||
$dbLearning->active_time = $cacheLearning->active_time;
|
||||
|
||||
$dbLearning->update();
|
||||
|
||||
$this->updateChapterUser($dbLearning);
|
||||
}
|
||||
|
||||
$this->cache->delete($itemKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param LearningModel $learning
|
||||
*/
|
||||
protected function updateChapterUser(LearningModel $learning)
|
||||
{
|
||||
$chapterUserRepo = new ChapterUserRepo();
|
||||
|
||||
$chapterUser = $chapterUserRepo->findPlanChapterUser($learning->chapter_id, $learning->user_id, $learning->plan_id);
|
||||
|
||||
if (!$chapterUser) return;
|
||||
|
||||
$chapterRepo = new ChapterRepo();
|
||||
|
||||
$chapter = $chapterRepo->findById($learning->chapter_id);
|
||||
|
||||
if (!$chapter) return;
|
||||
|
||||
$chapterUser->duration += $learning->duration;
|
||||
|
||||
/**
|
||||
* 消费规则
|
||||
*
|
||||
* 1.点播观看时间大于时长30%
|
||||
* 2.直播观看时间超过10分钟
|
||||
* 3.图文浏览即消费
|
||||
*/
|
||||
if ($chapter->model == CourseModel::MODEL_VOD) {
|
||||
|
||||
$duration = $chapter->attrs['duration'] ?: 300;
|
||||
|
||||
$progress = floor(100 * $chapterUser->duration / $duration);
|
||||
|
||||
$chapterUser->position = floor($learning->position);
|
||||
$chapterUser->progress = $progress < 100 ? $progress : 100;
|
||||
$chapterUser->consumed = $chapterUser->duration > 0.3 * $duration ? 1 : 0;
|
||||
|
||||
} elseif ($chapter->model == CourseModel::MODEL_LIVE) {
|
||||
|
||||
$chapterUser->consumed = $chapterUser->duration > 600 ? 1 : 0;
|
||||
|
||||
} elseif ($chapter->model == CourseModel::MODEL_READ) {
|
||||
|
||||
$chapterUser->consumed = 1;
|
||||
}
|
||||
|
||||
$chapterUser->update();
|
||||
|
||||
if ($chapterUser->consumed == 1) {
|
||||
$this->updateCourseUser($learning);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param LearningModel $learning
|
||||
*/
|
||||
protected function updateCourseUser(LearningModel $learning)
|
||||
{
|
||||
$courseUserRepo = new CourseUserRepo();
|
||||
|
||||
$courseUser = $courseUserRepo->findPlanCourseUser($learning->course_id, $learning->user_id, $learning->plan_id);
|
||||
|
||||
if (!$courseUser) return;
|
||||
|
||||
$courseRepo = new CourseRepo();
|
||||
|
||||
$courseLessons = $courseRepo->findLessons($learning->course_id);
|
||||
|
||||
if ($courseLessons->count() == 0) return;
|
||||
|
||||
$userLearnings = $courseRepo->findUserLearnings($learning->course_id, $learning->user_id, $learning->plan_id);
|
||||
|
||||
if ($userLearnings->count() == 0) return;
|
||||
|
||||
$consumedUserLearnings = [];
|
||||
|
||||
foreach ($userLearnings->toArray() as $userLearning) {
|
||||
if ($userLearning['consumed'] == 1) {
|
||||
$consumedUserLearnings[] = $userLearning;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($consumedUserLearnings) == 0) return;
|
||||
|
||||
$duration = 0;
|
||||
|
||||
foreach ($consumedUserLearnings as $userLearning) {
|
||||
$duration += $userLearning['duration'];
|
||||
}
|
||||
|
||||
$courseLessonIds = kg_array_column($courseLessons->toArray(), 'id');
|
||||
$consumedUserLessonIds = kg_array_column($consumedUserLearnings, 'chapter_id');
|
||||
$consumedLessonIds = array_intersect($courseLessonIds, $consumedUserLessonIds);
|
||||
|
||||
$totalCount = count($courseLessonIds);
|
||||
$consumedCount = count($consumedLessonIds);
|
||||
$progress = intval(100 * $consumedCount / $totalCount);
|
||||
|
||||
$courseUser->progress = $progress;
|
||||
$courseUser->duration = $duration;
|
||||
$courseUser->update();
|
||||
}
|
||||
|
||||
}
|
60
app/Console/Tasks/SyncUserIndexTask.php
Normal file
60
app/Console/Tasks/SyncUserIndexTask.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use App\Repos\User as UserRepo;
|
||||
use App\Services\Search\UserDocument;
|
||||
use App\Services\Search\UserSearcher;
|
||||
use App\Services\Sync\UserIndex as UserIndexSync;
|
||||
|
||||
class SyncUserIndexTask extends Task
|
||||
{
|
||||
|
||||
public function mainAction()
|
||||
{
|
||||
$redis = $this->getRedis();
|
||||
|
||||
$key = $this->getSyncKey();
|
||||
|
||||
$userIds = $redis->sRandMember($key, 1000);
|
||||
|
||||
if (!$userIds) return;
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$users = $userRepo->findByIds($userIds);
|
||||
|
||||
if ($users->count() == 0) return;
|
||||
|
||||
$document = new UserDocument();
|
||||
|
||||
$handler = new UserSearcher();
|
||||
|
||||
$index = $handler->getXS()->getIndex();
|
||||
|
||||
$index->openBuffer();
|
||||
|
||||
foreach ($users as $user) {
|
||||
|
||||
$doc = $document->setDocument($user);
|
||||
|
||||
if ($user->deleted == 0) {
|
||||
$index->update($doc);
|
||||
} else {
|
||||
$index->del($user->id);
|
||||
}
|
||||
}
|
||||
|
||||
$index->closeBuffer();
|
||||
|
||||
$redis->sRem($key, ...$userIds);
|
||||
}
|
||||
|
||||
protected function getSyncKey()
|
||||
{
|
||||
$sync = new UserIndexSync();
|
||||
|
||||
return $sync->getSyncKey();
|
||||
}
|
||||
|
||||
}
|
@ -2,16 +2,46 @@
|
||||
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use App\Library\Logger;
|
||||
use App\Services\Service as AppService;
|
||||
|
||||
|
||||
class Task extends \Phalcon\Cli\Task
|
||||
{
|
||||
|
||||
public function getConfig()
|
||||
{
|
||||
$appService = new AppService();
|
||||
|
||||
return $appService->getConfig();
|
||||
}
|
||||
|
||||
|
||||
public function getCache()
|
||||
{
|
||||
$appService = new AppService();
|
||||
|
||||
return $appService->getCache();
|
||||
}
|
||||
|
||||
public function getRedis()
|
||||
{
|
||||
$appService = new AppService();
|
||||
|
||||
return $appService->getRedis();
|
||||
}
|
||||
|
||||
public function getLogger($channel = null)
|
||||
{
|
||||
$logger = new Logger();
|
||||
$appService = new AppService();
|
||||
|
||||
return $logger->getInstance($channel);
|
||||
return $appService->getLogger($channel);
|
||||
}
|
||||
|
||||
public function getSettings($section)
|
||||
{
|
||||
$appService = new AppService();
|
||||
|
||||
return $appService->getLogger($section);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,7 +3,8 @@
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use App\Models\User as UserModel;
|
||||
use Phalcon\Cli\Task;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class UnlockUserTask extends Task
|
||||
{
|
||||
@ -12,34 +13,28 @@ class UnlockUserTask extends Task
|
||||
{
|
||||
$users = $this->findUsers();
|
||||
|
||||
if ($users->count() == 0) {
|
||||
return;
|
||||
}
|
||||
if ($users->count() == 0) return;
|
||||
|
||||
foreach ($users as $user) {
|
||||
$user->locked = 0;
|
||||
$user->locked_expiry = 0;
|
||||
$user->update();
|
||||
$user->update(['locked' => 0]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找待解锁用户
|
||||
*
|
||||
* @param integer $limit
|
||||
* @return \Phalcon\Mvc\Model\ResultsetInterface
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|UserModel[]
|
||||
*/
|
||||
protected function findUsers($limit = 1000)
|
||||
{
|
||||
$time = time() - 6 * 3600;
|
||||
|
||||
$users = UserModel::query()
|
||||
return UserModel::query()
|
||||
->where('locked = 1')
|
||||
->andWhere('locked_expiry < :time:', ['time' => $time])
|
||||
->andWhere('lock_expiry_time < :time:', ['time' => $time])
|
||||
->limit($limit)
|
||||
->execute();
|
||||
|
||||
return $users;
|
||||
}
|
||||
|
||||
}
|
||||
|
127
app/Console/Tasks/UpgradeTask.php
Normal file
127
app/Console/Tasks/UpgradeTask.php
Normal file
@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use App\Caches\Setting as SettingCache;
|
||||
use App\Models\Setting as SettingModel;
|
||||
|
||||
class UpgradeTask extends Task
|
||||
{
|
||||
|
||||
public function mainAction()
|
||||
{
|
||||
$this->resetSettingAction();
|
||||
$this->resetAnnotationAction();
|
||||
$this->resetMetadataAction();
|
||||
$this->resetVoltAction();
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置系统设置
|
||||
*
|
||||
* @command: php console.php upgrade reset_setting
|
||||
*/
|
||||
public function resetSettingAction()
|
||||
{
|
||||
echo "start reset setting..." . PHP_EOL;
|
||||
|
||||
$rows = SettingModel::query()->columns('section')->distinct(true)->execute();
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$cache = new SettingCache();
|
||||
$cache->rebuild($row->section);
|
||||
}
|
||||
|
||||
echo "end reset setting..." . PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置注解
|
||||
*
|
||||
* @command: php console.php upgrade reset_annotation
|
||||
*/
|
||||
public function resetAnnotationAction()
|
||||
{
|
||||
$config = $this->getConfig();
|
||||
|
||||
$redis = $this->getRedis();
|
||||
|
||||
$dbIndex = $config->path('annotation.db');
|
||||
$statsKey = $config->path('annotation.statsKey');
|
||||
|
||||
$redis->select($dbIndex);
|
||||
|
||||
$keys = $redis->sMembers($statsKey);
|
||||
|
||||
echo "start reset annotation..." . PHP_EOL;
|
||||
|
||||
if (count($keys) > 0) {
|
||||
|
||||
$keys = $this->handlePhKeys($keys);
|
||||
|
||||
$redis->del(...$keys);
|
||||
$redis->del($statsKey);
|
||||
}
|
||||
|
||||
echo "end reset annotation..." . PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置元数据
|
||||
*
|
||||
* @command: php console.php upgrade reset_metadata
|
||||
*/
|
||||
public function resetMetadataAction()
|
||||
{
|
||||
$config = $this->getConfig();
|
||||
|
||||
$redis = $this->getRedis();
|
||||
|
||||
$dbIndex = $config->path('metadata.db');
|
||||
$statsKey = $config->path('metadata.statsKey');
|
||||
|
||||
$redis->select($dbIndex);
|
||||
|
||||
$keys = $redis->sMembers($statsKey);
|
||||
|
||||
echo "start reset metadata..." . PHP_EOL;
|
||||
|
||||
if (count($keys) > 0) {
|
||||
|
||||
$keys = $this->handlePhKeys($keys);
|
||||
|
||||
$redis->del(...$keys);
|
||||
$redis->del($statsKey);
|
||||
}
|
||||
|
||||
echo "start reset metadata..." . PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置模板
|
||||
*
|
||||
* @command: php console.php upgrade reset_volt
|
||||
*/
|
||||
public function resetVoltAction()
|
||||
{
|
||||
echo "start reset volt..." . PHP_EOL;
|
||||
|
||||
$dir = cache_path('volt');
|
||||
|
||||
foreach (scandir($dir) as $file) {
|
||||
if (strpos($file, '.php')) {
|
||||
unlink($dir . '/' . $file);
|
||||
}
|
||||
}
|
||||
|
||||
echo "end reset volt..." . PHP_EOL;
|
||||
}
|
||||
|
||||
protected function handlePhKeys($keys)
|
||||
{
|
||||
return array_map(function ($key) {
|
||||
return "_PHCR{$key}";
|
||||
}, $keys);
|
||||
}
|
||||
|
||||
}
|
125
app/Console/Tasks/UserIndexTask.php
Normal file
125
app/Console/Tasks/UserIndexTask.php
Normal file
@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use App\Models\User as UserModel;
|
||||
use App\Services\Search\UserDocument;
|
||||
use App\Services\Search\UserSearcher;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class UserIndexTask extends Task
|
||||
{
|
||||
|
||||
/**
|
||||
* 搜索测试
|
||||
*
|
||||
* @command: php console.php user_index search {query}
|
||||
* @param array $params
|
||||
* @throws \XSException
|
||||
*/
|
||||
public function searchAction($params)
|
||||
{
|
||||
$query = $params[0] ?? null;
|
||||
|
||||
if (!$query) {
|
||||
exit('please special a query word' . PHP_EOL);
|
||||
}
|
||||
|
||||
$result = $this->searchUsers($query);
|
||||
|
||||
var_export($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空索引
|
||||
*
|
||||
* @command: php console.php user_index clean
|
||||
*/
|
||||
public function cleanAction()
|
||||
{
|
||||
$this->cleanUserIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* 重建索引
|
||||
*
|
||||
* @command: php console.php user_index rebuild
|
||||
*/
|
||||
public function rebuildAction()
|
||||
{
|
||||
$this->rebuildUserIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空索引
|
||||
*/
|
||||
protected function cleanUserIndex()
|
||||
{
|
||||
$handler = new UserSearcher();
|
||||
|
||||
$index = $handler->getXS()->getIndex();
|
||||
|
||||
echo 'start clean index' . PHP_EOL;
|
||||
|
||||
$index->clean();
|
||||
|
||||
echo 'end clean index' . PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重建索引
|
||||
*/
|
||||
protected function rebuildUserIndex()
|
||||
{
|
||||
$users = $this->findUsers();
|
||||
|
||||
if ($users->count() == 0) return;
|
||||
|
||||
$handler = new UserSearcher();
|
||||
|
||||
$documenter = new UserDocument();
|
||||
|
||||
$index = $handler->getXS()->getIndex();
|
||||
|
||||
echo 'start rebuild index' . PHP_EOL;
|
||||
|
||||
$index->beginRebuild();
|
||||
|
||||
foreach ($users as $user) {
|
||||
$document = $documenter->setDocument($user);
|
||||
$index->add($document);
|
||||
}
|
||||
|
||||
$index->endRebuild();
|
||||
|
||||
echo 'end rebuild index' . PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索课程
|
||||
*
|
||||
* @param string $query
|
||||
* @return array
|
||||
* @throws \XSException
|
||||
*/
|
||||
protected function searchUsers($query)
|
||||
{
|
||||
$handler = new UserSearcher();
|
||||
|
||||
return $handler->search($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找课程
|
||||
*
|
||||
* @return ResultsetInterface|Resultset|UserModel[]
|
||||
*/
|
||||
protected function findUsers()
|
||||
{
|
||||
return UserModel::query()
|
||||
->where('deleted = 0')
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user