Dotclear

source: inc/core/class.dc.meta.php @ 0:54703be25dd6

Revision 0:54703be25dd6, 15.9 KB checked in by Dsls <dsls@…>, 14 years ago (diff)

2.3 branch (trunk) first checkin

Line 
1<?php
2# -- BEGIN LICENSE BLOCK ---------------------------------------
3#
4# This file is part of Dotclear 2.
5#
6# Copyright (c) 2003-2010 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 metadata class.
18
19Dotclear metadata class instance is provided by dcCore $meta property.
20*/
21class dcMeta
22{
23     private $core; ///< <b>dcCore</b> dcCore instance
24     private $con;  ///< <b>connection</b>   Database connection object
25     private $table;     ///< <b>string</b> Media table name
26     
27     /**
28     Object constructor.
29     
30     @param    core      <b>dcCore</b>       dcCore instance
31     */
32     public function __construct($core)
33     {
34          $this->core =& $core;
35          $this->con =& $this->core->con;
36          $this->table = $this->core->prefix.'meta';
37     }
38     
39     /**
40     Splits up comma-separated values into an array of
41     unique, URL-proof metadata values.
42     
43     @param    str       <b>string</b>       Comma-separated metadata.
44     
45     @return   <b>Array</b>   The array of sanitized metadata
46     */
47     public function splitMetaValues($str)
48     {
49          $res = array();
50          foreach (explode(',',$str) as $i => $tag)
51          {
52               $tag = trim($tag);
53               $tag = self::sanitizeMetaID($tag);
54               
55               if ($tag != false) {
56                    $res[$i] = $tag;
57               }
58          }
59         
60          return array_unique($res);
61     }
62     
63     /**
64     Make a metadata ID URL-proof.
65     
66     @param    str       <b>string</b>  the metadata ID.
67     
68     @return   <b>string</b>  The sanitized metadata
69     */
70     public static function sanitizeMetaID($str)
71     {
72          return text::tidyURL($str,false,true);
73     }
74     
75     /**
76     Converts serialized metadata (for instance in dc_post post_meta)
77     into a meta array.
78     
79     @param    str       <b>string</b>  the serialized metadata.
80     
81     @return   <b>Array</b>   the resulting array of post meta
82     */
83     public function getMetaArray($str)
84     {
85          $meta = @unserialize($str);
86         
87          if (!is_array($meta)) {
88               return array();
89          }
90         
91          return $meta;
92     }
93     
94     /**
95     Converts serialized metadata (for instance in dc_post post_meta)
96     into a comma-separated meta list for a given type.
97     
98     @param    str       <b>string</b>  the serialized metadata.
99     @param    type <b>string</b>  meta type to retrieve metaIDs from.
100     
101     @return   <b>string</b>  the comma-separated list of meta
102     */
103     public function getMetaStr($str,$type)
104     {
105          $meta = $this->getMetaArray($str);
106         
107          if (!isset($meta[$type])) {
108               return '';
109          }
110         
111          return implode(', ',$meta[$type]);
112     }
113     
114     /**
115     Converts serialized metadata (for instance in dc_post post_meta)
116     into a "fetchable" metadata record.
117     
118     @param    str       <b>string</b>  the serialized metadata.
119     @param    type <b>string</b>  meta type to retrieve metaIDs from.
120     
121     @return   <b>record</b>  the meta recordset
122     */
123     public function getMetaRecordset($str,$type)
124     {
125          $meta = $this->getMetaArray($str);
126          $data = array();
127         
128          if (isset($meta[$type]))
129          {
130               foreach ($meta[$type] as $v)
131               {
132                    $data[] = array(
133                         'meta_id' => $v,
134                         'meta_type' => $type,
135                         'meta_id_lower' => mb_strtolower($v),
136                         'count' => 0,
137                         'percent' => 0,
138                         'roundpercent' => 0
139                    );
140               }
141          }
142         
143          return staticRecord::newFromArray($data);
144     }
145     
146     /**
147     @deprecated since version 2.2 : $core->meta is always defined
148     @see getMetaRecordset
149     static version of getMetaRecordset
150     */
151     public static function getMetaRecord($core,$str,$type)
152     {
153          $meta = new self($core);
154          return $meta->getMetaRecordset($str,$type);
155     }
156     
157     /**
158     Checks whether the current user is allowed to change post meta
159     An exception is thrown if user is not allowed.
160     
161     @param    post_id   <b>string</b>  the post_id to check.
162     */
163     private function checkPermissionsOnPost($post_id)
164     {
165          $post_id = (integer) $post_id;
166         
167          if (!$this->core->auth->check('usage,contentadmin',$this->core->blog->id)) {
168               throw new Exception(__('You are not allowed to change this entry status'));
169          }
170         
171          #�If user can only publish, we need to check the post's owner
172          if (!$this->core->auth->check('contentadmin',$this->core->blog->id))
173          {
174               $strReq = 'SELECT post_id '.
175                         'FROM '.$this->core->prefix.'post '.
176                         'WHERE post_id = '.$post_id.' '.
177                         "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
178               
179               $rs = $this->con->select($strReq);
180               
181               if ($rs->isEmpty()) {
182                    throw new Exception(__('You are not allowed to change this entry status'));
183               }
184          }
185     }
186     
187     /**
188     Updates serialized post_meta information with dc_meta table information.
189     
190     @param    post_id   <b>string</b>  the post_id to update.
191     */
192     private function updatePostMeta($post_id)
193     {
194          $post_id = (integer) $post_id;
195         
196          $strReq = 'SELECT meta_id, meta_type '.
197                    'FROM '.$this->table.' '.
198                    'WHERE post_id = '.$post_id.' ';
199         
200          $rs = $this->con->select($strReq);
201         
202          $meta = array();
203          while ($rs->fetch()) {
204               $meta[$rs->meta_type][] = $rs->meta_id;
205          }
206         
207          $post_meta = serialize($meta);
208         
209          $cur = $this->con->openCursor($this->core->prefix.'post');
210          $cur->post_meta = $post_meta;
211         
212          $cur->update('WHERE post_id = '.$post_id);
213          $this->core->blog->triggerBlog();
214     }
215     
216     /**
217     Retrieves posts corresponding to given meta criteria.
218     <b>$params</b> is an array taking the following optional parameters:
219     - meta_id : get posts having meta id
220     - meta_type : get posts having meta type
221     
222     @param    params    <b>array</b>   Parameters
223     @param    count_only     <b>boolean</b>      Only counts results
224     
225     @return   <b>record</b>  the resulting posts record
226     */
227     public function getPostsByMeta($params=array(),$count_only=false)
228     {
229          if (!isset($params['meta_id'])) {
230               return null;
231          }
232         
233          $params['from'] = ', '.$this->table.' META ';
234          $params['sql'] = 'AND META.post_id = P.post_id ';
235         
236          $params['sql'] .= "AND META.meta_id = '".$this->con->escape($params['meta_id'])."' ";
237         
238          if (!empty($params['meta_type'])) {
239               $params['sql'] .= "AND META.meta_type = '".$this->con->escape($params['meta_type'])."' ";
240               unset($params['meta_type']);
241          }
242         
243          unset($params['meta_id']);
244         
245          return $this->core->blog->getPosts($params,$count_only);
246     }
247     
248     /**
249     Retrieves comments to posts corresponding to given meta criteria.
250     <b>$params</b> is an array taking the following optional parameters:
251     - meta_id : get comments to posts having meta id
252     - meta_type : get comments to posts having meta type
253     
254     @param    params    <b>array</b>   Parameters
255     @param    count_only     <b>boolean</b>      Only counts results
256     
257     @return   <b>record</b>  the resulting comments record
258     */
259     public function getCommentsByMeta($params=array(),$count_only=false)
260     {
261          if (!isset($params['meta_id'])) {
262               return null;
263          }
264         
265          $params['from'] = ', '.$this->table.' META ';
266          $params['sql'] = 'AND META.post_id = P.post_id ';
267          $params['sql'] .= "AND META.meta_id = '".$this->con->escape($params['meta_id'])."' ";
268         
269          if (!empty($params['meta_type'])) {
270               $params['sql'] .= "AND META.meta_type = '".$this->con->escape($params['meta_type'])."' ";
271               unset($params['meta_type']);
272          }
273         
274          return $this->core->blog->getComments($params,$count_only);
275     }
276     
277     /**
278     @deprecated since 2.2. Use getMetadata and computeMetaStats instead.
279     Generic-purpose metadata retrieval : gets metadatas according to given
280     criteria. Metadata get enriched with stastistics columns (only relevant
281     if limit parameter is not set). Metadata are sorted by post count
282     descending
283     
284     @param    type <b>string</b>  if not null, get metas having the given type
285     @param    limit     <b>string</b>  if not null, number of max fetched metas
286     @param    meta_id   <b>string</b>  if not null, get metas having the given id
287     @param    post_id   <b>string</b>  if not null, get metas for the given post id
288     
289     @return   <b>record</b>  the meta recordset
290     */
291     public function getMeta($type=null,$limit=null,$meta_id=null,$post_id=null) {
292          $params = array();
293         
294          if ($type != null)
295               $params['meta_type'] = $type;
296          if ($limit != null)
297               $params['limit'] = $limit;
298          if ($meta_id != null)
299               $params['meta_id'] = $meta_id;
300          if ($meta_id != null)
301               $params['post_id'] = $post_id;
302          $rs = $this->getMetadata($params, false);
303          return $this->computeMetaStats($rs);
304     }
305     
306     /**
307     Generic-purpose metadata retrieval : gets metadatas according to given
308     criteria. <b>$params</b> is an array taking the following
309     optionnal parameters:
310     
311     - type: get metas having the given type
312     - meta_id: if not null, get metas having the given id
313     - post_id: get metas for the given post id
314     - limit: number of max fetched metas
315     - order: results order (default : posts count DESC)
316     
317     @param    params         <b>array</b>        Parameters
318     @param    count_only     <b>boolean</b>      Only counts results
319     
320     @return   <b>record</b>  the resulting comments record
321     */
322     public function getMetadata($params=array(), $count_only=false)
323     {
324          if ($count_only) {
325               $strReq = 'SELECT count(distinct M.meta_id) ';
326          } else {
327               $strReq = 'SELECT M.meta_id, M.meta_type, COUNT(M.post_id) as count ';
328          }
329         
330          $strReq .=
331          'FROM '.$this->table.' M LEFT JOIN '.$this->core->prefix.'post P '.
332          'ON M.post_id = P.post_id '.
333          "WHERE P.blog_id = '".$this->con->escape($this->core->blog->id)."' ";
334         
335          if (isset($params['meta_type'])) {
336               $strReq .= " AND meta_type = '".$this->con->escape($params['meta_type'])."' ";
337          }
338         
339          if (isset($params['meta_id'])) {
340               $strReq .= " AND meta_id = '".$this->con->escape($params['meta_id'])."' ";
341          }
342         
343          if (isset($params['post_id'])) {
344               $strReq .= ' AND P.post_id '.$this->con->in($params['post_id']).' ';
345          }
346         
347          if (!$this->core->auth->check('contentadmin',$this->core->blog->id)) {
348               $strReq .= 'AND ((post_status = 1 ';
349               
350               if ($this->core->blog->without_password) {
351                    $strReq .= 'AND post_password IS NULL ';
352               }
353               $strReq .= ') ';
354               
355               if ($this->core->auth->userID()) {
356                    $strReq .= "OR P.user_id = '".$this->con->escape($this->core->auth->userID())."')";
357               } else {
358                    $strReq .= ') ';
359               }
360          }
361         
362          if (!$count_only) {
363               if (!isset($params['order'])) {
364                    $params['order'] = 'count DESC';
365               }
366               
367               $strReq .=
368               'GROUP BY meta_id,meta_type,P.blog_id '.
369               'ORDER BY '.$params['order'];
370               
371               if (isset($params['limit'])) {
372                    $strReq .= $this->con->limit($params['limit']);
373               }
374          }
375         
376          $rs = $this->con->select($strReq);
377          return $rs;
378     }
379     
380     /**
381     Computes statistics from a metadata recordset.
382     Each record gets enriched with lowercase name, percent and roundpercent columns
383     
384     @param    rs   <b>record</b>  recordset to enrich
385     
386     @return   <b>record</b>  the enriched recordset
387     */
388     public function computeMetaStats($rs) {
389          $rs_static = $rs->toStatic();
390         
391          $max = array();
392          while ($rs_static->fetch())
393          {
394               $type = $rs_static->meta_type;
395               if (!isset($max[$type])) {
396                    $max[$type] = $rs_static->count;
397               } else {
398                    if ($rs_static->count > $max[$type]) {
399                         $max[$type] = $rs_static->count;
400                    }
401               }
402          }
403         
404          while ($rs_static->fetch())
405          {
406               $rs_static->set('meta_id_lower',mb_strtolower($rs_static->meta_id));
407               
408               $count = $rs_static->count;
409               $percent = ((integer) $rs_static->count) * 100 / $max[$rs_static->meta_type];
410               
411               $rs_static->set('percent',(integer) round($percent));
412               $rs_static->set('roundpercent',round($percent/10)*10);
413          }
414         
415          return $rs_static;
416     }
417     
418     /**
419     Adds a metadata to a post.
420     
421     @param    post_id   <b>integer</b> the post id
422     @param    type <b>string</b>  meta type
423     @param    value     <b>integer</b> meta value
424     */
425     public function setPostMeta($post_id,$type,$value)
426     {
427          $this->checkPermissionsOnPost($post_id);
428         
429          $value = trim($value);
430          if ($value === false) { return; }
431         
432          $cur = $this->con->openCursor($this->table);
433         
434          $cur->post_id = (integer) $post_id;
435          $cur->meta_id = (string) $value;
436          $cur->meta_type = (string) $type;
437         
438          $cur->insert();
439          $this->updatePostMeta((integer) $post_id);
440     }
441     
442     /**
443     Removes metadata from a post.
444     
445     @param    post_id   <b>integer</b> the post id
446     @param    type <b>string</b>  meta type (if null, delete all types)
447     @param    value     <b>integer</b> meta value (if null, delete all values)
448     */
449     public function delPostMeta($post_id,$type=null,$meta_id=null)
450     {
451          $post_id = (integer) $post_id;
452         
453          $this->checkPermissionsOnPost($post_id);
454         
455          $strReq = 'DELETE FROM '.$this->table.' '.
456                    'WHERE post_id = '.$post_id;
457         
458          if ($type !== null) {
459               $strReq .= " AND meta_type = '".$this->con->escape($type)."' ";
460          }
461         
462          if ($meta_id !== null) {
463               $strReq .= " AND meta_id = '".$this->con->escape($meta_id)."' ";
464          }
465         
466          $this->con->execute($strReq);
467          $this->updatePostMeta((integer) $post_id);
468     }
469     
470     /**
471     Mass updates metadata for a given post_type.
472     
473     @param    meta_id        <b>integer</b> old value
474     @param    new_meta  <b>integer</b> new value
475     @param    type <b>string</b>  meta type (if null, select all types)
476     @param    post_type <b>integer</b> impacted post_type (if null, select all types)
477     @return   <b>boolean</b> true if at least 1 post has been impacted
478     */
479     public function updateMeta($meta_id,$new_meta_id,$type=null,$post_type=null)
480     {
481          $new_meta_id = self::sanitizeMetaID($new_meta_id);
482         
483          if ($new_meta_id == $meta_id) {
484               return true;
485          }
486         
487          $getReq = 'SELECT M.post_id '.
488                    'FROM '.$this->table.' M, '.$this->core->prefix.'post P '.
489                    'WHERE P.post_id = M.post_id '.
490                    "AND P.blog_id = '".$this->con->escape($this->core->blog->id)."' ".
491                    "AND meta_id = '%s' ";
492         
493          if (!$this->core->auth->check('contentadmin',$this->core->blog->id)) {
494               $getReq .= "AND P.user_id = '".$this->con->escape($this->core->auth->userID())."' ";
495          }
496          if ($post_type !== null) {
497               $getReq .= "AND P.post_type = '".$this->con->escape($post_type)."' ";
498          }
499         
500          $delReq = 'DELETE FROM '.$this->table.' '.
501                    'WHERE post_id IN (%s) '.
502                    "AND meta_id = '%s' ";
503         
504          $updReq = 'UPDATE '.$this->table.' '.
505                    "SET meta_id = '%s' ".
506                    'WHERE post_id IN (%s) '.
507                    "AND meta_id = '%s' ";
508         
509          if ($type !== null) {
510               $plus = " AND meta_type = '%s' ";
511               $getReq .= $plus;
512               $delReq .= $plus;
513               $updReq .= $plus;
514          }
515         
516          $to_update = $to_remove = array();
517         
518          $rs = $this->con->select(sprintf($getReq,$this->con->escape($meta_id),
519                                   $this->con->escape($type)));
520         
521          while ($rs->fetch()) {
522               $to_update[] = $rs->post_id;
523          }
524         
525          if (empty($to_update)) {
526               return false;
527          }
528         
529          $rs = $this->con->select(sprintf($getReq,$new_meta_id,$type));
530          while ($rs->fetch()) {
531               if (in_array($rs->post_id,$to_update)) {
532                    $to_remove[] = $rs->post_id;
533                    unset($to_update[array_search($rs->post_id,$to_update)]);
534               }
535          }
536         
537          # Delete duplicate meta
538          if (!empty($to_remove))
539          {
540               $this->con->execute(sprintf($delReq,implode(',',$to_remove),
541                                   $this->con->escape($meta_id),
542                                   $this->con->escape($type)));
543               
544               foreach ($to_remove as $post_id) {
545                    $this->updatePostMeta($post_id);
546               }
547          }
548         
549          # Update meta
550          if (!empty($to_update))
551          {
552               $this->con->execute(sprintf($updReq,$this->con->escape($new_meta_id),
553                                   implode(',',$to_update),
554                                   $this->con->escape($meta_id),
555                                   $this->con->escape($type)));
556               
557               foreach ($to_update as $post_id) {
558                    $this->updatePostMeta($post_id);
559               }
560          }
561         
562          return true;
563     }
564     
565     /**
566     Mass delete metadata for a given post_type.
567     
568     @param    meta_id        <b>integer</b> meta value
569     @param    type <b>string</b>  meta type (if null, select all types)
570     @param    post_type <b>integer</b> impacted post_type (if null, select all types)
571     @return   <b>Array</b>   the list of impacted post_ids
572     */
573     public function delMeta($meta_id,$type=null,$post_type=null)
574     {
575          $strReq = 'SELECT M.post_id '.
576                    'FROM '.$this->table.' M, '.$this->core->prefix.'post P '.
577                    'WHERE P.post_id = M.post_id '.
578                    "AND P.blog_id = '".$this->con->escape($this->core->blog->id)."' ".
579                    "AND meta_id = '".$this->con->escape($meta_id)."' ";
580         
581          if ($type !== null) {
582               $strReq .= " AND meta_type = '".$this->con->escape($type)."' ";
583          }
584         
585          if ($post_type !== null) {
586               $strReq .= " AND P.post_type = '".$this->con->escape($post_type)."' ";
587          }
588         
589          $rs = $this->con->select($strReq);
590         
591          if ($rs->isEmpty()) return array();
592         
593          $ids = array();
594          while ($rs->fetch()) {
595               $ids[] = $rs->post_id;
596          }
597         
598          $strReq = 'DELETE FROM '.$this->table.' '.
599                    'WHERE post_id IN ('.implode(',',$ids).') '.
600                    "AND meta_id = '".$this->con->escape($meta_id)."' ";
601         
602          if ($type !== null) {
603               $strReq .= " AND meta_type = '".$this->con->escape($type)."' ";
604          }
605         
606          $rs = $this->con->execute($strReq);
607         
608          foreach ($ids as $post_id) {
609               $this->updatePostMeta($post_id);
610          }
611         
612          return $ids;
613     }
614}
615?>
Note: See TracBrowser for help on using the repository browser.

Sites map