dcCore dcCore instance private $con; ///< connection Database connection object private $table; ///< string Media table name /** Object constructor. @param core dcCore dcCore instance */ public function __construct($core) { $this->core =& $core; $this->con =& $this->core->con; $this->table = $this->core->prefix.'meta'; } /** Splits up comma-separated values into an array of unique, URL-proof metadata values. @param str string Comma-separated metadata. @return Array The array of sanitized metadata */ public function splitMetaValues($str) { $res = array(); foreach (explode(',',$str) as $i => $tag) { $tag = trim($tag); $tag = self::sanitizeMetaID($tag); if ($tag != false) { $res[$i] = $tag; } } return array_unique($res); } /** Make a metadata ID URL-proof. @param str string the metadata ID. @return string The sanitized metadata */ public static function sanitizeMetaID($str) { return text::tidyURL($str,false,true); } /** Converts serialized metadata (for instance in dc_post post_meta) into a meta array. @param str string the serialized metadata. @return Array the resulting array of post meta */ public function getMetaArray($str) { $meta = @unserialize($str); if (!is_array($meta)) { return array(); } return $meta; } /** Converts serialized metadata (for instance in dc_post post_meta) into a comma-separated meta list for a given type. @param str string the serialized metadata. @param type string meta type to retrieve metaIDs from. @return string the comma-separated list of meta */ public function getMetaStr($str,$type) { $meta = $this->getMetaArray($str); if (!isset($meta[$type])) { return ''; } return implode(', ',$meta[$type]); } /** Converts serialized metadata (for instance in dc_post post_meta) into a "fetchable" metadata record. @param str string the serialized metadata. @param type string meta type to retrieve metaIDs from. @return record the meta recordset */ public function getMetaRecordset($str,$type) { $meta = $this->getMetaArray($str); $data = array(); if (isset($meta[$type])) { foreach ($meta[$type] as $v) { $data[] = array( 'meta_id' => $v, 'meta_type' => $type, 'meta_id_lower' => mb_strtolower($v), 'count' => 0, 'percent' => 0, 'roundpercent' => 0 ); } } return staticRecord::newFromArray($data); } /** @deprecated since version 2.2 : $core->meta is always defined @see getMetaRecordset static version of getMetaRecordset */ public static function getMetaRecord($core,$str,$type) { $meta = new self($core); return $meta->getMetaRecordset($str,$type); } /** Checks whether the current user is allowed to change post meta An exception is thrown if user is not allowed. @param post_id string the post_id to check. */ private function checkPermissionsOnPost($post_id) { $post_id = (integer) $post_id; if (!$this->core->auth->check('usage,contentadmin',$this->core->blog->id)) { throw new Exception(__('You are not allowed to change this entry status')); } #�If user can only publish, we need to check the post's owner if (!$this->core->auth->check('contentadmin',$this->core->blog->id)) { $strReq = 'SELECT post_id '. 'FROM '.$this->core->prefix.'post '. 'WHERE post_id = '.$post_id.' '. "AND user_id = '".$this->con->escape($this->core->auth->userID())."' "; $rs = $this->con->select($strReq); if ($rs->isEmpty()) { throw new Exception(__('You are not allowed to change this entry status')); } } } /** Updates serialized post_meta information with dc_meta table information. @param post_id string the post_id to update. */ private function updatePostMeta($post_id) { $post_id = (integer) $post_id; $strReq = 'SELECT meta_id, meta_type '. 'FROM '.$this->table.' '. 'WHERE post_id = '.$post_id.' '; $rs = $this->con->select($strReq); $meta = array(); while ($rs->fetch()) { $meta[$rs->meta_type][] = $rs->meta_id; } $post_meta = serialize($meta); $cur = $this->con->openCursor($this->core->prefix.'post'); $cur->post_meta = $post_meta; $cur->update('WHERE post_id = '.$post_id); $this->core->blog->triggerBlog(); } /** Retrieves posts corresponding to given meta criteria. $params is an array taking the following optional parameters: - meta_id : get posts having meta id - meta_type : get posts having meta type @param params array Parameters @param count_only boolean Only counts results @return record the resulting posts record */ public function getPostsByMeta($params=array(),$count_only=false) { if (!isset($params['meta_id'])) { return null; } $params['from'] = ', '.$this->table.' META '; $params['sql'] = 'AND META.post_id = P.post_id '; $params['sql'] .= "AND META.meta_id = '".$this->con->escape($params['meta_id'])."' "; if (!empty($params['meta_type'])) { $params['sql'] .= "AND META.meta_type = '".$this->con->escape($params['meta_type'])."' "; unset($params['meta_type']); } unset($params['meta_id']); return $this->core->blog->getPosts($params,$count_only); } /** Retrieves comments to posts corresponding to given meta criteria. $params is an array taking the following optional parameters: - meta_id : get comments to posts having meta id - meta_type : get comments to posts having meta type @param params array Parameters @param count_only boolean Only counts results @return record the resulting comments record */ public function getCommentsByMeta($params=array(),$count_only=false) { if (!isset($params['meta_id'])) { return null; } $params['from'] = ', '.$this->table.' META '; $params['sql'] = 'AND META.post_id = P.post_id '; $params['sql'] .= "AND META.meta_id = '".$this->con->escape($params['meta_id'])."' "; if (!empty($params['meta_type'])) { $params['sql'] .= "AND META.meta_type = '".$this->con->escape($params['meta_type'])."' "; unset($params['meta_type']); } return $this->core->blog->getComments($params,$count_only); } /** @deprecated since 2.2. Use getMetadata and computeMetaStats instead. Generic-purpose metadata retrieval : gets metadatas according to given criteria. Metadata get enriched with stastistics columns (only relevant if limit parameter is not set). Metadata are sorted by post count descending @param type string if not null, get metas having the given type @param limit string if not null, number of max fetched metas @param meta_id string if not null, get metas having the given id @param post_id string if not null, get metas for the given post id @return record the meta recordset */ public function getMeta($type=null,$limit=null,$meta_id=null,$post_id=null) { $params = array(); if ($type != null) $params['meta_type'] = $type; if ($limit != null) $params['limit'] = $limit; if ($meta_id != null) $params['meta_id'] = $meta_id; if ($meta_id != null) $params['post_id'] = $post_id; $rs = $this->getMetadata($params, false); return $this->computeMetaStats($rs); } /** Generic-purpose metadata retrieval : gets metadatas according to given criteria. $params is an array taking the following optionnal parameters: - type: get metas having the given type - meta_id: if not null, get metas having the given id - post_id: get metas for the given post id - limit: number of max fetched metas - order: results order (default : posts count DESC) @param params array Parameters @param count_only boolean Only counts results @return record the resulting comments record */ public function getMetadata($params=array(), $count_only=false) { if ($count_only) { $strReq = 'SELECT count(distinct M.meta_id) '; } else { $strReq = 'SELECT M.meta_id, M.meta_type, COUNT(M.post_id) as count '; } $strReq .= 'FROM '.$this->table.' M LEFT JOIN '.$this->core->prefix.'post P '. 'ON M.post_id = P.post_id '. "WHERE P.blog_id = '".$this->con->escape($this->core->blog->id)."' "; if (isset($params['meta_type'])) { $strReq .= " AND meta_type = '".$this->con->escape($params['meta_type'])."' "; } if (isset($params['meta_id'])) { $strReq .= " AND meta_id = '".$this->con->escape($params['meta_id'])."' "; } if (isset($params['post_id'])) { $strReq .= ' AND P.post_id '.$this->con->in($params['post_id']).' '; } if (!$this->core->auth->check('contentadmin',$this->core->blog->id)) { $strReq .= 'AND ((post_status = 1 '; if ($this->core->blog->without_password) { $strReq .= 'AND post_password IS NULL '; } $strReq .= ') '; if ($this->core->auth->userID()) { $strReq .= "OR P.user_id = '".$this->con->escape($this->core->auth->userID())."')"; } else { $strReq .= ') '; } } if (!$count_only) { if (!isset($params['order'])) { $params['order'] = 'count DESC'; } $strReq .= 'GROUP BY meta_id,meta_type,P.blog_id '. 'ORDER BY '.$params['order']; if (isset($params['limit'])) { $strReq .= $this->con->limit($params['limit']); } } $rs = $this->con->select($strReq); return $rs; } /** Computes statistics from a metadata recordset. Each record gets enriched with lowercase name, percent and roundpercent columns @param rs record recordset to enrich @return record the enriched recordset */ public function computeMetaStats($rs) { $rs_static = $rs->toStatic(); $max = array(); while ($rs_static->fetch()) { $type = $rs_static->meta_type; if (!isset($max[$type])) { $max[$type] = $rs_static->count; } else { if ($rs_static->count > $max[$type]) { $max[$type] = $rs_static->count; } } } while ($rs_static->fetch()) { $rs_static->set('meta_id_lower',mb_strtolower($rs_static->meta_id)); $count = $rs_static->count; $percent = ((integer) $rs_static->count) * 100 / $max[$rs_static->meta_type]; $rs_static->set('percent',(integer) round($percent)); $rs_static->set('roundpercent',round($percent/10)*10); } return $rs_static; } /** Adds a metadata to a post. @param post_id integer the post id @param type string meta type @param value integer meta value */ public function setPostMeta($post_id,$type,$value) { $this->checkPermissionsOnPost($post_id); $value = trim($value); if ($value === false) { return; } $cur = $this->con->openCursor($this->table); $cur->post_id = (integer) $post_id; $cur->meta_id = (string) $value; $cur->meta_type = (string) $type; $cur->insert(); $this->updatePostMeta((integer) $post_id); } /** Removes metadata from a post. @param post_id integer the post id @param type string meta type (if null, delete all types) @param value integer meta value (if null, delete all values) */ public function delPostMeta($post_id,$type=null,$meta_id=null) { $post_id = (integer) $post_id; $this->checkPermissionsOnPost($post_id); $strReq = 'DELETE FROM '.$this->table.' '. 'WHERE post_id = '.$post_id; if ($type !== null) { $strReq .= " AND meta_type = '".$this->con->escape($type)."' "; } if ($meta_id !== null) { $strReq .= " AND meta_id = '".$this->con->escape($meta_id)."' "; } $this->con->execute($strReq); $this->updatePostMeta((integer) $post_id); } /** Mass updates metadata for a given post_type. @param meta_id integer old value @param new_meta integer new value @param type string meta type (if null, select all types) @param post_type integer impacted post_type (if null, select all types) @return boolean true if at least 1 post has been impacted */ public function updateMeta($meta_id,$new_meta_id,$type=null,$post_type=null) { $new_meta_id = self::sanitizeMetaID($new_meta_id); if ($new_meta_id == $meta_id) { return true; } $getReq = 'SELECT M.post_id '. 'FROM '.$this->table.' M, '.$this->core->prefix.'post P '. 'WHERE P.post_id = M.post_id '. "AND P.blog_id = '".$this->con->escape($this->core->blog->id)."' ". "AND meta_id = '%s' "; if (!$this->core->auth->check('contentadmin',$this->core->blog->id)) { $getReq .= "AND P.user_id = '".$this->con->escape($this->core->auth->userID())."' "; } if ($post_type !== null) { $getReq .= "AND P.post_type = '".$this->con->escape($post_type)."' "; } $delReq = 'DELETE FROM '.$this->table.' '. 'WHERE post_id IN (%s) '. "AND meta_id = '%s' "; $updReq = 'UPDATE '.$this->table.' '. "SET meta_id = '%s' ". 'WHERE post_id IN (%s) '. "AND meta_id = '%s' "; if ($type !== null) { $plus = " AND meta_type = '%s' "; $getReq .= $plus; $delReq .= $plus; $updReq .= $plus; } $to_update = $to_remove = array(); $rs = $this->con->select(sprintf($getReq,$this->con->escape($meta_id), $this->con->escape($type))); while ($rs->fetch()) { $to_update[] = $rs->post_id; } if (empty($to_update)) { return false; } $rs = $this->con->select(sprintf($getReq,$new_meta_id,$type)); while ($rs->fetch()) { if (in_array($rs->post_id,$to_update)) { $to_remove[] = $rs->post_id; unset($to_update[array_search($rs->post_id,$to_update)]); } } # Delete duplicate meta if (!empty($to_remove)) { $this->con->execute(sprintf($delReq,implode(',',$to_remove), $this->con->escape($meta_id), $this->con->escape($type))); foreach ($to_remove as $post_id) { $this->updatePostMeta($post_id); } } # Update meta if (!empty($to_update)) { $this->con->execute(sprintf($updReq,$this->con->escape($new_meta_id), implode(',',$to_update), $this->con->escape($meta_id), $this->con->escape($type))); foreach ($to_update as $post_id) { $this->updatePostMeta($post_id); } } return true; } /** Mass delete metadata for a given post_type. @param meta_id integer meta value @param type string meta type (if null, select all types) @param post_type integer impacted post_type (if null, select all types) @return Array the list of impacted post_ids */ public function delMeta($meta_id,$type=null,$post_type=null) { $strReq = 'SELECT M.post_id '. 'FROM '.$this->table.' M, '.$this->core->prefix.'post P '. 'WHERE P.post_id = M.post_id '. "AND P.blog_id = '".$this->con->escape($this->core->blog->id)."' ". "AND meta_id = '".$this->con->escape($meta_id)."' "; if ($type !== null) { $strReq .= " AND meta_type = '".$this->con->escape($type)."' "; } if ($post_type !== null) { $strReq .= " AND P.post_type = '".$this->con->escape($post_type)."' "; } $rs = $this->con->select($strReq); if ($rs->isEmpty()) return array(); $ids = array(); while ($rs->fetch()) { $ids[] = $rs->post_id; } $strReq = 'DELETE FROM '.$this->table.' '. 'WHERE post_id IN ('.implode(',',$ids).') '. "AND meta_id = '".$this->con->escape($meta_id)."' "; if ($type !== null) { $strReq .= " AND meta_type = '".$this->con->escape($type)."' "; } $rs = $this->con->execute($strReq); foreach ($ids as $post_id) { $this->updatePostMeta($post_id); } return $ids; } }