1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Form object for shop search. |
4
|
|
|
* |
5
|
|
|
* @author Mark Guinn <[email protected]> |
6
|
|
|
* @date 09.23.2013 |
7
|
|
|
* @package shop_search |
8
|
|
|
*/ |
9
|
|
|
class ShopSearchForm extends Form |
|
|
|
|
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
|
|
|
} |
152
|
|
|
} |
153
|
|
|
|
You can fix this by adding a namespace to your class:
When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.