Hooks = $this->Application->makeClass('kHookManager'); $this->ScheduledTasks = $this->Application->makeClass('kScheduledTaskManager'); $this->Request = $this->Application->makeClass('kRequestManager'); } /** * Sets data from cache to object * * @param Array $data * @access public */ public function setFromCache(&$data) { $this->Hooks->setFromCache($data); $this->ScheduledTasks->setFromCache($data); $this->buildEvents = $data['EventManager.buildEvents']; } /** * Gets object data for caching * * @return Array * @access public */ public function getToCache() { return array_merge( $this->Hooks->getToCache(), $this->ScheduledTasks->getToCache(), Array ( 'EventManager.buildEvents' => $this->buildEvents, ) ); } /** * Returns information about registered scheduled tasks * * @param bool $from_cache * @return Array * @access public */ public function getScheduledTasks($from_cache = false) { return $this->ScheduledTasks->getAll($from_cache); } /** * Add new scheduled task * * @param string $short_name name to be used to store last maintenance run info * @param string $event_string * @param int $run_schedule run schedule like for Cron * @param int $status * @access public */ public function registerScheduledTask($short_name, $event_string, $run_schedule, $status = STATUS_ACTIVE) { $this->ScheduledTasks->add($short_name, $event_string, $run_schedule, $status); } /** * Run registered scheduled tasks with specified event type * * @param bool $from_cron * @access public */ public function runScheduledTasks($from_cron = false) { $this->ScheduledTasks->runAll($from_cron); } /** * Runs scheduled task based on given data * * @param Array $scheduled_task_data * @return bool * @access public */ public function runScheduledTask($scheduled_task_data) { return $this->ScheduledTasks->run($scheduled_task_data); } /** * Registers Hook from sub-prefix event to master prefix event * * Pattern: Observer * * @param string $hook_event * @param string $do_event * @param int $mode * @param bool $conditional * @access public */ public function registerHook($hook_event, $do_event, $mode = hAFTER, $conditional = false) { $this->Hooks->registerHook($hook_event, $do_event, $mode, $conditional); } /** * Registers build event for given pseudo class * * @param string $pseudo_class * @param string $event_name * @access public */ public function registerBuildEvent($pseudo_class, $event_name) { $this->buildEvents[$pseudo_class] = $event_name; } /** * Runs build event for given $pseudo_class instance, when defined * * @param string $prefix_special * @param string $pseudo_class * @param Array $event_params * @access public */ public function runBuildEvent($prefix_special, $pseudo_class, $event_params) { if ( !isset($this->buildEvents[$pseudo_class]) ) { return ; } $event = new kEvent($prefix_special . ':' . $this->buildEvents[$pseudo_class], $event_params); $this->HandleEvent($event); } /** * Check if event is called twice, that causes recursion * * @param kEvent $event * @return bool * @access protected */ protected function isRecursion($event) { $event_key = $event->getPrefixSpecial() . ':' . $event->Name; return in_array($event_key, $this->recursionStack); } /** * Adds event to recursion stack * * @param kEvent $event * @access protected */ protected function pushEvent($event) { $event_key = $event->getPrefixSpecial() . ':' . $event->Name; array_push($this->recursionStack, $event_key); } /** * Removes event from recursion stack * * @access protected */ protected function popEvent() { array_pop($this->recursionStack); } /** * Allows to process any type of event * * @param kEvent $event * @return void * @access public */ public function HandleEvent($event) { if ( $this->isRecursion($event) || !$this->verifyEventPrefix($event) ) { return; } $this->pushEvent($event); if ( !$event->SkipBeforeHooks ) { $this->Hooks->runHooks($event, hBEFORE); if ( $event->status == kEvent::erFATAL ) { return; } } /** @var kEventHandler $event_handler */ $event_handler = $this->Application->recallObject($event->Prefix . '_EventHandler'); $event_handler->processEvent($event); if ( $event->status == kEvent::erFATAL ) { return; } if ( !$event->SkipAfterHooks ) { $this->Hooks->runHooks($event, hAFTER); } $this->popEvent(); } /** * Notifies event subscribers, that event has occured * * @param kEvent $event * @return void */ public function notifySubscribers(kEvent $event) { if ( $event->status != kEvent::erSUCCESS ) { return; } $cache_key = 'email_to_event_mapping[%EmailTemplateSerial%]'; $event_mapping = $this->Application->getCache($cache_key); if ( $event_mapping === false ) { $this->Conn->nextQueryCachable = true; $sql = 'SELECT TemplateId, TemplateName, Type, BindToSystemEvent FROM ' . $this->Application->getUnitOption('email-template', 'TableName') . ' WHERE BindToSystemEvent <> ""'; $event_mapping = $this->Conn->Query($sql, 'BindToSystemEvent'); $this->Application->setCache($cache_key, $event_mapping); } $email_template = Array (); if ( isset($event_mapping[(string)$event]) ) { $email_template = $event_mapping[(string)$event]; } elseif ( isset($event_mapping[$event->Prefix . '.*:' . $event->Name]) ) { $email_template = $event_mapping[$event->Prefix . '.*:' . $event->Name]; } if ( !$email_template ) { return; } $where_clause = Array (); $where_clause['EmailTemplateId'] = 'EmailTemplateId = ' . $email_template['TemplateId']; try { $category_ids = Array (); /** @var kDBItem $category */ $category = $this->Application->recallObject('c'); if ( $category->isLoaded() ) { $category_ids = explode('|', substr($category->GetDBField('ParentPath'), 1, -1)); } } catch (Exception $e) { } $where_clause['CategoryId'] = $this->_getSubscriberFilter('CategoryId', $category_ids, true); try { $item_id = $parent_item_id = false; /** @var kDBItem $object */ $object = $event->getObject(); if ( $object->isLoaded() ) { $item_id = $object->GetID(); $parent_prefix = $this->Application->getUnitOption($event->Prefix, 'ParentPrefix'); if ( $parent_prefix ) { $parent_item_id = $object->getParentId($parent_prefix); } } } catch (Exception $e) { } $where_clause['ItemId'] = $this->_getSubscriberFilter('ItemId', $item_id); $where_clause['ParentItemId'] = $this->_getSubscriberFilter('ParentItemId', $parent_item_id); $event_params = Array ( 'EmailTemplateId' => $email_template['TemplateId'], 'CategoryIds' => $category_ids, 'ItemId' => $item_id, 'ParentId' => $parent_item_id, 'where_clause' => $where_clause, ); $sql_event = new kEvent($event->getPrefixSpecial() . ':OnGetEventSubscribersQuery', $event_params); $sql_event->MasterEvent = $event; $this->HandleEvent($sql_event); $subscribers = $this->Conn->GetIterator($sql_event->getEventParam('sql')); if ( !count($subscribers) ) { // mapping exists, but nobody has subscribed return; } $send_params = Array ( 'Prefix' => $event->Prefix, 'Special' => $event->Special, 'PrefixSpecial' => $event->getPrefixSpecial(), ); $send_method = $email_template['Type'] == EmailTemplate::TEMPLATE_TYPE_FRONTEND ? 'emailUser' : 'emailAdmin'; foreach ($subscribers as $subscriber_info) { $send_params['to_name'] = $subscriber_info['SubscriberEmail']; $send_params['to_email'] = $subscriber_info['SubscriberEmail']; $this->Application->$send_method($email_template['TemplateName'], $subscriber_info['UserId'], $send_params); } } /** * Returns filter for searching event subscribers * * @param string $field * @param mixed $value * @param bool $is_category * @return string * @access protected */ protected function _getSubscriberFilter($field, $value, $is_category = false) { if ( $value ) { // send to this item subscribers AND to subscribers to all items if ( $is_category ) { $clause = 'IF(IncludeSublevels = 1, ' . $field . ' IN (' . implode(',', $value) . '), ' . $field . ' = ' . end($value) . ')'; } else { $clause = $field . ' = ' . $this->Conn->qstr($value); } return $clause . ' OR ' . $field . ' IS NULL'; } // send to subscribers to all items return $field . ' IS NULL'; } /** * Checks, that given event is implemented * * @param kEvent $event * @return bool * @access public */ public function eventImplemented(kEvent $event) { if ( !$this->verifyEventPrefix($event, true) ) { return false; } /** @var kEventHandler $event_handler */ $event_handler = $this->Application->recallObject($event->Prefix . '_EventHandler'); return $event_handler->getEventMethod($event) != ''; } /** * Checks if event prefix is valid * * @param kEvent $event * @param bool $is_fatal * @return string * @access public */ public function verifyEventPrefix($event, $is_fatal = false) { if ( !$this->Application->prefixRegistred($event->Prefix) ) { // when "l-cdata" is requested, then load "l", that will clone "l-cdata" unit config $this->Application->UnitConfigReader->loadConfig($event->Prefix); if ( !$this->Application->prefixRegistred($event->Prefix) ) { $error_msg = 'Prefix "' . $event->Prefix . '" not registred (requested event "' . $event->Name . '")'; if ($is_fatal) { throw new Exception($error_msg); } else { trigger_error($error_msg, E_USER_WARNING); } return false; } } return true; } /** * Processes request * * @access public */ public function ProcessRequest() { $this->Request->process(); } /** * Allows to add new element to opener stack * * @param string $template * @param Array $params * @access public */ public function openerStackPush($template = '', $params = Array ()) { $this->Request->openerStackPush($template, $params); } /** * Set's new event for $prefix_special * passed * * @param string $prefix_special * @param string $event_name * @access public */ public function setEvent($prefix_special,$event_name) { /** @var Params $actions */ $actions = $this->Application->recallObject('kActions'); $actions->Set('events[' . $prefix_special . ']', $event_name); } /** * Allows to determine, that required event is beeing processed right now * * @param string $event_key Event name in format prefix[.special]:event_name * @return bool * @access public */ public function eventRunning($event_key) { return array_search($event_key, $this->recursionStack) !== false; } }