package.xml 0000664 0001750 0001750 00000047325 13160217705 011314 0 ustar jan jan
contentpear.horde.orgTagging applicationThis application provides tagging support for the other Horde applications.Chuck Hagenbuchchuckchuck@horde.orgyesMichael J Rubinskymrubinskmrubinsk@horde.orgyes2017-09-192.0.62.0.0stablestableBSD-2-Clause
* [jan] Officially support PHP 7.
5.3.08.0.0alpha18.0.0alpha11.7.0Horde_Corepear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Datepear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Exceptionpear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Dbpear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Injectorpear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Rdopear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Utilpear.horde.org2.0.03.0.0alpha13.0.0alpha1gettextjsonHorde_Argvpear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Controllerpear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_ElasticSearchpear.horde.org1.0.02.0.0alpha12.0.0alpha1hordeRolepear.horde.org1.0.0alpha11.0.0alphaalpha2011-03-09BSD-2-Clause
* First alpha release for Horde 4.
1.0.0beta11.0.0betabeta2011-03-16BSD-2-Clause
* First beta release for Horde 4.
1.0.0RC11.0.0betabeta2011-03-23BSD-2-Clause
* First release candidate for Horde 4.
1.0.0RC21.0.0betabeta2011-03-30BSD-2-Clause
* Second release candidate for Horde 4.
* [jan] Rename all scripts to be prefixed with content- (Request #9647).
1.0.01.0.0stablestable2011-04-06BSD-2-Clause
* First stable release for Horde 4.
* [jan] Fix case-insensitive filtering of duplicate tags (Bug #9617).
1.0.11.0.0stablestable2011-08-05BSD-2-Clause
* [mjr] Enforce that object and type names are always taken as a string (Bug #10171).
* [mjr] Updated unit tests to new test structure.
* [mjr] Prevent tagging with empty tags.
1.0.21.0.0stablestable2011-08-11BSD-2-Clause
* [mjr] Fix broken tag cloud queries due to missing GROUP BY fields (Bug #10419)
* [mjr] Prevent tagging with empty strings.
1.0.31.0.0stablestable2011-10-14BSD-2-Clause
* [mjr] Honor the limit and radius parameters.
* [mjr] Fix getObjects method when passing object_id (Bug# 10439).
* [mjr] Fix including all non-aggregate fields in GROUP BY clause (Bug# 10419).
* [jan] Fix commandline scripts (Bug #10656).
1.0.41.0.0stablestable2011-10-14BSD-2-Clause
*
2012-08-292.0.0beta12.0.0beta1betabetaBSD-2-Clause
* First beta release for Horde 5.
2.0.02.0.0stablestable2012-10-30BSD-2-Clause
* First stable release for Horde 5.
2.0.12.0.0stablestable2012-11-15BSD-2-Clause
* [jan] Add missing optional dependency on Horde_ElasticSearch.
* [jan] Catch exceptions from Horde_ElasticSearch.
2.0.22.0.0stablestable2013-02-11BSD-2-Clause
* [mjr] Fix logic that could possibly lead to incorrect content types being applied to objects (Bug #12016).
2.0.32.0.0stablestable2013-07-16BSD-2-Clause
* [mjr] Fix obtaining tag cloud information when filtering by objectIds.
2.0.42.0.0stablestable2014-06-02BSD-2-Clause
* [jan] Fix date format for 'created' column.
2.0.52.0.0stablestable2015-10-21BSD-2-Clause
* [mjr] Fix bug that was causing tag stats to be incorrectly incremented (Bug #14112).
* [mjr] Add Content_Objects_Manager::delete().
* [jan] Add unit tests for Oracle.
2.0.62.0.0stablestable2017-09-19BSD-2-Clause
* [jan] Officially support PHP 7.
content-2.0.6/app/controllers/ApplicationController.php 0000664 0001750 0001750 00000000557 13160217705 021454 0 ustar jan jan tagger = $GLOBALS['injector']->getInstance('Content_Tagger');
}
}
content-2.0.6/app/controllers/TagController.php 0000664 0001750 0001750 00000010334 13160217705 017716 0 ustar jan jan results = $this->tagger->getTags(array(
'q' => $this->params->q,
'typeId' => $this->params->typeId,
'userId' => $this->params->userId,
'objectId' => $this->params->objectId,
));
$this->_render();
}
/**
*/
public function recentTags()
{
$this->results = $this->tagger->getRecentTags(array(
'limit' => 10,
'typeId' => $this->params->typeId,
'objectId' => $this->params->objectId,
));
$this->_render();
}
public function searchUsers()
{
}
public function recentUsers()
{
}
public function searchObjects()
{
}
public function recentObjects()
{
}
/**
* Add a tag
*/
public function tag()
{
// The route configuration enforces POST or PUT only, but double-check here.
}
/**
* Remove a tag
*/
public function untag()
{
// The route configuration enforces POST or DELETE only, but double-check here.
}
protected function _render()
{
switch ((string)$this->_request->getFormat()) {
case 'html':
$this->render();
break;
case 'atom':
case 'rss':
$method = '_' . $this->_action . 'Feed';
$this->$method();
break;
case 'json':
default:
$this->renderText(json_encode($this->results));
break;
}
}
protected function _recentTagsFeed()
{
$entries = array();
foreach ($this->results as $tag) {
$entries[] = array(
'id' => 'tag/' . $tag['tag_id'], /* @TODO use routes to get the full URI here */
'title' => $tag['tag_name'],
'updated' => $tag['created'],
);
}
$format = $this->_request->getFormat();
$class = 'Horde_Feed_' . ucfirst((string)$this->_request->getFormat());
$feed = new $class(array(
'id' => 'tags/recent', /* @TODO Use routes to get url to this search */
'title' => 'Recent tags',
'updated' => $this->_request->getTimestamp(),
'entry' => $entries,
));
header('Content-type: ' . $format->string);
$this->renderText($feed->saveXml());
}
protected function _recentObjectsFeed()
{
$entries = array();
foreach ($this->results as $object) {
$entries[] = array(
'id' => 'object/' . $object['object_id'], /* @TODO use routes to get the full URI here */
'title' => $object['object_name'],
'updated' => $object['created'],
);
}
$format = $this->_request->getFormat();
$class = 'Horde_Feed_' . ucfirst((string)$this->_request->getFormat());
$feed = new $class(array(
'id' => 'objects/recent', /* @TODO Use routes to get url to this search */
'title' => 'Recent objects',
'updated' => $this->_request->getTimestamp(),
'entry' => $entries,
));
header('Content-type: ' . $format->string);
$this->renderText($feed->saveXml());
}
protected function _recentUsersFeed()
{
$entries = array();
foreach ($this->results as $user) {
$entries[] = array(
'id' => 'user/' . $user['user_id'], /* @TODO use routes to get the full URI here */
'title' => $user['user_name'],
'updated' => $user['created'],
);
}
$format = $this->_request->getFormat();
$class = 'Horde_Feed_' . ucfirst((string)$this->_request->getFormat());
$feed = new $class(array(
'id' => 'users/recent', /* @TODO Use routes to get url to this search */
'title' => 'Recent users',
'updated' => $this->_request->getTimestamp(),
'entry' => $entries,
));
header('Content-type: ' . $format->string);
$this->renderText($feed->saveXml());
}
}
content-2.0.6/app/views/Tag/recentTags.html.php 0000664 0001750 0001750 00000000355 13160217705 017505 0 ustar jan jan
results as $tag): ?>
escape($tag['tag_name']) ?>
content-2.0.6/app/views/Tag/searchTags.html.php 0000664 0001750 0001750 00000000270 13160217705 017466 0 ustar jan jan
results as $tag_id => $tag_name): ?>
escape($tag_name) ?>
content-2.0.6/bin/content-object-add 0000775 0001750 0001750 00000002463 13160217705 015446 0 ustar jan jan #!/usr/bin/env php
get('horde_dir', null, 'pear.horde.org') . '/content/';
}
require_once $baseDir . 'lib/Application.php';
Horde_Registry::appInit('content', array('cli' => true));
$options = array(
new Horde_Argv_Option('-i', '--id', array('type' => 'int')),
new Horde_Argv_Option('-t', '--type-id', array('type' => 'int')),
);
$parser = new Horde_Argv_Parser(array('optionList' => $options));
list($opts, $positional) = $parser->parseArgs();
if (!$opts->id || !$opts->type_id) {
throw new InvalidArgumentException('id and type-id are both required');
}
require CONTENT_BASE . '/lib/Objects/Object.php';
require CONTENT_BASE . '/lib/Objects/ObjectMapper.php';
$m = new Content_ObjectMapper($injector->getInstance('Horde_Db_Adapter'));
$i = $m->create(array('object_name' => $opts->id,
'type_id' => $opts->type_id,
));
echo 'Created new object with id ' . $i->object_id . ' for ' . $i->type_id . ':' . $i->object_name . ".\n";
exit(0);
content-2.0.6/bin/content-object-delete 0000775 0001750 0001750 00000002107 13160217705 016153 0 ustar jan jan #!/usr/bin/env php
get('horde_dir', null, 'pear.horde.org') . '/content/';
}
require_once $baseDir . 'lib/Application.php';
Horde_Registry::appInit('content', array('cli' => true));
$options = array(
new Horde_Argv_Option('-m', '--object-id', array('type' => 'int')),
);
$parser = new Horde_Argv_Parser(array('optionList' => $options));
list($opts, $positional) = $parser->parseArgs();
if (!$opts->object_id) {
throw new InvalidArgumentException('object_id is required');
}
$m = new Content_ObjectMapper($injector->getInstance('Horde_Db_Adapter'));
if ($m->delete($opts->object_id)) {
echo 'Deleted object with id ' . $opts->object_id . ".\n";
exit(0);
} else {
echo 'Object #' . $opts->object_id . " not found.\n";
exit(1);
}
content-2.0.6/bin/content-tag 0000775 0001750 0001750 00000002222 13160217705 014216 0 ustar jan jan #!/usr/bin/env php
get('horde_dir', null, 'pear.horde.org') . '/content/';
}
require_once $baseDir . 'lib/Application.php';
Horde_Registry::appInit('content', array('cli' => true));
$options = array(
new Horde_Argv_Option('-u', '--user-id', array('type' => 'int')),
new Horde_Argv_Option('-o', '--object-id', array('type' => 'int')),
);
$parser = new Horde_Argv_Parser(array('optionList' => $options));
list($opts, $tags) = $parser->parseArgs();
if (!$opts->user_id || !$opts->object_id) {
throw new InvalidArgumentException('user-id and object-id are both required');
}
if (!count($tags)) {
throw new InvalidArgumentException('List at least one tag to add.');
}
/* @TODO Switch to using the TagController */
$injector->getInstance('Content_Tagger')
->tag($opts->user_id, $opts->object_id, $tags);
exit(0);
content-2.0.6/bin/content-tag-add 0000775 0001750 0001750 00000002022 13160217705 014742 0 ustar jan jan #!/usr/bin/env php
get('horde_dir', null, 'pear.horde.org') . '/content/';
}
require_once $baseDir . 'lib/Application.php';
Horde_Registry::appInit('content', array('cli' => true));
$parser = new Horde_Argv_Parser();
list($opts, $tags) = $parser->parseArgs();
if (!count($tags)) {
throw new InvalidArgumentException('List at least one tag to add.');
}
require CONTENT_BASE . '/lib/Tags/Tag.php';
require CONTENT_BASE . '/lib/Tags/TagMapper.php';
$m = new Content_TagMapper($injector->getInstance('Horde_Db_Adapter'));
foreach ($tags as $tag) {
$t = $m->create(array('tag_name' => $tag));
echo 'Created new tag with id ' . $t->tag_id . ' and name "' . $t->tag_name . "\".\n";
}
exit(0);
content-2.0.6/bin/content-tag-delete 0000775 0001750 0001750 00000002307 13160217705 015462 0 ustar jan jan #!/usr/bin/env php
get('horde_dir', null, 'pear.horde.org') . '/content/';
}
require_once $baseDir . 'lib/Application.php';
Horde_Registry::appInit('content', array('cli' => true));
$parser = new Horde_Argv_Parser();
list($opts, $tags) = $parser->parseArgs();
if (!count($tags)) {
throw new InvalidArgumentException('List at least tag to delete.');
}
require CONTENT_BASE . '/lib/Tags/Tag.php';
require CONTENT_BASE . '/lib/Tags/TagMapper.php';
$m = new Content_TagMapper($injector->getInstance('Horde_Db_Adapter'));
foreach ($tags as $tag) {
$t = $m->findOne(array('tag_name' => $tag));
if (!$t) {
echo "$tag doesn't seem to exist, skipping it.\n";
continue;
}
if ($t->delete()) {
echo "Delete tag '$tag' (#".$t->tag_id.")\n";
continue;
} else {
echo "Failed to delete '$tag'\n";
exit(1);
}
}
exit(0);
content-2.0.6/bin/content-untag 0000775 0001750 0001750 00000002227 13160217705 014566 0 ustar jan jan #!/usr/bin/env php
get('horde_dir', null, 'pear.horde.org') . '/content/';
}
require_once $baseDir . 'lib/Application.php';
Horde_Registry::appInit('content', array('cli' => true));
$options = array(
new Horde_Argv_Option('-u', '--user-id', array('type' => 'int')),
new Horde_Argv_Option('-i', '--object-id', array('type' => 'int')),
);
$parser = new Horde_Argv_Parser(array('optionList' => $options));
list($opts, $tags) = $parser->parseArgs();
if (!$opts->user_id || !$opts->object_id) {
throw new InvalidArgumentException('user-id and object-id are both required');
}
if (!count($tags)) {
throw new InvalidArgumentException('List at least one tag to remove.');
}
/* @TODO Switch to using the TagController */
$injector->getInstance('Content_Tagger')
->untag($opts->user_id, $opts->object_id, $tags);
exit(0);
content-2.0.6/config/.htaccess 0000664 0001750 0001750 00000000174 13160217705 014344 0 ustar jan jan
Require all denied
Deny from all
content-2.0.6/config/routes.php 0000664 0001750 0001750 00000004376 13160217705 014610 0 ustar jan jan connect('tags', array('controller' => 'tag', 'action' => 'searchTags'));
$mapper->connect('tags.:(format)', array('controller' => 'tag', 'action' => 'searchTags'));
// Most recent tags. Available query parameters:
// typeId: restrict matches to tags that have been applied to objects with type $typeId
// userId: restrict matches to tags that have been applied by $userId
$mapper->connect('tags/recent', array('controller' => 'tag', 'action' => 'recentTags'));
$mapper->connect('tags/recent.:(format)', array('controller' => 'tag', 'action' => 'recentTags'));
// List objects. At least a content type, or more specific parameters, are
// required; listing all objects is not allowed.
$mapper->connect('objects', array('controller' => 'tag', 'action' => 'searchObjects'));
$mapper->connect('objects.:(format)', array('controller' => 'tag', 'action' => 'searchObjects'));
// List users. Specific parameters are required as listing all users is not
// allowed.
$mapper->connect('users', array('controller' => 'tag', 'action' => 'searchUsers'));
$mapper->connect('users.:(format)', array('controller' => 'tag', 'action' => 'searchUsers'));
// Tag an object. Required POST parameters are: tags (array or string list) and
// objectId. userId is inferred from the authenticated user:
$mapper->connect('tag', array('controller' => 'tag', 'action' => 'tag',
'conditions' => array('method' => array('POST', 'PUT'))));
// Untag an object. Required POST parameters are: tags (array or string list)
// and objectId. userId is inferred from the authenticated user:
$mapper->connect('untag', array('controller' => 'tag', 'action' => 'untag',
'conditions' => array('method' => array('POST', 'DELETE'))));
content-2.0.6/docs/CHANGES 0000600 0001750 0001750 00000002726 13160217705 013217 0 ustar jan jan ------
v2.0.6
------
[jan] Officially support PHP 7.
------
v2.0.5
------
[mjr] Fix bug that was causing tag stats to be incorrectly incremented (Bug
#14112).
[mjr] Add Content_Objects_Manager::delete().
[jan] Add unit tests for Oracle.
------
v2.0.4
------
[jan] Fix date format for 'created' column.
------
v2.0.3
------
[mjr] Fix obtaining tag cloud information when filtering by objectIds.
------
v2.0.2
------
[mjr] Fix logic that could possibly lead to incorrect content types being
applied to objects (Bug #12016).
------
v2.0.1
------
[jan] Add missing optional dependency on Horde_ElasticSearch.
[jan] Catch exceptions from Horde_ElasticSearch.
------
v2.0.0
------
[jan] Support Horde 5.
------
v1.0.3
------
[mjr] Honor the limit and radius parameters.
[mjr] Fix getObjects method when passing object_id (Bug# 10439).
[mjr] Fix including all non-aggregate fields in GROUP BY clause (Bug# 10419).
[jan] Fix commandline scripts (Bug #10656).
------
v1.0.2
------
[mjr] Fix broken tag cloud queries due to missing GROUP BY fields (Bug #10419)
[mjr] Prevent tagging with empty strings.
------
v1.0.1
------
[mjr] Enforce that object and type names are always taken as a string (Bug
#10171).
[mjr] Updated unit tests to new test structure.
[mjr] Prevent tagging with empty tags.
------
v1.0.0
------
[jan] Fix case-insensitive filtering of duplicate tags (Bug #9617).
[jan] Rename all scripts to be prefixed with content- (Request #9647).
content-2.0.6/docs/RELEASE_NOTES 0000664 0001750 0001750 00000000061 13160217705 014177 0 ustar jan jan
* @author Michael Rubinsky
* @license http://www.horde.org/licenses/bsd BSD
* @category Horde
* @package Horde_Content
*/
/**
* @author Chuck Hagenbuch
* @author Michael Rubinsky
* @license http://www.horde.org/licenses/bsd BSD
* @category Horde
* @package Horde_Content
*/
class Content_Objects_Manager
{
/**
* Database adapter
*
* @var Horde_Db_Adapter
*/
protected $_db;
/**
* Tables
*
* @TODO: this should probably be populated by the responsible manager...
* @var array
*/
protected $_tables = array(
'objects' => 'rampage_objects',
);
/**
* Type manager
*
* @var Content_Types_Manager
*/
protected $_typeManager;
/**
* Constructor
*
* @param Horde_Db_Adapter $db The db adapter
* @param Content_Types_Manager $typeManager A content type manager
*
* @return Content_Objects_Manager
*/
public function __construct(Horde_Db_Adapter $db, Content_Types_Manager $typeManager)
{
$this->_db = $db;
$this->_typeManager = $typeManager;
}
/**
* Check for object existence without causing the objects to be created.
* Helps save queries for things like tags when we already know the object
* doesn't yet exist in rampage tables.
*
* @param mixed string|array $objects Either an object identifier or an
* array of them.
* @param mixed $type A type identifier. Either a string
* type name or the integer type_id.
*
* @return mixed Either a hash of object_id => object_names or false if
* the object(s) do not exist.
* @throws InvalidArgumentException, Content_Exception
*/
public function exists($objects, $type)
{
$type = current($this->_typeManager->ensureTypes($type));
if (!is_array($objects)) {
$objects = array($objects);
}
if (!count($objects)) {
return array();
}
// Ensure we take the object as a string indentifier.
foreach ($objects as &$object) {
$object = strval($object);
}
$params = $objects;
$params[] = $type;
try {
$ids = $this->_db->selectAssoc(
'SELECT object_id, object_name FROM ' . $this->_t('objects')
. ' WHERE object_name IN ('
. str_repeat('?,', count($objects) - 1) . '?)'
. ' AND type_id = ?', $params);
if ($ids) {
return $ids;
}
} catch (Horde_Db_Exception $e) {
throw new Content_Exception($e);
}
return false;
}
/**
* Remove the object.
* NOTE: This does not ensure any references to this object were removed.
* E.g., does not remove any tags etc... That is client code's
* responsibility.
*
* @param array $objects An array of object identifiers to delete.
* @param string $type The type of the objects. All objects must be of
* the same type.
*
* @throws Content_Exception
*/
public function delete(array $objects, $type)
{
$type = current($this->_typeManager->ensureTypes($type));
// Ensure we take the object as a string indentifier.
foreach ($objects as &$object) {
$object = strval($object);
}
$params = $objects;
$params[] = $type;
try {
$this->_db->delete(
'DELETE FROM ' . $this->_t('objects') . ' WHERE object_name IN ('
. str_repeat('?,', count($objects) - 1) . '?)'
. ' AND type_id = ?',
$params
);
} catch (Horde_Db_Exception $e) {
throw new Content_Exception($e);
}
}
/**
* Ensure that an array of objects exist in storage. Create any that don't,
* return object_ids for all. All objects in the $objects array must be
* of the same content type.
*
* @param mixed $objects An array of objects (or single obejct value).
* Values typed as an integer are assumed to already
* be an object_id.
* @param mixed $type Either a string type_name or integer type_id
*
* @return array An array of object_ids.
*/
public function ensureObjects($objects, $type)
{
if (!is_array($objects)) {
$objects = array($objects);
}
$objectIds = array();
$objectName = array();
$type = current($this->_typeManager->ensureTypes($type));
// Anything already typed as an integer is assumed to be an object id.
foreach ($objects as $objectIndex => $object) {
if (is_int($object)) {
$objectIds[$objectIndex] = $object;
} else {
$objectName[$object] = $objectIndex;
}
}
// Get the ids for any objects that already exist.
try {
if (count($objectName)) {
$rows = $this->_db->selectAll(
'SELECT object_id, object_name FROM ' . $this->_t('objects')
. ' WHERE object_name IN ('
. implode(',', array_map(array($this->_db, 'quoteString'), array_keys($objectName)))
. ') AND type_id = ' . $type);
foreach ($rows as $row) {
$objectIndex = $objectName[$row['object_name']];
unset($objectName[$row['object_name']]);
$objectIds[$objectIndex] = $row['object_id'];
}
}
// Create any objects that didn't already exist
foreach ($objectName as $object => $objectIndex) {
$objectIds[$objectIndex] = $this->_db->insert('INSERT INTO '
. $this->_t('objects') . ' (object_name, type_id) VALUES ('
. $this->_db->quoteString($object) . ', ' . $type . ')');
}
} catch (Horde_Db_Exception $e) {
throw new Content_Exception($e);
}
return $objectIds;
}
/**
* 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]);
}
}
content-2.0.6/lib/Objects/Object.php 0000664 0001750 0001750 00000000412 13160217705 015352 0 ustar jan jan
* @license http://www.horde.org/licenses/bsd BSD
* @category Horde
* @package Horde_Content
*/
class Content_Object extends Horde_Rdo_Base
{
}
content-2.0.6/lib/Relationships/Relationship.php 0000664 0001750 0001750 00000000000 13160217705 020031 0 ustar jan jan content-2.0.6/lib/Relationships/RelationshipMapper.php 0000664 0001750 0001750 00000000000 13160217705 021176 0 ustar jan jan content-2.0.6/lib/Tags/Tag.php 0000664 0001750 0001750 00000000407 13160217705 014170 0 ustar jan jan
* @license http://www.horde.org/licenses/bsd BSD
* @category Horde
* @package Horde_Content
*/
class Content_Tag extends Horde_Rdo_Base
{
}
content-2.0.6/lib/Tags/TagMapper.php 0000664 0001750 0001750 00000000577 13160217705 015345 0 ustar jan jan
* @license http://www.horde.org/licenses/bsd BSD
* @category Horde
* @package Horde_Content
*/
class Content_TagMapper extends Horde_Rdo_Mapper
{
/**
* Inflector doesn't support Horde-style tables yet
*/
protected $_table = 'rampage_tags';
}
content-2.0.6/lib/Types/Manager.php 0000664 0001750 0001750 00000005453 13160217705 015243 0 ustar jan jan
* @author Michael Rubinsky
* @license http://www.horde.org/licenses/bsd BSD
* @category Horde
* @package Horde_Content
*/
class Content_Types_Manager
{
/**
* Database adapter
* @var Horde_Db_Adapter
*/
protected $_db;
/**
* Tables
* @var array
*/
protected $_tables = array(
'types' => 'rampage_types',
);
public function __construct(Horde_Db_Adapter $db)
{
$this->_db = $db;
}
/**
* Ensure that an array of types exist in storage. Create any that don't,
* return type_ids for all.
*
* @param mixed $types An array of types or single type value. Values typed
* as an integer are assumed to already be an type_id.
*
* @return array An array of type_ids.
* @throws Content_Exception
*/
public function ensureTypes($types)
{
if (!is_array($types)) {
$types = array($types);
}
$typeIds = array();
$typeName = array();
// Anything already typed as an integer is assumed to be a type id.
foreach ($types as $typeIndex => $type) {
if (is_int($type)) {
$typeIds[$typeIndex] = $type;
} else {
$typeName[$type] = $typeIndex;
}
}
try {
// Get the ids for any types that already exist.
if (count($typeName)) {
$rows = $this->_db->selectAssoc('SELECT type_id, type_name FROM '
. $this->_t('types') . ' WHERE type_name IN ('
. implode(',', array_map(array($this->_db, 'quoteString'), array_keys($typeName)))
. ')');
foreach ($rows as $id => $type) {
$typeIndex = $typeName[$type];
unset($typeName[$type]);
$typeIds[$typeIndex] = (int)$id;
}
}
// Create any types that didn't already exist
foreach ($typeName as $type => $typeIndex) {
$typeIds[$typeIndex] = intval($this->_db->insert(
'INSERT INTO ' . $this->_t('types')
. ' (type_name) VALUES ('
. $this->_db->quoteString($type) . ')'));
}
} catch (Horde_Db_Exception $e) {
throw new Content_Exception($e);
}
return $typeIds;
}
/**
* 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]);
}
}
content-2.0.6/lib/Users/Manager.php 0000664 0001750 0001750 00000005510 13160217705 015232 0 ustar jan jan
* @author Michael Rubinsky
* @license http://www.horde.org/licenses/bsd BSD
* @category Horde
* @package Horde_Content
*/
class Content_Users_Manager
{
/**
* Database adapter
* @var Horde_Db_Adapter
*/
protected $_db;
/**
* Tables
* @var array
*/
protected $_tables = array(
'users' => 'rampage_users',
);
public function __construct(Horde_Db_Adapter $db)
{
$this->_db = $db;
}
/**
* Ensure that an array of users exist in storage. Create any that don't,
* return user_ids for all.
*
* @param array $users An array of users. Values typed as an integer
* are assumed to already be an user_id.
*
* @return array An array of user_ids.
*/
public function ensureUsers($users)
{
if (!is_array($users)) {
$users = array($users);
}
$userIds = array();
$userName = array();
// Anything already typed as an integer is assumed to be a user id.
foreach ($users as $userIndex => $user) {
if (is_int($user)) {
$userIds[$userIndex] = $user;
} else {
$userName[$user] = $userIndex;
}
}
// Get the ids for any users that already exist.
try {
if (count($userName)) {
$userName;
$sql = 'SELECT user_id, user_name FROM ' . $this->_t('users')
. ' WHERE user_name IN (' . implode(',', array_map(array($this, 'toDriver'), array_keys($userName))) . ')';
foreach ($this->_db->selectAll($sql) as $row) {
$userIndex = $userName[$row['user_name']];
unset($userName[$row['user_name']]);
$userIds[$userIndex] = $row['user_id'];
}
}
// Create any users that didn't already exist
foreach ($userName as $user => $userIndex) {
$userIds[$userIndex] = $this->_db->insert('INSERT INTO ' . $this->_t('users') . ' (user_name) VALUES (' . $this->toDriver($user) . ')');
}
} catch (Horde_Db_Exception $e) {
throw new Content_Exception($e);
}
return $userIds;
}
/**
* 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.6/lib/.htaccess 0000664 0001750 0001750 00000000174 13160217705 013645 0 ustar jan jan
Require all denied
Deny from all
content-2.0.6/lib/Application.php 0000664 0001750 0001750 00000002041 13160217705 015016 0 ustar jan jan
* @license http://www.horde.org/licenses/bsd BSD
* @category Horde
* @package Horde_Content
*/
class Content_Indexer
{
/**
* ElasticSearch client
* @var Horde_ElasticSearch_Client
*/
protected $_es;
/**
* User manager object
* @var Content_Users_Manager
*/
protected $_userManager;
/**
* Type management object
* @var Content_Types_Manager
*/
protected $_typeManager;
/**
* Object manager
* @var Content_Objects_Manager
*/
protected $_objectManager;
/**
* Constructor
*/
public function __construct(Horde_ElasticSearch_Client $es,
Content_Users_Manager $userManager,
Content_Types_Manager $typeManager,
Content_Objects_Manager $objectManager)
{
$this->_es = $es;
$this->_userManager = $userManager;
$this->_typeManager = $typeManager;
$this->_objectManager = $objectManager;
}
public function index($index, $type, $id, $data)
{
try {
$this->_es->add($index, $type, $id, $data);
} catch (Horde_ElasticSearch_Exception $e) {
throw new Content_Exception($e);
}
}
public function search($index, $type, $query)
{
try {
return $this->_es->search($index, $type, $query);
} catch (Horde_ElasticSearch_Exception $e) {
throw new Content_Exception($e);
}
}
/**
* 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;
}
}
content-2.0.6/lib/ObjectMapper.php 0000664 0001750 0001750 00000001122 13160217705 015125 0 ustar jan jan
* @license http://www.horde.org/licenses/bsd BSD
* @category Horde
* @package Horde_Content
*/
/**
* @author Chuck Hagenbuch
* @license http://www.horde.org/licenses/bsd BSD
* @category Horde
* @package Horde_Content
*
* @todo Change name to Content_Objects_Mapper
*/
class Content_ObjectMapper extends Horde_Rdo_Mapper
{
/**
* Inflector doesn't support Horde-style tables yet
*/
protected $_table = 'rampage_objects';
}
content-2.0.6/lib/Tagger.php 0000664 0001750 0001750 00000116146 13160217705 014000 0 ustar jan jan
* @author Michael J. Rubinsky
* @license http://www.horde.org/licenses/bsd BSD
* @category Horde
* @package Horde_Content
*
* References:
* http://forge.mysql.com/wiki/TagSchema
* http://www.slideshare.net/edbond/tagging-and-folksonomy-schema-design-for-scalability-and-performance
* http://blog.thinkphp.de/archives/124-An-alternative-Approach-to-Tagging.html
* http://code.google.com/p/freetag/
*
* @TODO:
* need to add type_id to the rampage_tagged table for performance?
* need stat tables by type_id?
*
* Potential features:
* Infer data from combined tags (capital + washington d.c. - http://www.slideshare.net/kakul/tagging-web-2-expo-2008/)
* Normalize tag text (http://tagsonomy.com/index.php/interview-with-gordon-luk-freetag/)
*/
class Content_Tagger
{
/**
* Database connection
* @var Horde_Db_Adapter
*/
protected $_db;
/**
* Tables
* @var array
*/
protected $_tables = array(
'tags' => 'rampage_tags',
'tagged' => 'rampage_tagged',
'objects' => 'rampage_objects',
'tag_stats' => 'rampage_tag_stats',
'user_tag_stats' => 'rampage_user_tag_stats',
'users' => 'rampage_users',
'types' => 'rampage_types',
);
/**
* User manager object
* @var Content_Users_Manager
*/
protected $_userManager;
/**
* Type management object
* @var Content_Types_Manager
*/
protected $_typeManager;
/**
* Object manager
* @var Content_Objects_Manager
*/
protected $_objectManager;
/**
* Default radius for relationship queries.
* @var integer
*/
protected $_defaultRadius = 10;
/**
* Constructor
*/
public function __construct(Horde_Db_Adapter $db,
Content_Users_Manager $userManager,
Content_Types_Manager $typeManager,
Content_Objects_Manager $objectManager)
{
$this->_db = $db;
$this->_userManager = $userManager;
$this->_typeManager = $typeManager;
$this->_objectManager = $objectManager;
}
/**
* Adds a tag or several tags to an object_id. This method does not
* remove other tags.
*
* @param mixed $userId The user tagging the object.
* @param mixed $objectId The object id to tag or an array containing
* the object_name and type.
* @param array $tags An array of tag name or ids.
* @param Horde_Date $created The datetime of the tagging operation.
*
* @return void
*/
public function tag($userId, $objectId, $tags, Horde_Date $created = null)
{
if (is_null($created)) {
$created = date('Y-m-d H:i:s');
} else {
$created = $created->format('Y-m-d H:i:s');
}
// Make sure the object exists
$objectId = $this->_ensureObject($objectId);
// Validate/ensure the parameters
$userId = current($this->_userManager->ensureUsers($userId));
foreach ($this->ensureTags($tags) as $tagId) {
if (!$this->_db->selectValue('SELECT 1 from ' . $this->_t('tagged') . ' WHERE user_id = ? AND object_id = ? AND tag_id = ?', array((int)$userId, (int)$objectId, (int)$tagId))) {
try {
$this->_db->insert(
'INSERT INTO ' . $this->_t('tagged') . ' (user_id, object_id, tag_id, created) VALUES (?, ?, ?, ?)',
array((int)$userId, (int)$objectId, (int)$tagId, $created));
} catch (Horde_Db_Exception $e) {
throw new Content_Exception($e);
}
// increment tag stats
if (!$this->_db->update('UPDATE ' . $this->_t('tag_stats') . ' SET count = count + 1 WHERE tag_id = ' . (int)$tagId)) {
$this->_db->insert('INSERT INTO ' . $this->_t('tag_stats') . ' (tag_id, count) VALUES (' . (int)$tagId . ', 1)', null, null, 'tag_id', $tagId);
}
// increment user-tag stats
if (!$this->_db->update('UPDATE ' . $this->_t('user_tag_stats') . ' SET count = count + 1 WHERE user_id = ' . (int)$userId . ' AND tag_id = ' . (int)$tagId)) {
$this->_db->insert('INSERT INTO ' . $this->_t('user_tag_stats') . ' (user_id, tag_id, count) VALUES (' . (int)$userId . ', ' . (int)$tagId . ', 1)');
}
}
}
}
/**
* Undo a user's tagging of an object.
*
* @param mixed $userId The user who tagged the object.
* @param mixed $objectId The object to remove the tag from.
* @param array $tags An array of tag name or ids to remove.
*/
public function untag($userId, $objectId, $tags)
{
// Ensure parameters
$userId = current($this->_userManager->ensureUsers($userId));
$objectId = $this->_ensureObject($objectId);
foreach ($this->ensureTags($tags) as $tagId) {
if ($this->_db->delete('DELETE FROM ' . $this->_t('tagged') . ' WHERE user_id = ? AND object_id = ? AND tag_id = ?', array($userId, $objectId, $tagId))) {
$this->_db->update('UPDATE ' . $this->_t('tag_stats') . ' SET count = count - 1 WHERE tag_id = ?', array($tagId));
$this->_db->update('UPDATE ' . $this->_t('user_tag_stats') . ' SET count = count - 1 WHERE user_id = ? AND tag_id = ?', array($userId, $tagId));
}
}
// Cleanup
$this->_db->delete('DELETE FROM ' . $this->_t('tag_stats') . ' WHERE count = 0');
$this->_db->delete('DELETE FROM ' . $this->_t('user_tag_stats') . ' WHERE count = 0');
}
/**
* Remove all occurrences of a specific tag from an object regardless of
* the username who tagged the object originally.
*
* @param mixed $obejctId The object identifier @see Content_Tagger::tag()
* @param mixed $tags The tags to remove. @see Content_Tagger::tag()
*
* @return void
*/
public function removeTagFromObject($objectId, $tags)
{
$objectId = $this->_ensureObject($objectId);
if (!is_array($tags)) {
$tags = array($tags);
}
foreach ($this->ensureTags($tags) as $tagId) {
// Get the users who have tagged this so we can update the stats
$users = $this->_db->selectValues('SELECT user_id, tag_id FROM ' . $this->_t('tagged') . ' WHERE object_id = ? AND tag_id = ?', array($objectId, $tagId));
// Delete the tags
if ($this->_db->delete('DELETE FROM ' . $this->_t('tagged') . ' WHERE object_id = ? AND tag_id = ?', array($objectId, $tagId))) {
// Update the stats
$this->_db->update('UPDATE ' . $this->_t('tag_stats') . ' SET count = count - ' . count($users) . ' WHERE tag_id = ?', array($tagId));
$this->_db->update('UPDATE ' . $this->_t('user_tag_stats') . ' SET count = count - 1 WHERE user_id IN(' . str_repeat('?, ', count($users) - 1) . '?) AND tag_id = ?', array_merge($users, array($tagId)));
// Housekeeping
$this->_db->delete('DELETE FROM ' . $this->_t('tag_stats') . ' WHERE count = 0');
$this->_db->delete('DELETE FROM ' . $this->_t('user_tag_stats') . ' WHERE count = 0');
}
}
}
/**
* Obtain all the tags for a given set of objects.
*
* @param mixed string|array $objects A local object id or an array of
* local object id strings.
* @param mixed $type Either a string type description, or
* an integer content type_id
*
* @return array An array in the form of:
*