From 1a8545df8ae09608c44cbda08692abd8e8f75e9a Mon Sep 17 00:00:00 2001 From: Erik Amaru Ortiz Date: Tue, 15 May 2012 10:56:48 -0400 Subject: [PATCH] BUG 0000 herbert> SOLR implementation in PMOS2 Solr support in PMOS2 includes: Functionality: - Implementation of Home views (Inbox, Draft, Participated, Unassigned). The views return fast results. - Include read, unread, all, and process filter in inbox View. - Include process filter in draft view. - Include started by me, completed by me, all, process, and status filter in participated view. - Include process filter in unassigned view. - Improved search functionality (search in user defined variables): Use the following syntax to search in process (user defined) variables. {variable_name}:{search_word} ex1:"causal:20*" where causal is the variable defined by the user. + Use of wildcards in search: Use * as wildcard at the begin or end of word + Multiple conditions in search: Separate multiple conditions by space ex2:"Materiales causal:20*" means that we are searching for the word Materiales and the causal that begin with 20. + Search in dates (interval ): Format=> {variable_date}:[yyyy-mm-dd TO yyyy-mm-dd] Local date not UTC date required ex: FechaRegistro:[2011-04-15 TO 2011-04-30] //registros con fecha entre el 2011-04-15 y el 2011-04-30. + we can use the wildcard *: ex: FechaRegistro:[* TO 2011-04-30] //registros con fecha menor o igual a 2011-04-30. FechaRegistro:[2011-04-15 TO *] //registros con fecha mayor o igual a 2011-04-15. + Search of exact phrases. format: {variable}:"frase a buscar" ex: Cliente:"Jesus Marin" - Application update function. + The function is called every time a change is detected in the application's data including the related delegations. - Use of cache to improve performance Not included: - Order of task, sent by, and due date columns. Pending: - Advanced search view using faceted lists. --- workflow/engine/bin/reindex_solr.php | 255 +++ workflow/engine/classes/class.AppSolr.php | 1757 +++++++++++++++++ workflow/engine/classes/class.case.php | 137 +- workflow/engine/classes/class.fileCache.php | 110 ++ workflow/engine/classes/class.memcached.php | 263 +-- workflow/engine/classes/class.searchIndex.php | 364 ++++ workflow/engine/classes/class.solr.php | 432 ++++ .../engine/classes/entities/AppSolrQueue.php | 35 + workflow/engine/classes/entities/Base.php | 135 ++ .../engine/classes/entities/FacetGroup.php | 49 + .../entities/FacetInterfaceRequest.php | 36 + .../classes/entities/FacetInterfaceResult.php | 35 + .../engine/classes/entities/FacetItem.php | 42 + .../engine/classes/entities/FacetRequest.php | 39 + .../engine/classes/entities/FacetResult.php | 33 + .../entities/SelectedFacetGroupItem.php | 36 + .../classes/entities/SolrQueryResult.php | 36 + .../classes/entities/SolrRequestData.php | 42 + .../classes/entities/SolrUpdateDocument.php | 31 + .../engine/classes/model/AppSolrQueue.php | 126 ++ .../engine/classes/model/AppSolrQueuePeer.php | 23 + .../model/map/AppSolrQueueMapBuilder.php | 73 + .../classes/model/om/BaseAppSolrQueue.php | 557 ++++++ .../classes/model/om/BaseAppSolrQueuePeer.php | 570 ++++++ workflow/engine/config/schema.xml | 24 + workflow/engine/data/mssql/schema.sql | 38 + workflow/engine/data/mysql/schema.sql | 13 + .../engine/methods/cases/proxyCasesList.php | 22 +- workflow/engine/templates/cases/casesList.js | 11 +- 29 files changed, 5198 insertions(+), 126 deletions(-) create mode 100644 workflow/engine/bin/reindex_solr.php create mode 100644 workflow/engine/classes/class.AppSolr.php create mode 100644 workflow/engine/classes/class.fileCache.php create mode 100644 workflow/engine/classes/class.searchIndex.php create mode 100644 workflow/engine/classes/class.solr.php create mode 100644 workflow/engine/classes/entities/AppSolrQueue.php create mode 100644 workflow/engine/classes/entities/Base.php create mode 100644 workflow/engine/classes/entities/FacetGroup.php create mode 100644 workflow/engine/classes/entities/FacetInterfaceRequest.php create mode 100644 workflow/engine/classes/entities/FacetInterfaceResult.php create mode 100644 workflow/engine/classes/entities/FacetItem.php create mode 100644 workflow/engine/classes/entities/FacetRequest.php create mode 100644 workflow/engine/classes/entities/FacetResult.php create mode 100644 workflow/engine/classes/entities/SelectedFacetGroupItem.php create mode 100644 workflow/engine/classes/entities/SolrQueryResult.php create mode 100644 workflow/engine/classes/entities/SolrRequestData.php create mode 100644 workflow/engine/classes/entities/SolrUpdateDocument.php create mode 100644 workflow/engine/classes/model/AppSolrQueue.php create mode 100644 workflow/engine/classes/model/AppSolrQueuePeer.php create mode 100644 workflow/engine/classes/model/map/AppSolrQueueMapBuilder.php create mode 100644 workflow/engine/classes/model/om/BaseAppSolrQueue.php create mode 100644 workflow/engine/classes/model/om/BaseAppSolrQueuePeer.php diff --git a/workflow/engine/bin/reindex_solr.php b/workflow/engine/bin/reindex_solr.php new file mode 100644 index 000000000..5e34d2aa9 --- /dev/null +++ b/workflow/engine/bin/reindex_solr.php @@ -0,0 +1,255 @@ + '1', 'sLastExecution' => date('Y-m-d H:i:s')))); +// } + +print "PATH_HOME: " . PATH_HOME . "\n"; +print "PATH_DB: " . PATH_DB . "\n"; +print "PATH_CORE: " . PATH_CORE . "\n"; + + +//define the site name (instance name) +if (!defined('SYS_SYS')) { + $sObject = $argv[1]; + $sNow = '';//$argv[2]; + $sFilter = ''; + + for($i=3; $i', '', $sContent); + $sContent = str_replace('define', '', $sContent); + $sContent = str_replace("('", "$", $sContent); + $sContent = str_replace("',", '=', $sContent); + $sContent = str_replace(");", ';', $sContent); + + eval($sContent); + $dsn = $DB_ADAPTER . '://' . $DB_USER . ':' . $DB_PASS . '@' . $DB_HOST . '/' . $DB_NAME; + $dsnRbac = $DB_ADAPTER . '://' . $DB_RBAC_USER . ':' . $DB_RBAC_PASS . '@' . $DB_RBAC_HOST . '/' . $DB_RBAC_NAME; + $dsnRp = $DB_ADAPTER . '://' . $DB_REPORT_USER . ':' . $DB_REPORT_PASS . '@' . $DB_REPORT_HOST . '/' . $DB_REPORT_NAME; + switch ($DB_ADAPTER) { + case 'mysql': + $dsn .= '?encoding=utf8'; + $dsnRbac .= '?encoding=utf8'; + break; + case 'mssql': + //$dsn .= '?sendStringAsUnicode=false'; + //$dsnRbac .= '?sendStringAsUnicode=false'; + break; + default: + break; + } + //initialize db + $pro['datasources']['workflow']['connection'] = $dsn; + $pro['datasources']['workflow']['adapter'] = $DB_ADAPTER; + $pro['datasources']['rbac']['connection'] = $dsnRbac; + $pro['datasources']['rbac']['adapter'] = $DB_ADAPTER; + $pro['datasources']['rp']['connection'] = $dsnRp; + $pro['datasources']['rp']['adapter'] = $DB_ADAPTER; + //$pro['datasources']['dbarray']['connection'] = 'dbarray://user:pass@localhost/pm_os'; + //$pro['datasources']['dbarray']['adapter'] = 'dbarray'; + $oFile = fopen(PATH_CORE . 'config/_databases_.php', 'w'); + fwrite($oFile, ''); + fclose($oFile); + Propel::init(PATH_CORE . 'config/_databases_.php'); + //Creole::registerDriver('dbarray', 'creole.contrib.DBArrayConnection'); + + eprintln("Processing workspace: " . $sObject, 'green'); + try{ + processWorkspace(); + }catch(Exception $e){ + echo $e->getMessage(); + eprintln("Probelm in workspace: " . $sObject.' it was omitted.', 'red'); + } + eprintln(); + unlink(PATH_CORE . 'config/_databases_.php'); + } + } + +} +else { + processWorkspace(); +} + +//finally update the file +//@file_put_contents(PATH_DATA . 'cron', serialize(array('bCronIsRunning' => '0', 'sLastExecution' => date('Y-m-d H:i:s')))); + + +function processWorkspace() { + global $sLastExecution; + G::LoadClass('AppSolr'); + + try { + $oAppSolr = new AppSolr(); + if ($oAppSolr->isSolrEnabled()) { + $oAppSolr->reindexAllApplications(); + //$data = $ApplicationSolrIndex->getAppGridData($start, $limit, $action, $filter, $search, $process, $user, $status, $type, $dateFrom, $dateTo, $callback, $dir, $sort); + //$result = G::json_encode($data); + } + } + catch (Exception $oError) { + saveLog ("main", "error", "Error processing workspace : " . $oError->getMessage() . "\n" ); + } +} + +function saveLog($sSource, $sType, $sDescription) { + try { + global $isDebug; + if ( $isDebug ) + print date('H:i:s') ." ($sSource) $sType $sDescription
\n"; + @fwrite($oFile, date('Y-m-d H:i:s') . '(' . $sSource . ') ' . $sDescription . "\n"); + + G::verifyPath(PATH_DATA . 'log' . PATH_SEP, true); + if ($sType == 'action') { + $oFile = @fopen(PATH_DATA . 'log' . PATH_SEP . 'cron.log', 'a+'); + } + else { + $oFile = @fopen(PATH_DATA . 'log' . PATH_SEP . 'cronError.log', 'a+'); + } + @fwrite($oFile, date('Y-m-d H:i:s') . '(' . $sSource . ') ' . $sDescription . "\n"); + @fclose($oFile); + } + catch (Exception $oError) { + //CONTINUE + } +} + +function setExecutionMessage($m){ + $len = strlen($m); + $linesize = 60; + $rOffset = $linesize - $len; + + eprint("* $m"); + for($i=0; $i<$rOffset; $i++) eprint('.'); +} + +function setExecutionResultMessage($m, $t=''){ + $c='green'; + if($t=='error') $c = 'red'; + if($t=='info') $c = 'yellow'; + eprintln("[$m]", $c); +} diff --git a/workflow/engine/classes/class.AppSolr.php b/workflow/engine/classes/class.AppSolr.php new file mode 100644 index 000000000..90d172417 --- /dev/null +++ b/workflow/engine/classes/class.AppSolr.php @@ -0,0 +1,1757 @@ +code}]: {$this->message}\n"; + } +} + +class AppSolr { + private $solrIsEnabled = false; + private $solrHost = ""; + private $solrInstance = ""; + + function __construct() { + // define solr availability + $this->solrIsEnabled = SOLR_ENABLED; + $this->solrHost = SOLR_HOST; + $this->solrInstance = SOLR_INSTANCE; + } + + public function isSolrEnabled() { + return $this->solrIsEnabled; + } + + public function getAppGridData($userUid, $start = null, $limit = null, $action = null, $filter = null, $search = null, $process = null, $user = null, $status = null, $type = null, $dateFrom = null, $dateTo = null, $callback = null, $dir = null, $sort = 'APP_CACHE_VIEW.APP_NUMBER') { + $callback = isset ( $callback ) ? $callback : 'stcCallback1001'; + $dir = isset ( $dir ) ? $dir : 'DESC'; // direction of sort column + // (ASC, DESC) + $sort = isset ( $sort ) ? $sort : ''; // sort column (APP_NUMBER, + // CASE_SUMMARY, + // CASE_NOTES_COUNT, APP_TITLE, + // APP_PRO_TITLE, APP_TAS_TITLE, + // APP_DEL_PREVIOUS_USER, + // DEL_TASK_DUE_DATE, + // APP_UPDATE_DATE, DEL_PRIORITY) + $start = isset ( $start ) ? $start : '0'; + $limit = isset ( $limit ) ? $limit : '25'; + $filter = isset ( $filter ) ? $filter : ''; // posible values ('read', + // 'unread', 'started', + // 'completed') + $search = isset ( $search ) ? $search : ''; // search in fields, plain text + $process = isset ( $process ) ? $process : ''; // filter by an specific + // process + // uid + $user = isset ( $user ) ? $user : ''; // filter by an specific user uid + $status = isset ( $status ) ? strtoupper ( $status ) : ''; // filter by an + // specific + // app_status + $action = isset ( $action ) ? $action : 'todo'; // todo, paused + $type = isset ( $type ) ? $type : 'extjs'; + $dateFrom = isset ( $dateFrom ) ? $dateFrom : ''; // filter by + // DEL_DELEGATE_DATE + $dateTo = isset ( $dateTo ) ? $dateTo : ''; // filter by DEL_DELEGATE_DATE + + $swErrorInSearchText = false; + $solrQueryResult = null; + + $result = array (); + $result ['totalCount'] = 0; + $result ['data'] = array (); + $result ['success'] = false; + $result ['message'] = "Error description."; + + G::LoadClass ( 'searchIndex' ); + + try { + + // the array of data that must be returned with placeholders + $columsToInclude = array ( + 'APP_CREATE_DATE', + '', + '', + '', + 'APP_NUMBER', + '', + 'APP_PRO_TITLE', + 'APP_STATUS', + '', + '', + 'APP_TITLE', + 'APP_UID', + 'DEL_LAST_UPDATE_DATE', + '', + '', + '', + '', + '', + '', + '', + '', + 'DEL_MAX_PRIORITY', + '', + '', + '', + '', + '', + 'PRO_UID', + '', + '' + ); + // create pagination data + $solrSearchText = ""; + $sortableCols = array (); + $sortCols = array (); + $sortDir = array (); + $numSortingCols = 0; + // only one column is sorted + $dir = strtolower ( $dir ); + + if (! empty ( $sort )) { + switch ($sort) { + case 'APP_CACHE_VIEW.APP_NUMBER' : + case 'APP_NUMBER' : + $sortCols [0] = 4; + $sortableCols [0] = 'true'; + $sortDir [0] = $dir; + break; + // multivalue field can't be ordered + case 'APP_TITLE' : + $sortCols [0] = 10; + $sortableCols [0] = 'true'; + $sortDir [0] = $dir; + break; + case 'APP_PRO_TITLE' : + $sortCols [0] = 6; + $sortableCols [0] = 'true'; + $sortDir [0] = $dir; + break; + case 'APP_UPDATE_DATE' : + $sortCols [0] = 12; + $sortableCols [0] = 'true'; + $sortDir [0] = $dir; + break; + default : + $sortCols [0] = 4; + $sortableCols [0] = 'true'; + $sortDir [0] = 'desc'; + break; + } + $numSortingCols ++; + } + + // get del_index field + $delIndexDynaField = ""; + + if ($process != '') { + $solrSearchText .= "PRO_UID:" . $process . " AND "; + } + + if ($status != '') { + $solrSearchText .= "APP_STATUS:" . $status . " AND "; + } + // todo list + if ($userUid != null && $action == 'todo') { + if ($filter == 'read') { + $solrSearchText .= "APP_ASSIGNED_USERS_READ:" . $userUid . " AND "; + $delIndexDynaField = "APP_ASSIGNED_USER_READ_DEL_INDEX_" . trim ( $userUid ) . '_txt'; + } + elseif ($filter == 'unread') { + $solrSearchText .= "APP_ASSIGNED_USERS_UNREAD:" . $userUid . " AND "; + $delIndexDynaField = "APP_ASSIGNED_USER_UNREAD_DEL_INDEX_" . trim ( $userUid ) . '_txt'; + } + else { + $solrSearchText .= "APP_ASSIGNED_USERS:" . $userUid . " AND "; + $delIndexDynaField = "APP_ASSIGNED_USER_DEL_INDEX_" . trim ( $userUid ) . '_txt'; + } + } + // participated + if ($userUid != null && $action == 'sent') { + if ($filter == 'started') { + $solrSearchText .= "APP_PARTICIPATED_USERS_STARTED:" . $userUid . " AND "; + $delIndexDynaField = "APP_PARTICIPATED_USER_STARTED_DEL_INDEX_" . trim ( $userUid ) . '_txt'; + } + elseif ($filter == 'completed') { + $solrSearchText .= "APP_PARTICIPATED_USERS_COMPLETED:" . $userUid . " AND "; + $delIndexDynaField = "APP_PARTICIPATED_USER_COMPLETED_DEL_INDEX_" . trim ( $userUid ) . '_txt'; + } + else { + $solrSearchText .= "APP_PARTICIPATED_USERS:" . $userUid . " AND "; + $delIndexDynaField = "APP_PARTICIPATED_USER_DEL_INDEX_" . trim ( $userUid ) . '_txt'; + } + } + // draft + if ($userUid != null && $action == 'draft') { + $solrSearchText .= "APP_DRAFT_USER:" . $userUid . " AND "; + // index is allways 1 + } + // unassigned + if ($userUid != null && $action == 'unassigned') { + // get the list of groups to which belongs the user. + $userGroups = $this->getUserGroups ( $userUid ); + $solrSearchText .= "(APP_UNASSIGNED_USERS:" . $userUid . " OR "; + foreach ( $userGroups as $group ) { + $solrSearchText .= "APP_UNASSIGNED_GROUPS:" . $group ['GRP_UID'] . " OR "; + } + $solrSearchText .= ") AND "; + + $delIndexDynaField = "APP_UNASSIGNED_USER_GROUP_DEL_INDEX_" . trim ( $userUid ) . '_txt'; + } + + // remove last AND + if ($solrSearchText != '') + $solrSearchText = substr_replace ( $solrSearchText, "", - 5 ); + + // add parentesis + if ($solrSearchText != "") + $solrSearchText = "(" . $solrSearchText . ")"; + + // create query string + if ($search != '') { + // format search string + // return exception in case of invalid text + $search = $this->getSearchText ( $search ); + + if ($solrSearchText != "" && $search != "") + $solrSearchText .= " AND "; + if ($search != "") + $solrSearchText .= "(" . $search . ")"; + } + + // add del_index dynamic field + $columsToInclude = array_merge ( $columsToInclude, array ( + $delIndexDynaField + ) ); + + $data = array ( + 'workspace' => $this->solrInstance, // solr instance + 'startAfter' => intval ( $start ), + 'pageSize' => intval ( $limit ), + 'searchText' => $solrSearchText, + 'filterText' => '', // $filter, //ex:'field1:value1,field2:[value2.1 + // TO value2.2],field3:value3' + 'numSortingCols' => $numSortingCols, + 'sortableCols' => $sortableCols, + 'sortCols' => $sortCols, + 'sortDir' => $sortDir, + 'includeCols' => $columsToInclude, + 'resultFormat' => 'json' + ); + + $solrRequestData = Entity_SolrRequestData::CreateForRequestPagination ( $data ); + // use search index to return list of cases + $searchIndex = new BpmnEngine_Services_SearchIndex ( $this->solrIsEnabled, $this->solrHost ); + // execute query + $solrQueryResult = $searchIndex->getDataTablePaginatedList ( $solrRequestData ); + + // complete return data + $resultColumns = array ( + "APP_CREATE_DATE", + "APP_CURRENT_USER", + "APP_DEL_PREVIOUS_USER", + "APP_FINISH_DATE", + "APP_NUMBER", + "APP_OVERDUE_PERCENTAGE", + "APP_PRO_TITLE", + "APP_STATUS", + "APP_TAS_TITLE", + "APP_THREAD_STATUS", + "APP_TITLE", + "APP_UID", + "APP_UPDATE_DATE", + "DEL_DELAYED", + "DEL_DELAY_DURATION", + "DEL_DELEGATE_DATE", + "DEL_DURATION", + "DEL_FINISHED", + "DEL_FINISH_DATE", + "DEL_INDEX", + "DEL_INIT_DATE", + "DEL_PRIORITY", + "DEL_QUEUE_DURATION", + "DEL_STARTED", + "DEL_TASK_DUE_DATE", + "DEL_THREAD_STATUS", + "PREVIOUS_USR_UID", + "PRO_UID", + "TAS_UID", + "USR_UID" + ); + + $rows = array (); + $result ['totalCount'] = $solrQueryResult->iTotalDisplayRecords; + + foreach ( $solrQueryResult->aaData as $i => $data ) { + // complete empty values + $appUID = $data [11]; + $delIndexes = $data [30]; + // verify if the delindex is an array + // if is not an array all the indexed must be returned + if (! is_array ( $delIndexes )) { + // if is draft + if ($action == 'draft') { + $delIndexes [] = 1; // the first default index + } + elseif ($action == 'search') { + // get all the indexes + $delIndexes = $this->getApplicationDelegationsIndex ( $appUID ); + } + } + foreach ( $delIndexes as $delIndex ) { + $aRow = array (); + foreach ( $resultColumns as $j => $columnName ) { + $aRow [$columnName] = $data [$j]; + } + // convert date from solr format UTC to local time in MySQL format + $solrdate = $data [0]; + $localDate = date ( 'Y-m-d H:i:s', strtotime ( $solrdate ) ); + $aRow ['APP_CREATE_DATE'] = $localDate; + + $solrdate = $data [12]; + $localDate = date ( 'Y-m-d H:i:s', strtotime ( $solrdate ) ); + $aRow ['APP_UPDATE_DATE'] = $localDate; + + // get delegation data from DB + $row = $this->getAppDelegationData ( $appUID, $delIndex ); + + $aRow ['APP_FINISH_DATE'] = null; + $aRow ['APP_CURRENT_USER'] = $row ['USR_NAME'] . " " . $row ['USR_LAST']; + $aRow ['APP_DEL_PREVIOUS_USER'] = $row ['USR_PREV_NAME'] . " " . $row ['USR_PREV_LAST']; + $aRow ['APP_OVERDUE_PERCENTAGE'] = $row ['APP_OVERDUE_PERCENTAGE']; + $aRow ['APP_TAS_TITLE'] = $row ['APP_TAS_TITLE']; + $aRow ['APP_THREAD_STATUS'] = $row ['APP_THREAD_STATUS']; + $aRow ['DEL_DELAYED'] = $row ['DEL_DELAYED']; + $aRow ['DEL_DELAY_DURATION'] = $row ['DEL_DELAY_DURATION']; + $aRow ['DEL_DELEGATE_DATE'] = $row ['DEL_DELEGATE_DATE']; + $aRow ['DEL_DURATION'] = $row ['DEL_DURATION']; + $aRow ['DEL_FINISHED'] = (isset ( $row ['DEL_FINISH_DATE'] ) && $row ['DEL_FINISH_DATE'] != '') ? 1 : 0; + $aRow ['DEL_FINISH_DATE'] = $row ['DEL_FINISH_DATE']; + $aRow ['DEL_INDEX'] = $row ['DEL_INDEX']; + $aRow ['DEL_INIT_DATE'] = $row ['DEL_INIT_DATE']; + $aRow ['DEL_QUEUE_DURATION'] = $row ['DEL_QUEUE_DURATION']; + $aRow ['DEL_STARTED'] = (isset ( $row ['DEL_INIT_DATE'] ) && $row ['DEL_INIT_DATE'] != '') ? 1 : 0; + $aRow ['DEL_TASK_DUE_DATE'] = $row ['DEL_TASK_DUE_DATE']; + $aRow ['DEL_THREAD_STATUS'] = $row ['DEL_THREAD_STATUS']; + $aRow ['PREVIOUS_USR_UID'] = $row ['PREVIOUS_USR_UID']; + $aRow ['TAS_UID'] = $row ['TAS_UID']; + $aRow ['USR_UID'] = $userUid; + + $rows [] = $aRow; + } + } + $result ['data'] = $rows; + $result ['success'] = true; + $result ['result'] = true; + $result ['message'] = ""; + + return $result; + + } // end try + catch ( InvalidIndexSearchTextException $e ) { + // return empty result with description of error + $result = array (); + $result ['totalCount'] = 0; + $result ['data'] = array (); + $result ['success'] = true; + $result ['result'] = false; + $result ['message'] = $e->getMessage (); + return $result; + } + } + + function getUserGroups($usrUID) { + $gu = new GroupUser (); + $rows = $gu->getAllUserGroups ( $usrUID ); + return $rows; + } + + function getAppDelegationData($appUID, $delIndex) { + + $c = new Criteria (); + + $c->addSelectColumn ( AppDelegationPeer::APP_UID ); + $c->addSelectColumn ( AppDelegationPeer::DEL_INDEX ); + + $c->addAsColumn ( 'USR_NAME', 'u.USR_FIRSTNAME' ); + $c->addAsColumn ( 'USR_LAST', 'u.USR_LASTNAME' ); + + $c->addAsColumn ( 'USR_PREV_NAME', 'uprev.USR_FIRSTNAME' ); + $c->addAsColumn ( 'USR_PREV_LAST', 'uprev.USR_LASTNAME' ); + $c->addAsColumn ( 'PREVIOUS_USR_UID', 'uprev.USR_UID' ); + + $c->addAsColumn ( 'APP_TAS_TITLE', 'ctastitle.CON_VALUE' ); + $c->addAsColumn ( 'APP_THREAD_STATUS', 'at.APP_THREAD_STATUS' ); + + $c->addSelectColumn ( AppDelegationPeer::APP_OVERDUE_PERCENTAGE ); + + $c->addSelectColumn ( AppDelegationPeer::DEL_DELAYED ); + $c->addSelectColumn ( AppDelegationPeer::DEL_DELAY_DURATION ); + $c->addSelectColumn ( AppDelegationPeer::DEL_DELEGATE_DATE ); + $c->addSelectColumn ( AppDelegationPeer::DEL_DURATION ); + $c->addSelectColumn ( AppDelegationPeer::DEL_FINISH_DATE ); + $c->addSelectColumn ( AppDelegationPeer::DEL_INIT_DATE ); + $c->addSelectColumn ( AppDelegationPeer::DEL_QUEUE_DURATION ); + $c->addSelectColumn ( AppDelegationPeer::DEL_TASK_DUE_DATE ); + $c->addSelectColumn ( AppDelegationPeer::DEL_THREAD_STATUS ); + $c->addSelectColumn ( AppDelegationPeer::TAS_UID ); + + $c->addAlias ( 'u', 'USERS' ); + $c->addAlias ( 'uprev', 'USERS' ); + $c->addAlias ( 'adprev', 'APP_DELEGATION' ); + $c->addAlias ( 'ctastitle', 'CONTENT' ); + $c->addAlias ( 'at', 'APP_THREAD' ); + + $aConditions = array (); + $aConditions [] = array ( + AppDelegationPeer::USR_UID, + 'u.USR_UID' + ); + $c->addJoinMC ( $aConditions, Criteria::LEFT_JOIN ); + + $aConditions = array (); + $aConditions [] = array ( + AppDelegationPeer::APP_UID, + 'adprev.APP_UID' + ); + $aConditions [] = array ( + AppDelegationPeer::DEL_PREVIOUS, + 'adprev.DEL_INDEX' + ); + $c->addJoinMC ( $aConditions, Criteria::LEFT_JOIN ); + + $aConditions = array (); + $aConditions [] = array ( + AppDelegationPeer::TAS_UID, + 'ctastitle.CON_ID' + ); + $c->addJoinMC ( $aConditions, Criteria::LEFT_JOIN ); + + $aConditions = array (); + $aConditions [] = array ( + 'adprev.USR_UID', + 'uprev.USR_UID' + ); + $c->addJoinMC ( $aConditions, Criteria::LEFT_JOIN ); + + $aConditions = array (); + $aConditions [] = array ( + AppDelegationPeer::APP_UID, + 'at.APP_UID' + ); + $aConditions [] = array ( + AppDelegationPeer::DEL_THREAD, + 'at.APP_THREAD_INDEX' + ); + $c->addJoinMC ( $aConditions, Criteria::LEFT_JOIN ); + + $c->add ( AppDelegationPeer::APP_UID, $appUID ); + $c->add ( AppDelegationPeer::DEL_INDEX, $delIndex ); + + $c->add ( 'ctastitle.CON_CATEGORY', 'TAS_TITLE' ); + $c->add ( 'ctastitle.CON_LANG', 'en' ); + + $rs = AppDelegationPeer::doSelectRS ( $c ); + $rs->setFetchmode ( ResultSet::FETCHMODE_ASSOC ); + // echo $c->toString(); + $rs->next (); + $row = $rs->getRow (); + + return $row; + } + + /** + * return the correct search text for solr. + * if a field is included only search in this field. + * + * @param string $plainSearchText + */ + function getSearchText($plainSearchText) { + $formattedSearchText = ""; + // if an error is found in string null is returned + $includeToken = true; + + // prepare string to separate and join parentesis + // " " => " " + $count = 1; + while ( $count > 0 ) { + $plainSearchText = preg_replace ( '/\s\s+/', ' ', $plainSearchText, - 1, $count ); + } + // "text0( text1" => "text0 (text1"; "text0 )text1" => "text0) text1"; + $plainSearchText = preg_replace ( '/\s\[\s/', '[', $plainSearchText ); + $plainSearchText = preg_replace ( '/\s\]\s/', '] ', $plainSearchText ); + $plainSearchText = preg_replace ( '/\s"\s/', '" ', $plainSearchText ); + + // print "format search string: " . $plainSearchText . "\n"; + // format + // 1: plain text that is used to search in text field: concat field + // 2: a field is specified [field_name]:["phrase search"] + // [field_name]:["phrase search"] [field_name]:[word_search] word_search + // "phrase search" + // to scape a reserved character use a double value: "::", """" + // ex: (APP_ASSIGNED_USERS:7091676694d9269da75c254003021135) AND + // (contrato_t:76* AND Causal_t:1021 AND Materiales AND 143073) + // ex: date search => APP_CREATE_DATE:[2012-03-12T00:00:00Z TO + // 2012-04-12T00:00:00Z] + // ex: phrase => TEXT:"This is a lazy dog" + + // search the first + + // cache the index fields + G::LoadClass ( 'PMmemcached' ); + $oMemcache = PMmemcached::getSingleton ( $this->solrInstance ); + $ListFieldsInfo = $oMemcache->get ( 'Solr_Index_Fields' ); + if (! $ListFieldsInfo) { + G::LoadClass ( 'searchIndex' ); + + $searchIndex = new BpmnEngine_Services_SearchIndex ( $this->solrIsEnabled, $this->solrHost ); + // execute query + $ListFieldsInfo = $searchIndex->getIndexFields ( $this->solrInstance ); + + // cache + $oMemcache->set ( 'Solr_Index_Fields', $ListFieldsInfo ); + + } + + $tok = strtok ( $plainSearchText, " " ); + + while ( $tok !== false ) { + $fieldName = strstr ( $tok, ":", true ); + $searchText = strstr ( $tok, ":" ); + + // verify if there's a field definition + if ($fieldName === false) { + // it's not a field + // the token is not a field + // add it completelly + $includeToken = true; + // no field found + $formattedSearchText .= $tok; // used to search in the general default + // text field + } + else { + // it's a field + // verify if is complete + if ($fieldName == "" || $searchText == ":") { + $includeToken = false; + throw new InvalidIndexSearchTextException ( "Invalid search text, verify the syntax. Expected format = {variable_name}:{search_text}" ); + } + + // field name found + // search index field name + $indexFieldName = ""; + if (array_key_exists ( $fieldName, $ListFieldsInfo )) { + $indexFieldName = $ListFieldsInfo [$fieldName]; + } + else { + // no field name found + // don't include field search + // return message about it + $includeToken = false; + throw new InvalidIndexSearchTextException ( "Invalid search text, variable not found." ); + } + + // The token is part of a phrase, date or a word? + if ($searchText [1] == "[" || $searchText [1] == "\"") { // + // expecting + // date + // interval + // we must + // search + // the end of + // the + // phrase + + // the phrase is complete? + if ($searchText [1] == "[" && $searchText [strlen ( $searchText ) - 1] == "]") { + // complete phrase ok, the date must be validated + // throw new InvalidIndexSearchTextException("Invalid search text. + // Expected date interval format => + // {variable_name}:[YYYY-MM-DDThh:mm:ssZ TO YYYY-MM-DDThh:mm:ssZ]"); + } + elseif ($searchText [1] == "\"" && $searchText [strlen ( $searchText ) - 1] == "\"") { + // the phrase is complete and is ok. + } + else { + // search end of phrase + $tok = strtok ( " " ); + $found = false; + while ( $tok !== false ) { + if ((($searchText [1] == "[") && ($tok [strlen ( $tok ) - 1] == "]")) || (($searchText [1] == "\"") && ($tok [strlen ( $tok ) - 1] == "\""))) { + // end of phrase found + $found = true; + $searchText .= " " . $tok; + break; + } + else { + // continue adding text + $searchText .= " " . $tok; + } + $tok = strtok ( " " ); + } + if (! $found) { + // error invalid text + throw new InvalidIndexSearchTextException ( "Invalid search text. The date or phase is not completed" ); // Expected + // date + // interval + // format + // => + // {variable_name}:[YYYY-MM-DDThh:mm:ssZ + // TO + // YYYY-MM-DDThh:mm:ssZ] + } + } + } + + // validate phrase in case of date + if (($searchText [1] == "[")) { + // validate date range format + // use regular expresion to validate it [yyyy-mm-dd TO yyyy-mm-dd] + $reg = "/:\[(\d\d\d\d-\d\d-\d\d|\*)\sTO\s(\d\d\d\d-\d\d-\d\d|\*)\]/"; + // convert date to utc + $matched = preg_match ( $reg, $searchText, $matches ); + if ($matched == 1) { + // the date interval is valid + // convert to SOlr format + $fromDateOriginal = $matches [1]; + $fromDate = $matches [1]; + + $toDateOriginal = $matches [2]; + $toDate = $matches [2]; + + if ($fromDateOriginal != '*') { + $fromDateDatetime = date_create_from_format ( 'Y-m-d', $fromDateOriginal ); + $fromDate = gmdate ( "Y-m-d\T00:00:00\Z", $fromDateDatetime->getTimestamp () ); + } + if ($toDateOriginal != '*') { + $toDateDatetime = date_create_from_format ( 'Y-m-d', $toDateOriginal ); + $toDate = gmdate ( "Y-m-d\T00:00:00\Z", $toDateDatetime->getTimestamp () ); + } + $searchText = ":[" . $fromDate . " TO " . $toDate . "]"; + } + else { + throw new InvalidIndexSearchTextException ( "Invalid search text. Expected date interval format => {variable_name}:[YYYY-MM-DD TO YYYY-MM-DD]" ); + } + } + + $formattedSearchText .= $indexFieldName . $searchText; + $includeToken = true; + } + + if ($includeToken) + $formattedSearchText .= " AND "; + + // next token + $tok = strtok ( " " ); + } + // remove last AND + $formattedSearchText = substr_replace ( $formattedSearchText, "", - 5 ); + return $formattedSearchText; + } + + function getApplicationDelegationsIndex($appUID) { + $delIndexes = array (); + + $c = new Criteria (); + + $c->addSelectColumn ( AppDelegationPeer::DEL_INDEX ); + $c->add ( AppDelegationPeer::APP_UID, $appUID ); + + $rs = AppDelegationPeer::doSelectRS ( $c ); + $rs->setFetchmode ( ResultSet::FETCHMODE_ASSOC ); + + $rs->next (); + $row = $rs->getRow (); + + while ( is_array ( $row ) ) { + $delIndexes [] = $row ['DEL_INDEX']; + $rs->next (); + $row = $rs->getRow (); + } + + return $delIndexes; + + } + + function updateApplicationSearchIndex($aaAPPUIDs) { + if (empty ( $aaAPPUIDs )) + return; + + if (! is_array ( $aaAPPUIDs )) { + // convert to array + $APPUID = $aaAPPUIDs; + $aaAPPUIDs = array (); + $aaAPPUIDs [] = array ( + 'APP_UID' => $APPUID + ); + } + // check if index server is available + if (! $this->isSolrEnabled ()) { + // store update in table and return + foreach ( $aaAPPUIDs as $aAPPUID ) { + $this->applicationChangedUpdateSolrQueue ( $aAPPUID ['APP_UID'], true ); + } + } + // create XML document + $xmlDoc = $this->createSolrXMLDocument ( $aaAPPUIDs ); + + // update document + $data = array ( + 'workspace' => $this->solrInstance, + 'document' => $xmlDoc + ); + $oSolrUpdateDocument = Entity_SolrUpdateDocument::CreateForRequest ( $data ); + + G::LoadClass ( 'searchIndex' ); + + $oSearchIndex = new BpmnEngine_Services_SearchIndex ( $this->solrIsEnabled, $this->solrHost ); + + $oSearchIndex->updateIndexDocument ( $oSolrUpdateDocument ); + + // commit changes + $oSearchIndex->commitIndexChanges ( $this->solrInstance ); + } + + function deleteApplicationSearchIndex($appUID) { + if (empty ( $appUID )) + return; + + // check if index server is available + if (! $this->isSolrEnabled) { + // store update in table and return + $this->applicationChangedUpdateSolrQueue ( $appUID ['APP_UID'], 2 ); // delete + } + + $idQuery = "APP_UID:" . $appUID; + + G::LoadClass ( 'searchIndex' ); + + $oSearchIndex = new BpmnEngine_Services_SearchIndex ( $this->solrIsEnabled, $this->solrHost ); + + $oSearchIndex->deleteDocumentFromIndex ( $this->solrInstance, $idQuery ); + + // commit changes + $oSearchIndex->commitIndexChanges ( $this->solrInstance ); + } + + function createSolrXMLDocument($aaAPPUIDs) { + // search data from DB + $xmlDoc = "\n"; + $xmlDoc .= "\n"; + // echo "APP Uids to index \n"; + foreach ( $aaAPPUIDs as $aAPPUID ) { + $result = $this->getApplicationIndexData ( $aAPPUID ['APP_UID'] ); + + if ($result == null) + continue; + + $documentInformation = $result [0]; + $dynaformFieldTypes = $result [1]; + $lastUpdateDate = $result [2]; + $maxPriority = $result [3]; + $assignedUsers = $result [4]; + $assignedUsersRead = $result [5]; + $assignedUsersUnread = $result [6]; + $draftUser = $result [7]; + $participatedUsers = $result [8]; + $participatedUsersStartedByUser = $result [9]; + $participatedUsersCompletedByUser = $result [10]; + $unassignedUsers = $result [11]; + $unassignedGroups = $result [12]; + + // create document + $xmlDoc .= $this->buildSearchIndexDocumentPMOS2 ( $documentInformation, $dynaformFieldTypes, $lastUpdateDate, $maxPriority, $assignedUsers, $assignedUsersRead, $assignedUsersUnread, $draftUser, $participatedUsers, $participatedUsersStartedByUser, $participatedUsersCompletedByUser, $unassignedUsers, $unassignedGroups ); + + } + + $xmlDoc .= "\n"; + + return $xmlDoc; + } + + /** + * build search index document xml for PMOS2 + * @gearman = false + * @rest = false + * @background = false + * + * @param + * [in] array $documentData array of data for the xml document of + * application + * @param + * [in] array $dynaformFieldTypes array of dynaform field types, used + * to store the info of APP_DATA with types + * @param + * [in] array $appTitles array of array of application titles in all + * languages + * @param + * [in] array $proTitles array of array of process titles in all + * languages + * @param + * [in] array $assignedUsers array of array of uids of assigned users + * to Application UIDs + * @param + * [in] array $draftUsers array of array of uids of draft users to + * Application UIDs + * @param + * [in] array $participatedUsers array of array of participated users + * UIDs in application + * @param + * [in] array $unassignedUsers array of unassigned users UIDs + * @param + * [in] array $unassignedGroups array of unassigned groups UIDs + * @param + * [out] xml xml document + * + * $xmlDoc .= buildSearchIndexDocumentPMOS2($documentInformation, + * $dynaformFieldTypes, + * $lastUpdateDate, $maxPriority, + * $assignedUsers, $assignedUsersRead, $assignedUsersUnread, + * $draftUser, + * $participatedUsers, $participatedUsersStartedByUser, + * $participatedUsersCompletedByUser, + * $unassignedUsers, $unassignedGroups);* + */ + function buildSearchIndexDocumentPMOS2($documentData, $dynaformFieldTypes, $lastUpdateDate, $maxPriority, $assignedUsers, $assignedUsersRead, $assignedUsersUnread, $draftUser, $participatedUsers, $participatedUsersStartedByUser, $participatedUsersCompletedByUser, $unassignedUsers, $unassignedGroups) { + // build xml document + + $writer = new XMLWriter (); + $writer->openMemory (); + $writer->setIndent ( 4 ); + + $writer->startElement ( "doc" ); + + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', 'APP_UID' ); + $writer->text ( $documentData ['APP_UID'] ); + $writer->endElement (); + + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', 'APP_NUMBER' ); + $writer->text ( $documentData ['APP_NUMBER'] ); + $writer->endElement (); + + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', 'APP_STATUS' ); + $writer->text ( $documentData ['APP_STATUS'] ); + $writer->endElement (); + + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', 'PRO_UID' ); + $writer->text ( $documentData ['PRO_UID'] ); + $writer->endElement (); + + if (! empty ( $documentData ['APP_TITLE'] )) { + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', 'APP_TITLE' ); + $writer->text ( $documentData ['APP_TITLE'] ); + $writer->endElement (); + } + else { + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', 'APP_TITLE' ); + $writer->text ( "" ); + $writer->endElement (); + } + + if (! empty ( $documentData ['PRO_TITLE'] )) { + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', 'APP_PRO_TITLE' ); + $writer->text ( $documentData ['PRO_TITLE'] ); + $writer->endElement (); + + } + else { + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', 'APP_PRO_TITLE' ); + $writer->text ( "" ); + $writer->endElement (); + } + + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', 'APP_CREATE_DATE' ); + // convert date to UTC with gmdate + $writer->text ( gmdate ( "Y-m-d\TH:i:s\Z", strtotime ( $documentData ['APP_CREATE_DATE'] ) ) ); + $writer->endElement (); + + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', 'DEL_LAST_UPDATE_DATE' ); + // convert date to UTC with gmdate + $writer->text ( gmdate ( "Y-m-d\TH:i:s\Z", strtotime ( $lastUpdateDate ) ) ); + $writer->endElement (); + + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', 'DEL_MAX_PRIORITY' ); + $writer->text ( $maxPriority ); + $writer->endElement (); + + if (is_array ( $assignedUsers ) && ! empty ( $assignedUsers )) { + foreach ( $assignedUsers as $userUID ) { + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', 'APP_ASSIGNED_USERS' ); + $writer->text ( $userUID ['USR_UID'] ); + $writer->endElement (); + + // add dynamic field for del_index information + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', 'APP_ASSIGNED_USER_DEL_INDEX_' . trim ( $userUID ['USR_UID'] ) . '_txt' ); + $writer->text ( $userUID ['DEL_INDEX'] ); + $writer->endElement (); + + } + } + + if (is_array ( $assignedUsersRead ) && ! empty ( $assignedUsersRead )) { + foreach ( $assignedUsersRead as $userUID ) { + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', 'APP_ASSIGNED_USERS_READ' ); + $writer->text ( $userUID ['USR_UID'] ); + $writer->endElement (); + + // add dynamic field for del_index information + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', 'APP_ASSIGNED_USER_READ_DEL_INDEX_' . trim ( $userUID ['USR_UID'] ) . '_txt' ); + $writer->text ( $userUID ['DEL_INDEX'] ); + $writer->endElement (); + } + } + + if (is_array ( $assignedUsersUnread ) && ! empty ( $assignedUsersUnread )) { + foreach ( $assignedUsersUnread as $userUID ) { + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', 'APP_ASSIGNED_USERS_UNREAD' ); + $writer->text ( $userUID ['USR_UID'] ); + $writer->endElement (); + + // add dynamic field for del_index information + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', 'APP_ASSIGNED_USER_UNREAD_DEL_INDEX_' . trim ( $userUID ['USR_UID'] ) . '_txt' ); + $writer->text ( $userUID ['DEL_INDEX'] ); + $writer->endElement (); + } + } + + if (! empty ( $draftUser )) { + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', 'APP_DRAFT_USER' ); + $writer->text ( $draftUser ['USR_UID'] ); + $writer->endElement (); + } + + if (is_array ( $participatedUsers ) && ! empty ( $participatedUsers )) { + foreach ( $participatedUsers as $userUID ) { + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', 'APP_PARTICIPATED_USERS' ); + $writer->text ( $userUID ['USR_UID'] ); + $writer->endElement (); + + // add dynamic field for del_index information + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', 'APP_PARTICIPATED_USER_DEL_INDEX_' . trim ( $userUID ['USR_UID'] ) . '_txt' ); + $writer->text ( $userUID ['DEL_INDEX'] ); + $writer->endElement (); + } + } + + if (is_array ( $participatedUsersStartedByUser ) && ! empty ( $participatedUsersStartedByUser )) { + foreach ( $participatedUsersStartedByUser as $userUID ) { + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', 'APP_PARTICIPATED_USERS_STARTED' ); + $writer->text ( $userUID ['USR_UID'] ); + $writer->endElement (); + + // add dynamic field for del_index information + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', 'APP_PARTICIPATED_USER_STARTED_DEL_INDEX_' . trim ( $userUID ['USR_UID'] ) . '_txt' ); + $writer->text ( $userUID ['DEL_INDEX'] ); + $writer->endElement (); + } + } + + if (is_array ( $participatedUsersCompletedByUser ) && ! empty ( $participatedUsersCompletedByUser )) { + foreach ( $participatedUsersCompletedByUser as $userUID ) { + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', 'APP_PARTICIPATED_USERS_COMPLETED' ); + $writer->text ( $userUID ['USR_UID'] ); + $writer->endElement (); + + // add dynamic field for del_index information + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', 'APP_PARTICIPATED_USER_COMPLETED_DEL_INDEX_' . trim ( $userUID ['USR_UID'] ) . '_txt' ); + $writer->text ( $userUID ['DEL_INDEX'] ); + $writer->endElement (); + } + } + + if (is_array ( $unassignedUsers ) && ! empty ( $unassignedUsers )) { + foreach ( $unassignedUsers as $userUID ) { + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', 'APP_UNASSIGNED_USERS' ); + $writer->text ( $userUID ['USR_UID'] ); + $writer->endElement (); + + // add dynamic field for del_index information + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', 'APP_UNASSIGNED_USER_GROUP_DEL_INDEX_' . trim ( $userUID ['USR_UID'] ) . '_txt' ); + $writer->text ( $userUID ['DEL_INDEX'] ); + $writer->endElement (); + } + } + + if (is_array ( $unassignedGroups ) && ! empty ( $unassignedGroups )) { + foreach ( $unassignedGroups as $groupUID ) { + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', 'APP_UNASSIGNED_GROUPS' ); + $writer->text ( $groupUID ['USR_UID'] ); + $writer->endElement (); + + // add dynamic field for del_index information + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', 'APP_UNASSIGNED_USER_GROUP_DEL_INDEX_' . trim ( $userUID ['USR_UID'] ) . '_txt' ); + $writer->text ( $userUID ['DEL_INDEX'] ); + $writer->endElement (); + } + } + + // get the serialized fields + if (! empty ( $documentData ['APP_DATA'] )) { + + $UnSerializedCaseData = unserialize ( $documentData ['APP_DATA'] ); + + if ($UnSerializedCaseData === false) { + $UnSerializedCaseData = preg_replace ( '!s:(\d+):"(.*?)";!e', "'s:'.strlen('$2').':\"$2\";'", $documentData ['APP_DATA'] ); // utf8_encode + $UnSerializedCaseData = unserialize ( $UnSerializedCaseData ); + } + + if (! $UnSerializedCaseData) { + // error unserializing + throw new Exception ( "Unserialize APP_DATA error. APP_UID: " . $documentData ['APP_UID'] ); + } + else { + foreach ( $UnSerializedCaseData as $k => $value ) { + if (! is_array ( $value ) && $value != '' && $k != 'SYS_LANG' && $k != 'SYS_SKIN' && $k != 'SYS_SYS') { + // search the field type in array of dynaform fields + if (! empty ( $dynaformFieldTypes ) && array_key_exists ( trim ( $k ), $dynaformFieldTypes )) { + $type = $dynaformFieldTypes [trim ( $k )]; + $typeSufix = '_t'; + switch ($type) { + case 'text' : + $typeSufix = '_t'; + break; + case 'Int' : + $typeSufix = '_ti'; + $value = intval ( $value ); + break; + case 'Real' : + $typeSufix = '_td'; + $value = floatval ( $value ); + break; + case 'date' : + $newdate = false; + $withHour = true; + // try to convert string to date + $newdate = date_create_from_format ( 'Y-m-d H:i:s', $value ); + if (! $newdate) { + $newdate = date_create_from_format ( 'Y-m-d', $value ); + $withHour = false; + } + if (! $newdate) { + $newdate = date_create_from_format ( 'd/m/Y', $value ); + $withHour = false; + } + if (! $newdate) { + $newdate = date_create_from_format ( 'j/m/Y', $value ); + $withHour = false; + } + + if (! $newdate) { + $typeSufix = '*'; // not store field + } + else { + $typeSufix = '_tdt'; + if ($withHour) + $value = gmdate ( "Y-m-d\TH:i:s\Z", $newdate->getTimestamp () ); + else { + $value = gmdate ( "Y-m-d\T00:00:00\Z", $newdate->getTimestamp () ); + } + } + break; + case 'dropdown' : + $typeSufix = '_t'; + break; + case 'textarea' : + $typeSufix = '_t'; + break; + case 'currency' : + $typeSufix = '_td'; + break; + case 'percentage' : + $typeSufix = '_t'; + break; + case 'password' : + $typeSufix = '_t'; + break; + case 'suggest' : + $typeSufix = '_t'; + break; + case 'yesno' : + $typeSufix = '_t'; + break; + case 'listbox' : + $typeSufix = '_t'; + break; + case 'checkbox' : + $typeSufix = '_t'; + break; + case 'checkgroup' : + $typeSufix = '_t'; + break; + case 'radiogroup' : + $typeSufix = '_t'; + break; + case 'hidden' : + $typeSufix = '_t'; + break; + } + if ($typeSufix != '*') { + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', trim ( $k ) . $typeSufix ); + $writer->text ( $value ); + $writer->endElement (); + } + } + else { + $writer->startElement ( "field" ); + $writer->writeAttribute ( 'name', trim ( $k ) . '_t' ); + $writer->text ( $value ); + $writer->endElement (); + } + } + } // foreach unserialized data + } + } // empty APP_DATA + + $writer->endElement (); // end /doc + + return $writer->outputMemory ( true ); + } + + function getApplicationIndexData($AppUID) { + + G::LoadClass ( 'memcached' ); + + // get all the application data + $allAppDbData = $this->getApplicationDelegationData ( $AppUID ); + // check if the application record was found + // this case occurs when the application doesn't have related delegation + // records. + if (empty ( $allAppDbData ) || ! isset ( $allAppDbData [0] )) { + throw new Exception ( "Application without delegation records. APP_UID: " . $AppUID ); + } + + // copy the application information + $documentInformation = $allAppDbData [0]; + + // get the last delegate date using the del_delegate_date + $index = $this->aaGetMaximun ( $allAppDbData, 'DEL_DELEGATE_DATE', 'DATE' ); + + $lastUpdateDate = $allAppDbData [$index] ['DEL_DELEGATE_DATE']; + + // get the delegate with max priority => minimun value + $index2 = $this->aaGetMinimun ( $allAppDbData, 'DEL_PRIORITY', 'NUMBER', 'DEL_THREAD_STATUS', 'OPEN' ); + + if ($index2 == null) { + // get the last priority + $maxPriority = $allAppDbData [$index] ['DEL_PRIORITY']; + } + else { + $maxPriority = $allAppDbData [$index2] ['DEL_PRIORITY']; + } + + $assignedUsers = array (); + $indexes = $this->aaSearchRecords ( $allAppDbData, array ( + 'DEL_THREAD_STATUS' => 'OPEN', + 'DEL_FINISH_DATE' => 'NULL', + 'APP_STATUS' => 'TO_DO', + 'APP_THREAD_STATUS' => 'OPEN' + ) ); + foreach ( $indexes as $index ) { + $assignedUsers [] = array ( + 'USR_UID' => $allAppDbData [$index] ['USR_UID'], + 'DEL_INDEX' => $allAppDbData [$index] ['DEL_INDEX'] + ); + } + + $assignedUsersRead = array (); + $indexes = $this->aaSearchRecords ( $allAppDbData, array ( + 'DEL_THREAD_STATUS' => 'OPEN', + 'DEL_FINISH_DATE' => 'NULL', + 'APP_STATUS' => 'TO_DO', + 'APP_THREAD_STATUS' => 'OPEN', + 'DEL_INIT_DATE' => 'NOTNULL' + ) ); + foreach ( $indexes as $index ) { + $assignedUsersRead [] = array ( + 'USR_UID' => $allAppDbData [$index] ['USR_UID'], + 'DEL_INDEX' => $allAppDbData [$index] ['DEL_INDEX'] + ); + } + + $assignedUsersUnread = array (); + $indexes = $this->aaSearchRecords ( $allAppDbData, array ( + 'DEL_THREAD_STATUS' => 'OPEN', + 'DEL_FINISH_DATE' => 'NULL', + 'APP_STATUS' => 'TO_DO', + 'APP_THREAD_STATUS' => 'OPEN', + 'DEL_INIT_DATE' => 'NULL' + ) ); + foreach ( $indexes as $index ) { + $assignedUsersUnread [] = array ( + 'USR_UID' => $allAppDbData [$index] ['USR_UID'], + 'DEL_INDEX' => $allAppDbData [$index] ['DEL_INDEX'] + ); + } + + $draftUser = array (); + $indexes = $this->aaSearchRecords ( $allAppDbData, array ( + 'DEL_THREAD_STATUS' => 'OPEN', + 'DEL_FINISH_DATE' => 'NULL', + 'APP_STATUS' => 'DRAFT', + 'APP_THREAD_STATUS' => 'OPEN' + ) ); + if (! empty ( $indexes )) { + $draftUser = array ( + 'USR_UID' => $allAppDbData [$indexes [0]] ['USR_UID'], + 'DEL_INDEX' => $allAppDbData [$indexes [0]] ['DEL_INDEX'] + ); + } + + $participatedUsers = array (); + foreach ( $allAppDbData as $row ) { + $participatedUsers [] = array ( + 'USR_UID' => $row ['USR_UID'], + 'DEL_INDEX' => $row ['DEL_INDEX'] + ); + } + + $participatedUsersStartedByUser = array (); + $indexes = $this->aaSearchRecords ( $allAppDbData, array ( + 'DEL_INDEX' => '1' + ) ); + foreach ( $indexes as $index ) { + $participatedUsersStartedByUser [] = array ( + 'USR_UID' => $allAppDbData [$index] ['USR_UID'], + 'DEL_INDEX' => $allAppDbData [$index] ['DEL_INDEX'] + ); + } + + $participatedUsersCompletedByUser = array (); + $indexes = $this->aaSearchRecords ( $allAppDbData, array ( + 'APP_STATUS' => 'COMPLETED' + ) ); + foreach ( $indexes as $index ) { + $participatedUsersCompletedByUser [] = array ( + 'USR_UID' => $allAppDbData [$index] ['USR_UID'], + 'DEL_INDEX' => $allAppDbData [$index] ['DEL_INDEX'] + ); + } + // search information of unassigned users + // the unassigned users are the self service users and groups. + // the self service users are defined in the TASKs of the PROCESS. + foreach ( $allAppDbData as $row ) { + $unassignedUsersGroups = array (); + // use cache + $oMemcache = PMmemcached::getSingleton ( $this->solrInstance ); + $unassignedUsersGroups = $oMemcache->get ( $row ['PRO_UID'] . "_" . $row ['TAS_UID'] ); + if (! $unassignedUsersGroups) { + + $unassignedUsersGroups = $this->getTaskUnassignedUsersGroupsData ( $row ['PRO_UID'], $row ['TAS_UID'] ); + + // add del_index + foreach ( $unassignedUsersGroups as $i => $newRow ) { + $unassignedUsersGroups [$i] ['DEL_INDEX'] = $row ['DEL_INDEX']; + } + // store in cache + $oMemcache->set ( $row ['PRO_UID'] . "_" . $row ['TAS_UID'], $unassignedUsersGroups ); + } + + // copy list of unassigned users and groups + $unassignedUsers = array (); + $unassignedGroups = array (); + foreach ( $unassignedUsersGroups as $unassignedUserGroup ) { + if ($unassignedUserGroup ['TU_RELATION'] == 1) { + $unassignedUsers [] = array ( + 'USR_UID' => $unassignedUserGroup ['USR_UID'], + 'DEL_INDEX' => $unassignedUserGroup ['DEL_INDEX'] + ); + } + elseif ($unassignedUserGroup ['TU_RELATION'] == 2) { + $unassignedGroups [] = array ( + 'USR_UID' => $unassignedUserGroup ['USR_UID'], + 'DEL_INDEX' => $unassignedUserGroup ['DEL_INDEX'] + ); + } + } + + } + // Get DataTypes of dynaforms + // use cache array to store the dynaform variables per process + // use memory array to store information of Datatypes of Dynaforms + // All the datatypes of the process => all variables in all dynaforms in the + // process + $dynaformFieldTypes = array (); + // get cache instance + $oMemcache = PMmemcached::getSingleton ( $this->solrInstance ); + $dynaformFieldTypes = $oMemcache->get ( $documentInformation ['PRO_UID'] ); + if (! $dynaformFieldTypes) { + G::LoadClass ( 'dynaformhandler' ); + $dynaformFileNames = $this->getProcessDynaformFileNames ( $documentInformation ['PRO_UID'] ); + $dynaformFields = array (); + foreach ( $dynaformFileNames as $dynaformFileName ) { + if (file_exists ( PATH_DATA . '/sites/workflow/xmlForms/' . $dynaformFileName ['DYN_FILENAME'] . '.xml' )) { + $dyn = new dynaFormHandler ( PATH_DATA . '/sites/workflow/xmlForms/' . $dynaformFileName ['DYN_FILENAME'] . '.xml' ); + $dynaformFields [] = $dyn->getFields (); + } + } + + foreach ( $dynaformFields as $aDynFormFields ) { + foreach ( $aDynFormFields as $field ) { + // create array of fields and types + if ($field->getAttribute ( 'validate' ) == 'Int') { + $dynaformFieldTypes [$field->nodeName] = 'Int'; + } + elseif ($field->getAttribute ( 'validate' ) == 'Real') { + $dynaformFieldTypes [$field->nodeName] = 'Real'; + } + else { + $dynaformFieldTypes [$field->nodeName] = $field->getAttribute ( 'type' ); + } + } + } + // create cache of dynaformfields + $oMemcache->set ( $documentInformation ['PRO_UID'], $dynaformFieldTypes ); + } + + // return result values + $result = array ( + $documentInformation, + $dynaformFieldTypes, + $lastUpdateDate, + $maxPriority, + $assignedUsers, + $assignedUsersRead, + $assignedUsersUnread, + $draftUser, + $participatedUsers, + $participatedUsersStartedByUser, + $participatedUsersCompletedByUser, + $unassignedUsers, + $unassignedGroups + ); + + return $result; + } + + /** + * Find the maximun value of the specified column in the array and return the + * row index + * + * @param array{array} $arr + * @param string $column + */ + function aaGetMaximun($arr, $column, $columnType = 'STRING', $columnCondition = "", $condition = "") { + // get first value + $auxValue = $arr [0] [$column]; + $index = null; + foreach ( $arr as $i => $row ) { + switch ($columnType) { + case 'STRING' : + if ((strnatcmp ( $row [$column], $auxValue ) >= 0) && (($columnCondition == "") || ($row [$columnCondition] == $condition))) { + $auxValue = $row [$column]; + $index = $i; + } + break; + case 'NUMBER' : + if (($row [$column] >= $auxValue) && (($columnCondition == "") || ($row [$columnCondition] == $condition))) { + $auxValue = $row [$column]; + $index = $i; + } + break; + case 'DATE' : + if ((strtotime ( $row [$column] ) >= strtotime ( $auxValue )) && (($columnCondition == "") || ($row [$columnCondition] == $condition))) { + $auxValue = $row [$column]; + $index = $i; + } + break; + } + } + return $index; + } + + /** + * Get minimum of array of arrays + * + * @param unknown_type $arr + * @param unknown_type $column + * @param unknown_type $columnType + * @param unknown_type $columnCondition + * @param unknown_type $condition + * @return Ambigous + */ + function aaGetMinimun($arr, $column, $columnType = 'STRING', $columnCondition = "", $condition = "") { + // get first value + $auxValue = $arr [0] [$column]; + $index = null; + foreach ( $arr as $i => $row ) { + switch ($columnType) { + case 'STRING' : + if ((strnatcmp ( $row [$column], $auxValue ) <= 0) && (($columnCondition == "") || ($row [$columnCondition] == $condition))) { + $auxValue = $row [$column]; + $index = $i; + } + break; + case 'NUMBER' : + if (($row [$column] <= $auxValue) && (($columnCondition == "") || ($row [$columnCondition] == $condition))) { + $auxValue = $row [$column]; + $index = $i; + } + break; + case 'DATE' : + if ((strtotime ( $row [$column] ) <= strtotime ( $auxValue )) && (($columnCondition == "") || ($row [$columnCondition] == $condition))) { + $auxValue = $row [$column]; + $index = $i; + + } + break; + } + } + return $index; + } + + /** + * Search array of indexes that fullfill the conditions + * + * @param + * array o arrays $arr contains the arrays that are searched + * @param array $andColumnsConditions + * contain the conditions that must be fullfill 'Column'=>'Condition' + * @return multitype:unknown + */ + function aaSearchRecords($arr, $andColumnsConditions) { + $indexes = array (); + $isEqual = true; + foreach ( $arr as $i => $row ) { + $evaluateRow = false; + // evaluate each row + foreach ( $andColumnsConditions as $column => $valueCondition ) { + $condition = $valueCondition; + $isEqual = true; + if ($valueCondition == 'NULL') { + $isEqual = true; + $condition = ''; + } + if ($valueCondition == 'NOTNULL') { + $isEqual = false; + $condition = ''; + } + if ($isEqual) { + if ($row [$column] == $condition) { + $evaluateRow = true; + } + else { + $evaluateRow = false; + breaK; + } + } + else { + if ($row [$column] != $condition) { + $evaluateRow = true; + } + else { + $evaluateRow = false; + breaK; + } + } + } + // add row to indexes + if ($evaluateRow) { + $indexes [] = $i; + } + } + return $indexes; + } + + function getApplicationDelegationData($AppUID) { + + $allAppDbData = array (); + + $c = new Criteria (); + + $c->addSelectColumn ( ApplicationPeer::APP_UID ); + $c->addSelectColumn ( ApplicationPeer::APP_NUMBER ); + $c->addSelectColumn ( ApplicationPeer::APP_STATUS ); + $c->addSelectColumn ( ApplicationPeer::PRO_UID ); + $c->addSelectColumn ( ApplicationPeer::APP_CREATE_DATE ); + $c->addSelectColumn ( ApplicationPeer::APP_FINISH_DATE ); + $c->addSelectColumn ( ApplicationPeer::APP_UPDATE_DATE ); + $c->addSelectColumn ( ApplicationPeer::APP_DATA ); + + $c->addAsColumn ( 'APP_TITLE', 'capp.CON_VALUE' ); + $c->addAsColumn ( 'PRO_TITLE', 'cpro.CON_VALUE' ); + + $c->addSelectColumn ( 'ad.DEL_INDEX' ); + $c->addSelectColumn ( 'ad.DEL_PREVIOUS' ); + $c->addSelectColumn ( 'ad.TAS_UID' ); + $c->addSelectColumn ( 'ad.USR_UID' ); + $c->addSelectColumn ( 'ad.DEL_TYPE' ); + $c->addSelectColumn ( 'ad.DEL_THREAD' ); + $c->addSelectColumn ( 'ad.DEL_THREAD_STATUS' ); + $c->addSelectColumn ( 'ad.DEL_PRIORITY' ); + $c->addSelectColumn ( 'ad.DEL_DELEGATE_DATE' ); + $c->addSelectColumn ( 'ad.DEL_INIT_DATE' ); + $c->addSelectColumn ( 'ad.DEL_TASK_DUE_DATE' ); + $c->addSelectColumn ( 'ad.DEL_FINISH_DATE' ); + $c->addSelectColumn ( 'ad.DEL_DURATION' ); + $c->addSelectColumn ( 'ad.DEL_QUEUE_DURATION' ); + $c->addSelectColumn ( 'ad.DEL_DELAY_DURATION' ); + $c->addSelectColumn ( 'ad.DEL_STARTED' ); + $c->addSelectColumn ( 'ad.DEL_FINISHED' ); + $c->addSelectColumn ( 'ad.DEL_DELAYED' ); + $c->addSelectColumn ( 'ad.APP_OVERDUE_PERCENTAGE' ); + + $c->addSelectColumn ( 'at.APP_THREAD_INDEX' ); + $c->addSelectColumn ( 'at.APP_THREAD_PARENT' ); + $c->addSelectColumn ( 'at.APP_THREAD_STATUS' ); + + $c->addAlias ( 'capp', 'CONTENT' ); + $c->addAlias ( 'cpro', 'CONTENT' ); + $c->addAlias ( 'ad', 'APP_DELEGATION' ); + $c->addAlias ( 'at', 'APP_THREAD' ); + + $aConditions = array (); + $aConditions [] = array ( + ApplicationPeer::APP_UID, + 'capp.CON_ID' + ); + $aConditions [] = array ( + 'capp.CON_CATEGORY', + DBAdapter::getStringDelimiter () . 'APP_TITLE' . DBAdapter::getStringDelimiter () + ); + $aConditions [] = array ( + 'capp.CON_LANG', + DBAdapter::getStringDelimiter () . 'en' . DBAdapter::getStringDelimiter () + ); + $c->addJoinMC ( $aConditions, Criteria::LEFT_JOIN ); + + $aConditions = array (); + $aConditions [] = array ( + ApplicationPeer::PRO_UID, + 'cpro.CON_ID' + ); + $aConditions [] = array ( + 'cpro.CON_CATEGORY', + DBAdapter::getStringDelimiter () . 'PRO_TITLE' . DBAdapter::getStringDelimiter () + ); + $aConditions [] = array ( + 'cpro.CON_LANG', + DBAdapter::getStringDelimiter () . 'en' . DBAdapter::getStringDelimiter () + ); + $c->addJoinMC ( $aConditions, Criteria::LEFT_JOIN ); + + $c->addJoin ( ApplicationPeer::APP_UID, 'ad.APP_UID', Criteria::JOIN ); + + $aConditions = array (); + $aConditions [] = array ( + 'ad.APP_UID', + 'at.APP_UID' + ); + $aConditions [] = array ( + 'ad.DEL_THREAD', + 'at.APP_THREAD_INDEX' + ); + $c->addJoinMC ( $aConditions, Criteria::JOIN ); + + $c->add ( ApplicationPeer::APP_UID, $AppUID ); + + $rs = ApplicationPeer::doSelectRS ( $c ); + $rs->setFetchmode ( ResultSet::FETCHMODE_ASSOC ); + + $rs->next (); + $row = $rs->getRow (); + + while ( is_array ( $row ) ) { + $allAppDbData [] = $row; + $rs->next (); + $row = $rs->getRow (); + } + return $allAppDbData; + } + + function getTaskUnassignedUsersGroupsData($ProUID, $TaskUID) { + $unassignedUsersGroups = array (); + + $c = new Criteria (); + + $c->addSelectColumn ( TaskUserPeer::USR_UID ); + $c->addSelectColumn ( TaskUserPeer::TU_RELATION ); + + $aConditions = array (); + $aConditions [] = array ( + TaskPeer::TAS_UID, + TaskUserPeer::TAS_UID + ); + $aConditions [] = array ( + TaskPeer::TAS_ASSIGN_TYPE, + DBAdapter::getStringDelimiter () . 'SELF_SERVICE' . DBAdapter::getStringDelimiter () + ); + $c->addJoinMC ( $aConditions, Criteria::JOIN ); + + $c->add ( TaskPeer::PRO_UID, $ProUID ); + $c->add ( TaskPeer::TAS_UID, $TaskUID ); + + $rs = TaskPeer::doSelectRS ( $c ); + $rs->setFetchmode ( ResultSet::FETCHMODE_ASSOC ); + // echo $c->toString(); + $rs->next (); + $row = $rs->getRow (); + + while ( is_array ( $row ) ) { + $unassignedUsersGroups [] = $row; + $rs->next (); + $row = $rs->getRow (); + } + + return $unassignedUsersGroups; + } + + function getProcessDynaformFileNames($ProUID) { + $dynaformFileNames = array (); + + $c = new Criteria (); + + $c->addSelectColumn ( DynaformPeer::DYN_FILENAME ); + + $c->add ( DynaformPeer::PRO_UID, $ProUID ); + + $rs = DynaformPeer::doSelectRS ( $c ); + $rs->setFetchmode ( ResultSet::FETCHMODE_ASSOC ); + $rs->next (); + $row = $rs->getRow (); + + while ( is_array ( $row ) ) { + $dynaformFileNames [] = $row; + $rs->next (); + $row = $rs->getRow (); + } + + return $dynaformFileNames; + } + /** + * Store a flag indicating if the application was updated + * + * @param unknown_type $AppUid + * @param integer $updated + * 0:false, not updated, 1: updated, 2:deleted + */ + function applicationChangedUpdateSolrQueue($AppUid, $updated) { + $oAppSolrQueue = new AppSolrQueue (); + + $oAppSolrQueue->createUpdate ( $AppUid, $updated ); + } + + function synchronizePendingApplications() { + // check table of pending updates + $oAppSolrQueue = new AppSolrQueue (); + + $aAppSolrQueue = $oAppSolrQueue->getListUpdatedApplications (); + + foreach ( $aAppSolrQueue as $oAppSolrQueueEntity ) { + // call the syncronization function + $this->updateApplicationSearchIndex ( $oAppSolrQueueEntity->appUid ); + $this->applicationChangedUpdateSolrQueue ( $oAppSolrQueueEntity->appUid, 0 ); + } + + } + + function getCountApplicationsPMOS2() { + $c = new Criteria (); + + $c->addSelectColumn ( ApplicationPeer::APP_UID ); + + $count = ApplicationPeer::doCount ( $c ); + + return $count; + } + + function getPagedApplicationUids($skip, $pagesize) { + + $c = new Criteria (); + + $c->addSelectColumn ( ApplicationPeer::APP_UID ); + $c->setOffset ( $skip ); + $c->setLimit ( $pagesize ); + + $rs = ApplicationPeer::doSelectRS ( $c ); + $rs->setFetchmode ( ResultSet::FETCHMODE_ASSOC ); + + $rs->next (); + $row = $rs->getRow (); + $appUIds = array (); + while ( is_array ( $row ) ) { + $appUIds [] = $row; + $rs->next (); + $row = $rs->getRow (); + } + return $appUIds; + } + + function reindexAllApplications() { + $trunk = 1000; + // delete all documents to begin reindex + // deleteAllDocuments(); + // commitChanges(); + // print "Deleted all documents \n"; + // search trunks of id's to regenerate index + $numRows = $this->getCountApplicationsPMOS2 (); + print "Total number of records: " . $numRows . "\n"; + // + $initTimeAll = microtime ( true ); + // $numRows = 15; + for($skip = 0; $skip <= $numRows;) { + $aaAPPUIds = $this->getPagedApplicationUids ( $skip, $trunk ); + + printf ( "Indexing %d to %d \n", $skip, $skip + $trunk ); + $initTimeDoc = microtime ( true ); + $this->updateApplicationSearchIndex ( $aaAPPUIds ); + + $curTimeDoc = gmdate ( 'H:i:s', (microtime ( true ) - $initTimeDoc) ); + printf ( "Indexing document time: %s \n", $curTimeDoc ); + $skip += $trunk; + } + + $curTimeDoc = gmdate ( 'H:i:s', (microtime ( true ) - $initTimeAll) ); + printf ( "Total reindex time: %s \n", $curTimeDoc ); + } + +} diff --git a/workflow/engine/classes/class.case.php b/workflow/engine/classes/class.case.php index fea4199d5..1011dc2d3 100755 --- a/workflow/engine/classes/class.case.php +++ b/workflow/engine/classes/class.case.php @@ -833,6 +833,9 @@ class Cases { */ function updateCase($sAppUid, $Fields = array()) { + //initialize solrindex object + G::LoadClass('AppSolr'); + $appSolr = new AppSolr(); try { $aApplicationFields = $Fields['APP_DATA']; $Fields['APP_UID'] = $sAppUid; @@ -920,7 +923,9 @@ class Cases { } } } - + //Update Solr Index + $appSolr->updateApplicationSearchIndex($sAppUid); + return $Fields; } catch (exception $e) { @@ -937,6 +942,9 @@ class Cases { */ function removeCase($sAppUid) { + //initialize solrindex object + G::LoadClass('AppSolr'); + $appSolr = new AppSolr(); try { $oApplication = new Application(); $oAppDelegation = new AppDelegation(); @@ -990,7 +998,12 @@ class Cases { $oCriteria2->add(SubApplicationPeer::APP_PARENT, $sAppUid); SubApplicationPeer::doDelete($oCriteria2); $oApp = new Application; - return $oApp->remove($sAppUid); + $result = $oApp->remove($sAppUid); + + //delete application from index + $appSolr->deleteApplicationSearchIndex($sAppUid); + + return $result; } catch (exception $e) { throw ($e); } @@ -1006,10 +1019,15 @@ class Cases { */ function setDelInitDate($sAppUid, $iDelIndex) { + //initialize solrindex object + G::LoadClass('AppSolr'); + $appSolr = new AppSolr(); try { $oAppDel = AppDelegationPeer::retrieveByPk($sAppUid, $iDelIndex); $oAppDel->setDelInitDate("now"); $oAppDel->save(); + //update searchindex + $appSolr->updateApplicationSearchIndex($sAppUid); } catch (exception $e) { throw ($e); } @@ -1026,11 +1044,17 @@ class Cases { */ function setCatchUser($sAppUid, $iDelIndex, $usrId) { + //initialize solrindex object + G::LoadClass('AppSolr'); + $appSolr = new AppSolr(); try { $oAppDel = AppDelegationPeer::retrieveByPk($sAppUid, $iDelIndex); $oAppDel->setDelInitDate("now"); $oAppDel->setUsrUid($usrId); $oAppDel->save(); + + //update searchindex + $appSolr->updateApplicationSearchIndex($sAppUid); } catch (exception $e) { throw ($e); } @@ -1436,9 +1460,15 @@ class Cases { */ function newAppDelegation($sProUid, $sAppUid, $sTasUid, $sUsrUid, $sPrevious, $iPriority, $sDelType, $iAppThreadIndex = 1, $nextDel=null) { + //initialize solrindex object + G::LoadClass('AppSolr'); + $appSolr = new AppSolr(); try { $appDel = new AppDelegation(); - return $appDel->createAppDelegation($sProUid, $sAppUid, $sTasUid, $sUsrUid, $iAppThreadIndex, $iPriority, false, $sPrevious, $nextDel); + $result = $appDel->createAppDelegation($sProUid, $sAppUid, $sTasUid, $sUsrUid, $iAppThreadIndex, $iPriority, false, $sPrevious, $nextDel); + //update searchindex + $appSolr->updateApplicationSearchIndex($sAppUid); + return $result; } catch (exception $e) { throw ($e); @@ -1457,6 +1487,9 @@ class Cases { */ function updateAppDelegation($sAppUid, $iDelIndex, $iAppThreadIndex) { + //initialize solrindex object + G::LoadClass('AppSolr'); + $appSolr = new AppSolr(); try { $appDelegation = new AppDelegation(); $aData = array(); @@ -1465,6 +1498,9 @@ class Cases { $aData['DEL_THREAD'] = $iAppThreadIndex; $appDelegation->update($aData); + //update searchindex + $appSolr->updateApplicationSearchIndex($sAppUid); + return true; } catch (exception $e) { throw ($e); @@ -1540,6 +1576,9 @@ class Cases { */ function updateAppThread($sAppUid, $iAppThreadIndex, $iNewDelIndex) { + //initialize solrindex object + G::LoadClass('AppSolr'); + $appSolr = new AppSolr(); try { /// updating the DEL_INDEX value in the APP_THREAD $con = Propel::getConnection('workflow'); @@ -1559,6 +1598,9 @@ class Cases { $aData['DEL_INDEX'] = $iNewDelIndex; $appThread->update($aData); */ + //update searchindex + $appSolr->updateApplicationSearchIndex($sAppUid); + return $iNewDelIndex; } catch (exception $e) { @@ -1576,6 +1618,9 @@ class Cases { */ function closeAppThread($sAppUid, $iAppThreadIndex) { +// //initialize solrindex object called from other functions +// G::LoadClass('AppSolr'); +// $appSolr = new AppSolr(); try { $appThread = new AppThread(); $aData = array(); @@ -1584,6 +1629,8 @@ class Cases { $aData['APP_THREAD_STATUS'] = 'CLOSED'; $appThread->update($aData); +// //update searchindex +// $appSolr->updateApplicationSearchIndex($sAppUid); return true; } catch (exception $e) { throw ($e); @@ -1599,6 +1646,9 @@ class Cases { */ function closeAllThreads($sAppUid) { + //initialize solrindex object + G::LoadClass('AppSolr'); + $appSolr = new AppSolr(); try { //Execute('UPDATE APP_DELEGATION SET DEL_THREAD_STATUS="CLOSED" WHERE APP_UID="$sAppUid" AND DEL_THREAD_STATUS="OPEN"'); $c = new Criteria(); @@ -1616,6 +1666,8 @@ class Cases { throw (new PropelException('The row cannot be created!', new PropelException($msg))); } } + //update searchindex + $appSolr->updateApplicationSearchIndex($sAppUid); } catch (exception $e) { throw ($e); } @@ -1633,9 +1685,15 @@ class Cases { */ function newAppThread($sAppUid, $iNewDelIndex, $iAppParent) { + //initialize solrindex object + G::LoadClass('AppSolr'); + $appSolr = new AppSolr(); try { $appThread = new AppThread(); - return $appThread->createAppThread($sAppUid, $iNewDelIndex, $iAppParent); + $result = $appThread->createAppThread($sAppUid, $iNewDelIndex, $iAppParent); + //update searchindex + $appSolr->updateApplicationSearchIndex($sAppUid); + return $result; } catch (exception $e) { throw ($e); } @@ -1650,6 +1708,9 @@ class Cases { */ function closeAllDelegations($sAppUid) { + //initialize solrindex object + G::LoadClass('AppSolr'); + $appSolr = new AppSolr(); try { //Execute('UPDATE APP_DELEGATION SET DEL_THREAD_STATUS="CLOSED" WHERE APP_UID="$sAppUid" AND DEL_THREAD_STATUS="OPEN"'); $c = new Criteria(); @@ -1667,6 +1728,8 @@ class Cases { throw (new PropelException('The row cannot be created!', new PropelException($msg))); } } + //update searchindex + $appSolr->updateApplicationSearchIndex($sAppUid); } catch (exception $e) { throw ($e); } @@ -1682,6 +1745,10 @@ class Cases { */ function CloseCurrentDelegation($sAppUid, $iDelIndex) { + //called from other functions +// //initialize solrindex object +// G::LoadClass('AppSolr'); +// $appSolr = new AppSolr(); try { //Execute('UPDATE APP_DELEGATION SET DEL_THREAD_STATUS="CLOSED" WHERE APP_UID="$sAppUid" AND DEL_THREAD_STATUS="OPEN"'); $c = new Criteria(); @@ -1703,6 +1770,9 @@ class Cases { throw (new PropelException('The row cannot be created!', new PropelException($msg))); } } +// //update searchindex +// $appSolr->updateApplicationSearchIndex($sAppUid); + } catch (exception $e) { throw ($e); } @@ -1719,6 +1789,9 @@ class Cases { */ function ReactivateCurrentDelegation($sAppUid, $iDelegation) { +// //initialize solrindex object called from other function +// G::LoadClass('AppSolr'); +// $appSolr = new AppSolr(); try { $c = new Criteria(); $c->add(AppDelegationPeer::APP_UID, $sAppUid); @@ -1737,6 +1810,8 @@ class Cases { throw (new PropelException('The row cannot be created!', new PropelException($msg))); } } +// //update searchindex +// $appSolr->updateApplicationSearchIndex($sAppUid); } catch (exception $e) { throw ($e); } @@ -1754,7 +1829,11 @@ class Cases { function startCase($sTasUid, $sUsrUid, $isSubprocess=false) { if ($sTasUid != '') { - try { + //initialize solrindex object + G::LoadClass('AppSolr'); + $appSolr = new AppSolr(); + + try { $this->Task = new Task; $Fields = $this->Task->Load($sTasUid); @@ -1795,6 +1874,8 @@ class Cases { G::LoadClass('derivation'); $oDerivation = new Derivation(); $oDerivation->setTasLastAssigned($sTasUid, $sUsrUid); + //update searchindex + $appSolr->updateApplicationSearchIndex($sAppUid); } catch (exception $e) { throw ($e); } @@ -3341,6 +3422,10 @@ class Cases { */ function pauseCase($sApplicationUID, $iDelegation, $sUserUID, $sUnpauseDate = null) { + //initialize solrindex object + G::LoadClass('AppSolr'); + $appSolr = new AppSolr(); + $this->CloseCurrentDelegation($sApplicationUID, $iDelegation); $oApplication = new Application(); $aFields = $oApplication->Load($sApplicationUID); @@ -3368,6 +3453,9 @@ class Cases { $aData['APP_DISABLE_ACTION_DATE'] = $sUnpauseDate; $oAppDelay = new AppDelay(); $oAppDelay->create($aData); + + //update searchindex + $appSolr->updateApplicationSearchIndex($sApplicationUID); } /* @@ -3427,6 +3515,9 @@ class Cases { $aData['APP_DISABLE_ACTION_DATE'] = date('Y-m-d H:i:s'); $oAppDelay = new AppDelay(); $aFieldsDelay = $oAppDelay->update($aData); + + //update searchindex + $appSolr->updateApplicationSearchIndex($sApplicationUID); } /* @@ -3440,6 +3531,10 @@ class Cases { */ function cancelCase($sApplicationUID, $iIndex, $user_logged) { + //initialize solrindex object + G::LoadClass('AppSolr'); + $appSolr = new AppSolr(); + $oApplication = new Application(); $aFields = $oApplication->load($sApplicationUID); $oCriteria = new Criteria('workflow'); @@ -3496,6 +3591,9 @@ class Cases { $oDerivation = new Derivation(); $oDerivation->verifyIsCaseChild($sApplicationUID); } + + //update searchindex + $appSolr->updateApplicationSearchIndex($sApplicationUID); } /* @@ -3509,6 +3607,10 @@ class Cases { */ function reactivateCase($sApplicationUID, $iIndex, $user_logged) { + //initialize solrindex object + G::LoadClass('AppSolr'); + $appSolr = new AppSolr(); + $oApplication = new Application(); $aFields = $oApplication->load((isset($_POST['sApplicationUID']) ? $_POST['sApplicationUID'] : $_SESSION['APPLICATION'])); $aFields['APP_STATUS'] = 'TO_DO'; @@ -3542,6 +3644,9 @@ class Cases { $sql = "UPDATE APP_THREAD SET APP_THREAD_STATUS = 'OPEN' WHERE APP_UID = '$sApplicationUID' AND DEL_INDEX ='$iIndex' "; $stmt = $con->createStatement(); $rs = $stmt->executeQuery($sql, ResultSet::FETCHMODE_ASSOC); + + //update searchindex + $appSolr->updateApplicationSearchIndex($sApplicationUID); } /* @@ -3557,6 +3662,10 @@ class Cases { */ function reassignCase($sApplicationUID, $iDelegation, $sUserUID, $newUserUID, $sType = 'REASSIGN') { + //initialize solrindex object + G::LoadClass('AppSolr'); + $appSolr = new AppSolr(); + $this->CloseCurrentDelegation($sApplicationUID, $iDelegation); $oAppDelegation = new AppDelegation(); $aFieldsDel = $oAppDelegation->Load($sApplicationUID, $iDelegation); @@ -3589,6 +3698,10 @@ class Cases { $aData['APP_ENABLE_ACTION_DATE'] = date('Y-m-d H:i:s'); $oAppDelay = new AppDelay(); $oAppDelay->create($aData); + + //update searchindex + $appSolr->updateApplicationSearchIndex($sApplicationUID); + return true; } @@ -5040,6 +5153,10 @@ class Cases { */ function executeTriggersAfterExternal($sProcess, $sTask, $sApplication, $iIndex, $iStepPosition, $aNewData = array()) { +// //initialize solrindex object UpdateCase añready calls the update +// G::LoadClass('AppSolr'); +// $appSolr = new AppSolr(); + //load the variables $Fields = $this->loadCase($sApplication); $Fields['APP_DATA'] = array_merge($Fields['APP_DATA'], G::getSystemConstants()); @@ -5056,6 +5173,9 @@ class Cases { $aData['DEL_INDEX'] = $iIndex; $aData['TAS_UID'] = $sTask; $this->updateCase($sApplication, $aData); + +// //update searchindex +// $appSolr->updateApplicationSearchIndex($sApplication); } /* @@ -5408,11 +5528,18 @@ class Cases { } function discriminateCases($aData){ + //initialize solrindex object + G::LoadClass('AppSolr'); + $appSolr = new AppSolr(); + $siblingThreadData = $this->GetAllOpenDelegation($aData); foreach($siblingThreadData as $thread => $threadData) { $this->closeAppThread ( $aData['APP_UID'], $threadData['DEL_INDEX']); //Close Sibling AppThreads $this->CloseCurrentDelegation ($aData['APP_UID'], $threadData['DEL_INDEX']); //Close Sibling AppDelegations + + //update searchindex + $appSolr->updateApplicationSearchIndex($aData['APP_UID']); } } diff --git a/workflow/engine/classes/class.fileCache.php b/workflow/engine/classes/class.fileCache.php new file mode 100644 index 000000000..a9d4efbc4 --- /dev/null +++ b/workflow/engine/classes/class.fileCache.php @@ -0,0 +1,110 @@ +. + * + * For more information, contact Colosa Inc, 2566 Le Jeune Rd., + * Coral Gables, FL, 33134, USA, or email info@colosa.com. + * + */ + +class FileCache { + + function __construct($dir) { + $this->dir = $dir; + } + + private function _name($key) { + return sprintf ( "%s/%s", $this->dir, sha1 ( $key ) ); + } + + public function get($key, $expiration = 3600) { + + if (! is_dir ( $this->dir ) or ! is_writable ( $this->dir )) { + return FALSE; + } + + $cache_path = $this->_name ( $key ); + + if (! @file_exists ( $cache_path )) { + return FALSE; + } + + if (filemtime ( $cache_path ) < (time () - $expiration)) { + // $this->clear($key); + // different users can have different timeout requests + return FALSE; + } + + if (! $fp = @fopen ( $cache_path, 'rb' )) { + return FALSE; + } + + flock ( $fp, LOCK_SH ); + + $cache = ''; + + if (filesize ( $cache_path ) > 0) { + $cache = unserialize ( fread ( $fp, filesize ( $cache_path ) ) ); + } + else { + $cache = NULL; + } + + flock ( $fp, LOCK_UN ); + fclose ( $fp ); + + return $cache; + } + + public function set($key, $data) { + + if (! is_dir ( $this->dir ) or ! is_writable ( $this->dir )) { + return FALSE; + } + + $cache_path = $this->_name ( $key ); + + if (! $fp = fopen ( $cache_path, 'wb' )) { + return FALSE; + } + + if (flock ( $fp, LOCK_EX )) { + fwrite ( $fp, serialize ( $data ) ); + flock ( $fp, LOCK_UN ); + } + else { + return FALSE; + } + fclose ( $fp ); + @chmod ( $cache_path, 0777 ); + return TRUE; + } + + public function clear($key) { + $cache_path = $this->_name ( $key ); + + if (file_exists ( $cache_path )) { + unlink ( $cache_path ); + return TRUE; + } + + return FALSE; + } +} \ No newline at end of file diff --git a/workflow/engine/classes/class.memcached.php b/workflow/engine/classes/class.memcached.php index a59c89039..4e5a92359 100644 --- a/workflow/engine/classes/class.memcached.php +++ b/workflow/engine/classes/class.memcached.php @@ -24,131 +24,164 @@ * */ - /** * The ProcessMaker memcached class + * * @package workflow.engine.ProcessMaker */ - class PMmemcached { - const ONE_MINUTE = 60; - const ONE_HOUR = 3600; - const TWO_HOURS = 7200; - const EIGHT_HOURS = 28800; - - var $version; - var $mem; - var $connected = false; - var $enabled = false; - var $supported = false; - - static private $instance = NULL; - - private function __construct( $workspace ) { - $this->enabled = MEMCACHED_ENABLED; - $this->connected = false; - $this->workspace = $workspace; - if (class_exists('Memcached')) { - $this->mem = new Memcached(); - $this->class = 'Memcached'; - } - else { - if (class_exists('Memcache')) { - $this->mem = new Memcache(); - $this->class = 'Memcache'; - $this->supported = true; - $this->connected = @$this->mem->connect( MEMCACHED_SERVER , 11211); - if ( $this->connected ) { - $this->version = $this->mem->getVersion(); - } +class PMmemcached { + const ONE_MINUTE = 60; + const ONE_HOUR = 3600; + const TWO_HOURS = 7200; + const EIGHT_HOURS = 28800; + + var $version; + var $mem; + var $connected = false; + var $enabled = false; + var $supported = false; + + private static $instance = NULL; + + private function __construct($workspace) { + $this->enabled = MEMCACHED_ENABLED; + $this->connected = false; + $this->workspace = $workspace; + if (class_exists ( 'Memcached' )) { + $this->mem = new Memcached (); + $this->class = 'Memcached'; + $this->connected = true; + } + else { + if (class_exists ( 'Memcache' )) { + $this->mem = new Memcache (); + $this->class = 'Memcache'; + $this->supported = true; + $this->connected = @$this->mem->connect ( MEMCACHED_SERVER, 11211 ); + if ($this->connected) { + $this->version = $this->mem->getVersion (); } } - - if ( ! MEMCACHED_ENABLED ) { - $this->connected = false; - return false; - } - - } - - /** - * to get singleton instance - * - * @access public - * @return object - */ - function &getSingleton( $workspace ) { - if (self::$instance == NULL) { - self::$instance = new PMmemcached( $workspace ); + else { + G::Loadclass ( 'fileCache' ); + // create cache folder + $cacheFolder = PATH_DATA . "sites/" . $workspace . "/cachefiles/"; + if (! file_exists ( $cacheFolder )) { + if (! mkdir ( $cacheFolder )) { + return false; + } + } + $this->class = 'fileCache'; + $this->connected = true; + $this->mem = new FileCache ( $cacheFolder ); } - return self::$instance; } - - function set($key, $object, $timeout=0) { - if (! $this->connected ) return false; - $this->mem->set( $this->workspace . '_' . $key, $object, false, $timeout) ; - } - - function get($key) { - if (! $this->connected ) return false; - return $this->mem->get( $this->workspace . '_' . $key) ; - } - - function add($key, $value ) { - if (! $this->connected ) return false; - return $this->mem->add( $this->workspace . '_' . $key, $value ) ; - } - - function increment($key, $value ) { - if (! $this->connected ) return false; - return $this->mem->increment( $this->workspace . '_' . $key, $value ) ; - } - - function delete($key) { - if (! $this->connected ) return false; - return $this->mem->delete( $this->workspace . '_' . $key) ; - } - - function flush() { - if (! $this->connected ) return false; - return $this->mem->flush(); - } - - function getStats() { - if (! $this->connected ) return false; - return $status = $this->mem->getStats(); + + if (! MEMCACHED_ENABLED) { + $this->connected = false; + return false; } - - function printDetails() { - if (! $this->connected ) return false; - $status = $this->mem->getStats(); - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - - $percCacheHit=((real)$status ["get_hits"]/ (real)$status ["cmd_get"] *100); - $percCacheHit=round($percCacheHit,3); - $percCacheMiss=100-$percCacheHit; - - echo ""; - echo ""; - - $MBRead= (real)$status["bytes_read"]/(1024*1024); - - echo ""; - $MBWrite=(real) $status["bytes_written"]/(1024*1024) ; - echo ""; - $MBSize=(real) $status["limit_maxbytes"]/(1024*1024) ; - echo ""; - echo ""; - echo "
Memcache Server version: ".$status ["version"]."
Number of hours this server has been running " . ($status ["uptime"] /3660) ."
Total number of items stored by this server ever since it started ".$status ["total_items"]."
Number of open connections ".$status ["curr_connections"]."
Total number of connections opened since the server started running ".$status ["total_connections"]."
Number of connection structures allocated by the server ".$status ["connection_structures"]."
Cumulative number of retrieval requests ".$status ["cmd_get"]."
Cumulative number of storage requests ".$status ["cmd_set"]."
Number of keys that have been requested and found present ".$status ["get_hits"]." ($percCacheHit%)
Number of items that have been requested and not found ".$status ["get_misses"]."($percCacheMiss%)
Total number of bytes read by this server from network ".$MBRead." Mega Bytes
Total number of bytes sent by this server to network ".$MBWrite." Mega Bytes
Number of bytes this server is allowed to use for storage.".$MBSize." Mega Bytes
Number of valid items removed from cache to free memory for new items.".$status ["evictions"]."
"; + + } + + /** + * to get singleton instance + * + * @access public + * @return object + */ + public static function getSingleton($workspace) { + if (! self::$instance instanceof self) { + self::$instance = new PMmemcached ( $workspace ); } - + return self::$instance; + } + + public function __clone() { + throw new Exception ( "Clone is not allowed." ); + } + + public function __wakeup() { + throw new Exception ( "Deserializing is not allowed." ); + } + + function set($key, $object, $timeout = 0) { + if (! $this->connected) + return false; + if ($this->class != 'filecache') + $this->mem->set ( $this->workspace . '_' . $key, $object, false, $timeout ); + else + $this->mem->set ( $this->workspace . '_' . $key, $object ); + } + + function get($key) { + if (! $this->connected) + return false; + return $this->mem->get ( $this->workspace . '_' . $key ); + } + + function add($key, $value) { + if ((! $this->connected) || ($this->class == 'filecache')) + return false; + return $this->mem->add ( $this->workspace . '_' . $key, $value ); + } + + function increment($key, $value) { + if ((! $this->connected) || ($this->class == 'filecache')) + return false; + return $this->mem->increment ( $this->workspace . '_' . $key, $value ); + } + + function delete($key) { + if ((! $this->connected) || ($this->class == 'filecache')) + return false; + return $this->mem->delete ( $this->workspace . '_' . $key ); + } + + function flush() { + if ((! $this->connected) || ($this->class == 'filecache')) + return false; + return $this->mem->flush (); + } + + function getStats() { + if ((! $this->connected) || ($this->class == 'filecache')) + return false; + return $status = $this->mem->getStats (); + } + + function printDetails() { + if ((! $this->connected) || ($this->class == 'filecache')) + return false; + $status = $this->mem->getStats (); + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + + $percCacheHit = (( real ) $status ["get_hits"] / ( real ) $status ["cmd_get"] * 100); + $percCacheHit = round ( $percCacheHit, 3 ); + $percCacheMiss = 100 - $percCacheHit; + + echo ""; + echo ""; + + $MBRead = ( real ) $status ["bytes_read"] / (1024 * 1024); + + echo ""; + $MBWrite = ( real ) $status ["bytes_written"] / (1024 * 1024); + echo ""; + $MBSize = ( real ) $status ["limit_maxbytes"] / (1024 * 1024); + echo ""; + echo ""; + echo "
Memcache Server version: " . $status ["version"] . "
Number of hours this server has been running " . ($status ["uptime"] / 3660) . "
Total number of items stored by this server ever since it started " . $status ["total_items"] . "
Number of open connections " . $status ["curr_connections"] . "
Total number of connections opened since the server started running " . $status ["total_connections"] . "
Number of connection structures allocated by the server " . $status ["connection_structures"] . "
Cumulative number of retrieval requests " . $status ["cmd_get"] . "
Cumulative number of storage requests " . $status ["cmd_set"] . "
Number of keys that have been requested and found present " . $status ["get_hits"] . " ($percCacheHit%)
Number of items that have been requested and not found " . $status ["get_misses"] . "($percCacheMiss%)
Total number of bytes read by this server from network " . $MBRead . " Mega Bytes
Total number of bytes sent by this server to network " . $MBWrite . " Mega Bytes
Number of bytes this server is allowed to use for storage." . $MBSize . " Mega Bytes
Number of valid items removed from cache to free memory for new items." . $status ["evictions"] . "
"; } +} + diff --git a/workflow/engine/classes/class.searchIndex.php b/workflow/engine/classes/class.searchIndex.php new file mode 100644 index 000000000..61a4d3836 --- /dev/null +++ b/workflow/engine/classes/class.searchIndex.php @@ -0,0 +1,364 @@ +solrIsEnabled = $registry->isRegistered('solrEnabled') && $registry->get('solrEnabled') == 1; +// $this->solrHost = $registry->isRegistered('solrHost')?$registry->get('solrHost'):""; +// } +// else{ +// //use the parameters to initialize class + $this->solrIsEnabled = $solrIsEnabled; + $this->solrHost = $solrHost; +// } + } + /** + * Verify if the Solr service is available + * @gearman = false + * @rest = false + * @background = false + * + * no input parameters @param[in] + * @param[out] bool true if index service is enabled false in other case + */ + public function isEnabled() + { + //require_once (ROOT_PATH . '/businessLogic/modules/SearchIndexAccess/Solr.php'); + require_once ('class.solr.php'); + $solr = new BpmnEngine_SearchIndexAccess_Solr($this->solrIsEnabled, $this->solrHost); + return $solr->isEnabled(); + } + + + /** + * Get the list of facets in base to the specified query and filter + * @gearman = true + * @rest = false + * @background = false + * + * @param[in] Entity_FacetRequest facetRequestEntity Facet request entity + * @param[out] array FacetGroup + */ + function getFacetsList($facetRequestEntity) + { + require_once ('class.solr.php'); + //require_once (ROOT_PATH . '/businessLogic/modules/SearchIndexAccess/Solr.php'); + require_once ('entities/FacetGroup.php'); + require_once ('entities/FacetItem.php'); + require_once ('entities/SelectedFacetGroupItem.php'); + require_once ('entities/FacetResult.php'); + + /******************************************************************/ + //get array of selected facet groups + $facetRequestEntity->selectedFacetsString = str_replace(',,', ',', $facetRequestEntity->selectedFacetsString); + //remove descriptions of selected facet groups + + $aGroups = explode(',', $facetRequestEntity->selectedFacetsString); + + $aGroups = array_filter($aGroups);//remove empty items + + $aSelectedFacetGroups = array(); + foreach($aGroups as $i => $value) + { + $gi = explode(':::', $value); + $gr = explode('::', $gi[0]); + $it = explode('::', $gi[1]); + + //create string for remove condition + $count = 0; + $removeCondition = str_replace($value . ',', '', $facetRequestEntity->selectedFacetsString, $count); + if($count == 0) + { + $removeCondition = str_replace($value, '', $facetRequestEntity->selectedFacetsString, $count); + } + $selectedFacetGroupData= array( + 'selectedFacetGroupName' => $gr[0], + 'selectedFacetGroupPrintName' => $gr[1], + 'selectedFacetItemName' => $it[0], + 'selectedFacetItemPrintName' => $it[1], + 'selectedFacetRemoveCondition' => $removeCondition + ); + + $aSelectedFacetGroups[] = Entity_SelectedFacetGroupItem::CreateForRequest($selectedFacetGroupData); + } + + /******************************************************************/ + //convert request to index request + //create filters + $filters = array(); + if (!empty($aSelectedFacetGroups)) { + //exclude facetFields and facetDates included in filter from the next list of facets + foreach ($aSelectedFacetGroups as $value) { + $facetRequestEntity->facetFields = array_diff($facetRequestEntity->facetFields, array($value->selectedFacetGroupName)); + $facetRequestEntity->facetDates = array_diff($facetRequestEntity->facetDates, array($value->selectedFacetGroupName)); + } + + //$facetFields = array_diff($facetFields, $facetInterfaceRequestEntity->selectedFacetGroups); + //$facetDates = array_diff($facetDates, $facetInterfaceRequestEntity->selectedFacetGroups); + foreach ($aSelectedFacetGroups as $group) { + $filters[] = $group->selectedFacetGroupName . ':' . urlencode($group->selectedFacetItemName); + } + } + $facetRequestEntity->filters = $filters; + + $solr = new BpmnEngine_SearchIndexAccess_Solr($this->solrIsEnabled, $this->solrHost); + + //create list of facets + $facetsList = $solr->getFacetsList($facetRequestEntity); + + $numFound = $facetsList['response']['numFound']; + + $facetCounts = $facetsList['facet_counts']; + + $facetGroups = array(); + //convert facet fields result to objects + /************************************************************************/ + //include facet field results + $facetFieldsResult = $facetsList['facet_counts']['facet_fields']; + if(!empty($facetFieldsResult)) + { + foreach($facetFieldsResult as $facetGroup => $facetvalues) + { + if(count($facetvalues) > 0) //if the group have facets included + { + $data = array('facetGroupName' => $facetGroup); + $data['facetGroupPrintName'] = $facetGroup; + $data['facetGroupType'] = 'field'; + $facetItems = array(); + for($i = 0; $i < count($facetvalues) ; $i+=2) + { + $dataItem = array(); + $dataItem['facetName'] = $facetvalues[$i]; + $dataItem['facetPrintName'] = $facetvalues[$i]; + $dataItem['facetCount'] = $facetvalues[$i+1]; + $dataItem['facetSelectCondition'] = $facetRequestEntity->selectedFacetsString . (empty($facetRequestEntity->selectedFacetsString)?'':',') . $data['facetGroupName'] . '::' . $data['facetGroupPrintName'] .':::' . $dataItem['facetName'] . '::' . $dataItem['facetPrintName']; + $newFacetItem = Entity_FacetItem::CreateForInsert($dataItem); + $facetItems[] =$newFacetItem; + } + $data['facetItems'] = $facetItems; + $newFacetGroup = Entity_FacetGroup::CreateForInsert($data); + + $facetGroups[] = $newFacetGroup; + } + } + } + /************************************************************************/ + //include facet date ranges results + $facetDatesResult = $facetsList['facet_counts']['facet_dates']; + if(!empty($facetDatesResult)) + { + foreach($facetDatesResult as $facetGroup => $facetvalues) + { + if(count($facetvalues) > 3) //if the group have any facets included besides start, end and gap + { + $data = array('facetGroupName' => $facetGroup); + $data['facetGroupPrintName'] = $facetGroup; + $data['facetGroupType'] = 'daterange'; + $facetItems = array(); + $facetvalueskeys = array_keys($facetvalues); + foreach ($facetvalueskeys as $i => $k) + { + if($k != 'gap' && $k != 'start' && $k != 'end') + { + $dataItem = array(); + if($i < count($facetvalueskeys) - 4){ + + $dataItem['facetName'] = '['.$k.'%20TO%20'.$facetvalueskeys[$i+1].']'; + $dataItem['facetPrintName'] = '['.$k.'%20TO%20'.$facetvalueskeys[$i+1].']'; + } + else { + //the last group + $dataItem['facetName'] = '['.$k.'%20TO%20'.$facetvalues['end'].']'; + $dataItem['facetPrintName'] = '['.$k.'%20TO%20'.$facetvalues['end'].']'; + } + + $dataItem['facetCount'] = $facetvalues[$k]; + $dataItem['facetSelectCondition'] = $facetRequestEntity->selectedFacetsString . (empty($facetRequestEntity->selectedFacetsString)?'':',') . $data['facetGroupName'] . '::' . $data['facetGroupPrintName'] .':::' . $dataItem['facetName'] . '::' . $dataItem['facetPrintName']; + $newFacetItem = Entity_FacetItem::CreateForInsert($dataItem); + $facetItems[] =$newFacetItem; + } + } + + $data['facetItems'] = $facetItems; + $newFacetGroup = Entity_FacetGroup::CreateForInsert($data); + + $facetGroups[] = $newFacetGroup; + } + } + } + //TODO:convert facet queries + //----- + /******************************************************************/ + //Create a filter string used in the filter of results of a datatable + $filterText = ''; //the list of selected filters used for filtering result, send in ajax + foreach($aSelectedFacetGroups as $selectedFacetGroup) + { + $filterText .= $selectedFacetGroup->selectedFacetGroupName .':'. urlencode($selectedFacetGroup->selectedFacetItemName).','; + } + $filterText = substr_replace($filterText, '', -1); + //$filterText = ($filterText == '')?'':'&filterText='.$filterText; + + /******************************************************************/ + //Create result + $dataFacetResult = array( + 'aFacetGroups' => $facetGroups, + 'aSelectedFacetGroups' => $aSelectedFacetGroups, + 'sFilterText' => $filterText + ); + $facetResult = Entity_FacetResult::CreateForRequest($dataFacetResult); + + return $facetResult; + } + + function getNumberDocuments($workspace){ + require_once ('class.solr.php'); + //require_once (ROOT_PATH . '/businessLogic/modules/SearchIndexAccess/Solr.php'); + $solr = new BpmnEngine_SearchIndexAccess_Solr($this->solrIsEnabled, $this->solrHost); + + //create list of facets + $numberDocuments = $solr->getNumberDocuments($workspace); + + return $numberDocuments; + } + + function updateIndexDocument($solrUpdateDocumentEntity){ + G::LoadClass('solr'); + + $solr = new BpmnEngine_SearchIndexAccess_Solr($this->solrIsEnabled, $this->solrHost); + + //create list of facets + $solr->updateDocument($solrUpdateDocumentEntity); + } + + function deleteDocumentFromIndex($workspace, $idQuery){ + G::LoadClass('solr'); + + $solr = new BpmnEngine_SearchIndexAccess_Solr($this->solrIsEnabled, $this->solrHost); + + //create list of facets + $solr->deleteDocument($workspace, $idQuery); + } + + function commitIndexChanges($workspace){ + G::LoadClass('solr'); + + $solr = new BpmnEngine_SearchIndexAccess_Solr($this->solrIsEnabled, $this->solrHost); + + //commit + $solr->commitChanges($workspace); + } + + function getDataTablePaginatedList($solrRequestData){ + require_once ('class.solr.php'); + //require_once (ROOT_PATH . '/businessLogic/modules/SearchIndexAccess/Solr.php'); + require_once ('entities/SolrRequestData.php'); + require_once ('entities/SolrQueryResult.php'); + + //print_r($solrRequestData); + //prepare the list of sorted columns + //verify if the data of sorting is available + if(isset($solrRequestData->sortCols[0])){ + for($i=0; $i<$solrRequestData->numSortingCols; $i++){ + //verify if column is sortable + if($solrRequestData->includeCols[$solrRequestData->sortCols[$i]] != '' && $solrRequestData->sortableCols[$i] == "true"){ + //change sorting column index to column names + $solrRequestData->sortCols[$i] = $solrRequestData->includeCols[$solrRequestData->sortCols[$i]]; + //define the direction of the sorting columns + $solrRequestData->sortDir[$i] = $solrRequestData->sortDir[$i]; + } + } + } + //remove placeholder fields + //the placeholder doesn't affect the the solr's response + //$solrRequestData->includeCols = array_diff($solrRequestData->includeCols, array('')); + + //print_r($solrRequestData); + //execute query + $solr = new BpmnEngine_SearchIndexAccess_Solr($this->solrIsEnabled, $this->solrHost); + $solrPaginatedResult = $solr->executeQuery($solrRequestData); + + //get total number of documents in index + $numTotalDocs = $solr->getNumberDocuments($solrRequestData->workspace); + + //create the Datatable response of the query + $numFound = $solrPaginatedResult['response']['numFound']; + + $docs = $solrPaginatedResult['response']['docs']; + //print_r($docs); + //insert list of names in docs result + $data = array( + "sEcho" => '',//must be completed in response + "iTotalRecords" => intval($numTotalDocs), //we must get the total number of documents + "iTotalDisplayRecords" => $numFound, + "aaData" => array() + ); + //copy result document or add placeholders to result + foreach ($docs as $i => $doc) { + $data['aaData'][$i] = array(); + foreach($solrRequestData->includeCols as $columnName){ + if($columnName == ''){ + $data['aaData'][$i][] = ''; //placeholder + }else{ + if(isset($doc[$columnName])){ + $data['aaData'][$i][] = $doc[$columnName]; + }else{ + $data['aaData'][$i][] = ''; + } + } + } + } + + $solrQueryResponse = Entity_SolrQueryResult::CreateForRequest($data); + // + + return $solrQueryResponse; + } + + function getIndexFields($workspace){ + //global $indexFields; + //cache +// if(!empty($indexFields)) +// return $indexFields; + + require_once ('class.solr.php'); + //require_once (ROOT_PATH . '/businessLogic/modules/SearchIndexAccess/Solr.php'); + $solr = new BpmnEngine_SearchIndexAccess_Solr($this->solrIsEnabled, $this->solrHost); + + + //print "SearchIndex!!!!"; + //create list of facets + $solrFieldsData = $solr->getListIndexedStoredFields($workspace); + + //copy list of arrays + $listFields = array(); + foreach($solrFieldsData['fields'] as $key => $fieldData){ + if(array_key_exists('dynamicBase', $fieldData)){ + //remove * + $originalFieldName = substr($key, 0, -strlen($fieldData['dynamicBase'])+1); + //$listFields[strtolower($originalFieldName)] = $key; + //Maintain case sensitive variable names + $listFields[$originalFieldName] = $key; + }else{ + //$listFields[strtolower($key)] = $key; + //Maintain case sensitive variable names + $listFields[$key] = $key; + } + } + + //print_r($listFields); + //$indexFields = $listFields; + + return $listFields; + } + +} \ No newline at end of file diff --git a/workflow/engine/classes/class.solr.php b/workflow/engine/classes/class.solr.php new file mode 100644 index 000000000..4057fbdb0 --- /dev/null +++ b/workflow/engine/classes/class.solr.php @@ -0,0 +1,432 @@ +solrIsEnabled = $solrIsEnabled; + $this->solrHost = $solrHost; + } + + /** + * Verify if the Solr service is available + * @gearman = false + * @rest = false + * @background = false + * + * @return bool + */ + function isEnabled() { + // verify solr server response + + return $this->solrIsEnabled; + } + + /** + * Returns the total number of indexed documents + * @gearman = false + * @rest = false + * @background = false + * + * @param + * workspace: workspace name + * @return total + */ + function getNumberDocuments($workspace) { + if (! $this->solrIsEnabled) + return; + // get configuration information in base to workspace parameter + + // get total number of documents in registry + $solrIntruct = $this->solrHost; + $solrIntruct .= $workspace; + $solrIntruct .= "/select/?q=*:*"; + $solrIntruct .= self::SOLR_VERSION; + $solrIntruct .= "&start=0&rows=0&echoParams=none&wt=json"; + + $handlerTotal = curl_init ( $solrIntruct ); + curl_setopt ( $handlerTotal, CURLOPT_RETURNTRANSFER, true ); + $responseTotal = curl_exec ( $handlerTotal ); + curl_close ( $handlerTotal ); + + // verify the result of solr + $responseSolrTotal = json_decode ( $responseTotal, true ); + if ($responseSolrTotal['responseHeader']['status'] != 0) { + throw new Exception ( "Error returning the total number of documents in Solr." ); + } + $numTotalDocs = $responseSolrTotal ['response'] ['numFound']; + return $numTotalDocs; + } + + /** + * Execute a query in base to Request data + * @gearman = false + * @rest = false + * @background = false + * + * @return solr response + */ + function executeQuery($solrRequestData) { + if (! $this->solrIsEnabled) + return; + $solrIntruct = ''; + // get configuration information in base to workspace parameter + $workspace = $solrRequestData->workspace; + + // format request + $query = empty ( $solrRequestData->searchText ) ? '*:*' : $solrRequestData->searchText; + $query = rawurlencode ( $query ); + $start = '&start=' . $solrRequestData->startAfter; + $rows = '&rows=' . $solrRequestData->pageSize; + $fieldList = ''; + $cols = $solrRequestData->includeCols; + if (! empty ( $cols )) { + $fieldList = "&fl=" . implode ( ",", $cols ); + } + $sort = ''; + if ($solrRequestData->numSortingCols > 0) { + $sort = '&sort='; + for($i = 0; $i < $solrRequestData->numSortingCols; $i ++) { + $sort .= $solrRequestData->sortCols [$i] . "%20" . $solrRequestData->sortDir [$i] . ","; + } + + $sort = substr_replace ( $sort, "", - 1 ); + } + $resultFormat = empty ( $solrRequestData->resultFormat ) ? '' : '&wt=' . $solrRequestData->resultFormat; + $filters = ''; + $aFilters = explode ( ',', $solrRequestData->filterText ); + foreach ( $aFilters as $value ) { + $filters .= '&fq=' . urlencode ( $value ); + } + + $solrIntruct = $this->solrHost; + $solrIntruct .= $workspace; + $solrIntruct .= "/select/?q=$query"; + $solrIntruct .= "&echoParams=none"; + $solrIntruct .= self::SOLR_VERSION; + $solrIntruct .= $start; + $solrIntruct .= $rows; + $solrIntruct .= $fieldList; + $solrIntruct .= $sort; + $solrIntruct .= $filters; + $solrIntruct .= $resultFormat; + + // send query + // search the cases in base to datatable parameters + $handler = curl_init ( $solrIntruct ); + curl_setopt ( $handler, CURLOPT_RETURNTRANSFER, true ); + $response = curl_exec ( $handler ); + curl_close ( $handler ); + + // decode + $responseSolr = json_decode ( $response, true ); + if ($responseSolr['responseHeader']['status'] != 0) { + throw new Exception ( "Error executing query to Solr." ); + } + + return $responseSolr; + } + + /** + * Insert or Update document index + * @gearman = false + * @rest = false + * @background = false + * + * @return solr response + */ + function updateDocument($solrUpdateDocument) { + if (! $this->solrIsEnabled) + return; + $solrIntruct = ''; + // get configuration information in base to workspace parameter + $solrIntruct = $this->solrHost; + $solrIntruct .= $solrUpdateDocument->workspace; + $solrIntruct .= "/update"; + + $handler = curl_init ( $solrIntruct ); + curl_setopt ( $handler, CURLOPT_RETURNTRANSFER, true ); + curl_setopt ( $handler, CURLOPT_HTTPHEADER, array ( + 'Content-type:application/xml' + ) ); // -H + curl_setopt ( $handler, CURLOPT_BINARYTRANSFER, TRUE ); // --data-binary + curl_setopt ( $handler, CURLOPT_POSTFIELDS, $solrUpdateDocument->document ); // data + $response = curl_exec ( $handler ); + + curl_close ( $handler ); + + $swOk = strpos ( $response, '0' ); + if (! $swOk) { + throw new Exception ( "Error updating document in Solr." ); + } + } + + /** + * Commit the changes since the last commit + * @gearman = false + * @rest = false + * @background = false + * + * @return solr response + */ + function commitChanges($workspace) { + if (! $this->solrIsEnabled) + return; + $solrIntruct = ''; + // get configuration information in base to workspace parameter + $solrIntruct = $this->solrHost; + $solrIntruct .= $workspace; + $solrIntruct .= "/update"; + + $handler = curl_init ( $solrIntruct ); + curl_setopt ( $handler, CURLOPT_RETURNTRANSFER, true ); + curl_setopt ( $handler, CURLOPT_HTTPHEADER, array ( + 'Content-type:application/xml' + ) ); // -H + curl_setopt ( $handler, CURLOPT_BINARYTRANSFER, TRUE ); // --data-binary + curl_setopt ( $handler, CURLOPT_POSTFIELDS, "" ); // data + $response = curl_exec ( $handler ); + curl_close ( $handler ); + + $swOk = strpos ( $response, '0' ); + if (! $swOk) { + throw new Exception ( "Error commiting changes in Solr." ); + } + } + + /** + * Commit the changes since the last commit + * @gearman = false + * @rest = false + * @background = false + * + * @return solr response + */ + function rollbackChanges($workspace) { + if (! $this->solrIsEnabled) + return; + + $solrIntruct = ''; + // get configuration information in base to workspace parameter + $solrIntruct = $this->solrHost; + $solrIntruct .= $workspace; + $solrIntruct .= "/update"; + + $handler = curl_init ( $solrIntruct ); + curl_setopt ( $handler, CURLOPT_RETURNTRANSFER, true ); + curl_setopt ( $handler, CURLOPT_HTTPHEADER, array ( + 'Content-type:application/xml' + ) ); // -H + curl_setopt ( $handler, CURLOPT_BINARYTRANSFER, TRUE ); // --data-binary + curl_setopt ( $handler, CURLOPT_POSTFIELDS, "" ); // data + $response = curl_exec ( $handler ); + curl_close ( $handler ); + + $swOk = strpos ( $response, '0' ); + if (! $swOk) { + throw new Exception ( "Error rolling back changes in Solr." ); + } + } + + /** + * Insert or Update document index + * @gearman = false + * @rest = false + * @background = false + * + * @return solr response + */ + function optimizeChanges($workspace) { + if (! $this->solrIsEnabled) + return; + + $solrIntruct = ''; + // get configuration information in base to workspace parameter + $solrIntruct = $this->solrHost; + $solrIntruct .= $workspace; + $solrIntruct .= "/update"; + + $handler = curl_init ( $solrIntruct ); + curl_setopt ( $handler, CURLOPT_RETURNTRANSFER, true ); + curl_setopt ( $handler, CURLOPT_HTTPHEADER, array ( + 'Content-type:application/xml' + ) ); // -H + curl_setopt ( $handler, CURLOPT_BINARYTRANSFER, TRUE ); // --data-binary + curl_setopt ( $handler, CURLOPT_POSTFIELDS, "" ); // data + $response = curl_exec ( $handler ); + curl_close ( $handler ); + + $swOk = strpos ( $response, '0' ); + if (! $swOk) { + throw new Exception ( "Error optimizing changes in Solr." ); + } + } + + function getListIndexedStoredFields($workspace) { + if (! $this->solrIsEnabled) + return; + + $solrIntruct = ''; + // get configuration information in base to workspace parameter + $solrIntruct = $this->solrHost; + $solrIntruct .= $workspace; + $solrIntruct .= "/admin/luke?numTerms=0&wt=json"; + + $handler = curl_init ( $solrIntruct ); + curl_setopt ( $handler, CURLOPT_RETURNTRANSFER, true ); + $response = curl_exec ( $handler ); + curl_close ( $handler ); + // decode + $responseSolr = json_decode ( $response, true ); + if ($responseSolr['responseHeader']['status'] != 0) { + throw new Exception ( "Error getting index fields in Solr." ); + } + return $responseSolr; + } + + /** + * Delete all documents from index + * @gearman = false + * @rest = false + * @background = false + * + * @return solr response + */ + function deleteAllDocuments($workspace) { + if (! $this->solrIsEnabled) + return; + // $registry = Zend_Registry::getInstance(); + + $solrIntruct = ''; + // get configuration information in base to workspace parameter + $solrIntruct = $this->solrHost; + $solrIntruct .= $workspace; + $solrIntruct .= "/update"; + + $handler = curl_init ( $solrIntruct ); + curl_setopt ( $handler, CURLOPT_RETURNTRANSFER, true ); + curl_setopt ( $handler, CURLOPT_HTTPHEADER, array ( + 'Content-type:application/xml' + ) ); // -H + curl_setopt ( $handler, CURLOPT_BINARYTRANSFER, TRUE ); // --data-binary + curl_setopt ( $handler, CURLOPT_POSTFIELDS, "*:*" ); // data + $response = curl_exec ( $handler ); + + curl_close ( $handler ); + + $swOk = strpos ( $response, '0' ); + if (! $swOk) { + throw new Exception ( "Error deleting all documents in Solr." ); + } + } + + /** + * Delete specified documents from index + * @gearman = false + * @rest = false + * @background = false + * + * @return solr response + */ + function deleteDocument($workspace, $idQuery) { + if (! $this->solrIsEnabled) + return; + // $registry = Zend_Registry::getInstance(); + + $solrIntruct = ''; + // get configuration information in base to workspace parameter + $solrIntruct = $this->solrHost; + $solrIntruct .= $workspace; + $solrIntruct .= "/update"; + + $handler = curl_init ( $solrIntruct ); + curl_setopt ( $handler, CURLOPT_RETURNTRANSFER, true ); + curl_setopt ( $handler, CURLOPT_HTTPHEADER, array ( + 'Content-type:application/xml' + ) ); // -H + curl_setopt ( $handler, CURLOPT_BINARYTRANSFER, TRUE ); // --data-binary + curl_setopt ( $handler, CURLOPT_POSTFIELDS, "" . $idQuery . "" ); // data + $response = curl_exec ( $handler ); + + curl_close ( $handler ); + + $swOk = strpos ( $response, '0' ); + if (! $swOk) { + throw new Exception ( "Error deleting document in Solr." ); + } + } + + /** + * Execute a query in base to Request data + * + * @param Entity_FacetRequest $facetRequestEntity + * @return solr response: list of facets array + */ + function getFacetsList($facetRequest) { + if (! $this->solrIsEnabled) + return; + + $solrIntruct = ''; + // get configuration information in base to workspace parameter + $workspace = $facetRequest->workspace; + + // format request + $query = empty ( $facetRequest->searchText ) ? '*:*' : $facetRequest->searchText; + $query = rawurlencode ( $query ); + $start = '&start=0'; + $rows = '&rows=0'; + $facets = '&facet=on&facet.mincount=1&facet.limit=20'; // enable facet and + // only return facets + // with minimun one + // instance + foreach ( $facetRequest->facetFields as $value ) { + $facets .= '&facet.field=' . $value; + } + foreach ( $facetRequest->facetQueries as $value ) { + $facets .= '&facet.query=' . $value; + } + if (! empty ( $facetRequest->facetDates )) { + foreach ( $facetRequest->facetDates as $value ) { + $facets .= '&facet.date=' . $value; + } + $facets .= '&facet.date.start=' . $facetRequest->facetDatesStart; + $facets .= '&facet.date.end=' . $facetRequest->facetDatesEnd; + $facets .= '&facet.date.gap=' . $facetRequest->facetDateGap; + } + $filters = ''; + foreach ( $facetRequest->filters as $value ) { + $filters .= '&fq=' . $value; + } + // echo "
";
+    
+    $resultFormat = '&wt=json';
+    
+    $solrIntruct = $this->solrHost;
+    $solrIntruct .= $workspace;
+    $solrIntruct .= "/select/?q=$query";
+    $solrIntruct .= "&echoParams=none";
+    $solrIntruct .= self::SOLR_VERSION;
+    $solrIntruct .= $start;
+    $solrIntruct .= $rows;
+    $solrIntruct .= $facets;
+    $solrIntruct .= $filters;
+    $solrIntruct .= $resultFormat;
+    
+    // send query
+    // search the cases in base to datatable parameters
+    $handler = curl_init ( $solrIntruct );
+    curl_setopt ( $handler, CURLOPT_RETURNTRANSFER, true );
+    $response = curl_exec ( $handler );
+    curl_close ( $handler );
+    
+    // decode
+    $responseSolr = json_decode ( $response, true );
+    if ($responseSolr['responseHeader']['status'] != 0) {
+      throw new Exception ( "Error getting faceted list from Solr." );
+    }
+    
+    return $responseSolr;
+  }
+}
\ No newline at end of file
diff --git a/workflow/engine/classes/entities/AppSolrQueue.php b/workflow/engine/classes/entities/AppSolrQueue.php
new file mode 100644
index 000000000..089babac9
--- /dev/null
+++ b/workflow/engine/classes/entities/AppSolrQueue.php
@@ -0,0 +1,35 @@
+initializeObject ( $data );
+    
+    $requiredFields = array (
+        "appUid",
+        "appUpdated" 
+    );
+    
+    $obj->validateRequiredFields ( $requiredFields );
+    
+    return $obj;
+  }
+
+}
diff --git a/workflow/engine/classes/entities/Base.php b/workflow/engine/classes/entities/Base.php
new file mode 100644
index 000000000..b1e776d32
--- /dev/null
+++ b/workflow/engine/classes/entities/Base.php
@@ -0,0 +1,135 @@
+ $f ) {
+      if (isset ( $this->temp [$f] )) {
+        $fieldIsEmpty = false;
+        return $this->temp [$f];
+      }
+    }
+    
+    // field empty means the user has not sent a value for this Field, so we are
+    // using the default value
+    if ($fieldIsEmpty) {
+      if ($default !== false) {
+        return $default;
+      }
+    }
+  }
+  
+  protected function validateRequiredFields($requiredFields = array()) {
+    foreach ( $requiredFields as $k => $field ) {
+      if ($this->{$field} === NULL) {
+        throw (new Zend_Exception ( "Field $field is required in " . get_class ( $this ) ));
+        die ();
+      }
+    }
+  }
+  
+  /**
+   *
+   *
+   * Copy the values of the Entity to the array of aliases
+   * The array of aliases must be defined.
+   *
+   * @return Array of alias with the Entity values
+   */
+  public function getAliasDataArray() {
+    $aAlias = array ();
+    // get aliases from class
+    $className = get_class ( $this );
+    if (method_exists ( $className, 'GetAliases' )) {
+      $aliases = $className::GetAliases ();
+      foreach ( $this as $field => $value )
+        if (isset ( $aliases [$field] )) {
+          // echo "Field exists in Aliases: " . $field . "\n";
+          // echo "Alias Name:" . $aliases[$field] . "\n";
+          // echo "Alias value:" . $value . "\n";
+          $aAlias [$aliases [$field]] = $value;
+        }
+    }
+    
+    return $aAlias;
+  }
+  
+  /**
+   *
+   *
+   * Set the data from array of alias to Entity
+   *
+   * @param $aAliasData array
+   *          of data of aliases
+   */
+  public function setAliasDataArray($aAliasData) {
+    // get aliases from class
+    $className = get_class ( $this );
+    if (method_exists ( $className, 'GetAliases' )) {
+      $aliases = $className::GetAliases ();
+      
+      foreach ( $this as $field => $value )
+        if (isset ( $aliases [$field] ))
+          $this->{$field} = $aAliasData [$aliases [$field]];
+    }
+  }
+  
+  /**
+   *
+   *
+   * Initialize object with values from $data.
+   * The values from data use properties or alias array.
+   * 
+   * @param
+   *          $data
+   */
+  protected function initializeObject($data) {
+    // get aliases from class
+    $className = get_class ( $this );
+    $aliases = array ();
+    $swAliases = false;
+    if (method_exists ( $className, 'GetAliases' )) {
+      $aliases = $className::GetAliases ();
+      $swAliases = true;
+    }
+    // use object properties or aliases to initialize
+    foreach ( $this as $field => $value )
+      if (isset ( $data [$field] )) {
+        $this->$field = $data [$field];
+      }
+      elseif ($swAliases && isset ( $aliases [$field] ) && isset ( $data [$aliases [$field]] )) {
+        $this->$field = $data [$aliases [$field]];
+      }
+  }
+  
+  public function serialize() {
+    if (isset ( $this->temp ))
+      unset ( $this->temp );
+    return serialize ( $this );
+  }
+  
+  public function unserialize($str) {
+    $className = get_class ( $this );
+    $data = unserialize ( $str );
+    return new $className ( $data );
+  }
+
+}
\ No newline at end of file
diff --git a/workflow/engine/classes/entities/FacetGroup.php b/workflow/engine/classes/entities/FacetGroup.php
new file mode 100644
index 000000000..1b9b16f3b
--- /dev/null
+++ b/workflow/engine/classes/entities/FacetGroup.php
@@ -0,0 +1,49 @@
+initializeObject ( $data );
+    
+    $requiredFields = array (
+        "facetGroupName",
+        "facetItems" 
+    );
+    
+    $obj->validateRequiredFields ( $requiredFields );
+    
+    return $obj;
+  }
+
+}
\ No newline at end of file
diff --git a/workflow/engine/classes/entities/FacetInterfaceRequest.php b/workflow/engine/classes/entities/FacetInterfaceRequest.php
new file mode 100644
index 000000000..72b9f8a45
--- /dev/null
+++ b/workflow/engine/classes/entities/FacetInterfaceRequest.php
@@ -0,0 +1,36 @@
+initializeObject ( $data );
+    
+    $requiredFields = array (
+        "searchText",
+        "selectedFacetsString" 
+    );
+    
+    $obj->validateRequiredFields ( $requiredFields );
+    
+    return $obj;
+  }
+
+}
diff --git a/workflow/engine/classes/entities/FacetInterfaceResult.php b/workflow/engine/classes/entities/FacetInterfaceResult.php
new file mode 100644
index 000000000..37a12b76a
--- /dev/null
+++ b/workflow/engine/classes/entities/FacetInterfaceResult.php
@@ -0,0 +1,35 @@
+initializeObject ( $data );
+    
+    $requiredFields = array (
+        "aFacetGroup",
+        "aSelectedFacetGroupItem",
+        "sFilterText" 
+    );
+    
+    $obj->validateRequiredFields ( $requiredFields );
+    
+    return $obj;
+  }
+
+}
\ No newline at end of file
diff --git a/workflow/engine/classes/entities/FacetItem.php b/workflow/engine/classes/entities/FacetItem.php
new file mode 100644
index 000000000..ae07719af
--- /dev/null
+++ b/workflow/engine/classes/entities/FacetItem.php
@@ -0,0 +1,42 @@
+initializeObject ( $data );
+    
+    $requiredFields = array (
+        "facetName",
+        "facetCount" 
+    );
+    
+    $obj->validateRequiredFields ( $requiredFields );
+    
+    return $obj;
+  }
+
+}
\ No newline at end of file
diff --git a/workflow/engine/classes/entities/FacetRequest.php b/workflow/engine/classes/entities/FacetRequest.php
new file mode 100644
index 000000000..6c5d5b067
--- /dev/null
+++ b/workflow/engine/classes/entities/FacetRequest.php
@@ -0,0 +1,39 @@
+initializeObject ( $data );
+    
+    $requiredFields = array (
+        "workspace" 
+    );
+    
+    $obj->validateRequiredFields ( $requiredFields );
+    
+    return $obj;
+  }
+
+}
\ No newline at end of file
diff --git a/workflow/engine/classes/entities/FacetResult.php b/workflow/engine/classes/entities/FacetResult.php
new file mode 100644
index 000000000..e50a0d66f
--- /dev/null
+++ b/workflow/engine/classes/entities/FacetResult.php
@@ -0,0 +1,33 @@
+initializeObject ( $data );
+    
+    $requiredFields = array (
+        "aFacetGroups",
+        "aSelectedFacetGroups",
+        "sFilterText" 
+    );
+    
+    $obj->validateRequiredFields ( $requiredFields );
+    
+    return $obj;
+  }
+
+}
\ No newline at end of file
diff --git a/workflow/engine/classes/entities/SelectedFacetGroupItem.php b/workflow/engine/classes/entities/SelectedFacetGroupItem.php
new file mode 100644
index 000000000..f90cea42b
--- /dev/null
+++ b/workflow/engine/classes/entities/SelectedFacetGroupItem.php
@@ -0,0 +1,36 @@
+initializeObject ( $data );
+    
+    $requiredFields = array (
+        "selectedFacetGroupName",
+        "selectedFacetItemName" 
+    );
+    
+    $obj->validateRequiredFields ( $requiredFields );
+    
+    return $obj;
+  }
+
+}
\ No newline at end of file
diff --git a/workflow/engine/classes/entities/SolrQueryResult.php b/workflow/engine/classes/entities/SolrQueryResult.php
new file mode 100644
index 000000000..1ce33edb8
--- /dev/null
+++ b/workflow/engine/classes/entities/SolrQueryResult.php
@@ -0,0 +1,36 @@
+initializeObject ( $data );
+    
+    $requiredFields = array (
+        'sEcho',
+        'iTotalRecords',
+        'iTotalDisplayRecords',
+        'aaData' 
+    );
+    
+    $obj->validateRequiredFields ( $requiredFields );
+    
+    return $obj;
+  }
+
+}
\ No newline at end of file
diff --git a/workflow/engine/classes/entities/SolrRequestData.php b/workflow/engine/classes/entities/SolrRequestData.php
new file mode 100644
index 000000000..84e66c0cc
--- /dev/null
+++ b/workflow/engine/classes/entities/SolrRequestData.php
@@ -0,0 +1,42 @@
+initializeObject ( $data );
+    
+    $requiredFields = array (
+        'workspace' 
+    );
+    
+    $obj->validateRequiredFields ( $requiredFields );
+    
+    return $obj;
+  }
+
+}
\ No newline at end of file
diff --git a/workflow/engine/classes/entities/SolrUpdateDocument.php b/workflow/engine/classes/entities/SolrUpdateDocument.php
new file mode 100644
index 000000000..6c32c5c38
--- /dev/null
+++ b/workflow/engine/classes/entities/SolrUpdateDocument.php
@@ -0,0 +1,31 @@
+initializeObject ( $data );
+    
+    $requiredFields = array (
+        "workspace",
+        "document" 
+    );
+    
+    $obj->validateRequiredFields ( $requiredFields );
+    
+    return $obj;
+  }
+
+}
\ No newline at end of file
diff --git a/workflow/engine/classes/model/AppSolrQueue.php b/workflow/engine/classes/model/AppSolrQueue.php
new file mode 100644
index 000000000..8d045c279
--- /dev/null
+++ b/workflow/engine/classes/model/AppSolrQueue.php
@@ -0,0 +1,126 @@
+exists($sAppUid)){
+                $con->begin();
+                //update record
+                //$oRow = AppSolrQueuePeer::retrieveByPK( $sAppUid );
+                //$aFields = $oRow->toArray(BasePeer::TYPE_FIELDNAME);
+                //$this->fromArray($aFields,BasePeer::TYPE_FIELDNAME);
+                $this->setNew(false);
+                //set field
+                $this->setAppUid($sAppUid);
+                $this->setAppUpdated($iUpdated);
+                if($this->validate())
+                {
+                    $result=$this->save();
+                }
+                else
+                {
+                    $con->rollback();
+                    throw(new Exception("Failed Validation in class ".get_class($this)."."));
+                }
+                $con->commit();
+                return $result;                
+            }else{
+                //create record
+                //set values
+                $this->setAppUid($sAppUid);
+                $this->setAppUpdated($iUpdated);
+                if($this->validate())
+                {
+                    $result=$this->save();
+                }
+                else
+                {
+                    $e=new Exception("Failed Validation in class ".get_class($this).".");
+                    //$e->aValidationFailures=$this->getValidationFailures();
+                    throw($e);
+                }
+                $con->commit();
+                return $result;                
+            }
+        }
+        catch(Exception $e)
+        {
+            $con->rollback();
+            throw($e);
+        }
+    }
+    
+    /**
+     * Returns the list of updated applications
+     * array of Entity_AppSolrQueue
+     */
+    public function getListUpdatedApplications(){
+        $updatedApplications = array();
+        try
+        {
+            $c = new Criteria();
+            
+            $c->addSelectColumn(AppSolrQueuePeer::APP_UID);
+            $c->addSelectColumn(AppSolrQueuePeer::APP_UPDATED);
+            
+            //"WHERE 
+            $c->add(AppSolrQueuePeer::APP_UPDATED, 0, Criteria::NOT_EQUAL);
+            
+            $rs = AppSolrQueuePeer::doSelectRS($c);
+            $rs->setFetchmode(ResultSet::FETCHMODE_ASSOC);
+            //echo $c->toString();
+            $rs->next();
+            $row = $rs->getRow();
+            
+            while (is_array($row)) {
+                $appSolrQueue = Entity_AppSolrQueue::CreateEmpty();
+                $appSolrQueue->appUid = $row['APP_UID'];
+                $appSolrQueue->appUpdated = $row['APP_UPDATED'];
+                $updatedApplications[] = $appSolrQueue;
+                $rs->next();
+                $row = $rs->getRow();
+            }
+            
+            return $updatedApplications;
+        }catch(Exception $e){
+            $con->rollback();
+            throw($e);
+        }
+    }
+} // AppSolrQueue
diff --git a/workflow/engine/classes/model/AppSolrQueuePeer.php b/workflow/engine/classes/model/AppSolrQueuePeer.php
new file mode 100644
index 000000000..cf47a3f95
--- /dev/null
+++ b/workflow/engine/classes/model/AppSolrQueuePeer.php
@@ -0,0 +1,23 @@
+dbMap !== null);
+	}
+
+	/**
+	 * Gets the databasemap this map builder built.
+	 *
+	 * @return     the databasemap
+	 */
+	public function getDatabaseMap()
+	{
+		return $this->dbMap;
+	}
+
+	/**
+	 * The doBuild() method builds the DatabaseMap
+	 *
+	 * @return     void
+	 * @throws     PropelException
+	 */
+	public function doBuild()
+	{
+		$this->dbMap = Propel::getDatabaseMap('workflow');
+
+		$tMap = $this->dbMap->addTable('APP_SOLR_QUEUE');
+		$tMap->setPhpName('AppSolrQueue');
+
+		$tMap->setUseIdGenerator(false);
+
+		$tMap->addPrimaryKey('APP_UID', 'AppUid', 'string', CreoleTypes::VARCHAR, true, 32);
+
+		$tMap->addColumn('APP_UPDATED', 'AppUpdated', 'int', CreoleTypes::TINYINT, true, null);
+
+	} // doBuild()
+
+} // AppSolrQueueMapBuilder
diff --git a/workflow/engine/classes/model/om/BaseAppSolrQueue.php b/workflow/engine/classes/model/om/BaseAppSolrQueue.php
new file mode 100644
index 000000000..e025cc0d8
--- /dev/null
+++ b/workflow/engine/classes/model/om/BaseAppSolrQueue.php
@@ -0,0 +1,557 @@
+app_uid;
+	}
+
+	/**
+	 * Get the [app_updated] column value.
+	 * 
+	 * @return     int
+	 */
+	public function getAppUpdated()
+	{
+
+		return $this->app_updated;
+	}
+
+	/**
+	 * Set the value of [app_uid] column.
+	 * 
+	 * @param      string $v new value
+	 * @return     void
+	 */
+	public function setAppUid($v)
+	{
+
+		// Since the native PHP type for this column is string,
+		// we will cast the input to a string (if it is not).
+		if ($v !== null && !is_string($v)) {
+			$v = (string) $v; 
+		}
+
+		if ($this->app_uid !== $v || $v === '') {
+			$this->app_uid = $v;
+			$this->modifiedColumns[] = AppSolrQueuePeer::APP_UID;
+		}
+
+	} // setAppUid()
+
+	/**
+	 * Set the value of [app_updated] column.
+	 * 
+	 * @param      int $v new value
+	 * @return     void
+	 */
+	public function setAppUpdated($v)
+	{
+
+		// Since the native PHP type for this column is integer,
+		// we will cast the input value to an int (if it is not).
+		if ($v !== null && !is_int($v) && is_numeric($v)) {
+			$v = (int) $v;
+		}
+
+		if ($this->app_updated !== $v || $v === 1) {
+			$this->app_updated = $v;
+			$this->modifiedColumns[] = AppSolrQueuePeer::APP_UPDATED;
+		}
+
+	} // setAppUpdated()
+
+	/**
+	 * Hydrates (populates) the object variables with values from the database resultset.
+	 *
+	 * An offset (1-based "start column") is specified so that objects can be hydrated
+	 * with a subset of the columns in the resultset rows.  This is needed, for example,
+	 * for results of JOIN queries where the resultset row includes columns from two or
+	 * more tables.
+	 *
+	 * @param      ResultSet $rs The ResultSet class with cursor advanced to desired record pos.
+	 * @param      int $startcol 1-based offset column which indicates which restultset column to start with.
+	 * @return     int next starting column
+	 * @throws     PropelException  - Any caught Exception will be rewrapped as a PropelException.
+	 */
+	public function hydrate(ResultSet $rs, $startcol = 1)
+	{
+		try {
+
+			$this->app_uid = $rs->getString($startcol + 0);
+
+			$this->app_updated = $rs->getInt($startcol + 1);
+
+			$this->resetModified();
+
+			$this->setNew(false);
+
+			// FIXME - using NUM_COLUMNS may be clearer.
+			return $startcol + 2; // 2 = AppSolrQueuePeer::NUM_COLUMNS - AppSolrQueuePeer::NUM_LAZY_LOAD_COLUMNS).
+
+		} catch (Exception $e) {
+			throw new PropelException("Error populating AppSolrQueue object", $e);
+		}
+	}
+
+	/**
+	 * Removes this object from datastore and sets delete attribute.
+	 *
+	 * @param      Connection $con
+	 * @return     void
+	 * @throws     PropelException
+	 * @see        BaseObject::setDeleted()
+	 * @see        BaseObject::isDeleted()
+	 */
+	public function delete($con = null)
+	{
+		if ($this->isDeleted()) {
+			throw new PropelException("This object has already been deleted.");
+		}
+
+		if ($con === null) {
+			$con = Propel::getConnection(AppSolrQueuePeer::DATABASE_NAME);
+		}
+
+		try {
+			$con->begin();
+			AppSolrQueuePeer::doDelete($this, $con);
+			$this->setDeleted(true);
+			$con->commit();
+		} catch (PropelException $e) {
+			$con->rollback();
+			throw $e;
+		}
+	}
+
+	/**
+	 * Stores the object in the database.  If the object is new,
+	 * it inserts it; otherwise an update is performed.  This method
+	 * wraps the doSave() worker method in a transaction.
+	 *
+	 * @param      Connection $con
+	 * @return     int The number of rows affected by this insert/update and any referring fk objects' save() operations.
+	 * @throws     PropelException
+	 * @see        doSave()
+	 */
+	public function save($con = null)
+	{
+		if ($this->isDeleted()) {
+			throw new PropelException("You cannot save an object that has been deleted.");
+		}
+
+		if ($con === null) {
+			$con = Propel::getConnection(AppSolrQueuePeer::DATABASE_NAME);
+		}
+
+		try {
+			$con->begin();
+			$affectedRows = $this->doSave($con);
+			$con->commit();
+			return $affectedRows;
+		} catch (PropelException $e) {
+			$con->rollback();
+			throw $e;
+		}
+	}
+
+	/**
+	 * Stores the object in the database.
+	 *
+	 * If the object is new, it inserts it; otherwise an update is performed.
+	 * All related objects are also updated in this method.
+	 *
+	 * @param      Connection $con
+	 * @return     int The number of rows affected by this insert/update and any referring fk objects' save() operations.
+	 * @throws     PropelException
+	 * @see        save()
+	 */
+	protected function doSave($con)
+	{
+		$affectedRows = 0; // initialize var to track total num of affected rows
+		if (!$this->alreadyInSave) {
+			$this->alreadyInSave = true;
+
+
+			// If this object has been modified, then save it to the database.
+			if ($this->isModified()) {
+				if ($this->isNew()) {
+					$pk = AppSolrQueuePeer::doInsert($this, $con);
+					$affectedRows += 1; // we are assuming that there is only 1 row per doInsert() which
+										 // should always be true here (even though technically
+										 // BasePeer::doInsert() can insert multiple rows).
+
+					$this->setNew(false);
+				} else {
+					$affectedRows += AppSolrQueuePeer::doUpdate($this, $con);
+				}
+				$this->resetModified(); // [HL] After being saved an object is no longer 'modified'
+			}
+
+			$this->alreadyInSave = false;
+		}
+		return $affectedRows;
+	} // doSave()
+
+	/**
+	 * Array of ValidationFailed objects.
+	 * @var        array ValidationFailed[]
+	 */
+	protected $validationFailures = array();
+
+	/**
+	 * Gets any ValidationFailed objects that resulted from last call to validate().
+	 *
+	 *
+	 * @return     array ValidationFailed[]
+	 * @see        validate()
+	 */
+	public function getValidationFailures()
+	{
+		return $this->validationFailures;
+	}
+
+	/**
+	 * Validates the objects modified field values and all objects related to this table.
+	 *
+	 * If $columns is either a column name or an array of column names
+	 * only those columns are validated.
+	 *
+	 * @param      mixed $columns Column name or an array of column names.
+	 * @return     boolean Whether all columns pass validation.
+	 * @see        doValidate()
+	 * @see        getValidationFailures()
+	 */
+	public function validate($columns = null)
+	{
+		$res = $this->doValidate($columns);
+		if ($res === true) {
+			$this->validationFailures = array();
+			return true;
+		} else {
+			$this->validationFailures = $res;
+			return false;
+		}
+	}
+
+	/**
+	 * This function performs the validation work for complex object models.
+	 *
+	 * In addition to checking the current object, all related objects will
+	 * also be validated.  If all pass then true is returned; otherwise
+	 * an aggreagated array of ValidationFailed objects will be returned.
+	 *
+	 * @param      array $columns Array of column names to validate.
+	 * @return     mixed true if all validations pass; array of ValidationFailed objets otherwise.
+	 */
+	protected function doValidate($columns = null)
+	{
+		if (!$this->alreadyInValidation) {
+			$this->alreadyInValidation = true;
+			$retval = null;
+
+			$failureMap = array();
+
+
+			if (($retval = AppSolrQueuePeer::doValidate($this, $columns)) !== true) {
+				$failureMap = array_merge($failureMap, $retval);
+			}
+
+
+
+			$this->alreadyInValidation = false;
+		}
+
+		return (!empty($failureMap) ? $failureMap : true);
+	}
+
+	/**
+	 * Retrieves a field from the object by name passed in as a string.
+	 *
+	 * @param      string $name name
+	 * @param      string $type The type of fieldname the $name is of:
+	 *                     one of the class type constants TYPE_PHPNAME,
+	 *                     TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM
+	 * @return     mixed Value of field.
+	 */
+	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
+	{
+		$pos = AppSolrQueuePeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
+		return $this->getByPosition($pos);
+	}
+
+	/**
+	 * Retrieves a field from the object by Position as specified in the xml schema.
+	 * Zero-based.
+	 *
+	 * @param      int $pos position in xml schema
+	 * @return     mixed Value of field at $pos
+	 */
+	public function getByPosition($pos)
+	{
+		switch($pos) {
+			case 0:
+				return $this->getAppUid();
+				break;
+			case 1:
+				return $this->getAppUpdated();
+				break;
+			default:
+				return null;
+				break;
+		} // switch()
+	}
+
+	/**
+	 * Exports the object as an array.
+	 *
+	 * You can specify the key type of the array by passing one of the class
+	 * type constants.
+	 *
+	 * @param      string $keyType One of the class type constants TYPE_PHPNAME,
+	 *                        TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM
+	 * @return     an associative array containing the field names (as keys) and field values
+	 */
+	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
+	{
+		$keys = AppSolrQueuePeer::getFieldNames($keyType);
+		$result = array(
+			$keys[0] => $this->getAppUid(),
+			$keys[1] => $this->getAppUpdated(),
+		);
+		return $result;
+	}
+
+	/**
+	 * Sets a field from the object by name passed in as a string.
+	 *
+	 * @param      string $name peer name
+	 * @param      mixed $value field value
+	 * @param      string $type The type of fieldname the $name is of:
+	 *                     one of the class type constants TYPE_PHPNAME,
+	 *                     TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM
+	 * @return     void
+	 */
+	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
+	{
+		$pos = AppSolrQueuePeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
+		return $this->setByPosition($pos, $value);
+	}
+
+	/**
+	 * Sets a field from the object by Position as specified in the xml schema.
+	 * Zero-based.
+	 *
+	 * @param      int $pos position in xml schema
+	 * @param      mixed $value field value
+	 * @return     void
+	 */
+	public function setByPosition($pos, $value)
+	{
+		switch($pos) {
+			case 0:
+				$this->setAppUid($value);
+				break;
+			case 1:
+				$this->setAppUpdated($value);
+				break;
+		} // switch()
+	}
+
+	/**
+	 * Populates the object using an array.
+	 *
+	 * This is particularly useful when populating an object from one of the
+	 * request arrays (e.g. $_POST).  This method goes through the column
+	 * names, checking to see whether a matching key exists in populated
+	 * array. If so the setByName() method is called for that column.
+	 *
+	 * You can specify the key type of the array by additionally passing one
+	 * of the class type constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME,
+	 * TYPE_NUM. The default key type is the column's phpname (e.g. 'authorId')
+	 *
+	 * @param      array  $arr     An array to populate the object from.
+	 * @param      string $keyType The type of keys the array uses.
+	 * @return     void
+	 */
+	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
+	{
+		$keys = AppSolrQueuePeer::getFieldNames($keyType);
+
+		if (array_key_exists($keys[0], $arr)) $this->setAppUid($arr[$keys[0]]);
+		if (array_key_exists($keys[1], $arr)) $this->setAppUpdated($arr[$keys[1]]);
+	}
+
+	/**
+	 * Build a Criteria object containing the values of all modified columns in this object.
+	 *
+	 * @return     Criteria The Criteria object containing all modified values.
+	 */
+	public function buildCriteria()
+	{
+		$criteria = new Criteria(AppSolrQueuePeer::DATABASE_NAME);
+
+		if ($this->isColumnModified(AppSolrQueuePeer::APP_UID)) $criteria->add(AppSolrQueuePeer::APP_UID, $this->app_uid);
+		if ($this->isColumnModified(AppSolrQueuePeer::APP_UPDATED)) $criteria->add(AppSolrQueuePeer::APP_UPDATED, $this->app_updated);
+
+		return $criteria;
+	}
+
+	/**
+	 * Builds a Criteria object containing the primary key for this object.
+	 *
+	 * Unlike buildCriteria() this method includes the primary key values regardless
+	 * of whether or not they have been modified.
+	 *
+	 * @return     Criteria The Criteria object containing value(s) for primary key(s).
+	 */
+	public function buildPkeyCriteria()
+	{
+		$criteria = new Criteria(AppSolrQueuePeer::DATABASE_NAME);
+
+		$criteria->add(AppSolrQueuePeer::APP_UID, $this->app_uid);
+
+		return $criteria;
+	}
+
+	/**
+	 * Returns the primary key for this object (row).
+	 * @return     string
+	 */
+	public function getPrimaryKey()
+	{
+		return $this->getAppUid();
+	}
+
+	/**
+	 * Generic method to set the primary key (app_uid column).
+	 *
+	 * @param      string $key Primary key.
+	 * @return     void
+	 */
+	public function setPrimaryKey($key)
+	{
+		$this->setAppUid($key);
+	}
+
+	/**
+	 * Sets contents of passed object to values from current object.
+	 *
+	 * If desired, this method can also make copies of all associated (fkey referrers)
+	 * objects.
+	 *
+	 * @param      object $copyObj An object of AppSolrQueue (or compatible) type.
+	 * @param      boolean $deepCopy Whether to also copy all rows that refer (by fkey) to the current row.
+	 * @throws     PropelException
+	 */
+	public function copyInto($copyObj, $deepCopy = false)
+	{
+
+		$copyObj->setAppUpdated($this->app_updated);
+
+
+		$copyObj->setNew(true);
+
+		$copyObj->setAppUid(''); // this is a pkey column, so set to default value
+
+	}
+
+	/**
+	 * Makes a copy of this object that will be inserted as a new row in table when saved.
+	 * It creates a new object filling in the simple attributes, but skipping any primary
+	 * keys that are defined for the table.
+	 *
+	 * If desired, this method can also make copies of all associated (fkey referrers)
+	 * objects.
+	 *
+	 * @param      boolean $deepCopy Whether to also copy all rows that refer (by fkey) to the current row.
+	 * @return     AppSolrQueue Clone of current object.
+	 * @throws     PropelException
+	 */
+	public function copy($deepCopy = false)
+	{
+		// we use get_class(), because this might be a subclass
+		$clazz = get_class($this);
+		$copyObj = new $clazz();
+		$this->copyInto($copyObj, $deepCopy);
+		return $copyObj;
+	}
+
+	/**
+	 * Returns a peer instance associated with this om.
+	 *
+	 * Since Peer classes are not to have any instance attributes, this method returns the
+	 * same instance for all member of this class. The method could therefore
+	 * be static, but this would prevent one from overriding the behavior.
+	 *
+	 * @return     AppSolrQueuePeer
+	 */
+	public function getPeer()
+	{
+		if (self::$peer === null) {
+			self::$peer = new AppSolrQueuePeer();
+		}
+		return self::$peer;
+	}
+
+} // BaseAppSolrQueue
diff --git a/workflow/engine/classes/model/om/BaseAppSolrQueuePeer.php b/workflow/engine/classes/model/om/BaseAppSolrQueuePeer.php
new file mode 100644
index 000000000..55abc052e
--- /dev/null
+++ b/workflow/engine/classes/model/om/BaseAppSolrQueuePeer.php
@@ -0,0 +1,570 @@
+ array ('AppUid', 'AppUpdated', ),
+		BasePeer::TYPE_COLNAME => array (AppSolrQueuePeer::APP_UID, AppSolrQueuePeer::APP_UPDATED, ),
+		BasePeer::TYPE_FIELDNAME => array ('APP_UID', 'APP_UPDATED', ),
+		BasePeer::TYPE_NUM => array (0, 1, )
+	);
+
+	/**
+	 * holds an array of keys for quick access to the fieldnames array
+	 *
+	 * first dimension keys are the type constants
+	 * e.g. self::$fieldNames[BasePeer::TYPE_PHPNAME]['Id'] = 0
+	 */
+	private static $fieldKeys = array (
+		BasePeer::TYPE_PHPNAME => array ('AppUid' => 0, 'AppUpdated' => 1, ),
+		BasePeer::TYPE_COLNAME => array (AppSolrQueuePeer::APP_UID => 0, AppSolrQueuePeer::APP_UPDATED => 1, ),
+		BasePeer::TYPE_FIELDNAME => array ('APP_UID' => 0, 'APP_UPDATED' => 1, ),
+		BasePeer::TYPE_NUM => array (0, 1, )
+	);
+
+	/**
+	 * @return     MapBuilder the map builder for this peer
+	 * @throws     PropelException Any exceptions caught during processing will be
+	 *		 rethrown wrapped into a PropelException.
+	 */
+	public static function getMapBuilder()
+	{
+		include_once 'classes/model/map/AppSolrQueueMapBuilder.php';
+		return BasePeer::getMapBuilder('classes.model.map.AppSolrQueueMapBuilder');
+	}
+	/**
+	 * Gets a map (hash) of PHP names to DB column names.
+	 *
+	 * @return     array The PHP to DB name map for this peer
+	 * @throws     PropelException Any exceptions caught during processing will be
+	 *		 rethrown wrapped into a PropelException.
+	 * @deprecated Use the getFieldNames() and translateFieldName() methods instead of this.
+	 */
+	public static function getPhpNameMap()
+	{
+		if (self::$phpNameMap === null) {
+			$map = AppSolrQueuePeer::getTableMap();
+			$columns = $map->getColumns();
+			$nameMap = array();
+			foreach ($columns as $column) {
+				$nameMap[$column->getPhpName()] = $column->getColumnName();
+			}
+			self::$phpNameMap = $nameMap;
+		}
+		return self::$phpNameMap;
+	}
+	/**
+	 * Translates a fieldname to another type
+	 *
+	 * @param      string $name field name
+	 * @param      string $fromType One of the class type constants TYPE_PHPNAME,
+	 *                         TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM
+	 * @param      string $toType   One of the class type constants
+	 * @return     string translated name of the field.
+	 */
+	static public function translateFieldName($name, $fromType, $toType)
+	{
+		$toNames = self::getFieldNames($toType);
+		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
+		if ($key === null) {
+			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
+		}
+		return $toNames[$key];
+	}
+
+	/**
+	 * Returns an array of of field names.
+	 *
+	 * @param      string $type The type of fieldnames to return:
+	 *                      One of the class type constants TYPE_PHPNAME,
+	 *                      TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM
+	 * @return     array A list of field names
+	 */
+
+	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
+	{
+		if (!array_key_exists($type, self::$fieldNames)) {
+			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
+		}
+		return self::$fieldNames[$type];
+	}
+
+	/**
+	 * Convenience method which changes table.column to alias.column.
+	 *
+	 * Using this method you can maintain SQL abstraction while using column aliases.
+	 * 
+	 *		$c->addAlias("alias1", TablePeer::TABLE_NAME);
+	 *		$c->addJoin(TablePeer::alias("alias1", TablePeer::PRIMARY_KEY_COLUMN), TablePeer::PRIMARY_KEY_COLUMN);
+	 * 
+	 * @param      string $alias The alias for the current table.
+	 * @param      string $column The column name for current table. (i.e. AppSolrQueuePeer::COLUMN_NAME).
+	 * @return     string
+	 */
+	public static function alias($alias, $column)
+	{
+		return str_replace(AppSolrQueuePeer::TABLE_NAME.'.', $alias.'.', $column);
+	}
+
+	/**
+	 * Add all the columns needed to create a new object.
+	 *
+	 * Note: any columns that were marked with lazyLoad="true" in the
+	 * XML schema will not be added to the select list and only loaded
+	 * on demand.
+	 *
+	 * @param      criteria object containing the columns to add.
+	 * @throws     PropelException Any exceptions caught during processing will be
+	 *		 rethrown wrapped into a PropelException.
+	 */
+	public static function addSelectColumns(Criteria $criteria)
+	{
+
+		$criteria->addSelectColumn(AppSolrQueuePeer::APP_UID);
+
+		$criteria->addSelectColumn(AppSolrQueuePeer::APP_UPDATED);
+
+	}
+
+	const COUNT = 'COUNT(APP_SOLR_QUEUE.APP_UID)';
+	const COUNT_DISTINCT = 'COUNT(DISTINCT APP_SOLR_QUEUE.APP_UID)';
+
+	/**
+	 * Returns the number of rows matching criteria.
+	 *
+	 * @param      Criteria $criteria
+	 * @param      boolean $distinct Whether to select only distinct columns (You can also set DISTINCT modifier in Criteria).
+	 * @param      Connection $con
+	 * @return     int Number of matching rows.
+	 */
+	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
+	{
+		// we're going to modify criteria, so copy it first
+		$criteria = clone $criteria;
+
+		// clear out anything that might confuse the ORDER BY clause
+		$criteria->clearSelectColumns()->clearOrderByColumns();
+		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
+			$criteria->addSelectColumn(AppSolrQueuePeer::COUNT_DISTINCT);
+		} else {
+			$criteria->addSelectColumn(AppSolrQueuePeer::COUNT);
+		}
+
+		// just in case we're grouping: add those columns to the select statement
+		foreach($criteria->getGroupByColumns() as $column)
+		{
+			$criteria->addSelectColumn($column);
+		}
+
+		$rs = AppSolrQueuePeer::doSelectRS($criteria, $con);
+		if ($rs->next()) {
+			return $rs->getInt(1);
+		} else {
+			// no rows returned; we infer that means 0 matches.
+			return 0;
+		}
+	}
+	/**
+	 * Method to select one object from the DB.
+	 *
+	 * @param      Criteria $criteria object used to create the SELECT statement.
+	 * @param      Connection $con
+	 * @return     AppSolrQueue
+	 * @throws     PropelException Any exceptions caught during processing will be
+	 *		 rethrown wrapped into a PropelException.
+	 */
+	public static function doSelectOne(Criteria $criteria, $con = null)
+	{
+		$critcopy = clone $criteria;
+		$critcopy->setLimit(1);
+		$objects = AppSolrQueuePeer::doSelect($critcopy, $con);
+		if ($objects) {
+			return $objects[0];
+		}
+		return null;
+	}
+	/**
+	 * Method to do selects.
+	 *
+	 * @param      Criteria $criteria The Criteria object used to build the SELECT statement.
+	 * @param      Connection $con
+	 * @return     array Array of selected Objects
+	 * @throws     PropelException Any exceptions caught during processing will be
+	 *		 rethrown wrapped into a PropelException.
+	 */
+	public static function doSelect(Criteria $criteria, $con = null)
+	{
+		return AppSolrQueuePeer::populateObjects(AppSolrQueuePeer::doSelectRS($criteria, $con));
+	}
+	/**
+	 * Prepares the Criteria object and uses the parent doSelect()
+	 * method to get a ResultSet.
+	 *
+	 * Use this method directly if you want to just get the resultset
+	 * (instead of an array of objects).
+	 *
+	 * @param      Criteria $criteria The Criteria object used to build the SELECT statement.
+	 * @param      Connection $con the connection to use
+	 * @throws     PropelException Any exceptions caught during processing will be
+	 *		 rethrown wrapped into a PropelException.
+	 * @return     ResultSet The resultset object with numerically-indexed fields.
+	 * @see        BasePeer::doSelect()
+	 */
+	public static function doSelectRS(Criteria $criteria, $con = null)
+	{
+		if ($con === null) {
+			$con = Propel::getConnection(self::DATABASE_NAME);
+		}
+
+		if (!$criteria->getSelectColumns()) {
+			$criteria = clone $criteria;
+			AppSolrQueuePeer::addSelectColumns($criteria);
+		}
+
+		// Set the correct dbName
+		$criteria->setDbName(self::DATABASE_NAME);
+
+		// BasePeer returns a Creole ResultSet, set to return
+		// rows indexed numerically.
+		return BasePeer::doSelect($criteria, $con);
+	}
+	/**
+	 * The returned array will contain objects of the default type or
+	 * objects that inherit from the default.
+	 *
+	 * @throws     PropelException Any exceptions caught during processing will be
+	 *		 rethrown wrapped into a PropelException.
+	 */
+	public static function populateObjects(ResultSet $rs)
+	{
+		$results = array();
+	
+		// set the class once to avoid overhead in the loop
+		$cls = AppSolrQueuePeer::getOMClass();
+		$cls = Propel::import($cls);
+		// populate the object(s)
+		while($rs->next()) {
+		
+			$obj = new $cls();
+			$obj->hydrate($rs);
+			$results[] = $obj;
+			
+		}
+		return $results;
+	}
+	/**
+	 * Returns the TableMap related to this peer.
+	 * This method is not needed for general use but a specific application could have a need.
+	 * @return     TableMap
+	 * @throws     PropelException Any exceptions caught during processing will be
+	 *		 rethrown wrapped into a PropelException.
+	 */
+	public static function getTableMap()
+	{
+		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
+	}
+
+	/**
+	 * The class that the Peer will make instances of.
+	 *
+	 * This uses a dot-path notation which is tranalted into a path
+	 * relative to a location on the PHP include_path.
+	 * (e.g. path.to.MyClass -> 'path/to/MyClass.php')
+	 *
+	 * @return     string path.to.ClassName
+	 */
+	public static function getOMClass()
+	{
+		return AppSolrQueuePeer::CLASS_DEFAULT;
+	}
+
+	/**
+	 * Method perform an INSERT on the database, given a AppSolrQueue or Criteria object.
+	 *
+	 * @param      mixed $values Criteria or AppSolrQueue object containing data that is used to create the INSERT statement.
+	 * @param      Connection $con the connection to use
+	 * @return     mixed The new primary key.
+	 * @throws     PropelException Any exceptions caught during processing will be
+	 *		 rethrown wrapped into a PropelException.
+	 */
+	public static function doInsert($values, $con = null)
+	{
+		if ($con === null) {
+			$con = Propel::getConnection(self::DATABASE_NAME);
+		}
+
+		if ($values instanceof Criteria) {
+			$criteria = clone $values; // rename for clarity
+		} else {
+			$criteria = $values->buildCriteria(); // build Criteria from AppSolrQueue object
+		}
+
+
+		// Set the correct dbName
+		$criteria->setDbName(self::DATABASE_NAME);
+
+		try {
+			// use transaction because $criteria could contain info
+			// for more than one table (I guess, conceivably)
+			$con->begin();
+			$pk = BasePeer::doInsert($criteria, $con);
+			$con->commit();
+		} catch(PropelException $e) {
+			$con->rollback();
+			throw $e;
+		}
+
+		return $pk;
+	}
+
+	/**
+	 * Method perform an UPDATE on the database, given a AppSolrQueue or Criteria object.
+	 *
+	 * @param      mixed $values Criteria or AppSolrQueue object containing data that is used to create the UPDATE statement.
+	 * @param      Connection $con The connection to use (specify Connection object to exert more control over transactions).
+	 * @return     int The number of affected rows (if supported by underlying database driver).
+	 * @throws     PropelException Any exceptions caught during processing will be
+	 *		 rethrown wrapped into a PropelException.
+	 */
+	public static function doUpdate($values, $con = null)
+	{
+		if ($con === null) {
+			$con = Propel::getConnection(self::DATABASE_NAME);
+		}
+
+		$selectCriteria = new Criteria(self::DATABASE_NAME);
+
+		if ($values instanceof Criteria) {
+			$criteria = clone $values; // rename for clarity
+
+			$comparison = $criteria->getComparison(AppSolrQueuePeer::APP_UID);
+			$selectCriteria->add(AppSolrQueuePeer::APP_UID, $criteria->remove(AppSolrQueuePeer::APP_UID), $comparison);
+
+		} else { // $values is AppSolrQueue object
+			$criteria = $values->buildCriteria(); // gets full criteria
+			$selectCriteria = $values->buildPkeyCriteria(); // gets criteria w/ primary key(s)
+		}
+
+		// set the correct dbName
+		$criteria->setDbName(self::DATABASE_NAME);
+
+		return BasePeer::doUpdate($selectCriteria, $criteria, $con);
+	}
+
+	/**
+	 * Method to DELETE all rows from the APP_SOLR_QUEUE table.
+	 *
+	 * @return     int The number of affected rows (if supported by underlying database driver).
+	 */
+	public static function doDeleteAll($con = null)
+	{
+		if ($con === null) {
+			$con = Propel::getConnection(self::DATABASE_NAME);
+		}
+		$affectedRows = 0; // initialize var to track total num of affected rows
+		try {
+			// use transaction because $criteria could contain info
+			// for more than one table or we could emulating ON DELETE CASCADE, etc.
+			$con->begin();
+			$affectedRows += BasePeer::doDeleteAll(AppSolrQueuePeer::TABLE_NAME, $con);
+			$con->commit();
+			return $affectedRows;
+		} catch (PropelException $e) {
+			$con->rollback();
+			throw $e;
+		}
+	}
+
+	/**
+	 * Method perform a DELETE on the database, given a AppSolrQueue or Criteria object OR a primary key value.
+	 *
+	 * @param      mixed $values Criteria or AppSolrQueue object or primary key or array of primary keys
+	 *              which is used to create the DELETE statement
+	 * @param      Connection $con the connection to use
+	 * @return     int 	The number of affected rows (if supported by underlying database driver).  This includes CASCADE-related rows
+	 *				if supported by native driver or if emulated using Propel.
+	 * @throws     PropelException Any exceptions caught during processing will be
+	 *		 rethrown wrapped into a PropelException.
+	 */
+	 public static function doDelete($values, $con = null)
+	 {
+		if ($con === null) {
+			$con = Propel::getConnection(AppSolrQueuePeer::DATABASE_NAME);
+		}
+
+		if ($values instanceof Criteria) {
+			$criteria = clone $values; // rename for clarity
+		} elseif ($values instanceof AppSolrQueue) {
+
+			$criteria = $values->buildPkeyCriteria();
+		} else {
+			// it must be the primary key
+			$criteria = new Criteria(self::DATABASE_NAME);
+			$criteria->add(AppSolrQueuePeer::APP_UID, (array) $values, Criteria::IN);
+		}
+
+		// Set the correct dbName
+		$criteria->setDbName(self::DATABASE_NAME);
+
+		$affectedRows = 0; // initialize var to track total num of affected rows
+
+		try {
+			// use transaction because $criteria could contain info
+			// for more than one table or we could emulating ON DELETE CASCADE, etc.
+			$con->begin();
+			
+			$affectedRows += BasePeer::doDelete($criteria, $con);
+			$con->commit();
+			return $affectedRows;
+		} catch (PropelException $e) {
+			$con->rollback();
+			throw $e;
+		}
+	}
+
+	/**
+	 * Validates all modified columns of given AppSolrQueue object.
+	 * If parameter $columns is either a single column name or an array of column names
+	 * than only those columns are validated.
+	 *
+	 * NOTICE: This does not apply to primary or foreign keys for now.
+	 *
+	 * @param      AppSolrQueue $obj The object to validate.
+	 * @param      mixed $cols Column name or array of column names.
+	 *
+	 * @return     mixed TRUE if all columns are valid or the error message of the first invalid column.
+	 */
+	public static function doValidate(AppSolrQueue $obj, $cols = null)
+	{
+		$columns = array();
+
+		if ($cols) {
+			$dbMap = Propel::getDatabaseMap(AppSolrQueuePeer::DATABASE_NAME);
+			$tableMap = $dbMap->getTable(AppSolrQueuePeer::TABLE_NAME);
+
+			if (! is_array($cols)) {
+				$cols = array($cols);
+			}
+
+			foreach($cols as $colName) {
+				if ($tableMap->containsColumn($colName)) {
+					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
+					$columns[$colName] = $obj->$get();
+				}
+			}
+		} else {
+
+		}
+
+		return BasePeer::doValidate(AppSolrQueuePeer::DATABASE_NAME, AppSolrQueuePeer::TABLE_NAME, $columns);
+	}
+
+	/**
+	 * Retrieve a single object by pkey.
+	 *
+	 * @param      mixed $pk the primary key.
+	 * @param      Connection $con the connection to use
+	 * @return     AppSolrQueue
+	 */
+	public static function retrieveByPK($pk, $con = null)
+	{
+		if ($con === null) {
+			$con = Propel::getConnection(self::DATABASE_NAME);
+		}
+
+		$criteria = new Criteria(AppSolrQueuePeer::DATABASE_NAME);
+
+		$criteria->add(AppSolrQueuePeer::APP_UID, $pk);
+
+
+		$v = AppSolrQueuePeer::doSelect($criteria, $con);
+
+		return !empty($v) > 0 ? $v[0] : null;
+	}
+
+	/**
+	 * Retrieve multiple objects by pkey.
+	 *
+	 * @param      array $pks List of primary keys
+	 * @param      Connection $con the connection to use
+	 * @throws     PropelException Any exceptions caught during processing will be
+	 *		 rethrown wrapped into a PropelException.
+	 */
+	public static function retrieveByPKs($pks, $con = null)
+	{
+		if ($con === null) {
+			$con = Propel::getConnection(self::DATABASE_NAME);
+		}
+
+		$objs = null;
+		if (empty($pks)) {
+			$objs = array();
+		} else {
+			$criteria = new Criteria();
+			$criteria->add(AppSolrQueuePeer::APP_UID, $pks, Criteria::IN);
+			$objs = AppSolrQueuePeer::doSelect($criteria, $con);
+		}
+		return $objs;
+	}
+
+} // BaseAppSolrQueuePeer
+
+// static code to register the map builder for this Peer with the main Propel class
+if (Propel::isInit()) {
+	// the MapBuilder classes register themselves with Propel during initialization
+	// so we need to load them here.
+	try {
+		BaseAppSolrQueuePeer::getMapBuilder();
+	} catch (Exception $e) {
+		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
+	}
+} else {
+	// even if Propel is not yet initialized, the map builder class can be registered
+	// now and then it will be loaded when Propel initializes.
+	require_once 'classes/model/map/AppSolrQueueMapBuilder.php';
+	Propel::registerMapBuilder('classes.model.map.AppSolrQueueMapBuilder');
+}
diff --git a/workflow/engine/config/schema.xml b/workflow/engine/config/schema.xml
index 765da4493..c67ca5979 100755
--- a/workflow/engine/config/schema.xml
+++ b/workflow/engine/config/schema.xml
@@ -2840,4 +2840,28 @@
     
     
   
+  
+    
+      
+      
+      
+      
+      
+      
+      
+      
+      
+      
+      
+      
+      
+      
+      
+      
+      
+      
+    
+    
+    
+  
diff --git a/workflow/engine/data/mssql/schema.sql b/workflow/engine/data/mssql/schema.sql index b4249728a..ca1020e77 100755 --- a/workflow/engine/data/mssql/schema.sql +++ b/workflow/engine/data/mssql/schema.sql @@ -3116,3 +3116,41 @@ CREATE TABLE [DASHLET_INSTANCE] [DAS_INS_STATUS] TINYINT default 1 NOT NULL, CONSTRAINT DASHLET_INSTANCE_PK PRIMARY KEY ([DAS_INS_UID]) ); + +/* ---------------------------------------------------------------------- */ +/* APP_SOLR_QUEUE */ +/* ---------------------------------------------------------------------- */ + + +IF EXISTS (SELECT 1 FROM sysobjects WHERE type = 'U' AND name = 'APP_SOLR_QUEUE') +BEGIN + DECLARE @reftable_69 nvarchar(60), @constraintname_69 nvarchar(60) + DECLARE refcursor CURSOR FOR + select reftables.name tablename, cons.name constraintname + from sysobjects tables, + sysobjects reftables, + sysobjects cons, + sysreferences ref + where tables.id = ref.rkeyid + and cons.id = ref.constid + and reftables.id = ref.fkeyid + and tables.name = 'APP_SOLR_QUEUE' + OPEN refcursor + FETCH NEXT from refcursor into @reftable_69, @constraintname_69 + while @@FETCH_STATUS = 0 + BEGIN + exec ('alter table '+@reftable_69+' drop constraint '+@constraintname_69) + FETCH NEXT from refcursor into @reftable_69, @constraintname_69 + END + CLOSE refcursor + DEALLOCATE refcursor + DROP TABLE [APP_SOLR_QUEUE] +END + + +CREATE TABLE [APP_SOLR_QUEUE] +( + [APP_UID] VARCHAR(32) default '' NOT NULL, + [APP_UPDATED] TINYINT default 1 NOT NULL, + CONSTRAINT APP_SOLR_QUEUE_PK PRIMARY KEY ([APP_UID]) +); diff --git a/workflow/engine/data/mysql/schema.sql b/workflow/engine/data/mysql/schema.sql index 3c02bfdd4..98fb3de3f 100755 --- a/workflow/engine/data/mysql/schema.sql +++ b/workflow/engine/data/mysql/schema.sql @@ -1403,5 +1403,18 @@ CREATE TABLE `DASHLET_INSTANCE` `DAS_INS_STATUS` TINYINT default 1 NOT NULL, PRIMARY KEY (`DAS_INS_UID`) )ENGINE=MyISAM DEFAULT CHARSET='utf8' COMMENT='Dashblets definitions'; +#----------------------------------------------------------------------------- +#-- APP_SOLR_QUEUE +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `APP_SOLR_QUEUE`; + + +CREATE TABLE `APP_SOLR_QUEUE` +( + `APP_UID` VARCHAR(32) default '' NOT NULL, + `APP_UPDATED` TINYINT default 1 NOT NULL, + PRIMARY KEY (`APP_UID`) +)ENGINE=MyISAM DEFAULT CHARSET='utf8' COMMENT='APP_SOLR_QUEUE'; # This restores the fkey checks, after having unset them earlier SET FOREIGN_KEY_CHECKS = 1; diff --git a/workflow/engine/methods/cases/proxyCasesList.php b/workflow/engine/methods/cases/proxyCasesList.php index db6a959b6..d0cb8ea10 100755 --- a/workflow/engine/methods/cases/proxyCasesList.php +++ b/workflow/engine/methods/cases/proxyCasesList.php @@ -18,13 +18,25 @@ $dateTo = isset($_POST['dateTo']) ? substr($_POST['dateTo'],0,10) : ''; try { - // - G::LoadClass('applications'); - $apps = new Applications(); + $result =""; + + G::LoadClass('AppSolr'); + $ApplicationSolrIndex = new AppSolr(); + $userUid = ( isset($_SESSION['USER_LOGGED'] ) && $_SESSION['USER_LOGGED'] != '' ) ? $_SESSION['USER_LOGGED'] : null; - $data = $apps->getAll($userUid, $start, $limit, $action, $filter, $search, $process, $user, $status, $type, $dateFrom, $dateTo, $callback, $dir, $sort); - echo G::json_encode($data); + if ($action != 'paused' && $ApplicationSolrIndex->isSolrEnabled()) { + $data = $ApplicationSolrIndex->getAppGridData($userUid, $start, $limit, $action, $filter, $search, $process, $user, $status, $type, $dateFrom, $dateTo, $callback, $dir, $sort); + $result = G::json_encode($data); + } + else{ + G::LoadClass('applications'); + $apps = new Applications(); + $data = $apps->getAll($userUid, $start, $limit, $action, $filter, $search, $process, $user, $status, $type, $dateFrom, $dateTo, $callback, $dir, $sort); + + $result = G::json_encode($data); + } + echo $result; } catch ( Exception $e ) { $msg = array ( 'error' => $e->getMessage() ); diff --git a/workflow/engine/templates/cases/casesList.js b/workflow/engine/templates/cases/casesList.js index a72d26cba..97f07f934 100644 --- a/workflow/engine/templates/cases/casesList.js +++ b/workflow/engine/templates/cases/casesList.js @@ -600,7 +600,16 @@ Ext.onReady ( function() { reader: readerCasesList, writer: writerCasesList, // <-- plug a DataWriter into the store just as you would a Reader autoSave: true, // <-- false would delay executing create, update, destroy requests until specifically told to do so with some [save] buton. - sortInfo:{field: 'APP_CACHE_VIEW.APP_NUMBER', direction: "DESC"} + sortInfo:{field: 'APP_CACHE_VIEW.APP_NUMBER', direction: "DESC"}, + listeners: { + load: function(response){ + //console.log(response.reader.jsonData); + if (response.reader.jsonData.result === false) { + PMExt.notify('ERROR', response.reader.jsonData.message); + //PMExt.error + } + } + } }); storeReassignCases = new Ext.data.Store({