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;
|
||||
}
|
||||
|
||||
}
|
||||
20
src/SearchFacade.php
Normal file
20
src/SearchFacade.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: 91373
|
||||
* Date: 7/8/2016
|
||||
* Time: 6:31 PM
|
||||
*/
|
||||
|
||||
namespace Element\Search;
|
||||
|
||||
|
||||
use Illuminate\Support\Facades\Facade;
|
||||
|
||||
class SearchFacade extends Facade
|
||||
{
|
||||
public static function getFacadeAccessor()
|
||||
{
|
||||
return 'e-search';
|
||||
}
|
||||
}
|
||||
24
src/SearchServiceProvider.php
Normal file
24
src/SearchServiceProvider.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Element\Search;
|
||||
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class SearchServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function boot(){
|
||||
|
||||
}
|
||||
|
||||
public function register(){
|
||||
|
||||
$this->app->bind('e-search', function(){
|
||||
return new Search;
|
||||
});
|
||||
|
||||
$loader = \Illuminate\Foundation\AliasLoader::getInstance();
|
||||
$loader->alias('Search', 'Element\Search\SearchFacade');
|
||||
|
||||
}
|
||||
}
|
||||
17
src/SearchableContract.php
Normal file
17
src/SearchableContract.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Element\Search;
|
||||
|
||||
interface SearchableContract {
|
||||
|
||||
/**
|
||||
* Returns an array of the names of the model's
|
||||
* database columns that should be searched.
|
||||
* The columns should be of type STRING
|
||||
* or TEXT only.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getSearchable();
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user