NewsController.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  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. throw new NotFoundHttpException("Сюжен не найден");
  142. return '';
  143. //$news_query = \app\models\front\News::find(); // optimized
  144. }
  145. $cnt = \Yii::$app->cache->getOrSet('story_cnt_'.$topic->id, function () use ($news_query){
  146. return $news_query->count();
  147. },7200);
  148. $pages = new \yii\data\Pagination(['totalCount' => $cnt, 'pageSize'=>20]);
  149. $dateRange = \Yii::$app->request->get('daterange',NULL);
  150. if(!is_null($dateRange) && $dateRange!=""){
  151. $dateRange = explode(" — ",$dateRange);
  152. $dateRange[0] = date("Y-m-d 00:00:01",strtotime($dateRange[0]));
  153. $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]));
  154. $news_query->andWhere(["BETWEEN","dt_pub",$dateRange[0],$dateRange[1]]);
  155. }
  156. return $this->render("index",["topic"=>$topic,"daterange"=>$dateRange,"news_query"=>$news_query,"pages"=>$pages]);
  157. }
  158. /**
  159. * @param int $id
  160. */
  161. public function actionView(int $id) {
  162. $model = $this->findModel($id);
  163. if(!$model instanceof News) throw new NotFoundHttpException("Новость не найдена");
  164. if( $link = trim( $model->link ) ){
  165. $link = str_replace( 'http://www.amic.ru', '', $link);
  166. $this->redirect($link, 301);
  167. return '';
  168. }
  169. $queryString = \Yii::$app->request->queryString?'?'.\Yii::$app->request->queryString:'';
  170. if( \Yii::$app->request->url != $model->getUrl().$queryString ){
  171. $this->redirect($model->getUrl(true).$queryString, 301);
  172. return '';
  173. }
  174. if(\Yii::$app->request->isPost){
  175. $capcha_result = base64_decode(\Yii::$app->request->post('capcha_salt'))/3.14;
  176. if(
  177. \Yii::$app->request->post('capcha')=="" ||
  178. \Yii::$app->request->post('capcha')!= $capcha_result
  179. ){
  180. \Yii::$app->session->setFlash('danger','Ошибка размещения комментария, пример решен неверно. Правильный ответ был: '.$capcha_result);
  181. } else {
  182. if(\Yii::$app->request->post('message')!=""){
  183. $comment = new Comments();
  184. if( $comment::$conf->isActive() ){
  185. $comment->fakename = str_replace('"',"'", (\Yii::$app->request->post('fakename')));
  186. $comment->message = strip_tags(\Yii::$app->request->post('message'),'<i><b><s><u>');
  187. $comment->news_id = $model->id;
  188. $comment->visible = ( $comment::$conf->isPreModerate() )?'N':'Y'; //если пользователь зареген поставить true
  189. $comment->ip_address = \Yii::$app->request->getRemoteIP().",".\Yii::$app->request->getUserIP();
  190. $comment->user_agent = \Yii::$app->request->userAgent;
  191. $comment->created_at = date("Y-m-d H:i:s");
  192. $comment->parent_id = \Yii::$app->request->post('parent_id');
  193. $res = $comment->save();
  194. if($res){
  195. \Yii::$app->session->setFlash('success','Комментарий успешно отправлен на модерацию');
  196. $this->redirect($model->getUrl()."#comments");
  197. \Yii::$app->end();
  198. } else {
  199. \Yii::$app->session->setFlash('danger','Ошибка размещения комментария');
  200. }
  201. }
  202. }
  203. }
  204. }
  205. return $this->render('view',['model'=>$model]);
  206. }
  207. /**
  208. * @param string $uid
  209. * @return string
  210. */
  211. public function actionUidView(string $uid):string {
  212. if( Uuid::isvalid($uid) ){
  213. $model = \app\models\News::find()->andWhere(['uid'=>$uid])->one();
  214. if(!$model instanceof \app\models\News) throw new NotFoundHttpException("Новость не найдена");
  215. if( $model->active == 'N' || strtotime($model->dt_pub) > time() ){
  216. return $this->render('view',['model'=>$model]);
  217. }else{
  218. $this->redirect($model->geturl());
  219. return '';
  220. }
  221. }else{
  222. throw new NotFoundHttpException("Новость не найдена");
  223. }
  224. }
  225. public function actionStoryslugView($storyslug):string
  226. {
  227. $model = News::find()->andWhere(['alias'=>$storyslug])->one();
  228. if(!$model instanceof News) throw new NotFoundHttpException("Новость не найдена");
  229. return $this->render('view',['model'=>$model]);
  230. }
  231. public function actionInfinityNewsfeed($post_id,$last_post_id=NULL,$amount=0){
  232. if($last_post_id=="null"){
  233. $last_post = News::find()->limit(1)->one();
  234. } else {
  235. $last_post = News::findOne(["id"=>$last_post_id]);
  236. }
  237. $feed = News::find()
  238. ->andWhere(['!=','id',$post_id])
  239. //->andFilterWhere(['<','id',$last_post_id])
  240. ->andFilterWhere(['<','dt_pub',$last_post->dt_pub])
  241. ->limit(1)
  242. ->one();
  243. if(!is_null($feed)){
  244. return $this->asJson([
  245. "id"=>$feed->id,
  246. "html"=>$this->renderPartial('/news/view/infinity_newsfeed/_item',["model"=>$feed,"index"=>$amount])
  247. ]);
  248. }
  249. return NULL;
  250. }
  251. public function actionClike(){
  252. if(\Yii::$app->request->isPost){
  253. if(\Yii::$app->request->post('id') && \Yii::$app->request->post('grd') ){
  254. $id = (int) \Yii::$app->request->post('id'); //комент
  255. $nid = (int) \Yii::$app->request->post('nid'); //новость
  256. $grd = (int) \Yii::$app->request->post('grd'); //градиент
  257. if( Comments::isUserLike($id) ) return $this->asJson(['err']);
  258. if( $id > 0 && ( $grd == 1 || $grd == -1 ) ){
  259. $comment = Comments::findOne($id);
  260. $comment->likeed += $grd;
  261. if( $comment->save() ){
  262. Comments::setUserLike($nid, $id);
  263. }
  264. }
  265. }
  266. }
  267. return $this->asJson(['ok']);
  268. }
  269. public function actionSsearch()
  270. {
  271. if (Yii::$app->request->isGet && $get = Yii::$app->request->get('query')){
  272. $model = new Story();
  273. $gets = mb_strlen( $get ) < 6?$get.'*':$get;
  274. $items = $model->search($gets, 10);
  275. $res = array();
  276. $json = '{}';
  277. $resj = json_decode($json);
  278. $resj->query = $get;
  279. if( $items && is_array( $items ) ){
  280. foreach( $items as $item ){
  281. $res[] = array( 'data'=>$item['id']*1, 'value'=>$item['title'] );
  282. }
  283. $resj->suggestions = $res;
  284. return json_encode( $resj );
  285. }
  286. }
  287. $json = '{}';
  288. $resj = json_decode($json);
  289. $resj->query = $get;
  290. $resj->suggestions = [];
  291. return json_encode( $resj );
  292. }
  293. private function findModel($id)
  294. {
  295. return News::find()->andWhere(['id'=>$id])->limit(1)->one();
  296. }
  297. }