Completed
Push — master ( ec8fbc...686b54 )
by Mark
22:56
created
tasks/BuildVFI.php 1 patch
Indentation   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -1,12 +1,12 @@
 block discarded – undo
1 1
 <?php
2 2
 /**
3
- * Rebuilds all VirtualFieldIndexes
4
- *
5
- * @author Mark Guinn <[email protected]>
6
- * @date 9.26.13
7
- * @package shop_search
8
- * @subpackage tasks
9
- */
3
+	 * Rebuilds all VirtualFieldIndexes
4
+	 *
5
+	 * @author Mark Guinn <[email protected]>
6
+	 * @date 9.26.13
7
+	 * @package shop_search
8
+	 * @subpackage tasks
9
+	 */
10 10
 class BuildVFI extends BuildTask
11 11
 {
12 12
 	protected $title = 'Rebuild Virtual Field Indexes';
Please login to merge, or discard this patch.
code/SearchLog.php 1 patch
Indentation   +50 added lines, -50 removed lines patch added patch discarded remove patch
@@ -8,54 +8,54 @@
 block discarded – undo
8 8
  */
9 9
 class SearchLog extends DataObject
10 10
 {
11
-    private static $db = array(
12
-        'Query'         => 'Varchar(255)',
13
-        'Title'         => 'Varchar(255)', // title for breadcrumbs. any new facets added will be reflected here
14
-        'Link'          => 'Varchar(255)',
15
-        'Filters'       => 'Text', // json
16
-        'NumResults'    => 'Int',
17
-    );
18
-
19
-    private static $has_one = array(
20
-        'Member'        => 'Member',
21
-        'ParentSearch'  => 'SearchLog', // used in constructing a search breadcrumb
22
-    );
23
-
24
-
25
-    /**
26
-     * Generate the title if needed
27
-     */
28
-    protected function onBeforeWrite()
29
-    {
30
-        parent::onBeforeWrite();
31
-        if (!$this->Title) {
32
-            $this->Title = empty($this->Query) ? "Search" : "Search: {$this->Query}";
33
-        }
34
-    }
35
-
36
-
37
-    /**
38
-     * @return ArrayList
39
-     */
40
-    public function getBreadcrumbs()
41
-    {
42
-        $out    = new ArrayList();
43
-        $cur    = $this;
44
-
45
-        while ($cur && $cur->exists()) {
46
-            $out->unshift($cur);
47
-            $cur = $cur->ParentSearchID > 0 ? $cur->ParentSearch() : null;
48
-        }
49
-
50
-        return $out;
51
-    }
52
-
53
-
54
-    /**
55
-     * @return array
56
-     */
57
-    public function getFiltersArray()
58
-    {
59
-        return $this->Filters ? json_decode($this->Filters, true) : array();
60
-    }
11
+	private static $db = array(
12
+		'Query'         => 'Varchar(255)',
13
+		'Title'         => 'Varchar(255)', // title for breadcrumbs. any new facets added will be reflected here
14
+		'Link'          => 'Varchar(255)',
15
+		'Filters'       => 'Text', // json
16
+		'NumResults'    => 'Int',
17
+	);
18
+
19
+	private static $has_one = array(
20
+		'Member'        => 'Member',
21
+		'ParentSearch'  => 'SearchLog', // used in constructing a search breadcrumb
22
+	);
23
+
24
+
25
+	/**
26
+	 * Generate the title if needed
27
+	 */
28
+	protected function onBeforeWrite()
29
+	{
30
+		parent::onBeforeWrite();
31
+		if (!$this->Title) {
32
+			$this->Title = empty($this->Query) ? "Search" : "Search: {$this->Query}";
33
+		}
34
+	}
35
+
36
+
37
+	/**
38
+	 * @return ArrayList
39
+	 */
40
+	public function getBreadcrumbs()
41
+	{
42
+		$out    = new ArrayList();
43
+		$cur    = $this;
44
+
45
+		while ($cur && $cur->exists()) {
46
+			$out->unshift($cur);
47
+			$cur = $cur->ParentSearchID > 0 ? $cur->ParentSearch() : null;
48
+		}
49
+
50
+		return $out;
51
+	}
52
+
53
+
54
+	/**
55
+	 * @return array
56
+	 */
57
+	public function getFiltersArray()
58
+	{
59
+		return $this->Filters ? json_decode($this->Filters, true) : array();
60
+	}
61 61
 }
Please login to merge, or discard this patch.
code/ShopSearch.php 1 patch
Indentation   +356 added lines, -356 removed lines patch added patch discarded remove patch
@@ -1,383 +1,383 @@
 block discarded – undo
1 1
 <?php
2 2
 /**
3
- * Fulltext search index for shop buyables
4
- *
5
- * @author Mark Guinn <[email protected]>
6
- * @date 08.29.2013
7
- * @package shop_search
8
- */
3
+	 * Fulltext search index for shop buyables
4
+	 *
5
+	 * @author Mark Guinn <[email protected]>
6
+	 * @date 08.29.2013
7
+	 * @package shop_search
8
+	 */
9 9
 class ShopSearch extends Object
10 10
 {
11
-    const FACET_TYPE_LINK       = 'link';
12
-    const FACET_TYPE_CHECKBOX   = 'checkbox';
13
-    const FACET_TYPE_RANGE      = 'range';
11
+	const FACET_TYPE_LINK       = 'link';
12
+	const FACET_TYPE_CHECKBOX   = 'checkbox';
13
+	const FACET_TYPE_RANGE      = 'range';
14 14
 
15
-    /** @var string - class name of adapter class to use */
16
-    private static $adapter_class = 'ShopSearchSimple';
15
+	/** @var string - class name of adapter class to use */
16
+	private static $adapter_class = 'ShopSearchSimple';
17 17
 
18
-    /** @var array - these classes will be added to the index - e.g. Category, Page, etc. */
19
-    private static $searchable = array();
18
+	/** @var array - these classes will be added to the index - e.g. Category, Page, etc. */
19
+	private static $searchable = array();
20 20
 
21
-    /** @var bool - if true, all buyable models will be added to the index automatically  */
22
-    private static $buyables_are_searchable = true;
21
+	/** @var bool - if true, all buyable models will be added to the index automatically  */
22
+	private static $buyables_are_searchable = true;
23 23
 
24
-    /** @var int - size of paging in the search */
25
-    private static $page_size = 10;
24
+	/** @var int - size of paging in the search */
25
+	private static $page_size = 10;
26 26
 
27
-    /** @var bool */
28
-    private static $suggest_enabled = true;
27
+	/** @var bool */
28
+	private static $suggest_enabled = true;
29 29
 
30
-    /** @var int - how many suggestions to provide */
31
-    private static $suggest_limit = 5;
30
+	/** @var int - how many suggestions to provide */
31
+	private static $suggest_limit = 5;
32 32
 
33
-    /** @var bool */
34
-    private static $search_as_you_type_enabled = true;
33
+	/** @var bool */
34
+	private static $search_as_you_type_enabled = true;
35 35
 
36
-    /** @var int - how may sayt (search-as-you-type) entries to provide */
37
-    private static $sayt_limit = 5;
36
+	/** @var int - how may sayt (search-as-you-type) entries to provide */
37
+	private static $sayt_limit = 5;
38 38
 
39
-    /** @var bool - automatically create facets for static attributes */
40
-    private static $auto_facet_attributes = false;
39
+	/** @var bool - automatically create facets for static attributes */
40
+	private static $auto_facet_attributes = false;
41 41
 
42
-    /** @var string - optionally, a different template to run ajax results through (sans-Page.ss) */
43
-    private static $ajax_results_template = '';
42
+	/** @var string - optionally, a different template to run ajax results through (sans-Page.ss) */
43
+	private static $ajax_results_template = '';
44 44
 
45
-    /** @var string - these allow you to use different querystring params in you need to */
46
-    private static $qs_query         = 'q';
47
-    private static $qs_filters       = 'f';
48
-    private static $qs_parent_search = '__ps';
49
-    private static $qs_title         = '__t';
50
-    private static $qs_source        = '__src'; // used to log searches from search-as-you-type
51
-    private static $qs_sort          = 'sort';
45
+	/** @var string - these allow you to use different querystring params in you need to */
46
+	private static $qs_query         = 'q';
47
+	private static $qs_filters       = 'f';
48
+	private static $qs_parent_search = '__ps';
49
+	private static $qs_title         = '__t';
50
+	private static $qs_source        = '__src'; // used to log searches from search-as-you-type
51
+	private static $qs_sort          = 'sort';
52 52
 
53
-    /** @var array - I'm leaving this particularly bare b/c with config merging it's a pain to remove items */
54
-    private static $sort_options = array(
55
-        'score desc'            => 'Relevance',
53
+	/** @var array - I'm leaving this particularly bare b/c with config merging it's a pain to remove items */
54
+	private static $sort_options = array(
55
+		'score desc'            => 'Relevance',
56 56
 //		'SiteTree_Title asc'    => 'Alphabetical (A-Z)',
57 57
 //		'SiteTree_Title dsc'    => 'Alphabetical (Z-A)',
58
-    );
59
-
60
-    /**
61
-     * @var array - default search facets (price, category, etc)
62
-     *   Key    field name - e.g. Price - can be a VirtualFieldIndex field
63
-     *   Value  facet label - e.g. Search By Category - if the value is a relation or returns an array or
64
-     *          list all values will be faceted individually
65
-     *          NOTE: this can also be another array with keys: Label, Type, and Values (for checkbox only)
66
-     */
67
-    private static $facets = array();
68
-
69
-    /** @var array - field definition for Solr only */
70
-    private static $solr_fulltext_fields = array();
71
-
72
-    /** @var array - field definition for Solr only */
73
-    private static $solr_filter_fields = array();
74
-
75
-    /** @var string - if present, will create a copy of SiteTree_Title that's suited for alpha sorting */
76
-    private static $solr_title_sort_field = '';
77
-
78
-    /**
79
-     * @var string - If present, everything matching the following regex will be removed from
80
-     *               keyword search queries before passing to the search adapter.
81
-     */
82
-    private static $keyword_filter_regex = '/[^a-zA-Z0-9\s\-]/';
83
-
84
-
85
-    /**
86
-     * @return array
87
-     */
88
-    public static function get_searchable_classes()
89
-    {
90
-        // First get any explicitly declared searchable classes
91
-        $searchable = Config::inst()->get('ShopSearch', 'searchable');
92
-        if (is_string($searchable) && strlen($searchable) > 0) {
93
-            $searchable = array($searchable);
94
-        } elseif (!is_array($searchable)) {
95
-            $searchable = array();
96
-        }
97
-
98
-        // Add in buyables automatically if asked
99
-        if (Config::inst()->get('ShopSearch', 'buyables_are_searchable')) {
100
-            $buyables = SS_ClassLoader::instance()->getManifest()->getImplementorsOf('Buyable');
101
-            if (is_array($buyables) && count($buyables) > 0) {
102
-                foreach ($buyables as $c) {
103
-                    $searchable[] = $c;
104
-                }
105
-            }
106
-        }
107
-
108
-        return array_unique($searchable);
109
-    }
110
-
111
-    /**
112
-     * Returns an array of categories suitable for a dropdown menu
113
-     * TODO: cache this
114
-     *
115
-     * @param int $parentID [optional]
116
-     * @param string $prefix [optional]
117
-     * @param int $maxDepth [optional]
118
-     * @return array
119
-     * @static
120
-     */
121
-    public static function get_category_hierarchy($parentID = 0, $prefix = '', $maxDepth = 999)
122
-    {
123
-        $out = array();
124
-        $cats = ProductCategory::get()
125
-            ->filter(array(
126
-                'ParentID'      => $parentID,
127
-                'ShowInMenus'   => 1,
128
-            ))
129
-            ->sort('Sort');
130
-
131
-        // If there is a single parent category (usually "Products" or something), we
132
-        // probably don't want that in the hierarchy.
133
-        if ($parentID == 0 && $cats->count() == 1) {
134
-            return self::get_category_hierarchy($cats->first()->ID, $prefix, $maxDepth);
135
-        }
136
-
137
-        foreach ($cats as $cat) {
138
-            $out[$cat->ID] = $prefix . $cat->Title;
139
-            if ($maxDepth > 1) {
140
-                $out += self::get_category_hierarchy($cat->ID, $prefix . $cat->Title . ' > ', $maxDepth - 1);
141
-            }
142
-        }
143
-
144
-        return $out;
145
-    }
146
-
147
-    /**
148
-     * @return ShopSearchAdapter
149
-     */
150
-    public static function adapter()
151
-    {
152
-        $adapterClass = Config::inst()->get('ShopSearch', 'adapter_class');
153
-        return Injector::inst()->get($adapterClass);
154
-    }
155
-
156
-    /**
157
-     * @return ShopSearch
158
-     */
159
-    public static function inst()
160
-    {
161
-        return Injector::inst()->get('ShopSearch');
162
-    }
163
-
164
-    /**
165
-     * The result will contain at least the following:
166
-     *      Matches - SS_List of results
167
-     *      TotalMatches - total # of results, unlimited
168
-     *      Query - query string
169
-     * Also saves a log record.
170
-     *
171
-     * @param array $vars
172
-     * @param bool $logSearch [optional]
173
-     * @param bool $useFacets [optional]
174
-     * @param int $start [optional]
175
-     * @param int $limit [optional]
176
-     * @return ArrayData
177
-     */
178
-    public function search(array $vars, $logSearch=true, $useFacets=true, $start=-1, $limit=-1)
179
-    {
180
-        $qs_q   = $this->config()->get('qs_query');
181
-        $qs_f   = $this->config()->get('qs_filters');
182
-        $qs_ps  = $this->config()->get('qs_parent_search');
183
-        $qs_t   = $this->config()->get('qs_title');
184
-        $qs_sort= $this->config()->get('qs_sort');
185
-        if ($limit < 0) {
186
-            $limit  = $this->config()->get('page_size');
187
-        }
188
-        if ($start < 0) {
189
-            $start  = !empty($vars['start']) ? (int)$vars['start'] : 0;
190
-        } // as far as i can see, fulltextsearch hard codes 'start'
191
-        $facets = $useFacets ? $this->config()->get('facets') : array();
192
-        if (!is_array($facets)) {
193
-            $facets = array();
194
-        }
195
-        if (empty($limit)) {
196
-            $limit = -1;
197
-        }
198
-
199
-        // figure out and scrub the sort
200
-        $sortOptions = $this->config()->get('sort_options');
201
-        $sort        = !empty($vars[$qs_sort]) ? $vars[$qs_sort] : '';
202
-        if (!isset($sortOptions[$sort])) {
203
-            $sort    = current(array_keys($sortOptions));
204
-        }
205
-
206
-        // figure out and scrub the filters
207
-        $filters  = !empty($vars[$qs_f]) ? FacetHelper::inst()->scrubFilters($vars[$qs_f]) : array();
208
-
209
-        // do the search
210
-        $keywords = !empty($vars[$qs_q]) ? $vars[$qs_q] : '';
211
-        if ($keywordRegex = $this->config()->get('keyword_filter_regex')) {
212
-            $keywords = preg_replace($keywordRegex, '', $keywords);
213
-        }
214
-        $results  = self::adapter()->searchFromVars($keywords, $filters, $facets, $start, $limit, $sort);
215
-
216
-        // massage the results a bit
217
-        if (!empty($keywords) && !$results->hasValue('Query')) {
218
-            $results->Query = $keywords;
219
-        }
220
-        if (!empty($filters) && !$results->hasValue('Filters')) {
221
-            $results->Filters = new ArrayData($filters);
222
-        }
223
-        if (!$results->hasValue('Sort')) {
224
-            $results->Sort = $sort;
225
-        }
226
-        if (!$results->hasValue('TotalMatches')) {
227
-            $results->TotalMatches = $results->Matches->hasMethod('getTotalItems')
228
-                ? $results->Matches->getTotalItems()
229
-                : $results->Matches->count();
230
-        }
231
-
232
-        // for some types of facets, update the state
233
-        if ($results->hasValue('Facets')) {
234
-            FacetHelper::inst()->transformHierarchies($results->Facets);
235
-            FacetHelper::inst()->updateFacetState($results->Facets, $filters);
236
-        }
237
-
238
-        // make a hash of the search so we can know if we've already logged it this session
239
-        $loggedFilters = !empty($filters) ? json_encode($filters) : null;
240
-        $loggedQuery   = strtolower($results->Query);
58
+	);
59
+
60
+	/**
61
+	 * @var array - default search facets (price, category, etc)
62
+	 *   Key    field name - e.g. Price - can be a VirtualFieldIndex field
63
+	 *   Value  facet label - e.g. Search By Category - if the value is a relation or returns an array or
64
+	 *          list all values will be faceted individually
65
+	 *          NOTE: this can also be another array with keys: Label, Type, and Values (for checkbox only)
66
+	 */
67
+	private static $facets = array();
68
+
69
+	/** @var array - field definition for Solr only */
70
+	private static $solr_fulltext_fields = array();
71
+
72
+	/** @var array - field definition for Solr only */
73
+	private static $solr_filter_fields = array();
74
+
75
+	/** @var string - if present, will create a copy of SiteTree_Title that's suited for alpha sorting */
76
+	private static $solr_title_sort_field = '';
77
+
78
+	/**
79
+	 * @var string - If present, everything matching the following regex will be removed from
80
+	 *               keyword search queries before passing to the search adapter.
81
+	 */
82
+	private static $keyword_filter_regex = '/[^a-zA-Z0-9\s\-]/';
83
+
84
+
85
+	/**
86
+	 * @return array
87
+	 */
88
+	public static function get_searchable_classes()
89
+	{
90
+		// First get any explicitly declared searchable classes
91
+		$searchable = Config::inst()->get('ShopSearch', 'searchable');
92
+		if (is_string($searchable) && strlen($searchable) > 0) {
93
+			$searchable = array($searchable);
94
+		} elseif (!is_array($searchable)) {
95
+			$searchable = array();
96
+		}
97
+
98
+		// Add in buyables automatically if asked
99
+		if (Config::inst()->get('ShopSearch', 'buyables_are_searchable')) {
100
+			$buyables = SS_ClassLoader::instance()->getManifest()->getImplementorsOf('Buyable');
101
+			if (is_array($buyables) && count($buyables) > 0) {
102
+				foreach ($buyables as $c) {
103
+					$searchable[] = $c;
104
+				}
105
+			}
106
+		}
107
+
108
+		return array_unique($searchable);
109
+	}
110
+
111
+	/**
112
+	 * Returns an array of categories suitable for a dropdown menu
113
+	 * TODO: cache this
114
+	 *
115
+	 * @param int $parentID [optional]
116
+	 * @param string $prefix [optional]
117
+	 * @param int $maxDepth [optional]
118
+	 * @return array
119
+	 * @static
120
+	 */
121
+	public static function get_category_hierarchy($parentID = 0, $prefix = '', $maxDepth = 999)
122
+	{
123
+		$out = array();
124
+		$cats = ProductCategory::get()
125
+			->filter(array(
126
+				'ParentID'      => $parentID,
127
+				'ShowInMenus'   => 1,
128
+			))
129
+			->sort('Sort');
130
+
131
+		// If there is a single parent category (usually "Products" or something), we
132
+		// probably don't want that in the hierarchy.
133
+		if ($parentID == 0 && $cats->count() == 1) {
134
+			return self::get_category_hierarchy($cats->first()->ID, $prefix, $maxDepth);
135
+		}
136
+
137
+		foreach ($cats as $cat) {
138
+			$out[$cat->ID] = $prefix . $cat->Title;
139
+			if ($maxDepth > 1) {
140
+				$out += self::get_category_hierarchy($cat->ID, $prefix . $cat->Title . ' > ', $maxDepth - 1);
141
+			}
142
+		}
143
+
144
+		return $out;
145
+	}
146
+
147
+	/**
148
+	 * @return ShopSearchAdapter
149
+	 */
150
+	public static function adapter()
151
+	{
152
+		$adapterClass = Config::inst()->get('ShopSearch', 'adapter_class');
153
+		return Injector::inst()->get($adapterClass);
154
+	}
155
+
156
+	/**
157
+	 * @return ShopSearch
158
+	 */
159
+	public static function inst()
160
+	{
161
+		return Injector::inst()->get('ShopSearch');
162
+	}
163
+
164
+	/**
165
+	 * The result will contain at least the following:
166
+	 *      Matches - SS_List of results
167
+	 *      TotalMatches - total # of results, unlimited
168
+	 *      Query - query string
169
+	 * Also saves a log record.
170
+	 *
171
+	 * @param array $vars
172
+	 * @param bool $logSearch [optional]
173
+	 * @param bool $useFacets [optional]
174
+	 * @param int $start [optional]
175
+	 * @param int $limit [optional]
176
+	 * @return ArrayData
177
+	 */
178
+	public function search(array $vars, $logSearch=true, $useFacets=true, $start=-1, $limit=-1)
179
+	{
180
+		$qs_q   = $this->config()->get('qs_query');
181
+		$qs_f   = $this->config()->get('qs_filters');
182
+		$qs_ps  = $this->config()->get('qs_parent_search');
183
+		$qs_t   = $this->config()->get('qs_title');
184
+		$qs_sort= $this->config()->get('qs_sort');
185
+		if ($limit < 0) {
186
+			$limit  = $this->config()->get('page_size');
187
+		}
188
+		if ($start < 0) {
189
+			$start  = !empty($vars['start']) ? (int)$vars['start'] : 0;
190
+		} // as far as i can see, fulltextsearch hard codes 'start'
191
+		$facets = $useFacets ? $this->config()->get('facets') : array();
192
+		if (!is_array($facets)) {
193
+			$facets = array();
194
+		}
195
+		if (empty($limit)) {
196
+			$limit = -1;
197
+		}
198
+
199
+		// figure out and scrub the sort
200
+		$sortOptions = $this->config()->get('sort_options');
201
+		$sort        = !empty($vars[$qs_sort]) ? $vars[$qs_sort] : '';
202
+		if (!isset($sortOptions[$sort])) {
203
+			$sort    = current(array_keys($sortOptions));
204
+		}
205
+
206
+		// figure out and scrub the filters
207
+		$filters  = !empty($vars[$qs_f]) ? FacetHelper::inst()->scrubFilters($vars[$qs_f]) : array();
208
+
209
+		// do the search
210
+		$keywords = !empty($vars[$qs_q]) ? $vars[$qs_q] : '';
211
+		if ($keywordRegex = $this->config()->get('keyword_filter_regex')) {
212
+			$keywords = preg_replace($keywordRegex, '', $keywords);
213
+		}
214
+		$results  = self::adapter()->searchFromVars($keywords, $filters, $facets, $start, $limit, $sort);
215
+
216
+		// massage the results a bit
217
+		if (!empty($keywords) && !$results->hasValue('Query')) {
218
+			$results->Query = $keywords;
219
+		}
220
+		if (!empty($filters) && !$results->hasValue('Filters')) {
221
+			$results->Filters = new ArrayData($filters);
222
+		}
223
+		if (!$results->hasValue('Sort')) {
224
+			$results->Sort = $sort;
225
+		}
226
+		if (!$results->hasValue('TotalMatches')) {
227
+			$results->TotalMatches = $results->Matches->hasMethod('getTotalItems')
228
+				? $results->Matches->getTotalItems()
229
+				: $results->Matches->count();
230
+		}
231
+
232
+		// for some types of facets, update the state
233
+		if ($results->hasValue('Facets')) {
234
+			FacetHelper::inst()->transformHierarchies($results->Facets);
235
+			FacetHelper::inst()->updateFacetState($results->Facets, $filters);
236
+		}
237
+
238
+		// make a hash of the search so we can know if we've already logged it this session
239
+		$loggedFilters = !empty($filters) ? json_encode($filters) : null;
240
+		$loggedQuery   = strtolower($results->Query);
241 241
 //		$searchHash    = md5($loggedFilters . $loggedQuery);
242 242
 //		$sessSearches  = Session::get('loggedSearches');
243 243
 //		if (!is_array($sessSearches)) $sessSearches = array();
244 244
 //		Debug::dump($searchHash, $sessSearches);
245 245
 
246
-        // save the log record
247
-        if ($start == 0 && $logSearch && (!empty($keywords) || !empty($filters))) { // && !in_array($searchHash, $sessSearches)) {
248
-            $log = SearchLog::create(array(
249
-                'Query'         => $loggedQuery,
250
-                'Title'         => !empty($vars[$qs_t]) ? $vars[$qs_t] : '',
251
-                'Link'          => Controller::curr()->getRequest()->getURL(true), // I'm not 100% happy with this, but can't think of a better way
252
-                'NumResults'    => $results->TotalMatches,
253
-                'MemberID'      => Member::currentUserID(),
254
-                'Filters'       => $loggedFilters,
255
-                'ParentSearchID'=> !empty($vars[$qs_ps]) ? $vars[$qs_ps] : 0,
256
-            ));
257
-            $log->write();
258
-            $results->SearchLogID = $log->ID;
259
-            $results->SearchBreadcrumbs = $log->getBreadcrumbs();
246
+		// save the log record
247
+		if ($start == 0 && $logSearch && (!empty($keywords) || !empty($filters))) { // && !in_array($searchHash, $sessSearches)) {
248
+			$log = SearchLog::create(array(
249
+				'Query'         => $loggedQuery,
250
+				'Title'         => !empty($vars[$qs_t]) ? $vars[$qs_t] : '',
251
+				'Link'          => Controller::curr()->getRequest()->getURL(true), // I'm not 100% happy with this, but can't think of a better way
252
+				'NumResults'    => $results->TotalMatches,
253
+				'MemberID'      => Member::currentUserID(),
254
+				'Filters'       => $loggedFilters,
255
+				'ParentSearchID'=> !empty($vars[$qs_ps]) ? $vars[$qs_ps] : 0,
256
+			));
257
+			$log->write();
258
+			$results->SearchLogID = $log->ID;
259
+			$results->SearchBreadcrumbs = $log->getBreadcrumbs();
260 260
 
261 261
 //			$sessSearches[] = $searchHash;
262 262
 //			Session::set('loggedSearches', $sessSearches);
263
-        }
264
-
265
-        return $results;
266
-    }
267
-
268
-    /**
269
-     * @param string $str
270
-     * @return SS_Query
271
-     */
272
-    public function getSuggestQuery($str='')
273
-    {
274
-        $hasResults = 'CASE WHEN max("SearchLog"."NumResults") > 0 THEN 1 ELSE 0 END';
275
-        $searchCount = 'count(distinct "SearchLog"."ID")';
276
-        $q = new SQLQuery();
277
-        $q = $q->setSelect('"SearchLog"."Query"')
278
-            // TODO: what to do with filter?
279
-            ->selectField($searchCount, 'SearchCount')
280
-            ->selectField('max("SearchLog"."Created")', 'LastSearch')
281
-            ->selectField('max("SearchLog"."NumResults")', 'NumResults')
282
-            ->selectField($hasResults, 'HasResults')
283
-            ->setFrom('"SearchLog"')
284
-            ->setGroupBy('"SearchLog"."Query"')
285
-            ->setOrderBy(array(
286
-                "$hasResults DESC",
287
-                "$searchCount DESC"
288
-            ))
289
-            ->setLimit(Config::inst()->get('ShopSearch', 'suggest_limit'))
290
-        ;
291
-
292
-        if (strlen($str) > 0) {
293
-            $q = $q->addWhere(sprintf('"SearchLog"."Query" LIKE \'%%%s%%\'', Convert::raw2sql($str)));
294
-        }
295
-
296
-        return $q;
297
-    }
298
-
299
-
300
-    /**
301
-     * @param string $str
302
-     * @return array
303
-     */
304
-    public function suggest($str='')
305
-    {
306
-        $adapter = self::adapter();
307
-        if ($adapter->hasMethod('suggest')) {
308
-            return $adapter->suggest($str);
309
-        } else {
310
-            return $this->getSuggestQuery($str)->execute()->column('Query');
311
-        }
312
-    }
313
-
314
-
315
-    /**
316
-     * Returns an array that can be made into json and passed to the controller
317
-     * containing both term suggestions and a few product matches.
318
-     *
319
-     * @param array $searchVars
320
-     * @return array
321
-     */
322
-    public function suggestWithResults(array $searchVars)
323
-    {
324
-        $qs_q       = $this->config()->get('qs_query');
325
-        $qs_f       = $this->config()->get('qs_filters');
326
-        $keywords   = !empty($searchVars[$qs_q]) ? $searchVars[$qs_q] : '';
327
-        $filters    = !empty($searchVars[$qs_f]) ? $searchVars[$qs_f] : array();
328
-
329
-        $adapter = self::adapter();
330
-
331
-        // get suggestions and product list from the adapter
332
-        if ($adapter->hasMethod('suggestWithResults')) {
333
-            $results = $adapter->suggestWithResults($keywords, $filters);
334
-        } else {
335
-            $limit      = (int)ShopSearch::config()->sayt_limit;
336
-            $search     = self::adapter()->searchFromVars($keywords, $filters, array(), 0, $limit, 'Popularity DESC');
337
-            //$search     = ShopSearch::inst()->search($searchVars, false, false, 0, $limit);
338
-
339
-            $results = array(
340
-                'products'      => $search->Matches,
341
-                'suggestions'   => $this->suggest($keywords),
342
-            );
343
-        }
344
-
345
-        // the adapter just gave us a list of products, which we need to process a little further
346
-        if (!empty($results['products'])) {
347
-            // this gets encoded into the product links
348
-            $searchVars['total'] = $results['products']->hasMethod('getTotalItems')
349
-                ? $results['products']->getTotalItems()
350
-                : $results['products']->count();
351
-
352
-            $products   = array();
353
-            foreach ($results['products'] as $prod) {
354
-                if (!$prod || !$prod->exists()) {
355
-                    continue;
356
-                }
357
-                $img = $prod->hasMethod('ProductImage') ? $prod->ProductImage() : $prod->Image();
358
-                $thumb = ($img && $img->exists()) ? $img->getThumbnail() : null;
359
-
360
-                $json = array(
361
-                    'link'  => $prod->Link() . '?' . ShopSearch::config()->qs_source . '=' . urlencode(base64_encode(json_encode($searchVars))),
362
-                    'title' => $prod->Title,
363
-                    'desc'  => $prod->obj('Content')->Summary(),
364
-                    'thumb' => $thumb ? $thumb->Link() : '',
365
-                    'price' => $prod->obj('Price')->Nice(),
366
-                );
367
-
368
-                if ($prod->hasExtension('HasPromotionalPricing') && $prod->hasValidPromotion()) {
369
-                    $json['original_price'] = $prod->getOriginalPrice()->Nice();
370
-                }
371
-
372
-                $products[] = $json;
373
-            }
374
-
375
-            // replace the list of product objects with json
376
-            $results['products'] = $products;
377
-        }
378
-
379
-        $this->extend('updateSuggestWithResults', $results, $keywords, $filters);
380
-
381
-        return $results;
382
-    }
263
+		}
264
+
265
+		return $results;
266
+	}
267
+
268
+	/**
269
+	 * @param string $str
270
+	 * @return SS_Query
271
+	 */
272
+	public function getSuggestQuery($str='')
273
+	{
274
+		$hasResults = 'CASE WHEN max("SearchLog"."NumResults") > 0 THEN 1 ELSE 0 END';
275
+		$searchCount = 'count(distinct "SearchLog"."ID")';
276
+		$q = new SQLQuery();
277
+		$q = $q->setSelect('"SearchLog"."Query"')
278
+			// TODO: what to do with filter?
279
+			->selectField($searchCount, 'SearchCount')
280
+			->selectField('max("SearchLog"."Created")', 'LastSearch')
281
+			->selectField('max("SearchLog"."NumResults")', 'NumResults')
282
+			->selectField($hasResults, 'HasResults')
283
+			->setFrom('"SearchLog"')
284
+			->setGroupBy('"SearchLog"."Query"')
285
+			->setOrderBy(array(
286
+				"$hasResults DESC",
287
+				"$searchCount DESC"
288
+			))
289
+			->setLimit(Config::inst()->get('ShopSearch', 'suggest_limit'))
290
+		;
291
+
292
+		if (strlen($str) > 0) {
293
+			$q = $q->addWhere(sprintf('"SearchLog"."Query" LIKE \'%%%s%%\'', Convert::raw2sql($str)));
294
+		}
295
+
296
+		return $q;
297
+	}
298
+
299
+
300
+	/**
301
+	 * @param string $str
302
+	 * @return array
303
+	 */
304
+	public function suggest($str='')
305
+	{
306
+		$adapter = self::adapter();
307
+		if ($adapter->hasMethod('suggest')) {
308
+			return $adapter->suggest($str);
309
+		} else {
310
+			return $this->getSuggestQuery($str)->execute()->column('Query');
311
+		}
312
+	}
313
+
314
+
315
+	/**
316
+	 * Returns an array that can be made into json and passed to the controller
317
+	 * containing both term suggestions and a few product matches.
318
+	 *
319
+	 * @param array $searchVars
320
+	 * @return array
321
+	 */
322
+	public function suggestWithResults(array $searchVars)
323
+	{
324
+		$qs_q       = $this->config()->get('qs_query');
325
+		$qs_f       = $this->config()->get('qs_filters');
326
+		$keywords   = !empty($searchVars[$qs_q]) ? $searchVars[$qs_q] : '';
327
+		$filters    = !empty($searchVars[$qs_f]) ? $searchVars[$qs_f] : array();
328
+
329
+		$adapter = self::adapter();
330
+
331
+		// get suggestions and product list from the adapter
332
+		if ($adapter->hasMethod('suggestWithResults')) {
333
+			$results = $adapter->suggestWithResults($keywords, $filters);
334
+		} else {
335
+			$limit      = (int)ShopSearch::config()->sayt_limit;
336
+			$search     = self::adapter()->searchFromVars($keywords, $filters, array(), 0, $limit, 'Popularity DESC');
337
+			//$search     = ShopSearch::inst()->search($searchVars, false, false, 0, $limit);
338
+
339
+			$results = array(
340
+				'products'      => $search->Matches,
341
+				'suggestions'   => $this->suggest($keywords),
342
+			);
343
+		}
344
+
345
+		// the adapter just gave us a list of products, which we need to process a little further
346
+		if (!empty($results['products'])) {
347
+			// this gets encoded into the product links
348
+			$searchVars['total'] = $results['products']->hasMethod('getTotalItems')
349
+				? $results['products']->getTotalItems()
350
+				: $results['products']->count();
351
+
352
+			$products   = array();
353
+			foreach ($results['products'] as $prod) {
354
+				if (!$prod || !$prod->exists()) {
355
+					continue;
356
+				}
357
+				$img = $prod->hasMethod('ProductImage') ? $prod->ProductImage() : $prod->Image();
358
+				$thumb = ($img && $img->exists()) ? $img->getThumbnail() : null;
359
+
360
+				$json = array(
361
+					'link'  => $prod->Link() . '?' . ShopSearch::config()->qs_source . '=' . urlencode(base64_encode(json_encode($searchVars))),
362
+					'title' => $prod->Title,
363
+					'desc'  => $prod->obj('Content')->Summary(),
364
+					'thumb' => $thumb ? $thumb->Link() : '',
365
+					'price' => $prod->obj('Price')->Nice(),
366
+				);
367
+
368
+				if ($prod->hasExtension('HasPromotionalPricing') && $prod->hasValidPromotion()) {
369
+					$json['original_price'] = $prod->getOriginalPrice()->Nice();
370
+				}
371
+
372
+				$products[] = $json;
373
+			}
374
+
375
+			// replace the list of product objects with json
376
+			$results['products'] = $products;
377
+		}
378
+
379
+		$this->extend('updateSuggestWithResults', $results, $keywords, $filters);
380
+
381
+		return $results;
382
+	}
383 383
 }
Please login to merge, or discard this patch.
code/ShopSearchAdapter.php 1 patch
Indentation   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -1,21 +1,21 @@
 block discarded – undo
1 1
 <?php
2 2
 /**
3
- * Interface for shop search drivers.
4
- *
5
- * @author Mark Guinn <[email protected]>
6
- * @date 09.03.2013
7
- * @package shop_search
8
- */
3
+	 * Interface for shop search drivers.
4
+	 *
5
+	 * @author Mark Guinn <[email protected]>
6
+	 * @date 09.03.2013
7
+	 * @package shop_search
8
+	 */
9 9
 interface ShopSearchAdapter
10 10
 {
11
-    /**
12
-     * @param string $keywords
13
-     * @param array $filters [optional]
14
-     * @param array $facetSpec [optional]
15
-     * @param int $start [optional]
16
-     * @param int $limit [optional]
17
-     * @param string $sort [optional]
18
-     * @return ArrayData - must contain at least 'Matches' with an list of data objects that match the search
19
-     */
20
-    public function searchFromVars($keywords, array $filters=array(), array $facetSpec=array(), $start=-1, $limit=-1, $sort='');
11
+	/**
12
+	 * @param string $keywords
13
+	 * @param array $filters [optional]
14
+	 * @param array $facetSpec [optional]
15
+	 * @param int $start [optional]
16
+	 * @param int $limit [optional]
17
+	 * @param string $sort [optional]
18
+	 * @return ArrayData - must contain at least 'Matches' with an list of data objects that match the search
19
+	 */
20
+	public function searchFromVars($keywords, array $filters=array(), array $facetSpec=array(), $start=-1, $limit=-1, $sort='');
21 21
 }
Please login to merge, or discard this patch.
code/ShopSearchAjax.php 1 patch
Indentation   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -1,30 +1,30 @@
 block discarded – undo
1 1
 <?php
2 2
 /**
3
- * Pending some changes introduced to the core shop module, this will supply
4
- * some standard, easily overridable ajax features.
5
- *
6
- * @author Mark Guinn <[email protected]>
7
- * @date 07.21.2014
8
- * @package shop_search
9
- */
3
+	 * Pending some changes introduced to the core shop module, this will supply
4
+	 * some standard, easily overridable ajax features.
5
+	 *
6
+	 * @author Mark Guinn <[email protected]>
7
+	 * @date 07.21.2014
8
+	 * @package shop_search
9
+	 */
10 10
 class ShopSearchAjax extends Extension
11 11
 {
12
-    /**
13
-     * @param SS_HTTPRequest $request
14
-     * @param SS_HTTPResponse $response
15
-     * @param ArrayData $results
16
-     * @param array $data
17
-     */
18
-    public function updateSearchResultsResponse(&$request, &$response, $results, $data)
19
-    {
20
-        if ($request->isAjax() && $this->owner->hasExtension('AjaxControllerExtension')) {
21
-            if (!$response) {
22
-                $response = $this->owner->getAjaxResponse();
23
-            }
24
-            $response->addRenderContext('RESULTS', $results);
25
-            $response->pushRegion('SearchResults', $results);
26
-            $response->pushRegion('SearchHeader', $results);
27
-            $response->triggerEvent('searchresults');
28
-        }
29
-    }
12
+	/**
13
+	 * @param SS_HTTPRequest $request
14
+	 * @param SS_HTTPResponse $response
15
+	 * @param ArrayData $results
16
+	 * @param array $data
17
+	 */
18
+	public function updateSearchResultsResponse(&$request, &$response, $results, $data)
19
+	{
20
+		if ($request->isAjax() && $this->owner->hasExtension('AjaxControllerExtension')) {
21
+			if (!$response) {
22
+				$response = $this->owner->getAjaxResponse();
23
+			}
24
+			$response->addRenderContext('RESULTS', $results);
25
+			$response->pushRegion('SearchResults', $results);
26
+			$response->pushRegion('SearchHeader', $results);
27
+			$response->triggerEvent('searchresults');
28
+		}
29
+	}
30 30
 }
Please login to merge, or discard this patch.
code/ShopSearchControllerExtension.php 1 patch
Indentation   +76 added lines, -76 removed lines patch added patch discarded remove patch
@@ -1,92 +1,92 @@
 block discarded – undo
1 1
 <?php
2 2
 /**
3
- * Adds SearchForm and results methods to the controller.
4
- *
5
- * @author Mark Guinn <[email protected]>
6
- * @date 08.29.2013
7
- * @package shop_search
8
- */
3
+	 * Adds SearchForm and results methods to the controller.
4
+	 *
5
+	 * @author Mark Guinn <[email protected]>
6
+	 * @date 08.29.2013
7
+	 * @package shop_search
8
+	 */
9 9
 class ShopSearchControllerExtension extends Extension
10 10
 {
11
-    private static $allowed_actions = array('SearchForm', 'results', 'search_suggest');
11
+	private static $allowed_actions = array('SearchForm', 'results', 'search_suggest');
12 12
 
13
-    /**
14
-     * @return ShopSearchForm
15
-     */
16
-    public function SearchForm()
17
-    {
18
-        return ShopSearchForm::create($this->owner, 'SearchForm', $this->owner->Link() . 'search-suggest');
19
-    }
13
+	/**
14
+	 * @return ShopSearchForm
15
+	 */
16
+	public function SearchForm()
17
+	{
18
+		return ShopSearchForm::create($this->owner, 'SearchForm', $this->owner->Link() . 'search-suggest');
19
+	}
20 20
 
21 21
 
22
-    /**
23
-     * @param SS_HTTPRequest $req
24
-     * @return string
25
-     */
26
-    public function search_suggest(SS_HTTPRequest $req)
27
-    {
28
-        /** @var SS_HTTPResponse $response */
29
-        $response    = $this->owner->getResponse();
30
-        $callback    = $req->requestVar('callback');
22
+	/**
23
+	 * @param SS_HTTPRequest $req
24
+	 * @return string
25
+	 */
26
+	public function search_suggest(SS_HTTPRequest $req)
27
+	{
28
+		/** @var SS_HTTPResponse $response */
29
+		$response    = $this->owner->getResponse();
30
+		$callback    = $req->requestVar('callback');
31 31
 
32
-        // convert the search results into usable json for search-as-you-type
33
-        if (ShopSearch::config()->search_as_you_type_enabled) {
34
-            $searchVars = $req->requestVars();
35
-            $searchVars[ ShopSearch::config()->qs_query ] = $searchVars['term'];
36
-            unset($searchVars['term']);
37
-            $results = ShopSearch::inst()->suggestWithResults($searchVars);
38
-        } else {
39
-            $results = array(
40
-                'suggestions'   => ShopSearch::inst()->suggest($req->requestVar('term')),
41
-            );
42
-        }
32
+		// convert the search results into usable json for search-as-you-type
33
+		if (ShopSearch::config()->search_as_you_type_enabled) {
34
+			$searchVars = $req->requestVars();
35
+			$searchVars[ ShopSearch::config()->qs_query ] = $searchVars['term'];
36
+			unset($searchVars['term']);
37
+			$results = ShopSearch::inst()->suggestWithResults($searchVars);
38
+		} else {
39
+			$results = array(
40
+				'suggestions'   => ShopSearch::inst()->suggest($req->requestVar('term')),
41
+			);
42
+		}
43 43
 
44
-        if ($callback) {
45
-            $response->addHeader('Content-type', 'application/javascript');
46
-            $response->setBody($callback . '(' . json_encode($results) . ');');
47
-        } else {
48
-            $response->addHeader('Content-type', 'application/json');
49
-            $response->setBody(json_encode($results));
50
-        }
51
-        return $response;
52
-    }
44
+		if ($callback) {
45
+			$response->addHeader('Content-type', 'application/javascript');
46
+			$response->setBody($callback . '(' . json_encode($results) . ');');
47
+		} else {
48
+			$response->addHeader('Content-type', 'application/json');
49
+			$response->setBody(json_encode($results));
50
+		}
51
+		return $response;
52
+	}
53 53
 
54 54
 
55
-    /**
56
-     * If there is a search encoded in the link, go ahead and log it.
57
-     * This happens when you click through on a search suggestion
58
-     */
59
-    public function onAfterInit()
60
-    {
61
-        $req = $this->owner->getRequest();
62
-        $src = $req->requestVar(Config::inst()->get('ShopSearch', 'qs_source'));
63
-        if ($src) {
64
-            $qs_q   = Config::inst()->get('ShopSearch', 'qs_query');
65
-            $qs_f   = Config::inst()->get('ShopSearch', 'qs_filters');
66
-            $vars   = json_decode(base64_decode($src), true);
55
+	/**
56
+	 * If there is a search encoded in the link, go ahead and log it.
57
+	 * This happens when you click through on a search suggestion
58
+	 */
59
+	public function onAfterInit()
60
+	{
61
+		$req = $this->owner->getRequest();
62
+		$src = $req->requestVar(Config::inst()->get('ShopSearch', 'qs_source'));
63
+		if ($src) {
64
+			$qs_q   = Config::inst()->get('ShopSearch', 'qs_query');
65
+			$qs_f   = Config::inst()->get('ShopSearch', 'qs_filters');
66
+			$vars   = json_decode(base64_decode($src), true);
67 67
 
68
-            // log the search
69
-            $log = SearchLog::create(array(
70
-                'Query'         => strtolower($vars[$qs_q]),
71
-                'Link'          => $req->getURL(false), // These searches will never have child searches, but this will allow us to know what they clicked
72
-                'NumResults'    => $vars['total'],
73
-                'MemberID'      => Member::currentUserID(),
74
-                'Filters'       => !empty($vars[$qs_f]) ? json_encode($vars[$qs_f]) : null,
75
-            ));
76
-            $log->write();
68
+			// log the search
69
+			$log = SearchLog::create(array(
70
+				'Query'         => strtolower($vars[$qs_q]),
71
+				'Link'          => $req->getURL(false), // These searches will never have child searches, but this will allow us to know what they clicked
72
+				'NumResults'    => $vars['total'],
73
+				'MemberID'      => Member::currentUserID(),
74
+				'Filters'       => !empty($vars[$qs_f]) ? json_encode($vars[$qs_f]) : null,
75
+			));
76
+			$log->write();
77 77
 
78
-            // redirect to the clean page
79
-            $this->owner->redirect($req->getURL(false));
80
-        }
81
-    }
78
+			// redirect to the clean page
79
+			$this->owner->redirect($req->getURL(false));
80
+		}
81
+	}
82 82
 
83 83
 
84
-    /**
85
-     * @param ArrayData $results
86
-     * @param array     $data
87
-     * @return string
88
-     */
89
-    protected function generateLongTitle(ArrayData $results, array $data)
90
-    {
91
-    }
84
+	/**
85
+	 * @param ArrayData $results
86
+	 * @param array     $data
87
+	 * @return string
88
+	 */
89
+	protected function generateLongTitle(ArrayData $results, array $data)
90
+	{
91
+	}
92 92
 }
Please login to merge, or discard this patch.
code/ShopSearchForm.php 1 patch
Indentation   +147 added lines, -147 removed lines patch added patch discarded remove patch
@@ -1,152 +1,152 @@
 block discarded – undo
1 1
 <?php
2 2
 /**
3
- * Form object for shop search.
4
- *
5
- * @author Mark Guinn <[email protected]>
6
- * @date 09.23.2013
7
- * @package shop_search
8
- */
3
+	 * Form object for shop search.
4
+	 *
5
+	 * @author Mark Guinn <[email protected]>
6
+	 * @date 09.23.2013
7
+	 * @package shop_search
8
+	 */
9 9
 class ShopSearchForm extends Form
10 10
 {
11
-    /** @var bool - setting this to true will remove the category dropdwon from the form */
12
-    private static $disable_category_dropdown = false;
13
-
14
-    /** @var string - this probably ought to be overridden with a vfi or solr facet unless you're products are only in one category */
15
-    private static $category_field = 'f[ParentID]';
16
-
17
-    /** @var string - setting to 'NONE' will mean the category dropdwon will have no empty option */
18
-    private static $category_empty_string = 'All Products';
19
-
20
-    /** @var int - how deep to list the categories for the dropdown */
21
-    private static $category_max_depth = 10;
22
-
23
-
24
-    /**
25
-     * @param Controller $controller
26
-     * @param String     $method
27
-     * @param string     $suggestURL
28
-     */
29
-    public function __construct($controller, $method, $suggestURL = '')
30
-    {
31
-        $searchField = TextField::create('q', '');
32
-        $searchField->setAttribute('placeholder', _t('ShopSearch.SEARCH', 'Search'));
33
-        if ($suggestURL) {
34
-            $searchField->setAttribute('data-suggest-url', $suggestURL);
35
-        }
36
-
37
-        $fields = FieldList::create($searchField);
38
-        if (!self::config()->disable_category_dropdown) {
39
-            $cats     = ShopSearch::get_category_hierarchy(0, '', self::config()->category_max_depth);
40
-            $catField = DropdownField::create(self::get_category_field(), '', $cats, Session::get('LastSearchCatID'));
41
-
42
-            $emptyString = self::config()->category_empty_string;
43
-            if ($emptyString !== 'NONE') {
44
-                $catField->setEmptyString(_t('ShopSearch.'.$emptyString, $emptyString));
45
-            }
46
-
47
-            $fields->push($catField);
48
-        }
49
-
50
-        parent::__construct($controller, $method, $fields, FieldList::create(array(FormAction::create('results', _t('ShopSearch.GO', 'Go')))));
51
-
52
-        $this->setFormMethod('GET');
53
-        $this->disableSecurityToken();
54
-        if ($c = self::config()->css_classes) {
55
-            $this->addExtraClass($c);
56
-        }
57
-
58
-        Requirements::css(SHOP_SEARCH_FOLDER . '/css/ShopSearch.css');
59
-
60
-        if (Config::inst()->get('ShopSearch', 'suggest_enabled')) {
61
-            Requirements::javascript(THIRDPARTY_DIR . '/jquery-ui/jquery-ui.js');
62
-            Requirements::css(THIRDPARTY_DIR . '/jquery-ui-themes/smoothness/jquery-ui.css');
63
-            Requirements::javascript(SHOP_SEARCH_FOLDER . '/javascript/search.suggest.js');
64
-            Requirements::javascript(SHOP_SEARCH_FOLDER . '/javascript/search.js');
65
-        }
66
-    }
67
-
68
-
69
-    /**
70
-     * @return string
71
-     */
72
-    public static function get_category_field()
73
-    {
74
-        return Config::inst()->get('ShopSearchForm', 'category_field');
75
-    }
76
-
77
-
78
-    /**
79
-     * @param array $data
80
-     * @return mixed
81
-     */
82
-    public function results(array $data)
83
-    {
84
-        // do the search
85
-        $results  = ShopSearch::inst()->search($data);
86
-        $request  = $this->controller->getRequest();
87
-        $baseLink = $request->getURL(false);
88
-
89
-        // if there was only one category filter, remember it for the category dropdown to retain it's value
90
-        if (!ShopSearchForm::config()->disable_category_dropdown) {
91
-            $qs_filters  = (string)Config::inst()->get('ShopSearch', 'qs_filters');
92
-            $categoryKey = (string)ShopSearchForm::config()->category_field;
93
-
94
-            if (preg_match('/\[(.+)\]/', $categoryKey, $matches)) {
95
-                // get right of the f[] around the actual key if present
96
-                $categoryKey = $matches[1];
97
-            }
98
-
99
-            if (!empty($data[$qs_filters][$categoryKey])) {
100
-                $categoryID = $data[$qs_filters][$categoryKey];
101
-                if (is_numeric($categoryID)) {
102
-                    // If it's set in the dropdown it will just be a number
103
-                    // If it's set from the checkboxes it will be something like LIST~1,2,3,4
104
-                    // We only want to remember the value in the former case
105
-                    Session::set('LastSearchCatID', $categoryID);
106
-                }
107
-            } else {
108
-                // If they unchecked every value, then clear the dropdown as well
109
-                Session::clear('LastSearchCatID');
110
-            }
111
-        }
112
-
113
-        // add links for any facets
114
-        if ($results->Facets && $results->Facets->count()) {
115
-            $qs_ps      = (string)Config::inst()->get('ShopSearch', 'qs_parent_search');
116
-            $baseParams = array_merge($data, array($qs_ps => $results->SearchLogID));
117
-            unset($baseParams['url']);
118
-            $results->Facets = FacetHelper::inst()->insertFacetLinks($results->Facets, $baseParams, $baseLink);
119
-        }
120
-
121
-        // add a dropdown for sorting
122
-        $qs_sort    = (string)Config::inst()->get('ShopSearch', 'qs_sort');
123
-        $options    = Config::inst()->get('ShopSearch', 'sort_options');
124
-        $sortParams = array_merge($data, array($qs_sort => 'NEWSORTVALUE'));
125
-        unset($sortParams['url']);
126
-        $results->SortControl = DropdownField::create($qs_sort, ShopSearch::config()->sort_label, $options, $results->Sort)
127
-            ->setAttribute('data-url', $baseLink . '?' . http_build_query($sortParams));
128
-
129
-        // a little more output management
130
-        $results->Title = "Search Results";
131
-        $results->Results = $results->Matches; // this makes us compatible with the default search template
132
-
133
-        // Give a hook for the parent controller to format the results, for example,
134
-        // interpreting filters in a specific way to affect the title or content
135
-        // when no results are returned. Since this is domain-specific we just leave
136
-        // it up to the host app.
137
-        if ($this->controller->hasMethod('onBeforeSearchDisplay')) {
138
-            $this->controller->onBeforeSearchDisplay($results);
139
-        }
140
-
141
-        // give a hook for processing ajax requests through a different template (i.e. for returning only fragments)
142
-        $tpl = Config::inst()->get('ShopSearch', 'ajax_results_template');
143
-        if (!empty($tpl) && Director::is_ajax()) {
144
-            return $this->controller->customise($results)->renderWith($tpl);
145
-        }
146
-
147
-        // Give a hook for modifying the search responses
148
-        $this->controller->extend('updateSearchResultsResponse', $request, $response, $results, $data);
149
-
150
-        return $response ?: $this->controller->customise($results)->renderWith(array('ShopSearch_results', 'Page_results', 'Page'));
151
-    }
11
+	/** @var bool - setting this to true will remove the category dropdwon from the form */
12
+	private static $disable_category_dropdown = false;
13
+
14
+	/** @var string - this probably ought to be overridden with a vfi or solr facet unless you're products are only in one category */
15
+	private static $category_field = 'f[ParentID]';
16
+
17
+	/** @var string - setting to 'NONE' will mean the category dropdwon will have no empty option */
18
+	private static $category_empty_string = 'All Products';
19
+
20
+	/** @var int - how deep to list the categories for the dropdown */
21
+	private static $category_max_depth = 10;
22
+
23
+
24
+	/**
25
+	 * @param Controller $controller
26
+	 * @param String     $method
27
+	 * @param string     $suggestURL
28
+	 */
29
+	public function __construct($controller, $method, $suggestURL = '')
30
+	{
31
+		$searchField = TextField::create('q', '');
32
+		$searchField->setAttribute('placeholder', _t('ShopSearch.SEARCH', 'Search'));
33
+		if ($suggestURL) {
34
+			$searchField->setAttribute('data-suggest-url', $suggestURL);
35
+		}
36
+
37
+		$fields = FieldList::create($searchField);
38
+		if (!self::config()->disable_category_dropdown) {
39
+			$cats     = ShopSearch::get_category_hierarchy(0, '', self::config()->category_max_depth);
40
+			$catField = DropdownField::create(self::get_category_field(), '', $cats, Session::get('LastSearchCatID'));
41
+
42
+			$emptyString = self::config()->category_empty_string;
43
+			if ($emptyString !== 'NONE') {
44
+				$catField->setEmptyString(_t('ShopSearch.'.$emptyString, $emptyString));
45
+			}
46
+
47
+			$fields->push($catField);
48
+		}
49
+
50
+		parent::__construct($controller, $method, $fields, FieldList::create(array(FormAction::create('results', _t('ShopSearch.GO', 'Go')))));
51
+
52
+		$this->setFormMethod('GET');
53
+		$this->disableSecurityToken();
54
+		if ($c = self::config()->css_classes) {
55
+			$this->addExtraClass($c);
56
+		}
57
+
58
+		Requirements::css(SHOP_SEARCH_FOLDER . '/css/ShopSearch.css');
59
+
60
+		if (Config::inst()->get('ShopSearch', 'suggest_enabled')) {
61
+			Requirements::javascript(THIRDPARTY_DIR . '/jquery-ui/jquery-ui.js');
62
+			Requirements::css(THIRDPARTY_DIR . '/jquery-ui-themes/smoothness/jquery-ui.css');
63
+			Requirements::javascript(SHOP_SEARCH_FOLDER . '/javascript/search.suggest.js');
64
+			Requirements::javascript(SHOP_SEARCH_FOLDER . '/javascript/search.js');
65
+		}
66
+	}
67
+
68
+
69
+	/**
70
+	 * @return string
71
+	 */
72
+	public static function get_category_field()
73
+	{
74
+		return Config::inst()->get('ShopSearchForm', 'category_field');
75
+	}
76
+
77
+
78
+	/**
79
+	 * @param array $data
80
+	 * @return mixed
81
+	 */
82
+	public function results(array $data)
83
+	{
84
+		// do the search
85
+		$results  = ShopSearch::inst()->search($data);
86
+		$request  = $this->controller->getRequest();
87
+		$baseLink = $request->getURL(false);
88
+
89
+		// if there was only one category filter, remember it for the category dropdown to retain it's value
90
+		if (!ShopSearchForm::config()->disable_category_dropdown) {
91
+			$qs_filters  = (string)Config::inst()->get('ShopSearch', 'qs_filters');
92
+			$categoryKey = (string)ShopSearchForm::config()->category_field;
93
+
94
+			if (preg_match('/\[(.+)\]/', $categoryKey, $matches)) {
95
+				// get right of the f[] around the actual key if present
96
+				$categoryKey = $matches[1];
97
+			}
98
+
99
+			if (!empty($data[$qs_filters][$categoryKey])) {
100
+				$categoryID = $data[$qs_filters][$categoryKey];
101
+				if (is_numeric($categoryID)) {
102
+					// If it's set in the dropdown it will just be a number
103
+					// If it's set from the checkboxes it will be something like LIST~1,2,3,4
104
+					// We only want to remember the value in the former case
105
+					Session::set('LastSearchCatID', $categoryID);
106
+				}
107
+			} else {
108
+				// If they unchecked every value, then clear the dropdown as well
109
+				Session::clear('LastSearchCatID');
110
+			}
111
+		}
112
+
113
+		// add links for any facets
114
+		if ($results->Facets && $results->Facets->count()) {
115
+			$qs_ps      = (string)Config::inst()->get('ShopSearch', 'qs_parent_search');
116
+			$baseParams = array_merge($data, array($qs_ps => $results->SearchLogID));
117
+			unset($baseParams['url']);
118
+			$results->Facets = FacetHelper::inst()->insertFacetLinks($results->Facets, $baseParams, $baseLink);
119
+		}
120
+
121
+		// add a dropdown for sorting
122
+		$qs_sort    = (string)Config::inst()->get('ShopSearch', 'qs_sort');
123
+		$options    = Config::inst()->get('ShopSearch', 'sort_options');
124
+		$sortParams = array_merge($data, array($qs_sort => 'NEWSORTVALUE'));
125
+		unset($sortParams['url']);
126
+		$results->SortControl = DropdownField::create($qs_sort, ShopSearch::config()->sort_label, $options, $results->Sort)
127
+			->setAttribute('data-url', $baseLink . '?' . http_build_query($sortParams));
128
+
129
+		// a little more output management
130
+		$results->Title = "Search Results";
131
+		$results->Results = $results->Matches; // this makes us compatible with the default search template
132
+
133
+		// Give a hook for the parent controller to format the results, for example,
134
+		// interpreting filters in a specific way to affect the title or content
135
+		// when no results are returned. Since this is domain-specific we just leave
136
+		// it up to the host app.
137
+		if ($this->controller->hasMethod('onBeforeSearchDisplay')) {
138
+			$this->controller->onBeforeSearchDisplay($results);
139
+		}
140
+
141
+		// give a hook for processing ajax requests through a different template (i.e. for returning only fragments)
142
+		$tpl = Config::inst()->get('ShopSearch', 'ajax_results_template');
143
+		if (!empty($tpl) && Director::is_ajax()) {
144
+			return $this->controller->customise($results)->renderWith($tpl);
145
+		}
146
+
147
+		// Give a hook for modifying the search responses
148
+		$this->controller->extend('updateSearchResultsResponse', $request, $response, $results, $data);
149
+
150
+		return $response ?: $this->controller->customise($results)->renderWith(array('ShopSearch_results', 'Page_results', 'Page'));
151
+	}
152 152
 }
Please login to merge, or discard this patch.
code/adapters/ShopSearchMysql.php 1 patch
Indentation   +72 added lines, -72 removed lines patch added patch discarded remove patch
@@ -1,89 +1,89 @@
 block discarded – undo
1 1
 <?php
2 2
 /**
3
- * Adapter that will use MySQL's full text search features.
4
- *
5
- * @author Mark Guinn <[email protected]>
6
- * @date 11.13.2013
7
- * @package shop_search
8
- * @subpackage adapters
9
- */
3
+	 * Adapter that will use MySQL's full text search features.
4
+	 *
5
+	 * @author Mark Guinn <[email protected]>
6
+	 * @date 11.13.2013
7
+	 * @package shop_search
8
+	 * @subpackage adapters
9
+	 */
10 10
 class ShopSearchMysql extends Object implements ShopSearchAdapter
11 11
 {
12
-    /**
13
-     * @param string $keywords
14
-     * @param array $filters [optional]
15
-     * @param array $facetSpec [optional]
16
-     * @param int $start [optional]
17
-     * @param int $limit [optional]
18
-     * @param string $sort [optional]
19
-     * @return ArrayData
20
-     */
21
-    public function searchFromVars($keywords, array $filters=array(), array $facetSpec=array(), $start=-1, $limit=-1, $sort='')
22
-    {
23
-        $searchable = ShopSearch::get_searchable_classes();
24
-        $matches = new ArrayList;
12
+	/**
13
+	 * @param string $keywords
14
+	 * @param array $filters [optional]
15
+	 * @param array $facetSpec [optional]
16
+	 * @param int $start [optional]
17
+	 * @param int $limit [optional]
18
+	 * @param string $sort [optional]
19
+	 * @return ArrayData
20
+	 */
21
+	public function searchFromVars($keywords, array $filters=array(), array $facetSpec=array(), $start=-1, $limit=-1, $sort='')
22
+	{
23
+		$searchable = ShopSearch::get_searchable_classes();
24
+		$matches = new ArrayList;
25 25
 
26
-        foreach ($searchable as $className) {
27
-            $list = DataObject::get($className);
26
+		foreach ($searchable as $className) {
27
+			$list = DataObject::get($className);
28 28
 
29
-            // get searchable fields
30
-            $keywordFields = $this->getSearchFields($className);
29
+			// get searchable fields
30
+			$keywordFields = $this->getSearchFields($className);
31 31
 
32
-            // build the filter
33
-            $filter = array();
32
+			// build the filter
33
+			$filter = array();
34 34
 
35
-            // Use parametrized query if SilverStripe >= 3.2
36
-            if (SHOP_SEARCH_IS_SS32) {
37
-                foreach ($keywordFields as $indexFields) {
38
-                    $filter[] = array("MATCH ($indexFields) AGAINST (?)" => $keywords);
39
-                }
40
-                $list = $list->whereAny($filter);
41
-            } else {
42
-                foreach ($keywordFields as $indexFields) {
43
-                    $filter[] = sprintf("MATCH ($indexFields) AGAINST ('%s')", Convert::raw2sql($keywords));
44
-                }
45
-                // join all the filters with an "OR" statement
46
-                $list = $list->where(implode(' OR ', $filter));
47
-            }
35
+			// Use parametrized query if SilverStripe >= 3.2
36
+			if (SHOP_SEARCH_IS_SS32) {
37
+				foreach ($keywordFields as $indexFields) {
38
+					$filter[] = array("MATCH ($indexFields) AGAINST (?)" => $keywords);
39
+				}
40
+				$list = $list->whereAny($filter);
41
+			} else {
42
+				foreach ($keywordFields as $indexFields) {
43
+					$filter[] = sprintf("MATCH ($indexFields) AGAINST ('%s')", Convert::raw2sql($keywords));
44
+				}
45
+				// join all the filters with an "OR" statement
46
+				$list = $list->where(implode(' OR ', $filter));
47
+			}
48 48
 
49
-            // add in any other filters
50
-            $list = FacetHelper::inst()->addFiltersToDataList($list, $filters);
49
+			// add in any other filters
50
+			$list = FacetHelper::inst()->addFiltersToDataList($list, $filters);
51 51
 
52
-            // add any matches to the big list
53
-            $matches->merge($list);
54
-        }
52
+			// add any matches to the big list
53
+			$matches->merge($list);
54
+		}
55 55
 
56
-        return new ArrayData(array(
57
-            'Matches'   => $matches,
58
-            'Facets'    => FacetHelper::inst()->buildFacets($matches, $facetSpec, (bool)Config::inst()->get('ShopSearch', 'auto_facet_attributes')),
59
-        ));
60
-    }
56
+		return new ArrayData(array(
57
+			'Matches'   => $matches,
58
+			'Facets'    => FacetHelper::inst()->buildFacets($matches, $facetSpec, (bool)Config::inst()->get('ShopSearch', 'auto_facet_attributes')),
59
+		));
60
+	}
61 61
 
62 62
 
63
-    /**
64
-     * @param $className
65
-     * @return array an array containing fields per index
66
-     * @throws Exception
67
-     */
68
-    protected function getSearchFields($className)
69
-    {
70
-        $indexes = Config::inst()->get($className, 'indexes');
63
+	/**
64
+	 * @param $className
65
+	 * @return array an array containing fields per index
66
+	 * @throws Exception
67
+	 */
68
+	protected function getSearchFields($className)
69
+	{
70
+		$indexes = Config::inst()->get($className, 'indexes');
71 71
 
72
-        $indexList = array();
73
-        foreach ($indexes as $name => $index) {
74
-            if (is_array($index)) {
75
-                if (!empty($index['type']) && $index['type'] == 'fulltext' && !empty($index['value'])) {
76
-                    $indexList[] = trim($index['value']);
77
-                }
78
-            } elseif (preg_match('/fulltext\((.+)\)/', $index, $m)) {
79
-                $indexList[] = trim($m[1]);
80
-            }
81
-        }
72
+		$indexList = array();
73
+		foreach ($indexes as $name => $index) {
74
+			if (is_array($index)) {
75
+				if (!empty($index['type']) && $index['type'] == 'fulltext' && !empty($index['value'])) {
76
+					$indexList[] = trim($index['value']);
77
+				}
78
+			} elseif (preg_match('/fulltext\((.+)\)/', $index, $m)) {
79
+				$indexList[] = trim($m[1]);
80
+			}
81
+		}
82 82
 
83
-        if (count($indexList) === 0) {
84
-            throw new Exception("Class $className does not appear to have any fulltext indexes");
85
-        }
83
+		if (count($indexList) === 0) {
84
+			throw new Exception("Class $className does not appear to have any fulltext indexes");
85
+		}
86 86
 
87
-        return $indexList;
88
-    }
87
+		return $indexList;
88
+	}
89 89
 }
Please login to merge, or discard this patch.
code/adapters/ShopSearchSimple.php 1 patch
Indentation   +89 added lines, -89 removed lines patch added patch discarded remove patch
@@ -1,104 +1,104 @@
 block discarded – undo
1 1
 <?php
2 2
 /**
3
- * VERY simple adapter to use DataList and :PartialMatch searches. Bare mininum
4
- * that will probably get terrible results but doesn't require any
5
- * additional setup.
6
- *
7
- * @author Mark Guinn <[email protected]>
8
- * @date 09.03.2013
9
- * @package shop_search
10
- */
3
+	 * VERY simple adapter to use DataList and :PartialMatch searches. Bare mininum
4
+	 * that will probably get terrible results but doesn't require any
5
+	 * additional setup.
6
+	 *
7
+	 * @author Mark Guinn <[email protected]>
8
+	 * @date 09.03.2013
9
+	 * @package shop_search
10
+	 */
11 11
 class ShopSearchSimple extends Object implements ShopSearchAdapter
12 12
 {
13
-    /**
14
-     * @param string $keywords
15
-     * @param array $filters [optional]
16
-     * @param array $facetSpec [optional]
17
-     * @param int $start [optional]
18
-     * @param int $limit [optional]
19
-     * @param string $sort [optional]
20
-     * @return ArrayData
21
-     */
22
-    public function searchFromVars($keywords, array $filters=array(), array $facetSpec=array(), $start=-1, $limit=-1, $sort='')
23
-    {
24
-        $searchable = ShopSearch::get_searchable_classes();
25
-        $matches = new ArrayList;
13
+	/**
14
+	 * @param string $keywords
15
+	 * @param array $filters [optional]
16
+	 * @param array $facetSpec [optional]
17
+	 * @param int $start [optional]
18
+	 * @param int $limit [optional]
19
+	 * @param string $sort [optional]
20
+	 * @return ArrayData
21
+	 */
22
+	public function searchFromVars($keywords, array $filters=array(), array $facetSpec=array(), $start=-1, $limit=-1, $sort='')
23
+	{
24
+		$searchable = ShopSearch::get_searchable_classes();
25
+		$matches = new ArrayList;
26 26
 
27
-        foreach ($searchable as $className) {
28
-            $list = DataObject::get($className);
27
+		foreach ($searchable as $className) {
28
+			$list = DataObject::get($className);
29 29
 
30
-            // get searchable fields
31
-            $keywordFields = $this->scaffoldSearchFields($className);
30
+			// get searchable fields
31
+			$keywordFields = $this->scaffoldSearchFields($className);
32 32
 
33
-            // convert that list into something we can pass to Datalist::filter
34
-            $keywordFilter = array();
35
-            if (!empty($keywords)) {
36
-                foreach ($keywordFields as $searchField) {
37
-                    $name = (strpos($searchField, ':') !== false) ? $searchField : "$searchField:PartialMatch";
38
-                    $keywordFilter[$name] = $keywords;
39
-                }
40
-            }
41
-            if (count($keywordFilter) > 0) {
42
-                $list = $list->filterAny($keywordFilter);
43
-            }
33
+			// convert that list into something we can pass to Datalist::filter
34
+			$keywordFilter = array();
35
+			if (!empty($keywords)) {
36
+				foreach ($keywordFields as $searchField) {
37
+					$name = (strpos($searchField, ':') !== false) ? $searchField : "$searchField:PartialMatch";
38
+					$keywordFilter[$name] = $keywords;
39
+				}
40
+			}
41
+			if (count($keywordFilter) > 0) {
42
+				$list = $list->filterAny($keywordFilter);
43
+			}
44 44
 
45
-            // add in any other filters
46
-            $list = FacetHelper::inst()->addFiltersToDataList($list, $filters);
45
+			// add in any other filters
46
+			$list = FacetHelper::inst()->addFiltersToDataList($list, $filters);
47 47
 
48
-            // add any matches to the big list
49
-            $matches->merge($list);
50
-        }
48
+			// add any matches to the big list
49
+			$matches->merge($list);
50
+		}
51 51
 
52
-        return new ArrayData(array(
53
-            'Matches'   => $matches,
54
-            'Facets'    => FacetHelper::inst()->buildFacets($matches, $facetSpec, (bool)Config::inst()->get('ShopSearch', 'auto_facet_attributes')),
55
-        ));
56
-    }
52
+		return new ArrayData(array(
53
+			'Matches'   => $matches,
54
+			'Facets'    => FacetHelper::inst()->buildFacets($matches, $facetSpec, (bool)Config::inst()->get('ShopSearch', 'auto_facet_attributes')),
55
+		));
56
+	}
57 57
 
58 58
 
59
-    /**
60
-     * This is verbatim copied from GridFieldAddExistingAutocompleter, with the exception
61
-     * that the default is 'PartialMatch' instead of 'StartsWith'
62
-     *
63
-     * @param String $dataClass - the class name
64
-     * @return Array|null - names of the searchable fields, with filters if appropriate
65
-     */
66
-    protected function scaffoldSearchFields($dataClass)
67
-    {
68
-        $obj = singleton($dataClass);
69
-        $fields = null;
70
-        if ($fieldSpecs = $obj->searchableFields()) {
71
-            $customSearchableFields = $obj->stat('searchable_fields');
72
-            foreach ($fieldSpecs as $name => $spec) {
73
-                if (is_array($spec) && array_key_exists('filter', $spec)) {
74
-                    // The searchableFields() spec defaults to PartialMatch,
75
-                    // so we need to check the original setting.
76
-                    // If the field is defined $searchable_fields = array('MyField'),
77
-                    // then default to StartsWith filter, which makes more sense in this context.
78
-                    if (!$customSearchableFields || array_search($name, $customSearchableFields)) {
79
-                        $filter = 'PartialMatch';
80
-                    } else {
81
-                        $filter = preg_replace('/Filter$/', '', $spec['filter']);
82
-                    }
59
+	/**
60
+	 * This is verbatim copied from GridFieldAddExistingAutocompleter, with the exception
61
+	 * that the default is 'PartialMatch' instead of 'StartsWith'
62
+	 *
63
+	 * @param String $dataClass - the class name
64
+	 * @return Array|null - names of the searchable fields, with filters if appropriate
65
+	 */
66
+	protected function scaffoldSearchFields($dataClass)
67
+	{
68
+		$obj = singleton($dataClass);
69
+		$fields = null;
70
+		if ($fieldSpecs = $obj->searchableFields()) {
71
+			$customSearchableFields = $obj->stat('searchable_fields');
72
+			foreach ($fieldSpecs as $name => $spec) {
73
+				if (is_array($spec) && array_key_exists('filter', $spec)) {
74
+					// The searchableFields() spec defaults to PartialMatch,
75
+					// so we need to check the original setting.
76
+					// If the field is defined $searchable_fields = array('MyField'),
77
+					// then default to StartsWith filter, which makes more sense in this context.
78
+					if (!$customSearchableFields || array_search($name, $customSearchableFields)) {
79
+						$filter = 'PartialMatch';
80
+					} else {
81
+						$filter = preg_replace('/Filter$/', '', $spec['filter']);
82
+					}
83 83
 
84
-                    if (class_exists($filter . 'Filter')) {
85
-                        $fields[] = "{$name}:{$filter}";
86
-                    } else {
87
-                        $fields[] = $name;
88
-                    }
89
-                } else {
90
-                    $fields[] = $name;
91
-                }
92
-            }
93
-        }
94
-        if (is_null($fields)) {
95
-            if ($obj->hasDatabaseField('Title')) {
96
-                $fields = array('Title');
97
-            } elseif ($obj->hasDatabaseField('Name')) {
98
-                $fields = array('Name');
99
-            }
100
-        }
84
+					if (class_exists($filter . 'Filter')) {
85
+						$fields[] = "{$name}:{$filter}";
86
+					} else {
87
+						$fields[] = $name;
88
+					}
89
+				} else {
90
+					$fields[] = $name;
91
+				}
92
+			}
93
+		}
94
+		if (is_null($fields)) {
95
+			if ($obj->hasDatabaseField('Title')) {
96
+				$fields = array('Title');
97
+			} elseif ($obj->hasDatabaseField('Name')) {
98
+				$fields = array('Name');
99
+			}
100
+		}
101 101
 
102
-        return $fields;
103
-    }
102
+		return $fields;
103
+	}
104 104
 }
Please login to merge, or discard this patch.