package.xml 0000664 0001750 0001750 00000044007 12171301731 011300 0 ustar jan jan
* array('localobjectId' => array('tagone', 'tagtwo'),
* 'anotherobjectid' => array('anothertag', 'yetanother'))
*
*/
public function getTagsByObjects($objects, $type)
{
$object_ids = $this->_objectManager->exists($objects, $type);
$results = array();
if (!$object_ids) {
foreach ($objects as $id) {
$results[$id] = array();
}
} else {
$sql = 'SELECT DISTINCT tag_name, tagged.object_id FROM '
. $this->_t('tags') . ' t INNER JOIN ' . $this->_t('tagged')
. ' tagged ON t.tag_id = tagged.tag_id AND tagged.object_id IN ('
. str_repeat('?,', count($object_ids) - 1) . '?)';
$tags = $this->_db->selectAll($sql, array_keys($object_ids));
foreach ($tags as $tag) {
if (empty($results[$object_ids[$tag['object_id']]])) {
$results[$object_ids[$tag['object_id']]] = array();
}
$results[$object_ids[$tag['object_id']]][] = $tag['tag_name'];
}
}
return $results;
}
/**
* Retrieve tags based on criteria.
*
* @param array $args Search criteria:
* q Starts-with search on tag_name.
* limit Maximum number of tags to return.
* offset Offset the results. Only useful for paginating, and not recommended.
* userId Only return tags that have been applied by a specific user.
* typeId Only return tags that have been applied by a specific object type.
* objectId Only return tags that have been applied to a specific object.
*
* @return array An array of tags, id => name.
*/
public function getTags($args)
{
if (isset($args['objectId'])) {
// Don't create the object just because we're trying to load an
// objects's tags - just check if the object is there. Assume if we
// have an integer, it's a valid object_id.
if (is_array($args['objectId'])) {
$args['objectId'] = $this->_objectManager->exists($args['objectId']['object'], $args['objectId']['type']);
if ($args['objectId']) {
$args['objectId'] = current(array_keys($args['objectId']));
}
}
if (!$args['objectId']) {
return array();
}
$sql = 'SELECT DISTINCT t.tag_id AS tag_id, tag_name FROM ' . $this->_t('tags') . ' t INNER JOIN ' . $this->_t('tagged') . ' tagged ON t.tag_id = tagged.tag_id AND tagged.object_id = ' . (int)$args['objectId'];
} elseif (isset($args['userId']) && isset($args['typeId'])) {
$args['userId'] = current($this->_userManager->ensureUsers($args['userId']));
$args['typeId'] = current($this->_typeManager->ensureTypes($args['typeId']));
$sql = 'SELECT DISTINCT t.tag_id AS tag_id, tag_name FROM ' . $this->_t('tags') . ' t INNER JOIN ' . $this->_t('tagged') . ' tagged ON t.tag_id = tagged.tag_id AND tagged.user_id = ' . (int)$args['userId'] . ' INNER JOIN ' . $this->_t('objects') . ' objects ON tagged.object_id = objects.object_id AND objects.type_id = ' . (int)$args['typeId'];
} elseif (isset($args['userId'])) {
$args['userId'] = current($this->_userManager->ensureUsers($args['userId']));
$sql = 'SELECT DISTINCT t.tag_id AS tag_id, tag_name FROM ' . $this->_t('tagged') . ' tagged INNER JOIN ' . $this->_t('tags') . ' t ON tagged.tag_id = t.tag_id WHERE tagged.user_id = ' . (int)$args['userId'];
$haveWhere = true;
} elseif (isset($args['typeId'])) {
$args['typeId'] = current($this->_typeManager->ensureTypes($args['typeId']));
$sql = 'SELECT DISTINCT t.tag_id AS tag_id, tag_name FROM ' . $this->_t('tagged') . ' tagged INNER JOIN ' . $this->_t('objects') . ' objects ON tagged.object_id = objects.object_id AND objects.type_id = ' . (int)$args['typeId'] . ' INNER JOIN ' . $this->_t('tags') . ' t ON tagged.tag_id = t.tag_id';
} elseif (isset($args['tagId'])) {
$radius = isset($args['limit']) ? (int)$args['limit'] : $this->_defaultRadius;
unset($args['limit']);
$inner = $this->_db->addLimitOffset('SELECT object_id FROM ' . $this->_t('tagged') . ' WHERE tag_id = ' . (int)$args['tagId'], array('limit' => $radius));
$sql = $this->_db->addLimitOffset('SELECT DISTINCT tagged2.tag_id AS tag_id, tag_name FROM (' . $inner . ') tagged1 INNER JOIN ' . $this->_t('tagged') . ' tagged2 ON tagged1.object_id = tagged2.object_id INNER JOIN ' . $this->_t('tags') . ' t ON tagged2.tag_id = t.tag_id', array('limit' => $args['limit']));
} else {
$sql = 'SELECT DISTINCT t.tag_id, tag_name FROM ' . $this->_t('tags') . ' t JOIN ' . $this->_t('tagged') . ' tagged ON t.tag_id = tagged.tag_id';
}
if (isset($args['q']) && strlen($args['q'])) {
// @TODO tossing a where clause in won't work with all query modes
$sql .= (!empty($haveWhere) ? ' AND' : ' WHERE') . ' tag_name LIKE ' . $this->_db->quoteString($args['q'] . '%');
}
if (isset($args['limit'])) {
$sql = $this->_db->addLimitOffset($sql, array('limit' => $args['limit'], 'offset' => isset($args['offset']) ? $args['offset'] : 0));
}
return $this->_db->selectAssoc($sql);
}
/**
* Generate a tag cloud. Same syntax as getTags, except that fetching a
* cloud for a userId + objectId combination doesn't make sense - the counts
* would all be one. In addition, this method returns counts for each tag.
*
* @param array $args Search criteria:
* - limit: (integer) Maximum number of tags to return.
* - offset: (integet) Offset the results. Only useful for paginating, and
* not recommended.
* - userId: (string) Only return tags that have been applied by a
* specific user.
* - typeId: (array) Only return tags that have been applied by specific
* object types.
* - objectId: (array) Only return tags that have been applied to specific
* objects all objects must be of the same type and
* specified by typeId.
* - tagIds: (array) Only return information on specific tag
* (an array of tag ids).
*
* @return array An array of hashes, each containing tag_id, tag_name, and count.
*/
public function getTagCloud($args = array())
{
if (isset($args['objectId'])) {
if (empty($args['typeId'])) {
throw new Content_Exception('Specified objectId, but failed to specify typeId for getTagCloud call.');
}
$args['objectId'] = $this->_objectManager->ensureObjects($args['objectId'], $args['typeId']);
$sql = 'SELECT t.tag_id AS tag_id, tag_name, COUNT(*) AS count FROM ' . $this->_t('tagged') . ' tagged INNER JOIN ' . $this->_t('tags') . ' t ON tagged.tag_id = t.tag_id WHERE tagged.object_id IN (' . implode(',', $args['objectId']) . ') GROUP BY t.tag_id, t.tag_name';
} elseif (isset($args['userId']) && isset($args['typeId'])) {
$args['userId'] = current($this->_userManager->ensureUsers($args['userId']));
$args['typeId'] = $this->_typeManager->ensureTypes($args['typeId']);
// This doesn't use a stat table, so may be slow.
$sql = 'SELECT t.tag_id AS tag_id, tag_name, COUNT(*) AS count FROM ' . $this->_t('tagged') . ' tagged INNER JOIN ' . $this->_t('objects') . ' objects ON tagged.object_id = objects.object_id AND objects.type_id IN (' . implode(',', $args['typeId']) . ') INNER JOIN ' . $this->_t('tags') . ' t ON tagged.tag_id = t.tag_id WHERE tagged.user_id = ' . (int)$args['userId'] . ' GROUP BY t.tag_id, t.tag_name';
} elseif (isset($args['userId'])) {
$args['userId'] = current($this->_userManager->ensureUsers($args['userId']));
$sql = 'SELECT t.tag_id AS tag_id, tag_name, count FROM ' . $this->_t('tagged') . ' tagged INNER JOIN ' . $this->_t('tags') . ' t ON tagged.tag_id = t.tag_id INNER JOIN ' . $this->_t('user_tag_stats') . ' uts ON t.tag_id = uts.tag_id AND uts.user_id = ' . (int)$args['userId'] . ' GROUP BY t.tag_id, tag_name, count';
} elseif (isset($args['tagIds']) && isset($args['typeId'])) {
$args['typeId'] = $this->_typeManager->ensureTypes($args['typeId']);
// This doesn't use a stat table, so may be slow.
$sql = 'SELECT t.tag_id AS tag_id, tag_name, COUNT(*) AS count FROM ' . $this->_t('tagged') . ' tagged INNER JOIN ' . $this->_t('objects') . ' objects ON tagged.object_id = objects.object_id AND objects.type_id IN(' . implode(',', $args['typeId']) . ') INNER JOIN ' . $this->_t('tags') . ' t ON tagged.tag_id = t.tag_id AND t.tag_id IN (' . implode(', ', $args['tagIds']) . ') GROUP BY t.tag_id, t.tag_name';
} elseif (isset($args['typeId'])) {
$args['typeId'] = $this->_typeManager->ensureTypes($args['typeId']);
// This doesn't use a stat table, so may be slow.
$sql = 'SELECT t.tag_id AS tag_id, tag_name, COUNT(*) AS count FROM ' . $this->_t('tagged') . ' tagged INNER JOIN ' . $this->_t('objects') . ' objects ON tagged.object_id = objects.object_id AND objects.type_id IN(' . implode(',', $args['typeId']) . ') INNER JOIN ' . $this->_t('tags') . ' t ON tagged.tag_id = t.tag_id GROUP BY t.tag_id, t.tag_name';
} elseif (isset($args['tagIds'])) {
$ids = $this->_checkTags($args['tagIds'], false);
$sql = 'SELECT t.tag_id AS tag_id, tag_name, COUNT(*) AS count FROM ' . $this->_t('tagged') . ' tagged INNER JOIN ' . $this->_t('tags') . ' t ON tagged.tag_id = t.tag_id INNER JOIN ' . $this->_t('tag_stats') . ' ts ON t.tag_id = ts.tag_id WHERE t.tag_id IN (' . implode(', ', $ids) . ') GROUP BY t.tag_id, t.tag_name';
} else {
$sql = 'SELECT t.tag_id AS tag_id, tag_name, COUNT(*) AS count FROM ' . $this->_t('tagged') . ' tagged INNER JOIN ' . $this->_t('tags') . ' t ON tagged.tag_id = t.tag_id INNER JOIN ' . $this->_t('tag_stats') . ' ts ON t.tag_id = ts.tag_id GROUP BY t.tag_id, t.tag_name';
}
if (isset($args['limit'])) {
$sql = $this->_db->addLimitOffset($sql . ' ORDER BY count DESC', array('limit' => $args['limit'], 'offset' => isset($args['offset']) ? $args['offset'] : 0));
}
try {
$rows = $this->_db->selectAll($sql);
$results = array();
foreach ($rows as $row) {
$results[$row['tag_id']] = $row;
}
return $results;
} catch (Exception $e) {
throw new Content_Exception($e);
}
}
/**
* Get the most recently used tags.
*
* @param array $args Search criteria:
* limit Maximum number of tags to return.
* offset Offset the results. Only useful for paginating, and not recommended.
* userId Only return tags that have been used by a specific user.
* typeId Only return tags applied to objects of a specific type.
*
* @return array
*/
public function getRecentTags($args = array())
{
$sql = 'SELECT tagged.tag_id AS tag_id, tag_name, MAX(created) AS created FROM ' . $this->_t('tagged') . ' tagged INNER JOIN ' . $this->_t('tags') . ' t ON tagged.tag_id = t.tag_id';
if (isset($args['typeId'])) {
$args['typeId'] = current($this->_typeManager->ensureTypes($args['typeId']));
$sql .= ' INNER JOIN ' . $this->_t('objects') . ' objects ON tagged.object_id = objects.object_id AND objects.type_id = ' . (int)$args['typeId'];
}
if (isset($args['userId'])) {
$args['userId'] = current($this->_userManager->ensureUsers($args['userId']));
$sql .= ' WHERE tagged.user_id = ' . (int)$args['userId'];
}
$sql .= ' GROUP BY tagged.tag_id, tag_name ORDER BY created DESC';
if (isset($args['limit'])) {
$sql = $this->_db->addLimitOffset($sql, array('limit' => $args['limit'], 'offset' => isset($args['offset']) ? $args['offset'] : 0));
}
return $this->_db->selectAll($sql);
}
/**
* Get objects matching search criteria.
*
* @param array $args Search criteria:
* limit Maximum number of objects to return.
* offset Offset the results. Only useful for paginating, and not recommended.
* tagId Return objects related through one or more tags.
* notTagId Don't return objects tagged with one or more tags.
* typeId Only return objects with a specific type.
* objectId Return objects with the same tags as $objectId.
* userId Limit results to objects tagged by a specific user.
* radius Radius setting for relationship queries e.g., objectId
*
* @return array An array of object ids.
*/
public function getObjects($args)
{
if (isset($args['objectId'])) {
if (is_array($args['objectId'])) {
$args['objectId'] = current($this->_objectManager->ensureObjects(
$args['objectId']['object'],
$args['objectId']['type']));
}
$radius = isset($args['radius']) ?
(int)$args['radius'] :
$this->_defaultRadius;
$inner = $this->_db->addLimitOffset(
'SELECT tag_id, object_id FROM ' . $this->_t('tagged')
. ' WHERE object_id = ' . (int)$args['objectId'],
array('limit' => $radius));
$sql = 'SELECT t2.object_id AS object_id, object_name FROM ('
. $inner . ') t1 INNER JOIN ' . $this->_t('tagged')
. ' t2 ON t1.tag_id = t2.tag_id INNER JOIN ' . $this->_t('objects')
. ' objects ON objects.object_id = t2.object_id WHERE t2.object_id != '
. (int)$args['objectId'] . ' GROUP BY t2.object_id, object_name';
if (!empty($args['limit'])) {
$sql = $this->_db->addLimitOffset($sql, $args['limit']);
}
} elseif (isset($args['tagId'])) {
$tags = is_array($args['tagId']) ? array_values($args['tagId']) : array($args['tagId']);
$count = count($tags);
if (!$count) {
return array();
}
$notTags = isset($args['notTagId']) ? (is_array($args['notTagId']) ? array_values($args['notTagId']) : array($args['notTagId'])) : array();
$notCount = count($notTags);
$sql = 'SELECT DISTINCT tagged.object_id AS object_id, object_name FROM ' . $this->_t('tagged') . ' tagged INNER JOIN ' . $this->_t('objects') . ' objects ON objects.object_id = tagged.object_id';
if (!empty($args['typeId'])) {
$args['typeId'] = $this->_typeManager->ensureTypes($args['typeId']);
}
if ($count > 1) {
for ($i = 1; $i < $count; $i++) {
$sql .= ' INNER JOIN ' . $this->_t('tagged') . ' tagged' . $i . ' ON tagged.object_id = tagged' . $i . '.object_id';
}
}
if ($notCount) {
// Left joins for tags we want to exclude.
for ($j = 0; $j < $notCount; $j++) {
$sql .= ' LEFT JOIN ' . $this->_t('tagged') . ' not_tagged' . $j . ' ON tagged.object_id = not_tagged' . $j . '.object_id AND not_tagged' . $j . '.tag_id = ' . (int)$notTags[$j];
}
}
$sql .= ' WHERE tagged.tag_id = ' . (int)$tags[0];
if ($count > 1) {
for ($i = 1; $i < $count; $i++) {
$sql .= ' AND tagged' . $i . '.tag_id = ' . (int)$tags[$i];
}
}
if ($notCount) {
for ($j = 0; $j < $notCount; $j++) {
$sql .= ' AND not_tagged' . $j . '.object_id IS NULL';
}
}
if (!empty($args['typeId']) && count($args['typeId'])) {
$sql .= ' AND objects.type_id IN (' . implode(', ', $args['typeId']) . ')';
}
if (array_key_exists('userId', $args)) {
$args['userId'] = $this->_userManager->ensureUsers($args['userId']);
$sql .= ' AND tagged.user_id IN (' . implode(', ', $args['userId']) . ')';
}
}
if (isset($args['limit'])) {
$sql = $this->_db->addLimitOffset($sql, array('limit' => $args['limit'], 'offset' => isset($args['offset']) ? $args['offset'] : 0));
}
return $this->_db->selectAssoc($sql);
}
/**
* Return objects related to the given object via tags, along with a
* similarity rank.
*
* @param mixed $object_id The object to find relations for.
* @param array $args
* limit Maximum number of objects to return (default 10).
* userId Only return objects that have been tagged by a specific user.
* typeId Only return objects of a specific type.
* threshold Number of tags-in-common objects must have to match (default 1).
*
* @return array An array of (client) object ids => similarity rank
*/
public function getSimilarObjects($object_id, array $args = array())
{
$defaults = array('limit' => 10, 'threshold' => 1);
$args = array_merge($defaults, $args);
if (is_array($object_id)) {
$object_id = $this->_objectManager->exists($object_id['object'], $object_id['type']);
if (!$object_id) {
return array();
}
$object_id = current(array_keys($object_id));
} elseif (!is_int($object_id)) {
throw new InvalidArgumentException(_("Missing or invalid object type parameter."));
}
$threshold = intval($args['threshold']);
$max_objects = intval($args['limit']);
if (!isset($object_id) || !($object_id > 0)) {
return array();
}
if ($threshold <= 0 || $max_objects <= 0) {
return array();
}
/* Get the object's tags */
$tagObjects = $this->getTags(array('objectId' => $object_id));
$tagArray = array_keys($tagObjects);
$numTags = count($tagArray);
if ($numTags == 0) {
return array(); // Return empty set of matches
}
$sql = 'SELECT objects.object_name, COUNT(matches.object_id) AS num_common_tags FROM '
. $this->_t('tagged') . ' matches INNER JOIN '
. $this->_t('tags') . ' tags ON (tags.tag_id = matches.tag_id)';
if (!empty($args['userId'])) {
$sql .= ' INNER JOIN ' . $this->_t('users')
. ' users ON users.user_id = matches.user_id AND users.user_name = '
. $this->_db->quoteString($args['userId']);
}
$sql .= ' INNER JOIN ' . $this->_t('objects')
. ' objects ON objects.object_id = matches.object_id';
if (!empty($args['typeId'])) {
$sql .= ' INNER JOIN ' . $this->_t('types')
. ' types ON types.type_id=objects.type_id AND types.type_name = '
. $this->_db->quoteString($args['typeId']);
}
$sql .= ' WHERE tags.tag_id IN (' . implode(',', $tagArray) . ') AND matches.object_id <> ' . (int)$object_id
.' GROUP BY objects.object_name HAVING COUNT(matches.object_id) >= ' . $threshold
. ' ORDER BY num_common_tags DESC';
$sql = $this->_db->addLimitOffset($sql, array('limit' => $max_objects));
try {
return $this->_db->selectAssoc($sql);
} catch (Horde_Db_Exception $e) {
throw new Content_Exception($e);
}
}
/**
* Get the most recently tagged objects.
*
* @param array $args Search criteria:
* limit Maximum number of objects to return.
* offset Offset the results. Only useful for paginating, and not recommended.
* userId Only return objects that have been tagged by a specific user.
* typeId Only return objects of a specific object type.
*
* @return array
*/
public function getRecentObjects($args = array())
{
$sql = 'SELECT tagged.object_id AS object_id, MAX(created) AS created FROM ' . $this->_t('tagged') . ' tagged';
if (isset($args['typeId'])) {
$args['typeId'] = current($this->_typeManager->ensureTypes($args['typeId']));
$sql .= ' INNER JOIN ' . $this->_t('objects') . ' objects ON tagged.object_id = objects.object_id AND objects.type_id = ' . (int)$args['typeId'];
}
if (isset($args['userId'])) {
$args['userId'] = current($this->_userManager->ensureUsers($args['userId']));
$sql .= ' WHERE tagged.user_id = ' . (int)$args['userId'];
}
$sql .= ' GROUP BY tagged.object_id ORDER BY created DESC';
if (isset($args['limit'])) {
$sql = $this->_db->addLimitOffset($sql, array('limit' => $args['limit'], 'offset' => isset($args['offset']) ? $args['offset'] : 0));
}
return $this->_db->selectAll($sql);
}
/**
* Find users through objects, tags, or other users.
*/
public function getUsers($args)
{
if (isset($args['objectId'])) {
$args['objectId'] = $this->_ensureObject($args['objectId']);
$sql = 'SELECT t.user_id, user_name FROM ' . $this->_t('tagged') . ' t INNER JOIN ' . $this->_t('users') . ' u ON t.user_id = u.user_id WHERE object_id = ' . (int)$args['objectId'];
} elseif (isset($args['userId'])) {
$args['userId'] = current($this->_userManager->ensureUsers($args['userId']));
$radius = isset($args['radius']) ? (int)$args['radius'] : $this->_defaultRadius;
$sql = 'SELECT others.user_id, user_name FROM ' . $this->_t('tagged') . ' others INNER JOIN ' . $this->_t('users') . ' u ON u.user_id = others.user_id INNER JOIN (SELECT tag_id FROM ' . $this->_t('tagged') . ' WHERE user_id = ' . (int)$args['userId'] . ' GROUP BY tag_id HAVING COUNT(tag_id) >= ' . $radius . ') self ON others.tag_id = self.tag_id GROUP BY others.user_id';
} elseif (isset($args['tagId'])) {
$tags = $this->ensureTags($args['tagId']);
//$tags = is_array($args['tagId']) ? array_values($args['tagId']) : array($args['tagId']);
$count = count($tags);
if (!$count) {
return array();
}
$notTags = isset($args['notTagId']) ? (is_array($args['notTagId']) ? array_values($args['notTagId']) : array($args['notTagId'])) : array();
$notCount = count($notTags);
$sql = 'SELECT DISTINCT tagged.user_id, user_name FROM ' . $this->_t('tagged') . ' tagged INNER JOIN ' . $this->_t('users') . ' u ON u.user_id = tagged.user_id ';
if ($count > 1) {
for ($i = 1; $i < $count; $i++) {
$sql .= ' INNER JOIN ' . $this->_t('tagged') . ' tagged' . $i . ' ON tagged.user_id = tagged' . $i . '.user_id';
}
}
if ($notCount) {
// Left joins for tags we want to exclude.
for ($j = 0; $j < $notCount; $j++) {
$sql .= ' LEFT JOIN ' . $this->_t('tagged') . ' not_tagged' . $j . ' ON tagged.user_id = not_tagged' . $j . '.user_id AND not_tagged' . $j . '.tag_id = ' . (int)$notTags[$j];
}
}
$sql .= ' WHERE tagged.tag_id = ' . (int)$tags[0];
if ($count > 1) {
for ($i = 1; $i < $count; $i++) {
$sql .= ' AND tagged' . $i . '.tag_id = ' . (int)$tags[$i];
}
}
if ($notCount) {
for ($j = 0; $j < $notCount; $j++) {
$sql .= ' AND not_tagged' . $j . '.user_id IS NULL';
}
}
}
if (isset($args['limit'])) {
$sql = $this->_db->addLimitOffset($sql, array('limit' => $args['limit'], 'offset' => isset($args['offset']) ? $args['offset'] : 0));
}
return $this->_db->selectAssoc($sql);
}
/**
* Get the users who have most recently tagged objects.
*
* @param array $args Search criteria:
* limit Maximum number of users to return.
* offset Offset the results. Only useful for paginating, and not recommended.
* typeId Only return users who have tagged objects of a specific object type.
*
* @return array
*/
public function getRecentUsers($args = array())
{
$sql = 'SELECT tagged.user_id AS user_id, MAX(created) AS created FROM ' . $this->_t('tagged') . ' tagged';
if (isset($args['typeId'])) {
$args['typeId'] = current($this->_typeManager->ensureTypes($args['typeId']));
$sql .= ' INNER JOIN ' . $this->_t('objects') . ' objects ON tagged.object_id = objects.object_id AND objects.type_id = ' . (int)$args['typeId'];
}
$sql .= ' GROUP BY tagged.user_id ORDER BY created DESC';
if (isset($args['limit'])) {
$sql = $this->_db->addLimitOffset($sql, array('limit' => $args['limit'], 'offset' => isset($args['offset']) ? $args['offset'] : 0));
}
return $this->_db->selectAll($sql);
}
/**
* Return users related to a given user along with a similarity rank.
*/
public function getSimilarUsers($args)
{
$args['userId'] = current($this->_userManager->ensureUsers($args['userId']));
$radius = isset($args['radius']) ? (int)$args['radius'] : $this->_defaultRadius;
$sql = 'SELECT others.user_id, (others.count - self.count) AS rank FROM ' . $this->_t('user_tag_stats') . ' others INNER JOIN (SELECT tag_id, count FROM ' . $this->_t('user_tag_stats') . ' WHERE user_id = ' . (int)$args['userId'] . ' AND count >= ' . $radius . ') self ON others.tag_id = self.tag_id ORDER BY rank DESC';
if (isset($args['limit'])) {
$sql = $this->_db->addLimitOffset($sql, array('limit' => $args['limit']));
}
return $this->_db->selectAssoc($sql);
}
/**
* Check if tags exists, optionally create them if they don't and return ids
* for all that exist (including those that are optionally created).
*
* @param string|array $tags The tag names to check.
* @param boolean $create If true, create the tag in the tags table.
*
* @return array A hash of tag_name => tag_id values.
*/
protected function _checkTags($tags, $create = true)
{
if (empty($tags)) {
return array();
}
if (!is_array($tags)) {
$tags = is_int($tags) ? array($tags) : $this->splitTags($tags);
}
$tagIds = array();
// Anything already typed as an integer is assumed to be a tag id.
foreach ($tags as $tag) {
if (is_int($tag)) {
$tagIds[$tag] = $tag;
continue;
}
// Don't attempt to tag with an empty value
if (!strlen(trim($tag))) {
continue;
}
// Get the ids for any tags that already exist.
$sql = 'SELECT tag_id FROM ' . $this->_t('tags')
. ' WHERE LOWER(tag_name) = LOWER('
. $this->toDriver($tag) . ')';
if ($id = $this->_db->selectValue($sql)) {
$tagIds[$tag] = (int)$id;
} elseif ($create) {
// Create any tags that didn't already exist
$tagIds[$tag] = (int)$this->_db->insert('INSERT INTO ' . $this->_t('tags') . ' (tag_name) VALUES (' . $this->toDriver($tag) . ')');
}
}
return $tagIds;
}
/**
* Ensure that an array of tags exist, create any that don't, and
* return ids for all of them.
*
* @param array $tags Array of tag names or ids.
*
* @return array Hash of tag_name => tag_id values.
*/
public function ensureTags($tags)
{
return $this->_checkTags($tags);
}
/**
*
*/
public function getTagIds($tags)
{
return $this->_checkTags($tags, false);
}
/**
* Split a string into an array of tag names, respecting tags with spaces
* and ones that are quoted in some way. For example:
* this, "somecompany, llc", "and ""this"" w,o.rks", foo bar
*
* Would parse to:
* array('this', 'somecompany, llc', 'and "this" w,o.rks', 'foo bar')
*
* @param string $text String to split into 1 or more tags.
*
* @return array Split tag array.
*/
public function splitTags($text)
{
// From http://drupal.org/project/community_tags
$regexp = '%(?:^|,\ *)("(?>[^"]*)(?>""[^"]* )*"|(?: [^",]*))%x';
preg_match_all($regexp, $text, $matches);
$tags = array();
foreach (array_unique($matches[1]) as $tag) {
// Remove escape codes
$tag = trim(str_replace('""', '"', preg_replace('/^"(.*)"$/', '\1', $tag)));
if (strlen($tag)) {
$tags[] = $tag;
}
}
return $tags;
}
/**
* Retrieve a set of tags with relationships to the specified set
* of tags.
*
* @param array $ids An array of tag_ids.
* @param integer $object The object type to limit to.
* @param string $user The user to limit to.
*
* @return array A hash of tag_id -> tag_name
*/
public function browseTags($ids, $object_type, $user)
{
if (!count($ids)) {
return array();
}
$sql = 'SELECT DISTINCT t.tag_id, t.tag_name FROM ' . $this->_t('tagged') . ' as r, ' . $this->_t('objects') . ' as i, ' . $this->_t('tags') . ' as t';
for ($i = 0; $i < count($ids); $i++) {
$sql .= ',' . $this->_t('tagged') . ' as r' . $i;
}
$sql .= ' WHERE r.tag_id = t.tag_id AND r.object_id = i.object_id';
for ($i = 0; $i < count($ids); $i++) {
$sql .= ' AND r' . $i . '.object_id = r.object_id AND r.tag_id != ' . (int)$ids[$i] . ' AND r' . $i . '.tag_id = ' . (int)$ids[$i];
}
/* Note that we don't convertCharset here, it's done in listTagInfo */
$tags = $this->_db->selectAssoc($sql);
foreach ($tags as $key => &$value) {
$value = Horde_String::convertCharset($value, $this->_db->getOption('charset'), 'UTF-8');
}
return $tags;
}
/**
* Convenience method - if $object is an array, it is taken as an array of
* 'object' and 'type' to pass to objectManager::ensureObjects() if it's a
* scalar value, it's taken as the object_id and simply returned.
*/
protected function _ensureObject($object)
{
if (is_array($object)) {
$object = current($this->_objectManager->ensureObjects(
$object['object'], (int)current($this->_typeManager->ensureTypes($object['type']))));
}
return (int)$object;
}
/**
* Shortcut for getting a table name.
*
* @param string $tableType
*
* @return string Configured table name.
*/
protected function _t($tableType)
{
return $this->_db->quoteTableName($this->_tables[$tableType]);
}
public function toDriver($value)
{
return $this->_db->quoteString(Horde_String::convertCharset($value, 'UTF-8', $this->_db->getOption('charset')));
}
}
content-2.0.3/migration/1_rampage_base_tables.php 0000644 0001750 0001750 00000003271 12171301731 020151 0 ustar jan jan tables();
if (!in_array('rampage_types', $tableList)) {
// rampage_types
$t = $this->createTable('rampage_types', array('autoincrementKey' => 'type_id'));
$t->column('type_name', 'string', array('limit' => 255, 'null' => false));
$t->end();
$this->addIndex('rampage_types', array('type_name'), array('name' => 'rampage_objects_type_name', 'unique' => true));
}
if (!in_array('rampage_objects', $tableList)) {
// rampage_objects
$t = $this->createTable('rampage_objects', array('autoincrementKey' => 'object_id'));
$t->column('object_name', 'string', array('limit' => 255, 'null' => false));
$t->column('type_id', 'integer', array('null' => false, 'unsigned' => true));
$t->end();
$this->addIndex('rampage_objects', array('type_id', 'object_name'), array('name' => 'rampage_objects_type_object_name', 'unique' => true));
}
if (!in_array('rampage_users', $tableList)) {
// rampage_users
$t = $this->createTable('rampage_users', array('autoincrementKey' => 'user_id'));
$t->column('user_name', 'string', array('limit' => 255, 'null' => false));
$t->end();
$this->addIndex('rampage_users', array('user_name'), array('name' => 'rampage_users_user_name', 'unique' => true));
}
}
public function down()
{
$this->dropTable('rampage_types');
$this->dropTable('rampage_objects');
$this->dropTable('rampage_users');
}
}
content-2.0.3/migration/2_rampage_tag_tables.php 0000644 0001750 0001750 00000005361 12171301731 020015 0 ustar jan jan tables();
if (!in_array('rampage_tags', $tableList)) {
// rampage_tags
$t = $this->createTable('rampage_tags', array('autoincrementKey' => 'tag_id'));
$t->column('tag_name', 'string', array('limit' => 255, 'null' => false));
$t->end();
$this->addIndex('rampage_tags', array('tag_name'), array('name' => 'rampage_tags_tag_name', 'unique' => true));
}
if (!in_array('rampage_tagged', $tableList)) {
// rampage_tagged
$t = $this->createTable('rampage_tagged', array('autoincrementKey' => false));
$t->column('user_id', 'integer', array('null' => false, 'unsigned' => true));
$t->column('object_id', 'integer', array('null' => false, 'unsigned' => true));
$t->column('tag_id', 'integer', array('null' => false, 'unsigned' => true));
$t->column('created', 'datetime');
$t->primaryKey(array('user_id', 'object_id', 'tag_id'));
$t->end();
$this->addIndex('rampage_tagged', array('object_id'), array('name' => 'rampage_tagged_object_id'));
$this->addIndex('rampage_tagged', array('tag_id'), array('name' => 'rampage_tagged_tag_id'));
$this->addIndex('rampage_tagged', array('created'), array('name' => 'rampage_tagged_created'));
}
if (!in_array('rampage_tag_stats', $tableList)) {
// rampage_tag_stats
$t = $this->createTable('rampage_tag_stats', array('autoincrementKey' => false));
$t->column('tag_id', 'integer', array('null' => false, 'unsigned' => true));
$t->column('count', 'integer', array('unsigned' => true));
$t->primaryKey(array('tag_id'));
$t->end();
}
if (!in_array('rampage_user_tag_stats', $tableList)) {
// rampage_user_tag_stats
$t = $this->createTable('rampage_user_tag_stats', array('autoincrementKey' => false));
$t->column('user_id', 'integer', array('null' => false, 'unsigned' => true));
$t->column('tag_id', 'integer', array('null' => false, 'unsigned' => true));
$t->column('count', 'integer', array('unsigned' => true));
$t->primaryKey(array('user_id', 'tag_id'));
$t->end();
$this->addIndex('rampage_user_tag_stats', array('tag_id'), array('name' => 'rampage_user_tag_stats_tag_id'));
}
}
public function down()
{
$this->dropTable('rampage_tags');
$this->dropTable('rampage_tagged');
$this->dropTable('rampage_tag_stats');
$this->dropTable('rampage_user_tag_stats');
}
}
content-2.0.3/test/Content/Sql/Pdo/MysqlTest.php 0000664 0001750 0001750 00000001355 12171301731 017622 0 ustar jan jan ':memory:', 'charset' => 'utf-8'));
parent::setUpBeforeClass();
}
} content-2.0.3/test/Content/Sql/Base.php 0000664 0001750 0001750 00000010416 12171301731 016003 0 ustar jan jan _create();
$objects = self::$db->selectAll('SELECT * FROM rampage_objects');
$this->assertEquals(4, count($objects));
// If these aren't strings, then ids were taken as names.
foreach ($objects as $object) {
$this->assertInternalType('string', $object['object_name']);
}
$types = self::$db->selectAll('SELECT * FROM rampage_types');
$this->assertEquals(2, count($types));
foreach ($types as $type) {
$this->assertInternalType('string', $type['type_name']);
}
}
/**
* @depends testCreate
*/
public function testEnsureTags()
{
$this->_testEnsureTags();
}
public function testEnsureTypes()
{
$this->_testEnsureTypes();
}
/**
* @depends testCreate
*/
public function testFullTagCloudSimple()
{
$this->_testFullTagCloudSimple();
}
/**
* @depends testCreate
*/
public function testTagCloudByType()
{
$this->_testTagCloudByType();
}
/**
* @depends testCreate
*/
public function testTagCloudByUser()
{
$this->_testTagCloudByUser();
}
/**
* @depends testCreate
*/
public function testTagCloudByUserType()
{
$this->_testTagCloudByUserType();
}
/**
* @depends testCreate
*/
public function testTagCloudByTagType()
{
$this->_testTagCloudByTagType();
}
/**
* @depends testCreate
*/
public function testTagCloudByTagIds()
{
$this->_testTagCloudByTagIds();
}
/**
* @depends testCreate
*/
public function testGetRecentTags()
{
$this->_testGetRecentTags();
}
/**
* @depends testCreate
*/
public function testGetRecentTagsByUser()
{
$this->_testGetRecentTagsByUser();
}
/**
* @depends testCreate
*/
public function testGetRecentObjects()
{
$this->_testGetRecentObjects();
}
/**
* @depends testCreate
*/
public function testGetRecentTagsByType()
{
$this->_testGetRecentTagsByType();
}
/**
* @depends testCreate
*/
public function testGetRecentObjectsByUser()
{
$this->_testGetRecentObjectsByUser();
}
/**
* @depends testCreate
*/
public function testGetRecentObjectsByType()
{
$this->_testGetRecentObjectsByType();
}
/**
*
* @depends testCreate
*/
public function testGetRecentUsers()
{
$this->_testGetRecentUsers();
}
/**
* @depends testCreate
*/
public function testGetRecentUsersByType()
{
$this->_testGetRecentUsersByType();
}
/**
* @depends testCreate
*/
public function testUntag()
{
$this->_testUntag();
}
public static function setUpBeforeClass()
{
self::$injector = new Horde_Injector(new Horde_Injector_TopLevel());
self::$injector->setInstance('Horde_Db_Adapter', self::$db);
// FIXME: get migration directory if not running from Git checkout.
self::$migrator = new Horde_Db_Migration_Migrator(
self::$db,
null, //$logger,
array('migrationsPath' => __DIR__ . '/../../../migration',
'schemaTableName' => 'content_test_schema'));
self::$migrator->up();
self::$tagger = self::$injector->getInstance('Content_Tagger');
self::$type_mgr = self::$injector->createInstance('Content_Types_Manager');
}
public static function tearDownAfterClass()
{
if (self::$migrator) {
self::$migrator->down();
}
self::$db = null;
parent::tearDownAfterClass();
}
public function setUp()
{
if (!self::$db) {
$this->markTestSkipped(self::$reason);
}
}
} content-2.0.3/test/Content/Sql/MysqliTest.php 0000664 0001750 0001750 00000001572 12171301731 017252 0 ustar jan jan
* @category Horde
* @package Content
* @subpackage UnitTests
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
*/
class Content_Sql_MysqliTest extends Content_Test_Sql_Base
{
public static function setUpBeforeClass()
{
if (!extension_loaded('mysqli')) {
self::$reason = 'No mysqli extension';
return;
}
$config = self::getConfig('GROUP_SQL_MYSQLI_TEST_CONFIG',
__DIR__ . '/..');
if ($config && !empty($config['group']['sql']['mysqli'])) {
self::$db = new Horde_Db_Adapter_Mysqli($config['group']['sql']['mysqli']);
parent::setUpBeforeClass();
}
}
}
content-2.0.3/test/Content/Sql/MysqlTest.php 0000664 0001750 0001750 00000001563 12171301731 017101 0 ustar jan jan
* @category Horde
* @package Content
* @subpackage UnitTests
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
*/
class Content_Sql_MysqlTest extends Content_Test_Sql_Base
{
public static function setUpBeforeClass()
{
if (!extension_loaded('mysql')) {
self::$reason = 'No mysql extension';
return;
}
$config = self::getConfig('GROUP_SQL_MYSQL_TEST_CONFIG',
__DIR__ . '/..');
if ($config && !empty($config['group']['sql']['mysql'])) {
self::$db = new Horde_Db_Adapter_Mysql($config['group']['sql']['mysql']);
parent::setUpBeforeClass();
}
}
}
content-2.0.3/test/Content/AllTests.php 0000664 0001750 0001750 00000000132 12171301731 016117 0 ustar jan jan run();
content-2.0.3/test/Content/Autoload.php 0000664 0001750 0001750 00000001124 12171301731 016136 0 ustar jan jan
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @link http://pear.horde.org/index.php?package=Content
*/
Horde_Test_Autoload::addPrefix('Content', __DIR__ . '/../../lib');
content-2.0.3/test/Content/Base.php 0000664 0001750 0001750 00000033447 12171301731 015255 0 ustar jan jan
* @author Chuck Hagenbuch