You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

196 lines
4.7 KiB

  1. <?php
  2. namespace TomLingham\Searchy\SearchDrivers;
  3. use Illuminate\Support\Facades\Schema;
  4. use TomLingham\Searchy\Interfaces\SearchDriverInterface;
  5. abstract class BaseSearchDriver implements SearchDriverInterface
  6. {
  7. protected $table;
  8. protected $columns;
  9. protected $searchFields;
  10. protected $searchString;
  11. protected $relevanceFieldName;
  12. protected $query;
  13. protected $withTrashed;
  14. /**
  15. * @param null $table
  16. * @param array $searchFields
  17. * @param $relevanceFieldName
  18. * @param array $columns
  19. *
  20. * @internal param $relevanceField
  21. */
  22. public function __construct($table = null, $searchFields = [], $relevanceFieldName, $columns = ['*'])
  23. {
  24. $this->searchFields = $searchFields;
  25. $this->table = $table;
  26. $this->columns = $columns;
  27. $this->relevanceFieldName = $relevanceFieldName;
  28. }
  29. /**
  30. * Specify whether to return soft deleted items or not
  31. *
  32. * @return $this
  33. */
  34. public function withTrashed()
  35. {
  36. $this->withTrashed = true;
  37. return $this;
  38. }
  39. /**
  40. * Specify which columns to return.
  41. *
  42. * @return $this
  43. */
  44. public function select()
  45. {
  46. $this->columns = func_get_args();
  47. return $this;
  48. }
  49. /**
  50. * Specify the string that is is being searched for.
  51. *
  52. * @param $searchString
  53. *
  54. * @return \Illuminate\Database\Query\Builder|mixed|static
  55. */
  56. public function query($searchString)
  57. {
  58. $this->searchString = trim(\DB::connection()->getPdo()->quote($searchString), "'");
  59. return $this;
  60. }
  61. /**
  62. * Get the results of the search as an Array.
  63. *
  64. * @return array
  65. */
  66. public function get()
  67. {
  68. return $this->run()->get();
  69. }
  70. /**
  71. * Returns an instance of the Laravel Fluent Database Query Object with the search
  72. * queries applied.
  73. *
  74. * @return array
  75. */
  76. public function getQuery()
  77. {
  78. return $this->run();
  79. }
  80. /**
  81. * Runs the 'having' method directly on the Laravel Fluent Database Query Object
  82. * and returns the instance of the object.
  83. *
  84. * @return mixed
  85. */
  86. public function having()
  87. {
  88. return call_user_func_array([$this->run(), 'having'], func_get_args());
  89. }
  90. /**
  91. * @return $this
  92. */
  93. protected function run()
  94. {
  95. $this->query = \DB::table($this->table)
  96. ->select($this->columns)
  97. ->addSelect($this->buildSelectQuery($this->searchFields));
  98. // If they included withTrashed flag then give them all records including soft deletes
  99. // Check to ensure the column exists before committing
  100. if( ! $this->withTrashed && in_array('deleted_at', Schema::getColumnListing($this->table)) )
  101. $this->query = $this->query->where('deleted_at', NULL);
  102. return $this->query
  103. ->orderBy($this->relevanceFieldName, 'desc')
  104. ->having($this->relevanceFieldName, '>', 0);
  105. }
  106. /**
  107. * @param array $searchFields
  108. *
  109. * @return array|\Illuminate\Database\Query\Expression
  110. */
  111. protected function buildSelectQuery(array $searchFields)
  112. {
  113. $query = [];
  114. foreach ($searchFields as $searchField) {
  115. if (strpos($searchField, '::')) {
  116. $concatString = implode(', ', array_map( [$this, 'sanitizeColumnName'] , explode('::', $searchField)));
  117. $query[] = $this->buildSelectCriteria("CONCAT({$concatString})");
  118. } else {
  119. $query[] = $this->buildSelectCriteria($this->sanitizeColumnName($searchField));
  120. }
  121. }
  122. return \DB::raw( implode(' + ', $query) . ' AS ' . $this->relevanceFieldName);
  123. }
  124. /**
  125. * Sanitize column names to prevent collisions with MySQL reserved words
  126. *
  127. * @param $name
  128. * @return string
  129. */
  130. protected function sanitizeColumnName( $name ){
  131. $name = trim($name, '` ');
  132. return "`${name}`";
  133. }
  134. /**
  135. * @param null $searchField
  136. *
  137. * @return string
  138. */
  139. protected function buildSelectCriteria($searchField = null)
  140. {
  141. $criteria = [];
  142. foreach ($this->matchers as $matcher => $multiplier) {
  143. $criteria[] = $this->makeMatcher($searchField, $matcher, $multiplier);
  144. }
  145. return implode(' + ', $criteria);
  146. }
  147. /**
  148. * @param $searchField
  149. * @param $matcherClass
  150. * @param $multiplier
  151. *
  152. * @return mixed
  153. */
  154. protected function makeMatcher($searchField, $matcherClass, $multiplier)
  155. {
  156. $matcher = new $matcherClass($multiplier);
  157. return $matcher->buildQueryString($searchField, $this->searchString);
  158. }
  159. }