private function stepImportImage() { /** * @var shopProductImagesModel $model */ static $model; if (!is_array($this->data['map'][self::STAGE_IMAGE]) && $this->data['map'][self::STAGE_IMAGE]) { $this->data['map'][self::STAGE_IMAGE] = array($this->data['map'][self::STAGE_IMAGE]); } if ($file = reset($this->data['map'][self::STAGE_IMAGE])) { if (!$model) { $model = new shopProductImagesModel(); } //TODO store image id & if repeated - skip it $target = 'new'; $u = @parse_url($file); $_is_url = false; if (!$u || !(isset($u['scheme']) && isset($u['host']) && isset($u['path']))) { } elseif (in_array($u['scheme'], array('http', 'https', 'ftp', 'ftps'))) { $_is_url = true; } else { $target = 'skip'; $file = null; $this->error(sprintf('Unsupported file source protocol', $u['scheme'])); } $search = array('product_id' => $this->data['map'][self::STAGE_PRODUCT], 'ext' => pathinfo($file, PATHINFO_EXTENSION)); try { $name = preg_replace('@[^a-zA-Zа-яА-Я0-9\\._\\-]+@', '', basename(urldecode($file))); if ($_is_url) { $pattern = sprintf('@/(%d)/images/(\\d+)/\\2\\.(\\d+(x\\d+)?)\\.([^\\.]+)$@', $search['product_id']); if (preg_match($pattern, $file, $matches)) { $image = array('product_id' => $matches[1], 'id' => $matches[2], 'ext' => $matches[5]); if (strpos($file, shopImage::getUrl($image, $matches[3])) !== false && $model->getByField($image)) { #skip local file $target = 'skip'; $file = null; } } if ($file) { waFiles::upload($file, $file = wa()->getTempPath('csv/upload/images/' . waLocale::transliterate($name, 'en_US'))); } } elseif ($file) { $file = $this->data['upload_path'] . $file; } if ($file && file_exists($file)) { if ($image = waImage::factory($file)) { $search['original_filename'] = $name; $data = array('product_id' => $this->data['map'][self::STAGE_PRODUCT], 'upload_datetime' => date('Y-m-d H:i:s'), 'width' => $image->width, 'height' => $image->height, 'size' => filesize($file), 'original_filename' => $name, 'ext' => pathinfo($file, PATHINFO_EXTENSION)); if ($exists = $model->getByField($search)) { $data = array_merge($exists, $data); $thumb_dir = shopImage::getThumbsPath($data); $back_thumb_dir = preg_replace('@(/$|$)@', '.back$1', $thumb_dir, 1); $paths[] = $back_thumb_dir; waFiles::delete($back_thumb_dir); // old backups if (file_exists($thumb_dir)) { if (!(waFiles::move($thumb_dir, $back_thumb_dir) || waFiles::delete($back_thumb_dir)) && !waFiles::delete($thumb_dir)) { throw new waException(_w("Error while rebuild thumbnails")); } } } $image_changed = false; /** * TODO move it code into product core method */ /** * Extend add/update product images * Make extra workup * @event image_upload */ $event = wa()->event('image_upload', $image); if ($event) { foreach ($event as $result) { if ($result) { $image_changed = true; break; } } } if (empty($data['id'])) { $image_id = $data['id'] = $model->add($data); } else { $image_id = $data['id']; $target = 'update'; $model->updateById($image_id, $data); } if (!$image_id) { throw new waException("Database error"); } $image_path = shopImage::getPath($data); if (file_exists($image_path) && !is_writable($image_path) || !file_exists($image_path) && !waFiles::create($image_path)) { $model->deleteById($image_id); throw new waException(sprintf("The insufficient file write permissions for the %s folder.", substr($image_path, strlen($this->getConfig()->getRootPath())))); } if ($image_changed) { $image->save($image_path); /** * @var shopConfig $config */ $config = $this->getConfig(); if ($config->getOption('image_save_original') && ($original_file = shopImage::getOriginalPath($data))) { waFiles::copy($file, $original_file); } } else { waFiles::copy($file, $image_path); } $this->data['processed_count'][self::STAGE_IMAGE][$target]++; } else { $this->error(sprintf('Invalid image file', $file)); } } elseif ($file) { $this->error(sprintf('File %s not found', $file)); $target = 'skip'; $this->data['processed_count'][self::STAGE_IMAGE][$target]++; } else { $this->data['processed_count'][self::STAGE_IMAGE][$target]++; } } catch (Exception $e) { $this->error($e->getMessage()); //TODO skip on repeated error } array_shift($this->data['map'][self::STAGE_IMAGE]); ++$this->data['current'][self::STAGE_IMAGE]; if ($_is_url) { waFiles::delete($file); } } return true; }
/** * @param array $options * @return shopProduct * @throws waException */ public function duplicate($options = array()) { if (!$this->checkRights()) { throw new waRightsException('Access denied'); } $data = $this->data; $skip = array('id', 'create_datetime', 'id_1c', 'rating', 'rating_count', 'total_sales', 'image_id', 'contact_id', 'ext', 'count', 'sku_count'); foreach ($skip as $field) { if (isset($data[$field])) { unset($data[$field]); } } $duplicate = new shopProduct(); $this->getStorage(null); $sku_files = array(); $sku_images = array(); $ignore_select = true; foreach (self::$data_storages as $key => $i) { $raw = $this->getStorage($key)->getData($this); switch ($key) { case 'features_selectable': $storage_data = array(); if (!$ignore_select) { if ($this->sku_type == shopProductModel::SKU_TYPE_SELECTABLE) { if (!is_array($raw)) { $raw = array(); } foreach ($raw as $id => $f) { if (!empty($f['selected'])) { foreach ($f['values'] as $value_id => &$value) { if (!empty($value['selected'])) { $value = array('id' => $value_id); } else { unset($f['values'][$value_id]); } } $storage_data[$id] = $f; } } } } break; case 'skus': $storage_data = array(); $i = 0; foreach ($raw as $sku_id => $sku) { if (!empty($sku['virtual']) || $ignore_select) { if ($file_path = shopProductSkusModel::getPath($sku)) { $sku_files[$sku['id']] = array('file_name' => $sku['file_name'], 'file_description' => $sku['file_description'], 'file_size' => $sku['file_size'], 'file_path' => $file_path); } if (!empty($sku['image_id'])) { $sku_images[$sku['id']] = $sku['image_id']; } foreach (array('id', 'id_1c', 'product_id', 'image_id', 'file_name', 'file_size', 'file_description') as $field) { if (isset($sku[$field])) { unset($sku[$field]); } } $storage_data[--$i] = $sku; } } break; case 'tags': $storage_data = array_values($raw); break; case 'categories': $storage_data = array_keys($raw); break; default: $storage_data = $raw; break; } $duplicate->{$key} = $storage_data; } $counter = 0; $data['url'] = shopHelper::genUniqueUrl($this->url, $this->model, $counter); $data['name'] = $this->name . sprintf('(%d)', $counter ? $counter : 1); $duplicate->save($data); $product_id = $duplicate->getId(); $sku_map = array_combine(array_keys($this->skus), array_keys($duplicate->skus)); $config = wa('shop')->getConfig(); $image_thumbs_on_demand = $config->getOption('image_thumbs_on_demand'); /** * @var shopConfig $config */ if ($this->pages) { $product_pages_model = new shopProductPagesModel(); foreach ($this->pages as $page) { unset($page['id']); unset($page['create_time']); unset($page['update_datetime']); unset($page['create_contact_id']); $page['product_id'] = $duplicate->getId(); $product_pages_model->add($page); } } #duplicate images $product_skus_model = new shopProductSkusModel(); $images_model = new shopProductImagesModel(); $images = $images_model->getByField('product_id', $this->getId(), $images_model->getTableId()); $callback = create_function('$a, $b', 'return (max(-1, min(1, $a["sort"] - $b["sort"])));'); usort($images, $callback); foreach ($images as $id => $image) { $source_path = shopImage::getPath($image); $original_file = shopImage::getOriginalPath($image); $image['product_id'] = $duplicate->getId(); if ($sku_id = array_search($image['id'], $sku_images)) { $sku_id = $sku_map[$sku_id]; } unset($image['id']); try { if ($image['id'] = $images_model->add($image, $id == $this->image_id)) { waFiles::copy($source_path, shopImage::getPath($image)); if (file_exists($original_file)) { waFiles::copy($original_file, shopImage::getOriginalPath($image)); } if ($sku_id) { $product_skus_model->updateById($sku_id, array('image_id' => $image['id'])); } if (!$image_thumbs_on_demand) { shopImage::generateThumbs($image, $config->getImageSizes()); //TODO use dummy copy with rename files } } } catch (waDbException $ex) { //just ignore it waLog::log('Error during copy product: ' . $ex->getMessage(), 'shop.log'); } catch (waException $ex) { if (!empty($image['id'])) { $images_model->deleteById($image['id']); } waLog::log('Error during copy product: ' . $ex->getMessage(), 'shop.log'); } } foreach ($sku_files as $sku_id => $data) { $source_path = $data['file_path']; unset($data['file_path']); $sku_id = $sku_map[$sku_id]; $sku = array_merge($duplicate->skus[$sku_id], $data); $product_skus_model->updateById($sku_id, $data); $target_path = shopProductSkusModel::getPath($sku); try { waFiles::copy($source_path, $target_path); } catch (waException $ex) { $data = array('file_name' => '', 'file_description' => '', 'file_size' => 0); $product_skus_model->updateById($sku_id, $data); print $ex->getMessage(); } } $product_features_model = new shopProductFeaturesModel(); $skus_features = $product_features_model->getSkuFeatures($this->id); $skus_features_data = array(); foreach ($skus_features as $sku_id => $features) { $sku_id = $sku_map[$sku_id]; foreach ($features as $feature_id => $feature_value_id) { $skus_features_data[] = compact('product_id', 'sku_id', 'feature_id', 'feature_value_id'); } } if ($skus_features_data) { $product_features_model->multipleInsert($skus_features_data); } if ($this->sku_type == shopProductModel::SKU_TYPE_SELECTABLE) { $product_features_selectable_model = new shopProductFeaturesSelectableModel(); if ($features_selectable = $product_features_selectable_model->getByField('product_id', $this->id, true)) { foreach ($features_selectable as &$feature_selectable) { $feature_selectable['product_id'] = $product_id; } unset($feature_selectable); $product_features_selectable_model->multipleInsert($features_selectable); } } $product_services_model = new shopProductServicesModel(); if ($services = $product_services_model->getByField('product_id', $this->id, true)) { foreach ($services as &$service) { unset($service['id']); $service['product_id'] = $product_id; $service['sku_id'] = ifset($sku_map[$service['sku_id']]); unset($service); } $product_services_model->multipleInsert($services); } $product_related_model = new shopProductRelatedModel(); if ($related = $product_related_model->getByField('product_id', $this->id, true)) { foreach ($related as &$row) { $row['product_id'] = $product_id; } unset($row); $product_related_model->multipleInsert($related); } $params = array('product' => &$this, 'duplicate' => &$duplicate); /** * @wa-event product_duplicate */ wa()->event('product_duplicate', $params); return $duplicate; }
/** * Get aggregated data about placing products(skus) in stocks * * @see getProductStocks * * @param int|array $product_id * @param string $order * @return array */ public function getProductStocksByProductId($product_id, $order = 'desc') { if (!$product_id) { return array(); } $product_ids = (array) $product_id; $product_ids_str = implode(',', $product_ids); $order = $order == 'desc' || $order == 'DESC' ? 'DESC' : 'ASC'; // necessary models $stock_model = new shopStockModel(); $product_images_model = new shopProductImagesModel(); // stock ids of items ordered by sort $stock_ids = array_keys($stock_model->getAll('id')); // get products $sql = "\n SELECT id, name, count, image_id\n FROM {$this->table}\n WHERE id IN ( {$product_ids_str} )\n ORDER BY count {$order}\n "; $data = array(); $image_ids = array(); foreach ($this->query($sql) as $item) { $data[$item['id']] = array('id' => $item['id'], 'name' => $item['name'], 'url_crop_small' => null, 'count' => $item['count'], 'skus' => array(), 'stocks' => array()); if ($item['image_id'] != null) { $image_ids[] = $item['image_id']; } } if (!$data) { return array(); } $product_ids = array_keys($data); $product_ids_str = implode(',', $product_ids); $images = $product_images_model->getByField('id', $image_ids, 'product_id'); $size = wa()->getConfig()->getImageSize('crop_small'); // get for skus number of stocks in which it presents $sql = "\n SELECT sk.id, COUNT(sk.id) num_of_stocks\n FROM shop_product_skus sk\n JOIN shop_product_stocks st ON sk.id = st.sku_id\n WHERE sk.product_id IN ( {$product_ids_str} )\n GROUP BY sk.id\n "; $num_of_stocks = $this->query($sql)->fetchAll('id', true); // get info about skus and stocks $sql = "SELECT\n sk.product_id,\n sk.id AS sku_id,\n sk.name AS sku_name,\n sk.count,\n\n pst.stock_id,\n pst.count AS stock_count\n FROM shop_product_skus sk\n LEFT JOIN shop_product_stocks pst ON pst.sku_id = sk.id\n WHERE sk.product_id IN ( {$product_ids_str} )\n ORDER BY sk.product_id, sk.count {$order}, sk.id"; $stocks_count = count($stock_ids); // temporary aggragating info about stocks $sku_stocks = array(); if ($stocks_count) { $sku_stocks = array_fill(0, $stocks_count, array()); } $sku_id = 0; $product_id = 0; $p_product = null; foreach ($this->query($sql) as $item) { // another product if ($product_id != $item['product_id']) { $product_id = $item['product_id']; $p_product =& $data[$product_id]; if (isset($images[$product_id])) { $p_product['url_crop_small'] = shopImage::getUrl($images[$product_id], $size); } } // another sku if ($sku_id != $item['sku_id']) { $sku_id = $item['sku_id']; $p_product['skus'][$sku_id] = array('id' => $sku_id, 'name' => $item['sku_name'], 'count' => $item['count'], 'num_of_stocks' => isset($num_of_stocks[$sku_id]) ? $num_of_stocks[$sku_id] : 0); } // aggregate info about stocks if ($item['stock_id'] !== null) { $sku_stocks[$item['stock_id']][$sku_id] = $item['stock_count']; } } // lay out stocks info if (!empty($sku_stocks)) { foreach ($data as &$product) { foreach ($stock_ids as $stock_id) { foreach ($product['skus'] as $sku_id => $sku) { $product['stocks'][$stock_id][$sku_id] = array('id' => $sku_id, 'name' => $sku['name'], 'count' => isset($sku_stocks[$stock_id][$sku_id]) ? $sku_stocks[$stock_id][$sku_id] : null, 'num_of_stocks' => $sku['num_of_stocks']); } } } unset($product); } return $data; }