Как пользоваться Vim в *nix. Найти и изменить.
sunnyblik
Скажу, что я раньше всегда избегал пользования этого Vim и немного не понимал, зачем им пользоваться, когда есть другие редакторы, например, gedit.
Теперь отвечу: да, когда есть возможность им пользоваться - конечно, им удобно. Но иногда надо через ssh зайти на другой сервер или виртуальную машину и там открыть большой текстовый файл, найти определенные строки и изменить значения. Так вот! Когда вы заходите на другой сервер через ssh, то разумеется вы не можете там открыть его через gedit!

так что мне пришлось использоват редактор VIM. И я просто перечертыхался весь, т.к. он вообще интуитивно ни разу не понятный. Это просто полный пиздец, без мануала не разобраться вообще никак. Итак, я не буду писать всего, что поддерживает этот редактор (а поддерживает он как ни странно, многое), а только напишу как найти определенный текст и изменить его! Дада, это не так то просто!!! И самому не догадаться!

1. открываем файл редактором vim. Тут все стандартно:
> vim file.txt

2. Открыли. видим содержимое. (мы находимся в первом режиме работы редактора)
Нажимаем "Enter". (Таким образом мы переключились в другой режим работы редактора).  Видим внизу отобразилась строка для ввода. Пишем тут следующее:
/подстрока_которую_ищем
и нажимаем "Enter"

3. Чтобы переходить к следующему найденному надо нажимать "n".

4. И вот чудо! Вы нашли ту строку,которую вам надо исправить. Внимание!!! Мы можем бегать курсором по документу, но изменять его не можем!  Для того чтобы можно было исправить текст, надо нажать клавишу "i"

5. когда закончите правку, нажимайте "ESC"

6. Чтобы  сохранить изменения и выйти - наберите: "ZZ". Внимание! при наборе этим символов, сами символы отображаться на экране не будут!

7. Чтобы выйти без сохранения изменений наберите: "ZQ". Внимание! при наборе этим символов, сами символы отображаться на экране не будут!


Таким образом это полный ахтунг. Я не привык пользоваться вот такими командами. Поэтому и расписал все по шагам, потому что сам потратил прилично времени, чтобы разобраться с этим.

полезные ссылки:
https://ru.wikibooks.org/wiki/Vim - Викиучебник
https://beget.ru/articles/vim - Основы работы



P.S.
еще можно использовать редактор nano, только вот для того, чтобы он умел искать в документе, его надо запускать с опцией -u
подробнее хорошо написано тут: http://habrahabr.ru/post/106748/
Tags:

Шаблон имени файла при экспорте phpmyadmin
sunnyblik
При сохранении базы данных в phpmyadmin можно использовать следующие варианты шаблонов в имени файла:

1. Используем сокращенный формат даты и времени
@DATABASE@-%F-%T
Пример:
my_database-2015-11-25-11_07_31.sql

Где:
%F = обозначает формат даты "%Y-%m-%d" (year-month-day) Пример: 2015-11-25
%T = обозначает формат времени, 24 часа (24 hour format), hour_minute_second) Пример: 11_07_31


2. Используем расширенный формат, чтобы выводить в последовательности: число-месяц-год_час_минута_секунда
@DATABASE@-%d-%m-%Y-%T
Пример:
my_database-17-11-2015-19_43_54.sql

Imagick. Описание работы php расширения. Примеры изображений на выходе. Imagick. example image.
sunnyblik
Понадобилось работать с изображениями - а точнее делать ресайз и кроп. Выбором стал Image Magic.
Рассмотрю и приведу примеры работы наиболее востребованных методов расширения Image Magic. Частично переведу официальную документацию, дополню её пояснениями от себя и сделаю показательные примеры.

Оригинальное изображение, которое буду использовать для своих экспериментов:
оригинальное изображение



1. thumbnailImage()
Изменение размера изображения. Функция предназначена для создания небольших картинок для веба, которые будут занимать мало места на диске.
Если в качестве третьего параметра указать TRUE (разумеется, при указанных первых двух), то пропорции изображения будут сохранены. Если указаны не пропорциональные размеры, то в этом случае одна из сторон будет уменьшена для сохранения пропорции.
В случае если одни из параметров равен "0" - то этот параметр подгоняется под нужный, для сохранения пропорции.

Пример 1:
если указывать размеры по ширине и высоте - то изображение будет вытянуто под указанные размер. (пропорции не будут соблюдены)

<?php
header('Content-type: image/jpeg');
$image = new Imagick('orig.JPG');
$image->thumbnailImage(800, 200);
$image->writeImage('800x200_thumbnailImage.jpg');
echo $image;




На выходе получим изображение 800x200px, 86Kb:
800x200_thumbnailImage


Пример 2:
Указываю теже 800 на 200, но третьим параметром передаю true.

<?php
header('Content-type: image/jpeg');
$image = new Imagick('orig.JPG');
$image->thumbnailImage(800, 200, true);
$image->writeImage('800x200_thumbnailImage_true.jpg');
echo $image;




На выходе: пропорциональный размер картинки: 300x200px, 37kb:
800x200_thumbnailImage


Пример 3.
Нужно получить пропорциональное изображение равное по ширине 800px и неважно какое будет по высоте. Для этого укажем вторым параметром "0".

<?php
header('Content-type: image/jpeg');
$image = new Imagick('orig.JPG');
$image->thumbnailImage(800, 0);
$image->writeImage('800x0_thumbnailImage.jpg');
echo $image;




На выходе: пропорциональное изображение: 800x532px, 200Kb
800x200_thumbnailImage



2. adaptiveResizeImage()
Адаптивное изменение размера изображения. В отличие от thumbnailImage() - изображение получается очень резким и занимает значительно больше места на диске.
Особенно резкость заметна если изображение преобразовывается из большого в маленькое.
Если в качестве третьего параметра указать TRUE (разумеется, при указанных первых двух), то пропорции изображения будут сохранены. Если указаны не пропорциональные размеры, то в этом случае одна из сторон будет уменьшена для сохранения пропорции.

Пример 1:
<?php
header('Content-type: image/jpeg');
$image = new Imagick('orig.JPG');
$image->adaptiveResizeImage(800, 0);
$image->writeImage('800x0_adaptiveResizeImage.jpg');
echo $image;




На выходе: пропорциональное изображение: 800x532px, 283Kb!




Пример 2:
<?php
header('Content-type: image/jpeg');
$image = new Imagick('orig.JPG');
$image->adaptiveResizeImage(200, 0);
$image->writeImage('200x0_adaptiveResizeImage.jpg');
echo $image;




На выходе: пропорциональное изображение: 200x133px, 86Kb!



Пример 3:
<?php
header('Content-type: image/jpeg');
$image = new Imagick('orig.JPG');
$image->adaptiveResizeImage(300, 100);
$image->writeImage('300x100_adaptiveResizeImage.jpg');
echo $image;




На выходе: получили изображение 300x100px (вытянутое, т.к. не указан третий параметр true),


Пример 4:
<?php
header('Content-type: image/jpeg');
$image = new Imagick('orig.JPG');
$image->adaptiveResizeImage(300, 100, true);
$image->writeImage('300x100_adaptiveResizeImage_true.jpg');
echo $image;




На выходе: получили изображение 150x100 (пропорциональное, т.к. указан третий параметр true) 150x100px, 88Kb



3. cropThumbnailImage
Создает изображения указанных размеров от центра. (увеличивая или уменьшая изображене). Другими словами - кропает по центру.

Пример 1:
<?php
header('Content-type: image/jpeg');
$image = new Imagick('orig.JPG');
$image->cropThumbnailImage(250, 250);
$image->writeImage('250x250_cropThumbnailImage.jpg');
echo $image;




На выходе: в результате кропа по центру - получили квадрат, в результате обрезки фотки слева и справа 250x250px, 38Kb



Пример 2:
<?php
header('Content-type: image/jpeg');
$image = new Imagick('orig.JPG');
$image->cropThumbnailImage(800, 200);
$image->writeImage('800x200_cropThumbnailImage.jpg');
echo $image;




На выходе: в результате кропа по центру - получили прямоугольную фотографию, в результате обрезки фотки сверху и снизу. 800x200px, 94Kb


Выводы:
Самыми полезными методами оказались  thumbnailImage() и cropThumbnailImage(). Изображения получаются хорошими по качеству (почти такимиже как и при изменении размера в фотошопе) и мало занимают места на диске весят.
Метод adaptiveResizeImage() - показал себя слишком большой резкостью и слишком большим весом изображения. По сравнению с предыдущими - в 1.5 - 2 раза!

Полезные ссылки по теме:

  1. http://www.phpro.org/examples/Create-Favicon-With-Imagick.html - установление формата, делаем иконку

  2. http://www.sitepoint.com/crop-and-resize-images-with-imagemagick/  - загрузка изображения на сервер и кроп

  3. http://habrahabr.ru/post/140704/  Как создать Instagram фильтры

  4. http://www.php.net/manual/ru/imagick.examples-1.php Создание миниатюр для всех JPG файлов в директории

  5. http://www.sitepoint.com/watermarking-images/ Накладываем водяной знак:

А какой вы пользуетесь библиотекой и почему? Пишите в комментариях
Tags: ,

Jquery. Полезные приемы.
sunnyblik
//Отображение поля по щелчке на check box
$('#hall_is_exist').click(function(){
this.checked?$('#hall_block').show(1000):$('#hall_block').hide(1000);
});

//Проверить существование элемента на странице
if($("#findID").length) {
// exists
}
Хорошо описано тут: http://interestabout.blogspot.ru/2011/07/jquery.html


//Удаление элемента со страницы
$('#findID').remove();


//Добавление элемента на странице. Например последним в body
var element = 'Привет';
$('body').append(element);


Отследить событие на элементе, добавленного через ajax
.on();
http://jquery.page2page.ru/index.php5/On


//Взять значение заполненного поля:
<input name="ImageGalleryAlbum[name]" id="ImageGalleryAlbum_name" type="text" maxlength="100" value="Некое значение">
$('#institution_id').val();

<input name="ImageGalleryAlbum[is_main]" id="ImageGalleryAlbum_is_main" value="1" type="checkbox">
$('#album_is_main').is(':checked') ? 1 : 0


//Берем значения (параметры) из формы и записываем в формате JSON:
var params = {
institution_id : $('#institution_id').val(),
name           : $('#album_name').val(),
is_main        : $('#album_is_main').is(':checked') ? 1 : 0,
id             : $('#album_id').val(),
hall_id        : $('#album_hall_id').val()
}


// param() Преобразование объектов для использования в url
Описание на русском
var myObject = {
one: 1,
two: 2,
three: 3
};
var recursiveEncoded = $.param(myObject); // one=1&two=2&three=3


//Автоматом берем значение из формы и записываем в строку
var str = $("#ImageGalleryAlbum").serialize();
console.log(str); //album_id=4&hall_id=2

//Автоматом берем значение из формы и записываем в массив. В этом случае удобно добавлять параметры через push
var str = $("#ImageGalleryAlbum").serializeArray();
str.push({
name: "institution_id",
value: 7
});
console.log(str); // [ Object {name="album_id", value="4"}, Object {name="hall_id", value="2"}]
str = $.param(str);
console.log(str); // album_id=4&hall_id=2&institution_id=7

Использование ролей в Yii через простой RBAC (Role based access control)
sunnyblik
***** В ПРОЦЕССЕ НАПИСАНИЯ *****
Известно, что для аутентификации и авторизации пользователя нам необходимо использовать 2 компонента:

  • CUserIdentity. Наследуем класс, переопределяем метод authenticate(), который возвращает верно ли соответствие $user и $password. Еще можно перекрыть метод getid(), и использовать метод setState() - для хранения информации в cookie.

  • CWebUser. - доступ к нему через Yii::app()->user. Для того, чтобы произвести вход в приложение, надо компонент CUserIdentity передать в метод Yii::app()->user->login($identity, 3600*24*7)


Где хранится роль
Роль у нас будет храниться в БД. Таблица users, поле role  -enum(user, admin).


Переопределяем в контроллере метод filters();

public function filters()
{
  return ['accessControl']
}






Переопределяем accessRules(), в котором определяем правила доступа фильтра accessControl:
public function accessRules()
{
  return [
    [
      'allow',
      'actions' => ['index'],
      'users'   => ['*']
    ]
  ];
}






Создаем методы в components/WebUser:

  • getRole()

  • setRole()

  • isRootRole()

  • getName()

Tags:

Прототипирование интерфейсов. Мой выбор - Divshot.com. Онлайн прототипирование.
sunnyblik
Столкнулся я с проблемой - в какой программе и где мне прототипировать интерфейс для проекта. Учитывая, что я не проектировщик, никогда не пользовался специальными для этого программами. Главное для меня - определиться с элементами на странице и их примерным расположением, задачами самого интерфейса для каждой страницы.

Многие частенько ищут: прототипирование интерфейса онлайн - чтож, эта статья как раз об этом =)

Что мне хотелось получить от программы прототипирования:

  • быстрое накидывание элементов таких как картинки, табы, меню, кнопки... Другими словами базовые и необходимые элементы на любом сайте

  • показать свое творение другому человеку

  • взять получившийся код верстки для внедрения на сайт для наглядности на этапе разработки с целью демонстрации функционала и наилучшего в будущем донесения идеи для дизайнера

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

Пришлось посмотреть множество видео, прочитать кучу статей на хабре и не только на эту тему, вобщем, перерыл просто гору материала. Понял, что прототипирование интерфейса для сайта - это целая наука, отрасль и, наконец, профессия.

И я себя, для данной задачи - остановился на удобном веб интерфейсе - Divshot.com
Это приложение доступно из браузера, интуитивно понятное, простое, бесплатное и без наворотов. Используется фреймворк Twitter Bootstrap. Можно натаскивать элементы вручную не думая о коде, а можно ручками править прямо в этом приложении верстку. Для меня было удобнее сразу же писать код ручками. Можно насоздавать папок, а в них станицы. Можно послать ссылку другу на оценку получившихся творений, и откроется сразу же html страничка. А также выгрузить получившийся код одним кликом.
Очень удобная штука в рамках ограниченного бюджета, времени и количества задействованных человек. Не надо разбираться в таких сложным программах как axure и прочих.


Даю ссылки на полезные материалы, которые я изучил по этой теме:

  1. Подход к проектированию веб сайтов. XMind, Workbench, hotgloo.com http://habrahabr.ru/post/111363/

  2. Яндекс конференция. Прототипирование на живом проекте. Как работают с прототипами в Яндексе, какие фреймворки используют. Какая взаимосвязь: прототип-дизайн-разработка-продакш. http://events.yandex.ru/events/yasubbotnik/msk-jul-2012/talks/304/

  3. Обзор веб-сервисов для создания макетов от Сmslist.ru http://iloveicons.ru/web-services-for-mocups/

  4. Список инструментов для прототипирования на хабре:

  5. Axure. Живые прототипы. Вебинар Дмитрия Сатина http://www.youtube.com/watch?v=BBySdd3ZNRM

  6. Прототипирование в VISIO:

  7. Прототипирование в AXURE:


P.S. Благодарю Артема Остапец, который мне посоветовал использовать divshot.com =)

Cоздание двух колонок с timestamp в MYSQL: date_create, date_update
sunnyblik
Задача: завести 2 поля в БД, чтобы автоматом вписывались значения при заведении новой записи и редактировании

Mysql по умолчанию запрещает создание колонок имеющие в default и in update значение current_timestamp.
То есть при попытке создать

`date_create` timestamp NULL default CURRENT_TIMESTAMP , 
`date_update` timestamp NOT NULL on update CURRENT_TIMESTAMP,
 



Будет ошибка: #1293 - Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause.
Такая же ошибка вылетает, если попытаться создать 2 колонки TIMESTAMP, указав во второй on update CURRENT_TIMESTAMP.
Всё дело в том, что при создании колонок TIMESTAMP, они должны быть ненулевыми, так как если попытаться вставить туда NULL, поле будет заполнено текущим временем ("TIMESTAMP columns are NOT NULL by default, cannot contain NULL values, and assigning NULL assigns the current timestamp.")
Поэтому, для создания хотя бы двух колонок, из которых current_timestamp должна содержать вторая приходится писать вот так:

CREATE TABLE `foo`.`bar` (
  `date_create` TIMESTAMP NOT NULL default '0000-00-00 00:00:00',
  `date_update` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
)





Пример в командной строке:

create table test_table(
id integer not null auto_increment primary key,
stamp_created timestamp default '0000-00-00 00:00:00',
stamp_updated timestamp default now() on update now()
);


 mysql> insert into test_table(stamp_created, stamp_updated) values(null, null); 
Query OK, 1 row affected (0.06 sec)
mysql> select * from t5; 
+----+---------------------+---------------------+ 
| id | stamp_created       | stamp_updated       |
+----+---------------------+---------------------+
|  2 | 2009-04-30 09:44:35 | 2009-04-30 09:44:35 |
+----+---------------------+---------------------+
2 rows in set (0.00 sec)  
mysql> update test_table set id = 3 where id = 2; 
Query OK, 1 row affected (0.05 sec) Rows matched: 1  Changed: 1  Warnings: 0  
mysql> select * from test_table;
+----+---------------------+---------------------+
| id | stamp_created       | stamp_updated       | 
+----+---------------------+---------------------+ 
|  3 | 2009-04-30 09:44:35 | 2009-04-30 09:46:59 | 
+----+---------------------+---------------------+ 
2 rows in set (0.00 sec)  
mysql>





Источники:
Информация почерпнута отсюда: http://gusiev.com/2009/04/update-and-create-timestamps-with-mysql/
и отсюда: http://playittilldeath.livejournal.com/27919.html
Tags: ,

Задачка по js. Доступ к перменной в двух функциях, через неглобальную область видимости
sunnyblik
Задача: Есть 2 функции. В каждой функции осуществить доступ к переменной. Эта переменная должна быть неглобальной

Однако решение очень простое:





(function ()
    {
  
      var b1 = 1;
  
      function a1()
      {
        alert(b1);
      }

      function a2()
      {
        alert(b1);
      }
      a1();
      a2();
    })();


* This source code was highlighted with Source Code Highlighter.





Таким образом, обернув наш код в безымянную функцию, мы объявили переменную в неглобальном пространстве! Что и нам требовалось!

Задача 2: Через метод apply передаем нужное значение this


(function ()
    {
     
      var b1 = 1;
     
      function a1()
      {
        alert(b1);
      }

      function a2 ()
      {
        alert(b1);
        this.a4 = function ()
        {
          alert(b1);
        }
       
      }
      a1(); //для тестирования. работает
      a2.a4(); //Оошибка: has no method 'a4'
      a2.apply(a2); //передаем значение параметра this
      a2.a4(); //работает
    })();


* This source code was highlighted with Source Code Highlighter.

Где купить рабочие прокси для Key Collector ?
sunnyblik
Рекомендую внимательно изучить раздел официального мануала (Новые возможности версии 2.7), прежде чем читать мою статью
Потому как может быть такое, что для ваших целей прокси севрера могут быть и не нужны:


Работаем в Key Collector через прокси. Где купить хорошие, чтобы быстро работали
Если вы используете программу Key Collector для составления семантического ядра, то понятное дело, что парсить wordstat через свой ip адрес нельзя (если вы не хотите, чтоб вас заблокировали)

Что делать если вас уже забанили в Wordstat (он заблокирован):
Напишите в поддержку (вроде бы там появляется окно обратной связи в случае блокировки). Я честно признался, что парсил wordstat, мол не знал что такие будут последствия и прошу разбанить. Разбанили на следующий день и написали, что если еще раз так буду делать - то бан уже будет надолго.

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

Вопрос - где взять прокси сервера для Key Collector?
Типы прокси:
1. Бесплатные/дешевые прокси

Плохой вариант. Либо они забанены, либо медленные, либо с капчей.
Я купил около 600 прокси (~2 WMZ), рабочими оказались около 20. Из них все запрашивали капчу. Вариант меня не впечатлил и я стать искать другие варианты

2. Купить прокси сервер у хостинг провайдера.
Стоимость около 2$ за прокси. Можно купить несколько прокси и парсить в много потоков.
Например, тут (форум maultalk.net)

3. VPN HotStopShield
Бесплатно подменяем свой ip адрес, большая скорость сканирования.
Минусы: как вы догадываетесь, парсить можно только в один поток
У меня негативный опыт по этой программе. HotStopShield не имеет даже настроек! Написано в описании программы - что она подменяет трафик автоматом. Если с браузером это видно (можно проверить по ip и значку в окне), то в KeyCollector это не видно. Поэтому я решил не рисковать.
Да и к тому же навязчивая реклама, всплывающие окна - это совсем не гуд.
Подробнее об этом описал Leossandro на webmasters.ru/forum/
Если кто разобрался с ней относительно KeyCollector - пишите в комментариях.

4. Tor
Курсе на 2 универа я впервые познакомился с ней. Но с тех пор прошло много лет, и я забыл о ее существовании.
Итак, скачиваем: https://www.torproject.org/
После установки у вас автоматом откроется браузер FireFox, в котором вы можете анонимно серфить интернет.
У Тора есть многочисленные настройки! И вот так выглядит главное окно программы:
tor
Нажимаем кнопку "Сменить личность" для смены нашего ip адреса.
Теперь открываем Key Collector и пишем следующие настройки:
выбираем сервер: socks5 (потому что Tor работает с socks5)
и пишем: 127.0.0.1:9050

Проверяем, и у вас прокси должен загореться зеленым (как у меня на скрине). Если прокси не проходит, то нажимаем в программе Tor кнопку "Сменить личность" и заново проверяем в Key Collector
настрока key collector для tor



Я привел 4 способа откуда брать прокси сервера, пишите свои отзывы и замечания в комментариях!

Парсинг строки и преобразование в маркированный список html
sunnyblik
Задача: Преобразовать длинную текстовую строку (с символами табуляции, новой строки) в маркированный html список. Учесть вложенность.

Строка на входе:
строка на входе
Рис.1

На выходе надо получить вот такой маркированный список:
html список

html код:
[html код]
Условия
<ul>
 <li>Купон дает скидку 68% на день игры в сети пейнтбольных клубов "Территория"</li>
 <ul>
  <li><strong>Вы заплатите 190 руб. вместо 610</strong></li>
 </ul>
 
 <li>В стоимость купона входит:</li>
 <ul>
  <li>100 шаров для игры</li>
  <li>полный игровой день в клубе</li>
  <li>камуфляж, маркер, маска</li>
  <li>заправка газом на весь день и работа судьи</li>
  <li>жидкость от запотевания масок</li>
  <li>теплые раздевалки, душ, туалет</li>
 </ul>
 
 <li>Скидка 10% на дополнительные шары при условии разовой покупки от 4000 шаров на компанию</li>
 <li>У клуба имеются 2 площадки в ближайшем подмосковье: площадка №1 и площадка №2</a></li>
 <li>Действует обязательная предварительная запись на игру по телефону: +7 (910) 406-0686, +7 (909) 155-2373, с указанием наличия купона</li>
 <li>Если Вы приобрели купон, но не воспользовались им до окончания срока действия, то купон считается использованным</li>
 <li>Вам проведут подробный инструктаж перед игрой и предоставят индивидуального инструктора на время игры группы</li>
 <li>Минимальное количество человек в группе – 2 человека (у маленьких групп есть возможность присоединяться), максимальное – не ограничено</li>
 <li>Скидка по купону не суммируется с другими предложениями клуба</li>
 <li>Обязательно предъявляйте распечатанный купон перед игрой</li>
 <li>Купон действителен до 17 апреля 2013 года</li>
</ul>
 
Особенности
<ul>
 <li>Качественное обрудование</li>
 <li>Достойные цены</li>
 <li>Профессиональные сотрудники</li>
 <li>Индивидуальный подход к каждому клиенту</li>
</ul>




Введение:
Паттерн
В этой задаче будем использовать следующий паттерн: разделение на парсинг строки, автомат и рендеринг маркированного списка html.
Что это дает:

  1. Механизм, который можно понятно расширять

  2. Устойчивый к выбросам на входе - например много пустых строк или что-то в этом духе

  3. Отделили парсинг от вывода. Например резонно захотеть выводить строки с 2-мя табами ни как список, а просто как один параграф, при этом автомат менять не придется.

Детерминированный конечный автомат
Диаграмма состояний выглядит следующим образом:
граф переходов
где:
Н - начало автомата
К - конец автомата
tab() - есть ли в строке из стека символ табуляции?
tab2() - есть ли в строке из стека 2 символа табуляция?
empty() - пуст ли стек?

Массив, из которого рендерим html список
Рендерить такой список удобней всего из массива. Структура нашего массива будет идентична структуре массива СMenu в Yii, а именно:
/* пример CMenu
$arr = array(
         array('label'=>'Домашняя', 'url'=>array('site/index')),
         array('label'=>'Товары', 'url'=>array('product/index'), 'items'=>array(
             array('label'=>'Новые поступления', 'url'=>array('product/new', 'tag'=>'new')),
             array('label'=>'Наиболее популярные', 'url'=>array('product/index', 'tag'=>'popular')),
         )),
         array('label'=>'Вход', 'url'=>array('site/login'), 'visible'=>'ll'),
     );
*/
 
//по образу создаем массив, который хотим получить
$arr = array(
         array('label'=>'Условия', 'items' => array(
   array('label' => 'Купон дает скидку 68', 'items'=> array(
    array('label' => 'Вы заплатите 190 р'
   ))),
   array('label' => 'В стоимость входит', 'items'=> array(
   ))
   ))
  );


Алгоритм решения
1. Преобразуем строку в массив. (разбиваем на массив по символу "\n" - новая строка). И запихиваем в стек.
2. С помощью детерминированного конечного автомата проходим по всем элементам массива и записываем результирующий массив (структура полученного массива идентична структуре CMenu в yii)
3. Генерация маркированного списка по результатам массива CMenu

Решение
1. Помещаем нашу большую строку (Рис. 1) в стек.
Разбиваем на массив, и запихиваем его в стек (для того, чтоб его мог использовать детереминированный конечный автомат)
$inputStr = 'Огромная строка на входе';
$inputArray = explode ("n",$inputStr);
$inputArray = array_reverse($inputArray);
$stack = new SplStack();
foreach ($inputArray as $value)
{
  $stack->push($value);
}



2. Заполняем массив дискаунт данными, в соответствии с раннее обозначенной структурой (как CMenu в Yii):
$discount = array();
$firstCh = -1; //первый элемент массива. -1 т.к. прибавим +1, если будет строка без таба
$state = 'p0';
while(!$stack->isEmpty())
{
 switch($state) {
  case 'p0':
   $str =  $stack->pop(); // выводим из очереди
   if (preg_match ('/tt/', $str) && strlen($str)>4)
   {
    $state = 'p2';
   }
   elseif (preg_match ('/t+/', $str) && strlen($str)>4)
   {
    $state = 'p1';
   }
   elseif (preg_match ('/^[a-zA-Zа-яА-Я]+/', $str) && strlen($str)>4)
   {
    $state = 'p3';
   }
   else
   {
    $state = 'p4';
   }
   $stack->push($str); // помещаем в очередь (в начало массива)
   break;
  case 'p2':
   //2 таба';
   $last = count($discount[$firstCh]['items']) - 1;
   $discount[$firstCh]['items'][$last]['items'][] = array('label' => $stack->pop());
   $state = 'p0';
   break;
  case 'p1':
   //1 таб';
   $discount[$firstCh]['items'][] = array('label' => $stack->pop());
   $state = 'p0';
   break;
  case 'p3':
   // без таба
   $firstCh++;
   $discount[$firstCh]['label'] = $stack->pop();
   $state = 'p0';
   break;
  case 'p4':
   //другое
   $stack->pop();
   $state = 'p0';
   break;
 }
}



3. И, наконец, функция генерации самого меню:
function renderMenuWhile($items)
{
 echo '<ul>';
 foreach ($items as $v)
 {
  echo '<li>';
  echo $v['label'];
 
  while (count($v['items']) >0)
  {
   echo '<ul>';
    //у каждого родителя проходим по дочерним элементам
    foreach ($v['items'] as $value)
    {
     echo '<li>';
     echo $value['label'];
     echo '</li>';
    }
   echo '</ul>';
   if (count($value['items']) > 0)
    $v['items'] = $value['items'];
  }
  echo '</li>';
 }
 echo '</ul>';
}



Вот, собственно, и все!

Выражаю благодарность Алексею Шарову, который объяснил мне этот материал. Иначе..., как минимум, не было бы этой статьи ;)

?

Log in

No account? Create an account