r46466 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r46465‎ | r46466 | r46467 >
Date:19:31, 28 January 2009
Author:tparscal
Status:deferred
Tags:
Comment:
Greatly improved the search feature.
Modified paths:
  • /trunk/extensions/DataCenter/DataCenter.css (modified) (history)
  • /trunk/extensions/DataCenter/DataCenter.db.php (modified) (history)
  • /trunk/extensions/DataCenter/DataCenter.i18n.php (modified) (history)
  • /trunk/extensions/DataCenter/DataCenter.ui.php (modified) (history)
  • /trunk/extensions/DataCenter/UI/Widgets/Search.php (modified) (history)
  • /trunk/extensions/DataCenter/UI/Widgets/SearchResults.php (modified) (history)

Diff [purge]

Index: trunk/extensions/DataCenter/DataCenter.css
@@ -123,11 +123,6 @@
124124 div.datacenter-ui div.widget-search input.query {
125125 margin-top: -8px;
126126 }
127 -div.datacenter-ui div.widget-search input.go {
128 - margin-top: -8px;
129 - margin-left: 8px;
130 - font-weight: bold;
131 -}
132127 div.datacenter-ui div.widget-search input.search {
133128 margin-top: -8px;
134129 margin-left: 8px;
@@ -136,11 +131,34 @@
137132 /*
138133 * Search Results Widget
139134 */
 135+div.datacenter-ui div.widget-searchresults div.types {
 136+ height: 22px;
 137+ border-bottom: solid 1px silver;
 138+ margin-bottom: 15px;
 139+}
 140+div.datacenter-ui div.widget-searchresults div.type-normal {
 141+ height: 21px;
 142+ float: left;
 143+ border-top: solid 1px white;
 144+ border-bottom: solid 1px silver;
 145+ padding-left: 7px;
 146+ padding-right: 7px;
 147+}
 148+div.datacenter-ui div.widget-searchresults div.type-current {
 149+ height: 21px;
 150+ float: left;
 151+ border: solid 1px silver;
 152+ border-bottom: solid 1px white;
 153+ padding-left: 6px;
 154+ padding-right: 6px;
 155+}
140156 div.datacenter-ui div.widget-searchresults div.results {
141 - border-top: solid 1px silver;
142 - margin-top: 8px;
143 - padding-top: 8px;
144157 }
 158+div.datacenter-ui div.widget-searchresults div.result {
 159+ padding: 8px;
 160+ cursor: pointer;
 161+ margin-bottom: 15px;
 162+}
145163
146164 /*
147165 * Form Widget
Index: trunk/extensions/DataCenter/DataCenter.db.php
@@ -445,78 +445,98 @@
446446 }
447447
448448 /**
449 - * Gets rows from list of targets that match query on specific columns
450 - * @param targets Array of Arrays with category, type and fields
451 - * keys where category and type are strings and
452 - * fields is an array of strings of field names
 449+ * Gets rows from a target that match query on specific columns
 450+ * @param target Array with category, type and fields keys where
 451+ * category and type are strings and fields is a
 452+ * string of a field name or an array of strings of
 453+ * field names
453454 * @param query String of search terms
454455 * @param options Optional Associative array of tables, fields,
455456 * conditions and options each being the array
456457 * form of compatible arguments to MediaWiki's
457458 * Database select statement.
458459 */
459 - public static function getSearchResults(
460 - array $targets,
 460+ public static function getMatches(
 461+ $class,
 462+ $category,
 463+ $type,
 464+ $fields,
461465 $query,
462466 array $options = array()
463467 ) {
464468 $dbr = wfGetDB( DB_SLAVE );
465 - $results = array();
466 - foreach ( $targets as $target ) {
467 - $targetOptions = self::buildSearchTargetOptions( $target, $query );
468 - $targetOptions = array_merge_recursive(
469 - $targetOptions, $options
 469+ if ( !self::isType( $category, $type ) ) {
 470+ throw new MWException(
 471+ $category . '/' . $type . ' is not a valid type'
470472 );
471 - $res = $dbr->select(
472 - array_unique( $targetOptions['tables'] ),
473 - $targetOptions['fields'],
474 - $targetOptions['conditions'],
475 - __METHOD__,
476 - $targetOptions['options'],
477 - $targetOptions['joins']
478 - );
479 - while ( $row = $dbr->fetchRow( $res ) ) {
480 - $results[] = new DataCenterDBSearchResult(
481 - $target['category'], $target['type'], $row
482 - );
483 - }
484473 }
 474+ $options = array_merge_recursive(
 475+ self::$defaultOptions,
 476+ array(
 477+ 'tables' => array( self::getTableName( $category, $type ) ),
 478+ 'fields' => array( '*' ),
 479+ ),
 480+ self::buildMatch( $category, $type, $fields, $query ),
 481+ $options
 482+ );
 483+ $res = $dbr->select(
 484+ array_unique( $options['tables'] ),
 485+ $options['fields'],
 486+ $options['conditions'],
 487+ __METHOD__,
 488+ $options['options'],
 489+ $options['joins']
 490+ );
 491+ $results = array();
 492+ while ( $row = $dbr->fetchRow( $res ) ) {
 493+ $results[] = new $class( $category, $type, $row );
 494+ }
485495 return $results;
486496 }
 497+
487498 /**
488499 * Gets number of rows of a category and type
489 - * @param targets Array of Arrays with category, type and fields
490 - * keys where category and type are strings and
491 - * fields is an array of strings of field names
 500+ * @param target Array with category, type and fields keys where
 501+ * category and type are strings and fields is a
 502+ * string of a field name or an array of strings of
 503+ * field names
492504 * @param query String of search terms
493505 * @param options Optional Associative array of tables, fields,
494506 * conditions and options each being the array
495507 * form of compatible arguments to MediaWiki's
496508 * Database select statement.
497509 */
498 - public static function numSearchResults(
499 - array $targets,
 510+ public static function numMatches(
 511+ $category,
 512+ $type,
 513+ $fields,
500514 $query,
501515 array $options = array()
502516 ) {
503517 $dbr = wfGetDB( DB_SLAVE );
504 - $count = 0;
505 - foreach ( $targets as $target ) {
506 - $targetOptions = self::buildSearchTargetOptions( $target, $query );
507 - $targetOptions = array_merge_recursive(
508 - $targetOptions, $options
 518+ if ( !self::isType( $category, $type ) ) {
 519+ throw new MWException(
 520+ $category . '/' . $type . ' is not a valid type'
509521 );
510 - $res = $dbr->select(
511 - array_unique( $targetOptions['tables'] ),
512 - $targetOptions['fields'],
513 - $targetOptions['conditions'],
514 - __METHOD__,
515 - $targetOptions['options'],
516 - $targetOptions['joins']
517 - );
518 - $count += $dbr->numRows( $res );
519522 }
520 - return $count;
 523+ $options = array_merge_recursive(
 524+ self::$defaultOptions,
 525+ array(
 526+ 'tables' => array( self::getTableName( $category, $type ) ),
 527+ 'fields' => array( '*' ),
 528+ ),
 529+ self::buildMatch( $category, $type, $fields, $query ),
 530+ $options
 531+ );
 532+ $res = $dbr->select(
 533+ array_unique( $options['tables'] ),
 534+ $options['fields'],
 535+ $options['conditions'],
 536+ __METHOD__,
 537+ $options['options'],
 538+ $options['joins']
 539+ );
 540+ return $dbr->numRows( $res );
521541 }
522542
523543 /**
@@ -1381,6 +1401,33 @@
13821402 );
13831403 }
13841404
 1405+ /**
 1406+ * Builds array of options which match a query against a number of fields
 1407+ * using case-insensitive partial matching
 1408+ * @param category String of category to lookup type in
 1409+ * @param type String of category to lookup fields in
 1410+ * @param fields String of field to match query with
 1411+ * @param value String of query to match to field value
 1412+ */
 1413+ public static function buildMatch(
 1414+ $category,
 1415+ $type,
 1416+ $fields,
 1417+ $query
 1418+ ) {
 1419+ $dbr = wfGetDB( DB_SLAVE );
 1420+ $conditions = array();
 1421+ if ( !is_array( $fields ) ) {
 1422+ $fields = array( $fields );
 1423+ }
 1424+ foreach ( $fields as $field ) {
 1425+ $columnName = self::getColumnName( $category, $type, $field );
 1426+ $conditions[] = 'UPPER(' . $columnName . ') LIKE UPPER(' .
 1427+ $dbr->addQuotes( '%' . $query . '%' ) . ')';
 1428+ }
 1429+ return array( 'conditions' => array( implode( '||', $conditions ) ) );
 1430+ }
 1431+
13851432 /* List Builders */
13861433
13871434 /**
@@ -1414,56 +1461,6 @@
14151462 }
14161463 return $table;
14171464 }
1418 -
1419 - /* Privates Static Functions */
1420 -
1421 - /**
1422 - * Builds array of options for a search target
1423 - * @param target Array of target parameters
1424 - * @param query String of search terms
1425 - */
1426 - private static function buildSearchTargetOptions(
1427 - $target,
1428 - $query
1429 - ) {
1430 - $dbr = wfGetDB( DB_SLAVE );
1431 - if (
1432 - !isset( $target['category'] ) ||
1433 - !isset( $target['type'] ) ||
1434 - !isset( $target['fields'] ) ||
1435 - !is_array( $target['fields'] )
1436 - ) {
1437 - throw new MWException(
1438 - 'Target does not contain enough information'
1439 - );
1440 - }
1441 - if ( !self::isType( $target['category'], $target['type'] ) ) {
1442 - throw new MWException(
1443 - $target['category'] . '/' . $target['type'] .
1444 - ' is not a valid type'
1445 - );
1446 - }
1447 - $conditions = array();
1448 - foreach ( $target['fields'] as $field ) {
1449 - $columnName = self::getColumnName(
1450 - $target['category'], $target['type'], $field
1451 - );
1452 - $conditions[] = $columnName . ' LIKE ' .
1453 - $dbr->addQuotes( $query );
1454 - }
1455 - return array_merge_recursive(
1456 - self::$defaultOptions,
1457 - array(
1458 - 'tables' => array(
1459 - self::getTableName(
1460 - $target['category'], $target['type']
1461 - )
1462 - ),
1463 - 'fields' => array( '*' ),
1464 - 'conditions' => implode( '||', $conditions )
1465 - )
1466 - );
1467 - }
14681465 }
14691466
14701467 class DataCenterDBRow {
@@ -2434,10 +2431,6 @@
24352432 }
24362433 }
24372434
2438 -class DataCenterDBSearchResult extends DataCenterDBRow {
2439 - //
2440 -}
2441 -
24422435 class DataCenterDBPlan extends DataCenterDBRow {
24432436
24442437 /* Protected Members */
Index: trunk/extensions/DataCenter/DataCenter.ui.php
@@ -532,24 +532,24 @@
533533 );
534534 $url = self::$urlBase;
535535 // Checks if the page is set now
536 - if ( $parameters['page'] ) {
 536+ if ( $parameters['page'] !== null ) {
537537 // Adds page to url
538538 $url .= '/' . $parameters['page'];
539 - if ( $parameters['type'] ) {
 539+ if ( $parameters['type'] !== null ) {
540540 // Adds type to url
541541 $url .= ':' . $parameters['type'];
542542 // Checks if object id was given
543 - if ( $parameters['id'] ) {
 543+ if ( $parameters['id'] !== null ) {
544544 // Adds id to url
545545 $url .= ':' . $parameters['id'];
546546 }
547547 }
548548 // Checks if action was given
549 - if ( $parameters['action'] ) {
 549+ if ( $parameters['action'] !== null ) {
550550 // Adds action to url
551551 $url .= '/' . $parameters['action'];
552552 // Checks if parameter was given
553 - if ( $parameters['parameter'] ) {
 553+ if ( $parameters['parameter'] !== null ) {
554554 if ( is_array( $parameters['parameter'] ) ) { // Adds parameter to url
555555 $url .= ':' . implode( ',', $parameters['parameter'] );
556556 } else {
@@ -557,12 +557,12 @@
558558 $url .= ':' . $parameters['parameter'];
559559 }
560560 }
561 - } else if ( $parameters['limit'] ) {
 561+ } else if ( $parameters['limit'] !== null ) {
562562 $url .= '/';
563563 }
564 - if ( $parameters['limit'] ) {
 564+ if ( $parameters['limit'] !== null ) {
565565 $url .= '/' . $parameters['limit'];
566 - if ( $parameters['offset'] ) {
 566+ if ( $parameters['offset'] !== null ) {
567567 $url .= ':' . $parameters['offset'];
568568 }
569569 }
Index: trunk/extensions/DataCenter/UI/Widgets/Search.php
@@ -115,16 +115,6 @@
116116 )
117117 )
118118 );
119 - // Adds go button
120 - $xmlOutput .= DataCenterXml::tag(
121 - 'input',
122 - array(
123 - 'type' => 'submit',
124 - 'class' => 'go',
125 - 'name' => 'meta[go]',
126 - 'value' => DataCenterUI::message( 'label', 'go' )
127 - )
128 - );
129119 // Adds search button
130120 $xmlOutput .= DataCenterXml::tag(
131121 'input',
@@ -166,31 +156,34 @@
167157 ) {
168158 global $wgOut;
169159 $path = DataCenterPage::getPath();
170 - if ( isset( $data['meta']['query'] ) && $data['meta']['query'] != '' ) {
171 - if ( isset( $data['meta']['go'] ) ) {
172 - // Look for exact match
173 - // Need some solution here
174 - // Checks if there was a match
175 - if ( false ) {
176 - // Goes right to it!
177 - $wgOut->redirect( DataCenterXml::url( $path ) );
178 - return;
179 - }
180 - }
181 - // Shows search results
182 - $path['action'] = 'results';
183 - // Sanitize: allow alpha-numeric as well as
184 - // spaces, underscores, dashes and periods
185 - $path['parameter'] = urlencode(
 160+ if ( isset( $data['meta']['query'] ) ) {
 161+ // Sanitize: allow alpha-numeric
 162+ $queryContent = urlencode(
186163 preg_replace(
187164 '`\ +`',
188165 ' ',
189166 preg_replace(
 167+ '`[^a-z0-9]`i', '', $data['meta']['query']
 168+ )
 169+ )
 170+ );
 171+ // Sanitize: allow alpha-numeric as well as spaces, underscores,
 172+ // dashes and periods
 173+ $query = urlencode(
 174+ preg_replace(
 175+ '`\ +`',
 176+ ' ',
 177+ preg_replace(
190178 '`[^a-z0-9\ \_\-\.]`i', '', $data['meta']['query']
191179 )
192180 )
193181 );
194182 }
 183+ if ( isset( $queryContent ) && $queryContent != '' ) {
 184+ // Shows search results
 185+ $path['action'] = 'results';
 186+ $path['parameter'] = $query;
 187+ }
195188 $wgOut->redirect( DataCenterXml::url( $path ) );
196189 }
197190 }
\ No newline at end of file
Index: trunk/extensions/DataCenter/UI/Widgets/SearchResults.php
@@ -31,14 +31,52 @@
3232
3333 private static $targets = array(
3434 array(
 35+ 'class' => 'DataCenterDBAsset',
3536 'category' => 'asset',
3637 'type' => 'rack',
37 - 'fields' => array( 'serial', 'asset' )
 38+ 'fields' => array( 'serial', 'asset' ),
 39+ 'table' => array(
 40+ 'fields' => array(
 41+ 'manufacturer',
 42+ 'model' => array( 'field' => 'name' ),
 43+ 'serial',
 44+ 'asset',
 45+ 'tense' => array( 'format' => 'option' ),
 46+ 'location' => array(
 47+ 'field' => 'location_name'
 48+ )
 49+ ),
 50+ 'link' => array(
 51+ 'page' => 'assets',
 52+ 'type' => 'rack',
 53+ 'id' => '#id',
 54+ 'action' => 'view',
 55+ )
 56+ ),
3857 ),
3958 array(
 59+ 'class' => 'DataCenterDBAsset',
4060 'category' => 'asset',
4161 'type' => 'object',
42 - 'fields' => array( 'serial', 'asset' )
 62+ 'fields' => array( 'serial', 'asset' ),
 63+ 'table' => array(
 64+ 'fields' => array(
 65+ 'manufacturer',
 66+ 'model' => array( 'field' => 'name' ),
 67+ 'serial',
 68+ 'asset',
 69+ 'tense' => array( 'format' => 'option' ),
 70+ 'location' => array(
 71+ 'field' => 'location_name'
 72+ )
 73+ ),
 74+ 'link' => array(
 75+ 'page' => 'assets',
 76+ 'type' => 'object',
 77+ 'id' => '#id',
 78+ 'action' => 'view',
 79+ )
 80+ ),
4381 )
4482 );
4583
@@ -54,18 +92,101 @@
5593 $parameters = array_merge( self::$defaultParameters, $parameters );
5694 // Begins widget
5795 $xmlOutput = parent::begin( $parameters['class'] );
58 - // Gets search results
59 - $results = DataCenterDB::getSearchResults(
60 - self::$targets, $parameters['query']
61 - );
62 - // Adds results
63 - $xmlOutput .= DataCenterXml::open( 'div', array( 'class' => 'results' ) );
64 - foreach ( $results as $result ) {
65 - $xmlOutput .= DataCenterXml::tag(
66 - 'pre', array(), var_export( $result->get(), true )
 96+ // Adds result type menu
 97+ $currentTarget = null;
 98+ $currentNum = null;
 99+ $menuItems = array();
 100+ foreach ( self::$targets as $target ) {
 101+ $numMatches = DataCenterDB::numMatches(
 102+ $target['category'],
 103+ $target['type'],
 104+ $target['fields'],
 105+ $parameters['query']
67106 );
 107+ if ( $numMatches == 0 ) {
 108+ continue;
 109+ }
 110+ $fusedType = $target['category'] . '.' . $target['type'];
 111+ if ( !$path['type'] ) {
 112+ $path['type'] = $fusedType;
 113+ }
 114+ if ( $path['type'] == $fusedType ) {
 115+ $currentTarget = $target;
 116+ $currentNum = $numMatches;
 117+ $state = 'current';
 118+ } else {
 119+ $state = 'normal';
 120+ }
 121+ $typePath = array_merge(
 122+ $path,
 123+ array( 'type' => $target['category'] . '.' . $target['type'] )
 124+ );
 125+ $menuItems[] = DataCenterXml::div(
 126+ array( 'class' => 'type-' . $state ),
 127+ DataCenterXml::link(
 128+ DataCenterUI::message(
 129+ 'results',
 130+ $target['category'] . '-' . $target['type'],
 131+ $numMatches
 132+ ),
 133+ $typePath
 134+ )
 135+ );
68136 }
69 - $xmlOutput .= DataCenterXml::close( 'div' );
 137+ $resultItems = array();
 138+ if ( !$currentTarget ) {
 139+ $xmlOutput .= DataCenterUI::renderWidget(
 140+ 'body',
 141+ array( 'message' => 'notice-no-results', 'style' => 'notice' )
 142+ );
 143+ }
 144+ else {
 145+ $joins = array();
 146+ if ( $currentTarget['class'] == 'DataCenterDBAsset' ) {
 147+ $joins = array_merge_recursive(
 148+ DataCenterDB::buildJoin(
 149+ 'model', $currentTarget['type'], 'id',
 150+ 'asset', $currentTarget['type'], 'model',
 151+ array( 'name', 'manufacturer' )
 152+ ),
 153+ DataCenterDB::buildJoin(
 154+ 'facility', 'location', 'id',
 155+ 'asset', $currentTarget['type'], 'location',
 156+ array( 'name' => 'location_name' )
 157+ )
 158+ );
 159+ }
 160+ // Gets search results
 161+ $results = DataCenterDB::getMatches(
 162+ $currentTarget['class'],
 163+ $currentTarget['category'],
 164+ $currentTarget['type'],
 165+ $currentTarget['fields'],
 166+ $parameters['query'],
 167+ array_merge_recursive(
 168+ $joins,
 169+ DataCenterDB::buildRange( $path )
 170+ )
 171+ );
 172+ // Adds types
 173+ $xmlOutput .= DataCenterXml::div(
 174+ array( 'class' => 'types' ), implode( $menuItems )
 175+ );
 176+ // Adds results
 177+ $xmlOutput .= DataCenterXml::div(
 178+ array( 'class' => 'results' ),
 179+ DataCenterUI::renderWidget(
 180+ 'table',
 181+ array_merge(
 182+ $currentTarget['table'],
 183+ array(
 184+ 'rows' => $results,
 185+ 'num' => $currentNum,
 186+ )
 187+ )
 188+ )
 189+ );
 190+ }
70191 // Ends widget
71192 $xmlOutput .= parent::end();
72193 // Returns results
Index: trunk/extensions/DataCenter/DataCenter.i18n.php
@@ -178,6 +178,9 @@
179179 'datacenter-ui-label-reset' => 'Reset',
180180 'datacenter-ui-label-save' => 'Save',
181181 'datacenter-ui-label-search' => 'Search',
 182+ // Results
 183+ 'datacenter-ui-results-asset-rack' => 'Rack Assets ($1)',
 184+ 'datacenter-ui-results-asset-object' => 'Object Assets ($1)',
182185 // Defaults
183186 'datacenter-ui-default-new-type' => 'New $1',
184187 // List Headings

Status & tagging log