Gentics Portal.Node PHP API
 All Classes Namespaces Functions Variables Pages
Channel.php
1 <?php
2 /**
3  * Created by JetBrains PhpStorm.
4  * User: Andrew
5  * Date: 07.06.13
6  * Time: 19:35
7  * To change this template use File | Settings | File Templates.
8  */
9 
10 /**
11  * Class for process a channel (import news from xml into database)
12  *
13  * @author Andrew Voloshin <andrew.voloshin@oberig.com>
14  *
15  * all parameters will be described in the part of current channel
16  * because 1 object of this class = 1 channel !!!
17  *
18  */
19 
20 class Channel
21 {
22  /**
23  * @var string name of the channel
24  */
25  public $name;
26  /**
27  * @var string path to fertig file of the channel
28  */
29  public $fertigPath;
30  /**
31  * @var string path to main folder of the channel
32  */
33  public $path;
34  /**
35  * @var string path to work folder of the channel
36  */
37  public $workPath;
38  /**
39  * @var string path to done folder of the channel
40  */
41  public $donePath;
42  /**
43  * @var string path to error folder of the channel
44  */
45  public $errorPath;
46  /**
47  * @var string path to public folder (where placed images and videos folders) of the channel
48  */
49  public $wwwPath;
50  /**
51  * @var string path to images files
52  */
53  public $imagesPath;
54  /**
55  * @var string path to images files
56  */
57  public $videosPath;
58  /**
59  * @var array extensions of removal files
60  */
61  private $removalExt = array('del');
62  /**
63  * @var array extensions of news files
64  */
65  private $newsExt = array('xml');
66  /**
67  * @var array extensions of images files
68  */
69  private $imagesExt = array('jpg');
70  /**
71  * @var array extensions of video files
72  */
73  private $videosExt = array('mp4');
74  /**
75  * @var string log file name
76  */
77  private $log_filename;
78  /**
79  * @var array relation between news files
80  */
81  private $relations = array();
82  /**
83  * @var boolean whether delivery folder was updated
84  */
85  private $isNew = false;
86  /**
87  * @var string channel instance
88  */
89  public static $instance;
90  /**
91  * Constructor initializes all parameters and makes necessary folders if they are not
92  */
93  public function __construct($name)
94  {
95  $time = time();
96  $this->log_filename .= "log_{$time}.txt";
97  $this->name = $name;
98  $channelAlias = "apalines.content.$name";
99 
100  $module = Yii::app()->getModule('apalines');
101  if(isset($module->channels[$name]['delivery_path'])){
102  $channelAlias = $module->channels[$name]['delivery_path'];
103  }
104 
105  $this->path = Yii::getPathOfAlias($channelAlias);
106  $this->fertigPath = $this->path.DIRECTORY_SEPARATOR.'fertig.txt';
107 
108  if (file_exists($this->fertigPath)) {
109  unlink($this->fertigPath);
110  $this->isNew = true;
111  }
112 
113  //Log router
114  if (file_exists($this->path)) {
115  Yii::app()->log->routes['file']->setLogPath($this->path);
116  Yii::app()->log->routes['file']->setLogFile($this->log_filename);
117  }
118  //Uncomment to overwrite log file
119  /*
120  if(file_exists($this->makePath($this->path,$this->log_filename))){
121  unlink($this->makePath($this->path,$this->log_filename));
122  }
123  **/
124  $this->workPath = Yii::getPathOfAlias("$channelAlias.work");
125  $this->donePath = Yii::getPathOfAlias("$channelAlias.done");
126  $this->errorPath = Yii::getPathOfAlias("$channelAlias.error");
127 
128  $wwwApaPath = Yii::getPathOfAlias("site.frontend.www.apalines");
129  $this->wwwPath = Yii::getPathOfAlias("site.frontend.www.apalines.$name");
130  $this->imagesPath = Yii::getPathOfAlias("site.frontend.www.apalines.$name.images");
131  $this->videosPath = Yii::getPathOfAlias("site.frontend.www.apalines.$name.videos");
132 
133  if (file_exists($this->path)) {
134  if (!file_exists($this->workPath)) {
135  mkdir($this->workPath);
136  }
137  if (!file_exists($this->donePath)) {
138  mkdir($this->donePath);
139  }
140  if (!file_exists($this->errorPath)) {
141  mkdir($this->errorPath);
142  }
143  if (!file_exists($wwwApaPath)) {
144  mkdir($wwwApaPath);
145  }
146  if (!file_exists($this->wwwPath)) {
147  mkdir($this->wwwPath);
148  }
149  if (!file_exists($this->imagesPath)) {
150  mkdir($this->imagesPath);
151  }
152  if (!file_exists($this->videosPath)) {
153  mkdir($this->videosPath);
154  }
155  }
156 
157  self::$instance = $this;
158  }
159  /**
160  * Function checks whether channel has updates
161  *
162  * @return boolean new or not
163  */
164  public function isNew()
165  {
166  return $this->isNew;
167  }
168  /**
169  * Function returns extension of filename
170  *
171  * @param string $filename - name of file
172  *
173  * @return string - extension
174  */
175  function getExt($filename)
176  {
177  return substr(strrchr($filename, '.'), 1);
178  }
179  /**
180  * Function processes files in work folder: distributes what handler should process each file
181  */
182  function processWork()
183  {
184  if (is_dir($this->workPath)) {
185  if ($dh = opendir($this->workPath)) {
186  while (($file = readdir($dh)) !== false) {
187  if (!is_file($this->makeWorkPath($file)) || $file == '.DS_Store') {
188  continue;
189  }
190  //Process deletions
191  if (in_array($this->getExt($file),$this->removalExt)){
192  $xml = simplexml_load_file($this->makeWorkPath($file));
193  $this->processRemoval($xml, $file);
194  }
195  }
196  //Step 2. Update meldung
197  rewinddir($dh);
198  while (($file = readdir($dh)) !== false) {
199  if (!is_file($this->makeWorkPath($file)) || $file == '.DS_Store') {
200  continue;
201  }
202  //Process news, images, videos
203  else if (in_array($this->getExt($file),$this->newsExt)) {
204  $xml = simplexml_load_file($this->makeWorkPath($file));
205  $this->processNews($xml, $file, array('DOK_MELDUNG'));
206  }
207  }
208  //Step 3. Update build
209  rewinddir($dh);
210  while (($file = readdir($dh)) !== false) {
211  if (!is_file($this->makeWorkPath($file)) || $file == '.DS_Store') {
212  continue;
213  }
214  //Process multimedia
215  else if (in_array($this->getExt($file),$this->newsExt)) {
216  $xml = simplexml_load_file($this->makeWorkPath($file));
217  $this->processNews($xml, $file, array('DOK_BILD', 'DOK_VIDEO'));
218  }
219  //Move images
220  else if (in_array($this->getExt($file),$this->imagesExt)) {
221  rename($this->makeWorkPath($file),
222  $this->makeImagesPath($file));
223  }
224  //Move videos
225  else if (in_array($this->getExt($file),$this->videosExt)) {
226  rename($this->makeWorkPath($file),
227  $this->makeVideosPath($file));
228  }
229  }
230  closedir($dh);
231  }
232  }
233  //Make relations between imported news and multimedia
234  $this->makeRelations();
235  //Remove multimedia which have not parent news
236  $this->checkMMParents();
237  }
238  /**
239  * Function processes: news and multimedia(images/video) xml files
240  *
241  * @param object $xml SimpleXMLElement
242  * @param string $xml_filename name of xml file
243  * @param array $specific what files should be processed
244  */
245  function processNews($xml, $xml_filename = null, $specific = false)
246  {
247  $parserXML = new parserXML($xml);
248  $isSuccess = false;
249  $docType = $parserXML->getDocType();
250 
251  if ($specific && is_array($specific) && !in_array($docType, $specific)) {
252  return;
253  }
254 
255  switch($parserXML->getDocType()) {
256  case 'DOK_MELDUNG':
257  $isSuccess = $this->processMeldung($parserXML, $xml_filename);
258  break;
259  case 'DOK_BILD' || 'DOK_VIDEO':
260  $isSuccess = $this->processBild($parserXML, $xml_filename);
261  break;
262  }
263  if ($isSuccess) {
264  //Moving to done folder
265  $this->moveFileToDone($xml_filename);
266  } else {
267  //Moving to error folder
268  $this->moveFileToError($xml_filename);
269  }
270  }
271  /**
272  * Function processes news xml files
273  *
274  * @param object $parserXML object of parserXml class
275  * @param string $xml_filename name of xml file
276  *
277  * @return boolean whether import finished successfully
278  */
279  function processMeldung($parserXML, $xml_filename = null)
280  {
281  $line = ApalinesNews::model()->find('docid = :docid',array(':docid'=>$parserXML->getDocId()));
282  $isExist = isset($line);
283 
284  if (!isset($line)) {
285  $line = new ApalinesNews();
286  $line->docid = $parserXML->getDocId();
287  $line->channel = $this->name;
288  } else {
289  $line->deleteFiles();
290  }
291 
292  $line->apa_id = $parserXML->getApaId();
293  $line->title = $parserXML->getTitle();
294  $line->ndate = $parserXML->getDate();
295  $line->content = $parserXML->getText();
296  $line->place = $parserXML->getPlace();
297  $line->source = $parserXML->getSource();
298  $line->keywords = $parserXML->getKeywords();
299  $line->author = $parserXML->getAuthor();
300  $line->teaser = $parserXML->getTeaser();
301  $line->filename = $parserXML->getFilename();
302  $line->xml_filename = $xml_filename;
303 
304  $relations = $parserXML->getRelations();
305  $this->relations = CMap::mergeArray(
306  $this->relations,
307  array($line->xml_filename => $relations)
308  );
309 
310  if (isset($line->id)) {
311  $childNews = ApalinesNews::model()->findAll('related_maindoc_id=:id', array(':id'=>$line->id));
312  foreach ($childNews as $child) {
313  if (!in_array($child->xml_filename, $relations)) {
314  $child->delete();
315  }
316  }
317  if (empty($relations)) {
318  $line->background_news = 0;
319  }
320  }
321 
322  if ($is_success = $line->save()) {
323  if ($isExist) {
324  Yii::log("{$line->xml_filename} done update doc_id:{$line->docid} title:{$line->title} DOK_MELDUNG", 'info');
325  } else {
326  Yii::log("{$line->xml_filename} done insert doc_id:{$line->docid} title:{$line->title} DOK_MELDUNG", 'info');
327  }
328  } else {
329  if($isExist){
330  Yii::log("{$line->xml_filename} error update doc_id:{$line->docid} title:{$line->title} DOK_MELDUNG", 'info');
331  } else {
332  Yii::log("{$line->xml_filename} error insert doc_id:{$line->docid} title:{$line->title} DOK_MELDUNG", 'info');
333  }
334  }
335  return $is_success;
336  }
337  /**
338  * Function processes multimedia xml files
339  *
340  * @param object $parserXML object of parserXml class
341  * @param string $xml_filename name of xml file
342  *
343  * @return boolean whether import finished successfully
344  */
345  function processBild($parserXML, $xml_filename = null)
346  {
347  $line = ApalinesMM::model()->find('docid = :docid',
348  array(':docid'=>$parserXML->getDocId()));
349  $isExist = isset($line);
350 
351  if (!isset($line)) {
352  $line = new ApalinesMM();
353  $line->docid = $parserXML->getDocId();
354  $line->channel = $this->name;
355  }
356 
357  $line->apa_id = $parserXML->getApaId();
358  $line->title = $parserXML->getTitle();
359  $line->ndate = $parserXML->getDate();
360  $line->place = $parserXML->getPlace();
361  $line->source = $parserXML->getSource();
362  $line->keywords = $parserXML->getKeywords();
363  $line->author = $parserXML->getAuthor();
364  $line->filename = $parserXML->getFilename();
365  $line->xml_filename = $xml_filename;
366 
367  $line->type = ($parserXML->getDocType() == 'DOK_BILD')? 0 : 1;
368 
369  $files = $parserXML->getFiles();
370 
371  if ($is_success = $line->save()) {
372  foreach($files as $file) {
373  $model = new ApalinesFile();
374  $model->attributes = $file;
375  switch ($model->size) {
376  case 'ORIGINAL':
377  $model->size = ApalinesFile::ORIGINAL;
378  break;
379  case 'THUMBNAIL':
380  $model->size = ApalinesFile::THUMBNAIL;
381  break;
382  case 'HIRES':
383  $model->size = ApalinesFile::HIRES;
384  break;
385  }
386  $model->parent_id = $line->id;
387  $model->save();
388  }
389 
390  if ($isExist) {
391  Yii::log("{$line->xml_filename} done update doc_id:{$line->docid} title:{$line->title} BILD", 'info');
392  } else {
393  Yii::log("{$line->xml_filename} done insert doc_id:{$line->docid} title:{$line->title} BILD", 'info');
394  }
395  } else {
396  if ($isExist) {
397  Yii::log("{$line->xml_filename} error update doc_id:{$line->docid} title:{$line->title} BILD", 'info');
398  } else {
399  Yii::log("{$line->xml_filename} error insert doc_id:{$line->docid} title:{$line->title} BILD", 'info');
400  }
401  }
402  return $is_success;
403  }
404  /**
405  * Function processes removing xml files
406  *
407  * @param object $parserXML object of parserXml class
408  * @param string $xml_filename name of xml file
409  *
410  * @return boolean whether import finished successfully
411  */
412  function processRemoval($xml, $xml_filename = null)
413  {
414  $parserXML = new parserXML($xml);
415  $deleteId = $parserXML->getDeleteId();
416 
417  $line = ApalinesNews::model()->find('docid = :docid',array(':docid'=> $deleteId ));
418  if (!isset($line)) {
419  $line = ApalinesMM::model()->find('docid = :docid',array(':docid'=> $deleteId ));
420  }
421  if (isset($line)) {
422  $line->delete();
423  //Moving to done folder
424  $this->moveFileToDone($xml_filename);
425  Yii::log("{$line->xml_filename} done delete docid:{$line->docid} title:{$line->title}", 'info');
426  } else {
427  //Moving to error folder
428  $this->moveFileToError($xml_filename);
429  Yii::log("{$xml_filename} error delete", 'info');
430  }
431  }
432  /**
433  * Function removes news and child news,files
434  * those lifetime is up
435  *
436  */
437  function clearOld()
438  {
439  $module = Yii::app()->getModule('apalines');
440  $max_age_of_news = false;
441  if (isset($module->channels[$this->name]['max_age_of_news'])) {
442  $max_age_of_news = $module->channels[$this->name]['max_age_of_news'];
443  }
444  if (!$max_age_of_news && isset($module->total_max_age_of_news)) {
445  $max_age_of_news = $module->total_max_age_of_news;
446  }
447  if (!$max_age_of_news) {
448  return;
449  }
450 
451  $news = ApalinesNews::model()->findAll(array(
452  'condition' => 'channel = :channel AND deleted <> 1 AND (FROM_UNIXTIME(ndate) < (NOW() - interval :max_age_of_news hour))',
453  'params' => array(
454  ':channel' => $this->name,
455  ':max_age_of_news' => $max_age_of_news
456  )
457  ));
458 
459  foreach ($news as $line) {
460  $line->delete();
461  }
462  }
463  /**
464  * Function removes multimedia files from public folder by file names
465  *
466  * @param array $files - names of files which should be removed
467  */
468  function removeFilesByName($files)
469  {
470  foreach ($files as $file) {
471  if (file_exists($this->makeImagesPath($file))) {
472  unlink($this->makeImagesPath($file));
473  Yii::log("{$file} done delete image", 'info');
474  } else if(file_exists($this->makeVideosPath($file))) {
475  Yii::log("{$file} done delete video", 'info');
476  unlink($this->makeVideosPath($file));
477  }
478  }
479  }
480  /**
481  * Function removes multimedia records which have not parent news
482  */
483  function checkMMParents()
484  {
485  $multimedia = ApalinesMM::model()->findAll('channel = :channel AND deleted=0 AND related_maindoc_id=0', array(':channel'=> $this->name));
486  foreach ($multimedia as $mm) {
487  $mm->delete();
488  }
489  }
490  /**
491  * Function make relations between database apa records
492  */
493  function makeRelations()
494  {
495  foreach($this->relations as $parent_xml_filename => $children){
496 
497  $parent = ApalinesNews::model()->find('xml_filename = :xml_filename',array(':xml_filename'=>$parent_xml_filename));
498  if (isset($parent)) {
499  // Make background relations
500  foreach ($children as $child_xml_filename) {
501  $child = ApalinesNews::model()->find('xml_filename = :xml_filename', array(':xml_filename'=>$child_xml_filename));
502  if (!isset($child)) {
503  $child = ApalinesMM::model()->find('xml_filename = :xml_filename', array(':xml_filename'=>$child_xml_filename));
504  }
505  if (isset($child)) {
506  // Relation is news-news
507  if ($child instanceof ApalinesNews) {
508  $parent->background_news = 1;
509  }
510  $child->related_maindoc_id = $parent->id;
511  $child->save();
512  }
513  }
514  $parent->save();
515  }
516  }
517  }
518  /**
519  * Function makes path to the file which placed in recieved folder path
520  *
521  * @param string $folder path to folder where the file placed
522  * @param string $file name of the file
523  *
524  * @return string full path to the file
525  */
526  function makePath($folder,$file)
527  {
528  return $folder.DIRECTORY_SEPARATOR.$file;
529  }
530  /**
531  * Function makes path to file which placed in work folder
532  *
533  * @param string $file name of the file
534  *
535  * @return string full path to the file
536  */
537  function makeWorkPath($file)
538  {
539  return $this->makePath($this->workPath, $file);
540  }
541  /**
542  * Function makes path to file which placed in done folder
543  *
544  * @param string $file name of the file
545  *
546  * @return string full path to the file
547  */
548  function makeDonePath($file)
549  {
550  return $this->makePath($this->donePath, $file);
551  }
552  /**
553  * Function makes path to file which placed in error folder
554  *
555  * @param string $file name of the file
556  *
557  * @return string full path to the file
558  */
559  function makeErrorPath($file)
560  {
561  return $this->makePath($this->errorPath, $file);
562  }
563  /**
564  * Function makes path to file which placed in images folder
565  *
566  * @param string $file name of the file
567  *
568  * @return string full path to the file
569  */
570  function makeImagesPath($file)
571  {
572  return $this->makePath($this->imagesPath, $file);
573  }
574  /**
575  * Function makes path to file which placed in videos folder
576  *
577  * @param string $file name of the file
578  *
579  * @return string full path to the file
580  */
581  function makeVideosPath($file)
582  {
583  return $this->makePath($this->videosPath, $file);
584  }
585  /**
586  * Function moves all files from main channel folder to work folder
587  */
588  function moveToWork()
589  {
590  if (is_dir($this->path)) {
591  if ($dh = opendir($this->path)) {
592  while (($file = readdir($dh)) !== false) {
593  $path = $this->makePath($this->path,$file);
594  $path_parts = pathinfo($path);
595  if(!is_file($path)||$path_parts['extension']=='txt'){
596  continue;
597  }
598  rename($this->makePath($this->path,$file),
599  $this->makeWorkPath($file));
600  }
601  closedir($dh);
602  }
603  }
604  }
605  /**
606  * Function moves the file from work folder to done folder
607  *
608  * @param string $file name of the file
609  */
610  function moveFileToDone($file)
611  {
612  rename($this->makeWorkPath($file),
613  $this->makeDonePath($file));
614  }
615  /**
616  * Function moves the file from work folder to error folder
617  *
618  * @param string $file name of the file
619  */
620  function moveFileToError($file)
621  {
622  rename($this->makeWorkPath($file),
623  $this->makeErrorPath($file));
624  }
625  /**
626  * Function moves the file from done folder to error folder.
627  * This function is needed if multimedia was successfully imported but it has not parents,
628  * so it should be removed and marked as error
629  *
630  */
631  function moveDoneFileToError($file)
632  {
633  rename($this->makeDonePath($file),
634  $this->makeErrorPath($file));
635  }
636 }