Ticket #90: svn.ticket90.search-on-part-of-a-tag.patch
| File svn.ticket90.search-on-part-of-a-tag.patch, 20.9 KB (added by sebastian, 2 years ago) |
|---|
-
search.php
65 65 /** Set a singular parameter 66 66 @param name Parameter name 67 67 @param value Parameter value 68 @param validate Optional parameter to validate the parameter. Default is 69 true 68 70 @return True on success */ 69 function setParam($name, $value ) {70 if ($ this->validate($name, $value)) {71 function setParam($name, $value, $validate = true) { 72 if ($validate === false || $this->validate($name, $value)) { 71 73 $this->_data[$name] = $value; 72 74 return true; 73 75 } else { … … 75 77 } 76 78 } 77 79 78 function addParam($name, $value) { 80 /** Add a parameter to an array. 81 @param name Parameter name. 82 @param value Parameter value (which will be pluralized) 83 @param validate Optional parameter to validate the parameter. Default is 84 true 85 @note The name will be pluralized. */ 86 function addParam($name, $value, $validate = true) { 79 87 $name = Inflector::pluralize($name); 80 88 if (is_array($value)) { 81 89 foreach ($value as $v) { 82 $this->addParam($name, $v );90 $this->addParam($name, $v, $validate); 83 91 } 84 92 return; 85 93 } 86 94 87 95 if ((!isset($this->_data[$name]) || !in_array($value, $this->_data[$name])) && 88 $this->validate($name, $value)) {96 ($validate === false || $this->validate($name, $value))) { 89 97 $this->_data[$name][] = $value; 90 98 } 91 99 } … … 133 141 case 'set': 134 142 if (count($args) == 1) { 135 143 return $this->setParam($name, $args[0]); 144 } elseif (count($args) == 2) { 145 return $this->setParam($name, $args[0], $args[1]); 136 146 } 137 147 break; 138 148 case 'add': 139 149 if (count($args) == 1) { 140 150 return $this->addParam($name, $args[0]); 151 } elseif (count($args) == 2) { 152 return $this->addParam($name, $args[0], $args[1]); 141 153 } 142 154 break; 143 155 case 'del': -
views/explorer/quicksearch.ctp
1 1 <h1>Quick Search Results</h1> 2 2 <?php $session->flash(); ?> 3 3 4 <div class="minis">5 <script type="text/javascript">6 var mediaData = [];7 </script>8 4 9 5 <?php 10 6 $search->initialize(); 11 7 $cell=0; 12 8 13 if ( count($dataTags) + count($dataCategories) + count($dataLocations) == 0): ?>9 if (!count($this->data)): ?> 14 10 <div class="info"> 15 11 <?php printf(__("Sorry, nothing was found for %s", true), h($quicksearch)); ?> 16 12 </div> 17 <?php e ndif;?>13 <?php else: ?> 18 14 19 <?php // -- Output for Tags -- 20 if (count($dataTags) > 0) : ?> 21 <h2>Results for Tags:</h2> 22 <div align="left"> 23 <?php 24 foreach($dataTags as $media) { 25 echo $imageData->mediaLink($media, 'mini').' '; 26 } 27 ?> 28 </div> 15 <h2><?php printf(__('Results of %s', true), h($quicksearch)); ?></h2> 16 <div class="minis" align="left"> 17 <script type="text/javascript"> 18 var mediaData = []; 19 </script> 29 20 30 <?php31 echo 'See more results with tag: ';32 $names = Set::extract('/Tag/name', $dataTags);33 $names = array_unique($names);34 $links = array();35 foreach ($names as $name) {36 $links[] = $html->link($name, '/explorer/tag/'.$name);37 }38 echo implode(', ', $links);39 ?>40 <?php endif; /* if (count($dataTags) > 0) */ ?>41 42 <?php // -- Output for Categories --43 if (count($dataCategories) > 0) : ?>44 <h2>Results for Categories:</h2>45 <div align="left">46 21 <?php 47 foreach($ dataCategoriesas $media) {22 foreach($this->data as $media) { 48 23 echo $imageData->mediaLink($media, 'mini').' '; 49 24 } 50 25 ?> 51 26 </div> 52 27 53 28 <?php 54 echo 'See more results with category: '; 55 $names = Set::extract('/Category/name', $dataCategories); 56 $names = array_unique($names); 57 $links = array(); 58 foreach ($names as $name) { 59 $links[] = $html->link($name, '/explorer/category/'.$name); 29 $tags = Set::extract('/Tag/name', $this->data); 30 if (count($tags)) { 31 echo '<p>' . __('See more results of tag', true) . ': '; 32 $tags = array_unique($tags); 33 $links = array(); 34 foreach ($tags as $name) { 35 $links[] = $html->link($name, '/explorer/tag/'.$name); 36 } 37 echo implode(', ', $links) . '</p>'; 60 38 } 61 echo implode(', ', $links);62 ?>63 <?php endif; /* if (count($dataCategories) > 0) */ ?>64 39 65 <?php // -- Output for Locations -- 66 if (count($dataLocations) > 0) : ?> 67 <h2>Results for Locations:</h2> 68 <div align="left"> 69 <?php 70 foreach($dataLocations as $media) { 71 echo $imageData->mediaLink($media, 'mini').' '; 40 $categories = Set::extract('/Category/name', $this->data); 41 if (count($categories)) { 42 echo '<p>' . __('See more results of category', true) . ': '; 43 $categories = array_unique($categories); 44 $links = array(); 45 foreach ($categories as $name) { 46 $links[] = $html->link($name, '/explorer/category/'.$name); 47 } 48 echo implode(', ', $links) . '</p>'; 72 49 } 73 ?>74 </div>75 50 76 <?php 77 echo 'See more results with location: '; 78 $names = Set::extract('/Location/name', $dataLocations); 79 $names = array_unique($names); 80 $links = array(); 81 foreach ($names as $name) { 82 $links[] = $html->link($name, '/explorer/location/'.$name); 51 $locations = Set::extract('/Location/name', $this->data); 52 if (count($locations)) { 53 echo '<p>' . __('See more results of location', true) . ': '; 54 $locations = array_unique($locations); 55 $links = array(); 56 foreach ($locations as $name) { 57 $links[] = $html->link($name, '/explorer/location/'.$name); 58 } 59 echo implode(', ', $links) . '</p>'; 83 60 } 84 echo implode(', ', $links);85 61 ?> 86 <?php endif; /* if (count($dataLocations) > 0) */ ?> 87 88 </div> 62 <?php endif; ?> -
views/elements/topnav.ctp
18 18 } 19 19 20 20 echo "\n<div class=\"searchBox\" ><div class=\"searchBoxSub\" >"; 21 echo $form->create(null, array('url' => array('controller' => 'explorer', 'action' => 'quicksearch')));21 echo $form->create(null, array('url' => '/explorer/quicksearch')); 22 22 echo $form->input('Media.quicksearch', array ('label' => false, 'div' => false)); 23 23 $icon = Router::url("/img/icons/zoom.png"); 24 24 echo "<input type=\"image\" src=\"$icon\" width=\"16\" height=\"16\" id=\"go\" alt=\"Search\" title=\"Search\" />"; -
tests/cases/components/search.test.php
1 1 <?php 2 2 App::import('Core', array('Controller')); 3 3 App::import('Component', array('Search')); 4 App::import('File', 'Logger', array('file' => APP.'logger.php')); 4 5 5 6 Mock::generatePartial('SearchComponent', 'NoStopSearch', array('_stop')); 6 7 … … 81 82 $result = $this->Search->getShow(); 82 83 $this->assertEqual($result, 12); 83 84 85 // one rule, disabled validation 86 $this->Search->setShow('no validation', false); 87 $result = $this->Search->getShow(); 88 $this->assertEqual($result, 'no validation'); 89 84 90 // multple rules 85 91 $this->Search->addTag(array('he', 'the')); 86 92 $result = $this->Search->getTags(); 87 93 $this->assertEqual($result, array('the')); 88 94 95 // multple rules, disabled validation 96 $result = $this->Search->delTags(); 97 $this->Search->addTag(array('he', '+_?'), false); 98 $result = $this->Search->getTags(); 99 $this->assertEqual($result, array('he', '+_?')); 100 89 101 // disabled parameter 90 102 $this->Search->setUser('joe'); 91 103 $result = $this->Search->getUser(); … … 100 112 $this->Search->setWorld("rule it"); 101 113 $result = $this->Search->getWorld(); 102 114 $this->assertEqual($result, null); 115 116 // disabled parameter with disabled validation 117 $this->Search->setWorld("rule it", false); 118 $result = $this->Search->getWorld(); 119 $this->assertEqual($result, "rule it"); 103 120 } 104 121 105 122 } -
config/sql/schema.php
35 35 var $categories = array( 36 36 'id' => array('type'=>'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'), 37 37 'name' => array('type'=>'string', 'null' => true, 'default' => NULL, 'length' => 64, 'key' => 'index'), 38 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1), 'name ' => array('column' => 'name', 'unique' => 0))38 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1), 'name_index' => array('column' => 'name', 'unique' => 0)) 39 39 ); 40 40 var $categories_media = array( 41 41 'media_id' => array('type'=>'integer', 'null' => false, 'default' => '0'), 42 42 'category_id' => array('type'=>'integer', 'null' => false, 'default' => '0'), 43 'indexes' => array('PRIMARY' => array('column' => array('media_id', 'category_id'), 'unique' => 1), ' setid' => array('column' => 'category_id', 'unique' => 0))43 'indexes' => array('PRIMARY' => array('column' => array('media_id', 'category_id'), 'unique' => 1), 'category_id_index' => array('column' => 'category_id', 'unique' => 0), 'media_id_index' => array('column' => 'media_id', 'unique' => 0)) 44 44 ); 45 45 var $comments = array( 46 46 'id' => array('type'=>'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'), … … 70 70 'size' => array('type'=>'integer', 'null' => false), 71 71 'time' => array('type'=>'datetime', 'null' => false), 72 72 'readed' => array('type'=>'datetime', 'null' => true, 'default' => NULL), 73 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1), ' id' => array('column' => 'id', 'unique' => 0), 'user_id' => array('column' => 'user_id', 'unique' => 0), 'media_id' => array('column' => 'media_id', 'unique' => 0))73 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1), 'user_id_index' => array('column' => 'user_id', 'unique' => 0), 'media_id_index' => array('column' => 'media_id', 'unique' => 0)) 74 74 ); 75 75 var $groups = array( 76 76 'id' => array('type'=>'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'), 77 77 'user_id' => array('type'=>'integer', 'null' => true, 'default' => NULL), 78 78 'name' => array('type'=>'string', 'null' => false, 'length' => 32), 79 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1) , 'id' => array('column' => 'id', 'unique' => 0))79 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1)) 80 80 ); 81 81 var $groups_users = array( 82 82 'user_id' => array('type'=>'integer', 'null' => false, 'default' => '0'), 83 83 'group_id' => array('type'=>'integer', 'null' => false, 'default' => '0'), 84 'indexes' => array('PRIMARY' => array('column' => array('user_id', 'group_id'), 'unique' => 1), 'user id' => array('column' => 'user_id', 'unique' => 0), 'groupid' => array('column' => 'group_id', 'unique' => 0))84 'indexes' => array('PRIMARY' => array('column' => array('user_id', 'group_id'), 'unique' => 1), 'user_id_index' => array('column' => 'user_id', 'unique' => 0), 'group_id_index' => array('column' => 'group_id', 'unique' => 0)) 85 85 ); 86 86 var $locks = array( 87 87 'id' => array('type'=>'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'), … … 94 94 'exclusivelock' => array('type'=>'integer', 'null' => false, 'default' => '0'), 95 95 'created' => array('type'=>'datetime', 'null' => true, 'default' => NULL), 96 96 'modified' => array('type'=>'datetime', 'null' => true, 'default' => NULL), 97 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1), 'token ' => array('column' => 'token', 'unique' => 0), 'expires' => array('column' => 'expires', 'unique' => 0))97 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1), 'token_index' => array('column' => 'token', 'unique' => 0), 'expires_index' => array('column' => 'expires', 'unique' => 0)) 98 98 ); 99 99 var $locations = array( 100 100 'id' => array('type'=>'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'), 101 101 'name' => array('type'=>'string', 'null' => false, 'length' => 64, 'key' => 'index'), 102 102 'type' => array('type'=>'integer', 'null' => true, 'default' => NULL, 'length' => 3), 103 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1), 'name ' => array('column' => 'name', 'unique' => 0))103 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1), 'name_index' => array('column' => 'name', 'unique' => 0)) 104 104 ); 105 105 var $locations_media = array( 106 106 'location_id' => array('type'=>'integer', 'null' => false, 'default' => '0'), 107 107 'media_id' => array('type'=>'integer', 'null' => false, 'default' => '0'), 108 'indexes' => array('PRIMARY' => array('column' => array('media_id', 'location_id'), 'unique' => 1), 'location id' => array('column' => 'location_id', 'unique' => 0))108 'indexes' => array('PRIMARY' => array('column' => array('media_id', 'location_id'), 'unique' => 1), 'location_id_index' => array('column' => 'location_id', 'unique' => 0), 'media_id_index' => array('column' => 'media_id', 'unique' => 0)) 109 109 ); 110 110 var $media = array( 111 111 'id' => array('type'=>'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'), … … 136 136 'ranking' => array('type'=>'float', 'null' => true, 'default' => '0', 'key' => 'index'), 137 137 'voting' => array('type'=>'float', 'null' => true, 'default' => '0'), 138 138 'votes' => array('type'=>'integer', 'null' => true, 'default' => '0'), 139 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1), 'date ' => array('column' => 'date', 'unique' => 0), 'ranking' => array('column' => 'ranking', 'unique' => 0), 'id' => array('column' => 'id', 'unique' => 0), 'oacl' => array('column' => 'oacl', 'unique' => 0))139 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1), 'date_index' => array('column' => 'date', 'unique' => 0), 'ranking_index' => array('column' => 'ranking', 'unique' => 0), 'oacl_index' => array('column' => 'oacl', 'unique' => 0)) 140 140 ); 141 141 var $media_tags = array( 142 142 'media_id' => array('type'=>'integer', 'null' => false, 'default' => '0'), 143 143 'tag_id' => array('type'=>'integer', 'null' => false, 'default' => '0'), 144 'indexes' => array('PRIMARY' => array('column' => array('media_id', 'tag_id'), 'unique' => 1), ' imageid' => array('column' => 'media_id', 'unique' => 0), 'tagid' => array('column' => 'tag_id', 'unique' => 0))144 'indexes' => array('PRIMARY' => array('column' => array('media_id', 'tag_id'), 'unique' => 1), 'media_id_index' => array('column' => 'media_id', 'unique' => 0), 'tag_id_index' => array('column' => 'tag_id', 'unique' => 0)) 145 145 ); 146 146 var $options = array( 147 147 'id' => array('type'=>'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'), 148 148 'user_id' => array('type'=>'integer', 'null' => true, 'default' => NULL), 149 149 'name' => array('type'=>'string', 'null' => true, 'default' => NULL, 'length' => 64), 150 150 'value' => array('type'=>'string', 'null' => true, 'default' => NULL, 'length' => 192), 151 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1), 'user_id ' => array('column' => 'user_id', 'unique' => 0))151 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1), 'user_id_index' => array('column' => 'user_id', 'unique' => 0)) 152 152 ); 153 153 var $properties = array( 154 154 'id' => array('type'=>'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'), … … 161 161 var $tags = array( 162 162 'id' => array('type'=>'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'), 163 163 'name' => array('type'=>'string', 'null' => true, 'default' => NULL, 'length' => 64, 'key' => 'index'), 164 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1), 'name ' => array('column' => 'name', 'unique' => 0))164 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1), 'name_index' => array('column' => 'name', 'unique' => 0)) 165 165 ); 166 166 var $users = array( 167 167 'id' => array('type'=>'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'), … … 177 177 'firstname' => array('type'=>'string', 'null' => true, 'default' => NULL, 'length' => 32), 178 178 'lastname' => array('type'=>'string', 'null' => false, 'length' => 32), 179 179 'email' => array('type'=>'string', 'null' => true, 'default' => NULL, 'length' => 64), 180 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1) , 'id' => array('column' => 'id', 'unique' => 0))180 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1)) 181 181 ); 182 182 } 183 183 ?> -
controllers/components/search.php
337 337 338 338 return $data; 339 339 } 340 341 function quicksearch($text, $show = 12) { 342 $words = preg_split('/\s+/', trim($text)); 343 344 $tmp = array(); 345 foreach($words as $word) { 346 $tmp[] = '*' . $word . '*'; 347 } 348 $words = $tmp; 349 350 $this->addTags($words, false); 351 $this->addCategories($words, false); 352 $this->addLocations($words, false); 353 $this->setOperand('OR'); 354 355 $this->setSort('default', false); 356 $this->setShow($show); 357 358 return $this->paginate(); 359 } 340 360 } 341 361 ?> -
controllers/components/upgrade_schema.php
191 191 $modelName = $this->modelMapping[$table]; 192 192 } 193 193 if (!in_array($modelName, $models)) { 194 Logger::err("Model '$modelName' does not exists"); 195 $columns[$table] = "Model '$modelName' does not exists"; 196 trigger_error(sprintf(__("Model '%s' does not exists", true), $modelName), E_USER_WARNING); 197 continue; 194 Logger::warn("Model '$modelName' does not exists"); 198 195 } 199 196 200 197 $columns[$table] = $this->db->alterSchema(array($table => $changes), $table); -
controllers/components/query_builder.php
240 240 $counts = array(); 241 241 $conditions = array(); 242 242 foreach ($query['_counts'] as $count) { 243 $counts[] = "( $count+ 1 )";243 $counts[] = "( COALESCE($count, 0) + 1 )"; 244 244 $conditions[] = "COALESCE($count, 0)"; 245 245 } 246 246 $query['conditions'][] = '( '.implode(' + ', $conditions).' ) > 0'; … … 299 299 $habtm = Inflector::singularize($name); 300 300 301 301 $field = Inflector::camelize($habtm).'.name'; 302 $query['conditions'][] = $this->_buildCondition($field, $value);303 302 303 $tags = array(); 304 foreach($value as $v) { 305 if (preg_match('/[*\?]/', $v)) { 306 $v = preg_replace('/\*/', '%', $v); 307 $v = preg_replace('/\?/', '_', $v); 308 $query['conditions'][] = $this->_buildCondition($field, $v, array('operand' => 'LIKE')); 309 } else { 310 $tags[] = $v; 311 } 312 } 313 if (count($tags)) { 314 $query['conditions'][] = $this->_buildCondition($field, $tags); 315 } 316 304 317 $fieldCount = Inflector::camelize($habtm).'Count'; 305 318 $query['_counts'][] = $fieldCount; 306 319 -
controllers/explorer_controller.php
70 70 } 71 71 72 72 if ($quicksearch) { 73 // Perform queries for each Tags, Categories and Locations 74 // seperately: 75 76 // Split the query so that we have a list of tags/categories/locations. 77 // For now we split at whitespaces, improvements could be made to not 78 // split multiple tags/categories/locations enclosed in quotation marks 79 $words = preg_split('/\s+/', trim($quicksearch)); 80 81 // Reduce results to 6 82 $this->Search->setShow(6); 83 84 // Add tag to the query 85 $this->Search->addTags($words); 86 // Set variable dataTags for view 87 $this->Search->setTagOp('OR'); 88 $this->set('dataTags', $this->Search->paginate()); 89 // Reset query 90 $this->Search->delTags(); 91 $this->Search->delTagOp(); 92 93 $this->Search->addCategories($words); 94 $this->Search->setCategoryOp('OR'); 95 $this->set('dataCategories', $this->Search->paginate()); 96 $this->Search->delCategories(); 97 $this->Search->delCategoryOp(); 98 99 $this->Search->addLocations($words); 100 $this->Search->setLocationOp('OR'); 101 $this->set('dataLocations', $this->Search->paginate()); 102 $this->Search->delLocations(); 103 $this->Search->delLocationOp(); 104 } else { 105 $this->set('dataTags', array()); 106 $this->set('dataCategories', array()); 107 $this->set('dataLocations', array()); 73 $this->data = $this->Search->quicksearch($quicksearch, 6); 108 74 } 109 75 $this->set('quicksearch', $quicksearch); 110 76 }
