ФорумПрограммированиеPHP для идиотов → Events

Events

  • Абырвалг

    Сообщения: 6476 Репутация: N Группа: Джедаи

    Spritz 20 октября 2009 г. 4:06

    Короче такая маза: не жалеет нос…

    Начну издалека.
    Давайте рассмотрим несколько модулей, которые вроде бы связаны между собой. Товары, заказы, галерея для товаров. В случае, если мы удаляем товар следует удалить также прикрепленные к нему картинки (как записи из базы так и с файловой системы). Если есть заказы, которые используют этот товар - то их нужно либо тоже удалить, либо перейти к ним, или че-то еще сделать по желанию админа. Это хорошо, когда мы заранее знаем что от чего зависит. Но бывает немного по-другому.

    1) В момент, когда модуль А должен проверить зависимости от модуля Б - Б не загружен. И это нормально.
    2) В момент, когда модуль А должен проверить зависимости - мы не знаем, какие зависимости у нас определены. Да, бывает и такое. Например модуля галерея может и не быть в системе или он отключен. Зачем удалять картинки, которых нет?

    В JS есть отличная вещь - callbacks. В пыхе версии 5.30 тоже появилась. Но они все равно не решат проблему 2. Проблему 1 частично решат они и __autoload.

    Идем дальше. Предлагаю добавить немного событий. Я уже пытался обсуждать это на php.ru, там идею зафукали. Сказали, что это вообще нифига не события.

    Примерный набросок того, чего я хочу: http://pastebin.mozilla-russia.org/102212
    Как использую:

    <?
    // какой-то дополнительный event
    public function event2($page)
    {
    return str_replace('т', '*', $page);
    }

    public function run()
    {
    $page = getContentPageById(2);
    // путь к папке, в которой сложены event'ы, которые следует запускать
    $eventsPath = 'config/events/modules/user/content/beforeAssign/';
    $page['content'] = EventsManager::instance()
    // аттачим дополнительный event, кроме тех, что в папке
    ->attach('content/beforeAssign', array($this, 'event2'))
    // вызываем все event'ы
    ->call('content/beforeAssign', $eventsPath, $page['content']);
    }

    // файл с основным event'ом, лежит в папке config/events/modules/user/content/beforeAssign
    function testFunc($content)
    {
    return str_replace('а', '_', $content);
    }

    return 'testFunc';


    какие плюшки мы получаем:
    мы можем добавить какой-то модуль, который будет вызываться другими модулями и не нужно будет править код этих других модулей. Такая независимая зависимость. Например я пишу плагин, который будет заменять все вхождения слова "селедка" в теле комментариев, контента, новостей на слово "скумбрия". При установке этого плагина копируются его главные файлы, он копирует файлы-event'ы в папки. Модуля комментариев даже может и не быть на сайте. Ничего страшного, мы создадим папку, скопируем туда файл. При удалении плагина - просто удалим эти файлы с event'ами

    какие минусы:
    - используется много папок и файлов.
    - при каждом вызове event'а мы сканируем папку на файлы
    - у event'ов нет сортировки/приоритетов. Мы можем сначала удалить все картинки товара, а потом вдруг сказать пользователю: "бааа! да у нас же тут некоторые заказы его используют". В принципе можно именовать файлы по приоритетам 1_checkOrders.php, 4_removeImages.php. Тогда в checkOrders будем бросать исключение и removeImages уже не выполнится.

    Еще можно хранить эти event'ы в базе, но я не хочу в базе хранить php-код. И может быть я буду event'ить подключение с базой (для какого-нить системного лога).

    В общем высказывайтесь. Может посоветуете че-нить, как удобно их хранить.
  • Trej Gun

    Сообщения: 5299 Репутация: N Группа: в ухо

    Spritz 21 октября 2009 г. 3:55, спустя 23 часа 49 минут 33 секунды

    о! вменяймый чел держите его чтоб с форума не свалил)))

    почитал я что ты делаешь. и могу сказать что я подобную реализацию уже видел тут http://neocrome.ru/
    скачай движло посмотри как присоединяются плагины

    когда плагин устанавливается он заносит в базу какие хуки он перехватывает и с каким приоритетом
    типа user.profile.onChangeAvatar или standalone
    файлы плагинов проименованы myPlugin.user.profile.onChangeAvatar.php
    в начале скрипта все записи о плагинах считываются из бд в массив (и кешируются)
    на страницах есть вызовы хуков которые из этого массива берут имя плагина и инклудят соответствующий файл

    Спустя 61 сек.
    плюсы
    + приоритет
    + один плагин - одна папка
    + ничего не сканируем
  • Абырвалг

    Сообщения: 6476 Репутация: N Группа: Джедаи

    Spritz 21 октября 2009 г. 6:43, спустя 2 часа 47 минут 51 секунду

    вообще нужно посмотреть как это во фреймворках реализовано
    http://docs.kohanaphp.com/core/event
    http://docs.kohanaphp.com/general/events
    диаграмма на русском
    http://brotkin.ru/examples/kohana_docs/kohana_sequences_rus.png
  • Абырвалг

    Сообщения: 6476 Репутация: N Группа: Джедаи

    Spritz 21 октября 2009 г. 10:15, спустя 3 часа 31 минуту 47 секунд

    ваще идею о событиях я вынашиваю эдак с 2 месяца. Несмотря на то, что работаю в разработке системы, в которой это уже внедрено. Но не так, как я хочу. А уж что-то писать на эту тему стал позавчера.

    Вообще можно обойтись без сканирования директории. И без базы. Мы можем просто складывать в файл все callbacks:

    // @file events/module.shop.goods.delete.php
    return array(
       'event1',
       'event2'
    );

    // @file events/system.logIn.php
    return array();


    Почему я так не делал(ю)?
    при установке/удалении модуля нужно ручками прописывать callbacks. Да, можно пробовать править этот файл регулярками, но это потенциально опасно, гыгы.

    Что можно придумать, что б хранить все callbacks в одном файле?
    Написать класс EventInstaller. Он будет пытаься загрузить файл с существующими callbacks для event'а, преобразовывая это в массив, делать array_push (install) или unset (unistall) для выбранного нового callback'а, сохранять это все заново, используя var_export и запись в файл.

    преимущества:
    + не нужна база
    + один файл, ничего не нужно сканировать
    +- в теории можно проритеты сделать. Например всего есть 5 приоритетов (5 - наивысший) - делаем EventSetup('eventName', 'callback', $priority); Один раз. При установке модуля.

    недостатки по сравнению с файлом для каждого callback'а:
    если для каждого callback делать свой файл, то эту функцию-callback можно в нем же и объявить. Тут же это невозможно сделать.

    Вот такие мысли у меня по этому поводу.
  • phpdude

    Сообщения: 26624 Репутация: N Группа: в ухо

    Spritz 22 октября 2009 г. 4:05, спустя 17 часов 49 минут 32 секунды

    я склоняюсь к тому, что каждый модуль имеет свою папочку, а что в ней, это дело другое, но там ВСЕГДА есть файлик init.php который делает нечто вида

    Events::register("ob_engine_start",array("mymodule_events","engine_start"));


    ну и инит подключает там необходимые модули и тп.

    если инита нет, значит он тут не нужен :)

    ну и движек нечто вида

    foreach(glob("modules/*") as $module)
    {
      if("$module/init.php") require_once "$module/init.php";
    }


    делает :)

    надеюсь обхяснил не как еблан :)
    Спустя 52 сек.
    а Events - класс имплементящий registry pattern. ну и ::register($eventname,$callback,$priority=10);

    это так, к примеру :)
    Сапожник без сапог
  • artoodetoo

    Сообщения: 5139 Репутация: N Группа: в ухо

    Spritz 21 октября 2009 г. 12:13, спустя 8 часов 8 минут

    В Yii интересно сделано:
    - все основные классы — потомки класса CComponent, а в нем заложен механизм Events на чтение/запись свойств.
    - в любой момент времени можно добавить свой event любому объекту. подробности можно поискать в доках и сорцах по слову "behavior".
    - можно модифицировать загрузчик классов чтобы он читал некую конфигурацию и инициировал набор ивентов при загрузке класса и создании инстанса
    ιιlllιlllι унц-унц
  • Sinkler

    Сообщения: 8059 Репутация: N Группа: в ухо

    Spritz 21 октября 2009 г. 13:19, спустя 1 час 6 минут 36 секунд

    /me держит Абырвалг, чтобы не убежал с форума…
  • phpdude

    Сообщения: 26624 Репутация: N Группа: в ухо

    Spritz 21 октября 2009 г. 22:14, спустя 8 часов 54 минуты 38 секунд

    artoodetoo, и как там реализовано это чтение и запись свойств?…
    Сапожник без сапог
  • krasun

    Сообщения: 1370 Репутация: N Группа: Джедаи

    Spritz 21 октября 2009 г. 22:49, спустя 35 минут 35 секунд

  • artoodetoo

    Сообщения: 5139 Репутация: N Группа: в ухо

    Spritz 22 октября 2009 г. 0:21, спустя 1 час 31 минуту 39 секунд

    phpdude, в базовой поставке нет никаких специальных правил насчет проекции Behavior классов на файловую систему, если ты об этом.
    Есть конфиг приложения, где описывается практически всё.
    Лучше читай первоисточник. Я навру, недорого возьму :)
    ιιlllιlllι унц-унц
  • Trej Gun

    Сообщения: 5299 Репутация: N Группа: в ухо

    Spritz 22 октября 2009 г. 3:59, спустя 3 часа 38 минут

    phpdude, ты хоть код оформляй

    ты там описал то на что я ссылку давал

    Yii вообще класное движло, его создатели в свое время написали Prado
    если б я чтото и делал на пхп то именно на нем, там очень четкая объектная модель, тоесть совсем нет процедурного кода как в вордпресе
  • phpdude

    Сообщения: 26624 Репутация: N Группа: в ухо

    Spritz 22 октября 2009 г. 4:06, спустя 6 минут 31 секунду

    вордпресс гумно про код. адское =)))

    CTAPbIu_MABP, оформил

    я ссылке не четаю, сорре =))

    чмоке)

    + писал ночью уставший и злой
    Сапожник без сапог
  • Абырвалг

    Сообщения: 6476 Репутация: N Группа: Джедаи

    Spritz 4 февраля 2010 г. 12:20, спустя 105 дней 9 часов 14 минут

    нужно их как-то именовать. Пока думаю насчет такого:
    a - after, b - before
    /**
    * eType examples:
    * 'admin/content/bSave' - admin, module (когда сохраняем страничку с контентом при редактировании)
    * 'admin/content/aDelete' - admin, module
    * 'application/bRender' - frontend, system  (это перед тем, как главный шаблон отрендерится)
    * 'system/aLogin' - system (когда входит под своей учеткой челоек. Причем без разницы куда он входит: в админку или в клиентскую часть)
    * 'user/content/bAssign' - frontend, module (перед тем, как модуль отдаст pageTitle, meta-информацию и основную информацию в главный шаблон)
    **/

    Спустя 42 сек.
    фак, хотел моноширный шрифт применить, а отредактировать нельзя (
  • phpdude

    Сообщения: 26624 Репутация: N Группа: в ухо

    Spritz 4 февраля 2010 г. 12:21, спустя 1 минуту 23 секунды

    pyha помогает
    Сапожник без сапог
  • Абырвалг

    Сообщения: 6476 Репутация: N Группа: Джедаи

    Spritz 13 апреля 2010 г. 3:08, спустя 67 дней 13 часов 47 минут

    эх, 20 октября - первый пост на Пыхе)
    Итак, кто-то сделал перевод описания RequestHandler'а ( http://habrahabr.ru/blogs/symfony/51505/ ). До этого я ессно тоже видел его, просто было лень читать описание на инглише.

    Вот думаю писать для BL свою систему ивентов или взять эту?

Пожалуйста, авторизуйтесь, чтобы написать комментарий!