From 3a5c84b94c08c89d7c1886d550dedac9d939b64e Mon Sep 17 00:00:00 2001 From: Jalaloedien Abrahams Date: Thu, 15 Feb 2007 13:49:52 +0000 Subject: [PATCH] KTS-1557 "Implement Tag Cloud system. " Implemented. --- lib/browse/Criteria.inc | 39 +++++++++++++++++++++++++++++++++++++++ lib/browse/criteriaregistry.php | 1 + lib/documentmanagement/documentutil.inc.php | 2 ++ plugins/ktcore/document/edit.php | 1 + plugins/tagcloud/TagCloudDashlet.php | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ plugins/tagcloud/TagCloudPlugin.php | 384 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ plugins/tagcloud/TagCloudRedirectPage.php | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ plugins/tagcloud/templates/TagCloud/dashlet.smarty | 30 ++++++++++++++++++++++++++++++ 8 files changed, 735 insertions(+), 0 deletions(-) create mode 100644 plugins/tagcloud/TagCloudDashlet.php create mode 100644 plugins/tagcloud/TagCloudPlugin.php create mode 100644 plugins/tagcloud/TagCloudRedirectPage.php create mode 100644 plugins/tagcloud/templates/TagCloud/dashlet.smarty diff --git a/lib/browse/Criteria.inc b/lib/browse/Criteria.inc index bc0348c..821546d 100644 --- a/lib/browse/Criteria.inc +++ b/lib/browse/Criteria.inc @@ -1041,7 +1041,46 @@ class TransactionTextCriterion extends BrowseCriterion { } } +class TagCloudCriterion extends BrowseCriterion { + var $bString = true; + var $bContains = false; + var $bHandleNot = false; + var $sDocumentField = 'tag';// this is linked to the field + var $sSortField = 'tag'; + var $sNamespace = 'ktcore.criteria.tagcloud'; + var $sSearchTable = "TWS" ; + + function TagCloudCriterion() { + $this->sDisplay = _kt('Tag Cloud'); + } + + function documentDisplay ($oDocument) { + return "Tag Cloud"; + } + function getName() { + return "tagcloud"; + } + + function searchSQL ($aRequest) { + $p = parent::searchSQL($aRequest, false); // handle not ourselves. + + // handle the boolean "not" stuff. + $want_invert = KTUtil::arrayGet($aRequest, $this->getWidgetBase() . '_not'); + if (is_null($want_invert) || ($want_invert == "0")) { + return $p; + } else { + $p[0] = '(NOT (' . $p[0] . '))'; + } + + return $p; + } + function searchJoinSQL () { + global $default; + return "INNER JOIN document_tags AS DTS ON DTS.document_id = D.id + INNER JOIN tag_words AS TWS ON tws.id = DTS.tag_id"; + } +} class DateCreatedDeltaCriterion extends DateCreatedCriterion { var $sDocumentField = 'created'; diff --git a/lib/browse/criteriaregistry.php b/lib/browse/criteriaregistry.php index 3d72966..575872d 100644 --- a/lib/browse/criteriaregistry.php +++ b/lib/browse/criteriaregistry.php @@ -44,6 +44,7 @@ class KTCriteriaRegistry { foreach($aFields as $oField) { $sNamespace = $oField->getNamespace(); $oFieldset =& KTFieldset::get($oField->getParentFieldset()); + if(is_null($oFieldset->userinfo)){continue;} $aInitialize = array(sprintf("%s: %s", $oFieldset->getName(), $oField->getName()), 'id', 'id', $oField->getId(), $sNamespace); $this->registerCriterion('GenericMetadataCriterion', $sNamespace, null, $aInitialize); } diff --git a/lib/documentmanagement/documentutil.inc.php b/lib/documentmanagement/documentutil.inc.php index 06d889e..eb26904 100644 --- a/lib/documentmanagement/documentutil.inc.php +++ b/lib/documentmanagement/documentutil.inc.php @@ -422,6 +422,7 @@ class KTDocumentUtil { // {{{ _in_add function &_in_add($oFolder, $sFilename, $oUser, $aOptions) { + $aOrigOptions = $aOptions; if (KTDocumentUtil::fileExists($oFolder, $sFilename)) { $oDoc = Document::getByFilenameAndFolder($sFilename, $oFolder->getId()); if (PEAR::isError($oDoc)) { @@ -514,6 +515,7 @@ class KTDocumentUtil { $oTrigger = new $sTrigger; $aInfo = array( "document" => $oDocument, + 'aOptions' => $aOrigOptions, ); $oTrigger->setInfo($aInfo); $ret = $oTrigger->postValidate(); diff --git a/plugins/ktcore/document/edit.php b/plugins/ktcore/document/edit.php index 7cec69b..6363ba0 100644 --- a/plugins/ktcore/document/edit.php +++ b/plugins/ktcore/document/edit.php @@ -205,6 +205,7 @@ class KTDocumentEditAction extends KTDocumentAction { $oTrigger = new $sTrigger; $aInfo = array( "document" => $this->oDocument, + "aOptions" => $MDPack, ); $oTrigger->setInfo($aInfo); $ret = $oTrigger->postValidate(); diff --git a/plugins/tagcloud/TagCloudDashlet.php b/plugins/tagcloud/TagCloudDashlet.php new file mode 100644 index 0000000..11d37cb --- /dev/null +++ b/plugins/tagcloud/TagCloudDashlet.php @@ -0,0 +1,149 @@ +sTitle = _kt('Tag Cloud'); + } + + /** + * Check to see if user is active + * + * @param object $oUser + * @return boolean + */ + function is_active($oUser) { + $this->oUser = $oUser; + return true; + } + + /** + * Render function for template + * + * @return unknown + */ + function render() { + $oTemplating =& KTTemplating::getSingleton(); + $oTemplate = $oTemplating->loadTemplate('TagCloud/dashlet'); + + $aTags = & $this->get_relevant_tags(); + $aTags = & $this->get_tag_weightings($aTags); + + $oRegistry =& KTPluginRegistry::getSingleton(); + $oPlugin =& $oRegistry->getPlugin('ktcore.tagcloud.plugin'); + $url = $oPlugin->getPagePath('TagCloudRedirection'); + + $aTemplateData = array( + 'tags' => $aTags, + 'url'=>$url + ); + return $oTemplate->render($aTemplateData); + } + + /** + * Builds the weightings for tags based on their frequency + * + * @param array $aTags + * @return array + */ + function & get_tag_weightings(&$aTags) + { + $aTags = $this->get_relevant_tags(); + + if (count($aTags) == 0) $min_freq=$max_freq=0; + else + { + $min_freq = min(array_values($aTags)); + $max_freq = max(array_values($aTags)); + } + $min_size = 12; + $max_size = 30; + + $distrib = $max_freq - $min_freq; + if ($distrib == 0) $distrib=1; + + $step = ($max_size - $min_size)/($distrib); + + foreach($aTags as $tag=>$freq) + { + $size = ceil($min_size + (($freq - $min_freq) * $step)); + $aTags[$tag] = $size; + } + + return $aTags; + } + + /** + * Returns the relevant tags for the current user + * + * @return array + */ + function & get_relevant_tags() + { + + list($where, $params, $joins) = KTSearchUtil::permissionToSQL($this->oUser, null); + + + $sql = " + SELECT + tw.tag, count(*) as freq + FROM + document_tags dt INNER JOIN tag_words tw ON dt.tag_id=tw.id + WHERE dt.document_id in (SELECT d.id FROM documents d $joins WHERE $where) GROUP BY tw.tag"; + + + $tags = DBUtil::getResultArray( + array($sql,$params) + + ); + $aTags = array(); + foreach($tags as $tag) + { + $word=$tag['tag']; + $freq=$tag['freq']; + $aTags[$word] = $freq; + } + return $aTags; + + } + +} +?> diff --git a/plugins/tagcloud/TagCloudPlugin.php b/plugins/tagcloud/TagCloudPlugin.php new file mode 100644 index 0000000..26fc4a6 --- /dev/null +++ b/plugins/tagcloud/TagCloudPlugin.php @@ -0,0 +1,384 @@ +sFriendlyName = _kt('Tag Cloud Plugin'); + return $res; + } + + /** + * Setup function for plugin + * + */ + function setup() { + // Register plugin components + $this->registerCriterion('TagCloudCriterion', 'ktcore.criteria.tagcloud', KT_LIB_DIR . '/browse/Criteria.inc'); + $this->registerDashlet('TagCloudDashlet', 'ktcore.tagcloud.feed.dashlet', 'TagCloudDashlet.php'); + $this->registerPage('TagCloudRedirection', 'TagCloudRedirectPage', __FILE__); + $this->registerTrigger('add', 'postValidate', 'KTAddDocumentTrigger', + 'ktcore.triggers.tagcloud.add'); + $this->registerTrigger('edit', 'postValidate', 'KTEditDocumentTrigger', + 'ktcore.triggers.tagcloud.edit'); + + // Check if the tagcloud fielset entry exists, if not, create it + if(!TagCloudPlugin::tagFieldsetExists()){ + $oFieldset = TagCloudPlugin::createFieldset(); + if (PEAR::isError($oFieldset)) { + return false; + } + if($oFieldset){ + // make the fieldset id viewable + $iFieldsetId = $oFieldset->iId; + } + }else{ // if the entry exists, make the fieldset id viewable anyway + $iFieldsetId = TagCloudPlugin::tagFieldsetExists(); + } + + // Check if the tagcloud document field entry exists, if not, create it + if(!TagCloudPlugin::tagFieldExists()){ + $oField = TagCloudPlugin::createDocumentField($iFieldsetId); + if (PEAR::isError($oField)) { + return false; + } + } + + $oTemplating =& KTTemplating::getSingleton(); + $oTemplating->addLocation('Tag Cloud Plugin', '/plugins/tagcloud/templates'); + } + + /** + * function to add fieldset entry to fieldsets table + * + * @return unknown + */ + function createFieldset(){ + // create the fieldsets entry + $oFieldset = KTFieldset::createFromArray(array( + 'name' => 'Tag Cloud', + 'description' => 'Tag Cloud', + 'namespace' => 'tagcloud', + 'mandatory' => false, + 'isConditional' => false, + 'isGeneric' => true, + 'isComplete' => false, + 'isComplex' => false, + 'isSystem' => false, + )); + + return $oFieldset; + } + + /** + * function to add the tagcloud entry to the document_fields table + * + * @param int $parentId + * @return int $id + */ + function createDocumentField($parentId){ + // create the document_field entry + $id = DocumentField::createFromArray(array( + 'Name' => 'Tag', + 'Description' => 'Tag Words', + 'DataType' => 'STRING', + 'IsGeneric' => false, + 'HasLookup' => false, + 'HasLookupTree' => false, + 'ParentFieldset' => $parentId, + 'IsMandatory' => false, + )); + + return $id; + } + + /** + * function to check if the Tag field exists in the document_fields table + * + * @return boolean + */ + function tagFieldExists(){ + $sQuery = 'SELECT df.id AS id FROM document_fields AS df ' . + 'WHERE df.name = \'Tag\''; + $sTag = DBUtil::getOneResultKey(array($sQuery), 'id'); + + if (PEAR::isError($sTag)) { + // XXX: log error + return false; + + } + if(!is_null($sTag)){ + return $sTag; + }else{ + return false; + } + } + + /** + * function to check if the fieldset exists in the database + * + * @return boolean + */ + function tagFieldsetExists(){ + $sQuery = 'SELECT fs.id AS id FROM fieldsets AS fs '. + 'WHERE namespace = \'tagcloud\''; + $iFieldset = DBUtil::getOneResultKey(array($sQuery), 'id'); + + if (PEAR::isError($iFieldset)) { + // XXX: log error + return false; + + } + if(!is_null($iFieldset)){ + return $iFieldset; + }else{ + return false; + } + } + } +$oPluginRegistry =& KTPluginRegistry::getSingleton(); +$oPluginRegistry->registerPlugin('TagCloudPlugin', 'ktcore.tagcloud.plugin', __FILE__); + +/** + * Trigger for document add (postValidate) + * + */ +class KTAddDocumentTrigger { + var $aInfo = null; + /** + * function to set the info for the trigger + * + * @param array $aInfo + */ + function setInfo(&$aInfo) { + $this->aInfo =& $aInfo; + } + + /** + * postValidate method for trigger + * + * @return unknown + */ + function postValidate() { + global $default; + $oDocument =& $this->aInfo['document']; + $aMeta = & $this->aInfo['aOptions']; + + $iDocId = $oDocument->getID(); + + // get tag id from document_fields table where name = Tag + $sQuery = 'SELECT df.id AS id FROM document_fields AS df ' . + 'WHERE df.name = \'Tag\''; + + $sTags = DBUtil::getOneResultKey(array($sQuery), 'id'); + if (PEAR::isError($sTags)) { + // XXX: log error + return false; + } + $tagString = ''; + // add tags + if ($sTags) { + foreach($aMeta[metadata] as $aMetaData){ + $oProxy = $aMetaData[0]; + if($oProxy->iId == $sTags){ + $tagString = $aMetaData[1]; + } + } + if($tagString != ''){ + $words_table = KTUtil::getTableName('tag_words'); + $tagString = str_replace(' ', '', $tagString); + $tags = explode(',',$tagString); + + $aTagIds = array(); + + foreach($tags as $sTag) + { + $sTag=strtolower(trim($sTag)); + + $res = DBUtil::getOneResult(array("SELECT id FROM $words_table WHERE tag = ?", array($sTag))); + + if (PEAR::isError($res)) { + return $res; + } + + if (is_null($res)) + { + $id = & DBUtil::autoInsert($words_table, array('tag'=>$sTag)); + $aTagIds[$sTag] = $id; + } + else + { + $aTagIds[$sTag] = $res['id']; + } + } + + $doc_tags = KTUtil::getTableName('document_tags'); + + foreach($aTagIds as $sTag=>$tagid) + { + DBUtil::autoInsert($doc_tags, array( + + 'document_id'=>$iDocId, + 'tag_id'=>$tagid), + array('noid'=>true)); + } + } + } + } +} + +/** + * Trigger for document edit (postValidate) + * + */ +class KTEditDocumentTrigger { + var $aInfo = null; + /** + * function to set the info for the trigger + * + * @param array $aInfo + */ + function setInfo(&$aInfo) { + $this->aInfo =& $aInfo; + } + + /** + * postValidate method for trigger + * + * @return unknown + */ + function postValidate() { + global $default; + $oDocument =& $this->aInfo['document']; + $aMeta = & $this->aInfo['aOptions']; + // get document id + $iDocId = $oDocument->getID(); + + // get all tags that are linked to the document + $sQuery = 'SELECT tw.id FROM tag_words AS tw, document_tags AS dt, documents AS d ' . + 'WHERE dt.tag_id = tw.id ' . + 'AND dt.document_id = d.id ' . + 'AND d.id = ?'; + $aParams = array($iDocId); + $aTagId = DBUtil::getResultArray(array($sQuery, $aParams)); + if (PEAR::isError($aTagId)) { + // XXX: log error + return false; + } + // if there are any related tags proceed + if ($aTagId) { + // delete all entries from document_tags table for the document + $sQuery = 'DELETE FROM document_tags ' . + 'WHERE document_id = ?'; + $aParams = array($iDocId); + $removed = DBUtil::runQuery(array($sQuery, $aParams)); + if (PEAR::isError($removed)) { + // XXX: log error + return false; + } + } + // proceed to add the tags as per normal + if($res){ + $sQuery = 'SELECT df.id AS id FROM document_fields AS df ' . + 'WHERE df.name = \'Tag\''; + + $sTags = DBUtil::getOneResultKey(array($sQuery), 'id'); + if (PEAR::isError($sTags)) { + // XXX: log error + return false; + } + $tagString = ''; + if ($sTags) { + foreach($aMeta as $aMetaData){ + $oProxy = $aMetaData[0]; + if($oProxy->iId == $sTags){ + $tagString = $aMetaData[1]; + break; + } + } + if($tagString != ''){ + $words_table = KTUtil::getTableName('tag_words'); + $tagString = str_replace(' ', ' ', $tagString); + $tags = explode(',',$tagString); + + $aTagIds = array(); + + foreach($tags as $sTag) + { + $sTag=strtolower(trim($sTag)); + + $res = DBUtil::getOneResult(array("SELECT id FROM $words_table WHERE tag = ?", array($sTag))); + + if (PEAR::isError($res)) { + return $res; + } + + if (is_null($res)) + { + $id = & DBUtil::autoInsert($words_table, array('tag'=>$sTag)); + $aTagIds[$sTag] = $id; + } + else + { + $aTagIds[$sTag] = $res['id']; + } + } + + $doc_tags = KTUtil::getTableName('document_tags'); + + foreach($aTagIds as $sTag=>$tagid) + { + DBUtil::autoInsert($doc_tags, array( + 'document_id'=>$iDocId, + 'tag_id'=>$tagid), + array('noid'=>true)); + } + } + } + } + } +} +?> diff --git a/plugins/tagcloud/TagCloudRedirectPage.php b/plugins/tagcloud/TagCloudRedirectPage.php new file mode 100644 index 0000000..94cc5a8 --- /dev/null +++ b/plugins/tagcloud/TagCloudRedirectPage.php @@ -0,0 +1,129 @@ +aBreadcrumbs[] = array('url' => 'dashboard.php', 'name' => _kt('Dashboard')); + $this->aBreadcrumbs[] = array('url' => $_SERVER['PHP_SELF'].'&tag='.$searchable_text, 'name' => _kt('Tag Cloud Search')); + // set page title + $sTitle = _kt('Search Results'); + + $this->oPage->setBreadcrumbDetails($sTitle); + + // build criteria set + $aCriteriaSet = array( + 'join'=>'AND', + 'subgroup'=>array( + 0=>array( + 'join'=>'AND', + 'values'=>array( + 1=>array( + 'data'=>array( + 'ktcore.criteria.tagcloud'=>$searchable_text, + 'ktcore.criteria.tagcloud_not'=>0 + ), + 'type'=>'ktcore.criteria.tagcloud' + ) + ) + ) + ) + ); + + + $this->browseType = 'Folder'; + $sSearch = md5(serialize($aCriteriaSet)); + $_SESSION['boolean_search'][$sSearch] = $aCriteriaSet; + + $collection = new AdvancedCollection; + $oColumnRegistry = KTColumnRegistry::getSingleton(); + $aColumns = $oColumnRegistry->getColumnsForView('ktcore.views.search'); + $collection->addColumns($aColumns); + + // set a view option + $aTitleOptions = array( + 'documenturl' => $GLOBALS['KTRootUrl'] . '/view.php', + ); + $collection->setColumnOptions('ktcore.columns.title', $aTitleOptions); + $collection->setColumnOptions('ktcore.columns.selection', array( + 'rangename' => 'selection', + 'show_folders' => true, + 'show_documents' => true, + )); + + $aOptions = $collection->getEnvironOptions(); // extract data from the environment + + $aOptions['return_url'] = KTUtil::addQueryString('dashboard.php', false); + $aOptions['empty_message'] = _kt('No documents or folders match this query.'); + $aOptions['is_browse'] = true; + + $collection->setOptions($aOptions); + $collection->setQueryObject(new BooleanSearchQuery($aCriteriaSet)); + + $oTemplating =& KTTemplating::getSingleton(); + $oTemplate = $oTemplating->loadTemplate('kt3/browse'); + $aTemplateData = array( + 'context' => $this, + 'collection' => $collection, + 'custom_title' => $sTitle, + 'isEditable' => true, + 'boolean_search' => $sSearch, + 'bulkactions' => KTBulkActionUtil::getAllBulkActions(), + 'browseutil' => new KTBrowseUtil(), + 'returnaction' => 'booleanSearch', + 'returndata' => $sSearch, + + ); + return $oTemplate->render($aTemplateData); + + } +} +?> diff --git a/plugins/tagcloud/templates/TagCloud/dashlet.smarty b/plugins/tagcloud/templates/TagCloud/dashlet.smarty new file mode 100644 index 0000000..eb06659 --- /dev/null +++ b/plugins/tagcloud/templates/TagCloud/dashlet.smarty @@ -0,0 +1,30 @@ +{literal} + +{/literal} + +{if empty($tags)} + +There are no tags defined or accessible. + +{else} +
+{foreach from=$tags key=tag item=size} + + {$tag}  + +{/foreach} +
+{/if} + + + +
+
-- libgit2 0.21.4