public function execute() { $search = new shopIndexSearch(); if (waRequest::param(0)) { $search->indexProduct(waRequest::param(0)); } else { $product_model = new shopProductModel(); $n = $product_model->countAll(); $limit = 100; $i = 0; $product_model->exec("TRUNCATE TABLE shop_search_index"); while ($i < $n) { echo $i . "/" . $n . "\n"; $sql = "SELECT p.*, t.name type_name FROM " . $product_model->getTableName() . " p\n LEFT JOIN shop_type t ON p.type_id = t.id\n LIMIT " . $i . ", " . $limit; $products = $product_model->query($sql)->fetchAll('id'); $product_ids = array_keys($products); // get skus $sql = "SELECT * FROM shop_product_skus WHERE product_id IN (i:id)"; $data = $product_model->query($sql, array('id' => $product_ids)); foreach ($data as $row) { $products[$row['product_id']]['skus'][] = $row; } // get tags $sql = "SELECT pt.product_id, t.name FROM shop_product_tags pt\n JOIN shop_tag t ON pt.tag_id = t.id WHERE pt.product_id IN (i:id)"; $data = $product_model->query($sql, array('id' => $product_ids)); foreach ($data as $row) { $products[$row['product_id']]['tags'][] = $row['name']; } // get features $sql = "SELECT pf.product_id, fv.value FROM shop_product_features pf\n JOIN shop_feature f ON pf.feature_id = f.id AND f.type = 'varchar'\n JOIN shop_feature_values_varchar fv ON pf.feature_value_id = fv.id WHERE pf.product_id IN (i:id)"; $data = $product_model->query($sql, array('id' => $product_ids)); foreach ($data as $row) { $products[$row['product_id']]['features'][] = $row['value']; } $sql = "SELECT pf.product_id, fv.value FROM shop_product_features pf\n JOIN shop_feature f ON pf.feature_id = f.id AND f.type = 'double'\n JOIN shop_feature_values_double fv ON pf.feature_value_id = fv.id WHERE pf.product_id IN (i:id)"; $data = $product_model->query($sql, array('id' => $product_ids)); foreach ($data as $row) { $products[$row['product_id']]['features'][] = $row['value']; } $sql = "SELECT pf.product_id, fv.value FROM shop_product_features pf\n JOIN shop_feature f ON pf.feature_id = f.id AND f.type = 'text'\n JOIN shop_feature_values_text fv ON pf.feature_value_id = fv.id WHERE pf.product_id IN (i:id)"; $data = $product_model->query($sql, array('id' => $product_ids)); foreach ($data as $row) { $products[$row['product_id']]['features'][] = $row['value']; } // get skus $sql = "SELECT * FROM shop_product_skus WHERE product_id IN (i:id)"; $data = $product_model->query($sql, array('id' => $product_ids)); foreach ($data as $row) { $products[$row['product_id']]['skus'][] = $row; } foreach ($products as $p) { $search->indexProduct($p, false); } $i += $limit; } } }
protected function step() { $limit = 10; $products = $this->product_model->select('id')->order('id')->limit("{$this->data['offset']}, {$limit}")->fetchAll(); foreach ($products as $p) { $this->data['offset'] += 1; try { // DO something with product $p $this->search_index->indexProduct($p['id']); } catch (Exception $e) { $this->error($e->getMessage()); } } sleep(1); }
/** * @return shopSearchWordModel */ protected function getWordModel() { if (!self::$word_model) { self::$word_model = new shopSearchWordModel(); } return self::$word_model; }
protected function searchPrepare($query, $auto_title = true) { $query = urldecode($query); $i = $offset = 0; $query_parts = array(); while (($j = strpos($query, '&', $offset)) !== false) { // escaped & if ($query[$j - 1] != '\\') { $query_parts[] = str_replace('\\&', '&', substr($query, $i, $j - $i)); $i = $j + 1; } $offset = $j + 1; } $query_parts[] = str_replace('\\&', '&', substr($query, $i)); $model = $this->getModel(); $title = array(); foreach ($query_parts as $part) { if (!($part = trim($part))) { continue; } $parts = preg_split("/(\\\$=|\\^=|\\*=|==|!=|>=|<=|=|>|<)/uis", $part, 2, PREG_SPLIT_DELIM_CAPTURE); if ($parts) { if ($parts[0] == 'category_id') { if ($parts[1] == '==' && $parts[2] == 'null') { $this->where[] = 'p.category_id IS NULL'; $title[] = 'without category'; } else { $this->addJoin('shop_category_products', null, ':table.category_id' . $this->getExpression($parts[1], $parts[2])); $title[] = "category_id " . $parts[1] . $parts[2]; } } elseif ($parts[0] == 'query') { $search = new shopIndexSearch(); $word_ids = $search->getWordIds($parts[2], true); if ($word_ids) { $this->joins[] = array('table' => 'shop_search_index', 'alias' => 'si'); $this->where[] = 'si.word_id IN (' . implode(",", $word_ids) . ')'; if (count($word_ids) > 1) { $this->fields[] = "SUM(si.weight) AS weight"; $this->order_by = 'weight DESC'; $this->group_by = 'p.id'; } else { $this->fields[] = "si.weight"; $this->order_by = 'si.weight DESC'; } } elseif ($parts[2]) { $this->where[] = '0'; } $this->prepared = true; // if not found try find by name if (!$this->count()) { $this->count = null; $this->joins = $this->where = $this->having = $this->fields = array(); if ($this->is_frontend) { if ($this->filtered) { $this->filtered = false; } $this->frontendConditions(); } $this->order_by = 'p.create_datetime DESC'; $this->group_by = null; $q = $model->escape($parts[2], 'like'); $this->addJoin('shop_product_skus', null, "(p.name LIKE '%" . $q . "%' OR :table.name LIKE '%" . $q . "%' OR :table.sku LIKE '%" . $q . "%')"); $this->group_by = 'p.id'; return; } elseif ($word_ids) { $result = $this->getProducts('*', 0, 1); $p = array_shift($result); $w = str_replace(',', '.', 0.3 * $p['weight']); if (count($word_ids) > 1) { $this->having[] = 'SUM(si.weight) >= ' . $w; } else { $this->where[] = 'weight >= ' . $w; } $this->count = null; } $title[] = $parts[0] . $parts[1] . $parts[2]; } elseif ($parts[0] == 'tag') { $tag_model = $this->getModel('tag'); if (strpos($parts[2], '||') !== false) { $tags = explode('||', $parts[2]); $tag_ids = $tag_model->getIds($tags); } else { $sql = "SELECT id FROM " . $tag_model->getTableName() . " WHERE name" . $this->getExpression($parts[1], $parts[2]); $tag_ids = $tag_model->query($sql)->fetchAll(null, true); } if ($tag_ids) { $this->addJoin('shop_product_tags', null, ":table.tag_id IN ('" . implode("', '", $tag_ids) . "')"); } else { $this->where[] = "0"; } } elseif ($model->fieldExists($parts[0])) { $title[] = $parts[0] . $parts[1] . $parts[2]; $this->where[] = 'p.' . $parts[0] . $this->getExpression($parts[1], $parts[2]); } elseif ($parts[1] == '=') { $code = $parts[0]; $is_value_id = false; if (substr($code, -9) == '.value_id') { $code = substr($code, 0, -9); $is_value_id = true; } $feature_model = $this->getModel('feature'); $f = $feature_model->getByCode($code); if ($f) { if ($is_value_id) { $value_id = $parts[2]; } else { $values_model = $feature_model->getValuesModel($f['type']); $value_id = $values_model->getValueId($f['id'], $parts[2]); } $this->addJoin('shop_product_features', null, ':table.feature_id = ' . $f['id'] . ' AND :table.feature_value_id = ' . (int) $value_id); $this->group_by = 'p.id'; } } } } if ($title) { $title = implode(', ', $title); // Strip slashes from search title. $bs = '\\\\'; $title = preg_replace("~{$bs}(_|%|&|{$bs})~", '\\1', $title); } if ($auto_title) { $this->addTitle($title, ' '); } }
/** * Saves product data to database. * * @param array $data * @return bool Whether saved successfully */ public function save($data = array(), $validate = true, &$errors = array()) { $result = false; $id = $this->getId(); $search = new shopIndexSearch(); foreach ($data as $name => $value) { // name have to be not empty if ($name == 'name' && !$value) { $value = _w('New product'); } // url have to be not empty if ($name == 'url' && !$value && $id) { $value = $id; } $this->__set($name, $value); } if ($this->is_dirty) { $product = array(); $id_changed = !empty($this->is_dirty['id']); foreach ($this->is_dirty as $field => $v) { if ($this->model->fieldExists($field)) { $product[$field] = $this->data[$field]; unset($this->is_dirty[$field]); } } if ($id && !$id_changed) { if (!isset($product['edit_datetime'])) { $product['edit_datetime'] = date('Y-m-d H:i:s'); } if (isset($product['type_id'])) { $this->model->updateType($id, $product['type_id']); unset($product['type_id']); } if ($this->model->updateById($id, $product)) { $this->saveData($errors); $search->onUpdate($id); $this->is_dirty = array(); $result = true; } } else { if (!isset($product['contact_id'])) { $product['contact_id'] = wa()->getUser()->getId(); } if (!isset($product['create_datetime'])) { $product['create_datetime'] = date('Y-m-d H:i:s'); } if (!isset($product['currency'])) { $product['currency'] = wa('shop')->getConfig()->getCurrency(); } if ($id = $this->model->insert($product)) { $this->data['id'] = $id; // update empty url by ID if (empty($product['url'])) { $this->data['url'] = $id; $this->model->updateById($id, array('url' => $this->data['url'])); } $this->saveData(); $search->onAdd($id); $this->is_dirty = array(); if (!empty($this->data['type_id'])) { $type_model = new shopTypeModel(); // increment on +1 $type_model->incCounters(array($this->data['type_id'] => 1)); } $result = true; } } } else { $result = true; } $params = array('data' => $this->getData(), 'instance' => &$this); /** * Plugin hook for handling product entry saving event * @event product_save * * @param array [string]mixed $params * @param array [string][string]mixed $params['data'] raw product data fields (see shop_product table description and related storages) * @param array [string][string]int $data['data']['id'] product ID * @param array [string]shopProduct $params['instance'] current shopProduct entry instance (avoid recursion) * @return void */ wa()->event('product_save', $params); return $result; }