Version Notes
Changelog:
* Bumped to 1.0.0 version in anticipation of Magento Connect initial release.
Download this release
Release Info
Developer | Swiftype |
Extension | Swiftype_Swiftype |
Version | 1.0.0 |
Comparing to | |
See all releases |
Version 1.0.0
- app/code/community/Swiftype/Swiftype/Block/Ajax/Suggest.php +7 -0
- app/code/community/Swiftype/Swiftype/Block/Autocomplete.php +29 -0
- app/code/community/Swiftype/Swiftype/Helper/Data.php +324 -0
- app/code/community/Swiftype/Swiftype/Helper/Log.php +46 -0
- app/code/community/Swiftype/Swiftype/Model/Observer/Adminhtml.php +36 -0
- app/code/community/Swiftype/Swiftype/Model/Observer/Frontend.php +35 -0
- app/code/community/Swiftype/Swiftype/Model/Observer/Global.php +47 -0
- app/code/community/Swiftype/Swiftype/Model/Request/Processor.php +34 -0
- app/code/community/Swiftype/Swiftype/Model/Resource/Fulltext.php +206 -0
- app/code/community/Swiftype/Swiftype/Model/Resource/Fulltext/Engine.php +167 -0
- app/code/community/Swiftype/Swiftype/Model/System/Config/Source/Catalog/Search/Engine.php +30 -0
- app/code/community/Swiftype/Swiftype/controllers/AjaxController.php +21 -0
- app/code/community/Swiftype/Swiftype/controllers/AnalyticsController.php +30 -0
- app/code/community/Swiftype/Swiftype/etc/config.xml +137 -0
- app/code/community/Swiftype/Swiftype/etc/system.xml +94 -0
- app/code/community/Swiftype/Swiftype/sql/swiftype_setup/install-1.php +55 -0
- app/design/frontend/base/default/layout/swiftype.xml +6 -0
- app/design/frontend/base/default/template/swiftype/ajax/suggest.phtml +45 -0
- app/etc/modules/Swiftype_Swiftype.xml +9 -0
- app/etc/swiftype.xml +10 -0
- package.xml +26 -0
app/code/community/Swiftype/Swiftype/Block/Ajax/Suggest.php
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Swiftype_Swiftype_Block_Ajax_Suggest
|
4 |
+
extends Mage_Core_Block_Template_Facade
|
5 |
+
{
|
6 |
+
|
7 |
+
}
|
app/code/community/Swiftype/Swiftype/Block/Autocomplete.php
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Swiftype_Swiftype_Block_Autocomplete
|
4 |
+
extends Mage_CatalogSearch_Block_Autocomplete
|
5 |
+
{
|
6 |
+
final public function getSuggestData()
|
7 |
+
{
|
8 |
+
$helper = Mage::helper('swiftype');
|
9 |
+
/* @var $helper Swiftype_Swiftype_Helper_Data */
|
10 |
+
|
11 |
+
if ($helper->getUseSwiftype()) {
|
12 |
+
$counter = 0;
|
13 |
+
$data = array();
|
14 |
+
|
15 |
+
foreach ($helper->getSuggestedProducts() as $product) {
|
16 |
+
/* @var $product Mage_Catalog_Model_Product */
|
17 |
+
$data[] = array(
|
18 |
+
'title' => $product->getName(),
|
19 |
+
'row_class' => (++$counter)%2?'odd':'even',
|
20 |
+
'num_of_results' => ''
|
21 |
+
);
|
22 |
+
}
|
23 |
+
|
24 |
+
return $data;
|
25 |
+
} else {
|
26 |
+
return parent::getSuggestData();
|
27 |
+
}
|
28 |
+
}
|
29 |
+
}
|
app/code/community/Swiftype/Swiftype/Helper/Data.php
ADDED
@@ -0,0 +1,324 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Swiftype_Swiftype_Helper_Data
|
4 |
+
extends Mage_Core_Helper_Abstract
|
5 |
+
{
|
6 |
+
const CATALOG_SEARCH_ENGINE_SWIFTYPE = 'swiftype/fulltext_engine';
|
7 |
+
const CATALOG_SEARCH_ENGINE_DEFAULT = 'catalogsearch/fulltext_engine';
|
8 |
+
|
9 |
+
const API_URL = 'https://api.swiftype.com/api/v1';
|
10 |
+
|
11 |
+
const DOCUMENT_TYPE = 'product';
|
12 |
+
const DOCUMENT_FIELD_TYPE_STRING = 'string';
|
13 |
+
const DOCUMENT_FIELD_TYPE_TEXT = 'text';
|
14 |
+
const DOCUMENT_FIELD_TYPE_ENUM = 'enum';
|
15 |
+
const DOCUMENT_FIELD_TYPE_INTEGER = 'integer';
|
16 |
+
const DOCUMENT_FIELD_TYPE_FLOAT = 'float';
|
17 |
+
const DOCUMENT_FIELD_TYPE_DATE = 'date';
|
18 |
+
const DOCUMENT_FIELD_TYPE_LOCATION = 'location';
|
19 |
+
|
20 |
+
|
21 |
+
final public function handleException(Exception $exception, $throw = false, $log = true)
|
22 |
+
{
|
23 |
+
if ($log) {
|
24 |
+
$this->getSwiftypeLogger($exception->getMessage());
|
25 |
+
}
|
26 |
+
|
27 |
+
if (Mage::getIsDeveloperMode() || $throw) {
|
28 |
+
throw $exception;
|
29 |
+
}
|
30 |
+
}
|
31 |
+
|
32 |
+
|
33 |
+
final public function onClickAutoselect($productId, $queryText)
|
34 |
+
{
|
35 |
+
$client = new Zend_Http_Client(self::API_URL . '/public/analytics/pas');
|
36 |
+
$client->setParameterGet('prefix', $queryText);
|
37 |
+
$client->setParameterGet('engine_key', $this->getEngineSlug());
|
38 |
+
$client->setParameterGet('entry_id', $productId);
|
39 |
+
$client->setParameterGet('document_type_id', 'product');
|
40 |
+
$client->request(Zend_Http_Client::GET);
|
41 |
+
}
|
42 |
+
/**
|
43 |
+
* Autocomplete click tracking.
|
44 |
+
*
|
45 |
+
* This function is automatically added to clicks coming from autocomplete
|
46 |
+
* product clicks.
|
47 |
+
*
|
48 |
+
*/
|
49 |
+
final public function getOnClickAutoselect(Mage_Catalog_Model_Product $product)
|
50 |
+
{
|
51 |
+
if ($onClickAutoselectUrl = $this->_getOnClickAutoselectUrl($product)) {
|
52 |
+
$onClickAutoselect = "new Ajax.Request('$onClickAutoselectUrl', {method: 'get', asynchronous: false})";
|
53 |
+
}
|
54 |
+
return isset($onClickAutoselect) ? $onClickAutoselect : '';
|
55 |
+
}
|
56 |
+
|
57 |
+
final protected function _getOnClickAutoselectUrl(Mage_Catalog_Model_Product $product)
|
58 |
+
{
|
59 |
+
if ($queryText = Mage::helper('catalogsearch')->getQueryText()) {
|
60 |
+
$onClickAutoselectUrl = Mage::getUrl('swiftype/analytics/onclickautoselect', array(
|
61 |
+
'id' => $product->getId(),
|
62 |
+
'q' => $queryText
|
63 |
+
));
|
64 |
+
}
|
65 |
+
return isset($onClickAutoselectUrl) ? $onClickAutoselectUrl : null;
|
66 |
+
}
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Search result click tracking.
|
70 |
+
*
|
71 |
+
* If you want to use it in search result pages, you need to
|
72 |
+
* include this in the HTML elements you want to track clicks on.
|
73 |
+
*
|
74 |
+
* In practice, this will be product links in the catalog/product/list.phtml
|
75 |
+
* file that your Package/Theme uses. To locate this file, turn on Template
|
76 |
+
* Hints in the System Configuration, and perform a test search. It will
|
77 |
+
* highlight the location of catalog/product/list.phtml
|
78 |
+
*
|
79 |
+
* @param Mage_Catalog_Model_Product $product
|
80 |
+
* @return string Contents of onClick if page is search result, empty string otherwise.
|
81 |
+
*/
|
82 |
+
final public function getOnClick(Mage_Catalog_Model_Product $product)
|
83 |
+
{
|
84 |
+
$onClick = '';
|
85 |
+
|
86 |
+
if ($onClickUrl = $this->_getOnClickUrl($product)) {
|
87 |
+
$onClick = "new Ajax.Request('$onClickUrl', {method: 'get', asynchronous: false})";
|
88 |
+
}
|
89 |
+
|
90 |
+
return $onClick;
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Get URL for Click Tracking
|
95 |
+
*
|
96 |
+
* @param Mage_Catalog_Model_Product $product
|
97 |
+
* @return string|null onClick URL if page is search result, null otherwise.
|
98 |
+
*/
|
99 |
+
final protected function _getOnClickUrl(Mage_Catalog_Model_Product $product)
|
100 |
+
{
|
101 |
+
$onClickUrl = null;
|
102 |
+
$queryText = Mage::helper('catalogsearch')->getQueryText();
|
103 |
+
|
104 |
+
if (!empty($queryText)) {
|
105 |
+
|
106 |
+
$onClickUrl = Mage::getUrl('swiftype/analytics/logclickthrough', array(
|
107 |
+
'id' => $product->getId(),
|
108 |
+
'q' => $queryText
|
109 |
+
));
|
110 |
+
}
|
111 |
+
|
112 |
+
return $onClickUrl;
|
113 |
+
}
|
114 |
+
|
115 |
+
/**
|
116 |
+
*
|
117 |
+
* @param int $productId
|
118 |
+
* @param string $query
|
119 |
+
*/
|
120 |
+
final public function logClickthrough($productId, $query)
|
121 |
+
{
|
122 |
+
$client = $this->getSwiftypeClient(array(
|
123 |
+
'uri' => array(
|
124 |
+
'engines' => $this->getEngineSlug(),
|
125 |
+
'document_types' => self::DOCUMENT_TYPE,
|
126 |
+
'analytics' => 'log_clickthrough.json'
|
127 |
+
),
|
128 |
+
'raw_data' => array(
|
129 |
+
'enctype' => 'application/json',
|
130 |
+
'data' => Zend_Json::encode(array(
|
131 |
+
'auth_token' => $this->getAuthToken(),
|
132 |
+
'id' => (int)$productId,
|
133 |
+
'q' => (string)$query
|
134 |
+
))
|
135 |
+
)
|
136 |
+
));
|
137 |
+
|
138 |
+
$response = $client->request(Zend_Http_Client::POST);
|
139 |
+
|
140 |
+
if ($response->getStatus() != 200) {
|
141 |
+
Mage::throwException($response->getStatus());
|
142 |
+
}
|
143 |
+
}
|
144 |
+
|
145 |
+
final public function getCacheKey()
|
146 |
+
{
|
147 |
+
$requestProcessor = Mage::getSingleton('swiftype/request_processor');
|
148 |
+
/* @var $requestProcessor Swiftype_Swiftype_Model_Request_Processor */
|
149 |
+
|
150 |
+
return $requestProcessor->getCacheKey();
|
151 |
+
}
|
152 |
+
|
153 |
+
final public function canCacheSwiftypeAutocomplete(Mage_Core_Controller_Request_Http $request = null)
|
154 |
+
{
|
155 |
+
if (!$this->getUseSwiftypeAutocomplete()
|
156 |
+
|| !Mage::app()->useCache(Swiftype_Swiftype_Model_Request_Processor::CACHE_KEY_PREFIX)) {
|
157 |
+
return false;
|
158 |
+
}
|
159 |
+
|
160 |
+
if (!$request) {
|
161 |
+
$request = Mage::app()->getRequest();
|
162 |
+
/* @var $request Mage_Core_Controller_Request_Http */
|
163 |
+
}
|
164 |
+
|
165 |
+
if ($request->getModuleName() == 'catalogsearch'
|
166 |
+
&& $request->getControllerName() == 'ajax'
|
167 |
+
&& $request->getActionName() == 'suggest') {
|
168 |
+
return true;
|
169 |
+
} else {
|
170 |
+
return false;
|
171 |
+
}
|
172 |
+
}
|
173 |
+
|
174 |
+
/**
|
175 |
+
*
|
176 |
+
* @return array
|
177 |
+
*/
|
178 |
+
final public function getSuggestedProducts()
|
179 |
+
{
|
180 |
+
$productsAsArray = array();
|
181 |
+
$products = Mage::getModel('catalog/product')->getCollection();
|
182 |
+
/* @var $products Mage_Catalog_Model_Resource_Product_Collection */
|
183 |
+
|
184 |
+
$products->addFieldToFilter('status', Mage_Catalog_Model_Product_Status::STATUS_ENABLED);
|
185 |
+
$products->addFieldToFilter('visibility', array('in' => array(
|
186 |
+
Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH,
|
187 |
+
Mage_Catalog_Model_Product_Visibility::VISIBILITY_IN_SEARCH
|
188 |
+
)));
|
189 |
+
|
190 |
+
$queryText = Mage::helper('catalogsearch')->getQueryText();
|
191 |
+
$queryText = !empty($queryText) ? $queryText : null;
|
192 |
+
|
193 |
+
if ($this->getUseSwiftype() && $queryText) {
|
194 |
+
$client = $this->getSwiftypeClient(array(
|
195 |
+
'uri' => array(
|
196 |
+
'public' => 'engines',
|
197 |
+
'suggest' => null
|
198 |
+
),
|
199 |
+
'get' => array(
|
200 |
+
'q' => $queryText,
|
201 |
+
'engine_key' => $this->getEngineKey()
|
202 |
+
)
|
203 |
+
));
|
204 |
+
|
205 |
+
$response = $client->request(Zend_Http_Client::GET);
|
206 |
+
|
207 |
+
if ($response->getStatus() != 200) {
|
208 |
+
Mage::throwException($response->getMessage());
|
209 |
+
}
|
210 |
+
|
211 |
+
$records = Zend_Json::decode($response->getBody(), Zend_Json::TYPE_OBJECT);
|
212 |
+
$productIds = array();
|
213 |
+
|
214 |
+
foreach ($records->records->product as $product) {
|
215 |
+
$productIds[] = $product->product_id;
|
216 |
+
}
|
217 |
+
|
218 |
+
if (!empty($productIds)) {
|
219 |
+
$products = $products->addAttributeToSelect('*')
|
220 |
+
->addFieldToFilter('entity_id', array('in' => $productIds));
|
221 |
+
|
222 |
+
foreach ($productIds as $productId) {
|
223 |
+
if ($product = $products->getItemById($productId)) {
|
224 |
+
$productsAsArray[$productId] = $product;
|
225 |
+
}
|
226 |
+
}
|
227 |
+
}
|
228 |
+
|
229 |
+
}
|
230 |
+
|
231 |
+
return array_slice($productsAsArray, 0, $this->getAutocompleteLimit());
|
232 |
+
}
|
233 |
+
|
234 |
+
/**
|
235 |
+
* Return HTTP client ready to interact with Swiftype
|
236 |
+
*
|
237 |
+
* @param mixed $store
|
238 |
+
* @param array $params
|
239 |
+
* @return Zend_Http_Client $client
|
240 |
+
*/
|
241 |
+
final public function getSwiftypeClient(array $params = array())
|
242 |
+
{
|
243 |
+
$uri = Swiftype_Swiftype_Helper_Data::API_URL;
|
244 |
+
|
245 |
+
foreach ($params['uri'] as $name => $value) {
|
246 |
+
$uri .= "/$name";
|
247 |
+
if ($value) {
|
248 |
+
$uri .= "/$value";
|
249 |
+
}
|
250 |
+
}
|
251 |
+
|
252 |
+
$client = new Zend_Http_Client($uri);
|
253 |
+
|
254 |
+
if (isset($params['raw_data'])) {
|
255 |
+
$client->setRawData($params['raw_data']['data'], $params['raw_data']['enctype']);
|
256 |
+
}
|
257 |
+
|
258 |
+
if (isset($params['get'])) {
|
259 |
+
foreach ($params['get'] as $name => $value) {
|
260 |
+
$client->setParameterGet($name, $value);
|
261 |
+
}
|
262 |
+
}
|
263 |
+
|
264 |
+
return $client;
|
265 |
+
}
|
266 |
+
|
267 |
+
/**
|
268 |
+
* Logger for Swiftype-related events
|
269 |
+
*/
|
270 |
+
final public function getSwiftypeLogger($message)
|
271 |
+
{
|
272 |
+
$filename = 'swiftype-'.date('m-d-y').'.log';
|
273 |
+
$message = is_string($message) ? "swiftype\\".$message : $message;
|
274 |
+
Mage::log($message, null, $filename, true);
|
275 |
+
}
|
276 |
+
|
277 |
+
final public function getUseSwiftype($store = null)
|
278 |
+
{
|
279 |
+
if (Mage::getStoreConfig('catalog/search/engine', $store) == self::CATALOG_SEARCH_ENGINE_SWIFTYPE) {
|
280 |
+
return true;
|
281 |
+
} else {
|
282 |
+
return false;
|
283 |
+
}
|
284 |
+
}
|
285 |
+
|
286 |
+
final public function getDocumentType()
|
287 |
+
{
|
288 |
+
return self::DOCUMENT_TYPE;
|
289 |
+
}
|
290 |
+
|
291 |
+
final public function getAuthToken($store = null)
|
292 |
+
{
|
293 |
+
return $this->getApiKey($store);
|
294 |
+
}
|
295 |
+
|
296 |
+
final public function getApiKey($store = null)
|
297 |
+
{
|
298 |
+
return Mage::getStoreConfig('catalog/search/swiftype_api_key', $store);
|
299 |
+
}
|
300 |
+
|
301 |
+
final public function getEngineSlug($store = null)
|
302 |
+
{
|
303 |
+
return Mage::getStoreConfig('catalog/search/swiftype_engine_slug', $store);
|
304 |
+
}
|
305 |
+
|
306 |
+
final public function getEngineKey($store = null)
|
307 |
+
{
|
308 |
+
return Mage::getStoreConfig('catalog/search/swiftype_engine_key', $store);
|
309 |
+
}
|
310 |
+
|
311 |
+
final public function getAutocompleteLimit($store = null)
|
312 |
+
{
|
313 |
+
return Mage::getStoreConfig('catalog/search/swiftype_autocomplete_limit', $store);
|
314 |
+
}
|
315 |
+
|
316 |
+
final public function getUseSwiftypeAutocomplete($store = null)
|
317 |
+
{
|
318 |
+
if (!$this->getUseSwiftype()) {
|
319 |
+
return false;
|
320 |
+
}
|
321 |
+
|
322 |
+
return Mage::getStoreConfig('catalog/search/swiftype_autocomplete', $store);
|
323 |
+
}
|
324 |
+
}
|
app/code/community/Swiftype/Swiftype/Helper/Log.php
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Swiftype_Swiftype_Helper_Log
|
4 |
+
extends Mage_Core_Helper_Abstract
|
5 |
+
{
|
6 |
+
final protected function _log($key, $message)
|
7 |
+
{
|
8 |
+
$logDir = Mage::getBaseDir('log') . DS . 'swiftype';
|
9 |
+
if (!is_readable($logDir)) {
|
10 |
+
mkdir($logDir, 0777);
|
11 |
+
}
|
12 |
+
Mage::log("$key: $message", null, 'swiftype/swiftype-' . date('d-m-Y') . '.log', true);
|
13 |
+
}
|
14 |
+
|
15 |
+
final protected function _getLogKey($storeId, array $swiftypeApiUri)
|
16 |
+
{
|
17 |
+
$logKey = '';
|
18 |
+
foreach ($swiftypeApiUri as $name => $value) {
|
19 |
+
$logKey .= "/$name";
|
20 |
+
if ($value) {
|
21 |
+
$logKey .= "/$value";
|
22 |
+
}
|
23 |
+
}
|
24 |
+
return "[$storeId] $logKey";
|
25 |
+
}
|
26 |
+
|
27 |
+
final public function logIndexRequest($storeId, array $swiftypeApiParameters, $productIds)
|
28 |
+
{
|
29 |
+
$this->_log($this->_getLogKey($storeId, $swiftypeApiParameters['uri']), 'Product IDs: ' . implode(',', $productIds));
|
30 |
+
}
|
31 |
+
|
32 |
+
final public function logIndexResponse($storeId, array $swiftypeApiParameters, Zend_Http_Response $swiftypeApiResponse)
|
33 |
+
{
|
34 |
+
$this->_log($this->_getLogKey($storeId, $swiftypeApiParameters['uri']), 'Status: ' . $swiftypeApiResponse->getStatus());
|
35 |
+
}
|
36 |
+
|
37 |
+
final public function logDeleteResponse($storeId, array $swiftypeApiParameters, Zend_Http_Response $swiftypeApiResponse)
|
38 |
+
{
|
39 |
+
$this->_log($this->_getLogKey($storeId, $swiftypeApiParameters['uri']), 'Method: Delete, Status: ' . $swiftypeApiResponse->getStatus());
|
40 |
+
}
|
41 |
+
|
42 |
+
final public function logSearchException($storeId, array $swiftypeApiParameters = array('uri' => array('search' => null)), $exceptionMessage)
|
43 |
+
{
|
44 |
+
$this->_log($this->_getLogKey($storeId, $swiftypeApiParameters['uri']), $exceptionMessage);
|
45 |
+
}
|
46 |
+
}
|
app/code/community/Swiftype/Swiftype/Model/Observer/Adminhtml.php
ADDED
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
final class Swiftype_Swiftype_Model_Observer_Adminhtml
|
4 |
+
{
|
5 |
+
/**
|
6 |
+
* Add Swiftype Document Field Types to Attribute Edit Form
|
7 |
+
*
|
8 |
+
* @param Varien_Event_Observer $observer
|
9 |
+
* @return \Swiftype_Swiftype_Model_Observer_Adminhtml
|
10 |
+
*/
|
11 |
+
final public function adminhtmlCatalogProductAttributeEditPrepareForm(Varien_Event_Observer $observer)
|
12 |
+
{
|
13 |
+
$form = $observer->getEvent()->getForm();
|
14 |
+
/* @var $form Varien_Data_Form */
|
15 |
+
|
16 |
+
$fieldset = $form->addFieldset('swiftype_fieldset',
|
17 |
+
array('legend' => 'Swiftype Properties')
|
18 |
+
);
|
19 |
+
$fieldset->addField('swiftype_document_field_type', 'select', array(
|
20 |
+
'name' => 'swiftype_document_field_type',
|
21 |
+
'label' => 'Document Field Type',
|
22 |
+
'title' => 'Document Field Type',
|
23 |
+
'note' => 'See <a href="https://swiftype.com/documentation/overview#field_types" target="_blank">Document Field Types</a>.',
|
24 |
+
'values' => array(
|
25 |
+
array('value' => Swiftype_Swiftype_Helper_Data::DOCUMENT_FIELD_TYPE_STRING, 'label' => 'String'),
|
26 |
+
array('value' => Swiftype_Swiftype_Helper_Data::DOCUMENT_FIELD_TYPE_TEXT, 'label' => 'Text'),
|
27 |
+
array('value' => Swiftype_Swiftype_Helper_Data::DOCUMENT_FIELD_TYPE_ENUM, 'label' => 'Enum'),
|
28 |
+
array('value' => Swiftype_Swiftype_Helper_Data::DOCUMENT_FIELD_TYPE_INTEGER, 'label' => 'Integer'),
|
29 |
+
array('value' => Swiftype_Swiftype_Helper_Data::DOCUMENT_FIELD_TYPE_FLOAT, 'label' => 'Float'),
|
30 |
+
array('value' => Swiftype_Swiftype_Helper_Data::DOCUMENT_FIELD_TYPE_DATE, 'label' => 'Date'),
|
31 |
+
array('value' => Swiftype_Swiftype_Helper_Data::DOCUMENT_FIELD_TYPE_LOCATION, 'label' => 'Location')
|
32 |
+
),
|
33 |
+
));
|
34 |
+
return $this;
|
35 |
+
}
|
36 |
+
}
|
app/code/community/Swiftype/Swiftype/Model/Observer/Frontend.php
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Swiftype_Swiftype_Model_Observer_Frontend
|
4 |
+
{
|
5 |
+
/**
|
6 |
+
* @return Swiftype_Swiftype_Helper_Data
|
7 |
+
*/
|
8 |
+
final protected function _getHelper()
|
9 |
+
{
|
10 |
+
return Mage::helper('swiftype');
|
11 |
+
}
|
12 |
+
|
13 |
+
/**
|
14 |
+
*
|
15 |
+
* @param Varien_Event_Observer $observer
|
16 |
+
* @return Swiftype_Swiftype_Model_Observer_Frontend
|
17 |
+
*/
|
18 |
+
final public function cacheSwiftypeAutoComplete(Varien_Event_Observer $observer)
|
19 |
+
{
|
20 |
+
if ($this->_getHelper()->canCacheSwiftypeAutocomplete()) {
|
21 |
+
$buffer = ob_get_clean();
|
22 |
+
|
23 |
+
$cache = Mage::app()->getCache();
|
24 |
+
$cacheKey = $this->_getHelper()->getCacheKey();
|
25 |
+
|
26 |
+
if (!empty($buffer)) {
|
27 |
+
$cache->save($buffer, $cacheKey, array(Swiftype_Swiftype_Model_Request_Processor::CACHE_TAG));
|
28 |
+
}
|
29 |
+
|
30 |
+
echo $buffer;
|
31 |
+
}
|
32 |
+
|
33 |
+
return $this;
|
34 |
+
}
|
35 |
+
}
|
app/code/community/Swiftype/Swiftype/Model/Observer/Global.php
ADDED
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Swiftype_Swiftype_Model_Observer_Global
|
4 |
+
{
|
5 |
+
final public function cleanSwiftypeAutocompleteCache(Varien_Event_Observer $observer)
|
6 |
+
{
|
7 |
+
Mage::app()->getCache()->clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG,
|
8 |
+
array(Swiftype_Swiftype_Model_Request_Processor::CACHE_TAG));
|
9 |
+
}
|
10 |
+
|
11 |
+
final public function clearCatalogsearchResults(Varien_Event_Observer $observer)
|
12 |
+
{
|
13 |
+
$configData = $observer->getEvent()->getConfigData();
|
14 |
+
/* @var $configData Mage_Core_Model_Config_Data */
|
15 |
+
$path = $configData->getPath();
|
16 |
+
$savedValue = $configData->getValue();
|
17 |
+
$originalValue = Mage::getStoreConfig($path);
|
18 |
+
|
19 |
+
if ($configData->getPath() == $path) {
|
20 |
+
if ($savedValue != $originalValue) {
|
21 |
+
if ($savedValue == Swiftype_Swiftype_Helper_Data::CATALOG_SEARCH_ENGINE_SWIFTYPE
|
22 |
+
|| $originalValue == Swiftype_Swiftype_Helper_Data::CATALOG_SEARCH_ENGINE_SWIFTYPE) {
|
23 |
+
$indexer = Mage::getModel('index/indexer');
|
24 |
+
/* @var $indexer Mage_Index_Model_Indexer */
|
25 |
+
$process = $indexer->getProcessByCode('catalogsearch_fulltext');
|
26 |
+
$process->changeStatus(Mage_Index_Model_Process::STATUS_REQUIRE_REINDEX);
|
27 |
+
$this->_clearCatalogsearchResults();
|
28 |
+
}
|
29 |
+
}
|
30 |
+
}
|
31 |
+
}
|
32 |
+
|
33 |
+
final protected function _clearCatalogsearchResults()
|
34 |
+
{
|
35 |
+
$resource = Mage::getModel('core/resource');
|
36 |
+
/* @var $resource Mage_Core_Model_Resource */
|
37 |
+
$adapter = $resource->getConnection('core_write');
|
38 |
+
/* @var $adapter Varien_Db_Adapter_Interface */
|
39 |
+
$adapter->beginTransaction();
|
40 |
+
try {
|
41 |
+
$adapter->delete($resource->getTableName('catalogsearch/result'));
|
42 |
+
$adapter->commit();
|
43 |
+
} catch (Exception $ex) {
|
44 |
+
Mage::helper('swiftype')->handleException($ex);
|
45 |
+
}
|
46 |
+
}
|
47 |
+
}
|
app/code/community/Swiftype/Swiftype/Model/Request/Processor.php
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Swiftype_Swiftype_Model_Request_Processor
|
4 |
+
{
|
5 |
+
const CACHE_KEY_PREFIX = 'swiftype_autocomplete';
|
6 |
+
const CACHE_TAG = 'SWIFTYPE_AUTOCOMPLETE';
|
7 |
+
|
8 |
+
final public function extractContent($content = false)
|
9 |
+
{
|
10 |
+
$cache = Mage::app()->getCache();
|
11 |
+
$content = $cache->load($this->getCacheKey());
|
12 |
+
|
13 |
+
if (!$content) {
|
14 |
+
ob_start();
|
15 |
+
}
|
16 |
+
|
17 |
+
return $content;
|
18 |
+
}
|
19 |
+
|
20 |
+
/**
|
21 |
+
*
|
22 |
+
* @param Mage_Core_Controller_Request_Http $request
|
23 |
+
* @return null|string
|
24 |
+
*/
|
25 |
+
final public function getCacheKey(Mage_Core_Controller_Request_Http $request = null)
|
26 |
+
{
|
27 |
+
if (!$request) {
|
28 |
+
$request = Mage::app()->getRequest();
|
29 |
+
/* @var $request Mage_Core_Controller_Request_Http */
|
30 |
+
}
|
31 |
+
|
32 |
+
return self::CACHE_KEY_PREFIX . '_' . md5($request->getRequestUri());
|
33 |
+
}
|
34 |
+
}
|
app/code/community/Swiftype/Swiftype/Model/Resource/Fulltext.php
ADDED
@@ -0,0 +1,206 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Swiftype_Swiftype_Model_Resource_Fulltext
|
4 |
+
extends Mage_CatalogSearch_Model_Resource_Fulltext
|
5 |
+
{
|
6 |
+
const PER_PAGE = 20;
|
7 |
+
|
8 |
+
final public function cleanIndex($storeId = null, $productId = null)
|
9 |
+
{
|
10 |
+
if ($storeId) {
|
11 |
+
$this->_setStoreEngine($storeId);
|
12 |
+
parent::cleanIndex($storeId, $productId);
|
13 |
+
} else {
|
14 |
+
foreach (Mage::app()->getStores() as $store) {
|
15 |
+
$this->cleanIndex($store->getId(), $productId);
|
16 |
+
}
|
17 |
+
}
|
18 |
+
|
19 |
+
return $this;
|
20 |
+
}
|
21 |
+
|
22 |
+
final protected function _rebuildStoreIndex($storeId, $productIds = null)
|
23 |
+
{
|
24 |
+
$this->_setStoreEngine($storeId);
|
25 |
+
|
26 |
+
return parent::_rebuildStoreIndex($storeId, $productIds);
|
27 |
+
}
|
28 |
+
|
29 |
+
final protected function _setStoreEngine($storeId)
|
30 |
+
{
|
31 |
+
$this->_engine = $this->_getStoreEngine($storeId);
|
32 |
+
}
|
33 |
+
|
34 |
+
final protected function _getStoreEngine($storeId)
|
35 |
+
{
|
36 |
+
$engine = $this->_getHelper()->getUseSwiftype($storeId) ?
|
37 |
+
Swiftype_Swiftype_Helper_Data::CATALOG_SEARCH_ENGINE_SWIFTYPE
|
38 |
+
: Swiftype_Swiftype_Helper_Data::CATALOG_SEARCH_ENGINE_DEFAULT;
|
39 |
+
|
40 |
+
return Mage::getResourceSingleton($engine);
|
41 |
+
}
|
42 |
+
|
43 |
+
final protected function _getSearchableProducts($storeId, array $staticFields, $productIds = null, $lastProductId = 0, $limit = 100)
|
44 |
+
{
|
45 |
+
if ($this->_getHelper()->getUseSwiftype($storeId)) {
|
46 |
+
$limit = null;
|
47 |
+
}
|
48 |
+
|
49 |
+
return parent::_getSearchableProducts($storeId, $staticFields, $productIds, $lastProductId, $limit);
|
50 |
+
}
|
51 |
+
|
52 |
+
/**
|
53 |
+
* @return Swiftype_Swiftype_Helper_Data
|
54 |
+
*/
|
55 |
+
final protected function _getHelper()
|
56 |
+
{
|
57 |
+
return Mage::helper('swiftype');
|
58 |
+
}
|
59 |
+
|
60 |
+
public function prepareResult($object, $queryText, $query)
|
61 |
+
{
|
62 |
+
$storeId = $query->getStoreId();
|
63 |
+
|
64 |
+
if (!$this->_getHelper()->getUseSwiftype($storeId)) {
|
65 |
+
return parent::prepareResult($object, $queryText, $query);
|
66 |
+
} else {
|
67 |
+
$this->_updateSearchResults($query, $this->_prepareResults($this->_getResults($query), $query));
|
68 |
+
$query->setIsProcessed(1);
|
69 |
+
return $this;
|
70 |
+
}
|
71 |
+
}
|
72 |
+
|
73 |
+
/**
|
74 |
+
*
|
75 |
+
* @param Mage_CatalogSearch_Model_Query $query
|
76 |
+
* @return array
|
77 |
+
*/
|
78 |
+
final protected function _getResults(Mage_CatalogSearch_Model_Query $query)
|
79 |
+
{
|
80 |
+
$results = array();
|
81 |
+
$result = $this->_getResult($query);
|
82 |
+
$results = $result->records->product;
|
83 |
+
|
84 |
+
if ($result->info->product->num_pages > 1) {
|
85 |
+
for ($page = 2; $page <= $result->info->product->num_pages; $page++) {
|
86 |
+
$result = $this->_getResult($query, $page);
|
87 |
+
$results = array_merge($results, $result->records->product);
|
88 |
+
}
|
89 |
+
}
|
90 |
+
|
91 |
+
return $results;
|
92 |
+
}
|
93 |
+
|
94 |
+
/**
|
95 |
+
*
|
96 |
+
* @param Mage_CatalogSearch_Model_Query $query
|
97 |
+
* @param int $page
|
98 |
+
* @return array
|
99 |
+
*/
|
100 |
+
final protected function _getResult(Mage_CatalogSearch_Model_Query $query, $page = 1)
|
101 |
+
{
|
102 |
+
$storeId = $query->getStoreId();
|
103 |
+
|
104 |
+
$swiftypeApiParameters = array(
|
105 |
+
'uri' => array(
|
106 |
+
'engines' => $this->_getHelper()->getEngineSlug($storeId),
|
107 |
+
'document_types' => Swiftype_Swiftype_Helper_Data::DOCUMENT_TYPE,
|
108 |
+
'search' => null
|
109 |
+
),
|
110 |
+
'get' => array(
|
111 |
+
'auth_token' => $this->_getHelper()->getAuthToken($storeId),
|
112 |
+
'q' => $this->_getQueryText($query),
|
113 |
+
'per_page' => self::PER_PAGE,
|
114 |
+
'page' => $page
|
115 |
+
)
|
116 |
+
);
|
117 |
+
|
118 |
+
$swiftypeApiClient = $this->_getHelper()->getSwiftypeClient($swiftypeApiParameters);
|
119 |
+
$swiftypeApiResponse = $swiftypeApiClient->request(Zend_Http_Client::GET);
|
120 |
+
|
121 |
+
if ($swiftypeApiResponse->getStatus() == 200) {
|
122 |
+
return Zend_Json::decode($swiftypeApiResponse->getBody(), Zend_Json::TYPE_OBJECT);
|
123 |
+
} else {
|
124 |
+
Mage::helper('swiftype/log')->logSearchException($storeId, $swiftypeApiParameters, 'Status: ' . $swiftypeApiResponse->getStatus());
|
125 |
+
}
|
126 |
+
}
|
127 |
+
|
128 |
+
/**
|
129 |
+
*
|
130 |
+
* @param array $results
|
131 |
+
* @param Mage_CatalogSearch_Model_Query $query
|
132 |
+
* @return array
|
133 |
+
*/
|
134 |
+
final protected function _prepareResults(array $results, Mage_CatalogSearch_Model_Query $query)
|
135 |
+
{
|
136 |
+
$preparedResults = array();
|
137 |
+
$resultCount = count($results);
|
138 |
+
$customRelevance = false;
|
139 |
+
|
140 |
+
foreach ($results as $result) {
|
141 |
+
/* @var $result stdClass */
|
142 |
+
$relevance = isset($result->_score) ? $result->_score : 0;
|
143 |
+
// Indicates custom ordering
|
144 |
+
if (!$relevance) {
|
145 |
+
$customRelevance = true;
|
146 |
+
break;
|
147 |
+
}
|
148 |
+
}
|
149 |
+
|
150 |
+
foreach ($results as $result) {
|
151 |
+
/* @var $result stdClass */
|
152 |
+
$relevance = isset($result->_score) ? $result->_score : 0;
|
153 |
+
|
154 |
+
if ($customRelevance) {
|
155 |
+
$relevance = $resultCount;
|
156 |
+
$resultCount--;
|
157 |
+
}
|
158 |
+
|
159 |
+
$preparedResults[] = array(
|
160 |
+
'product_id' => (int)$result->product_id,
|
161 |
+
'query_id' => (int)$query->getId(),
|
162 |
+
'relevance' => $relevance
|
163 |
+
);
|
164 |
+
}
|
165 |
+
|
166 |
+
return $preparedResults;
|
167 |
+
}
|
168 |
+
|
169 |
+
final protected function _updateSearchResults(Mage_CatalogSearch_Model_Query $query, array $results)
|
170 |
+
{
|
171 |
+
$adapter = $this->_getWriteAdapter();
|
172 |
+
$table = $this->getTable('catalogsearch/result');
|
173 |
+
|
174 |
+
$adapter->beginTransaction();
|
175 |
+
$adapter->delete($table, array('query_id = ?' => $query->getId()));
|
176 |
+
|
177 |
+
$failedResults = array();
|
178 |
+
$relevance = array('relevance');
|
179 |
+
foreach ($results as $result) {
|
180 |
+
try {
|
181 |
+
$adapter->insertOnDuplicate($table, $result, $relevance);
|
182 |
+
} catch (Exception $exception) {
|
183 |
+
if (!isset($failedResults[$exception->getMessage()])) {
|
184 |
+
$failedResults[$exception->getMessage()] = array();
|
185 |
+
}
|
186 |
+
$failedResults[$exception->getMessage()][] = $result['product_id'];
|
187 |
+
}
|
188 |
+
}
|
189 |
+
$adapter->commit();
|
190 |
+
|
191 |
+
if(!empty($failedResults)) {
|
192 |
+
Mage::helper('swiftype/log')->logSearchException($query->getStoreId(), null, Zend_Json::encode($failedResults));
|
193 |
+
}
|
194 |
+
}
|
195 |
+
|
196 |
+
final protected function _getQueryText(Mage_CatalogSearch_Model_Query $query)
|
197 |
+
{
|
198 |
+
$queryText = $query->getQueryText();
|
199 |
+
|
200 |
+
if ($query->getSynonymFor()) {
|
201 |
+
$queryText = $query->getSynonymFor();
|
202 |
+
}
|
203 |
+
|
204 |
+
return $queryText;
|
205 |
+
}
|
206 |
+
}
|
app/code/community/Swiftype/Swiftype/Model/Resource/Fulltext/Engine.php
ADDED
@@ -0,0 +1,167 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Swiftype_Swiftype_Model_Resource_Fulltext_Engine
|
4 |
+
extends Mage_CatalogSearch_Model_Resource_Fulltext_Engine
|
5 |
+
{
|
6 |
+
private $_documentFieldTypes = array();
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Create/update Documents in Swiftype
|
10 |
+
*
|
11 |
+
* @param int $storeId
|
12 |
+
* @param array $entityIndexes
|
13 |
+
* @param string $entity
|
14 |
+
* @return \Swiftype_Swiftype_Model_Resource_Fulltext_Engine
|
15 |
+
*/
|
16 |
+
final public function saveEntityIndexes($storeId, $entityIndexes, $entity = 'product')
|
17 |
+
{
|
18 |
+
if ($entity == 'product') {
|
19 |
+
$bulkCreateOrUpdate = new stdClass();
|
20 |
+
$bulkCreateOrUpdate->auth_token = $this->_getHelper()->getAuthToken($storeId);
|
21 |
+
|
22 |
+
foreach ($entityIndexes as $entityId => $index) {
|
23 |
+
$document = new stdClass();
|
24 |
+
$document->external_id = $entityId;
|
25 |
+
|
26 |
+
foreach ($index as $attributeCode => $value) {
|
27 |
+
$document->fields[] = array(
|
28 |
+
'name' => $attributeCode,
|
29 |
+
'value' => $value,
|
30 |
+
'type' => $this->_getDocumentFieldType($attributeCode)
|
31 |
+
);
|
32 |
+
}
|
33 |
+
$document->fields[] = array(
|
34 |
+
'name' => 'product_id',
|
35 |
+
'value' => $entityId,
|
36 |
+
'type' => Swiftype_Swiftype_Helper_Data::DOCUMENT_FIELD_TYPE_INTEGER
|
37 |
+
);
|
38 |
+
$bulkCreateOrUpdate->documents[] = $document;
|
39 |
+
}
|
40 |
+
|
41 |
+
$swiftypeApiParameters = array(
|
42 |
+
'uri' => array(
|
43 |
+
'engines' => $this->_getHelper()->getEngineSlug($storeId),
|
44 |
+
'document_types' => $entity,
|
45 |
+
'documents' => 'bulk_create_or_update_verbose'
|
46 |
+
),
|
47 |
+
'raw_data' => array(
|
48 |
+
'enctype' => 'application/json',
|
49 |
+
'data' => Zend_Json::encode($bulkCreateOrUpdate)
|
50 |
+
)
|
51 |
+
);
|
52 |
+
|
53 |
+
$swiftypeApiClient = $this->_getHelper()->getSwiftypeClient($swiftypeApiParameters);
|
54 |
+
$swiftypeApiResponse = $swiftypeApiClient->request(Zend_Http_Client::POST);
|
55 |
+
|
56 |
+
if ($swiftypeApiResponse->getStatus() == 200) {
|
57 |
+
$responseMessage = Zend_Json::decode($swiftypeApiResponse->getBody());
|
58 |
+
if ($responseMessage[0] !== true) {
|
59 |
+
$this->_logError($storeId, $swiftypeApiParameters, array_keys($entityIndexes), $swiftypeApiResponse);
|
60 |
+
}
|
61 |
+
} else {
|
62 |
+
$this->_logError($storeId, $swiftypeApiParameters, array_keys($entityIndexes), $swiftypeApiResponse);
|
63 |
+
}
|
64 |
+
}
|
65 |
+
|
66 |
+
return $this;
|
67 |
+
}
|
68 |
+
|
69 |
+
final protected function _logError($storeId, $swiftypeApiParameters, $productIds, $swiftypeApiResponse)
|
70 |
+
{
|
71 |
+
Mage::helper('swiftype/log')->logIndexRequest($storeId, $swiftypeApiParameters, $productIds);
|
72 |
+
Mage::helper('swiftype/log')->logIndexResponse($storeId, $swiftypeApiParameters, $swiftypeApiResponse);
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Get Swiftype Document Field Type for Attribute Code
|
77 |
+
*
|
78 |
+
* @param string $attributeCode
|
79 |
+
* @return string
|
80 |
+
*/
|
81 |
+
final protected function _getDocumentFieldType($attributeCode)
|
82 |
+
{
|
83 |
+
if (!in_array($attributeCode, $this->_documentFieldTypes)) {
|
84 |
+
$entityType = Mage::getModel('eav/entity_type')
|
85 |
+
->loadByCode(Mage_Catalog_Model_Product::ENTITY);
|
86 |
+
/* @var $entityType Mage_Eav_Model_Entity_Type */
|
87 |
+
$attribute = Mage::getModel('catalog/resource_eav_attribute')
|
88 |
+
->loadByCode($entityType->getId(), $attributeCode);
|
89 |
+
/* @var $attribute Mage_Catalog_Model_Resource_Eav_Attribute */
|
90 |
+
|
91 |
+
if ($attribute->getId()) {
|
92 |
+
$documentFieldType = $attribute->getSwiftypeDocumentFieldType();
|
93 |
+
} else {
|
94 |
+
$documentFieldType = Swiftype_Swiftype_Helper_Data::DOCUMENT_FIELD_TYPE_TEXT;
|
95 |
+
}
|
96 |
+
$this->_documentFieldTypes[$attributeCode] = $documentFieldType;
|
97 |
+
}
|
98 |
+
return $this->_documentFieldTypes[$attributeCode];
|
99 |
+
}
|
100 |
+
|
101 |
+
/**
|
102 |
+
* @return Swiftype_Swiftype_Helper_Data
|
103 |
+
*/
|
104 |
+
final protected function _getHelper()
|
105 |
+
{
|
106 |
+
return Mage::helper('swiftype');
|
107 |
+
}
|
108 |
+
|
109 |
+
/**
|
110 |
+
* Remove Document from Swiftype
|
111 |
+
*
|
112 |
+
* @param mixed $storeId
|
113 |
+
* @param mixed $entityId
|
114 |
+
* @param string $entity
|
115 |
+
* @return \Swiftype_Swiftype_Model_Resource_Fulltext_Engine
|
116 |
+
*/
|
117 |
+
final public function cleanIndex($storeId = null, $entityId = null, $entity = 'product')
|
118 |
+
{
|
119 |
+
if ($entity == 'product' && $entityId) {
|
120 |
+
if (!is_array($entityId)) {
|
121 |
+
$swiftypeApiParameters = array(
|
122 |
+
'uri' => array(
|
123 |
+
'engines' => $this->_getHelper()->getEngineSlug($storeId),
|
124 |
+
'document_types' => $entity,
|
125 |
+
'documents' => $entityId
|
126 |
+
),
|
127 |
+
'get' => array(
|
128 |
+
'auth_token' => $this->_getHelper()->getAuthToken($storeId)
|
129 |
+
)
|
130 |
+
|
131 |
+
);
|
132 |
+
$swiftypeApiClient = $this->_getHelper()->getSwiftypeClient($swiftypeApiParameters);
|
133 |
+
$swiftypeApiResponse = $swiftypeApiClient->request(Zend_Http_Client::DELETE);
|
134 |
+
|
135 |
+
if ($swiftypeApiResponse->getStatus() == 200 || $swiftypeApiResponse->getStatus() == 406) {
|
136 |
+
return $this;
|
137 |
+
}
|
138 |
+
|
139 |
+
Mage::helper('swiftype/log')->logDeleteResponse($storeId, $swiftypeApiParameters, $swiftypeApiResponse);
|
140 |
+
}
|
141 |
+
}
|
142 |
+
return $this;
|
143 |
+
}
|
144 |
+
|
145 |
+
/**
|
146 |
+
*
|
147 |
+
* @param array $index Data to index
|
148 |
+
* @param string $separator
|
149 |
+
* @return array Data formatted ready for indexing
|
150 |
+
*/
|
151 |
+
final public function prepareEntityIndex($index, $separator = ' ')
|
152 |
+
{
|
153 |
+
$separator = ' ';
|
154 |
+
foreach ($index as $attributeCode => $value) {
|
155 |
+
if (is_array($value)) {
|
156 |
+
reset($value);
|
157 |
+
$value = $value[key($value)];
|
158 |
+
}
|
159 |
+
if (preg_match('/^(Enabled)?$/', $value) || preg_match('/^(in_stock|price)?$/', $attributeCode)) {
|
160 |
+
unset($index[$attributeCode]);
|
161 |
+
} else {
|
162 |
+
$index[$attributeCode] = $value;
|
163 |
+
}
|
164 |
+
}
|
165 |
+
return $index;
|
166 |
+
}
|
167 |
+
}
|
app/code/community/Swiftype/Swiftype/Model/System/Config/Source/Catalog/Search/Engine.php
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
final class Swiftype_Swiftype_Model_System_Config_Source_Catalog_Search_Engine
|
4 |
+
{
|
5 |
+
final public function toOptionArray()
|
6 |
+
{
|
7 |
+
if (class_exists('Enterprise_Search_Model_Adminhtml_System_Config_Source_Engine')) {
|
8 |
+
$sourceModel = new Enterprise_Search_Model_Adminhtml_System_Config_Source_Engine();
|
9 |
+
|
10 |
+
$optionArray = $sourceModel->toOptionArray();
|
11 |
+
$optionArray[] = array(
|
12 |
+
'value' => Swiftype_Swiftype_Helper_Data::CATALOG_SEARCH_ENGINE_SWIFTYPE,
|
13 |
+
'label' => 'Swiftype'
|
14 |
+
);
|
15 |
+
} else {
|
16 |
+
$optionArray = array(
|
17 |
+
array(
|
18 |
+
'value' => Swiftype_Swiftype_Helper_Data::CATALOG_SEARCH_ENGINE_SWIFTYPE,
|
19 |
+
'label' => 'Swiftype'
|
20 |
+
),
|
21 |
+
array(
|
22 |
+
'value' => Swiftype_Swiftype_Helper_Data::CATALOG_SEARCH_ENGINE_DEFAULT,
|
23 |
+
'label' => 'MySQL'
|
24 |
+
)
|
25 |
+
);
|
26 |
+
}
|
27 |
+
|
28 |
+
return $optionArray;
|
29 |
+
}
|
30 |
+
}
|
app/code/community/Swiftype/Swiftype/controllers/AjaxController.php
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once(Mage::getModuleDir('controllers','Mage_CatalogSearch') . DS . 'AjaxController.php');
|
4 |
+
|
5 |
+
class Swiftype_Swiftype_AjaxController extends Mage_CatalogSearch_AjaxController
|
6 |
+
{
|
7 |
+
public function suggestAction()
|
8 |
+
{
|
9 |
+
$helper = Mage::helper('swiftype');
|
10 |
+
/* @var $helper Swiftype_Swiftype_Helper_Data */
|
11 |
+
|
12 |
+
if ($helper->getUseSwiftypeAutocomplete()) {
|
13 |
+
$this->loadLayout();
|
14 |
+
$this->renderLayout();
|
15 |
+
} else {
|
16 |
+
parent::suggestAction();
|
17 |
+
}
|
18 |
+
|
19 |
+
return $this;
|
20 |
+
}
|
21 |
+
}
|
app/code/community/Swiftype/Swiftype/controllers/AnalyticsController.php
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Swiftype_Swiftype_AnalyticsController
|
4 |
+
extends Mage_Core_Controller_Front_Action
|
5 |
+
{
|
6 |
+
/**
|
7 |
+
*
|
8 |
+
* @return \Swiftype_Swiftype_AnalyticsController
|
9 |
+
*/
|
10 |
+
final public function logclickthroughAction()
|
11 |
+
{
|
12 |
+
$id = $this->getRequest()->getParam('id');
|
13 |
+
$q = $this->getRequest()->getParam('q');
|
14 |
+
|
15 |
+
$helper = Mage::helper('swiftype');
|
16 |
+
/* @var $helper Swiftype_Swiftype_Helper_Data */
|
17 |
+
$helper->logClickthrough((int)$id, (string)$q);
|
18 |
+
|
19 |
+
return $this;
|
20 |
+
}
|
21 |
+
|
22 |
+
final public function onclickautoselectAction()
|
23 |
+
{
|
24 |
+
$helper = Mage::helper('swiftype');
|
25 |
+
/* @var $helper Swiftype_Swiftype_Helper_Data */
|
26 |
+
$helper->onClickAutoselect(
|
27 |
+
(int)$this->getRequest()->getParam('id'),
|
28 |
+
(string)$this->getRequest()->getParam('q'));
|
29 |
+
}
|
30 |
+
}
|
app/code/community/Swiftype/Swiftype/etc/config.xml
ADDED
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<config>
|
3 |
+
<modules>
|
4 |
+
<Swiftype_Swiftype>
|
5 |
+
<version>1.0.0</version>
|
6 |
+
</Swiftype_Swiftype>
|
7 |
+
</modules>
|
8 |
+
<global>
|
9 |
+
<helpers>
|
10 |
+
<swiftype>
|
11 |
+
<class>Swiftype_Swiftype_Helper</class>
|
12 |
+
</swiftype>
|
13 |
+
</helpers>
|
14 |
+
<blocks>
|
15 |
+
<swiftype>
|
16 |
+
<class>Swiftype_Swiftype_Block</class>
|
17 |
+
</swiftype>
|
18 |
+
<catalogsearch>
|
19 |
+
<rewrite>
|
20 |
+
<autocomplete>Swiftype_Swiftype_Block_Autocomplete</autocomplete>
|
21 |
+
</rewrite>
|
22 |
+
</catalogsearch>
|
23 |
+
</blocks>
|
24 |
+
<models>
|
25 |
+
<swiftype>
|
26 |
+
<class>Swiftype_Swiftype_Model</class>
|
27 |
+
<resourceModel>swiftype_resource</resourceModel>
|
28 |
+
</swiftype>
|
29 |
+
<swiftype_resource>
|
30 |
+
<class>Swiftype_Swiftype_Model_Resource</class>
|
31 |
+
</swiftype_resource>
|
32 |
+
<catalogsearch_resource>
|
33 |
+
<rewrite>
|
34 |
+
<fulltext>Swiftype_Swiftype_Model_Resource_Fulltext</fulltext>
|
35 |
+
</rewrite>
|
36 |
+
</catalogsearch_resource>
|
37 |
+
</models>
|
38 |
+
<resources>
|
39 |
+
<swiftype_setup>
|
40 |
+
<setup>
|
41 |
+
<module>Swiftype_Swiftype</module>
|
42 |
+
</setup>
|
43 |
+
</swiftype_setup>
|
44 |
+
</resources>
|
45 |
+
<cache>
|
46 |
+
<types>
|
47 |
+
<swiftype_autocomplete>
|
48 |
+
<label>Swiftype Autocomplete</label>
|
49 |
+
<description>Swiftype Autocomplete Cache</description>
|
50 |
+
<tags>SWIFTYPE_AUTOCOMPLETE</tags>
|
51 |
+
</swiftype_autocomplete>
|
52 |
+
</types>
|
53 |
+
</cache>
|
54 |
+
<events>
|
55 |
+
<core_config_data_save_after>
|
56 |
+
<observers>
|
57 |
+
<swiftype>
|
58 |
+
<class>swiftype/observer_global</class>
|
59 |
+
<method>clearCatalogsearchResults</method>
|
60 |
+
</swiftype>
|
61 |
+
</observers>
|
62 |
+
</core_config_data_save_after>
|
63 |
+
<core_config_data_save_commit_after>
|
64 |
+
<observers>
|
65 |
+
<swiftype_autocomplete>
|
66 |
+
<class>swiftype/observer_global</class>
|
67 |
+
<method>cleanSwiftypeAutocompleteCache</method>
|
68 |
+
</swiftype_autocomplete>
|
69 |
+
</observers>
|
70 |
+
</core_config_data_save_commit_after>
|
71 |
+
<catalog_product_save_commit_after>
|
72 |
+
<observers>
|
73 |
+
<swiftype_autocomplete>
|
74 |
+
<class>swiftype/observer_global</class>
|
75 |
+
<method>cleanSwiftypeAutocompleteCache</method>
|
76 |
+
</swiftype_autocomplete>
|
77 |
+
</observers>
|
78 |
+
</catalog_product_save_commit_after>
|
79 |
+
</events>
|
80 |
+
</global>
|
81 |
+
<frontend>
|
82 |
+
<events>
|
83 |
+
<controller_front_send_response_after>
|
84 |
+
<observers>
|
85 |
+
<swiftype_ajax_suggest>
|
86 |
+
<class>swiftype/observer_frontend</class>
|
87 |
+
<method>cacheSwiftypeAutocomplete</method>
|
88 |
+
</swiftype_ajax_suggest>
|
89 |
+
</observers>
|
90 |
+
</controller_front_send_response_after>
|
91 |
+
</events>
|
92 |
+
<routers>
|
93 |
+
<catalogsearch>
|
94 |
+
<args>
|
95 |
+
<modules>
|
96 |
+
<swiftype before="Mage_CatalogSearch">Swiftype_Swiftype</swiftype>
|
97 |
+
</modules>
|
98 |
+
</args>
|
99 |
+
</catalogsearch>
|
100 |
+
<swiftype>
|
101 |
+
<use>standard</use>
|
102 |
+
<args>
|
103 |
+
<module>Swiftype_Swiftype</module>
|
104 |
+
<frontName>swiftype</frontName>
|
105 |
+
</args>
|
106 |
+
</swiftype>
|
107 |
+
</routers>
|
108 |
+
<layout>
|
109 |
+
<updates>
|
110 |
+
<swiftype>
|
111 |
+
<file>swiftype.xml</file>
|
112 |
+
</swiftype>
|
113 |
+
</updates>
|
114 |
+
</layout>
|
115 |
+
</frontend>
|
116 |
+
<adminhtml>
|
117 |
+
<events>
|
118 |
+
<adminhtml_catalog_product_attribute_edit_prepare_form>
|
119 |
+
<observers>
|
120 |
+
<swiftype>
|
121 |
+
<class>swiftype/observer_adminhtml</class>
|
122 |
+
<method>adminhtmlCatalogProductAttributeEditPrepareForm</method>
|
123 |
+
</swiftype>
|
124 |
+
</observers>
|
125 |
+
</adminhtml_catalog_product_attribute_edit_prepare_form>
|
126 |
+
</events>
|
127 |
+
</adminhtml>
|
128 |
+
<default>
|
129 |
+
<catalog>
|
130 |
+
<search>
|
131 |
+
<engine>catalogsearch/fulltext_engine</engine>
|
132 |
+
<swiftype_autocomplete>1</swiftype_autocomplete>
|
133 |
+
<swiftype_autocomplete_limit>3</swiftype_autocomplete_limit>
|
134 |
+
</search>
|
135 |
+
</catalog>
|
136 |
+
</default>
|
137 |
+
</config>
|
app/code/community/Swiftype/Swiftype/etc/system.xml
ADDED
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<config>
|
3 |
+
<sections>
|
4 |
+
<catalog>
|
5 |
+
<groups>
|
6 |
+
<search translate="label" module="catalogsearch">
|
7 |
+
<expanded>true</expanded>
|
8 |
+
<fields>
|
9 |
+
<max_query_words translate="label comment">
|
10 |
+
<depends>
|
11 |
+
<engine>catalogsearch/fulltext_engine</engine>
|
12 |
+
</depends>
|
13 |
+
</max_query_words>
|
14 |
+
<search_type translate="label">
|
15 |
+
<depends>
|
16 |
+
<engine>catalogsearch/fulltext_engine</engine>
|
17 |
+
</depends>
|
18 |
+
</search_type>
|
19 |
+
<engine>
|
20 |
+
<label>Search Engine</label>
|
21 |
+
<frontend_type>select</frontend_type>
|
22 |
+
<source_model>swiftype/system_config_source_catalog_search_engine</source_model>
|
23 |
+
<sort_order>30</sort_order>
|
24 |
+
<show_in_default>1</show_in_default>
|
25 |
+
<show_in_website>0</show_in_website>
|
26 |
+
<show_in_store>1</show_in_store>
|
27 |
+
</engine>
|
28 |
+
<swiftype_api_key>
|
29 |
+
<label>API Key</label>
|
30 |
+
<frontend_type>password</frontend_type>
|
31 |
+
<sort_order>35</sort_order>
|
32 |
+
<show_in_default>0</show_in_default>
|
33 |
+
<show_in_website>0</show_in_website>
|
34 |
+
<show_in_store>1</show_in_store>
|
35 |
+
<depends>
|
36 |
+
<engine>swiftype/fulltext_engine</engine>
|
37 |
+
</depends>
|
38 |
+
<validate>required-entry</validate>
|
39 |
+
</swiftype_api_key>
|
40 |
+
<swiftype_engine_slug>
|
41 |
+
<label>Engine Slug</label>
|
42 |
+
<frontend_type>text</frontend_type>
|
43 |
+
<sort_order>40</sort_order>
|
44 |
+
<show_in_default>0</show_in_default>
|
45 |
+
<show_in_website>0</show_in_website>
|
46 |
+
<show_in_store>1</show_in_store>
|
47 |
+
<depends>
|
48 |
+
<engine>swiftype/fulltext_engine</engine>
|
49 |
+
</depends>
|
50 |
+
<validate>required-entry</validate>
|
51 |
+
</swiftype_engine_slug>
|
52 |
+
<swiftype_engine_key>
|
53 |
+
<label>Engine Key</label>
|
54 |
+
<frontend_type>text</frontend_type>
|
55 |
+
<sort_order>45</sort_order>
|
56 |
+
<show_in_default>0</show_in_default>
|
57 |
+
<show_in_website>0</show_in_website>
|
58 |
+
<show_in_store>1</show_in_store>
|
59 |
+
<depends>
|
60 |
+
<engine>swiftype/fulltext_engine</engine>
|
61 |
+
</depends>
|
62 |
+
<validate>required-entry</validate>
|
63 |
+
</swiftype_engine_key>
|
64 |
+
<swiftype_autocomplete>
|
65 |
+
<label>Use Swiftype Autocomplete</label>
|
66 |
+
<frontend_type>select</frontend_type>
|
67 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
68 |
+
<sort_order>50</sort_order>
|
69 |
+
<show_in_default>0</show_in_default>
|
70 |
+
<show_in_website>0</show_in_website>
|
71 |
+
<show_in_store>1</show_in_store>
|
72 |
+
<depends>
|
73 |
+
<engine>swiftype/fulltext_engine</engine>
|
74 |
+
</depends>
|
75 |
+
</swiftype_autocomplete>
|
76 |
+
<swiftype_autocomplete_limit>
|
77 |
+
<label>Autocomplete Limit</label>
|
78 |
+
<frontend_type>text</frontend_type>
|
79 |
+
<sort_order>55</sort_order>
|
80 |
+
<show_in_default>0</show_in_default>
|
81 |
+
<show_in_website>0</show_in_website>
|
82 |
+
<show_in_store>1</show_in_store>
|
83 |
+
<depends>
|
84 |
+
<engine>swiftype/fulltext_engine</engine>
|
85 |
+
<swiftype_autocomplete>1</swiftype_autocomplete>
|
86 |
+
</depends>
|
87 |
+
<validate>validate-number</validate>
|
88 |
+
</swiftype_autocomplete_limit>
|
89 |
+
</fields>
|
90 |
+
</search>
|
91 |
+
</groups>
|
92 |
+
</catalog>
|
93 |
+
</sections>
|
94 |
+
</config>
|
app/code/community/Swiftype/Swiftype/sql/swiftype_setup/install-1.php
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
$installer = $this;
|
4 |
+
/* @var $installer Mage_Core_Model_Resource_Setup */
|
5 |
+
$installer->startSetup();
|
6 |
+
|
7 |
+
$installer->getConnection()->addColumn(
|
8 |
+
$installer->getTable('catalog/eav_attribute'),
|
9 |
+
'swiftype_document_field_type',
|
10 |
+
array(
|
11 |
+
'TYPE' => Varien_Db_Ddl_Table::TYPE_TEXT,
|
12 |
+
'LENGTH' => 255,
|
13 |
+
'COMMENT' => 'Swiftype Document Field Type.',
|
14 |
+
'DEFAULT' => Swiftype_Swiftype_Helper_Data::DOCUMENT_FIELD_TYPE_STRING
|
15 |
+
));
|
16 |
+
|
17 |
+
$attributes = Mage::getResourceModel('catalog/product_attribute_collection');
|
18 |
+
/* @var $attributes Mage_Catalog_Model_Resource_Product_Attribute_Collection */
|
19 |
+
$attributes->addSearchableAttributeFilter();
|
20 |
+
|
21 |
+
foreach ($attributes as $attribute) {
|
22 |
+
/* @var $attribute Mage_Catalog_Model_Resource_Eav_Attribute */
|
23 |
+
|
24 |
+
$inputType = $attribute->getFrontend()->getInputType();
|
25 |
+
|
26 |
+
switch ($inputType) {
|
27 |
+
case 'boolean':
|
28 |
+
$swiftypeDocumentFieldType = Swiftype_Swiftype_Helper_Data::DOCUMENT_FIELD_TYPE_INTEGER;
|
29 |
+
break;
|
30 |
+
case 'date':
|
31 |
+
case 'datetime':
|
32 |
+
$swiftypeDocumentFieldType = Swiftype_Swiftype_Helper_Data::DOCUMENT_FIELD_TYPE_DATE;
|
33 |
+
break;
|
34 |
+
case 'multiselect':
|
35 |
+
case 'select':
|
36 |
+
case 'text':
|
37 |
+
$swiftypeDocumentFieldType = Swiftype_Swiftype_Helper_Data::DOCUMENT_FIELD_TYPE_STRING;
|
38 |
+
break;
|
39 |
+
case 'price':
|
40 |
+
case 'weight':
|
41 |
+
$swiftypeDocumentFieldType = Swiftype_Swiftype_Helper_Data::DOCUMENT_FIELD_TYPE_FLOAT;
|
42 |
+
break;
|
43 |
+
case 'textarea':
|
44 |
+
$swiftypeDocumentFieldType = Swiftype_Swiftype_Helper_Data::DOCUMENT_FIELD_TYPE_TEXT;
|
45 |
+
break;
|
46 |
+
default:
|
47 |
+
$swiftypeDocumentFieldType = Swiftype_Swiftype_Helper_Data::DOCUMENT_FIELD_TYPE_TEXT;
|
48 |
+
break;
|
49 |
+
}
|
50 |
+
|
51 |
+
$attribute->setData('swiftype_document_field_type', $swiftypeDocumentFieldType);
|
52 |
+
$attribute->save();
|
53 |
+
}
|
54 |
+
|
55 |
+
$installer->endSetup();
|
app/design/frontend/base/default/layout/swiftype.xml
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<layout version="0.1.0">
|
3 |
+
<catalogsearch_ajax_suggest>
|
4 |
+
<block type="swiftype/ajax_suggest" name="root" template="swiftype/ajax/suggest.phtml" />
|
5 |
+
</catalogsearch_ajax_suggest>
|
6 |
+
</layout>
|
app/design/frontend/base/default/template/swiftype/ajax/suggest.phtml
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
$helper = Mage::helper('swiftype');
|
3 |
+
/* @var $helper Swiftype_Swiftype_Helper_Data */
|
4 |
+
|
5 |
+
$products = $helper->getSuggestedProducts();
|
6 |
+
$productCount = count($products);
|
7 |
+
$suggestData = array();
|
8 |
+
$counter = 0;
|
9 |
+
$descriptionLimit = 150;
|
10 |
+
|
11 |
+
foreach ($products as $product) {
|
12 |
+
/* @var $product Mage_Catalog_Model_Product */
|
13 |
+
$suggestDatum = array(
|
14 |
+
'product' => $product,
|
15 |
+
'name' => $product->getName(),
|
16 |
+
'title' => $product->getName(),
|
17 |
+
'href' => $product->getUrlInStore(),
|
18 |
+
'description' => (strlen($product->getShortDescription()) > $descriptionLimit) ?
|
19 |
+
substr($product->getShortDescription(), 0, $descriptionLimit)."..." : $product->getShortDescription(),
|
20 |
+
'onClick' => $helper->getOnClickAutoselect($product)
|
21 |
+
);
|
22 |
+
|
23 |
+
if ($counter == 1) {
|
24 |
+
$suggestDatum['row_class'] = $suggestDatum['row_class'] . ' first';
|
25 |
+
} elseif ($counter == $productCount) {
|
26 |
+
$suggestDatum['row_class'] = $suggestDatum['row_class'] . ' last';
|
27 |
+
}
|
28 |
+
|
29 |
+
$suggestData[] = $suggestDatum;
|
30 |
+
}
|
31 |
+
?>
|
32 |
+
<?php if ($productCount) : ?>
|
33 |
+
<ul>
|
34 |
+
<li style="display:none"></li>
|
35 |
+
<?php foreach ($suggestData as $suggestDatum) : ?>
|
36 |
+
<li title="<?php echo str_replace('"', '', $suggestDatum['title']);?>" class="<?php echo str_replace('"', '', $suggestDatum['row_class']); ?>" style="background: #fff;">
|
37 |
+
<a href="<?php echo $suggestDatum['href']; ?>" onClick="<?php echo $suggestDatum['onClick']; ?>" style="display: block; position: relative; background: #fff; text-decoration: none; margin: 0; padding: 0 0 6px;">
|
38 |
+
<img style="position: absolute; left: -2px; top: 2px; margin: 0; border: 0;" src="<?php echo $this->helper('catalog/image')->init($suggestDatum['product'], 'thumbnail')->resize(56, 56); ?>" width="56" height="56"/>
|
39 |
+
<div style="padding: 8px 5px 0 60px; font-size: 11px; line-height: 1.4; font-weight: bold;"><?php echo htmlentities($suggestDatum['name']); ?></div>
|
40 |
+
<div style="padding: 2px 5px 5px 60px; min-height: 36px; overflow: hidden; font-size: 10px; line-height: 1.33; color: #777;"><?php echo htmlentities($suggestDatum['description']); ?></div>
|
41 |
+
</a>
|
42 |
+
</li>
|
43 |
+
<?php endforeach; ?>
|
44 |
+
</ul>
|
45 |
+
<?php endif; ?>
|
app/etc/modules/Swiftype_Swiftype.xml
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<config>
|
3 |
+
<modules>
|
4 |
+
<Swiftype_Swiftype>
|
5 |
+
<codePool>community</codePool>
|
6 |
+
<active>true</active>
|
7 |
+
</Swiftype_Swiftype>
|
8 |
+
</modules>
|
9 |
+
</config>
|
app/etc/swiftype.xml
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<config>
|
3 |
+
<global>
|
4 |
+
<cache>
|
5 |
+
<request_processors>
|
6 |
+
<swiftype>Swiftype_Swiftype_Model_Request_Processor</swiftype>
|
7 |
+
</request_processors>
|
8 |
+
</cache>
|
9 |
+
</global>
|
10 |
+
</config>
|
package.xml
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<package>
|
3 |
+
<name>Swiftype_Swiftype</name>
|
4 |
+
<version>1.0.0</version>
|
5 |
+
<stability>stable</stability>
|
6 |
+
<license uri="http://www.gnu.org/licenses/agpl.html">AGPL</license>
|
7 |
+
<channel>community</channel>
|
8 |
+
<extends/>
|
9 |
+
<summary>Great search for your Magento store.</summary>
|
10 |
+
<description>Swiftype provides great search for you Magento store. Some of the features that make search experience better with Swiftype:
|
11 |
+

|
12 |
+
* Powerful Search: Quick and relevant search for your online store.
|
13 |
+

|
14 |
+
* Drag-and-drop result ranking: We work hard to return the most relevant results by default for every search query, but sometimes you'll want to make your own customizations. Simply perform the search in our dashboard then drag-and-drop the results to re-order them.
|
15 |
+

|
16 |
+
* Autocomplete: Sometimes a search isn't even necessary; our search engines come with autocomplete built-in, and your users will thank you for having it.</description>
|
17 |
+
<notes>Changelog:
|
18 |
+

|
19 |
+
* Bumped to 1.0.0 version in anticipation of Magento Connect initial release.</notes>
|
20 |
+
<authors><author><name>Swiftype</name><user>swiftypeteam</user><email>team@swiftype.com</email></author></authors>
|
21 |
+
<date>2014-06-12</date>
|
22 |
+
<time>16:56:29</time>
|
23 |
+
<contents><target name="magecommunity"><dir name="Swiftype"><dir name="Swiftype"><dir name="Block"><dir name="Ajax"><file name="Suggest.php" hash="e5b55a9c41709eeffe31a6ea266876bc"/></dir><file name="Autocomplete.php" hash="f42063444facdccc951700591a82f8ca"/></dir><dir name="Helper"><file name="Data.php" hash="71cb37ad290d00ef577fb66b6cc8a0a5"/><file name="Log.php" hash="544a2a7075d3dec2d8c81eef0656f8a4"/></dir><dir name="Model"><dir name="Observer"><file name="Adminhtml.php" hash="6a1420a1fe9c7a7d7f3b90b5260af196"/><file name="Frontend.php" hash="923f4348d2b2785dfca43df9f2355e40"/><file name="Global.php" hash="8764a09f34b456cb729543616e0de889"/></dir><dir name="Request"><file name="Processor.php" hash="ca7fbb10d1dc0920ddb9605f7c9e310c"/></dir><dir name="Resource"><dir name="Fulltext"><file name="Engine.php" hash="5d95d1b7ea2d13c05478c4fec69d27d5"/></dir><file name="Fulltext.php" hash="c8117f47d91906e258d2000548befe1d"/></dir><dir name="System"><dir name="Config"><dir name="Source"><dir name="Catalog"><dir name="Search"><file name="Engine.php" hash="a9faa3a31d39cedf2e20fa6e50cc1a66"/></dir></dir></dir></dir></dir></dir><dir name="controllers"><file name="AjaxController.php" hash="0d61e11d4d332041f75981304546ff1b"/><file name="AnalyticsController.php" hash="8c8742944ddcf89182f6a03f49e747c4"/></dir><dir name="etc"><file name="config.xml" hash="3227643a18db99d75417eea199ed136c"/><file name="system.xml" hash="a372d79b32358f00aac38cf8864ca715"/></dir><dir name="sql"><dir name="swiftype_setup"><file name="install-1.php" hash="720c6d503a3493b9be8e34ff9af49528"/></dir></dir></dir></dir></target><target name="magedesign"><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file name="swiftype.xml" hash="b32acb6177dbf205ede8e0b0c2601705"/></dir><dir name="template"><dir name="swiftype"><dir name="ajax"><file name="suggest.phtml" hash="5c527591144181cc4615efd806a128d6"/></dir></dir></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Swiftype_Swiftype.xml" hash="6894235a6d3edae4c2f5aa04407274d6"/></dir><dir name="."><file name="swiftype.xml" hash="20e640f1fa6945f853c2d29e3c2f94d9"/></dir></target></contents>
|
24 |
+
<compatible/>
|
25 |
+
<dependencies><required><php><min>5.3.0</min><max>5.7.0</max></php></required></dependencies>
|
26 |
+
</package>
|