вторник, 6 ноября 2012 г.

Одновременный вывод подкатегорий и товаров в Vamshop

Черт меня дернул одному заказчику поставить интернет-магазин на движке Vamshop. И вот встала задача выводить на странице категории как список подкатегорий, так и список товаров. А движок работает так, что если в категорие есть товары, то он выводит только товары. В интернете решения этого вопроса не нашел, так что предлагаю свой вариант. Кому интересно, прошу под кат.

В файле includes/modules/product_listing.php после строк

    $listing_query = vamDBquery($listing_split->sql_query);
    while ($listing = vam_db_fetch_array($listing_query, true)) {
        $rows ++;
        $module_content[] =  $product->buildDataArray($listing);  
    }


добавляем:

    if ($_GET['cat']) {
        $categories_query = "SELECT c.categories_id, cd.categories_name FROM categories AS c, categories_description AS cd WHERE c.categories_id=cd.categories_id AND c.parent_id=$current_category_id";
        $categories_query = vamDBquery($categories_query);
        $categories_list = array();
        while ($subcategory = vam_db_fetch_array($categories_query, true)) {
            $categories_list[] =  array ('CATEGORIES_NAME' => $subcategory['categories_name'], 'CATEGORIES_ID' => $subcategory['categories_id']); 
        }
        $module->assign('categories_list', $categories_list);
    }


В кратце поясню, что мы банально выбираем из базы подкатегории нашей текущей категории и при помощи $module->assign('categories_list', $categories_list); делаем их доступными для системы шаблонов (Vamshop использует Smarty).

Далее в templates/<current_template>/modules/product_listing/product_listing_columns.html добавляем в нужном нам месте строки вида:

{if $categories_list}
<div class="page">
  <div class="pageItem">
    <ul class="categories-list">
     {foreach name=aussen item=category_data from=$categories_list} 
       <li><a href="index.php?cat={$category_data.CATEGORIES_ID}">{$category_data.CATEGORIES_NAME}</a></li>
     {/foreach}
    </ul>
  </div>
</div>
{/if}


Соответственно тут мы перебираем и выводим наши подкатегории.

Все очень просто, но гугл мне на мой вопрос ответа не дал. И я надеюсь, что это кому-нибудь да поможет.

вторник, 11 сентября 2012 г.

Виртуальные рабочие места

Виртуальные рабочие столы (места) в линуксе - это то, чего мне в винде не хватает (когда приходится там работать).

Если кто не в курсе, то благодаря этой фиче можно держать открытыми 10-20-<сколько позволяет мощность компа> окон, и при этом панель задач не превращается в сраное говно, в котором ничего нельзя найти и все мешается.

Моя обычная рабочая разбивка рабочих столов по задачам:
  1. IDE, сам сайт в браузере(ах), терминал, еще одно окно огнелиса с документацией
  2. Gimp и все что связано с обработкой изображений
  3. Здесь запускаю что-то дополнительное. Чаще всего - VirtualBox
  4. Резервный рабочий стол. Сюда вешаю, например, те окна где я работал, а потом пришлось отвлечься и переключиться. А потом я все равно продолжу. Ну или там я жду звонка, и что бы не искать материалы для разговора, у меня на этом рабочем столе уже все готовое висит.
  5. Рабочая почта, которую мне надо постоянно чекать
  6. Аудио-плеер

среда, 5 сентября 2012 г.

Люблю я классику

Не выдержал. Вернулся к старому доброму Гному без эффектов. Может дальше увижу, что в Убунте он сырой, но сейчас я радуюсь :-)

Ubuntu 12.04 и Unity

Пытаюсь привыкнуть к Unity. Работать можно, но неудобно. Некоторые давно заточенные мои личные приемы работы в графическом интерфейсе разрушены, а замена неудобна.

Что не нравится

  • Что бы без хоткея перейти на соседний рабочий стол нужно три раза кликнуть мышью, а не один.
  • Работать с несколькими окнами одного и того же приложения на одном рабочем столе неудобно. Нет нормальной панели задач, а новая работа альт-таба просто ужасна.
    А часто это мне нужно. В частности раньше я разбивал фаерфокс на два окна: сам сайт и все остальное. Вкладками делать тоже самое неудобно - загромождение, а рабочими столами неудобно, потому что Alt+TAB более удобный хоткей чем Ctrl+F1. С гимпом тоже проблема
  • Хочу отображение примонтированных устройств в верхней панели, но не знаю как. В лаунчере - это опять же загромождение
  • Иконки открытых окон со всех рабочих столов висят в лаунчере - загромождение
  • Раньше я все вообще используемые мною программы вынес на гномовскую панель, и они там отлично помещались. Теперь это что? Правильно - загромождение.

Что нравится 

 Лучше стал работать звук - прослушивание музыки перестало подвешивать систему. Ради этого и обновлялся с 11.04 до 12.04. Но к Unity это не относится, так что, видимо, в скором будущем буду экспериментировать с новым Гномом.

Хабр

Мою статью опубликовали на Хабре. Пусть и в песочнице, но все равно круто. Теперь я Ылита :)

Вот ссылочка - PHPExcel и большие файлы

четверг, 19 июля 2012 г.

PHPExcel и кодировка

У меня были проблемы с русской кодировкой при чтение xls файла при помощи PHPExcel. Кракозябры и почему-то iconv выдавал какую-то белиберду. Долго не мог найти в чем проблема, даже гугл не помог.

Потом полез ручками и оказалось, что оптимальное решение проблемы - это в файле Classes/PHPExcel/Reader/Excel5.php выставить нужную кодировку:

$this->_codepage            = 'CP1251';

Вот и все.

PHPExcel и большие файлы

PHPExcel - отличная библиотека с огромным функционалом по работе с форматами xls, xlsx. Можно считывать, записывать, менять форматирование, задавать формулы, а из xlsx можно и картинки вытаскивать.

Один минус у PHPExcel - вечно памяти не хватает, все время сыпятся ошибки "Fatal error: Out of memory". Этот пост о том, как это обойти.


Для чтения большого файла (~25 000 строк) я использовал своеобразное решение.

Считываем файл не целиком, а по несколько строк. Это делается так:

import_xls.php
require_once 'path/to/PHPExcel/IOFactory.php';

class chunkReadFilter implements PHPExcel_Reader_IReadFilter
{
    private $_startRow = 0;
    private $_endRow = 0;

    public function setRows($startRow, $chunkSize) {
        $this->_startRow    = $startRow;
        $this->_endRow      = $startRow + $chunkSize;
    }

    public function readCell($column, $row, $worksheetName = '') {
        //  Only read the heading row, and the rows that are configured in $this->_startRow and $this->_endRow
        if (($row == 1) || ($row >= $this->_startRow && $row < $this->_endRow)) {
            return true;
        }
        return false;
    }
}

session_start();

if ($_SESSION['startRow']) $startRow = $_SESSION['startRow'];
else $startRow = 13;

$fileName = "file.xls";
$inputFileType = 'Excel5';
$objReader = PHPExcel_IOFactory::createReader($inputFileType);
$chunkSize = 20;
$chunkFilter = new chunkReadFilter();

while ($startRow <= 65000) {
 $chunkFilter->setRows($startRow,$chunkSize);
 $objReader->setReadFilter($chunkFilter);
 $objReader->setReadDataOnly(true);
 $objPHPExcel = $objReader->load($fileName);
 //Что-то с этими строками делаем
 $startRow += $chunkSize;
 $_SESSION['startRow'] = $startRow;
unset($objReader);
unset($objPHPExcel);
}

echo "The End";
unset($_SESSION['startRow']);

Собственно класс chunkReadFilter - это то, что нам нужно. Устанавливаем его в качестве фильтра для чтения файла, и файл будет загружаться не целиком, а лишь определенное количество строк.

Кроме него еще используем такую полезную опцию как ReadDataOnly. Как ясно из названия, она позволяет не загружать форматирование документа, высвобождая место для данных.

И конечно же используем unset. Это так же поможет высвободить память.

Но помимо нехватки памяти возникает другая проблема. На большинстве хостингов у php-скриптов помимо ограничения на использование памяти, еще стоит ограничение на время выполнения. И крайне вероятно, что этого времени хватать не будет. Лично я обошел эту проблему при помощи сессий и повторяющихся ajax запросов. В коде представленном выше вы уже увидели использование сессий и завершающее "The End".

А вот код клиентской части

import_xls.html
<html>
<head>
<title>Импорт прайс-листа</title>
  <script src="/media/js/jquery.js" type="text/javascript"></script>
  <script src="/media/js/import-xls.js" type="text/javascript"></script>
</head>
<body>
<h1>Импорт прайс-листа</h1>
Подождите завершения импорта, не закрывайте данную страницу!
<div id="progress-bar">
</div>
<div id="content">
</div>
</body>
</html>

import-xls.js
function repeat_import() {
 $.get("import_xls.php", function(data){
  $("#progress-bar").append("I");
  if (data == "The End") {
   $("#content").html("<h2>Импорт завершен!</h2>");
  }
  else {
   $("#content").html(data);
   repeat_import();
  }
 });
}

$(function (){
 /*$(document).ajaxError(function (e, jqxhr, settings, exception) {
  error_message = jqxhr.status;
  alert(error_message);
 });*/
 repeat_import();
});

Т.е. мы отправляем ajax-запрос нашему скрипту, ждем ответа, и, если ответ нас не устраивает, посылаем новый ajax-запрос. Есть еще решение без использования AJAX - при помощи редиректа в самом php (header ("Location: import_xls.php");). Но лично мне больше нравится решение с AJAX, потому что тут можно легко и просто добавить прогресс-бар и какие-нибудь другие рюшечки. Кстати, внимательный читатель заметил, что в моем коде простой прогресс-бар уже реализован.



Для записи в формат xls так же около 25 000 строк крайне полезно использовать следующий код
$cacheMethod = PHPExcel_CachedObjectStorageFactory::cache_to_phpTemp;
$cacheSettings = array( 'memoryCacheSize ' => '256MB');
PHPExcel_Settings::setCacheStorageMethod($cacheMethod, $cacheSettings);
Можно еще поиграться с методами кеширования. Поддерживается

memcache
$cacheMethod = PHPExcel_CachedObjectStorageFactory::cache_to_memcache; $cacheSettings = array( 'memcacheServer' => 'localhost', 'memcachePort' => 11211, 'cacheTime' => 600 );


а так же cache_to_discISAM.

пятница, 6 апреля 2012 г.

Ubuntu 11.10 и Gnome 3

The shell in GNOME 3 can be modified by writing extensions in JavaScript.


o_O
...
вот те и на...