public function findProducts(ListingFilter $filter) { $must = []; if ($filter->getEshop() !== null) { $must[] = ["term" => [ProductMeta::ESHOP_ID => (string) $filter->getEshop()->getId()]]; } if ($filter->getCategory() !== null) { /** @var Category[] $childrenCategories */ $childrenCategories = $this->categoryRepository->find([CategoryMeta::PATH => $filter->getCategory()->getId()]); $must[] = ["terms" => [ProductMeta::CATEGORY_IDS => array_merge([(string) $filter->getCategory()->getId()], array_map(function (Category $category) { return (string) $category->getId(); }, $childrenCategories))]]; } $body = ["query" => ["filtered" => ["filter" => ["bool" => ["must" => $must]]]], "from" => $filter->getOffset(), "size" => $filter->getLimit(), "sort" => ["_score" => "desc"]]; if ($filter->getQ() !== null) { $body["query"]["filtered"]["query"] = ["multi_match" => ["query" => $filter->getQ(), "fields" => [ProductMeta::NAME . "^5", ProductMeta::LONG_NAME . "^5", ProductMeta::DESCRIPTION, ProductMeta::MANUFACTURER . "^2", ProductMeta::BRAND . "^2", ProductMeta::ESHOP . "." . EshopMeta::NAME . "^2"]]]; } // if (empty($body["query"]["filtered"]["filter"]["bool"]["must"])) { // unset($body["query"]["filtered"]["filter"]); // } $response = $this->elasticsearch->search(["index" => $this->catalogIndexAliasName, "type" => ProductMeta::SHORT_NAME, "body" => $body]); if (!isset($response["hits"]["hits"])) { throw new \RuntimeException("Response does not have hits->hits. Got: " . json_encode($response)); } $products = []; foreach ($response["hits"]["hits"] as $hit) { $products[] = ProductMeta::fromArray($hit["_source"], "json:"); } return $products; }
public function handleMessage(Change $change, Message $message, Channel $channel) { if (!$change->getProduct()) { throw new \InvalidArgumentException("Badly routed message '{$message->content}' with routing key '{$message->routingKey}'."); } $product = $change->getProduct(); /** @var Eshop $eshop */ $eshop = $this->eshopRepository->getOneById($product->getEshopId()); $product->setEshop($eshop); $categoryIds = $product->getCategoryIds(); if (!empty($categoryIds)) { $product->setCategories($this->categoryRepository->find(["_id" => ['$in' => $product->getCategoryIds()]])); } if (!$this->elasticsearch->indices()->existsAlias(["name" => $this->catalogIndexAliasName])) { $this->initIndex(); } $response = $this->elasticsearch->index(["index" => $this->catalogIndexAliasName, "type" => ProductMeta::SHORT_NAME, "id" => (string) $product->getId(), "version" => $product->getV(), "version_type" => "external_gte", "body" => ProductMeta::toObject($product, "json:")]); $this->log->info("Indexed Product#{$product->getId()} (v={$product->getV()}, created=" . json_encode($response["created"]) . ")."); $channel->ack($message); }
public function handleMessage(Import $import, Message $message, Channel $channel) { if (!$import->getTmpFileName()) { $this->log->error("Import w/o tmp file name: {$message->content}."); $channel->ack($message); return; } if (!file_exists($import->getTmpFileName())) { $this->log->error("Tmp file name '{$import->getTmpFileName()}' does not exist."); $channel->ack($message); return; } $this->log->info("Got " . $message->content); // TODO: error handling $handle = fopen($import->getTmpFileName(), "r+"); while (fread($handle, 3) === "") { fseek($handle, -3, SEEK_CUR); fwrite($handle, " "); $this->log->info("Removed BOM in file '{$import->getTmpFileName()}'."); } fseek($handle, 0, SEEK_SET); $data = fread($handle, 1024); if (($sp = strpos($data, "<?xml")) !== false) { if (($ep = strpos($data, "?>")) !== false) { $newData = substr($data, $sp, $ep - $sp + 2) . str_repeat(" ", $sp) . substr($data, $ep + 2); fseek($handle, 0, SEEK_SET); fwrite($handle, $newData); } } fclose($handle); $eshopId = $import->getEshop()->getId(); $reader = new \XMLReader(); $reader->open($import->getTmpFileName()); while ($reader->read()) { if (strtoupper($reader->name) !== "SHOPITEM") { continue; } $item = @$reader->expand(); if ($item === false) { $this->log->error("XMLReader error: " . json_encode(libxml_get_last_error())); break; } $reader->next(); $product = new Product(); $product->setEshopId($eshopId); foreach ($item->childNodes as $child) { /** @var \DOMNode $child */ if ($child->nodeType !== XML_ELEMENT_NODE) { continue; } $textContent = trim($child->textContent); if (empty($textContent)) { $textContent = null; } switch ($name = strtoupper($child->nodeName)) { case "ITEM_GROUP_ID": $product->setItemGroupId($textContent); break; case "ITEM_ID": $product->setItemId($textContent); break; case "PRODUCTNAME": $product->setName($textContent); break; case "PRODUCT": $product->setLongName($textContent); break; case "DESCRIPTION": $product->setDescription($textContent); break; case "URL": // TODO: normalize URL $product->setUrl($textContent); break; case "PRICE_VAT": $product->setPrice(floatval(preg_replace("/[^0-9.]+/", "", str_replace(",", ".", $textContent)))); break; case "DELIVERY_DATE": $product->setDeliveryDate(intval(preg_replace("/[^0-9]+/", "", $textContent))); break; case "IMGURL": case "IMGURL_ALTERNATIVE": // TODO: normalize URL $image = new Image(); $image->setUrl($textContent); $product->addImage($image); break; case "EAN": $product->setEan($textContent); break; case "ISBN": $product->setIsbn($textContent); break; case "PRODUCTNO": $product->setProductno($textContent); break; case "MANUFACTURER": $product->setManufacturer($textContent); break; case "BRAND": $product->setBrand($textContent); break; case "CATEGORYTEXT": if (!empty($textContent)) { $product->addCategoryText($textContent); } break; case "ITEM_TYPE": try { $product->setItemType(ProductItemTypeEnum::fromXML($textContent)); } catch (\InvalidArgumentException $e) { $this->log->warning("Got exception while assigning ITEM_TYPE: " . $e->getMessage()); } break; case "EXTRA_MESSAGE": try { $product->addExtraMessage(ProductExtraMessageEnum::fromXML($textContent)); } catch (\InvalidArgumentException $e) { $this->log->warning("Got exception while assigning EXTRA_MESSAGE: " . $e->getMessage()); } break; } } if ($product->getUrl() === null) { $this->log->warning("Skipping product without URL: " . ProductMeta::toJson($product)); continue; } if ($product->getName() === null) { if ($product->getLongName() === null) { $this->log->warning("Skipping product without PRODUCT/PRODUCTNAME: " . ProductMeta::toJson($product)); continue; } else { $product->setName($product->getLongName()); } } if ($product->getItemId() === null) { $product->setItemId($product->getUrl()); } if ($product->getItemGroupId() === null) { $product->setItemGroupId($product->getItemId()); } for (;;) { $existing = $this->productRepository->findOneFromEshop($product); if (!$existing) { $this->fillCategoryIds($product); $ret = $this->productRepository->insert($product); if (isset($ret["ok"]) && $ret["ok"]) { $this->changeProducer->publish(Change::create()->setProduct($product), RoutingKeys::CHANGE_PRODUCT_CREATE); break; } } else { $this->mergeProducts($product, $existing); $this->fillCategoryIds($product); $ret = $this->productRepository->update(["_id" => $existing->getId(), "v" => $existing->getV()], ProductMeta::toArray($product)); if (isset($ret["ok"]) && $ret["ok"] && isset($ret["updatedExisting"]) && $ret["updatedExisting"]) { $this->changeProducer->publish(Change::create()->setProduct($product), RoutingKeys::CHANGE_PRODUCT_UPDATE); break; } } } } // TODO: delete products not present in feed $reader->close(); libxml_clear_errors(); unlink($import->getTmpFileName()); $channel->ack($message); }
/** * Serializes \CC15\MQ\VO\Change to object * * @param Change $object * @param string $group * * @throws \InvalidArgumentException * * @return object */ public static function toObject($object, $group = NULL) { if ($object === null) { return null; } if (!isset(self::$groups[$group])) { throw new \InvalidArgumentException('Group \'' . $group . '\' not supported for ' . 'CC15\\MQ\\VO\\Change' . '.'); } else { $id = self::$groups[$group]; } if (!$object instanceof Change) { throw new \InvalidArgumentException('You have to pass object of class CC15\\MQ\\VO\\Change.'); } $output = array(); if (($id & 1) > 0) { $output['product'] = ProductMeta::toObject($object->product, $group); } if (($id & 2) > 0 && isset($object->product)) { $output['product'] = ProductMeta::toObject($object->product, $group); } if (($id & 1) > 0) { $output['category'] = CategoryMeta::toObject($object->category, $group); } if (($id & 2) > 0 && isset($object->category)) { $output['category'] = CategoryMeta::toObject($object->category, $group); } return (object) $output; }
protected function createMeta() { return ProductMeta::getInstance(); }