Dotclear

source: inc/core/class.dc.meta.php @ 873:f9ef04edef05

Revision 873:f9ef04edef05, 14.9 KB checked in by Dsls <dsls@…>, 13 years ago (diff)

Turned db fetches into foreach, upgraded jquery

Line 
1<?php
2# -- BEGIN LICENSE BLOCK ---------------------------------------
3#
4# This file is part of Dotclear 2.
5#
6# Copyright (c) 2003-2011 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          $rsmeta = $this->con->select($strReq);
201         
202          $meta = array();
203          foreach ($rsmeta as $r) {
204               $meta[$r->meta_type][] = $r->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     @deprecated since 2.2. Use getMetadata and computeMetaStats instead.
250     Generic-purpose metadata retrieval : gets metadatas according to given
251     criteria. Metadata get enriched with stastistics columns (only relevant
252     if limit parameter is not set). Metadata are sorted by post count
253     descending
254     
255     @param    type <b>string</b>  if not null, get metas having the given type
256     @param    limit     <b>string</b>  if not null, number of max fetched metas
257     @param    meta_id   <b>string</b>  if not null, get metas having the given id
258     @param    post_id   <b>string</b>  if not null, get metas for the given post id
259     
260     @return   <b>record</b>  the meta recordset
261     */
262     public function getMeta($type=null,$limit=null,$meta_id=null,$post_id=null) {
263          $params = array();
264         
265          if ($type != null)
266               $params['meta_type'] = $type;
267          if ($limit != null)
268               $params['limit'] = $limit;
269          if ($meta_id != null)
270               $params['meta_id'] = $meta_id;
271          if ($meta_id != null)
272               $params['post_id'] = $post_id;
273          $meta = $this->getMetadata($params, false);
274          return $this->computeMetaStats($meta);
275     }
276     
277     /**
278     Generic-purpose metadata retrieval : gets metadatas according to given
279     criteria. <b>$params</b> is an array taking the following
280     optionnal parameters:
281     
282     - type: get metas having the given type
283     - meta_id: if not null, get metas having the given id
284     - post_id: get metas for the given post id
285     - limit: number of max fetched metas
286     - order: results order (default : posts count DESC)
287     
288     @param    params         <b>array</b>        Parameters
289     @param    count_only     <b>boolean</b>      Only counts results
290     
291     @return   <b>record</b>  the resulting comments record
292     */
293     public function getMetadata($params=array(), $count_only=false)
294     {
295          if ($count_only) {
296               $strReq = 'SELECT count(distinct M.meta_id) ';
297          } else {
298               $strReq = 'SELECT M.meta_id, M.meta_type, COUNT(M.post_id) as count ';
299          }
300         
301          $strReq .=
302          'FROM '.$this->table.' M LEFT JOIN '.$this->core->prefix.'post P '.
303          'ON M.post_id = P.post_id '.
304          "WHERE P.blog_id = '".$this->con->escape($this->core->blog->id)."' ";
305         
306          if (isset($params['meta_type'])) {
307               $strReq .= " AND meta_type = '".$this->con->escape($params['meta_type'])."' ";
308          }
309         
310          if (isset($params['meta_id'])) {
311               $strReq .= " AND meta_id = '".$this->con->escape($params['meta_id'])."' ";
312          }
313         
314          if (isset($params['post_id'])) {
315               $strReq .= ' AND P.post_id '.$this->con->in($params['post_id']).' ';
316          }
317         
318          if (!$this->core->auth->check('contentadmin',$this->core->blog->id)) {
319               $strReq .= 'AND ((post_status = 1 ';
320               
321               if ($this->core->blog->without_password) {
322                    $strReq .= 'AND post_password IS NULL ';
323               }
324               $strReq .= ') ';
325               
326               if ($this->core->auth->userID()) {
327                    $strReq .= "OR P.user_id = '".$this->con->escape($this->core->auth->userID())."')";
328               } else {
329                    $strReq .= ') ';
330               }
331          }
332         
333          if (!$count_only) {
334               if (!isset($params['order'])) {
335                    $params['order'] = 'count DESC';
336               }
337               
338               $strReq .=
339               'GROUP BY meta_id,meta_type,P.blog_id '.
340               'ORDER BY '.$params['order'];
341               
342               if (isset($params['limit'])) {
343                    $strReq .= $this->con->limit($params['limit']);
344               }
345          }
346         
347          $meta = $this->con->select($strReq);
348          return $meta;
349     }
350     
351     /**
352     Computes statistics from a metadata recordset.
353     Each record gets enriched with lowercase name, percent and roundpercent columns
354     
355     @param    rs   <b>record</b>  recordset to enrich
356     
357     @return   <b>record</b>  the enriched recordset
358     */
359     public function computeMetaStats($meta) {
360          $meta_static = $meta->toStatic();
361         
362          $max = array();
363          foreach ($meta_static as $m)
364          {
365               $type = $m->meta_type;
366               if (!isset($max[$type])) {
367                    $max[$type] = $m->count;
368               } else {
369                    if ($m->count > $max[$type]) {
370                         $max[$type] = $m->count;
371                    }
372               }
373          }
374         
375          foreach ($meta_static as $m)
376          {
377               $m->set('meta_id_lower',mb_strtolower($m->meta_id));
378               
379               $count = $m->count;
380               $percent = ((integer) $m->count) * 100 / $max[$m->meta_type];
381               
382               $m->set('percent',(integer) round($percent));
383               $m->set('roundpercent',round($percent/10)*10);
384          }
385         
386          return $meta_static;
387     }
388     
389     /**
390     Adds a metadata to a post.
391     
392     @param    post_id   <b>integer</b> the post id
393     @param    type <b>string</b>  meta type
394     @param    value     <b>integer</b> meta value
395     */
396     public function setPostMeta($post_id,$type,$value)
397     {
398          $this->checkPermissionsOnPost($post_id);
399         
400          $value = trim($value);
401          if ($value === false) { return; }
402         
403          $cur = $this->con->openCursor($this->table);
404         
405          $cur->post_id = (integer) $post_id;
406          $cur->meta_id = (string) $value;
407          $cur->meta_type = (string) $type;
408         
409          $cur->insert();
410          $this->updatePostMeta((integer) $post_id);
411     }
412     
413     /**
414     Removes metadata from a post.
415     
416     @param    post_id   <b>integer</b> the post id
417     @param    type <b>string</b>  meta type (if null, delete all types)
418     @param    value     <b>integer</b> meta value (if null, delete all values)
419     */
420     public function delPostMeta($post_id,$type=null,$meta_id=null)
421     {
422          $post_id = (integer) $post_id;
423         
424          $this->checkPermissionsOnPost($post_id);
425         
426          $strReq = 'DELETE FROM '.$this->table.' '.
427                    'WHERE post_id = '.$post_id;
428         
429          if ($type !== null) {
430               $strReq .= " AND meta_type = '".$this->con->escape($type)."' ";
431          }
432         
433          if ($meta_id !== null) {
434               $strReq .= " AND meta_id = '".$this->con->escape($meta_id)."' ";
435          }
436         
437          $this->con->execute($strReq);
438          $this->updatePostMeta((integer) $post_id);
439     }
440     
441     /**
442     Mass updates metadata for a given post_type.
443     
444     @param    meta_id        <b>integer</b> old value
445     @param    new_meta  <b>integer</b> new value
446     @param    type <b>string</b>  meta type (if null, select all types)
447     @param    post_type <b>integer</b> impacted post_type (if null, select all types)
448     @return   <b>boolean</b> true if at least 1 post has been impacted
449     */
450     public function updateMeta($meta_id,$new_meta_id,$type=null,$post_type=null)
451     {
452          $new_meta_id = self::sanitizeMetaID($new_meta_id);
453         
454          if ($new_meta_id == $meta_id) {
455               return true;
456          }
457         
458          $getReq = 'SELECT M.post_id '.
459                    'FROM '.$this->table.' M, '.$this->core->prefix.'post P '.
460                    'WHERE P.post_id = M.post_id '.
461                    "AND P.blog_id = '".$this->con->escape($this->core->blog->id)."' ".
462                    "AND meta_id = '%s' ";
463         
464          if (!$this->core->auth->check('contentadmin',$this->core->blog->id)) {
465               $getReq .= "AND P.user_id = '".$this->con->escape($this->core->auth->userID())."' ";
466          }
467          if ($post_type !== null) {
468               $getReq .= "AND P.post_type = '".$this->con->escape($post_type)."' ";
469          }
470         
471          $delReq = 'DELETE FROM '.$this->table.' '.
472                    'WHERE post_id IN (%s) '.
473                    "AND meta_id = '%s' ";
474         
475          $updReq = 'UPDATE '.$this->table.' '.
476                    "SET meta_id = '%s' ".
477                    'WHERE post_id IN (%s) '.
478                    "AND meta_id = '%s' ";
479         
480          if ($type !== null) {
481               $plus = " AND meta_type = '%s' ";
482               $getReq .= $plus;
483               $delReq .= $plus;
484               $updReq .= $plus;
485          }
486         
487          $to_update = $to_remove = array();
488         
489          $meta = $this->con->select(sprintf($getReq,$this->con->escape($meta_id),
490                                   $this->con->escape($type)));
491         
492          foreach ($meta as $m) {
493               $to_update[] = $m->post_id;
494          }
495         
496          if (empty($to_update)) {
497               return false;
498          }
499         
500          $meta = $this->con->select(sprintf($getReq,$new_meta_id,$type));
501          foreach ($meta as $m) {
502               if (in_array($m->post_id,$to_update)) {
503                    $to_remove[] = $m->post_id;
504                    unset($to_update[array_search($m->post_id,$to_update)]);
505               }
506          }
507         
508          # Delete duplicate meta
509          if (!empty($to_remove))
510          {
511               $this->con->execute(sprintf($delReq,implode(',',$to_remove),
512                                   $this->con->escape($meta_id),
513                                   $this->con->escape($type)));
514               
515               foreach ($to_remove as $post_id) {
516                    $this->updatePostMeta($post_id);
517               }
518          }
519         
520          # Update meta
521          if (!empty($to_update))
522          {
523               $this->con->execute(sprintf($updReq,$this->con->escape($new_meta_id),
524                                   implode(',',$to_update),
525                                   $this->con->escape($meta_id),
526                                   $this->con->escape($type)));
527               
528               foreach ($to_update as $post_id) {
529                    $this->updatePostMeta($post_id);
530               }
531          }
532         
533          return true;
534     }
535     
536     /**
537     Mass delete metadata for a given post_type.
538     
539     @param    meta_id        <b>integer</b> meta value
540     @param    type <b>string</b>  meta type (if null, select all types)
541     @param    post_type <b>integer</b> impacted post_type (if null, select all types)
542     @return   <b>Array</b>   the list of impacted post_ids
543     */
544     public function delMeta($meta_id,$type=null,$post_type=null)
545     {
546          $strReq = 'SELECT M.post_id '.
547                    'FROM '.$this->table.' M, '.$this->core->prefix.'post P '.
548                    'WHERE P.post_id = M.post_id '.
549                    "AND P.blog_id = '".$this->con->escape($this->core->blog->id)."' ".
550                    "AND meta_id = '".$this->con->escape($meta_id)."' ";
551         
552          if ($type !== null) {
553               $strReq .= " AND meta_type = '".$this->con->escape($type)."' ";
554          }
555         
556          if ($post_type !== null) {
557               $strReq .= " AND P.post_type = '".$this->con->escape($post_type)."' ";
558          }
559         
560          $posts = $this->con->select($strReq);
561         
562          if (count($posts) == 0) return array();
563         
564          $ids = array();
565          foreach ($posts as $p) {
566               $ids[] = $p->post_id;
567          }
568         
569          $strReq = 'DELETE FROM '.$this->table.' '.
570                    'WHERE post_id IN ('.implode(',',$ids).') '.
571                    "AND meta_id = '".$this->con->escape($meta_id)."' ";
572         
573          if ($type !== null) {
574               $strReq .= " AND meta_type = '".$this->con->escape($type)."' ";
575          }
576         
577          $rs = $this->con->execute($strReq);
578         
579          foreach ($ids as $post_id) {
580               $this->updatePostMeta($post_id);
581          }
582         
583          return $ids;
584     }
585}
586?>
Note: See TracBrowser for help on using the repository browser.

Sites map