| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381 |
- <?php
- namespace addons\Course\common\models;
- use addons\Course\common\enums\CourseEnum;
- use common\components\export\CsvTool;
- use common\enums\RabbitMqEnum;
- use common\enums\StatusEnum;
- use common\helpers\CurlHelper;
- use common\helpers\FfmpegHelper;
- use common\models\api\AccessToken;
- use common\models\common\Attachment;
- use common\models\goods\Goods;
- use common\models\mall\Mall;
- /**
- * This is the model class for table "{{%addons_course_chapter}}".
- *
- * @property int $id
- * @property int $mall_id 商城id
- * @property int $course_id 课程id
- * @property int $dir_id 课程目录id,如果此字段值为0,说明没有二级目录
- * @property string $name 课程章节名称
- * @property string $video_url 课程章节视频url地址
- * @property int $type 视频类型 默认是0(视频) 0:视频 1:音频
- * @property string $goods_list 商品列表,用逗号连接
- * @property int $can_see 是否允许试看 默认允许 1:允许 0:不允许
- * @property int $views 课程章节实际播放次数
- * @property int $sort 序号 按asc升序排列
- * @property string $thumb_url 视频首图
- * @property int $status 状态 0禁用,1启用,-1是删除
- * @property int $created_at
- * @property int $updated_at
- * @property int $video_length 视频时长
- * @property int $can_see_time 试看时长,单位:秒
- */
- class AddonsCourseChapter extends \common\models\base\BaseActiveRecord
- {
- /**
- * {@inheritdoc}
- */
- public static function tableName()
- {
- return '{{%addons_course_chapter}}';
- }
- /**
- * {@inheritdoc}
- */
- public function rules()
- {
- return [
- [['mall_id', 'course_id', 'dir_id', 'type', 'can_see', 'views', 'sort', 'status', 'can_see_time', 'created_at', 'updated_at','select_type'], 'integer'],
- [['name', 'thumb_url'], 'string', 'max' => 255],
- [['video_url'], 'string', 'max' => 1000],
- [['goods_list'], 'string', 'max' => 1000],
- ['video_length', 'string', 'max' => 50],
- ];
- }
- /**
- * {@inheritdoc}
- */
- public function attributeLabels()
- {
- return [
- 'id' => 'ID',
- 'mall_id' => '商城id',
- 'course_id' => '课程id',
- 'dir_id' => '课程目录id,如果此字段值为0,说明没有二级目录',
- 'name' => '课程章节名称',
- 'video_url' => '课程章节视频url地址',
- 'type' => '视频类型 默认是1(视频) 1:视频 2:音频',
- 'goods_list' => '商品列表,用逗号连接',
- 'can_see' => '是否允许试看 默认允许 1:允许 0:不允许',
- 'views' => '课程章节实际播放次数',
- 'sort' => '序号 按asc升序排列',
- 'thumb_url' => '视频首图',
- 'status' => '状态 0禁用,1启用,-1是删除',
- 'created_at' => 'Created At',
- 'updated_at' => 'Updated At',
- 'video_length' => '视频时长',
- 'can_see_time' => '试看时长,单位:秒',
- ];
- }
- public static function setData(int $mall_id, array $data)
- {
- if (!empty($data['goods_list']) && is_array($data['goods_list'])) {
- $data['goods_list'] = implode(',', $data['goods_list']);
- }
- if (!empty($data['id'])) {
- $model = self::findOne(['mall_id' => $mall_id, 'status' => StatusEnum::ENABLED, 'id' => $data['id']]);
- if (empty($model)) {
- self::$static_error = '数据异常';
- return false;
- }
- } else {
- $model = new self();
- $model->loadDefaultValues();
- $model->mall_id = $mall_id;
- $model->status = StatusEnum::ENABLED;
- }
- foreach ($data as $key => $val) {
- $model->$key = $val;
- }
- $is_obtain_duration = false;
- $upload_file_info = Attachment::find()
- ->select('id,url,duration_str,thumb_url')
- ->where(['mall_id' => $mall_id, 'upload_type' => Attachment::UPLOAD_TYPE_VIDEOS, 'url' => $model->video_url])
- ->limit(1)
- ->one();
- if (empty($upload_file_info)) {
- if (!empty($data['type']) && CourseEnum::CHAPTER_TYPE_VIDEO == $data['type']) {
- $is_obtain_duration = true;
- }
- } else {
- // $model->video_length = $upload_file_info->duration_str;
- $model->thumb_url = $upload_file_info->thumb_url;
- }
- if ($is_obtain_duration) {
- // 需要异步获取视频时长
- $params = [
- 'id' => $model->id,
- 'mall_id' => $mall_id,
- ];
- \Yii::$app->services->rabbitMq->push(RabbitMqEnum::EXCHANGE_ORDER, RabbitMqEnum::ORDER_QUEUE, $params, self::class, 'obtainVideoDuration');
- }
- if (!$model->save()) {
- self::$static_error = '保存数据失败:' . $model->getErrorMessage();
- return false;
- }
- return $model;
- }
- /**
- * 批量获取商品详情
- * @param $goods_id_list string 用逗号连接的商品ID
- * @param bool $first boolean 获取第一个商品 true 是 false 否
- * @return array
- */
- public static function getAllGoods($goods_id_list, $first = true)
- {
- if (is_string($goods_id_list)) {
- $goods_ids = explode(',', $goods_id_list);
- } else {
- $goods_ids = $goods_id_list;
- }
- $list = Goods::find()
- ->select( 'id,stock as good_stock,goods_name as name,detail,cover_pic,price,sales_num as sales' )
- ->where(['status' => StatusEnum::ENABLED, 'id' => $goods_ids])
- ->asArray()
- ->all();
- if ($first) {
- $list = $list[0];
- }
- return $list;
- }
- /**
- * 拆分商品ID列表数据
- * @param $goods_id_list string
- * @return array
- */
- public static function explodeGoodsIdList($goods_id_list)
- {
- $result = [];
- $goods_id_list = trim($goods_id_list, ",");
- if (!empty($goods_id_list)) {
- $result = explode(",", $goods_id_list);
- }
- return $result;
- }
- /**
- * 获取单个商品详情
- * @param $goods_id int 商品ID
- * @return array
- */
- public static function getOneGoods($goods_id)
- {
- $result = [];
- $goods_info = Goods::findOne($goods_id);
- if (!empty($goods_info)) {
- $result = [
- 'id' => $goods_info->id,
- 'goods_stock' => $goods_info->stock,
- 'name' => $goods_info->goods_name,
- 'detail' => $goods_info->detail,
- 'cover_pic' => $goods_info->cover_pic,
- 'price' => $goods_info->price,
- 'sales' => $goods_info->virtual_sales,
- ];
- }
- return $result;
- }
- /**
- * @name:
- * @msg: 把秒转换为 时分秒 的表示形式
- * @param {int} $seconds
- * @return {string}
- */
- public static function convertTime(int $seconds): string
- {
- if (empty($seconds)) {
- return $seconds;
- }
- // 一个小时的秒数
- $hour_seconds = 60 * 60;
- $minute_seconds = 60;
- // 小时数
- $hours = floor($seconds / $hour_seconds);
- // 除去整小时后剩余秒数
- $hour_surplus_seconds = $seconds % $hour_seconds;
- // 分钟数
- $minutes = floor($hour_surplus_seconds / $minute_seconds);
- // 除去整分钟后剩余的秒数
- $minute_surplus_seconds = $hour_surplus_seconds % $minute_seconds;
- $res = '';
- if (!empty($hours)) {
- $hours = mb_strlen($hours) > 1 ? $hours : '0' . $hours;
- $res .= $hours . ':';
- } else {
- $res .= '00:';
- }
- if (!empty($minutes)) {
- $minutes = mb_strlen($minutes) > 1 ? $minutes : '0' . $minutes;
- $res .= $minutes . ':';
- } else {
- $res .= '00:';
- }
- if (!empty($minute_surplus_seconds)) {
- $minute_surplus_seconds = mb_strlen($minute_surplus_seconds) > 1 ? $minute_surplus_seconds : '0' . $minute_surplus_seconds;
- $res .= $minute_surplus_seconds;
- } else {
- $res .= '00';
- }
- return $res;
- }
- /**
- * 获取章节详情
- * @Author: guyu
- * @DateTime:2021-03-23 15:23
- * @param $id int 章节ID
- * @return mixed
- */
- public static function getDetail($id)
- {
- $result = self::findOne(['id' => $id, 'status' => StatusEnum::ENABLED]);
- if (!empty($result)) {
- $result->goods_list = self::explodeGoodsIdList($result->goods_list);
- }
- return $result;
- }
- /**
- * 更新章节的播放次数 课程的播放次数
- * @param $id int 章节ID
- * @param $course_id int 课程ID
- * @return boolean | \Exception
- */
- public static function updateViews($id, $course_id)
- {
- $trans = \Yii::$app->db->beginTransaction();
- try {
- $chapter = self::getDetail($id);
- $course = AddonsCourse::getDetail($course_id, $chapter->mall_id);
- //设置章节视频播放次数 + 1
- //$chapter->views = $chapter->views + 1;
- if (!$chapter->updateCounters(['views' => 1])) {
- throw new \Exception("保存课程章节视频播放次数失败");
- }
- //设置课程视频播放次数 + 1
- //$course->views = $course->views + 1;
- if (!$course->updateCounters(['views' => 1])) {
- throw new \Exception("保存课程播放次数失败");
- }
- $trans->commit();
- return true;
- } catch (\Exception $ex) {
- $trans->rollBack();
- throw new \Exception($ex->getMessage());
- }
- return false;
- }
- /**
- * @name:
- * @msg: 获取课程章节视频时长,异步队列调用
- * @param {array} $params id:章节 id;mall_id:商城 id
- * @return {*}
- */
- public static function obtainVideoDuration(array $params = null)
- {
- try {
- if (empty($params) || empty($params['id']) || empty($params['mall_id'])) {
- throw new \Exception('参数错误。params => ' . var_export($params, true));
- }
- $model = self::find()
- ->where(['mall_id' => $params['mall_id'], 'id' => $params['id']])
- ->one();
- if (empty($model) || empty($model->video_url)) {
- throw new \Exception('章节或视频不存在');
- }
- $path = '/tmp/course-chapter-video/';
- if (!file_exists($path)) {
- mkdir($path, 0755);
- }
- $fileinfo = pathinfo($model->video_url);
- // dd($fileinfo);
- $tmp_video_file = $path . $fileinfo['basename'];
- $tmp_thumb_file = $path . $fileinfo['filename'] . '.jpg';
- $video_str = file_get_contents($model->video_url);
- file_put_contents($tmp_video_file, $video_str);
- $video_info = FfmpegHelper::getVideoInfo($tmp_video_file);
- // dd($video_info);
- FfmpegHelper::imageResize($tmp_video_file, $tmp_thumb_file, '00:00:01');
- $datas = [
- 'id' => $params['id'],
- 'video_length' => $video_info['duration'],
- ];
- if (file_exists($tmp_thumb_file)) {
- $query = AccessToken::find()->where(['status' => StatusEnum::ENABLED])->orderBy('created_at desc');
- $token = '';
- foreach ($query->each(5) as $token_info) {
- $timestamp = (int)substr($token_info->access_token, strrpos($token_info->access_token, '_') + 1);
- $expire = 1296000;
- // 验证有效期
- if ($timestamp + $expire <= time()) {
- continue;
- }
- $token = $token_info->access_token;
- break;
- }
- $mall = Mall::findOne($params['mall_id']);
- $headers = [
- 'x-access-token' => $token,
- 'x-app-platform' => 'h5',
- 'x-mall-sign' => $mall->mall_sign ?? '',
- 'x-parent-id' => -1,
- 'x-source' => 0,
- ];
- $upload_url = \Yii::getAlias('@apiUrl') . '/index.php/v1/file/upload';
- $upload_res = CurlHelper::upload($upload_url, $tmp_thumb_file, $headers);
- if ($upload_res['code'] != 0) {
- throw new \Exception('首帧图片上传出错--' . $upload_res['msg']);
- }
- // dd($thumb_url);
- $datas['thumb_url'] = $upload_res['data']['url'];
- }
- $res = self::setData($params['mall_id'], $datas);
- if (false === $res) {
- throw new \Exception(self::getStaticError());
- }
- // 删除临时文件
- unlink($tmp_thumb_file);
- unlink($tmp_video_file);
- return true;
- } catch (\Exception $e) {
- \Yii::error('异步获取章节视频时长出错:' . $e->getMessage() . ', file: ' . $e->getFile() . ', line: ' . $e->getLine());
- \Yii::getLogger()->flush(true);
- }
- }
- }
|