2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4 * SugarCRM Community Edition is a customer relationship management program developed by
5 * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
7 * This program is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Affero General Public License version 3 as published by the
9 * Free Software Foundation with the addition of the following permission added
10 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
19 * You should have received a copy of the GNU Affero General Public License along with
20 * this program; if not, see http://www.gnu.org/licenses or write to the Free
21 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
27 * The interactive user interfaces in modified source and object code versions
28 * of this program must display Appropriate Legal Notices, as required under
29 * Section 5 of the GNU Affero General Public License version 3.
31 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32 * these Appropriate Legal Notices must retain the display of the "Powered by
33 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34 * technical reasons, the Appropriate Legal Notices must display the words
35 * "Powered by SugarCRM".
36 ********************************************************************************/
39 class BreadCrumbStack {
42 * Maintain an ordered list of items in the breadcrumbs
48 * Maps an item_id to the position index in stack
54 * Boolean flag to determine whether or not entries not visible should be removed
58 private $deleteInvisible = false;
63 * Constructor for BreadCrumbStack that builds list of breadcrumbs using tracker table
65 * @param $user_id String value of user id to get bread crumb items for
66 * @param $modules mixed value of module name(s) to provide extra filtering
68 public function BreadCrumbStack($user_id, $modules='') {
69 $this->stack = array();
70 $this->stackMap = array();
72 $admin = new Administration();
73 $admin->retrieveSettings('tracker');
75 $this->deleteInvisible = !empty($admin->settings['tracker_Tracker']);
76 $db = DBManagerFactory::getInstance();
79 if(!empty($modules)) {
80 $history_max_viewed = 10;
81 $module_query = is_array($modules) ? ' AND module_name IN (\'' . implode("','" , $modules) . '\')' : ' AND module_name = \'' . $modules . '\'';
83 $history_max_viewed = (!empty($GLOBALS['sugar_config']['history_max_viewed']))? $GLOBALS['sugar_config']['history_max_viewed'] : 50;
86 $query = 'SELECT distinct item_id AS item_id, id, item_summary, module_name, monitor_id, date_modified FROM tracker WHERE user_id = \'' . $user_id . '\' AND deleted = 0 AND visible = 1 ' . $module_query . ' ORDER BY date_modified DESC';
87 $result = $db->limitQuery($query, 0, $history_max_viewed);
89 while(($row = $db->fetchByAssoc($result))) {
92 $items = array_reverse($items);
93 foreach($items as $item) {
100 * Returns true if the stack contains the specified item_id, false otherwise.
102 * @param item_id the item id to search for
103 * @return id of the first item on the stack
105 public function contains($item_id) {
106 if(!empty($this->stackMap)){
107 return array_key_exists($item_id, $this->stackMap);
113 * Push an element onto the stack.
114 * This will only maintain a list of unique item_ids, if an item_id is found to
115 * already exist in the stack, we want to remove it and update the database to reflect it's
118 * @param array $row - a trackable item to store in memory
120 public function push($row) {
121 if(is_array($row) && !empty($row['item_id'])) {
122 if($this->contains($row['item_id'])) {
123 //if this item already exists in the stack then update the found items
124 //to visible = 0 and add our new item to the stack
125 $item = $this->stack[$this->stackMap[$row['item_id']]];
126 if(!empty($item['id']) && $row['id'] != $item['id']){
127 $this->makeItemInvisible($item['id'], 0);
129 $this->popItem($item['item_id']);
131 //If we reach the max count, shift the first element off the stack
132 $history_max_viewed = (!empty($GLOBALS['sugar_config']['history_max_viewed']))? $GLOBALS['sugar_config']['history_max_viewed'] : 50;
134 if($this->length() >= $history_max_viewed) {
137 //Push the element into the stack
138 $this->addItem($row);
143 * Pop an item off the stack
146 public function pop(){
147 $item = array_shift($this->stack);
148 if(!empty($item['item_id']) && isset($this->stackMap[$item['item_id']])){
149 unset($this->stackMap[$item['item_id']]);
155 * Change the visibility of an item
159 private function makeItemInvisible($id){
160 if($this->deleteInvisible) {
161 $query = "DELETE FROM tracker where id = '{$id}'";
163 $query = "UPDATE tracker SET visible = 0 WHERE id = '{$id}'";
165 $GLOBALS['db']->query($query, true);
169 * Pop an Item off the stack. Call heal to reconstruct the indices properly
171 * @param string $item_id - the item id to remove from the stack
173 public function popItem($item_id){
174 if(isset($this->stackMap[$item_id])){
175 $idx = $this->stackMap[$item_id];
176 unset($this->stack[$idx]);
177 unset($this->stackMap[$item_id]);
183 * Add an item to the stack
185 * @param array $row - the row from the db query
187 private function addItem($row){
188 $this->stack[] = $row;
189 $this->stackMap[$row['item_id']] = ($this->length() - 1);
193 * Once we have removed an item from the stack we need to be sure to have the
194 * ids and indices match up properly. Heal takes care of that. This method should only
195 * be called when an item_id is already in the stack and needs to be removed
198 private function heal(){
199 $vals = array_values($this->stack);
200 $this->stack = array();
201 $this->stackMap = array();
202 foreach($vals as $key => $val){
203 $this->addItem($val);
208 * Return the number of elements in the stack
210 * @return int - the number of elements in the stack
212 public function length(){
213 return count($this->stack);
217 * Return the list of breadcrubmbs currently in memory
219 * @return array of breadcrumbs
221 public function getBreadCrumbList($filter_module='') {
222 if(!empty($filter_module)) {
224 if(is_array($filter_module)) {
225 foreach($this->stack as $entry) {
226 if(in_array($entry['module_name'], $filter_module)) {
227 $s2[$entry['item_id']] = $entry;
231 foreach($this->stack as $entry) {
232 if($entry['module_name'] == $filter_module) {
233 $s2[$entry['item_id']] = $entry;
238 $s2 = array_reverse($s2);
239 if(count($s2) > 10) {
240 $s2 = array_slice($s2, 0, 10);
246 $s = array_reverse($s);
248 $s = array_slice($s, 0, 10);