Article.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. <?php
  2. /**
  3. * Author: lf
  4. * Blog: https://blog.feehi.com
  5. * Email: job@feehi.com
  6. * Created at: 2016-10-16 17:15
  7. */
  8. namespace common\models;
  9. use Yii;
  10. use common\helpers\Util;
  11. use common\models\meta\ArticleMetaImages;
  12. use common\models\meta\ArticleMetaLike;
  13. use common\models\meta\ArticleMetaTag;
  14. use feehi\cdn\TargetAbstract;
  15. use common\libs\Constants;
  16. use yii\behaviors\TimestampBehavior;
  17. use yii\web\UploadedFile;
  18. /**
  19. * This is the model class for table "{{%article}}".
  20. *
  21. * @property integer $id
  22. * @property integer $cid
  23. * @property integer $type
  24. * @property string $title
  25. * @property string $sub_title
  26. * @property string $summary
  27. * @property string $thumb
  28. * @property string $seo_title
  29. * @property string $seo_keywords
  30. * @property string $seo_description
  31. * @property integer $status
  32. * @property integer $sort
  33. * @property integer $author_id
  34. * @property string $author_name
  35. * @property integer $scan_count
  36. * @property integer $comment_count
  37. * @property integer $can_comment
  38. * @property integer $visibility
  39. * @property string $password
  40. * @property integer $flag_headline
  41. * @property integer $flag_recommend
  42. * @property integer $flag_slide_show
  43. * @property integer $flag_special_recommend
  44. * @property integer $flag_roll
  45. * @property integer $flag_bold
  46. * @property integer $flag_picture
  47. * @property string $template
  48. * @property integer $created_at
  49. * @property integer $updated_at
  50. *
  51. * @property ArticleContent $articleContent
  52. * @property Category $category
  53. */
  54. class Article extends \yii\db\ActiveRecord
  55. {
  56. const ARTICLE = 0;
  57. const SINGLE_PAGE = 2;
  58. const ARTICLE_PUBLISHED = 1;
  59. const ARTICLE_DRAFT = 0;
  60. /**
  61. * @var string
  62. */
  63. public $tag = '';
  64. /**
  65. * 需要截取的文章缩略图尺寸
  66. */
  67. public static $thumbSizes = [
  68. ["w"=>220, "h"=>150],//首页文章列表
  69. ["w"=>168, "h"=>112],//精选导读
  70. ["w"=>185, "h"=>110],//文章详情下边图片推荐
  71. ["w"=>125, "h"=>86],//热门推荐
  72. ];
  73. /**
  74. * @var array
  75. */
  76. public $images;
  77. public function behaviors()
  78. {
  79. return [
  80. TimestampBehavior::className(),
  81. ];
  82. }
  83. /**
  84. * @inheritdoc
  85. */
  86. public static function tableName()
  87. {
  88. return '{{%article}}';
  89. }
  90. /**
  91. * @inheritdoc
  92. */
  93. public function rules()
  94. {
  95. return [
  96. [['cid', 'type', 'status', 'sort', 'author_id', 'can_comment', 'visibility'], 'integer'],
  97. [['cid', 'sort', 'author_id'], 'compare', 'compareValue' => 0, 'operator' => '>='],
  98. [['title', 'status'], 'required'],
  99. [['can_comment'], 'default', 'value' => Constants::YesNo_Yes],
  100. [['visibility'], 'default', 'value' => Constants::ARTICLE_VISIBILITY_PUBLIC],
  101. [['thumb'], 'file', 'skipOnEmpty' => true, 'extensions' => 'png, jpg, jpeg, gif, webp'],
  102. [['images'], 'safe'],
  103. [['created_at', 'updated_at'], 'safe'],
  104. [
  105. [
  106. 'title',
  107. 'sub_title',
  108. 'summary',
  109. 'seo_title',
  110. 'seo_keywords',
  111. 'seo_description',
  112. 'author_name',
  113. 'tag',
  114. 'template'
  115. ],
  116. 'string',
  117. 'max' => 255
  118. ],
  119. [
  120. [
  121. 'flag_headline',
  122. 'flag_recommend',
  123. 'flag_slide_show',
  124. 'flag_special_recommend',
  125. 'flag_roll',
  126. 'flag_bold',
  127. 'flag_picture',
  128. 'status',
  129. 'can_comment'
  130. ],
  131. 'in',
  132. 'range' => [0, 1]
  133. ],
  134. [['visibility'], 'in', 'range' => array_keys(Constants::getArticleVisibility())],
  135. [['type'], 'default', 'value'=>self::ARTICLE, 'on'=>'article'],
  136. [['type'], 'default', 'value'=>self::SINGLE_PAGE, 'on'=>'page'],
  137. [['password'], 'string', 'max'=>20],
  138. ['cid', 'default', 'value'=>0]
  139. ];
  140. }
  141. /**
  142. * @inheritdoc
  143. */
  144. public function scenarios()
  145. {
  146. return [
  147. 'article' => [
  148. 'cid',
  149. 'type',
  150. 'title',
  151. 'sub_title',
  152. 'summary',
  153. 'thumb',
  154. 'seo_title',
  155. 'seo_keywords',
  156. 'seo_description',
  157. 'status',
  158. 'sort',
  159. 'author_id',
  160. 'author_name',
  161. 'created_at',
  162. 'updated_at',
  163. 'scan_count',
  164. 'comment_count',
  165. 'can_comment',
  166. 'visibility',
  167. 'tag',
  168. 'flag_headline',
  169. 'flag_recommend',
  170. 'flag_slide_show',
  171. 'flag_special_recommend',
  172. 'flag_roll',
  173. 'flag_bold',
  174. 'flag_picture',
  175. 'password',
  176. 'images',
  177. 'template'
  178. ],
  179. 'page' => [
  180. 'type',
  181. 'title',
  182. 'sub_title',
  183. 'summary',
  184. 'seo_title',
  185. 'seo_keywords',
  186. 'seo_description',
  187. 'status',
  188. 'can_comment',
  189. 'visibility',
  190. 'tag',
  191. 'sort',
  192. 'images',
  193. 'template'
  194. ],
  195. ];
  196. }
  197. /**
  198. * @inheritdoc
  199. */
  200. public function attributeLabels()
  201. {
  202. return [
  203. 'id' => Yii::t('app', 'ID'),
  204. 'cid' => Yii::t('app', 'Category Id'),
  205. 'type' => Yii::t('app', 'Type'),
  206. 'title' => Yii::t('app', 'Title'),
  207. 'sub_title' => Yii::t('app', 'Sub Title'),
  208. 'summary' => Yii::t('app', 'Summary'),
  209. 'thumb' => Yii::t('app', 'Thumb'),
  210. 'seo_title' => Yii::t('app', 'Seo Title'),
  211. 'seo_keywords' => Yii::t('app', 'Seo Keyword'),
  212. 'seo_description' => Yii::t('app', 'Seo Description'),
  213. 'status' => Yii::t('app', 'Status'),
  214. 'can_comment' => Yii::t('app', 'Can Comment'),
  215. 'visibility' => Yii::t('app', 'Visibility'),
  216. 'sort' => Yii::t('app', 'Sort'),
  217. 'tag' => Yii::t('app', 'Tag'),
  218. 'author_id' => Yii::t('app', 'Author Id'),
  219. 'author_name' => Yii::t('app', 'Author'),
  220. 'created_at' => Yii::t('app', 'Created At'),
  221. 'updated_at' => Yii::t('app', 'Updated At'),
  222. 'flag_headline' => Yii::t('app', 'Is Headline'),
  223. 'flag_recommend' => Yii::t('app', 'Is Recommend'),
  224. 'flag_special_recommend' => Yii::t('app', 'Is Special Recommend'),
  225. 'flag_slide_show' => Yii::t('app', 'Is Slide Show'),
  226. 'flag_roll' => Yii::t('app', 'Is Roll'),
  227. 'flag_bold' => Yii::t('app', 'Is Bold'),
  228. 'flag_picture' => Yii::t('app', 'Is Picture'),
  229. 'template' => Yii::t('app', 'Article Template'),
  230. 'password' => Yii::t('app', 'Password'),
  231. 'scan_count' => Yii::t('app', 'Scan Count'),
  232. 'comment_count' => Yii::t('app', 'Comment Count'),
  233. 'category' => Yii::t('app', 'Category'),
  234. 'images' => Yii::t('app', 'Article Images'),
  235. ];
  236. }
  237. /**
  238. * @return \yii\db\ActiveQuery
  239. */
  240. public function getCategory()
  241. {
  242. return $this->hasOne(Category::className(), ['id' => 'cid']);
  243. }
  244. /**
  245. * @return \yii\db\ActiveQuery
  246. */
  247. public function getArticleContent()
  248. {
  249. return $this->hasOne(ArticleContent::className(), ['aid' => 'id']);
  250. }
  251. /**
  252. * @return \yii\db\ActiveQuery
  253. */
  254. public function getArticleLikes()
  255. {
  256. $tempModel = new ArticleMetaLike();
  257. return $this->hasMany(ArticleMetaLike::className(), ['aid' => 'id'])->where(['key'=>$tempModel->keyName]);
  258. }
  259. public function getArticleTags()
  260. {
  261. $tempModel = new ArticleMetaTag();
  262. return $this->hasMany(ArticleMetaLike::className(), ['aid' => 'id'])->where(['key'=>$tempModel->keyName]);
  263. }
  264. /**
  265. * @inheritdoc
  266. */
  267. public function afterValidate()
  268. {
  269. if($this->visibility == Constants::ARTICLE_VISIBILITY_SECRET){//加密文章需要设置密码
  270. if( empty( $this->password ) ){
  271. $this->addError('password', Yii::t('app', "Secret article must set a password"));
  272. }
  273. }
  274. parent::afterValidate();
  275. }
  276. /**
  277. * @inheritdoc
  278. */
  279. public function beforeSave($insert)
  280. {
  281. $insert = $this->getIsNewRecord();
  282. Util::handleModelSingleFileUpload($this, 'thumb', $insert, '@thumb', ['thumbSizes'=>self::$thumbSizes]);
  283. $this->seo_keywords = str_replace(',', ',', $this->seo_keywords);
  284. if ($insert) {
  285. $this->author_id = Yii::$app->getUser()->getIdentity()->getId();
  286. $this->author_name = Yii::$app->getUser()->getIdentity()->username;
  287. }
  288. $this->type = self::ARTICLE;
  289. if( $this->getScenario() === 'page' ){
  290. $this->type = self::SINGLE_PAGE;
  291. }
  292. if ($this->thumb) {
  293. /** @var TargetAbstract $cdn */
  294. $cdn = Yii::$app->get('cdn');
  295. $this->thumb = str_replace($cdn->host, '', $this->thumb);
  296. }
  297. return parent::beforeSave($insert);
  298. }
  299. /**
  300. * @inheritdoc
  301. */
  302. public function afterSave($insert, $changedAttributes)
  303. {
  304. $articleMetaTag = new ArticleMetaTag();
  305. $articleMetaTag->setArticleTags($this->id, $this->tag);
  306. $articleMetaTag = new ArticleMetaImages();
  307. $articleMetaTag->setImages($this->id, $this->images);
  308. parent::afterSave($insert, $changedAttributes);
  309. }
  310. /**
  311. * @inheritdoc
  312. */
  313. public function beforeDelete()
  314. {
  315. if( !empty( $this->thumb ) ){
  316. Util::deleteThumbnails(Yii::getAlias('@frontend/web') . $this->thumb, self::$thumbSizes, true);
  317. }
  318. Comment::deleteAll(['aid' => $this->id]);
  319. return parent::beforeDelete();
  320. }
  321. /**
  322. * @inheritdoc
  323. */
  324. public function afterFind()
  325. {
  326. if ($this->thumb) {
  327. /** @var TargetAbstract $cdn */
  328. $cdn = Yii::$app->get('cdn');
  329. $this->thumb = $cdn->getCdnUrl($this->thumb);
  330. }
  331. $articleMetaImagesModel = new ArticleMetaImages();
  332. $this->images = $articleMetaImagesModel->getImagesByArticle($this->id);
  333. parent::afterFind();
  334. }
  335. /**
  336. * @return integer
  337. */
  338. public function getArticleLikeCount()
  339. {
  340. return $this->getArticleLikes()->count('id');
  341. }
  342. public function beforeValidate()
  343. {
  344. if ($this->thumb !== "0") {//为0表示需要删除图片,Util::handleModelSingleFileUpload()会有判断删除图片
  345. $this->thumb = UploadedFile::getInstance($this, "thumb");
  346. }
  347. return parent::beforeValidate();
  348. }
  349. public function getThumbUrlBySize($width='', $height='')
  350. {
  351. if( empty($width) || empty($height) ){
  352. return $this->thumb;
  353. }
  354. if( empty($this->thumb) ){//未配图
  355. return $this->thumb = '/static/images/' . rand(1, 10) . '.jpg';
  356. }
  357. static $str = null;
  358. if( $str === null ) {
  359. $str = "";
  360. foreach (self::$thumbSizes as $temp){
  361. $str .= $temp['w'] . 'x' . $temp['h'] . '---';
  362. }
  363. }
  364. if( strpos($str, $width . 'x' . $height) !== false ){
  365. $dotPosition = strrpos($this->thumb, '.');
  366. $thumbExt = "@" . $width . 'x' . $height;
  367. if( $dotPosition === false ){
  368. return $this->thumb . $thumbExt;
  369. }else{
  370. return substr_replace($this->thumb,$thumbExt, $dotPosition, 0);
  371. }
  372. }
  373. return Yii::$app->getRequest()->getBaseUrl() . '/timthumb.php?' . http_build_query(['src'=>$this->thumb, 'h'=>$height, 'w'=>$width, 'zc'=>0]);
  374. }
  375. }