Guest User

Untitled

a guest
Jul 16th, 2018
97
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.39 KB | None | 0 0
  1. <?php namespace Matchish\Sitesearch;
  2.  
  3. use Backend\Classes\Controller;
  4. use ElasticSearcher\ElasticSearcher;
  5. use ElasticSearcher\Environment;
  6. use Illuminate\Support\Collection;
  7. use Matchish\Sitesearch\Classes\Indices\ProductsIndex;
  8. use Matchish\Sitesearch\Classes\Queries\InstantSearchWithSuggestionsQuery;
  9. use Matchish\Sitesearch\Classes\Queries\ProductsQueryWithAggregations;
  10. use Matchish\Sitesearch\Classes\Support\TextLangCorrect;
  11. use Matchish\Sitesearch\Classes\Support\Url;
  12. use Matchish\Sitesearch\Components\ProductsFilter;
  13. use Matchish\Sitesearch\Contracts\Category;
  14. use Matchish\Sitesearch\Contracts\Characteristic;
  15. use Matchish\Sitesearch\Contracts\CharacteristicValue;
  16. use Matchish\Sitesearch\Contracts\Product;
  17. use Matchish\Sitesearch\Jobs\FetchCatalogPage;
  18. use Matchish\Sitesearch\Jobs\Reindex;
  19. use Model;
  20. use System\Classes\PluginBase;
  21.  
  22. class Plugin extends PluginBase
  23. {
  24.  
  25. public $require = ['Samorai.Catalog'];
  26.  
  27. public function registerComponents()
  28. {
  29. return [
  30. Components\SearchInput::class => Components\SearchInput::IDENT,
  31. Components\ProductsFilter::class => Components\ProductsFilter::IDENT,
  32. Components\SortBy::class => Components\SortBy::IDENT,
  33. ];
  34. }
  35.  
  36. public function registerMarkupTags()
  37. {
  38. return [
  39. 'functions' => [
  40. 'productsWithCharacteristicsUrl' => function ($category, $value) {
  41. //TODO: убрать хардкод
  42. return Url::to('catalog/category', $category, null, new Collection([$value]));
  43. }
  44. ],
  45. 'filters' => [
  46. 'groupByFrontName' => function($items) {
  47. //Так как значения характеристик с однинаковыми front_name считаем за одно же, поэтому обьединяем их
  48. //TODO: абстрация дала течь нужно придумать другую. Не нравится что нужно обьединять характеристики с одинаковыми front_name
  49. //потому что у этих значений свои sort_order итп
  50. $result = [];
  51. foreach ($items as $item) {
  52. $frontName = $item->front_name ? $item->front_name : $item->value;
  53. if (array_key_exists($frontName, $result)) {
  54. $result[$frontName]->id = $result[$frontName]->id . '|' . $item->id;
  55. $result[$frontName]->products_count = $result[$frontName]->products_count + $item->products_count;
  56. } else {
  57. $result[$frontName] = $item;
  58. }
  59. }
  60. return $result;
  61. }
  62. ]
  63. ];
  64. }
  65.  
  66. public function registerSettings()
  67. {
  68. return [
  69. 'settings' => [
  70. 'label' => 'matchish.sitesearch::lang.settings.label',
  71. 'description' => 'matchish.sitesearch::lang.settings.description',
  72. 'icon' => 'icon-search',
  73. 'class' => Models\Settings::class,
  74. 'order' => 500,
  75. 'keywords' => 'search filters',
  76. ],
  77. ];
  78. }
  79.  
  80. public function register()
  81. {
  82. $this->app->bind(Characteristic::class, \Samorai\Catalog\Models\Characteristic::class);
  83. $this->app->bind(CharacteristicValue::class, \Samorai\Catalog\Models\CharacteristicValue::class);
  84. $this->app->bind(Product::class, \Samorai\Catalog\Models\Product::class);
  85. $this->app->bind(Category::class, \Samorai\Catalog\Models\Category::class);
  86.  
  87. $this->app->bind('ProductsQuery', function () {
  88. return new ProductsQueryWithAggregations(app('SiteSearcher'));
  89. });
  90. $this->app->bind('InstantSearchQuery', function () {
  91. return new InstantSearchWithSuggestionsQuery(app('SiteSearcher'));
  92. });
  93. $this->app->singleton('SiteSearcher', function () {
  94. $env = new Environment(
  95. config('matchish.sitesearch::env')
  96. );
  97. $searcher = new ElasticSearcher($env);
  98. $productsIndex = new ProductsIndex;
  99. $searcher->indicesManager()->register($productsIndex);
  100.  
  101. return $searcher;
  102. });
  103.  
  104. }
  105.  
  106. public function boot()
  107. {
  108. Model::extend(function ($model) {
  109. $model->bindEvent('model.afterSave', function () use ($model) {
  110. $models = [
  111. \Samorai\Catalog\Models\Product::class,
  112. \Samorai\Catalog\Models\Category::class,
  113. \Samorai\Catalog\Models\Characteristic::class,
  114. \Samorai\Catalog\Models\CharacteristicValue::class,
  115. ];
  116. if (in_array(get_class($model), $models)) {
  117. $config = config('matchish.sitesearch::models.products');
  118. $job = new Reindex($config['index'], $config['model'], $config['type']);
  119. dispatch($job);
  120. }
  121. });
  122. });
  123.  
  124. \Event::listen('cms.page.init', function ($controller, $page) {
  125. //TODO: вынести в класс. зарегистрировать в зависимостях
  126. /** @var $page \Cms\Classes\Page */
  127. if (!($page
  128. && $page->hasComponent(ProductsFilter::IDENT)
  129. && $controller->getAjaxHandler() != 'onInstantSearch')
  130. ) {
  131. return;
  132. }
  133. $category = null;
  134. $characteristicsValues = null;
  135.  
  136. $categorySlug = $controller->param('categories_slug');
  137. if ($categorySlug) {
  138. # TODO: get category from page data if it exists
  139. $category = app(Category::class)->findBySlug($categorySlug);
  140. if (!$category) {
  141. return $controller->run('404');
  142. }
  143. } else {
  144. if (post('category_id')) {
  145. $category = app(Category::class)->find(post('category_id'));
  146. } else {
  147. $category = app(Category::class)->first();
  148. }
  149. }
  150. $ids = array_map(function ($item) {
  151. return explode('|', $item);
  152. }, request()->input('filters', []));
  153. if ($ids) {
  154. $ids = call_user_func_array('array_merge', $ids);
  155. }
  156. if ($controller->getAjaxHandler() == 'onFilter') {
  157. $characteristicsValues = app(CharacteristicValue::class)->with('characteristic')->findMany($ids);
  158. } else {
  159. $filtersSlug = $controller->param('filters');
  160. if ($filtersSlug) {
  161. $aliases = explode('-', $filtersSlug);
  162. $characteristicsValues = app(CharacteristicValue::class)
  163. ->with('characteristic')->findManyBySlug($aliases);
  164. if ($filtersSlug !== Url::getFilterSlug($characteristicsValues)) {
  165. return $controller->run('404');
  166. }
  167. }
  168. }
  169. $ranges = request()->input('ranges', []);
  170.  
  171. $term = request()->input('q', '');
  172. if ($term) {
  173. $controller->vars['term'] = $term;
  174. }
  175.  
  176. #TODO: there are no $page->{pageNumber,productPerPage} because component have start after cms.page.init
  177. $pageNumber = request()->input('page', $page->pageNumber);
  178. $defaultPerPage = 20;
  179. $productPerPage = request()->input('limit', $defaultPerPage);
  180. $sort = request()->input('sort', []);
  181.  
  182. $params = [];
  183. $params['category'] = $category;
  184. $params['characteristics_values'] = $characteristicsValues;
  185. $params['term'] = $term;
  186. $params['ranges'] = $ranges;
  187. $params['page'] = $pageNumber;
  188. $params['size'] = $productPerPage;
  189. $params['sort'] = $sort;
  190. $params['tags'] = null;
  191.  
  192. $cacheKey = serialize([
  193. 'matchish.sitesearch.plugin',
  194. 'category_id' => $category ? $category->id : null,
  195. 'values_ids' => $characteristicsValues ? $characteristicsValues->pluck('id')->all() : null,
  196. 'ranges' => $ranges,
  197. 'term' => $term,
  198. 'size' => $productPerPage,
  199. 'sort' => $sort,
  200. 'page' => $pageNumber,
  201. ]);
  202.  
  203. $job = new FetchCatalogPage($params);
  204. $cacheTags = [
  205. app(Product::class)->getTable(),
  206. app(Category::class)->getTable(),
  207. app(Characteristic::class)->getTable(),
  208. app(CharacteristicValue::class)->getTable(),
  209. ];
  210.  
  211. list($categoriesStatistics, $products, $filter) = \Cache::tags($cacheTags)->rememberForever($cacheKey,
  212. function () use ($job, $controller) {
  213. $response = $job->handle();
  214. $filter = $response->getCharacteristicsAggregations();
  215.  
  216. $products = $response->getResults();
  217.  
  218. $categoriesStatistics = $response->getCategoriesAggregations();
  219.  
  220. return [
  221. $categoriesStatistics,
  222. $products,
  223. //TODO: Можно кешировать партиал фильтра.
  224. //данные нигде не используются кроме как в этом партиале
  225. // а дополнительный запрос в кеш идет в компоненте.
  226. // Экономия 30 мс у меня на ноуте
  227. $filter,
  228. ];
  229.  
  230. });
  231.  
  232. $url = $filter->getUrl($page->getBaseFileName(), $category, $term);
  233. $parsed = parse_url($url);
  234. if (array_key_exists('path', $parsed)) {
  235. $products->setPath($parsed['path']);
  236. }
  237. if (array_key_exists('query', $parsed)) {
  238. parse_str($parsed['query'], $queryArr);
  239.  
  240. $products->appends($queryArr);
  241. }
  242. if ($productPerPage != $defaultPerPage) {
  243. $products->appends(['limit' => $productPerPage]);
  244. }
  245.  
  246. if ($term) {
  247. if (!$products->total()) {
  248. $corrector = new TextLangCorrect;
  249. $correctedTerm = $corrector->parse($term, $corrector::KEYBOARD_LAYOUT);
  250. if ($correctedTerm !== $term) {
  251. $controller->vars['correctedTerm'] = $correctedTerm;
  252. }
  253. } else {
  254. $query = Models\SearchQuery::firstOrCreate(['text' => mb_strtolower($term)]);
  255. $query->frequency = $query->frequency + 1;
  256. $query->hits = $products->total();
  257. $query->update();
  258. }
  259. }
  260. $controller->vars['sort'] = $sort;
  261. $controller->vars['products'] = $products;
  262. $controller->vars['productsList'] = new \Matchish\ProductCompare\ViewModels\ProductsList($products->all());
  263. $controller->vars['filter'] = $filter;
  264. $controller->vars['categoriesStatistics'] = $categoriesStatistics;
  265. $controller->vars['category'] = $category;
  266. });
  267. }
  268. }
Add Comment
Please, Sign In to add comment