initial commit
This commit is contained in:
131
src/Search.php
Normal file
131
src/Search.php
Normal file
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: 91373
|
||||
* Date: 7/8/2016
|
||||
* Time: 6:27 PM
|
||||
*/
|
||||
|
||||
namespace Element\Search;
|
||||
|
||||
class Search {
|
||||
|
||||
/* @var $model \Illuminate\Database\Eloquent\Model */
|
||||
public function search( SearchableContract $model, $string ){
|
||||
$query = $this->formatQuery( $string );
|
||||
$models = $model->all();
|
||||
$returns = [];
|
||||
$toOpt = [];
|
||||
$optHits = [];
|
||||
$orgHits = [];
|
||||
|
||||
/**
|
||||
* Count the number of times each word in the search
|
||||
* string is found in the $item's searchable fields
|
||||
* and push those to an array.
|
||||
*/
|
||||
/* @var $item \Illuminate\Database\Eloquent\Model */
|
||||
foreach ( $models as $item ){
|
||||
$counts = [];
|
||||
foreach ( $query as $word ){
|
||||
$wordcount = 0;
|
||||
foreach ( $model->getSearchable() as $field ){
|
||||
$wordcount = $wordcount + substr_count( strtolower( $item->$field ), $word );
|
||||
}
|
||||
$counts[ $word ] = $wordcount;
|
||||
}
|
||||
array_push( $toOpt, [
|
||||
'counts' => $counts,
|
||||
'item' => $item
|
||||
]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert the word found count for each individual
|
||||
* word to a single unified hit count, adjusting
|
||||
* for common words and letters and push to an
|
||||
* array.
|
||||
*/
|
||||
foreach ( $toOpt as $formattedItem ){
|
||||
$hits = 0;
|
||||
foreach ( $formattedItem['counts'] as $word => $count ){
|
||||
if ( strlen( $word ) == 1 ){
|
||||
$hits += ($count*0.1);
|
||||
}
|
||||
elseif ( strlen( $word ) == 2 ){
|
||||
$hits += ($count*0.3);
|
||||
}
|
||||
else {
|
||||
$hits += $count;
|
||||
}
|
||||
}
|
||||
array_push( $optHits, [
|
||||
'hits' => $hits,
|
||||
'item' => $formattedItem['item']
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the items in an array based on hit count.
|
||||
* Where the key is the number of hits, push all
|
||||
* items with that specific number of hits to
|
||||
* the sub array.
|
||||
*/
|
||||
foreach ( $optHits as $hitCountItem ){
|
||||
if ( isset( $orgHits[ (string) $hitCountItem['hits'] ] ) ){
|
||||
array_push( $orgHits[ (string) $hitCountItem['hits'] ], $hitCountItem['item'] );
|
||||
}
|
||||
else {
|
||||
$orgHits[ (string) $hitCountItem['hits'] ] = [ $hitCountItem['item'] ];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the array by the number of hits
|
||||
* from low to high. So, the items with
|
||||
* least hits to highest hits, still
|
||||
* grouped.
|
||||
*/
|
||||
ksort( $orgHits );
|
||||
|
||||
/**
|
||||
* Push each item to a single-dimensional array
|
||||
* in order of least number of hits to highest
|
||||
* number of hits.
|
||||
*/
|
||||
foreach ( $orgHits as $hitCountGroup ){
|
||||
foreach ( $hitCountGroup as $item ){
|
||||
array_push( $returns, $item );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the order of the array
|
||||
* so that the first item has the
|
||||
* greatest number of hits, and
|
||||
* the last one has the least.
|
||||
*/
|
||||
$returns = array_reverse( $returns );
|
||||
|
||||
/**
|
||||
* return the array in the form of a
|
||||
* Laravel model collection
|
||||
*/
|
||||
return collect( $returns );
|
||||
}
|
||||
|
||||
public function formatQuery( $string ){
|
||||
$words = explode(' ', $string);
|
||||
$return = [];
|
||||
foreach ( $words as $word ){
|
||||
$word = preg_replace('/[^[:alpha:]]/', '', $word); // removes all punctuation
|
||||
$word = strtolower( $word );
|
||||
if ( ! in_array( $word, $return ) ) {
|
||||
array_push($return, $word);
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user