private function initExport()
 {
     $hash = shopImportexportHelper::getCollectionHash();
     $this->data['export_category'] = !in_array($hash['type'], array('id', 'set', 'type'));
     $this->data['timestamp'] = time();
     $this->data['hash'] = $hash['hash'];
     $encoding = waRequest::post('encoding', 'utf-8');
     $options = array();
     $config = array('encoding' => $encoding, 'delimiter' => waRequest::post('delimiter', ';'), 'features' => !!waRequest::post('features'), 'images' => !!waRequest::post('images'), 'extra' => !!waRequest::post('extra'), 'domain' => waRequest::post('domain'), 'hash' => $hash['hash']);
     $map = shopCsvProductuploadController::getMapFields(true, $config['extra']);
     $this->data['composite_features'] = array();
     $features_model = new shopFeatureModel();
     if (!empty($config['features'])) {
         if (preg_match('@^id/(.+)$@', $this->data['hash'], $matches)) {
             $product_ids = array_unique(array_map('intval', explode(',', $matches[1])));
             $features = $features_model->getByProduct($product_ids);
             $feature_selectable_model = new shopProductFeaturesSelectableModel();
             $feature_ids = $feature_selectable_model->getFeatures($product_ids);
             if ($feature_ids = array_diff($feature_ids, array_keys($features))) {
                 $features += $features_model->getById($feature_ids);
             }
             $parents = array();
             foreach ($features as $feature) {
                 if (!empty($feature['parent_id'])) {
                     if (!isset($parents[$feature['parent_id']])) {
                         $parents[$feature['parent_id']] = $feature['parent_id'];
                     }
                 }
             }
             if ($parents) {
                 $features += $features_model->getById($parents);
             }
         } else {
             $features = $features_model->getAll();
         }
         if ($features) {
             $options['features'] = true;
             foreach ($features as $feature) {
                 if (!preg_match('/\\.\\d$/', $feature['code']) && $feature['type'] != shopFeatureModel::TYPE_DIVIDER) {
                     $map[sprintf('features:%s', $feature['code'])] = $feature['name'];
                     if ($encoding != 'UTF-8') {
                         $this->data['composite_features'][$feature['code']] = true;
                     }
                 }
             }
         }
     }
     $tax_model = new shopTaxModel();
     if ($taxes = $tax_model->getAll()) {
         $this->data['taxes'] = array();
         foreach ($taxes as $tax) {
             $this->data['taxes'][$tax['id']] = $tax['name'];
         }
     }
     if (!empty($config['images'])) {
         $sql = 'SELECT COUNT(1) AS `cnt` FROM `shop_product_images` GROUP BY `product_id` ORDER BY `cnt` DESC LIMIT 1';
         if ($cnt = $features_model->query($sql)->fetchField('cnt')) {
             $options['images'] = true;
             for ($n = 0; $n < $cnt; $n++) {
                 $field = sprintf('images:%d', $n);
                 $map[$field] = _w('Product images');
             }
         }
         if (isset($map['images'])) {
             unset($map['images']);
         }
     } else {
         if (isset($map['images'])) {
             unset($map['images']);
         }
         foreach (array_keys($map) as $field) {
             if (preg_match('@^images:\\d+$@', $field)) {
                 unset($map[$field]);
             }
         }
     }
     $profile_helper = new shopImportexportHelper('csv:product:export');
     $profile = $profile_helper->setConfig($config);
     $profile_raw = waRequest::request('profile', array(), waRequest::TYPE_ARRAY);
     $profile_name = substr(waLocale::transliterate(ifempty($profile_raw['name'], $profile)), 0, 32);
     $name = sprintf('products(%s)_%s_%s.csv', $profile_name, date('Y-m-d'), strtolower($encoding));
     $name = preg_replace('@[^A-Za-z0-9\\-\\(\\),_\\.]+@', '', $name);
     $file = wa()->getTempPath('csv/download/' . $profile . '/' . $name);
     $this->writer = new shopCsvWriter($file, $config['delimiter'], $encoding);
     $this->writer->setMap($map);
     $this->data['file'] = serialize($this->writer);
     $this->data['map'][self::STAGE_CATEGORY] = null;
     $this->data['map'][self::STAGE_PRODUCT] = 0;
     $this->data['config'] = $config;
     $this->data['options'] = $options;
     $this->initRouting();
     $this->data['count'] = array(self::STAGE_PRODUCT => $this->getCollection()->count(), self::STAGE_CATEGORY => 0, self::STAGE_SKU => null, self::STAGE_IMAGE => null);
     if ($this->data['export_category']) {
         $model = new shopCategoryModel();
         if (preg_match('@^category/(\\d+)$@', $this->data['hash'], $matches)) {
             $this->data['count'][self::STAGE_CATEGORY] = count($model->getPath($matches[1])) + 1;
             //TODO add subcategories for nested
             //$model->getTree($matches[1]);
         } else {
             $this->data['count'][self::STAGE_CATEGORY] = $model->countByField('type', shopCategoryModel::TYPE_STATIC);
         }
     }
 }
 public function save()
 {
     $raw_profile = waRequest::post('profile');
     if (is_array($raw_profile)) {
         $profile_id = isset($raw_profile['id']) ? intval(intval($raw_profile['id'])) : 0;
     } else {
         $profile_id = intval($raw_profile);
         $raw_profile = array();
     }
     if ($profile_id) {
         $profiles = new shopImportexportHelper($this->plugin);
         if ($profile_id < 0) {
             $profile_id = $profiles->addConfig(ifset($raw_profile['name'], date('c')), ifset($raw_profile['description'], ''));
         }
         $profiles->setConfig($raw_profile, $profile_id);
     }
 }
    protected function init()
    {
        try {
            $backend = wa()->getEnv() == 'backend';
            $profiles = new shopImportexportHelper('yandexmarket');
            switch ($this->encoding) {
                case 'windows-1251':
                    setlocale(LC_CTYPE, 'ru_RU.CP-1251', 'ru_RU.CP1251', 'ru_RU.win');
                    break;
            }
            $this->data['offset'] = array('offers' => 0);
            $this->data['timestamp'] = time();
            $default_export_config = array('zero_stock' => 0, 'compare_price' => 0, 'sku' => 0, 'sku_group' => '', 'hidden_categories' => 0);
            if ($backend) {
                $hash = shopImportexportHelper::getCollectionHash();
                $profile_config = array('hash' => $hash['hash'], 'domain' => waRequest::post('domain'), 'map' => array(), 'types' => array_filter((array) waRequest::post('types')), 'export' => (array) waRequest::post('export', array()) + $default_export_config, 'company' => waRequest::post('company'), 'company_name' => waRequest::post('company_name'), 'shop' => waRequest::post('shop'), 'lifetime' => waRequest::post('lifetime', 0, waRequest::TYPE_INT), 'utm_source' => waRequest::post('utm_source'), 'utm_medium' => waRequest::post('utm_medium'), 'utm_campaign' => waRequest::post('utm_campaign'));
                $this->data['map'] = $this->plugin()->map(waRequest::post('map', array()), $profile_config['types']);
                foreach ($this->data['map'] as $type => $offer_map) {
                    foreach ($offer_map['fields'] as $field => $info) {
                        if (!empty($info['source']) && preg_match('@^\\w+:(.+)$@', $info['source'], $matches) && $matches[1] != '%s') {
                            $profile_config['map'][$type][$field] = $info['source'];
                        }
                    }
                    if (empty($profile_config['map'][$type])) {
                        unset($profile_config['map'][$type]);
                    }
                }
                $profile_id = $profiles->setConfig($profile_config);
                $this->plugin()->getHash($profile_id);
            } else {
                $profile_id = waRequest::param('profile_id');
                if (!$profile_id || !($profile = $profiles->getConfig($profile_id))) {
                    throw new waException('Profile not found', 404);
                }
                $profile_config = $profile['config'];
                $profile_config['export'] += $default_export_config;
                $this->data['map'] = $this->plugin()->map($profile_config['map'], $profile_config['types']);
                foreach ($this->data['map'] as $type => &$offer_map) {
                    foreach ($offer_map['fields'] as $field => &$info) {
                        $info['source'] = ifempty($profile_config['map'][$type][$field], 'skip:');
                    }
                    unset($offer_map);
                }
            }
            foreach ($this->data['map'] as $type => &$offer_map) {
                if ($type != 'simple') {
                    $offer_map['fields']['type'] = array('source' => 'value:' . $type, 'attribute' => true);
                }
                unset($offer_map);
            }
            $feature_model = new shopFeatureModel();
            foreach ($this->data['map'] as $type => &$offer_map) {
                foreach ($offer_map['fields'] as $field => &$info) {
                    if (strpos($field, 'param.') === 0 && isset($info['source'])) {
                        switch (preg_replace('@:.+$@', '', $info['source'])) {
                            case 'feature':
                                if ($feature = $feature_model->getByCode(preg_replace('@^[^:]+:@', '', $info['source']))) {
                                    $info['source_name'] = $feature['name'];
                                }
                                break;
                        }
                    }
                }
                unset($info);
                unset($offer_map);
            }
            $this->data['hash'] = $profile_config['hash'];
            if (!isset($this->data['categories'])) {
                $this->data['categories'] = array();
            }
            $this->data['export'] = $profile_config['export'];
            $this->data['domain'] = $profile_config['domain'];
            $this->data['utm'] = array();
            foreach (array('utm_source', 'utm_medium', 'utm_campaign') as $field) {
                if (!empty($profile_config[$field])) {
                    $this->data['utm'][$field] = $profile_config[$field];
                }
            }
            if ($this->data['utm']) {
                $this->data['utm'] = http_build_query(array_map('rawurlencode', $this->data['utm']));
            }
            $this->data['types'] = array();
            foreach ($profile_config['types'] as $type => $type_map) {
                $this->data['types'] += array_fill_keys(array_filter(array_map('intval', $type_map)), $type);
            }
            $this->initRouting();
            $model = new shopCategoryModel();
            if (empty($this->data['export']['hidden_categories'])) {
                $sql = <<<SQL
SELECT COUNT(1) as `cnt`
FROM shop_category c
LEFT JOIN shop_category_routes cr ON (c.id = cr.category_id)
WHERE
  ((cr.route IS NULL) OR (cr.route = s:route))
   AND
  (`c`.`type`=i:type)
  AND
  (`c`.`status`=1)

SQL;
            } else {
                $sql = <<<SQL
SELECT COUNT(1) as `cnt`
FROM shop_category c
LEFT JOIN shop_category_routes cr ON (c.id = cr.category_id)
WHERE
  ((cr.route IS NULL) OR (cr.route = s:route))
   AND
  (`c`.`type`=i:type)

SQL;
            }
            $params = array('route' => $this->data['domain'], 'type' => shopCategoryModel::TYPE_STATIC);
            $this->data['count'] = array('category' => (int) $model->query($sql, $params)->fetchField('cnt'), 'product' => $this->getCollection()->count());
            $stages = array_keys($this->data['count']);
            $this->data['current'] = array_fill_keys($stages, 0);
            $this->data['processed_count'] = array_fill_keys($stages, 0);
            $this->data['stage'] = reset($stages);
            $this->data['stage_name'] = $this->getStageName($this->data['stage']);
            $this->data['memory'] = memory_get_peak_usage();
            $this->data['memory_avg'] = memory_get_usage();
            if (!class_exists('DOMDocument')) {
                throw new waException('PHP extension DOM required');
            }
            $this->dom = new DOMDocument("1.0", $this->encoding);
            $this->dom->encoding = $this->encoding;
            $this->dom->preserveWhiteSpace = false;
            $this->dom->formatOutput = true;
            /**
             * @var shopConfig $config
             */
            $config = wa('shop')->getConfig();
            $xml = <<<XML
<?xml version="1.0" encoding="{$this->encoding}"?>
<!DOCTYPE yml_catalog SYSTEM "shops.dtd">
<yml_catalog  date="%s">
</yml_catalog>
XML;
            $original = shopYandexmarketPlugin::path('shops.dtd');
            $target = $this->getTempPath('shops.dtd');
            $ft = filesize($target);
            $fo = filesize($original);
            if (!file_exists($target) || filesize($target) != filesize($original) && waFiles::delete($target)) {
                waFiles::copy($original, $target);
            }
            $this->dom->loadXML(sprintf($xml, date("Y-m-d H:i")));
            $this->dom->lastChild->appendChild($shop = $this->dom->createElement("shop"));
            $name = ifempty($profile_config['company_name'], $config->getGeneralSettings('name'));
            $name = str_replace('&', '&amp;', $name);
            $name = str_replace("'", '&apos;', $name);
            $this->addDomValue($shop, 'name', $name);
            $company = str_replace('&', '&amp;', $profile_config['company']);
            $company = str_replace("'", '&apos;', $company);
            $this->addDomValue($shop, 'company', $company);
            $this->addDomValue($shop, 'url', preg_replace('@^https@', 'http', wa()->getRouteUrl('shop/frontend', array(), true)));
            if ($phone = $config->getGeneralSettings('phone')) {
                $shop->appendChild($this->dom->createElement('phone', $phone));
            }
            $this->addDomValue($shop, 'platform', 'Shop-Script');
            $this->addDomValue($shop, 'version', wa()->getVersion('shop'));
            $currencies = $this->dom->createElement('currencies');
            $model = new shopCurrencyModel();
            $this->data['currency'] = array();
            $available_currencies = shopYandexmarketPlugin::settingsPrimaryCurrencies();
            if (empty($available_currencies)) {
                throw new waException('Экспорт не может быть выполнен: не задано ни одной валюты, которая могла бы использоваться в качестве основной.');
            }
            unset($available_currencies['auto']);
            $primary_currency = $this->plugin()->getSettings('primary_currency');
            $this->data['default_currency'] = $config->getCurrency();
            if (!isset($available_currencies[$primary_currency])) {
                $primary_currency = $this->data['default_currency'];
                if (!isset($available_currencies[$primary_currency])) {
                    reset($available_currencies);
                    $primary_currency = key($available_currencies);
                }
            }
            $this->data['primary_currency'] = $primary_currency;
            $rate = $available_currencies[$primary_currency]['rate'];
            $available_currencies = $model->getCurrencies(shopYandexmarketPlugin::getConfigParam('currency'));
            foreach ($available_currencies as $info) {
                if ($info['rate'] > 0) {
                    $info['rate'] = $info['rate'] / $rate;
                    $this->data['currency'][] = $info['code'];
                    if (abs(round($info['rate'], 4) - $info['rate']) / $info['rate'] > 0.01) {
                        $info['rate'] = 'CB';
                    }
                    $value = array('id' => $info['code'], 'rate' => $this->format('rate', $info['rate']));
                    $this->addDomValue($currencies, 'currency', $value);
                }
            }
            $shop->appendChild($currencies);
            $shop->appendChild($this->dom->createElement('categories'));
            $fields = array('store' => true, 'pickup' => true, 'delivery' => true, 'deliveryIncluded' => false, 'local_delivery_cost' => '%0.2f', 'adult' => true);
            foreach ($fields as $field => $include_value) {
                $value = ifset($profile_config['shop'][$field], '');
                if ($value || $value !== '') {
                    if ($include_value) {
                        $value = $include_value === true ? $value : $this->format($field, $value, array('format', $include_value));
                        $this->addDomValue($shop, $field, $value);
                    } else {
                        $shop->appendChild($this->dom->createElement($field));
                    }
                }
            }
            $shop->appendChild($this->dom->createElement('offers'));
            if (!$this->data['currency']) {
                throw new waException('Не задано ни одной поддерживаемой валюты');
            }
            if (!in_array($this->data['primary_currency'], $this->data['currency'])) {
                $this->data['primary_currency'] = reset($this->data['currency']);
            }
            $this->data['path'] = array('offers' => shopYandexmarketPlugin::path($profile_id . '.xml'));
            $this->save();
            $this->dom = null;
            $this->loadDom();
        } catch (waException $ex) {
            $this->error($ex->getMessage());
            echo json_encode(array('error' => $ex->getMessage()));
            exit;
        }
    }