PageRenderTime 44ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/model/topic.php

https://github.com/NeoRazorX/feedstorm
PHP | 472 lines | 387 code | 56 blank | 29 comment | 60 complexity | b037afff7aad73324e82ed3eeac77875 MD5 | raw file
Possible License(s): LGPL-3.0
  1. <?php
  2. /*
  3. * This file is part of FeedStorm
  4. * Copyright (C) 2014 Carlos Garcia Gomez neorazorx@gmail.com
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as
  8. * published by the Free Software Foundation, either version 3 of the
  9. * License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. require_once 'base/fs_model.php';
  20. require_once 'model/story.php';
  21. require_once 'model/topic_story.php';
  22. class topic extends fs_model
  23. {
  24. public $parent;
  25. public $name;
  26. public $title;
  27. public $description;
  28. public $keywords;
  29. public $importance;
  30. public $num_stories;
  31. public $num_children;
  32. public $icon;
  33. public function __construct($t=FALSE)
  34. {
  35. parent::__construct('topics');
  36. $this->parent = NULL;
  37. $this->name = NULL;
  38. $this->title = 'Desconocido';
  39. $this->description = 'Sin descripción';
  40. $this->keywords = '';
  41. $this->importance = 0;
  42. $this->num_stories = 0;
  43. $this->num_children = 0;
  44. $this->icon = '';
  45. if($t)
  46. {
  47. $this->id = $t['_id'];
  48. $this->parent = $t['parent'];
  49. $this->name = $t['name'];
  50. $this->title = $t['title'];
  51. $this->description = $t['description'];
  52. $this->keywords = $t['keywords'];
  53. $this->importance = $t['importance'];
  54. $this->num_stories = $t['num_stories'];
  55. $this->num_children = $t['num_children'];
  56. if( isset($t['icon']) )
  57. $this->icon = $t['icon'];
  58. }
  59. }
  60. public function install_indexes()
  61. {
  62. }
  63. public function description($width=250)
  64. {
  65. return $this->true_text_break($this->description, $width);
  66. }
  67. public function keywords()
  68. {
  69. $keys = array();
  70. foreach( explode(',', $this->keywords) as $key )
  71. $keys[] = trim($key);
  72. return $keys;
  73. }
  74. public function url()
  75. {
  76. if( is_null($this->id) )
  77. return FS_PATH.'topic_list';
  78. else if($this->name != '')
  79. return FS_PATH.'show_topic/'.$this->name;
  80. else
  81. return FS_PATH.'index.php?page=show_topic&id='.$this->id;
  82. }
  83. public function stories($gruop='W-Y')
  84. {
  85. $topic_story = new topic_story();
  86. $story = new story();
  87. $stories = array();
  88. $best_tss = array();
  89. $current_ts = FALSE;
  90. foreach($topic_story->best4topic($this->get_id()) as $ts)
  91. {
  92. if(!$current_ts)
  93. {
  94. $current_ts = $ts;
  95. }
  96. else if( Date($gruop, $ts->date) != Date($gruop, $current_ts->date) )
  97. {
  98. $best_tss[] = $current_ts;
  99. $current_ts = $ts;
  100. }
  101. else if($ts->popularity > $current_ts->popularity)
  102. {
  103. $current_ts = $ts;
  104. }
  105. }
  106. if($current_ts)
  107. $best_tss[] = $current_ts;
  108. foreach($best_tss as $ts)
  109. {
  110. if( $ts->popularity > 0 )
  111. {
  112. $st0 = $story->get($ts->story_id);
  113. if($st0)
  114. $stories[] = $st0;
  115. else
  116. $ts->delete();
  117. }
  118. }
  119. return $stories;
  120. }
  121. public function new_name()
  122. {
  123. $this->name = strtolower( $this->true_text_break($this->title, 85) );
  124. $changes = array('/à/' => 'a', '/á/' => 'a', '/â/' => 'a', '/ã/' => 'a', '/ä/' => 'a',
  125. '/å/' => 'a', '/æ/' => 'ae', '/ç/' => 'c', '/è/' => 'e', '/é/' => 'e', '/ê/' => 'e',
  126. '/ë/' => 'e', '/ì/' => 'i', '/í/' => 'i', '/î/' => 'i', '/ï/' => 'i', '/ð/' => 'd',
  127. '/ñ/' => 'n', '/ò/' => 'o', '/ó/' => 'o', '/ô/' => 'o', '/õ/' => 'o', '/ö/' => 'o',
  128. '/ő/' => 'o', '/ø/' => 'o', '/ù/' => 'u', '/ú/' => 'u', '/û/' => 'u', '/ü/' => 'u',
  129. '/ű/' => 'u', '/ý/' => 'y', '/þ/' => 'th', '/ÿ/' => 'y', '/ñ/' => 'ny',
  130. '/&quot;/' => '-'
  131. );
  132. $this->name = preg_replace(array_keys($changes), $changes, $this->name);
  133. $this->name = preg_replace('/[^a-z0-9]/i', '-', $this->name);
  134. $this->name = preg_replace('/-+/', '-', $this->name);
  135. if( substr($this->name, 0, 1) == '-' )
  136. $this->name = substr($this->name, 1);
  137. if( substr($this->name, -1) == '-' )
  138. $this->name = substr($this->name, 0, -1);
  139. $this->name .= '-'.mt_rand(0, 999).'.html';
  140. return $this->name;
  141. }
  142. public function get($id)
  143. {
  144. $this->add2history(__CLASS__.'::'.__FUNCTION__);
  145. try
  146. {
  147. if( substr($id, -5) == '.html' )
  148. {
  149. $data = $this->collection->findone( array('name' => $id) );
  150. if($data)
  151. return new topic($data);
  152. else
  153. {
  154. /// buscamos la raiz
  155. $parts = explode('-', substr($id, 0, -5));
  156. $new_name = '';
  157. for($i = 0; $i < count($parts)-1; $i++)
  158. $new_name .= $parts[$i].'-';
  159. $data = $this->collection->findone( array('name' => new MongoRegex('/'.$new_name.'/')) );
  160. if($data)
  161. return new topic($data);
  162. else
  163. return FALSE;
  164. }
  165. }
  166. else
  167. {
  168. $data = $this->collection->findone( array('_id' => new MongoId($id)) );
  169. if($data)
  170. return new topic($data);
  171. else
  172. return FALSE;
  173. }
  174. }
  175. catch(Exception $e)
  176. {
  177. $this->new_error($e);
  178. return FALSE;
  179. }
  180. }
  181. public function get_by_title($title)
  182. {
  183. $this->add2history(__CLASS__.'::'.__FUNCTION__);
  184. try
  185. {
  186. $data = $this->collection->findone( array('title' => $this->true_text_break($title)) );
  187. if($data)
  188. return new topic($data);
  189. else
  190. return FALSE;
  191. }
  192. catch(Exception $e)
  193. {
  194. $this->new_error($e);
  195. return FALSE;
  196. }
  197. }
  198. public function exists()
  199. {
  200. if( isset($this->id) )
  201. {
  202. $this->add2history(__CLASS__.'::'.__FUNCTION__);
  203. $data = $this->collection->findone( array('_id' => $this->id) );
  204. if($data)
  205. return TRUE;
  206. else
  207. return FALSE;
  208. }
  209. else
  210. return FALSE;
  211. }
  212. public function save()
  213. {
  214. $this->parent = $this->var2str($this->parent);
  215. $this->title = $this->true_text_break($this->title);
  216. $this->description = $this->true_text_break($this->description, 999);
  217. $data = array(
  218. 'parent' => $this->parent,
  219. 'name' => $this->name,
  220. 'title' => $this->title,
  221. 'description' => $this->description,
  222. 'keywords' => $this->keywords,
  223. 'importance' => $this->importance,
  224. 'num_stories' => $this->num_stories,
  225. 'num_children' => $this->num_children,
  226. 'icon' => $this->icon
  227. );
  228. if( $this->exists() )
  229. {
  230. $this->add2history(__CLASS__.'::'.__FUNCTION__.'@update');
  231. $filter = array('_id' => $this->id);
  232. $this->collection->update($filter, $data);
  233. }
  234. else
  235. {
  236. $this->add2history(__CLASS__.'::'.__FUNCTION__.'@insert');
  237. $data['name'] = $this->new_name();
  238. $this->collection->insert($data);
  239. $this->id = $data['_id'];
  240. }
  241. }
  242. public function delete()
  243. {
  244. $this->add2history(__CLASS__.'::'.__FUNCTION__);
  245. $this->collection->remove( array('_id' => $this->id) );
  246. $ts = new topic_story();
  247. $ts->delete4topic($this->id);
  248. }
  249. public function all()
  250. {
  251. $this->add2history(__CLASS__.'::'.__FUNCTION__);
  252. $tlist = array();
  253. foreach($this->collection->find()->sort(array('importance'=>-1)) as $t)
  254. $tlist[] = new topic($t);
  255. return $tlist;
  256. }
  257. public function all_from($parent=NULL)
  258. {
  259. $this->add2history(__CLASS__.'::'.__FUNCTION__);
  260. $tlist = array();
  261. foreach($this->collection->find(array('parent'=>$this->var2str($parent)))->sort(array('name'=>1)) as $t)
  262. $tlist[] = new topic($t);
  263. return $tlist;
  264. }
  265. public function count_from($parent=NULL)
  266. {
  267. if( is_null($parent) )
  268. {
  269. return 0;
  270. }
  271. else
  272. {
  273. $this->add2history(__CLASS__.'::'.__FUNCTION__);
  274. return $this->collection->find( array('parent' => $this->var2str($parent)) )->count();
  275. }
  276. }
  277. public function search($query)
  278. {
  279. $this->add2history(__CLASS__.'::'.__FUNCTION__);
  280. $stlist = array();
  281. $search = array( 'title' => new MongoRegex('/'.$query.'/iu') );
  282. foreach($this->collection->find($search)->sort(array('title'=>1))->limit(FS_MAX_STORIES) as $s)
  283. {
  284. /// parece ser que las expresiones regulares no funciona muy bien en mongodb
  285. if( preg_match('/\b'.$query.'\b/iu', $s['title']) )
  286. $stlist[] = new topic($s);
  287. }
  288. return $stlist;
  289. }
  290. public function cron_job()
  291. {
  292. $story = new story();
  293. $topic_story = new topic_story();
  294. $max_importance = 0;
  295. echo "\nProcesamos los temas...";
  296. foreach($this->all() as $topic)
  297. {
  298. echo '.';
  299. $story_ids = array();
  300. $stories = array();
  301. /// usamos las keywords para buscar artículos relacionados
  302. foreach($topic->keywords() as $key)
  303. {
  304. if( mt_rand(0, 2) != 2 )
  305. $relateds = $story->search($key, TRUE);
  306. else
  307. $relateds = $story->search($key, FALSE);
  308. for($i = 0; $i < count($relateds); $i++)
  309. {
  310. if( !in_array($topic->get_id(), $relateds[$i]->topics) )
  311. {
  312. if($relateds[$i]->keywords == '')
  313. $relateds[$i]->keywords = $key;
  314. else if( strpos($relateds[$i]->keywords, $key) === FALSE )
  315. $relateds[$i]->keywords .= ', '.$key;
  316. $relateds[$i]->topics[] = $topic->get_id();
  317. $relateds[$i]->save();
  318. $ts0 = new topic_story();
  319. $ts0->topic_id = $topic->get_id();
  320. $ts0->story_id = $relateds[$i]->get_id();
  321. $ts0->date = $relateds[$i]->date;
  322. $ts0->popularity = $relateds[$i]->max_popularity();
  323. $ts0->save();
  324. }
  325. else
  326. {
  327. /// ¿Actualizamos la popularidad?
  328. $ts0 = $topic_story->get2($topic->get_id(), $relateds[$i]->get_id());
  329. if($ts0)
  330. {
  331. if( $ts0->popularity != $relateds[$i]->max_popularity() )
  332. {
  333. $ts0->popularity = $relateds[$i]->max_popularity();
  334. $ts0->save();
  335. }
  336. }
  337. else
  338. {
  339. $relateds[$i]->topics = array();
  340. $relateds[$i]->keywords = '';
  341. $relateds[$i]->save();
  342. }
  343. }
  344. if( !in_array($relateds[$i]->get_id(), $story_ids) )
  345. {
  346. $story_ids[] = $relateds[$i]->get_id();
  347. $stories[] = $relateds[$i];
  348. }
  349. }
  350. }
  351. if( count($stories) > 0 )
  352. {
  353. /// ordenamos los artículos por popularidad
  354. usort($stories, function($a, $b) {
  355. if($a->popularity == $b->popularity)
  356. return 0;
  357. else if($a->popularity > $b->popularity)
  358. return -1;
  359. else
  360. return 1;
  361. } );
  362. /// interrelacionamos los artículos
  363. for($i = 0; $i < count($stories); $i++)
  364. {
  365. if( !isset($stories[$i]->related_id) )
  366. {
  367. for($j = 0; $j < count($stories); $j++)
  368. {
  369. if( $stories[$j]->date < $stories[$i]->date AND $stories[$j]->native_lang AND !$stories[$j]->penalize AND !$stories[$j]->parody )
  370. {
  371. $stories[$i]->related_id = $stories[$j]->get_id();
  372. $stories[$i]->save();
  373. break;
  374. }
  375. }
  376. }
  377. }
  378. }
  379. /*
  380. * Ahora vamos a comprobar la importancia del tema.
  381. * Los "hijos de un tema" o "subtemas" tienen más importancia que su padre,
  382. * así podemos destacar estos subtemas. Pero todos los temas o subtemas sin hijos
  383. * tienen la máxima importancia.
  384. */
  385. if($topic->importance > $max_importance)
  386. $max_importance = $topic->importance;
  387. $topic->num_children = $topic->count_from( $topic->get_id() );
  388. if($topic->num_children == 0)
  389. {
  390. $topic->importance = $max_importance;
  391. }
  392. else if( is_null($topic->parent) )
  393. {
  394. $topic->importance = 0;
  395. }
  396. else
  397. {
  398. $parent = $this->get($topic->parent);
  399. if($parent)
  400. {
  401. $topic->importance = $parent->importance + 1;
  402. }
  403. else
  404. {
  405. $topic->parent = NULL;
  406. if($topic->num_children == 0)
  407. $topic->importance = $max_importance;
  408. else
  409. $topic->importance = 0;
  410. }
  411. }
  412. $topic->num_stories = $topic_story->count4topic( $topic->get_id() );
  413. $topic->save();
  414. }
  415. }
  416. }