Dotclear

source: inc/core/class.dc.meta.php @ 3057:c03560e93166

Revision 3057:c03560e93166, 15.7 KB checked in by franck <carnet.franck.paul@…>, 10 years ago (diff)

Lexical sort for tags, adresses #1850 and #2058

RevLine 
[0]1<?php
2# -- BEGIN LICENSE BLOCK ---------------------------------------
3#
4# This file is part of Dotclear 2.
5#
[1179]6# Copyright (c) 2003-2013 Olivier Meunier & Association Dotclear
[0]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
[2566]26
[0]27     /**
28     Object constructor.
[2566]29
[0]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     }
[2566]38
[0]39     /**
40     Splits up comma-separated values into an array of
41     unique, URL-proof metadata values.
[2566]42
[0]43     @param    str       <b>string</b>       Comma-separated metadata.
[2566]44
[0]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);
[2566]54
[0]55               if ($tag != false) {
56                    $res[$i] = $tag;
57               }
58          }
[2566]59
[0]60          return array_unique($res);
61     }
[2566]62
[0]63     /**
64     Make a metadata ID URL-proof.
[2566]65
[0]66     @param    str       <b>string</b>  the metadata ID.
[2566]67
[0]68     @return   <b>string</b>  The sanitized metadata
69     */
70     public static function sanitizeMetaID($str)
71     {
72          return text::tidyURL($str,false,true);
73     }
[2566]74
[0]75     /**
76     Converts serialized metadata (for instance in dc_post post_meta)
77     into a meta array.
[2566]78
[0]79     @param    str       <b>string</b>  the serialized metadata.
[2566]80
[0]81     @return   <b>Array</b>   the resulting array of post meta
82     */
83     public function getMetaArray($str)
84     {
85          $meta = @unserialize($str);
[2566]86
[0]87          if (!is_array($meta)) {
88               return array();
89          }
[2566]90
[0]91          return $meta;
92     }
[2566]93
[0]94     /**
95     Converts serialized metadata (for instance in dc_post post_meta)
96     into a comma-separated meta list for a given type.
[2566]97
[0]98     @param    str       <b>string</b>  the serialized metadata.
99     @param    type <b>string</b>  meta type to retrieve metaIDs from.
[2566]100
[0]101     @return   <b>string</b>  the comma-separated list of meta
102     */
103     public function getMetaStr($str,$type)
104     {
105          $meta = $this->getMetaArray($str);
[2566]106
[0]107          if (!isset($meta[$type])) {
108               return '';
109          }
[2566]110
[0]111          return implode(', ',$meta[$type]);
112     }
[2566]113
[0]114     /**
115     Converts serialized metadata (for instance in dc_post post_meta)
116     into a "fetchable" metadata record.
[2566]117
[0]118     @param    str       <b>string</b>  the serialized metadata.
119     @param    type <b>string</b>  meta type to retrieve metaIDs from.
[2566]120
[0]121     @return   <b>record</b>  the meta recordset
122     */
123     public function getMetaRecordset($str,$type)
124     {
125          $meta = $this->getMetaArray($str);
126          $data = array();
[2566]127
[0]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          }
[2566]142
[0]143          return staticRecord::newFromArray($data);
144     }
[2566]145
[0]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     }
[2566]156
[0]157     /**
[2566]158     Checks whether the current user is allowed to change post meta
[0]159     An exception is thrown if user is not allowed.
[2566]160
[0]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;
[2566]166
[0]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          }
[2566]170
[0]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())."' ";
[2566]178
[0]179               $rs = $this->con->select($strReq);
[2566]180
[0]181               if ($rs->isEmpty()) {
182                    throw new Exception(__('You are not allowed to change this entry status'));
183               }
184          }
185     }
[2566]186
[0]187     /**
188     Updates serialized post_meta information with dc_meta table information.
[2566]189
[0]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;
[2566]195
[0]196          $strReq = 'SELECT meta_id, meta_type '.
197                    'FROM '.$this->table.' '.
198                    'WHERE post_id = '.$post_id.' ';
[2566]199
[0]200          $rs = $this->con->select($strReq);
[2566]201
[0]202          $meta = array();
203          while ($rs->fetch()) {
204               $meta[$rs->meta_type][] = $rs->meta_id;
205          }
[2566]206
[0]207          $post_meta = serialize($meta);
[2566]208
[0]209          $cur = $this->con->openCursor($this->core->prefix.'post');
210          $cur->post_meta = $post_meta;
[2566]211
[0]212          $cur->update('WHERE post_id = '.$post_id);
213          $this->core->blog->triggerBlog();
214     }
[2566]215
[0]216     /**
217     Retrieves posts corresponding to given meta criteria.
218     <b>$params</b> is an array taking the following optional parameters:
[2566]219     - meta_id : get posts having meta id
[0]220     - meta_type : get posts having meta type
[2566]221
[0]222     @param    params    <b>array</b>   Parameters
223     @param    count_only     <b>boolean</b>      Only counts results
[2566]224
[0]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          }
[2566]232
[0]233          $params['from'] = ', '.$this->table.' META ';
234          $params['sql'] = 'AND META.post_id = P.post_id ';
[2566]235
[0]236          $params['sql'] .= "AND META.meta_id = '".$this->con->escape($params['meta_id'])."' ";
[2566]237
[0]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          }
[2566]242
[0]243          unset($params['meta_id']);
[2566]244
[0]245          return $this->core->blog->getPosts($params,$count_only);
246     }
[2566]247
[0]248     /**
249     Retrieves comments to posts corresponding to given meta criteria.
250     <b>$params</b> is an array taking the following optional parameters:
[2566]251     - meta_id : get comments to posts having meta id
[0]252     - meta_type : get comments to posts having meta type
[2566]253
[0]254     @param    params    <b>array</b>   Parameters
255     @param    count_only     <b>boolean</b>      Only counts results
[2566]256
[0]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          }
[2566]264
[0]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'])."' ";
[2566]268
[0]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          }
[2566]273
[0]274          return $this->core->blog->getComments($params,$count_only);
275     }
[2566]276
[0]277     /**
278     @deprecated since 2.2. Use getMetadata and computeMetaStats instead.
279     Generic-purpose metadata retrieval : gets metadatas according to given
[2566]280     criteria. Metadata get enriched with stastistics columns (only relevant
281     if limit parameter is not set). Metadata are sorted by post count
[0]282     descending
[2566]283
[0]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
[2566]288
[0]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();
[2566]293
[0]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     }
[2566]305
[0]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:
[2566]310
[0]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)
[2566]316
[0]317     @param    params         <b>array</b>        Parameters
318     @param    count_only     <b>boolean</b>      Only counts results
[2566]319
[0]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          }
[2566]329
[0]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)."' ";
[2566]334
[0]335          if (isset($params['meta_type'])) {
336               $strReq .= " AND meta_type = '".$this->con->escape($params['meta_type'])."' ";
337          }
[2566]338
[0]339          if (isset($params['meta_id'])) {
340               $strReq .= " AND meta_id = '".$this->con->escape($params['meta_id'])."' ";
341          }
[2566]342
[0]343          if (isset($params['post_id'])) {
344               $strReq .= ' AND P.post_id '.$this->con->in($params['post_id']).' ';
345          }
[2566]346
[0]347          if (!$this->core->auth->check('contentadmin',$this->core->blog->id)) {
348               $strReq .= 'AND ((post_status = 1 ';
[2566]349
[0]350               if ($this->core->blog->without_password) {
351                    $strReq .= 'AND post_password IS NULL ';
352               }
353               $strReq .= ') ';
[2566]354
[0]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          }
[2566]361
[0]362          if (!$count_only) {
363               if (!isset($params['order'])) {
364                    $params['order'] = 'count DESC';
365               }
[2566]366
[0]367               $strReq .=
368               'GROUP BY meta_id,meta_type,P.blog_id '.
369               'ORDER BY '.$params['order'];
[2566]370
[0]371               if (isset($params['limit'])) {
372                    $strReq .= $this->con->limit($params['limit']);
373               }
374          }
[2566]375
[0]376          $rs = $this->con->select($strReq);
377          return $rs;
378     }
[2566]379
[0]380     /**
381     Computes statistics from a metadata recordset.
382     Each record gets enriched with lowercase name, percent and roundpercent columns
[2566]383
[0]384     @param    rs   <b>record</b>  recordset to enrich
[2566]385
[0]386     @return   <b>record</b>  the enriched recordset
387     */
388     public function computeMetaStats($rs) {
389          $rs_static = $rs->toStatic();
[2566]390
[0]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          }
[2566]403
[0]404          while ($rs_static->fetch())
405          {
[3057]406               $rs_static->set('meta_id_lower',dcUtils::removeDiacritics(mb_strtolower($rs_static->meta_id)));
[2566]407
[0]408               $count = $rs_static->count;
409               $percent = ((integer) $rs_static->count) * 100 / $max[$rs_static->meta_type];
[2566]410
[0]411               $rs_static->set('percent',(integer) round($percent));
412               $rs_static->set('roundpercent',round($percent/10)*10);
413          }
[2566]414
[0]415          return $rs_static;
416     }
[2566]417
[0]418     /**
419     Adds a metadata to a post.
[2566]420
[0]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);
[2566]428
[0]429          $value = trim($value);
430          if ($value === false) { return; }
[2566]431
[0]432          $cur = $this->con->openCursor($this->table);
[2566]433
[0]434          $cur->post_id = (integer) $post_id;
435          $cur->meta_id = (string) $value;
436          $cur->meta_type = (string) $type;
[2566]437
[0]438          $cur->insert();
439          $this->updatePostMeta((integer) $post_id);
440     }
[2566]441
[0]442     /**
443     Removes metadata from a post.
[2566]444
[0]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;
[2566]452
[0]453          $this->checkPermissionsOnPost($post_id);
[2566]454
[0]455          $strReq = 'DELETE FROM '.$this->table.' '.
456                    'WHERE post_id = '.$post_id;
[2566]457
[0]458          if ($type !== null) {
459               $strReq .= " AND meta_type = '".$this->con->escape($type)."' ";
460          }
[2566]461
[0]462          if ($meta_id !== null) {
463               $strReq .= " AND meta_id = '".$this->con->escape($meta_id)."' ";
464          }
[2566]465
[0]466          $this->con->execute($strReq);
467          $this->updatePostMeta((integer) $post_id);
468     }
[2566]469
[0]470     /**
471     Mass updates metadata for a given post_type.
[2566]472
[0]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);
[2566]482
[0]483          if ($new_meta_id == $meta_id) {
484               return true;
485          }
[2566]486
[0]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' ";
[2566]492
[0]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          }
[2566]499
[0]500          $delReq = 'DELETE FROM '.$this->table.' '.
501                    'WHERE post_id IN (%s) '.
502                    "AND meta_id = '%s' ";
[2566]503
[0]504          $updReq = 'UPDATE '.$this->table.' '.
505                    "SET meta_id = '%s' ".
506                    'WHERE post_id IN (%s) '.
507                    "AND meta_id = '%s' ";
[2566]508
[0]509          if ($type !== null) {
510               $plus = " AND meta_type = '%s' ";
511               $getReq .= $plus;
512               $delReq .= $plus;
513               $updReq .= $plus;
514          }
[2566]515
[0]516          $to_update = $to_remove = array();
[2566]517
[0]518          $rs = $this->con->select(sprintf($getReq,$this->con->escape($meta_id),
519                                   $this->con->escape($type)));
[2566]520
[0]521          while ($rs->fetch()) {
522               $to_update[] = $rs->post_id;
523          }
[2566]524
[0]525          if (empty($to_update)) {
526               return false;
527          }
[2566]528
[0]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          }
[2566]536
[0]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)));
[2566]543
[0]544               foreach ($to_remove as $post_id) {
545                    $this->updatePostMeta($post_id);
546               }
547          }
[2566]548
[0]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)));
[2566]556
[0]557               foreach ($to_update as $post_id) {
558                    $this->updatePostMeta($post_id);
559               }
560          }
[2566]561
[0]562          return true;
563     }
[2566]564
[0]565     /**
566     Mass delete metadata for a given post_type.
[2566]567
[0]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)."' ";
[2566]580
[0]581          if ($type !== null) {
582               $strReq .= " AND meta_type = '".$this->con->escape($type)."' ";
583          }
[2566]584
[0]585          if ($post_type !== null) {
586               $strReq .= " AND P.post_type = '".$this->con->escape($post_type)."' ";
587          }
[2566]588
[0]589          $rs = $this->con->select($strReq);
[2566]590
[0]591          if ($rs->isEmpty()) return array();
[2566]592
[0]593          $ids = array();
594          while ($rs->fetch()) {
595               $ids[] = $rs->post_id;
596          }
[2566]597
[0]598          $strReq = 'DELETE FROM '.$this->table.' '.
599                    'WHERE post_id IN ('.implode(',',$ids).') '.
600                    "AND meta_id = '".$this->con->escape($meta_id)."' ";
[2566]601
[0]602          if ($type !== null) {
603               $strReq .= " AND meta_type = '".$this->con->escape($type)."' ";
604          }
[2566]605
[0]606          $rs = $this->con->execute($strReq);
[2566]607
[0]608          foreach ($ids as $post_id) {
609               $this->updatePostMeta($post_id);
610          }
[2566]611
[0]612          return $ids;
613     }
614}
Note: See TracBrowser for help on using the repository browser.

Sites map