Dotclear

source: inc/core/class.dc.blog.php @ 1561:9ab4292a9cb0

Revision 1561:9ab4292a9cb0, 62.4 KB checked in by Denis Jean-Chirstian <contact@…>, 12 years ago (diff)

Refix (or not) comments counts on trigger comments, addresses #1401

Line 
1<?php
2# -- BEGIN LICENSE BLOCK ---------------------------------------
3#
4# This file is part of Dotclear 2.
5#
6# Copyright (c) 2003-2013 Olivier Meunier & Association Dotclear
7# Licensed under the GPL version 2.0 license.
8# See LICENSE file or
9# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
10#
11# -- END LICENSE BLOCK -----------------------------------------
12if (!defined('DC_RC_PATH')) { return; }
13
14/**
15@ingroup DC_CORE
16@nosubgrouping
17@brief Dotclear blog class.
18
19Dotclear blog class instance is provided by dcCore $blog property.
20*/
21class dcBlog
22{
23     /** @var dcCore dcCore instance */
24     protected $core;
25     /** @var connection Database connection object */
26     public $con;
27     /** @var string Database table prefix */
28     public $prefix;
29     
30     /** @var string Blog ID */
31     public $id;
32     /** @var string Blog unique ID */
33     public $uid;
34     /** @var string Blog name */
35     public $name;
36     /** @var string Blog description */
37     public $desc;
38     /** @var string Blog URL */
39     public $url;
40     /** @var string Blog host */
41     public $host;
42     /** @var string Blog creation date */
43     public $creadt;
44     /** @var string Blog last update date */
45     public $upddt;
46     /** @var string Blog status */
47     public $status;
48     
49     /** @var dcSettings dcSettings object */
50     public $settings;
51     /** @var string Blog theme path */
52     public $themes_path;
53     /** @var string Blog public path */
54     public $public_path;
55     
56     private $post_status = array();
57     private $comment_status = array();
58     
59     private $categories;
60     
61     /** @var boolean Disallow entries password protection */
62     public $without_password = true;
63     
64     /**
65     Inits dcBlog object
66     
67     @param    core      <b>dcCore</b>       Dotclear core reference
68     @param    id        <b>string</b>       Blog ID
69     */
70     public function __construct($core, $id)
71     {
72          $this->con =& $core->con;
73          $this->prefix = $core->prefix;
74          $this->core =& $core;
75         
76          if (($b = $this->core->getBlog($id)) !== false)
77          {
78               $this->id = $id;
79               $this->uid = $b->blog_uid;
80               $this->name = $b->blog_name;
81               $this->desc = $b->blog_desc;
82               $this->url = $b->blog_url;
83               $this->host = preg_replace('|^([a-z]{3,}://)(.*?)/.*$|','$1$2',$this->url);
84               $this->creadt = strtotime($b->blog_creadt);
85               $this->upddt = strtotime($b->blog_upddt);
86               $this->status = $b->blog_status;
87               
88               $this->settings = new dcSettings($this->core,$this->id);
89               
90               $this->themes_path = path::fullFromRoot($this->settings->system->themes_path,DC_ROOT);
91               $this->public_path = path::fullFromRoot($this->settings->system->public_path,DC_ROOT);
92               
93               $this->post_status['-2'] = __('pending');
94               $this->post_status['-1'] = __('scheduled');
95               $this->post_status['0'] = __('unpublished');
96               $this->post_status['1'] = __('published');
97               
98               $this->comment_status['-2'] = __('junk');
99               $this->comment_status['-1'] = __('pending');
100               $this->comment_status['0'] = __('unpublished');
101               $this->comment_status['1'] = __('published');
102               
103               # --BEHAVIOR-- coreBlogConstruct
104               $this->core->callBehavior('coreBlogConstruct',$this);
105          }
106     }
107     
108     /// @name Common public methods
109     //@{
110     /**
111     Returns blog URL ending with a question mark.
112     */
113     public function getQmarkURL()
114     {
115          if (substr($this->url,-1) != '?') {
116               return $this->url.'?';
117          }
118         
119          return $this->url;
120     }
121     
122     /**
123     Returns an entry status name given to a code. Status are translated, never
124     use it for tests. If status code does not exist, returns <i>unpublished</i>.
125     
126     @param    s    <b>integer</b> Status code
127     @return   <b>string</b> Blog status name
128     */
129     public function getPostStatus($s)
130     {
131          if (isset($this->post_status[$s])) {
132               return $this->post_status[$s];
133          }
134          return $this->post_status['0'];
135     }
136     
137     /**
138     Returns an array of available entry status codes and names.
139     
140     @return   <b>array</b> Simple array with codes in keys and names in value
141     */
142     public function getAllPostStatus()
143     {
144          return $this->post_status;
145     }
146     
147     /**
148     Returns an array of available comment status codes and names.
149     
150     @return   <b>array</b> Simple array with codes in keys and names in value
151     */
152     public function getAllCommentStatus()
153     {
154          return $this->comment_status;
155     }
156     
157     /**
158     Disallows entries password protection. You need to set it to
159     <var>false</var> while serving a public blog.
160     
161     @param    v         <b>boolean</b>
162     */
163     public function withoutPassword($v)
164     {
165          $this->without_password = (boolean) $v;
166     }
167     //@}
168     
169     /// @name Triggers methods
170     //@{
171     /**
172     Updates blog last update date. Should be called every time you change
173     an element related to the blog.
174     */
175     public function triggerBlog()
176     {
177          $cur = $this->con->openCursor($this->prefix.'blog');
178         
179          $cur->blog_upddt = date('Y-m-d H:i:s');
180         
181          $cur->update("WHERE blog_id = '".$this->con->escape($this->id)."' ");
182         
183          # --BEHAVIOR-- coreBlogAfterTriggerBlog
184          $this->core->callBehavior('coreBlogAfterTriggerBlog',$cur);
185     }
186     
187     /**
188     Updates comment and trackback counters in post table. Should be called
189     every time a comment or trackback is added, removed or changed its status.
190     
191     @param    id        <b>integer</b>      Comment ID
192     @param    del       <b>boolean</b>      If comment is delete, set this to true
193     */
194     public function triggerComment($id,$del=false)
195     {
196          $this->triggerComments($id,$del);
197     }
198     
199     /**
200     Updates comments and trackbacks counters in post table. Should be called
201     every time comments or trackbacks are added, removed or changed there status.
202     
203     @param    ids       <b>mixed</b>        Comment(s) ID(s)
204     @param    del       <b>boolean</b>      If comment is delete, set this to true
205     @param    affected_posts      <b>mixed</b>        Posts(s) ID(s)
206     */
207     public function triggerComments($ids, $del=false, $affected_posts=null)
208     {
209          $comments_ids = dcUtils::cleanIds($ids);
210          $affected_posts_ids = dcUtils::cleanIds($affected_posts);
211          $affected_is_trackback = 
212          $counted_posts_ids = 
213          $counted_is_trackback = 
214          $counted_nb_comments = array();
215         
216          # a) Retrieve posts affected by comments edition
217          if (empty($affected_posts_ids)) {
218               $strReq = 
219                    'SELECT post_id, comment_trackback '.
220                    'FROM '.$this->prefix.'comment '.
221                    'WHERE comment_id'.$this->con->in($comments_ids).
222                    'GROUP BY post_id,comment_trackback';
223               
224               $rs = $this->con->select($strReq);
225               
226               while ($rs->fetch()) {
227                    $affected_posts_ids[] = (integer) $rs->post_id;
228                    $affected_is_trackback[] = (boolean) $rs->comment_trackback;
229               }
230          }
231         
232          # b) Count comments of each posts previously retrieved
233          # Note that this does not return posts without comment
234          $strReq = 
235               'SELECT post_id, COUNT(post_id) AS nb_comment,comment_trackback '.
236               'FROM '.$this->prefix.'comment '.
237               'WHERE comment_status = 1 '.
238               (count($affected_posts_ids) > 0 ? 'AND post_id'.$this->con->in($affected_posts_ids) : ' ');
239         
240          if ($del) {
241               $strReq .= 
242                    'AND comment_id NOT'.$this->con->in($comments_ids);
243          }
244         
245          $strReq .= 
246               'GROUP BY post_id,comment_trackback';
247         
248          $rs = $this->con->select($strReq);
249         
250          while ($rs->fetch()) {
251               $counted_posts_ids[] = (integer) $rs->post_id;
252               $counted_is_trackback[] = (boolean) $rs->comment_trackback;
253               $counted_nb_comments[] = (integer) $rs->nb_comment;
254          }
255         
256          # c) Update comments numbers on posts
257          # This compare previous requests to update also posts without comment
258          $cur = $this->con->openCursor($this->prefix.'post');
259         
260          foreach($affected_posts_ids as $affected_key => $affected_post_id)
261          {
262               if (!array_key_exists($affected_key, $affected_is_trackback)) {
263                    $affected_is_trackback[$affected_key] = false;
264               }
265               $nb_comment = $nb_trackback = 0;
266               
267               foreach($counted_posts_ids as $counted_key => $counted_post_id)
268               {
269                    if ($affected_post_id != $counted_post_id 
270                    || $affected_is_trackback[$affected_key] != $counted_is_trackback[$counted_key]) {
271                         continue;
272                    }
273                   
274                    if ($counted_is_trackback[$counted_key]) {
275                         $nb_trackback = $counted_nb_comments[$counted_key];
276                    } else {
277                         $nb_comment = $counted_nb_comments[$counted_key];
278                    }
279               }
280               
281               if ($affected_is_trackback[$affected_key]) {
282                    $cur->nb_trackback = $nb_trackback;
283               } else {
284                    $cur->nb_comment = $nb_comment;
285               }
286
287               $cur->update('WHERE post_id = '.$affected_post_id);
288               $cur->clean();
289          }
290     }
291     //@}
292     
293     /// @name Categories management methods
294     //@{
295     public function categories()
296     {
297          if (!($this->categories instanceof dcCategories)) {
298               $this->categories = new dcCategories($this->core);
299          }
300         
301          return $this->categories;
302     }
303     
304     /**
305     Retrieves categories. <var>$params</var> is an associative array which can
306     take the following parameters:
307     
308     - post_type: Get only entries with given type (default "post")
309     - cat_url: filter on cat_url field
310     - cat_id: filter on cat_id field
311     - start: start with a given category
312     - level: categories level to retrieve
313     
314     @param    params    <b>array</b>        Parameters
315     @return   <b>record</b>
316     */
317     public function getCategories($params=array())
318     {
319          $c_params = array();
320          if (isset($params['post_type'])) {
321               $c_params['post_type'] = $params['post_type'];
322               unset($params['post_type']);
323          }
324          $counter = $this->getCategoriesCounter($c_params);
325         
326          $without_empty = $this->core->auth->userID() == false; # For public display
327         
328          $start = isset($params['start']) ? (integer) $params['start'] : 0;
329          $l = isset($params['level']) ? (integer) $params['level'] : 0;
330         
331          $rs = $this->categories()->getChildren($start,null,'desc');
332         
333          # Get each categories total posts count
334          $data = array();
335          $stack = array();
336          $level = 0;
337          $cols = $rs->columns();
338          while ($rs->fetch())
339          {
340               $nb_post = isset($counter[$rs->cat_id]) ? (integer) $counter[$rs->cat_id] : 0;
341               
342               if ($rs->level > $level) {
343                    $nb_total = $nb_post;
344                    $stack[$rs->level] = (integer) $nb_post;
345               } elseif ($rs->level == $level) {
346                    $nb_total = $nb_post;
347                    $stack[$rs->level] += $nb_post;
348               } else {
349                    $nb_total = $stack[$rs->level+1] + $nb_post;
350                    if (isset($stack[$rs->level])) {
351                         $stack[$rs->level] += $nb_total;
352                    } else {
353                         $stack[$rs->level] = $nb_total;
354                    }
355                    unset($stack[$rs->level+1]);
356               }
357               
358               if ($nb_total == 0 && $without_empty) {
359                    continue;
360               }
361               
362               $level = $rs->level;
363               
364               $t = array();
365               foreach ($cols as $c) {
366                    $t[$c] = $rs->f($c);
367               }
368               $t['nb_post'] = $nb_post;
369               $t['nb_total'] = $nb_total;
370               
371               if ($l == 0 || ($l > 0 && $l == $rs->level)) {
372                    array_unshift($data,$t);
373               }
374          }
375         
376          # We need to apply filter after counting
377          if (isset($params['cat_id']) && $params['cat_id'] !== '')
378          {
379               $found = false;
380               foreach ($data as $v) {
381                    if ($v['cat_id'] == $params['cat_id']) {
382                         $found = true;
383                         $data = array($v);
384                         break;
385                    }
386               }
387               if (!$found) {
388                    $data = array();
389               }
390          }
391         
392          if (isset($params['cat_url']) && ($params['cat_url'] !== '') 
393               && !isset($params['cat_id']))
394          {
395               $found = false;
396               foreach ($data as $v) {
397                    if ($v['cat_url'] == $params['cat_url']) {
398                         $found = true;
399                         $data = array($v);
400                         break;
401                    }
402               }
403               if (!$found) {
404                    $data = array();
405               }
406          }
407         
408          return staticRecord::newFromArray($data);
409     }
410     
411     /**
412     Retrieves a category by its ID.
413     
414     @param    id        <b>integer</b>      Category ID
415     @return   <b>record</b>
416     */
417     public function getCategory($id)
418     {
419          return $this->getCategories(array('cat_id' => $id));
420     }
421     
422     /**
423     Retrieves parents of a given category.
424     
425     @param    id        <b>integer</b>      Category ID
426     @return   <b>record</b>
427     */
428     public function getCategoryParents($id)
429     {
430          return $this->categories()->getParents($id);
431     }
432     
433     /**
434     Retrieves first parent of a given category.
435     
436     @param    id        <b>integer</b>      Category ID
437     @return   <b>record</b>
438     */
439     public function getCategoryParent($id)
440     {
441          return $this->categories()->getParent($id);
442     }
443     
444     /**
445     Retrieves all category's first children
446     
447     @param    id        <b>integer</b>      Category ID
448     @return   <b>record</b>
449     */
450     public function getCategoryFirstChildren($id)
451     {
452          return $this->getCategories(array('start' => $id,'level' => $id == 0 ? 1 : 2));
453     }
454     
455     private function getCategoriesCounter($params=array())
456     {
457          $strReq =
458          'SELECT  C.cat_id, COUNT(P.post_id) AS nb_post '.
459          'FROM '.$this->prefix.'category AS C '.
460          'JOIN '.$this->prefix."post P ON (C.cat_id = P.cat_id AND P.blog_id = '".$this->con->escape($this->id)."' ) ".
461          "WHERE C.blog_id = '".$this->con->escape($this->id)."' ";
462         
463          if (!$this->core->auth->userID()) {
464               $strReq .= 'AND P.post_status = 1 ';
465          }
466         
467          if (!empty($params['post_type'])) {
468               $strReq .= 'AND P.post_type '.$this->con->in($params['post_type']);
469          }
470         
471          $strReq .= 'GROUP BY C.cat_id ';
472         
473          $rs = $this->con->select($strReq);
474          $counters = array();
475          while ($rs->fetch()) {
476               $counters[$rs->cat_id] = $rs->nb_post;
477          }
478         
479          return $counters;
480     }
481     
482     /**
483     Creates a new category. Takes a cursor as input and returns the new category
484     ID.
485     
486     @param    cur       <b>cursor</b>       Category cursor
487     @return   <b>integer</b>      New category ID
488     */
489     public function addCategory($cur,$parent=0)
490     {
491          if (!$this->core->auth->check('categories',$this->id)) {
492               throw new Exception(__('You are not allowed to add categories'));
493          }
494         
495          $url = array();
496          if ($parent != 0)
497          {
498               $rs = $this->getCategory($parent);
499               if ($rs->isEmpty()) {
500                    $url = array();
501               } else {
502                    $url[] = $rs->cat_url;
503               }
504          }
505         
506          if ($cur->cat_url == '') {
507               $url[] = text::tidyURL($cur->cat_title,false);
508          } else {
509               $url[] = $cur->cat_url;
510          }
511         
512          $cur->cat_url = implode('/',$url);
513         
514          $this->getCategoryCursor($cur);
515          $cur->blog_id = (string) $this->id;
516         
517          # --BEHAVIOR-- coreBeforeCategoryCreate
518          $this->core->callBehavior('coreBeforeCategoryCreate',$this,$cur);
519         
520          $id = $this->categories()->addNode($cur,$parent);
521          # Update category's cursor
522          $rs = $this->getCategory($id);
523          if (!$rs->isEmpty()) {
524               $cur->cat_lft = $rs->cat_lft;
525               $cur->cat_rgt = $rs->cat_rgt;
526          }
527         
528          # --BEHAVIOR-- coreAfterCategoryCreate
529          $this->core->callBehavior('coreAfterCategoryCreate',$this,$cur);
530          $this->triggerBlog();
531         
532          return $cur->cat_id;
533     }
534     
535     /**
536     Updates an existing category.
537     
538     @param    id        <b>integer</b>      Category ID
539     @param    cur       <b>cursor</b>       Category cursor
540     */
541     public function updCategory($id,$cur)
542     {
543          if (!$this->core->auth->check('categories',$this->id)) {
544               throw new Exception(__('You are not allowed to update categories'));
545          }
546         
547          if ($cur->cat_url == '')
548          {
549               $url = array();
550               $rs = $this->categories()->getParents($id);
551               while ($rs->fetch()) {
552                    if ($rs->index() == $rs->count()-1) {
553                         $url[] = $rs->cat_url;
554                    }
555               }
556               
557               
558               $url[] = text::tidyURL($cur->cat_title,false);
559               $cur->cat_url = implode('/',$url);
560          }
561         
562          $this->getCategoryCursor($cur,$id);
563         
564          # --BEHAVIOR-- coreBeforeCategoryUpdate
565          $this->core->callBehavior('coreBeforeCategoryUpdate',$this,$cur);
566         
567          $cur->update(
568          'WHERE cat_id = '.(integer) $id.' '.
569          "AND blog_id = '".$this->con->escape($this->id)."' ");
570         
571          # --BEHAVIOR-- coreAfterCategoryUpdate
572          $this->core->callBehavior('coreAfterCategoryUpdate',$this,$cur);
573         
574          $this->triggerBlog();
575     }
576     
577     /**
578     DEPRECATED METHOD. Use dcBlog::setCategoryParent and dcBlog::moveCategory
579     instead.
580     
581     @param    id        <b>integer</b>      Category ID
582     @param    order     <b>integer</b>      Category position
583     */
584     public function updCategoryOrder($id,$order)
585     {
586          return;
587     }
588     
589     /**
590     Set a category parent
591     
592     @param    id        <b>integer</b>      Category ID
593     @param    parent    <b>integer</b>      Parent Category ID
594     */
595     public function setCategoryParent($id,$parent)
596     {
597          $this->categories()->setNodeParent($id,$parent);
598          $this->triggerBlog();
599     }
600     
601     /**
602     Set category position
603     
604     @param    id        <b>integer</b>      Category ID
605     @param    sibling   <b>integer</b>      Sibling Category ID
606     @param    move      <b>integer</b>      Order (before|after)
607     */
608     public function setCategoryPosition($id,$sibling,$move)
609     {
610          $this->categories()->setNodePosition($id,$sibling,$move);
611          $this->triggerBlog();
612     }
613     
614     /**
615     Deletes a category.
616     
617     @param    id        <b>integer</b>      Category ID
618     */
619     public function delCategory($id)
620     {
621          if (!$this->core->auth->check('categories',$this->id)) {
622               throw new Exception(__('You are not allowed to delete categories'));
623          }
624         
625          $strReq = 'SELECT COUNT(post_id) AS nb_post '.
626                    'FROM '.$this->prefix.'post '.
627                    'WHERE cat_id = '.(integer) $id.' '.
628                    "AND blog_id = '".$this->con->escape($this->id)."' ";
629         
630          $rs = $this->con->select($strReq);
631         
632          if ($rs->nb_post > 0) {
633               throw new Exception(__('This category is not empty.'));
634          }
635         
636          $this->categories()->deleteNode($id,true);
637          $this->triggerBlog();
638     }
639     
640     /**
641     Reset categories order and relocate them to first level
642     */
643     public function resetCategoriesOrder()
644     {
645          if (!$this->core->auth->check('categories',$this->id)) {
646               throw new Exception(__('You are not allowed to reset categories order'));
647          }
648         
649          $this->categories()->resetOrder();
650          $this->triggerBlog();
651     }
652     
653     private function checkCategory($title,$url,$id=null)
654     {
655          # Let's check if URL is taken...
656          $strReq = 
657               'SELECT cat_url FROM '.$this->prefix.'category '.
658               "WHERE cat_url = '".$this->con->escape($url)."' ".
659               ($id ? 'AND cat_id <> '.(integer) $id. ' ' : '').
660               "AND blog_id = '".$this->con->escape($this->id)."' ".
661               'ORDER BY cat_url DESC';
662         
663          $rs = $this->con->select($strReq);
664         
665          if (!$rs->isEmpty())
666          {
667               if ($this->con->driver() == 'mysql') {
668                    $clause = "REGEXP '^".$this->con->escape($url)."[0-9]+$'";
669               } elseif ($this->con->driver() == 'pgsql') {
670                    $clause = "~ '^".$this->con->escape($url)."[0-9]+$'";
671               } else {
672                    $clause = "LIKE '".$this->con->escape($url)."%'";
673               }
674               $strReq = 
675                    'SELECT cat_url FROM '.$this->prefix.'category '.
676                    "WHERE cat_url ".$clause.' '.
677                    ($id ? 'AND cat_id <> '.(integer) $id. ' ' : '').
678                    "AND blog_id = '".$this->con->escape($this->id)."' ".
679                    'ORDER BY cat_url DESC ';
680               
681               $rs = $this->con->select($strReq);
682               $a = array();
683               while ($rs->fetch()) {
684                    $a[] = $rs->cat_url;
685               }
686               
687               natsort($a);
688               $t_url = end($a);
689               
690               if (preg_match('/(.*?)([0-9]+)$/',$t_url,$m)) {
691                    $i = (integer) $m[2];
692                    $url = $m[1];
693               } else {
694                    $i = 1;
695               }
696               
697               return $url.($i+1);
698          }
699         
700          # URL is empty?
701          if ($url == '') {
702               throw new Exception(__('Empty category URL'));
703          }
704         
705          return $url;
706     }
707     
708     private function getCategoryCursor($cur,$id=null)
709     {
710          if ($cur->cat_title == '') {
711               throw new Exception(__('You must provide a category title'));
712          }
713         
714          # If we don't have any cat_url, let's do one
715          if ($cur->cat_url == '') {
716               $cur->cat_url = text::tidyURL($cur->cat_title,false);
717          }
718         
719          # Still empty ?
720          if ($cur->cat_url == '') {
721               throw new Exception(__('You must provide a category URL'));
722          } else {
723               $cur->cat_url = text::tidyURL($cur->cat_url,true);
724          }
725         
726          # Check if title or url are unique
727          $cur->cat_url = $this->checkCategory($cur->cat_title,$cur->cat_url,$id);
728         
729          if ($cur->cat_desc !== null) {
730               $cur->cat_desc = $this->core->HTMLfilter($cur->cat_desc);
731          }
732     }
733     //@}
734     
735     /// @name Entries management methods
736     //@{
737     /**
738     Retrieves entries. <b>$params</b> is an array taking the following
739     optionnal parameters:
740     
741     - no_content: Don't retrieve entry content (excerpt and content)
742     - post_type: Get only entries with given type (default "post", array for many types and '' for no type)
743     - post_id: (integer or array) Get entry with given post_id
744     - post_url: Get entry with given post_url field
745     - user_id: (integer) Get entries belonging to given user ID
746     - cat_id: (string or array) Get entries belonging to given category ID
747     - cat_id_not: deprecated (use cat_id with "id ?not" instead)
748     - cat_url: (string or array) Get entries belonging to given category URL
749     - cat_url_not: deprecated (use cat_url with "url ?not" instead)
750     - post_status: (integer) Get entries with given post_status
751     - post_selected: (boolean) Get select flaged entries
752     - post_year: (integer) Get entries with given year
753     - post_month: (integer) Get entries with given month
754     - post_day: (integer) Get entries with given day
755     - post_lang: Get entries with given language code
756     - search: Get entries corresponding of the following search string
757     - columns: (array) More columns to retrieve
758     - sql: Append SQL string at the end of the query
759     - from: Append SQL string after "FROM" statement in query
760     - order: Order of results (default "ORDER BY post_dt DES")
761     - limit: Limit parameter
762     - sql_only : return the sql request instead of results. Only ids are selected
763     - exclude_post_id : (integer or array) Exclude entries with given post_id
764     
765     Please note that on every cat_id or cat_url, you can add ?not to exclude
766     the category and ?sub to get subcategories.
767     
768     @param    params         <b>array</b>        Parameters
769     @param    count_only     <b>boolean</b>      Only counts results
770     @return   <b>record</b>  A record with some more capabilities or the SQL request
771     */
772     public function getPosts($params=array(),$count_only=false)
773     {
774          # --BEHAVIOR-- coreBlogBeforeGetPosts
775          $params = new ArrayObject($params);
776          $this->core->callBehavior('coreBlogBeforeGetPosts',$params);
777
778          if ($count_only)
779          {
780               $strReq = 'SELECT count(P.post_id) ';
781          }
782          elseif (!empty($params['sql_only'])) 
783          {
784               $strReq = 'SELECT P.post_id ';
785          }
786          else
787          {
788               if (!empty($params['no_content'])) {
789                    $content_req = '';
790               } else {
791                    $content_req =
792                    'post_excerpt, post_excerpt_xhtml, '.
793                    'post_content, post_content_xhtml, post_notes, ';
794               }
795               
796               if (!empty($params['columns']) && is_array($params['columns'])) {
797                    $content_req .= implode(', ',$params['columns']).', ';
798               }
799               
800               $strReq =
801               'SELECT P.post_id, P.blog_id, P.user_id, P.cat_id, post_dt, '.
802               'post_tz, post_creadt, post_upddt, post_format, post_password, '.
803               'post_url, post_lang, post_title, '.$content_req.
804               'post_type, post_meta, post_status, post_selected, post_position, '.
805               'post_open_comment, post_open_tb, nb_comment, nb_trackback, '.
806               'U.user_name, U.user_firstname, U.user_displayname, U.user_email, '.
807               'U.user_url, '.
808               'C.cat_title, C.cat_url, C.cat_desc ';
809          }
810         
811          $strReq .=
812          'FROM '.$this->prefix.'post P '.
813          'INNER JOIN '.$this->prefix.'user U ON U.user_id = P.user_id '.
814          'LEFT OUTER JOIN '.$this->prefix.'category C ON P.cat_id = C.cat_id ';
815         
816          if (!empty($params['from'])) {
817               $strReq .= $params['from'].' ';
818          }
819         
820          $strReq .=
821          "WHERE P.blog_id = '".$this->con->escape($this->id)."' ";
822         
823          if (!$this->core->auth->check('contentadmin',$this->id)) {
824               $strReq .= 'AND ((post_status = 1 ';
825               
826               if ($this->without_password) {
827                    $strReq .= 'AND post_password IS NULL ';
828               }
829               $strReq .= ') ';
830               
831               if ($this->core->auth->userID()) {
832                    $strReq .= "OR P.user_id = '".$this->con->escape($this->core->auth->userID())."')";
833               } else {
834                    $strReq .= ') ';
835               }
836          }
837         
838          #Adding parameters
839          if (isset($params['post_type']))
840          {
841               if (is_array($params['post_type']) || $params['post_type'] != '') {
842                    $strReq .= 'AND post_type '.$this->con->in($params['post_type']);
843               }
844          }
845          else
846          {
847               $strReq .= "AND post_type = 'post' ";
848          }
849         
850          if (isset($params['post_id']) && $params['post_id'] !== '') {
851               if (is_array($params['post_id'])) {
852                    array_walk($params['post_id'],create_function('&$v,$k','if($v!==null){$v=(integer)$v;}'));
853               } else {
854                    $params['post_id'] = array((integer) $params['post_id']);
855               }
856               $strReq .= 'AND P.post_id '.$this->con->in($params['post_id']);
857          }
858         
859          if (isset($params['exclude_post_id']) && $params['exclude_post_id'] !== '') {
860               if (is_array($params['exclude_post_id'])) {
861                    array_walk($params['exclude_post_id'],create_function('&$v,$k','if($v!==null){$v=(integer)$v;}'));
862               } else {
863                    $params['exclude_post_id'] = array((integer) $params['exclude_post_id']);
864               }
865               $strReq .= 'AND P.post_id NOT '.$this->con->in($params['exclude_post_id']);
866          }
867         
868          if (isset($params['post_url']) && $params['post_url'] !== '') {
869               $strReq .= "AND post_url = '".$this->con->escape($params['post_url'])."' ";
870          }
871         
872          if (!empty($params['user_id'])) {
873               $strReq .= "AND U.user_id = '".$this->con->escape($params['user_id'])."' ";
874          }
875         
876          if (isset($params['cat_id']) && $params['cat_id'] !== '')
877          {
878               if (!is_array($params['cat_id'])) {
879                    $params['cat_id'] = array($params['cat_id']);
880               }
881               if (!empty($params['cat_id_not'])) {
882                    array_walk($params['cat_id'],create_function('&$v,$k','$v=$v." ?not";'));
883               }
884               $strReq .= 'AND '.$this->getPostsCategoryFilter($params['cat_id'],'cat_id').' ';
885          }
886          elseif (isset($params['cat_url']) && $params['cat_url'] !== '')
887          {
888               if (!is_array($params['cat_url'])) {
889                    $params['cat_url'] = array($params['cat_url']);
890               }
891               if (!empty($params['cat_url_not'])) {
892                    array_walk($params['cat_url'],create_function('&$v,$k','$v=$v." ?not";'));
893               }
894               $strReq .= 'AND '.$this->getPostsCategoryFilter($params['cat_url'],'cat_url').' ';
895          }
896         
897          /* Other filters */
898          if (isset($params['post_status'])) {
899               $strReq .= 'AND post_status = '.(integer) $params['post_status'].' ';
900          }
901         
902          if (isset($params['post_selected'])) {
903               $strReq .= 'AND post_selected = '.(integer) $params['post_selected'].' ';
904          }
905         
906          if (!empty($params['post_year'])) {
907               $strReq .= 'AND '.$this->con->dateFormat('post_dt','%Y').' = '.
908               "'".sprintf('%04d',$params['post_year'])."' ";
909          }
910         
911          if (!empty($params['post_month'])) {
912               $strReq .= 'AND '.$this->con->dateFormat('post_dt','%m').' = '.
913               "'".sprintf('%02d',$params['post_month'])."' ";
914          }
915         
916          if (!empty($params['post_day'])) {
917               $strReq .= 'AND '.$this->con->dateFormat('post_dt','%d').' = '.
918               "'".sprintf('%02d',$params['post_day'])."' ";
919          }
920         
921          if (!empty($params['post_lang'])) {
922               $strReq .= "AND P.post_lang = '".$this->con->escape($params['post_lang'])."' ";
923          }
924         
925          if (!empty($params['search']))
926          {
927               $words = text::splitWords($params['search']);
928               
929               if (!empty($words))
930               {
931                    # --BEHAVIOR-- corePostSearch
932                    if ($this->core->hasBehavior('corePostSearch')) {
933                         $this->core->callBehavior('corePostSearch',$this->core,array(&$words,&$strReq,&$params));
934                    }
935                   
936                    if ($words)
937                    {
938                         foreach ($words as $i => $w) {
939                              $words[$i] = "post_words LIKE '%".$this->con->escape($w)."%'";
940                         }
941                         $strReq .= 'AND '.implode(' AND ',$words).' ';
942                    }
943               }
944          }
945         
946          if (!empty($params['sql'])) {
947               $strReq .= $params['sql'].' ';
948          }
949         
950          if (!$count_only)
951          {
952               if (!empty($params['order'])) {
953                    $strReq .= 'ORDER BY '.$this->con->escape($params['order']).' ';
954               } else {
955                    $strReq .= 'ORDER BY post_dt DESC ';
956               }
957          }
958         
959          if (!$count_only && !empty($params['limit'])) {
960               $strReq .= $this->con->limit($params['limit']);
961          }
962         
963          if (!empty($params['sql_only'])) {
964               return $strReq;
965          }
966         
967          $rs = $this->con->select($strReq);
968          $rs->core = $this->core;
969          $rs->_nb_media = array();
970          $rs->extend('rsExtPost');
971         
972          # --BEHAVIOR-- coreBlogGetPosts
973          $this->core->callBehavior('coreBlogGetPosts',$rs);
974         
975          return $rs;
976     }
977     
978     /**
979     Returns a record with post id, title and date for next or previous post
980     according to the post ID.
981     $dir could be 1 (next post) or -1 (previous post).
982     
983     @param    post_id                  <b>integer</b>      Post ID
984     @param    dir                      <b>integer</b>      Search direction
985     @param    restrict_to_category     <b>boolean</b>      Restrict to post with same category
986     @param    restrict_to_lang         <b>boolean</b>      Restrict to post with same lang
987     @return   record
988     */
989     public function getNextPost($post,$dir,$restrict_to_category=false, $restrict_to_lang=false)
990     {
991          $dt = $post->post_dt;
992          $post_id = (integer) $post->post_id;
993         
994          if($dir > 0) {
995               $sign = '>';
996               $order = 'ASC';
997          }
998          else {
999               $sign = '<';
1000               $order = 'DESC';
1001          }
1002         
1003          $params['post_type'] = $post->post_type;
1004          $params['limit'] = 1;
1005          $params['order'] = 'post_dt '.$order.', P.post_id '.$order;
1006          $params['sql'] =
1007          'AND ( '.
1008          "    (post_dt = '".$this->con->escape($dt)."' AND P.post_id ".$sign." ".$post_id.") ".
1009          "    OR post_dt ".$sign." '".$this->con->escape($dt)."' ".
1010          ') ';
1011         
1012          if ($restrict_to_category) {
1013               $params['sql'] .= $post->cat_id ? 'AND P.cat_id = '.(integer) $post->cat_id.' ' : 'AND P.cat_id IS NULL ';
1014          }
1015         
1016          if ($restrict_to_lang) {
1017               $params['sql'] .= $post->post_lang ? 'AND P.post_lang = \''. $this->con->escape($post->post_lang) .'\' ': 'AND P.post_lang IS NULL ';
1018          }
1019         
1020          $rs = $this->getPosts($params);
1021         
1022          if ($rs->isEmpty()) {
1023               return null;
1024          }
1025         
1026          return $rs;
1027     }
1028     
1029     /**
1030     Retrieves different languages and post count on blog, based on post_lang
1031     field. <var>$params</var> is an array taking the following optionnal
1032     parameters:
1033     
1034     - post_type: Get only entries with given type (default "post", '' for no type)
1035     - lang: retrieve post count for selected lang
1036     - order: order statement (default post_lang DESC)
1037     
1038     @param    params    <b>array</b>        Parameters
1039     @return   record
1040     */
1041     public function getLangs($params=array())
1042     {
1043          $strReq = 'SELECT COUNT(post_id) as nb_post, post_lang '.
1044                    'FROM '.$this->prefix.'post '.
1045                    "WHERE blog_id = '".$this->con->escape($this->id)."' ".
1046                    "AND post_lang <> '' ".
1047                    "AND post_lang IS NOT NULL ";
1048         
1049          if (!$this->core->auth->check('contentadmin',$this->id)) {
1050               $strReq .= 'AND ((post_status = 1 ';
1051               
1052               if ($this->without_password) {
1053                    $strReq .= 'AND post_password IS NULL ';
1054               }
1055               $strReq .= ') ';
1056               
1057               if ($this->core->auth->userID()) {
1058                    $strReq .= "OR user_id = '".$this->con->escape($this->core->auth->userID())."')";
1059               } else {
1060                    $strReq .= ') ';
1061               }
1062          }
1063         
1064          if (isset($params['post_type'])) {
1065               if ($params['post_type'] != '') {
1066                    $strReq .= "AND post_type = '".$this->con->escape($params['post_type'])."' ";
1067               }
1068          } else {
1069               $strReq .= "AND post_type = 'post' ";
1070          }
1071         
1072          if (isset($params['lang'])) {
1073               $strReq .= "AND post_lang = '".$this->con->escape($params['lang'])."' ";
1074          }
1075         
1076          $strReq .= 'GROUP BY post_lang ';
1077         
1078          $order = 'desc';
1079          if (!empty($params['order']) && preg_match('/^(desc|asc)$/i',$params['order'])) {
1080               $order = $params['order'];
1081          }
1082          $strReq .= 'ORDER BY post_lang '.$order.' ';
1083         
1084          return $this->con->select($strReq);
1085     }
1086     
1087     /**
1088     Returns a record with all distinct blog dates and post count.
1089     <var>$params</var> is an array taking the following optionnal parameters:
1090     
1091     - type: (day|month|year) Get days, months or years
1092     - year: (integer) Get dates for given year
1093     - month: (integer) Get dates for given month
1094     - day: (integer) Get dates for given day
1095     - cat_id: (integer) Category ID filter
1096     - cat_url: Category URL filter
1097     - post_lang: lang of the posts
1098     - next: Get date following match
1099     - previous: Get date before match
1100     - order: Sort by date "ASC" or "DESC"
1101     
1102     @param    params    <b>array</b>        Parameters array
1103     @return   record
1104     */
1105     public function getDates($params=array())
1106     {
1107          $dt_f = '%Y-%m-%d';
1108          $dt_fc = '%Y%m%d';
1109          if (isset($params['type'])) {
1110               if ($params['type'] == 'year') {
1111                    $dt_f = '%Y-01-01';
1112                    $dt_fc = '%Y0101';
1113               } elseif ($params['type'] == 'month') {
1114                    $dt_f = '%Y-%m-01';
1115                    $dt_fc = '%Y%m01';
1116               }
1117          }
1118          $dt_f .= ' 00:00:00';
1119          $dt_fc .= '000000';
1120         
1121          $cat_field = $catReq = $limit = '';
1122         
1123          if (isset($params['cat_id']) && $params['cat_id'] !== '') {
1124               $catReq = 'AND P.cat_id = '.(integer) $params['cat_id'].' ';
1125               $cat_field = ', C.cat_url ';
1126          } elseif (isset($params['cat_url']) && $params['cat_url'] !== '') {
1127               $catReq = "AND C.cat_url = '".$this->con->escape($params['cat_url'])."' ";
1128               $cat_field = ', C.cat_url ';
1129          }
1130          if (!empty($params['post_lang'])) {
1131               $catReq = 'AND P.post_lang = \''. $params['post_lang'].'\' ';
1132          }
1133         
1134          $strReq = 'SELECT DISTINCT('.$this->con->dateFormat('post_dt',$dt_f).') AS dt '.
1135                    $cat_field.
1136                    ',COUNT(P.post_id) AS nb_post '.
1137                    'FROM '.$this->prefix.'post P LEFT JOIN '.$this->prefix.'category C '.
1138                    'ON P.cat_id = C.cat_id '.
1139                    "WHERE P.blog_id = '".$this->con->escape($this->id)."' ".
1140                    $catReq;
1141         
1142          if (!$this->core->auth->check('contentadmin',$this->id)) {
1143               $strReq .= 'AND ((post_status = 1 ';
1144               
1145               if ($this->without_password) {
1146                    $strReq .= 'AND post_password IS NULL ';
1147               }
1148               $strReq .= ') ';
1149               
1150               if ($this->core->auth->userID()) {
1151                    $strReq .= "OR P.user_id = '".$this->con->escape($this->core->auth->userID())."')";
1152               } else {
1153                    $strReq .= ') ';
1154               }
1155          }
1156         
1157          if (!empty($params['post_type'])) {
1158               $strReq .= "AND post_type ".$this->con->in($params['post_type'])." ";
1159          } else {
1160               $strReq .= "AND post_type = 'post' ";
1161          }
1162         
1163          if (!empty($params['year'])) {
1164               $strReq .= 'AND '.$this->con->dateFormat('post_dt','%Y')." = '".sprintf('%04d',$params['year'])."' ";
1165          }
1166         
1167          if (!empty($params['month'])) {
1168               $strReq .= 'AND '.$this->con->dateFormat('post_dt','%m')." = '".sprintf('%02d',$params['month'])."' ";
1169          }
1170         
1171          if (!empty($params['day'])) {
1172               $strReq .= 'AND '.$this->con->dateFormat('post_dt','%d')." = '".sprintf('%02d',$params['day'])."' ";
1173          }
1174         
1175          # Get next or previous date
1176          if (!empty($params['next']) || !empty($params['previous']))
1177          {
1178               if (!empty($params['next'])) {
1179                    $pdir = ' > ';
1180                    $params['order'] = 'asc';
1181                    $dt = $params['next'];
1182               } else {
1183                    $pdir = ' < ';
1184                    $params['order'] = 'desc';
1185                    $dt = $params['previous'];
1186               }
1187               
1188               $dt = date('YmdHis',strtotime($dt));
1189               
1190               $strReq .= 'AND '.$this->con->dateFormat('post_dt',$dt_fc).$pdir."'".$dt."' ";
1191               $limit = $this->con->limit(1);
1192          }
1193         
1194          $strReq .= 'GROUP BY dt '.$cat_field;
1195         
1196          $order = 'desc';
1197          if (!empty($params['order']) && preg_match('/^(desc|asc)$/i',$params['order'])) {
1198               $order = $params['order'];
1199          }
1200         
1201          $strReq .=
1202          'ORDER BY dt '.$order.' '.
1203          $limit;
1204         
1205          $rs = $this->con->select($strReq);
1206          $rs->extend('rsExtDates');
1207          return $rs;
1208     }
1209     
1210     /**
1211     Creates a new entry. Takes a cursor as input and returns the new entry
1212     ID.
1213     
1214     @param    cur       <b>cursor</b>       Post cursor
1215     @return   <b>integer</b>      New post ID
1216     */
1217     public function addPost($cur)
1218     {
1219          if (!$this->core->auth->check('usage,contentadmin',$this->id)) {
1220               throw new Exception(__('You are not allowed to create an entry'));
1221          }
1222         
1223          $this->con->writeLock($this->prefix.'post');
1224          try
1225          {
1226               # Get ID
1227               $rs = $this->con->select(
1228                    'SELECT MAX(post_id) '.
1229                    'FROM '.$this->prefix.'post ' 
1230                    );
1231               
1232               $cur->post_id = (integer) $rs->f(0) + 1;
1233               $cur->blog_id = (string) $this->id;
1234               $cur->post_creadt = date('Y-m-d H:i:s');
1235               $cur->post_upddt = date('Y-m-d H:i:s');
1236               $cur->post_tz = $this->core->auth->getInfo('user_tz');
1237               
1238               # Post excerpt and content
1239               $this->getPostContent($cur,$cur->post_id);
1240               
1241               $this->getPostCursor($cur);
1242               
1243               $cur->post_url = $this->getPostURL($cur->post_url,$cur->post_dt,$cur->post_title,$cur->post_id);
1244               
1245               if (!$this->core->auth->check('publish,contentadmin',$this->id)) {
1246                    $cur->post_status = -2;
1247               }
1248               
1249               # --BEHAVIOR-- coreBeforePostCreate
1250               $this->core->callBehavior('coreBeforePostCreate',$this,$cur);
1251               
1252               $cur->insert();
1253               $this->con->unlock();
1254          }
1255          catch (Exception $e)
1256          {
1257               $this->con->unlock();
1258               throw $e;
1259          }
1260         
1261          # --BEHAVIOR-- coreAfterPostCreate
1262          $this->core->callBehavior('coreAfterPostCreate',$this,$cur);
1263         
1264          $this->triggerBlog();
1265         
1266          return $cur->post_id;
1267     }
1268     
1269     /**
1270     Updates an existing post.
1271     
1272     @param    id        <b>integer</b>      Post ID
1273     @param    cur       <b>cursor</b>       Post cursor
1274     */
1275     public function updPost($id,$cur)
1276     {
1277          if (!$this->core->auth->check('usage,contentadmin',$this->id)) {
1278               throw new Exception(__('You are not allowed to update entries'));
1279          }
1280         
1281          $id = (integer) $id;
1282         
1283          if (empty($id)) {
1284               throw new Exception(__('No such entry ID'));
1285          }
1286         
1287          # Post excerpt and content
1288          $this->getPostContent($cur,$id);
1289         
1290          $this->getPostCursor($cur);
1291         
1292          if ($cur->post_url !== null) {
1293               $cur->post_url = $this->getPostURL($cur->post_url,$cur->post_dt,$cur->post_title,$id);
1294          }
1295         
1296          if (!$this->core->auth->check('publish,contentadmin',$this->id)) {
1297               $cur->unsetField('post_status');
1298          }
1299         
1300          $cur->post_upddt = date('Y-m-d H:i:s');
1301         
1302          #If user is only "usage", we need to check the post's owner
1303          if (!$this->core->auth->check('contentadmin',$this->id))
1304          {
1305               $strReq = 'SELECT post_id '.
1306                         'FROM '.$this->prefix.'post '.
1307                         'WHERE post_id = '.$id.' '.
1308                         "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
1309               
1310               $rs = $this->con->select($strReq);
1311               
1312               if ($rs->isEmpty()) {
1313                    throw new Exception(__('You are not allowed to edit this entry'));
1314               }
1315          }
1316         
1317          # --BEHAVIOR-- coreBeforePostUpdate
1318          $this->core->callBehavior('coreBeforePostUpdate',$this,$cur);
1319         
1320          $cur->update('WHERE post_id = '.$id.' ');
1321         
1322          # --BEHAVIOR-- coreAfterPostUpdate
1323          $this->core->callBehavior('coreAfterPostUpdate',$this,$cur);
1324         
1325          $this->triggerBlog();
1326     }
1327     
1328     /**
1329     Updates post status.
1330     
1331     @param    id        <b>integer</b>      Post ID
1332     @param    status    <b>integer</b>      Post status
1333     */
1334     public function updPostStatus($id,$status)
1335     {
1336          $this->updPostsStatus($id,$status);
1337     }
1338     
1339     /**
1340     Updates posts status.
1341     
1342     @param    ids       <b>mixed</b>        Post(s) ID(s)
1343     @param    status    <b>integer</b>      Post status
1344     */
1345     public function updPostsStatus($ids,$status)
1346     {
1347          if (!$this->core->auth->check('publish,contentadmin',$this->id)) {
1348               throw new Exception(__('You are not allowed to change this entry status'));
1349          }
1350         
1351          $posts_ids = dcUtils::cleanIds($ids);
1352          $status = (integer) $status;
1353         
1354          $strReq = "WHERE blog_id = '".$this->con->escape($this->id)."' ".
1355                    "AND post_id ".$this->con->in($posts_ids);
1356         
1357          #If user can only publish, we need to check the post's owner
1358          if (!$this->core->auth->check('contentadmin',$this->id))
1359          {
1360               $strReq .= "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
1361          }
1362         
1363          $cur = $this->con->openCursor($this->prefix.'post');
1364         
1365          $cur->post_status = $status;
1366          $cur->post_upddt = date('Y-m-d H:i:s');
1367         
1368          $cur->update($strReq);
1369          $this->triggerBlog();
1370     }
1371     
1372     /**
1373     Updates post selection.
1374     
1375     @param    id        <b>integer</b>      Post ID
1376     @param    selected  <b>integer</b>      Is selected post
1377     */
1378     public function updPostSelected($id,$selected)
1379     {
1380          $this->updPostsSelected($id,$selected);
1381     }
1382     
1383     /**
1384     Updates posts selection.
1385     
1386     @param    ids       <b>mixed</b>        Post(s) ID(s)
1387     @param    selected  <b>integer</b>      Is selected post(s)
1388     */
1389     public function updPostsSelected($ids,$selected)
1390     {
1391          if (!$this->core->auth->check('usage,contentadmin',$this->id)) {
1392               throw new Exception(__('You are not allowed to change this entry category'));
1393          }
1394         
1395          $posts_ids = dcUtils::cleanIds($ids);
1396          $selected = (boolean) $selected;
1397         
1398          $strReq = "WHERE blog_id = '".$this->con->escape($this->id)."' ".
1399                    "AND post_id ".$this->con->in($posts_ids);
1400         
1401          # If user is only usage, we need to check the post's owner
1402          if (!$this->core->auth->check('contentadmin',$this->id))
1403          {
1404               $strReq .= "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
1405          }
1406         
1407          $cur = $this->con->openCursor($this->prefix.'post');
1408         
1409          $cur->post_selected = (integer) $selected;
1410          $cur->post_upddt = date('Y-m-d H:i:s');
1411         
1412          $cur->update($strReq);
1413          $this->triggerBlog();
1414     }
1415     
1416     /**
1417     Updates post category. <var>$cat_id</var> can be null.
1418     
1419     @param    id        <b>integer</b>      Post ID
1420     @param    cat_id    <b>integer</b>      Category ID
1421     */
1422     public function updPostCategory($id,$cat_id)
1423     {
1424          $this->updPostsCategory($id,$cat_id);
1425     }
1426     
1427     /**
1428     Updates posts category. <var>$cat_id</var> can be null.
1429     
1430     @param    ids       <b>mixed</b>        Post(s) ID(s)
1431     @param    cat_id    <b>integer</b>      Category ID
1432     */
1433     public function updPostsCategory($ids,$cat_id)
1434     {
1435          if (!$this->core->auth->check('usage,contentadmin',$this->id)) {
1436               throw new Exception(__('You are not allowed to change this entry category'));
1437          }
1438         
1439          $posts_ids = dcUtils::cleanIds($ids);
1440          $cat_id = (integer) $cat_id;
1441         
1442          $strReq = "WHERE blog_id = '".$this->con->escape($this->id)."' ".
1443                    "AND post_id ".$this->con->in($posts_ids);
1444         
1445          # If user is only usage, we need to check the post's owner
1446          if (!$this->core->auth->check('contentadmin',$this->id))
1447          {
1448               $strReq .= "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
1449          }
1450         
1451          $cur = $this->con->openCursor($this->prefix.'post');
1452         
1453          $cur->cat_id = ($cat_id ? $cat_id : null);
1454          $cur->post_upddt = date('Y-m-d H:i:s');
1455         
1456          $cur->update($strReq);
1457          $this->triggerBlog();
1458     }
1459     
1460     /**
1461     Updates posts category. <var>$new_cat_id</var> can be null.
1462     
1463     @param    old_cat_id     <b>integer</b>      Old category ID
1464     @param    new_cat_id     <b>integer</b>      New category ID
1465     */
1466     public function changePostsCategory($old_cat_id,$new_cat_id)
1467     {
1468          if (!$this->core->auth->check('contentadmin,categories',$this->id)) {
1469               throw new Exception(__('You are not allowed to change entries category'));
1470          }
1471         
1472          $old_cat_id = (integer) $old_cat_id;
1473          $new_cat_id = (integer) $new_cat_id;
1474         
1475          $cur = $this->con->openCursor($this->prefix.'post');
1476         
1477          $cur->cat_id = ($new_cat_id ? $new_cat_id : null);
1478          $cur->post_upddt = date('Y-m-d H:i:s');
1479         
1480          $cur->update(
1481               'WHERE cat_id = '.$old_cat_id.' '.
1482               "AND blog_id = '".$this->con->escape($this->id)."' "
1483          );
1484          $this->triggerBlog();
1485     }
1486     
1487     /**
1488     Deletes a post.
1489     
1490     @param    id        <b>integer</b>      Post ID
1491     */
1492     public function delPost($id)
1493     {
1494          $this->delPosts($id);
1495     }
1496     
1497     /**
1498     Deletes multiple posts.
1499     
1500     @param    ids       <b>mixed</b>        Post(s) ID(s)
1501     */
1502     public function delPosts($ids)
1503     {
1504          if (!$this->core->auth->check('delete,contentadmin',$this->id)) {
1505               throw new Exception(__('You are not allowed to delete entries'));
1506          }
1507         
1508          $posts_ids = dcUtils::cleanIds($ids);
1509         
1510          if (empty($posts_ids)) {
1511               throw new Exception(__('No such entry ID'));
1512          }
1513         
1514          $strReq = 'DELETE FROM '.$this->prefix.'post '.
1515                    "WHERE blog_id = '".$this->con->escape($this->id)."' ".
1516                    "AND post_id ".$this->con->in($posts_ids);
1517         
1518          #If user can only delete, we need to check the post's owner
1519          if (!$this->core->auth->check('contentadmin',$this->id))
1520          {
1521               $strReq .= "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
1522          }
1523         
1524          $this->con->execute($strReq);
1525          $this->triggerBlog();
1526     }
1527     
1528     /**
1529     Publishes all entries flaged as "scheduled".
1530     */
1531     public function publishScheduledEntries()
1532     {
1533          $strReq = 'SELECT post_id, post_dt, post_tz '.
1534                    'FROM '.$this->prefix.'post '.
1535                    'WHERE post_status = -1 '.
1536                    "AND blog_id = '".$this->con->escape($this->id)."' ";
1537         
1538          $rs = $this->con->select($strReq);
1539         
1540          $now = dt::toUTC(time());
1541          $to_change = new ArrayObject();
1542
1543          if ($rs->isEmpty()) {
1544               return;
1545          }
1546         
1547          while ($rs->fetch())
1548          {
1549               # Now timestamp with post timezone
1550               $now_tz = $now + dt::getTimeOffset($rs->post_tz,$now);
1551               
1552               # Post timestamp
1553               $post_ts = strtotime($rs->post_dt);
1554               
1555               # If now_tz >= post_ts, we publish the entry
1556               if ($now_tz >= $post_ts) {
1557                    $to_change[] = (integer) $rs->post_id;
1558               }
1559          }
1560          if (count($to_change))
1561          {
1562               # --BEHAVIOR-- coreBeforeScheduledEntriesPublish
1563               $this->core->callBehavior('coreBeforeScheduledEntriesPublish',$this,$to_change);
1564
1565               $strReq =
1566               'UPDATE '.$this->prefix.'post SET '.
1567               'post_status = 1 '.
1568               "WHERE blog_id = '".$this->con->escape($this->id)."' ".
1569               'AND post_id '.$this->con->in((array)$to_change).' ';
1570               $this->con->execute($strReq);
1571               $this->triggerBlog();
1572
1573               # --BEHAVIOR-- coreAfterScheduledEntriesPublish
1574               $this->core->callBehavior('coreAfterScheduledEntriesPublish',$this,$to_change);
1575          }
1576         
1577     }
1578     
1579     /**
1580     Retrieves all users having posts on current blog.
1581     
1582     @param    post_type      <b>string</b>       post_type filter (post)
1583     @return   record
1584     */
1585     public function getPostsUsers($post_type='post')
1586     {
1587          $strReq = 'SELECT P.user_id, user_name, user_firstname, '.
1588                    'user_displayname, user_email '.
1589                    'FROM '.$this->prefix.'post P, '.$this->prefix.'user U '.
1590                    'WHERE P.user_id = U.user_id '.
1591                    "AND blog_id = '".$this->con->escape($this->id)."' ";
1592         
1593          if ($post_type) {
1594               $strReq .= "AND post_type = '".$this->con->escape($post_type)."' ";
1595          }
1596         
1597          $strReq .= 'GROUP BY P.user_id, user_name, user_firstname, user_displayname, user_email ';
1598         
1599          return $this->con->select($strReq);
1600     }
1601     
1602     private function getPostsCategoryFilter($arr,$field='cat_id')
1603     {
1604          $field = $field == 'cat_id' ? 'cat_id' : 'cat_url';
1605         
1606          $sub = array();
1607          $not = array();
1608          $queries = array();
1609         
1610          foreach ($arr as $v)
1611          {
1612               $v = trim($v);
1613               $args = preg_split('/\s*[?]\s*/',$v,-1,PREG_SPLIT_NO_EMPTY);
1614               $id = array_shift($args);
1615               $args = array_flip($args);
1616               
1617               if (isset($args['not'])) { $not[$id] = 1; }
1618               if (isset($args['sub'])) { $sub[$id] = 1; }
1619               if ($field == 'cat_id') {
1620                    if (preg_match('/^null$/i',$id)) {
1621                         $queries[$id] = 'P.cat_id IS NULL';
1622                    }
1623                    else {
1624                         $queries[$id] = 'P.cat_id = '.(integer) $id;
1625                    }
1626               } else {
1627                    $queries[$id] = "C.cat_url = '".$this->con->escape($id)."' ";
1628               }
1629          }
1630         
1631          if (!empty($sub)) {
1632               $rs = $this->con->select(
1633                    'SELECT cat_id, cat_url, cat_lft, cat_rgt FROM '.$this->prefix.'category '.
1634                    "WHERE blog_id = '".$this->con->escape($this->id)."' ".
1635                    'AND '.$field.' '.$this->con->in(array_keys($sub))
1636               );
1637               
1638               while ($rs->fetch()) {
1639                    $queries[$rs->f($field)] = '(C.cat_lft BETWEEN '.$rs->cat_lft.' AND '.$rs->cat_rgt.')';
1640               }
1641          }
1642         
1643          # Create queries
1644          $sql = array(
1645               0 => array(), # wanted categories
1646               1 => array()  # excluded categories
1647          );
1648         
1649          foreach ($queries as $id => $q) {
1650               $sql[(integer) isset($not[$id])][] = $q;
1651          }
1652         
1653          $sql[0] = implode(' OR ',$sql[0]);
1654          $sql[1] = implode(' OR ',$sql[1]);
1655         
1656          if ($sql[0]) {
1657               $sql[0] = '('.$sql[0].')';
1658          } else {
1659               unset($sql[0]);
1660          }
1661         
1662          if ($sql[1]) {
1663               $sql[1] = '(P.cat_id IS NULL OR NOT('.$sql[1].'))';
1664          } else {
1665               unset($sql[1]);
1666          }
1667         
1668          return implode(' AND ',$sql);
1669     }
1670     
1671     private function getPostCursor($cur,$post_id=null)
1672     {
1673          if ($cur->post_title == '') {
1674               throw new Exception(__('No entry title'));
1675          }
1676         
1677          if ($cur->post_content == '') {
1678               throw new Exception(__('No entry content'));
1679          }
1680         
1681          if ($cur->post_password === '') {
1682               $cur->post_password = null;
1683          }
1684         
1685          if ($cur->post_dt == '') {
1686               $offset = dt::getTimeOffset($this->core->auth->getInfo('user_tz'));
1687               $now = time() + $offset;
1688               $cur->post_dt = date('Y-m-d H:i:00',$now);
1689          }
1690         
1691          $post_id = is_int($post_id) ? $post_id : $cur->post_id;
1692         
1693          if ($cur->post_content_xhtml == '') {
1694               throw new Exception(__('No entry content'));
1695          }
1696         
1697          # Words list
1698          if ($cur->post_title !== null && $cur->post_excerpt_xhtml !== null
1699          && $cur->post_content_xhtml !== null)
1700          {
1701               $words =
1702               $cur->post_title.' '.
1703               $cur->post_excerpt_xhtml.' '.
1704               $cur->post_content_xhtml;
1705               
1706               $cur->post_words = implode(' ',text::splitWords($words));
1707          }
1708     }
1709     
1710     private function getPostContent($cur,$post_id)
1711     {
1712          $post_excerpt = $cur->post_excerpt;
1713          $post_excerpt_xhtml = $cur->post_excerpt_xhtml;
1714          $post_content = $cur->post_content;
1715          $post_content_xhtml = $cur->post_content_xhtml;
1716         
1717          $this->setPostContent(
1718               $post_id,$cur->post_format,$cur->post_lang,
1719               $post_excerpt,$post_excerpt_xhtml,
1720               $post_content,$post_content_xhtml
1721          );
1722         
1723          $cur->post_excerpt = $post_excerpt;
1724          $cur->post_excerpt_xhtml = $post_excerpt_xhtml;
1725          $cur->post_content = $post_content;
1726          $cur->post_content_xhtml = $post_content_xhtml;
1727     }
1728     
1729     /**
1730     Creates post HTML content, taking format and lang into account.
1731     
1732     @param         post_id        <b>integer</b>      Post ID
1733     @param         format         <b>string</b>       Post format
1734     @param         lang           <b>string</b>       Post lang
1735     @param         excerpt        <b>string</b>       Post excerpt
1736     @param[out]    excerpt_xhtml  <b>string</b>       Post excerpt HTML
1737     @param         content        <b>string</b>       Post content
1738     @param[out]    content_xhtml  <b>string</b>       Post content HTML
1739     */
1740     public function setPostContent($post_id,$format,$lang,&$excerpt,&$excerpt_xhtml,&$content,&$content_xhtml)
1741     {
1742          if ($format == 'wiki')
1743          {
1744               $this->core->initWikiPost();
1745               $this->core->wiki2xhtml->setOpt('note_prefix','pnote-'.$post_id);
1746               switch ($this->settings->system->note_title_tag) {
1747                    case 1:
1748                         $tag = 'h3';
1749                         break;
1750                    case 2:
1751                         $tag = 'p';
1752                         break;
1753                    default:
1754                         $tag = 'h4';
1755                         break;
1756               }
1757               $this->core->wiki2xhtml->setOpt('note_str','<div class="footnotes"><'.$tag.' class="footnotes-title">'.
1758                    __('Notes').'</'.$tag.'>%s</div>');
1759               $this->core->wiki2xhtml->setOpt('note_str_single','<div class="footnotes"><'.$tag.' class="footnotes-title">'.
1760                    __('Note').'</'.$tag.'>%s</div>');
1761               if (strpos($lang,'fr') === 0) {
1762                    $this->core->wiki2xhtml->setOpt('active_fr_syntax',1);
1763               }
1764          }
1765         
1766          if ($excerpt) {
1767               $excerpt_xhtml = $this->core->callFormater($format,$excerpt);
1768               $excerpt_xhtml = $this->core->HTMLfilter($excerpt_xhtml);
1769          } else {
1770               $excerpt_xhtml = '';
1771          }
1772         
1773          if ($content) {
1774               $content_xhtml = $this->core->callFormater($format,$content);
1775               $content_xhtml = $this->core->HTMLfilter($content_xhtml);
1776          } else {
1777               $content_xhtml = '';
1778          }
1779         
1780          # --BEHAVIOR-- coreAfterPostContentFormat
1781          $this->core->callBehavior('coreAfterPostContentFormat',array(
1782               'excerpt' => &$excerpt,
1783               'content' => &$content,
1784               'excerpt_xhtml' => &$excerpt_xhtml,
1785               'content_xhtml' => &$content_xhtml
1786          ));
1787     }
1788     
1789     /**
1790     Returns URL for a post according to blog setting <var>post_url_format</var>.
1791     It will try to guess URL and append some figures if needed.
1792     
1793     @param    url            <b>string</b>       Origin URL, could be empty
1794     @param    post_dt        <b>string</b>       Post date (in YYYY-MM-DD HH:mm:ss)
1795     @param    post_title     <b>string</b>       Post title
1796     @param    post_id        <b>integer</b>      Post ID
1797     @return   <b>string</b>  result URL
1798     */
1799     public function getPostURL($url,$post_dt,$post_title,$post_id)
1800     {
1801          $url = trim($url);
1802         
1803          $url_patterns = array(
1804          '{y}' => date('Y',strtotime($post_dt)),
1805          '{m}' => date('m',strtotime($post_dt)),
1806          '{d}' => date('d',strtotime($post_dt)),
1807          '{t}' => text::tidyURL($post_title),
1808          '{id}' => (integer) $post_id
1809          );
1810         
1811          # If URL is empty, we create a new one
1812          if ($url == '')
1813          {
1814               # Transform with format
1815               $url = str_replace(
1816                    array_keys($url_patterns),
1817                    array_values($url_patterns),
1818                    $this->settings->system->post_url_format
1819               );
1820          }
1821          else
1822          {
1823               $url = text::tidyURL($url);
1824          }
1825         
1826          # Let's check if URL is taken...
1827          $strReq = 'SELECT post_url FROM '.$this->prefix.'post '.
1828                    "WHERE post_url = '".$this->con->escape($url)."' ".
1829                    'AND post_id <> '.(integer) $post_id. ' '.
1830                    "AND blog_id = '".$this->con->escape($this->id)."' ".
1831                    'ORDER BY post_url DESC';
1832         
1833          $rs = $this->con->select($strReq);
1834         
1835          if (!$rs->isEmpty())
1836          {
1837               if ($this->con->driver() == 'mysql') {
1838                    $clause = "REGEXP '^".$this->con->escape($url)."[0-9]+$'";
1839               } elseif ($this->con->driver() == 'pgsql') {
1840                    $clause = "~ '^".$this->con->escape($url)."[0-9]+$'";
1841               } else {
1842                    $clause = "LIKE '".$this->con->escape($url)."%'";
1843               }
1844               $strReq = 'SELECT post_url FROM '.$this->prefix.'post '.
1845                         "WHERE post_url ".$clause.' '.
1846                         'AND post_id <> '.(integer) $post_id.' '.
1847                         "AND blog_id = '".$this->con->escape($this->id)."' ".
1848                         'ORDER BY post_url DESC ';
1849               
1850               $rs = $this->con->select($strReq);
1851               $a = array();
1852               while ($rs->fetch()) {
1853                    $a[] = $rs->post_url;
1854               }
1855               
1856               natsort($a);
1857               $t_url = end($a);
1858               
1859               if (preg_match('/(.*?)([0-9]+)$/',$t_url,$m)) {
1860                    $i = (integer) $m[2];
1861                    $url = $m[1];
1862               } else {
1863                    $i = 1;
1864               }
1865               
1866               return $url.($i+1);
1867          }
1868         
1869          # URL is empty?
1870          if ($url == '') {
1871               throw new Exception(__('Empty entry URL'));
1872          }
1873         
1874          return $url;
1875     }
1876     //@}
1877     
1878     /// @name Comments management methods
1879     //@{
1880     /**
1881     Retrieves comments. <b>$params</b> is an array taking the following
1882     optionnal parameters:
1883     
1884     - no_content: Don't retrieve comment content
1885     - post_type: Get only entries with given type (default no type, array for many types)
1886     - post_id: (integer) Get comments belonging to given post_id
1887     - cat_id: (integer or array) Get comments belonging to entries of given category ID
1888     - comment_id: (integer) Get comment with given ID
1889     - comment_status: (integer) Get comments with given comment_status
1890     - comment_trackback: (integer) Get only comments (0) or trackbacks (1)
1891     - comment_ip: (string) Get comments with given IP address
1892     - post_url: Get entry with given post_url field
1893     - user_id: (integer) Get entries belonging to given user ID
1894     - q_author: Search comments by author
1895     - sql: Append SQL string at the end of the query
1896     - from: Append SQL string after "FROM" statement in query
1897     - order: Order of results (default "ORDER BY comment_dt DES")
1898     - limit: Limit parameter
1899     - sql_only : return the sql request instead of results. Only ids are selected
1900     
1901     @param    params         <b>array</b>        Parameters
1902     @param    count_only     <b>boolean</b>      Only counts results
1903     @return   <b>record</b>  A record with some more capabilities
1904     */
1905     public function getComments($params=array(),$count_only=false)
1906     {
1907          if ($count_only)
1908          {
1909               $strReq = 'SELECT count(comment_id) ';
1910          }
1911          elseif (!empty($params['sql_only'])) 
1912          {
1913               $strReq = 'SELECT P.post_id ';
1914          }
1915          else
1916          {
1917               if (!empty($params['no_content'])) {
1918                    $content_req = '';
1919               } else {
1920                    $content_req = 'comment_content, ';
1921               }
1922               
1923               if (!empty($params['columns']) && is_array($params['columns'])) {
1924                    $content_req .= implode(', ',$params['columns']).', ';
1925               }
1926               
1927               $strReq =
1928               'SELECT C.comment_id, comment_dt, comment_tz, comment_upddt, '.
1929               'comment_author, comment_email, comment_site, '.
1930               $content_req.' comment_trackback, comment_status, '.
1931               'comment_spam_status, comment_spam_filter, comment_ip, '.
1932               'P.post_title, P.post_url, P.post_id, P.post_password, P.post_type, '.
1933               'P.post_dt, P.user_id, U.user_email, U.user_url ';
1934          }
1935         
1936          $strReq .=
1937          'FROM '.$this->prefix.'comment C '.
1938          'INNER JOIN '.$this->prefix.'post P ON C.post_id = P.post_id '.
1939          'INNER JOIN '.$this->prefix.'user U ON P.user_id = U.user_id ';
1940         
1941          if (!empty($params['from'])) {
1942               $strReq .= $params['from'].' ';
1943          }
1944         
1945          $strReq .=
1946          "WHERE P.blog_id = '".$this->con->escape($this->id)."' ";
1947         
1948          if (!$this->core->auth->check('contentadmin',$this->id)) {
1949               $strReq .= 'AND ((comment_status = 1 AND P.post_status = 1 ';
1950               
1951               if ($this->without_password) {
1952                    $strReq .= 'AND post_password IS NULL ';
1953               }
1954               $strReq .= ') ';
1955               
1956               if ($this->core->auth->userID()) {
1957                    $strReq .= "OR P.user_id = '".$this->con->escape($this->core->auth->userID())."')";
1958               } else {
1959                    $strReq .= ') ';
1960               }
1961          }
1962         
1963          if (!empty($params['post_type']))
1964          {
1965               $strReq .= 'AND post_type '.$this->con->in($params['post_type']);
1966          }
1967         
1968          if (isset($params['post_id']) && $params['post_id'] !== '') {
1969               $strReq .= 'AND P.post_id = '.(integer) $params['post_id'].' ';
1970          }
1971         
1972          if (isset($params['cat_id']) && $params['cat_id'] !== '') {
1973               $strReq .= 'AND P.cat_id = '.(integer) $params['cat_id'].' ';
1974          }
1975         
1976          if (isset($params['comment_id']) && $params['comment_id'] !== '') {
1977               $strReq .= 'AND comment_id = '.(integer) $params['comment_id'].' ';
1978          }
1979         
1980          if (isset($params['comment_status'])) {
1981               $strReq .= 'AND comment_status = '.(integer) $params['comment_status'].' ';
1982          }
1983         
1984          if (!empty($params['comment_status_not']))
1985          {
1986               $strReq .= 'AND comment_status <> '.(integer) $params['comment_status_not'].' ';
1987          }
1988         
1989          if (isset($params['comment_trackback'])) {
1990               $strReq .= 'AND comment_trackback = '.(integer) (boolean) $params['comment_trackback'].' ';
1991          }
1992         
1993          if (isset($params['comment_ip'])) {
1994               $comment_ip = $this->con->escape(str_replace('*','%',$params['comment_ip']));
1995               $strReq .= "AND comment_ip LIKE '".$comment_ip."' ";
1996          }
1997         
1998          if (isset($params['q_author'])) {
1999               $q_author = $this->con->escape(str_replace('*','%',strtolower($params['q_author'])));
2000               $strReq .= "AND LOWER(comment_author) LIKE '".$q_author."' ";
2001          }
2002         
2003          if (!empty($params['search']))
2004          {
2005               $words = text::splitWords($params['search']);
2006               
2007               if (!empty($words))
2008               {
2009                    # --BEHAVIOR coreCommentSearch
2010                    if ($this->core->hasBehavior('coreCommentSearch')) {
2011                         $this->core->callBehavior('coreCommentSearch',$this->core,array(&$words,&$strReq,&$params));
2012                    }
2013                   
2014                    if ($words)
2015                    {
2016                         foreach ($words as $i => $w) {
2017                              $words[$i] = "comment_words LIKE '%".$this->con->escape($w)."%'";
2018                         }
2019                         $strReq .= 'AND '.implode(' AND ',$words).' ';
2020                    }
2021               }
2022          }
2023         
2024          if (!empty($params['sql'])) {
2025               $strReq .= $params['sql'].' ';
2026          }
2027         
2028          if (!$count_only)
2029          {
2030               if (!empty($params['order'])) {
2031                    $strReq .= 'ORDER BY '.$this->con->escape($params['order']).' ';
2032               } else {
2033                    $strReq .= 'ORDER BY comment_dt DESC ';
2034               }
2035          }
2036         
2037          if (!$count_only && !empty($params['limit'])) {
2038               $strReq .= $this->con->limit($params['limit']);
2039          }
2040
2041          if (!empty($params['sql_only'])) {
2042               return $strReq;
2043          }
2044         
2045          $rs = $this->con->select($strReq);
2046          $rs->core = $this->core;
2047          $rs->extend('rsExtComment');
2048         
2049          # --BEHAVIOR-- coreBlogGetComments
2050          $this->core->callBehavior('coreBlogGetComments',$rs);
2051         
2052          return $rs;
2053     }
2054     
2055     /**
2056     Creates a new comment. Takes a cursor as input and returns the new comment
2057     ID.
2058     
2059     @param    cur       <b>cursor</b>       Comment cursor
2060     @return   <b>integer</b>      New comment ID
2061     */
2062     public function addComment($cur)
2063     {
2064          $this->con->writeLock($this->prefix.'comment');
2065          try
2066          {
2067               # Get ID
2068               $rs = $this->con->select(
2069                    'SELECT MAX(comment_id) '.
2070                    'FROM '.$this->prefix.'comment ' 
2071               );
2072               
2073               $cur->comment_id = (integer) $rs->f(0) + 1;
2074               $cur->comment_upddt = date('Y-m-d H:i:s');
2075               
2076               $offset = dt::getTimeOffset($this->settings->system->blog_timezone);
2077               $cur->comment_dt = date('Y-m-d H:i:s',time() + $offset);
2078               $cur->comment_tz = $this->settings->system->blog_timezone;
2079               
2080               $this->getCommentCursor($cur);
2081               
2082               if ($cur->comment_ip === null) {
2083                    $cur->comment_ip = http::realIP();
2084               }
2085               
2086               # --BEHAVIOR-- coreBeforeCommentCreate
2087               $this->core->callBehavior('coreBeforeCommentCreate',$this,$cur);
2088               
2089               $cur->insert();
2090               $this->con->unlock();
2091          }
2092          catch (Exception $e)
2093          {
2094               $this->con->unlock();
2095               throw $e;
2096          }
2097         
2098          # --BEHAVIOR-- coreAfterCommentCreate
2099          $this->core->callBehavior('coreAfterCommentCreate',$this,$cur);
2100         
2101          $this->triggerComment($cur->comment_id);
2102          if ($cur->comment_status != -2) {
2103               $this->triggerBlog();
2104          }   
2105          return $cur->comment_id;
2106     }
2107     
2108     /**
2109     Updates an existing comment.
2110     
2111     @param    id        <b>integer</b>      Comment ID
2112     @param    cur       <b>cursor</b>       Comment cursor
2113     */
2114     public function updComment($id,$cur)
2115     {
2116          if (!$this->core->auth->check('usage,contentadmin',$this->id)) {
2117               throw new Exception(__('You are not allowed to update comments'));
2118          }
2119         
2120          $id = (integer) $id;
2121         
2122          if (empty($id)) {
2123               throw new Exception(__('No such comment ID'));
2124          }
2125         
2126          $rs = $this->getComments(array('comment_id' => $id));
2127         
2128          if ($rs->isEmpty()) {
2129               throw new Exception(__('No such comment ID'));
2130          }
2131         
2132          #If user is only usage, we need to check the post's owner
2133          if (!$this->core->auth->check('contentadmin',$this->id))
2134          {
2135               if ($rs->user_id != $this->core->auth->userID()) {
2136                    throw new Exception(__('You are not allowed to update this comment'));
2137               }
2138          }
2139         
2140          $this->getCommentCursor($cur);
2141         
2142          $cur->comment_upddt = date('Y-m-d H:i:s');
2143         
2144          if (!$this->core->auth->check('publish,contentadmin',$this->id)) {
2145               $cur->unsetField('comment_status');
2146          }
2147         
2148          # --BEHAVIOR-- coreBeforeCommentUpdate
2149          $this->core->callBehavior('coreBeforeCommentUpdate',$this,$cur,$rs);
2150         
2151          $cur->update('WHERE comment_id = '.$id.' ');
2152         
2153          # --BEHAVIOR-- coreAfterCommentUpdate
2154          $this->core->callBehavior('coreAfterCommentUpdate',$this,$cur,$rs);
2155         
2156          $this->triggerComment($id);
2157          $this->triggerBlog();
2158     }
2159     
2160     /**
2161     Updates comment status.
2162     
2163     @param    id        <b>integer</b>      Comment ID
2164     @param    status    <b>integer</b>      Comment status
2165     */
2166     public function updCommentStatus($id,$status)
2167     {
2168          $this->updCommentsStatus($id,$status);
2169     }
2170     
2171     /**
2172     Updates comments status.
2173     
2174     @param    ids       <b>mixed</b>        Comment(s) ID(s)
2175     @param    status    <b>integer</b>      Comment status
2176     */
2177     public function updCommentsStatus($ids,$status)
2178     {
2179          if (!$this->core->auth->check('publish,contentadmin',$this->id)) {
2180               throw new Exception(__("You are not allowed to change this comment's status"));
2181          }
2182         
2183          $co_ids = dcUtils::cleanIds($ids);
2184          $status = (integer) $status;
2185         
2186          $strReq = 
2187               'UPDATE '.$this->prefix.'comment tc ';
2188         
2189          # mySQL uses "JOIN" synthax
2190          if ($this->con->driver() == 'mysql') {
2191               $strReq .= 
2192                    'JOIN '.$this->prefix.'post tp ON tc.post_id = tp.post_id ';
2193          }
2194         
2195          $strReq .= 
2196               'SET comment_status = '.$status.' ';
2197         
2198          # pgSQL uses "FROM" synthax
2199          if ($this->con->driver() != 'mysql') {
2200               $strReq .= 
2201                    'FROM '.$this->prefix.'post tp ';
2202          }
2203         
2204          $strReq .=
2205               "WHERE blog_id = '".$this->con->escape($this->id)."' ".
2206               'AND comment_id'.$this->con->in($co_ids);
2207         
2208          # add pgSQL "WHERE" clause
2209          if ($this->con->driver() != 'mysql') {
2210               $strReq .= 
2211                    'AND tc.post_id = tp.post_id ';
2212          }
2213         
2214          #If user is only usage, we need to check the post's owner
2215          if (!$this->core->auth->check('contentadmin',$this->id))
2216          {
2217               $strReq .= 
2218                    "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
2219          }
2220         
2221          $this->con->execute($strReq);
2222          $this->triggerComments($co_ids);
2223          $this->triggerBlog();
2224     }
2225     
2226     /**
2227     Delete a comment
2228     
2229     @param    id        <b>integer</b>      Comment ID
2230     */
2231     public function delComment($id)
2232     {
2233          $this->delComments($id);
2234     }
2235     
2236     /**
2237     Delete comments
2238     
2239     @param    ids       <b>mixed</b>        Comment(s) ID(s)
2240     */
2241     public function delComments($ids)
2242     {
2243          if (!$this->core->auth->check('delete,contentadmin',$this->id)) {
2244               throw new Exception(__('You are not allowed to delete comments'));
2245          }
2246         
2247          $co_ids = dcUtils::cleanIds($ids);
2248         
2249          if (empty($co_ids)) {
2250               throw new Exception(__('No such comment ID'));
2251          }
2252         
2253          # Retrieve posts affected by comments edition
2254          $affected_posts = array();
2255          $strReq =
2256               'SELECT distinct(post_id) '.
2257               'FROM '.$this->prefix.'comment '.
2258               'WHERE comment_id'.$this->con->in($co_ids);
2259         
2260          $rs = $this->con->select($strReq);
2261         
2262          while ($rs->fetch()) {
2263               $affected_posts[] = (integer) $rs->post_id;
2264          }
2265         
2266          # mySQL uses "INNER JOIN" synthax
2267          if ($this->con->driver() == 'mysql') {
2268               $strReq = 
2269                    'DELETE FROM tc '.
2270                    'USING '.$this->prefix.'comment tc '.
2271                    'INNER JOIN '.$this->prefix.'post tp ';
2272          }
2273          # pgSQL uses nothing special
2274          else {
2275               $strReq = 
2276                    'DELETE FROM '.$this->prefix.'comment tc '.
2277                    'USING '.$this->prefix.'post tp ';
2278          }
2279         
2280          $strReq .= 
2281               'WHERE tc.post_id = tp.post_id '.
2282               "AND tp.blog_id = '".$this->con->escape($this->id)."' ".
2283               'AND comment_id'.$this->con->in($co_ids);
2284         
2285          #If user can only delete, we need to check the post's owner
2286          if (!$this->core->auth->check('contentadmin',$this->id))
2287          {
2288               $strReq .= 
2289                    "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
2290          }
2291         
2292          $this->con->execute($strReq);
2293          $this->triggerComments($co_ids, true, $affected_posts);
2294          $this->triggerBlog();
2295     }
2296
2297     public function delJunkComments()
2298     {
2299          if (!$this->core->auth->check('delete,contentadmin',$this->id)) {
2300               throw new Exception(__('You are not allowed to delete comments'));
2301          }
2302         
2303          # mySQL uses "INNER JOIN" synthax
2304          if ($this->con->driver() == 'mysql') {
2305               $strReq = 
2306                    'DELETE FROM tc '.
2307                    'USING '.$this->prefix.'comment tc '.
2308                    'INNER JOIN '.$this->prefix.'post tp ';
2309          }
2310          # pgSQL uses nothing special
2311          else {
2312               $strReq = 
2313                    'DELETE FROM '.$this->prefix.'comment tc '.
2314                    'USING '.$this->prefix.'post tp ';
2315          }
2316         
2317          $strReq .= 
2318               'WHERE tc.post_id = tp.post_id '.
2319               "AND tp.blog_id = '".$this->con->escape($this->id)."' ".
2320               'AND comment_status = -2';
2321         
2322          #If user can only delete, we need to check the post's owner
2323          if (!$this->core->auth->check('contentadmin',$this->id))
2324          {
2325               $strReq .= 
2326                    "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
2327          }
2328         
2329          $this->con->execute($strReq);
2330          $this->triggerBlog();
2331     }
2332     
2333     private function getCommentCursor($cur)
2334     {
2335          if ($cur->comment_content !== null && $cur->comment_content == '') {
2336               throw new Exception(__('You must provide a comment'));
2337          }
2338         
2339          if ($cur->comment_author !== null && $cur->comment_author == '') {
2340               throw new Exception(__('You must provide an author name'));
2341          }
2342         
2343          if ($cur->comment_email != '' && !text::isEmail($cur->comment_email)) {
2344               throw new Exception(__('Email address is not valid.'));
2345          }
2346         
2347          if ($cur->comment_site !== null && $cur->comment_site != '') {
2348               if (!preg_match('|^http(s?)://|i',$cur->comment_site, $matches)) {
2349                    $cur->comment_site = 'http://'.$cur->comment_site;
2350               }else{
2351                    $cur->comment_site = strtolower($matches[0]).substr($cur->comment_site, strlen($matches[0]));
2352               }
2353          }
2354         
2355          if ($cur->comment_status === null) {
2356               $cur->comment_status = (integer) $this->settings->system->comments_pub;
2357          }
2358         
2359          # Words list
2360          if ($cur->comment_content !== null)
2361          {
2362               $cur->comment_words = implode(' ',text::splitWords($cur->comment_content));
2363          }
2364     }
2365     //@}
2366}
2367?>
Note: See TracBrowser for help on using the repository browser.

Sites map