yoomoney / cms-opencart3

YooKassa payment module for Opencart 3.x
https://yookassa.ru/developers
Other
21 stars 16 forks source link

Разделение YML на части #84

Open freimaks opened 3 years ago

freimaks commented 3 years ago

Всем привет!

Недавно тут задавали вопрос про белый экран и в общем-то напрашивается простое решение - сегментировать YML файл на части подобно тому как это делается для сайтмапов.

Причем тоже самое нам говорит документация самого Яндекса:

разделите большие прайс-листы (более 500 000 предложений) на несколько, предложения, которые часто меняются, соберите в одном файле: сервис быстрее загружает небольшие прайс-листы и может обрабатывать их параллельно.

Хотя речь конечно может идти и не про 500 тысяч, а даже про пару-тройку десятков тысяч товаров, чтобы гарантировать обработку запроса со стороны вашего сервера.

Коррекции затрагивают только контроллер yandex_money.php и больше никаких правок не делает (можно оформить и в виде ocmod):

public function market() {
        $per_page = 0;
        if(isset($this->request->get['per_page'])) {
            $per_page = $this->request->get['per_page'];
        }

        $page = 0;
        if(isset($this->request->get['page'])) {
            $page = $this->request->get['page'];
        }        

        $xml = $this->getMarketXml($per_page, $page);

        $this->response->addHeader('Content-Type: application/xml; charset=utf-8');
        $this->response->setOutput($xml);
    }
private function getMarketXml($per_page, $page) {
        $cache     = new Cache("file");
        $marketXml = $cache->get("ym_market_xml");

        $marketXml = ''; // Вопрос с кэшем нужно решать дополнительно

        if (empty($marketXml)) {
            $marketXml = $this->generateMarketXml($per_page, $page);
            $cache->set("ym_market_xml", $marketXml);
        }

        return $marketXml;
    }
private function generateMarketXml($per_page, $page) {
$this->setDelivery()
             ->setCurrencies($currency_default, $offers_currency)
             ->setCategories($categories, $allowCategories)
             ->setProducts($currency_default, $strCategoryIds, $additionalConditionMap, $per_page, $page);
}
    private function setProducts($currency_default, $strCategoryIds, $additionalConditionMap, $per_page, $page)
    {
        $this->load->model('catalog/product');
        $this->load->model('tool/image');

        $nameTemplate = explode('%', $this->config->get('yandex_money_market_name_template'));
        $products     = $this->getMarketModel()->getProducts($strCategoryIds, false);
        $length       = new \Cart\Length($this->registry);

        $startFor = 0;
        $endFor = 0;

        if($per_page <= 0 || $page <= 0 || $per_page >= count($products)) {
            $startFor = 0;
            $endFor = count($products);
        } else {
            // $per_page = 1000, $page = 1: $startFor = 0, $endFor = 1000 (999)
            // $per_page = 1000, $page = 17: $startFor = 16000, $endFor = 17000 (16999)
            $startFor = $page * $per_page - $per_page;
            $endFor = $page * $per_page;

            if($startFor > count($products)){
                $startFor = count($products);
            }

            if($endFor > count($products)){
                $endFor = count($products);
            }
        }

        //foreach ($products as $product) {
        for($i = $startFor; $i < $endFor; $i++) {
            $product = $products[$i];
}

При таких изменениях адрес к YML будет выглядеть так: https://tratata.ta/index.php?route=extension/payment/yandex_money/market&per_page=1000&page=24

В ином случае нужны слишком большие таймауты для NGINX и PHP, чтобы дождаться генерации единого YML-файла.

P.S. Нагрузку на сервер может вызывать не только перебор товаров, но и к примеру выполнение операции $offer->addPicture($this->model_tool_image->resize($product['image'], 600, 600)); в случае, если у вас очищен кэш изображений (бонусом resize часто не только делает саму обрезку, но и генерирует дополнительное изображение в каком-нибудь WebP, чтобы обрадовать Google использованием современных форматов изображений). P.P.S. На скорость выборки (в особенности товаров со всеми атрибутами, опциями и изображениями) может влиять отсутствие дополнительных индексов в БД. Но это уже не относится напрямую к этому модулю.

ostulov commented 3 years ago

Добрый день!

Благодарю за подробное описание, рассмотрим Ваше предложение!

freimaks commented 3 years ago

Добрый день!

Благодарю за подробное описание, рассмотрим Ваше предложение!

@ostulov, здравствуйте! Если Вы рассматриваете предложения по доработкам, то есть еще пара моментов:

  1. В админке для Маркета сделать настройку размеров изображений. У Яндекса, судя по документации, есть ограничения - не менее 300 пикселей (по любой из сторон) и не более 3500 пикселей (по большей из сторон). Сейчас в Вашем модуле жестко зашиты размеры 600x600 (рекомендуемые Яндексом) и это не очень удобно в том случае, если используемый шаблон устанавливает другие размеры (например, 800x800, 1200x1200 и т.п.). Соответственно получается, что лишние изображения и отъедают время на генерацию, и занимают лишнее место на диске, при этом никакого смысла в них нет.

  2. Сделать для Маркета использование кэша опциональным с управлением через ту же админку. Тут проблема только для тех, у кого идет постоянная синхронизация складских остатков. Соответственно приходится либо после каждой синхронизации чистить кэш, либо просто глушить его использование в модуле. Если генерация YML по ссылке оптимизирована и укладывается в требуемые 150 секунд, то пусть сервер и генерирует его постоянно при каждом запросе робота.