NewsController.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. <?php
  2. namespace app\controllers;
  3. use Yii;
  4. use app\models\base\Comments;
  5. use app\models\base\NewsTopic;
  6. use app\models\base\Story;
  7. use app\models\front\News;
  8. use yii\db\Expression;
  9. use yii\helpers\ArrayHelper;
  10. use yii\helpers\Url;
  11. use yii\web\Controller;
  12. use yii\web\NotFoundHttpException;
  13. use yii\web\Response;
  14. use \app\helpers\Uuid;
  15. class NewsController extends Controller
  16. {
  17. /**
  18. * {@inheritdoc}
  19. */
  20. public function behaviors()
  21. {
  22. return [
  23. [
  24. 'class' => 'yii\filters\HttpCache',
  25. 'only' => ['index'],
  26. 'enabled' => true,
  27. 'cacheControlHeader' => 'public, max-age=120',
  28. 'lastModified' => function ($action, $params) {
  29. return time();
  30. }
  31. ],
  32. ];
  33. }
  34. public function actionIndex($topic=NULL)
  35. {
  36. $url = \Yii::$app->request->pathInfo;
  37. if( $url == 'news/' ){
  38. $queryString = \Yii::$app->request->queryString?'?'.\Yii::$app->request->queryString:'';
  39. $this->redirect('/news'.$queryString, 301);
  40. return '';
  41. }
  42. $gets = \Yii::$app->request->get();
  43. $valid_get = array_filter($gets, function($k) {
  44. $valid = ['page'=>true,'daterange'=>true,'topic'=>true];
  45. return isset( $valid[$k] );
  46. }, ARRAY_FILTER_USE_KEY);
  47. if( count($gets) != count($valid_get) ){
  48. $url = Url::toRoute(['news/index']+$valid_get);
  49. $this->redirect($url, 301);
  50. return '';
  51. }
  52. if(\Yii::$app->request->get("page",0)>500) {
  53. \Yii::$app->request->setQueryParams(["page"=>500]);
  54. }
  55. $url = $topic;
  56. $topic = NewsTopic::findOne(['url'=>$topic,'active'=>1]);
  57. if(!$topic instanceof NewsTopic){
  58. $topic = new \stdClass();
  59. $topic->id = NULL;
  60. }
  61. if( $url && !$topic->id ) throw new NotFoundHttpException("Раздел не найден");
  62. $pages = null;
  63. if( $topic->id ){
  64. // $news_query = \app\models\front\News::find()->leftJoin('news_topic_relation t', 't.news_id = id')->andWhere(['t.topic_id'=>$topic->id]);
  65. $news_query = News::find()
  66. ->from(new Expression("news FORCE INDEX (top,calendar) , news_topic_relation t USE index(news_id)"))
  67. ->andWhere(new Expression('t.news_id=id'))
  68. ->andWhere(['t.topic_id'=>$topic->id]);
  69. $dateRange = \Yii::$app->request->get('daterange',NULL);
  70. $dateRanges = $dateRange;
  71. if(!is_null($dateRange) && $dateRange!=""){
  72. $dateRange = explode(" — ",$dateRange);
  73. $dateRange[0] = date("Y-m-d 00:00:01",strtotime($dateRange[0]));
  74. $dateRange[1] = isset($dateRange[1])?date("Y-m-d 23:59:59",strtotime($dateRange[1])):date("Y-m-d 23:59:59",strtotime($dateRange[0]));
  75. $news_query->andWhere(["BETWEEN","dt_pub",$dateRange[0],$dateRange[1]]);
  76. }
  77. $cnt = \Yii::$app->cache->getOrSet('topic_cnt_'.$topic->id."_$dateRanges", function () use ($news_query){
  78. return $news_query->count();
  79. },7200);
  80. /*
  81. * Оптимизировано но не понятно как убрать автоматический offset при пагинации во внешнем селекте 4с->0.7c
  82. $sub_query = News::find()->select('news.id')->from(new Expression("news as news USE INDEX (calendar)"))
  83. ->join('inner join', 'news_topic_relation', 'news_topic_relation.news_id=news.id AND news_topic_relation.topic_id='.$topic->id)->offset($pages->offset)->limit($pages->limit);
  84. $news_query = News::find()
  85. ->from( 'news' )
  86. ->join( 'join',['nl'=>$sub_query], 'news.id=nl.id' );
  87. */
  88. }else{
  89. $news_query = \app\models\front\News::findFilter();
  90. $keyadd = \app\models\front\News::keyFilter();
  91. $dateRange = \Yii::$app->request->get('daterange',NULL);
  92. $dateRanges = crc32($dateRange);
  93. if(!is_null($dateRange) && $dateRange!=""){
  94. $dateRange = explode(" — ",$dateRange);
  95. $dateRange[0] = date("Y-m-d 00:00:01",strtotime($dateRange[0]));
  96. $dateRange[1] = isset($dateRange[1])?date("Y-m-d 23:59:59",strtotime($dateRange[1])):date("Y-m-d 23:59:59",strtotime($dateRange[0]));
  97. $news_query->andWhere(["BETWEEN","dt_pub",$dateRange[0],$dateRange[1]]);
  98. }
  99. $cnt = \Yii::$app->cache->getOrSet('topic_cnt'.$keyadd."_$dateRanges", function () use ($news_query){
  100. return $news_query->count();
  101. },7200);
  102. }
  103. $cnt = ($cnt/20 > 500)?500*20:$cnt;
  104. $pages = new \yii\data\Pagination(['totalCount' => $cnt, 'pageSize'=>20]);
  105. if($topic instanceof NewsTopic){
  106. /*
  107. Приведение к каноническому маршруту в пагинации
  108. */
  109. unset($valid_get['topic']);
  110. $pages->params = $valid_get;
  111. $pages->route = 'news/'.$topic->url;
  112. //
  113. // Нормализация к каноническому URL
  114. //
  115. $queryString = \Yii::$app->request->queryString?'?'.\Yii::$app->request->queryString:'';
  116. if( \Yii::$app->request->url != '/'.$pages->route.$queryString ){
  117. $url = Url::toRoute(['news/'.$topic->url]+$valid_get);
  118. /* echo \Yii::$app->request->url.'<br>';
  119. echo $pages->route.$queryString.' <br>';
  120. echo $url; */
  121. $this->redirect($url, 301);
  122. return '';
  123. }
  124. }
  125. //$pages->urlManager = Url::toRoute(['news/index']+$valid_get);
  126. // $headers = Yii::$app->response->headers;
  127. // $headers->set('Expires', gmdate('D, d M Y H:i:s \G\M\T', time() + (60 * 2)));
  128. return $this->render("index",["topic"=>$topic,"daterange"=>$dateRange,"news_query"=>$news_query,"pages"=>$pages,"keycahe"=>isset($keyadd)?$keyadd:'']);
  129. }
  130. public function actionStory($topic=NULL)
  131. {
  132. $topic = Story::findOne(['url'=>$topic]);
  133. if(!$topic instanceof Story){
  134. $topic = new \stdClass();
  135. $topic->id = NULL;
  136. }
  137. if( $topic->id ){
  138. $news_query = \app\models\front\News::find()->leftJoin('story_relation t', 't.news_id = id')->andWhere(['t.topic_id'=>$topic->id]); //joinWith('topics t')->andFilterWhere(['t.id'=>$topic->id]);
  139. // print_r($news_query->createCommand()->rawSQL);exit;
  140. }else{
  141. $news_query = \app\models\front\News::find(); // optimized
  142. }
  143. $cnt = \Yii::$app->cache->getOrSet('story_cnt_'.$topic->id, function () use ($news_query){
  144. return $news_query->count();
  145. },7200);
  146. $pages = new \yii\data\Pagination(['totalCount' => $cnt, 'pageSize'=>20]);
  147. $dateRange = \Yii::$app->request->get('daterange',NULL);
  148. if(!is_null($dateRange) && $dateRange!=""){
  149. $dateRange = explode(" — ",$dateRange);
  150. $dateRange[0] = date("Y-m-d 00:00:01",strtotime($dateRange[0]));
  151. $dateRange[1] = isset($dateRange[1])?date("Y-m-d 23:59:59",strtotime($dateRange[1])):date("Y-m-d 23:59:59",strtotime($dateRange[0]));
  152. $news_query->andWhere(["BETWEEN","dt_pub",$dateRange[0],$dateRange[1]]);
  153. }
  154. return $this->render("index",["topic"=>$topic,"daterange"=>$dateRange,"news_query"=>$news_query,"pages"=>$pages]);
  155. }
  156. /**
  157. * @param int $id
  158. */
  159. public function actionView(int $id) {
  160. $model = $this->findModel($id);
  161. if(!$model instanceof News) throw new NotFoundHttpException("Новость не найдена");
  162. if( $link = trim( $model->link ) ){
  163. $link = str_replace( 'http://www.amic.ru', '', $link);
  164. $this->redirect($link, 301);
  165. return '';
  166. }
  167. $queryString = \Yii::$app->request->queryString?'?'.\Yii::$app->request->queryString:'';
  168. if( \Yii::$app->request->url != $model->getUrl().$queryString ){
  169. $this->redirect($model->getUrl(true).$queryString, 301);
  170. return '';
  171. }
  172. if(\Yii::$app->request->isPost){
  173. $capcha_result = base64_decode(\Yii::$app->request->post('capcha_salt'))/3.14;
  174. if(
  175. \Yii::$app->request->post('capcha')=="" ||
  176. \Yii::$app->request->post('capcha')!= $capcha_result
  177. ){
  178. \Yii::$app->session->setFlash('danger','Ошибка размещения комментария, пример решен неверно. Правильный ответ был: '.$capcha_result);
  179. } else {
  180. if(\Yii::$app->request->post('message')!=""){
  181. $comment = new Comments();
  182. if( $comment::$conf->isActive() ){
  183. $comment->fakename = str_replace('"',"'", (\Yii::$app->request->post('fakename')));
  184. $comment->message = strip_tags(\Yii::$app->request->post('message'),'<i><b><s><u>');
  185. $comment->news_id = $model->id;
  186. $comment->visible = ( $comment::$conf->isPreModerate() )?'N':'Y'; //если пользователь зареген поставить true
  187. $comment->ip_address = \Yii::$app->request->getRemoteIP().",".\Yii::$app->request->userIP;
  188. $comment->user_agent = \Yii::$app->request->userAgent;
  189. $comment->created_at = date("Y-m-d H:i:s");
  190. $comment->parent_id = \Yii::$app->request->post('parent_id');
  191. $res = $comment->save();
  192. if($res){
  193. \Yii::$app->session->setFlash('success','Комментарий успешно отправлен на модерацию');
  194. $this->redirect($model->getUrl()."#comments");
  195. \Yii::$app->end();
  196. } else {
  197. \Yii::$app->session->setFlash('danger','Ошибка размещения комментария');
  198. }
  199. }
  200. }
  201. }
  202. }
  203. return $this->render('view',['model'=>$model]);
  204. }
  205. /**
  206. * @param string $uid
  207. * @return string
  208. */
  209. public function actionUidView(string $uid):string {
  210. if( Uuid::isvalid($uid) ){
  211. $model = \app\models\News::find()->andWhere(['uid'=>$uid])->one();
  212. if(!$model instanceof \app\models\News) throw new NotFoundHttpException("Новость не найдена");
  213. if( $model->active == 'N' || strtotime($model->dt_pub) > time() ){
  214. return $this->render('view',['model'=>$model]);
  215. }else{
  216. $this->redirect($model->geturl());
  217. return '';
  218. }
  219. }else{
  220. throw new NotFoundHttpException("Новость не найдена");
  221. }
  222. }
  223. public function actionStoryslugView($storyslug):string
  224. {
  225. $model = News::find()->andWhere(['alias'=>$storyslug])->one();
  226. if(!$model instanceof News) throw new NotFoundHttpException("Новость не найдена");
  227. return $this->render('view',['model'=>$model]);
  228. }
  229. public function actionInfinityNewsfeed($post_id,$last_post_id=NULL,$amount=0){
  230. if($last_post_id=="null"){
  231. $last_post = News::find()->limit(1)->one();
  232. } else {
  233. $last_post = News::findOne(["id"=>$last_post_id]);
  234. }
  235. $feed = News::find()
  236. ->andWhere(['!=','id',$post_id])
  237. //->andFilterWhere(['<','id',$last_post_id])
  238. ->andFilterWhere(['<','dt_pub',$last_post->dt_pub])
  239. ->limit(1)
  240. ->one();
  241. if(!is_null($feed)){
  242. return $this->asJson([
  243. "id"=>$feed->id,
  244. "html"=>$this->renderPartial('/news/view/infinity_newsfeed/_item',["model"=>$feed,"index"=>$amount])
  245. ]);
  246. }
  247. return NULL;
  248. }
  249. public function actionClike(){
  250. if(\Yii::$app->request->isPost){
  251. if(\Yii::$app->request->post('id') && \Yii::$app->request->post('grd') ){
  252. $id = (int) \Yii::$app->request->post('id'); //комент
  253. $nid = (int) \Yii::$app->request->post('nid'); //новость
  254. $grd = (int) \Yii::$app->request->post('grd'); //градиент
  255. if( Comments::isUserLike($id) ) return $this->asJson(['err']);
  256. if( $id > 0 && ( $grd == 1 || $grd == -1 ) ){
  257. $comment = Comments::findOne($id);
  258. $comment->likeed += $grd;
  259. if( $comment->save() ){
  260. Comments::setUserLike($nid, $id);
  261. }
  262. }
  263. }
  264. }
  265. return $this->asJson(['ok']);
  266. }
  267. public function actionSsearch()
  268. {
  269. if (Yii::$app->request->isGet && $get = Yii::$app->request->get('query')){
  270. $model = new Story();
  271. $gets = mb_strlen( $get ) < 6?$get.'*':$get;
  272. $items = $model->search($gets, 10);
  273. $res = array();
  274. $json = '{}';
  275. $resj = json_decode($json);
  276. $resj->query = $get;
  277. if( $items && is_array( $items ) ){
  278. foreach( $items as $item ){
  279. $res[] = array( 'data'=>$item['id']*1, 'value'=>$item['title'] );
  280. }
  281. $resj->suggestions = $res;
  282. return json_encode( $resj );
  283. }
  284. }
  285. $json = '{}';
  286. $resj = json_decode($json);
  287. $resj->query = $get;
  288. $resj->suggestions = [];
  289. return json_encode( $resj );
  290. }
  291. private function findModel($id)
  292. {
  293. return News::find()->andWhere(['id'=>$id])->limit(1)->one();
  294. }
  295. }