Page MenuHomeIn-Portal Phabricator

in-portal
No OneTemporary

File Metadata

Created
Fri, Jun 20, 10:08 PM

in-portal

Index: branches/unlabeled/unlabeled-1.65.2/kernel/units/general/cat_event_handler.php
===================================================================
--- branches/unlabeled/unlabeled-1.65.2/kernel/units/general/cat_event_handler.php (nonexistent)
+++ branches/unlabeled/unlabeled-1.65.2/kernel/units/general/cat_event_handler.php (revision 6141)
@@ -0,0 +1,1893 @@
+<?php
+
+$application =& kApplication::Instance();
+$application->Factory->includeClassFile('kDBEventHandler');
+
+class kCatDBEventHandler extends InpDBEventHandler {
+
+ /**
+ * Allows to override standart permission mapping
+ *
+ */
+ function mapPermissions()
+ {
+ parent::mapPermissions();
+ $permissions = Array(
+ 'OnExport' => Array('self' => 'view|advanced:export'),
+ 'OnExportBegin' => Array('self' => 'view|advanced:export'),
+ 'OnSaveSettings' => Array('self' => 'add|edit|advanced:import'),
+ 'OnBeforeDeleteOriginal' => Array('self' => 'edit|advanced:approve'),
+
+ 'OnCancelAction' => Array( 'self' => true),
+
+ );
+ $this->permMapping = array_merge($this->permMapping, $permissions);
+ }
+
+ /**
+ * Checks permissions of user
+ *
+ * @param kEvent $event
+ */
+ function CheckPermission(&$event)
+ {
+ if (!$this->Application->IsAdmin()) {
+ if ($event->Name == 'OnSetSortingDirect') {
+ // allow sorting on front event without view permission
+ return true;
+ }
+ }
+
+ if ($event->Name == 'OnExport') {
+ // save category_id before doing export
+ $this->Application->LinkVar('m_cat_id');
+ }
+
+ if ($event->Name == 'OnNew' && preg_match('/(.*)\/import$/', $this->Application->GetVar('t'), $rets)) {
+ // redirect to item import template, where permission (import) category will be chosen)
+ $root_category = $this->Application->findModule('Path', $rets[1].'/', 'RootCat');
+ $this->Application->StoreVar('m_cat_id', $root_category);
+ }
+
+ if ($event->Name == 'OnEdit' || $event->Name == 'OnSave') {
+ // check each id from selected individually and only if all are allowed proceed next
+ if ($event->Name == 'OnEdit') {
+ $selected_ids = implode(',', $this->StoreSelectedIDs($event));
+ }
+ else {
+ $selected_ids = $this->Application->RecallVar($event->getPrefixSpecial().'_selected_ids');
+ }
+
+ $id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
+ $table_name = $this->Application->getUnitOption($event->Prefix, 'TableName');
+ $sql = 'SELECT '.$id_field.', CreatedById, ci.CategoryId
+ FROM '.$table_name.' item_table
+ LEFT JOIN '.$this->Application->getUnitOption('ci', 'TableName').' ci ON ci.ItemResourceId = item_table.ResourceId
+ WHERE '.$id_field.' IN ('.$selected_ids.') AND (ci.PrimaryCat = 1)';
+ $items = $this->Conn->Query($sql, $id_field);
+
+ $perm_value = true;
+ $perm_helper =& $this->Application->recallObject('PermissionsHelper');
+ foreach ($items as $item_id => $item_data) {
+ if ($perm_helper->ModifyCheckPermission($item_data['CreatedById'], $item_data['CategoryId'], $event->Prefix) == 0) {
+ // one of items selected has no permission
+ $perm_value = false;
+ break;
+ }
+ }
+
+ if (!$perm_value) {
+ $event->status = erPERM_FAIL;
+ }
+
+ return $perm_value;
+ }
+
+ return parent::CheckPermission($event);
+ }
+
+ /**
+ * Add selected items to clipboard with mode = COPY (CLONE)
+ *
+ * @param kEvent $event
+ */
+ function OnCopy(&$event)
+ {
+ $this->Application->RemoveVar('clipboard');
+ $clipboard_helper =& $this->Application->recallObject('ClipboardHelper');
+ $clipboard_helper->setClipboard($event, 'copy', $this->StoreSelectedIDs($event));
+ }
+
+ /**
+ * Add selected items to clipboard with mode = CUT
+ *
+ * @param kEvent $event
+ */
+ function OnCut(&$event)
+ {
+ $this->Application->RemoveVar('clipboard');
+ $clipboard_helper =& $this->Application->recallObject('ClipboardHelper');
+ $clipboard_helper->setClipboard($event, 'cut', $this->StoreSelectedIDs($event));
+ }
+
+ /**
+ * Performs category item paste
+ *
+ * @param kEvent $event
+ */
+ function OnPaste(&$event)
+ {
+ if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
+ return;
+ }
+
+ $clipboard_data = $event->getEventParam('clipboard_data');
+
+ if (!$clipboard_data['cut'] && !$clipboard_data['copy']) {
+ return false;
+ }
+
+ if ($clipboard_data['copy']) {
+ $temp =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
+ $temp->CloneItems($event->Prefix, $event->Special, $clipboard_data['copy']);
+ }
+
+ if ($clipboard_data['cut']) {
+ $object =& $this->Application->recallObject($event->getPrefixSpecial().'.item', $event->Prefix, Array('skip_autoload' => true));
+
+ foreach ($clipboard_data['cut'] as $id) {
+ $object->Load($id);
+ $object->MoveToCat();
+ }
+ }
+ }
+
+ /**
+ * Return type clauses for list bulding on front
+ *
+ * @param kEvent $event
+ * @return Array
+ */
+ function getTypeClauses(&$event)
+ {
+ $types = $event->getEventParam('types');
+ $except_types = $event->getEventParam('except');
+ $type_clauses = Array();
+
+ $type_clauses['pick']['include'] = '%1$s.EditorsPick = 1 AND '.TABLE_PREFIX.'CategoryItems.PrimaryCat = 1';
+ $type_clauses['pick']['except'] = '%1$s.EditorsPick! = 1 AND '.TABLE_PREFIX.'CategoryItems.PrimaryCat = 1';
+ $type_clauses['pick']['having_filter'] = false;
+
+ $type_clauses['hot']['include'] = '`IsHot` = 1 AND PrimaryCat = 1';
+ $type_clauses['hot']['except'] = '`IsHot`! = 1 AND PrimaryCat = 1';
+ $type_clauses['hot']['having_filter'] = true;
+
+ $type_clauses['pop']['include'] = '`IsPop` = 1 AND PrimaryCat = 1';
+ $type_clauses['pop']['except'] = '`IsPop`! = 1 AND PrimaryCat = 1';
+ $type_clauses['pop']['having_filter'] = true;
+
+ $type_clauses['new']['include'] = '`IsNew` = 1 AND PrimaryCat = 1';
+ $type_clauses['new']['except'] = '`IsNew`! = 1 AND PrimaryCat = 1';
+ $type_clauses['new']['having_filter'] = true;
+
+ $type_clauses['displayed']['include'] = '';
+ $displayed = $this->Application->GetVar($event->Prefix.'_displayed_ids');
+ if ($displayed) {
+ $id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
+ $type_clauses['displayed']['except'] = '%1$s.'.$id_field.' NOT IN ('.$displayed.')';
+ }
+ else {
+ $type_clauses['displayed']['except'] = '';
+ }
+ $type_clauses['displayed']['having_filter'] = false;
+
+ if (strpos($types, 'search') !== false || strpos($except_types, 'search') !== false) {
+ $event_mapping = Array(
+ 'simple' => 'OnSimpleSearch',
+ 'subsearch' => 'OnSubSearch',
+ 'advanced' => 'OnAdvancedSearch');
+ if($this->Application->GetVar('INPORTAL_ON') && $this->Application->GetVar('Action') == 'm_simple_subsearch')
+ {
+ $type = 'subsearch';
+ }
+ else
+ {
+ $type = $this->Application->GetVar('search_type') ? $this->Application->GetVar('search_type') : 'simple';
+ }
+
+ if($keywords = $event->getEventParam('keyword_string')) // processing keyword_string param of ListProducts tag
+ {
+ $this->Application->SetVar('keywords', $keywords);
+ $type = 'simple';
+ }
+ $search_event = $event_mapping[$type];
+ $this->$search_event($event);
+ $search_table = TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_'.TABLE_PREFIX.'Search';
+ $sql = 'SHOW TABLES LIKE "'.$search_table.'"';
+ if ( $this->Conn->Query($sql) ) {
+ $search_res_ids = $this->Conn->GetCol('SELECT ResourceId FROM '.$search_table);
+ }
+
+ if ($search_res_ids) {
+ $type_clauses['search']['include'] = '%1$s.ResourceId IN ('.implode(',', $search_res_ids).') AND PrimaryCat = 1';
+ $type_clauses['search']['except'] = '%1$s.ResourceId NOT IN ('.implode(',', $search_res_ids).') AND PrimaryCat = 1';
+ }
+ else {
+ $type_clauses['search']['include'] = '0';
+ $type_clauses['search']['except'] = '1';
+ }
+ $type_clauses['search']['having_filter'] = false;
+ }
+
+ if (strpos($types, 'related') !== false || strpos($except_types, 'related') !== false) {
+
+ $related_to = $event->getEventParam('related_to');
+ if (!$related_to) {
+ $related_prefix = $event->Prefix;
+ }
+ else {
+ $sql = 'SELECT Prefix
+ FROM '.TABLE_PREFIX.'ItemTypes
+ WHERE ItemName = '.$this->Conn->qstr($related_to);
+ $related_prefix = $this->Conn->GetOne($sql);
+ }
+
+ $rel_table = $this->Application->getUnitOption('rel', 'TableName');
+ $item_type = $this->Application->getUnitOption($event->Prefix, 'ItemType');
+
+ $p_item =& $this->Application->recallObject($related_prefix.'.current', null, Array('skip_autoload' => true));
+ $p_item->Load( $this->Application->GetVar($related_prefix.'_id') );
+
+ $p_resource_id = $p_item->GetDBField('ResourceId');
+
+ $sql = 'SELECT SourceId, TargetId FROM '.$rel_table.'
+ WHERE
+ (Enabled = 1)
+ AND (
+ (Type = 0 AND SourceId = '.$p_resource_id.' AND TargetType = '.$item_type.')
+ OR
+ (Type = 1
+ AND (
+ (SourceId = '.$p_resource_id.' AND TargetType = '.$item_type.')
+ OR
+ (TargetId = '.$p_resource_id.' AND SourceType = '.$item_type.')
+ )
+ )
+ )';
+
+ $related_ids_array = $this->Conn->Query($sql);
+ $related_ids = Array();
+
+ foreach ($related_ids_array as $key => $record) {
+ $related_ids[] = $record[ $record['SourceId'] == $p_resource_id ? 'TargetId' : 'SourceId' ];
+ }
+
+ if (count($related_ids) > 0) {
+ $type_clauses['related']['include'] = '%1$s.ResourceId IN ('.implode(',', $related_ids).') AND PrimaryCat = 1';
+ $type_clauses['related']['except'] = '%1$s.ResourceId NOT IN ('.implode(',', $related_ids).') AND PrimaryCat = 1';
+ }
+ else {
+ $type_clauses['related']['include'] = '0';
+ $type_clauses['related']['except'] = '1';
+ }
+ $type_clauses['related']['having_filter'] = false;
+ }
+
+ return $type_clauses;
+ }
+
+ /**
+ * Apply filters to list
+ *
+ * @param kEvent $event
+ */
+ function SetCustomQuery(&$event)
+ {
+ parent::SetCustomQuery($event);
+
+ $object =& $event->getObject();
+
+ // add category filter if needed
+ if ($event->Special != 'showall') {
+ if ( $event->getEventParam('parent_cat_id') ) {
+ $parent_cat_id = $event->getEventParam('parent_cat_id');
+ }
+ else {
+ $parent_cat_id = $this->Application->GetVar('c_id');
+ if (!$parent_cat_id) {
+ $parent_cat_id = $this->Application->GetVar('m_cat_id');
+ }
+ if (!$parent_cat_id) {
+ $parent_cat_id = 0;
+ }
+ }
+
+ if ((string) $parent_cat_id != 'any') {
+ if ($event->getEventParam('recursive')) {
+ $current_path = $this->Conn->GetOne('SELECT ParentPath FROM '.TABLE_PREFIX.'Category WHERE CategoryId='.$parent_cat_id);
+ $subcats = $this->Conn->GetCol('SELECT CategoryId FROM '.TABLE_PREFIX.'Category WHERE ParentPath LIKE "'.$current_path.'%" ');
+ $object->addFilter('category_filter', TABLE_PREFIX.'CategoryItems.CategoryId IN ('.implode(', ', $subcats).')');
+ }
+ else {
+ $object->addFilter('category_filter', TABLE_PREFIX.'CategoryItems.CategoryId = '.$parent_cat_id );
+ }
+ }
+ }
+ else {
+ $object->addFilter('primary_filter', 'PrimaryCat = 1');
+ }
+
+ // add permission filter
+ if ($this->Application->GetVar('u_id') == -1) {
+ // for "root" CATEGORY.VIEW permission is checked for items lists too
+ $view_perm = 1;
+ }
+ else {
+ // for any real user itemlist view permission is checked instead of CATEGORY.VIEW
+ $sql = 'SELECT PermissionConfigId
+ FROM '.TABLE_PREFIX.'PermissionConfig
+ WHERE PermissionName = "'.$this->Application->getUnitOption($event->Prefix, 'PermItemPrefix').'.VIEW"';
+ $view_perm = $this->Conn->GetOne($sql);
+
+ $groups = explode( ',', $this->Application->RecallVar('UserGroups') );
+ foreach($groups as $group)
+ {
+ $view_filters[] = 'FIND_IN_SET('.$group.', perm.acl)';
+ }
+ $view_filter = implode(' OR ', $view_filters);
+ $object->addFilter('perm_filter2', $view_filter);
+ }
+
+ $object->addFilter('perm_filter', 'perm.PermId = '.$view_perm);
+
+ if ( !$this->Application->IsAdmin() )
+ {
+ $object->addFilter('status_filter', $object->TableName.'.Status = 1');
+ if ($this->Application->getUnitOption($event->Prefix, 'UsePendingEditing')) {
+ // if category item uses pending editing abilities, then in no cases show pending copies on front
+ $object->addFilter('original_filter', '%1$s.OrgId = 0 OR %1$s.OrgId IS NULL');
+ }
+ }
+ else {
+ if ($this->Application->getUnitOption($event->Prefix, 'UsePendingEditing')) {
+ $pending_ids = $this->Conn->GetCol(
+ 'SELECT OrgId FROM '.$object->TableName.'
+ WHERE Status = -2 AND OrgId IS NOT NULL');
+ if ($pending_ids) {
+ $object->addFilter('no_original_filter', '%1$s.'.$object->IDField.' NOT IN ('.implode(',', $pending_ids).')');
+ }
+ }
+ }
+
+ $types = $event->getEventParam('types');
+ $except_types = $event->getEventParam('except');
+ $type_clauses = $this->getTypeClauses($event);
+
+ // convert prepared type clauses into list filters
+ $includes_or_filter =& $this->Application->makeClass('kMultipleFilter');
+ $includes_or_filter->setType(FLT_TYPE_OR);
+
+ $excepts_and_filter =& $this->Application->makeClass('kMultipleFilter');
+ $excepts_and_filter->setType(FLT_TYPE_AND);
+
+ $includes_or_filter_h =& $this->Application->makeClass('kMultipleFilter');
+ $includes_or_filter_h->setType(FLT_TYPE_OR);
+
+ $excepts_and_filter_h =& $this->Application->makeClass('kMultipleFilter');
+ $excepts_and_filter_h->setType(FLT_TYPE_AND);
+
+ $except_types_array = explode(',', $types);
+
+ if ($types) {
+ $types_array = explode(',', $types);
+ for ($i = 0; $i < sizeof($types_array); $i++) {
+ $type = trim($types_array[$i]);
+ if (isset($type_clauses[$type])) {
+ if ($type_clauses[$type]['having_filter']) {
+ $includes_or_filter_h->removeFilter('filter_'.$type);
+ $includes_or_filter_h->addFilter('filter_'.$type, $type_clauses[$type]['include']);
+ }else {
+ $includes_or_filter->removeFilter('filter_'.$type);
+ $includes_or_filter->addFilter('filter_'.$type, $type_clauses[$type]['include']);
+ }
+ }
+ }
+ }
+
+ if ($except_types) {
+ $except_types_array = explode(',', $except_types);
+ for ($i = 0; $i < sizeof($except_types_array); $i++) {
+ $type = trim($except_types_array[$i]);
+ if (isset($type_clauses[$type])) {
+ if ($type_clauses[$type]['having_filter']) {
+ $excepts_and_filter_h->removeFilter('filter_'.$type);
+ $excepts_and_filter_h->addFilter('filter_'.$type, $type_clauses[$type]['except']);
+ }else {
+ $excepts_and_filter->removeFilter('filter_'.$type);
+ $excepts_and_filter->addFilter('filter_'.$type, $type_clauses[$type]['except']);
+ }
+ }
+ }
+ }
+
+ /*if ( !$this->Application->IsAdmin() ) {
+ $object->addFilter('expire_filter', '%1$s.Expire IS NULL OR %1$s.Expire > UNIX_TIMESTAMP()');
+ }*/
+
+ /*$list_type = $event->getEventParam('ListType');
+ switch($list_type)
+ {
+ case 'favorites':
+ $fav_table = $this->Application->getUnitOption('fav','TableName');
+ $user_id =& $this->Application->GetVar('u_id');
+
+ $sql = 'SELECT DISTINCT f.ResourceId
+ FROM '.$fav_table.' f
+ LEFT JOIN '.$object->TableName.' p ON p.ResourceId = f.ResourceId
+ WHERE f.PortalUserId = '.$user_id;
+ $ids = $this->Conn->GetCol($sql);
+ if(!$ids) $ids = Array(-1);
+ $object->addFilter('category_filter', TABLE_PREFIX.'CategoryItems.PrimaryCat = 1');
+ $object->addFilter('favorites_filter', '%1$s.`ResourceId` IN ('.implode(',',$ids).')');
+ break;
+ case 'search':
+ $search_results_table = TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_'.TABLE_PREFIX.'Search';
+ $sql = ' SELECT DISTINCT ResourceId
+ FROM '.$search_results_table.'
+ WHERE ItemType=11';
+ $ids = $this->Conn->GetCol($sql);
+ if(!$ids) $ids = Array(-1);
+ $object->addFilter('search_filter', '%1$s.`ResourceId` IN ('.implode(',',$ids).')');
+ break;
+ } */
+
+ $object->addFilter('includes_filter', $includes_or_filter);
+ $object->addFilter('excepts_filter', $excepts_and_filter);
+
+ $object->addFilter('includes_filter_h', $includes_or_filter_h, HAVING_FILTER);
+ $object->addFilter('excepts_filter_h', $excepts_and_filter_h, HAVING_FILTER);
+ }
+
+ /**
+ * Adds calculates fields for item statuses
+ *
+ * @param kCatDBItem $object
+ * @param kEvent $event
+ */
+ function prepareObject(&$object, &$event)
+ {
+ $this->prepareItemStatuses($event);
+
+ $object->addCalculatedField('CachedNavbar', 'l'.$this->Application->GetVar('m_lang').'_CachedNavbar');
+
+ if ($event->Special == 'export' || $event->Special == 'import')
+ {
+ $this->prepareExportColumns($event);
+ }
+ }
+
+ /**
+ * Creates calculated fields for all item statuses based on config settings
+ *
+ * @param kEvent $event
+ */
+ function prepareItemStatuses(&$event)
+ {
+ $object =& $event->getObject( Array('skip_autoload' => true) );
+
+ $property_map = $this->Application->getUnitOption($event->Prefix, 'ItemPropertyMappings');
+ if (!$property_map) {
+ return ;
+ }
+
+ // new items
+ $object->addCalculatedField('IsNew', ' IF(%1$s.NewItem = 2,
+ IF(%1$s.CreatedOn >= (UNIX_TIMESTAMP() - '.
+ $this->Application->ConfigValue($property_map['NewDays']).
+ '*3600*24), 1, 0),
+ %1$s.NewItem
+ )');
+
+ // hot items (cache updated every hour)
+ $sql = 'SELECT Data
+ FROM '.TABLE_PREFIX.'Cache
+ WHERE (VarName = "'.$property_map['HotLimit'].'") AND (Cached >'.(adodb_mktime() - 3600).')';
+ $hot_limit = $this->Conn->GetOne($sql);
+ if ($hot_limit === false) {
+ $hot_limit = $this->CalculateHotLimit($event);
+ }
+ $object->addCalculatedField('IsHot', ' IF(%1$s.HotItem = 2,
+ IF(%1$s.'.$property_map['ClickField'].' >= '.$hot_limit.', 1, 0),
+ %1$s.HotItem
+ )');
+
+ // popular items
+ $object->addCalculatedField('IsPop', ' IF(%1$s.PopItem = 2,
+ IF(%1$s.CachedVotesQty >= '.
+ $this->Application->ConfigValue($property_map['MinPopVotes']).
+ ' AND %1$s.CachedRating >= '.
+ $this->Application->ConfigValue($property_map['MinPopRating']).
+ ', 1, 0),
+ %1$s.PopItem)');
+
+ }
+
+ function CalculateHotLimit(&$event)
+ {
+ $property_map = $this->Application->getUnitOption($event->Prefix, 'ItemPropertyMappings');
+ if (!$property_map) {
+ return;
+ }
+ $click_field = $property_map['ClickField'];
+
+ $last_hot = $this->Application->ConfigValue($property_map['MaxHotNumber']) - 1;
+ $sql = 'SELECT '.$click_field.' FROM '.$this->Application->getUnitOption($event->Prefix, 'TableName').'
+ ORDER BY '.$click_field.' DESC
+ LIMIT '.$last_hot.', 1';
+ $res = $this->Conn->GetCol($sql);
+ $hot_limit = (double)array_shift($res);
+ $this->Conn->Query('REPLACE INTO '.TABLE_PREFIX.'Cache (VarName, Data, Cached) VALUES ("'.$property_map['HotLimit'].'", "'.$hot_limit.'", '.adodb_mktime().')');
+ return $hot_limit;
+
+ return 0;
+ }
+
+ /**
+ * Enter description here...
+ *
+ * @param kEvent $event
+ */
+ function OnBeforeItemUpdate(&$event)
+ {
+ $property_map = $this->Application->getUnitOption($event->Prefix, 'ItemPropertyMappings');
+ if (!$property_map) {
+ return;
+ }
+ $click_field = $property_map['ClickField'];
+
+ $object =& $event->getObject();
+ if( $this->Application->IsAdmin() && ($this->Application->GetVar($click_field.'_original') !== false) &&
+ floor($this->Application->GetVar($click_field.'_original')) != $object->GetDBField($click_field) )
+ {
+ $sql = 'SELECT MAX('.$click_field.') FROM '.$this->Application->getUnitOption($event->Prefix, 'TableName').'
+ WHERE FLOOR('.$click_field.') = '.$object->GetDBField($click_field);
+ $hits = ( $res = $this->Conn->GetOne($sql) ) ? $res + 0.000001 : $object->GetDBField($click_field);
+ $object->SetDBField($click_field, $hits);
+ }
+ }
+
+ /**
+ * Load price from temp table if product mode is temp table
+ *
+ * @param kEvent $event
+ */
+ function OnAfterItemLoad(&$event)
+ {
+ $special = substr($event->Special, -6);
+ $object =& $event->getObject();
+ if ($special == 'import' || $special == 'export') {
+ $image_data = $object->getPrimaryImageData();
+
+ if ($image_data) {
+ $thumbnail_image = $image_data[$image_data['LocalThumb'] ? 'ThumbPath' : 'ThumbUrl'];
+ if ($image_data['SameImages']) {
+ $full_image = '';
+ }
+ else {
+ $full_image = $image_data[$image_data['LocalImage'] ? 'LocalPath' : 'Url'];
+ }
+ $object->SetDBField('ThumbnailImage', $thumbnail_image);
+ $object->SetDBField('FullImage', $full_image);
+ $object->SetDBField('ImageAlt', $image_data['AltName']);
+ }
+ }
+
+ //substituiting pending status value for pending editing
+ if ($object->HasField('OrgId') && $object->GetDBField('OrgId') > 0 && $object->GetDBField('Status') == -2) {
+ $options = $object->Fields['Status']['options'];
+ foreach ($options as $key => $val) {
+ if ($key == 2) $key = -2;
+ $new_options[$key] = $val;
+ }
+ $object->Fields['Status']['options'] = $new_options;
+ }
+
+ }
+
+ function OnAfterItemUpdate(&$event)
+ {
+ $this->CalculateHotLimit($event);
+
+ if ( substr($event->Special, -6) == 'import') {
+ $this->setCustomExportColumns($event);
+ }
+ }
+
+ /**
+ * sets values for import process
+ *
+ * @param kEvent $event
+ */
+ function OnAfterItemCreate(&$event)
+ {
+ if ( substr($event->Special, -6) == 'import') {
+ $this->setCustomExportColumns($event);
+ }
+ }
+
+ /**
+ * Make record to search log
+ *
+ * @param string $keywords
+ * @param int $search_type 0 - simple search, 1 - advanced search
+ */
+ function saveToSearchLog($keywords, $search_type = 0)
+ {
+ $sql = 'UPDATE '.TABLE_PREFIX.'SearchLog
+ SET Indices = Indices + 1
+ WHERE Keyword = '.$this->Conn->qstr($keywords).' AND SearchType = '.$search_type; // 0 - simple search, 1 - advanced search
+ $this->Conn->Query($sql);
+ if ($this->Conn->getAffectedRows() == 0) {
+ $fields_hash = Array('Keyword' => $keywords, 'Indices' => 1, 'SearchType' => $search_type);
+ $this->Conn->doInsert($fields_hash, TABLE_PREFIX.'SearchLog');
+ }
+ }
+
+ /**
+ * Makes simple search for products
+ * based on keywords string
+ *
+ * @param kEvent $event
+ * @todo Change all hardcoded Products table & In-Commerce module usage to dynamic usage from item config !!!
+ */
+ function OnSimpleSearch(&$event)
+ {
+ if($this->Application->GetVar('INPORTAL_ON') && !($this->Application->GetVar('Action') == 'm_simple_search'))
+ {
+ return;
+ }
+
+ $event->redirect = false;
+ $search_table = TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_'.TABLE_PREFIX.'Search';
+
+ $keywords = unhtmlentities( trim($this->Application->GetVar('keywords')) );
+
+ $query_object =& $this->Application->recallObject('HTTPQuery');
+ $sql = 'SHOW TABLES LIKE "'.$search_table.'"';
+
+ if(!isset($query_object->Get['keywords']) &&
+ !isset($query_object->Post['keywords']) &&
+ $this->Conn->Query($sql))
+ {
+ return; // used when navigating by pages or changing sorting in search results
+ }
+ if(!$keywords || strlen($keywords) < $this->Application->ConfigValue('Search_MinKeyword_Length'))
+ {
+ $this->Conn->Query('DROP TABLE IF EXISTS '.$search_table);
+ $this->Application->SetVar('keywords_too_short', 1);
+ return; // if no or too short keyword entered, doing nothing
+ }
+
+ $this->Application->StoreVar('keywords', $keywords);
+ if (!$this->Application->GetVar('INPORTAL_ON')) {
+ // don't save search log, because in-portal already saved it
+ $this->saveToSearchLog($keywords, 0); // 0 - simple search, 1 - advanced search
+ }
+
+
+ $keywords = strtr($keywords, Array('%' => '\\%', '_' => '\\_'));
+
+ $event->setPseudoClass('_List');
+ $object =& $event->getObject();
+ $this->Application->SetVar($event->getPrefixSpecial().'_Page', 1);
+ $lang = $this->Application->GetVar('m_lang');
+ $product_table = $this->Application->getUnitOption('p', 'TableName');
+
+ $sql = ' SELECT * FROM '.$this->Application->getUnitOption('confs', 'TableName').'
+ WHERE ModuleName="In-Commerce"
+ AND SimpleSearch=1';
+ $search_config = $this->Conn->Query($sql, 'FieldName');
+ $field_list = array_keys($search_config);
+
+ $join_clauses = Array();
+
+ // field processing
+ $weight_sum = 0;
+
+ $alias_counter = 0;
+
+ $custom_fields = $this->Application->getUnitOption($event->Prefix, 'CustomFields');
+ if ($custom_fields) {
+ $custom_table = $this->Application->getUnitOption($event->Prefix.'-cdata', 'TableName');
+ $join_clauses[] = ' LEFT JOIN '.$custom_table.' custom_data ON '.$product_table.'.ResourceId = custom_data.ResourceId';
+ }
+
+ // what field in search config becomes what field in sql (key - new field, value - old field (from searchconfig table))
+ $search_config_map = Array();
+
+ foreach ($field_list as $key => $field) {
+ $options = $object->getFieldOptions($field);
+ $local_table = TABLE_PREFIX.$search_config[$field]['TableName'];
+ $weight_sum += $search_config[$field]['Priority']; // counting weight sum; used when making relevance clause
+
+ // processing multilingual fields
+ if (getArrayValue($options, 'formatter') == 'kMultiLanguage') {
+ $field_list[$key.'_primary'] = 'l'.$this->Application->GetDefaultLanguageId().'_'.$field;
+ $field_list[$key] = 'l'.$lang.'_'.$field;
+
+ if(!isset($search_config[$field]['ForeignField']))
+ {
+ $field_list[$key.'_primary'] = $local_table.'.'.$field_list[$key.'_primary'];
+ $search_config_map[ $field_list[$key.'_primary'] ] = $field;
+ }
+ }
+
+ // processing fields from other tables
+ if($foreign_field = $search_config[$field]['ForeignField'])
+ {
+ $exploded = explode(':', $foreign_field, 2);
+ if($exploded[0] == 'CALC')
+ {
+ unset($field_list[$key]);
+ continue; // ignoring having type clauses in simple search
+ /*$user_object =& $this->Application->recallObject('u');
+ $user_groups = $this->Application->RecallVar('UserGroups');
+ $having_list[$key] = str_replace('{PREFIX}', TABLE_PREFIX, $exploded[1]);
+ $join_clause = str_replace('{PREFIX}', TABLE_PREFIX, $search_config[$field]['JoinClause']);
+ $join_clause = str_replace('{USER_GROUPS}', $user_groups, $join_clause);
+ $join_clause = ' LEFT JOIN '.$join_clause;
+ $join_clauses[] = $join_clause;*/
+ }
+ else
+ {
+ $exploded = explode('.', $foreign_field); // format: table.field_name
+ $foreign_table = TABLE_PREFIX.$exploded[0];
+
+ $alias_counter++;
+ $alias = 't'.$alias_counter;
+
+ $field_list[$key] = $alias.'.'.$exploded[1];
+ $search_config_map[ $field_list[$key] ] = $field;
+
+ $join_clause = str_replace('{ForeignTable}', $alias, $search_config[$field]['JoinClause']);
+ $join_clause = str_replace('{LocalTable}', $product_table, $join_clause);
+
+ $join_clauses[] = ' LEFT JOIN '.$foreign_table.' '.$alias.'
+ ON '.$join_clause;
+ }
+ }
+ else {
+ // processing fields from local table
+ if ($search_config[$field]['CustomFieldId']) {
+ $local_table = 'custom_data';
+ $field_list[$key] = 'l'.$lang.'_cust_'.array_search($field_list[$key], $custom_fields);
+ }
+ $field_list[$key] = $local_table.'.'.$field_list[$key];
+ $search_config_map[ $field_list[$key] ] = $field;
+ }
+ }
+
+ // keyword string processing
+ $search_helper =& $this->Application->recallObject('SearchHelper');
+ $where_clause = $search_helper->buildWhereClause($keywords, $field_list);
+
+ $where_clause = $where_clause.' AND '.$product_table.'.Status=1';
+
+ if($this->Application->GetVar('Action') == 'm_simple_subsearch') // subsearch, In-portal
+ {
+ if( $event->getEventParam('ResultIds') )
+ {
+ $where_clause .= ' AND '.$product_table.'.ResourceId IN ('.implode(',', $event->specificParams['ResultIds']).')';
+ }
+ }
+ if( $event->MasterEvent && $event->MasterEvent->Name == 'OnListBuild' ) // subsearch, k4
+ {
+ if( $event->MasterEvent->getEventParam('ResultIds') )
+ {
+ $where_clause .= ' AND '.$product_table.'.ResourceId IN ('.implode(',', $event->MasterEvent->getEventParam('ResultIds')).')';
+ }
+ }
+
+ // making relevance clause
+ $positive_words = $search_helper->getPositiveKeywords($keywords);
+ $this->Application->StoreVar('highlight_keywords', serialize($positive_words));
+ $revelance_parts = Array();
+ reset($search_config);
+ foreach ($field_list as $field) {
+ $config_elem = $search_config[ $search_config_map[$field] ];
+ $weight = $config_elem['Priority'];
+ $revelance_parts[] = 'IF('.$field.' LIKE "%'.implode(' ', $positive_words).'%", '.$weight_sum.', 0)';
+ foreach ($positive_words as $keyword) {
+ $revelance_parts[] = 'IF('.$field.' LIKE "%'.$keyword.'%", '.$weight.', 0)';
+ }
+ }
+ $rel_keywords = $this->Application->ConfigValue('SearchRel_Keyword_products') / 100;
+ $rel_pop = $this->Application->ConfigValue('SearchRel_Pop_products') / 100;
+ $rel_rating = $this->Application->ConfigValue('SearchRel_Rating_products') / 100;
+ $relevance_clause = '('.implode(' + ', $revelance_parts).') / '.$weight_sum.' * '.$rel_keywords;
+ $relevance_clause .= ' + (Hits + 1) / (MAX(Hits) + 1) * '.$rel_pop;
+ $relevance_clause .= ' + (CachedRating + 1) / (MAX(CachedRating) + 1) * '.$rel_rating;
+
+ // building final search query
+ if (!$this->Application->GetVar('INPORTAL_ON')) {
+ $this->Conn->Query('DROP TABLE IF EXISTS '.$search_table); // erase old search table if clean k4 event
+ }
+
+ if ($this->Conn->Query('SHOW TABLES LIKE "'.$search_table.'"')) {
+ $select_intro = 'INSERT INTO '.$search_table.' (Relevance, ItemId, ResourceId, ItemType, EdPick) ';
+ }
+ else {
+ $select_intro = 'CREATE TABLE '.$search_table.' AS ';
+ }
+
+ $sql = $select_intro.' SELECT '.$relevance_clause.' AS Relevance,
+ '.$product_table.'.ProductId AS ItemId,
+ '.$product_table.'.ResourceId,
+ 11 AS ItemType,
+ '.$product_table.'.EditorsPick AS EdPick
+ FROM '.$object->TableName.'
+ '.implode(' ', $join_clauses).'
+ WHERE '.$where_clause.'
+ GROUP BY '.$product_table.'.ProductId';
+
+ $res = $this->Conn->Query($sql);
+ }
+
+ /**
+ * Enter description here...
+ *
+ * @param kEvent $event
+ */
+ function OnSubSearch(&$event)
+ {
+ $search_table = TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_'.TABLE_PREFIX.'Search';
+ $sql = 'SHOW TABLES LIKE "'.$search_table.'"';
+ if($this->Conn->Query($sql))
+ {
+ $sql = 'SELECT DISTINCT ResourceId FROM '.$search_table;
+ $ids = $this->Conn->GetCol($sql);
+ }
+ $event->setEventParam('ResultIds', $ids);
+ $event->CallSubEvent('OnSimpleSearch');
+ }
+
+ /**
+ * Enter description here...
+ *
+ * @param kEvent $event
+ * @todo Change all hardcoded Products table & In-Commerce module usage to dynamic usage from item config !!!
+ */
+ function OnAdvancedSearch(&$event)
+ {
+ $query_object =& $this->Application->recallObject('HTTPQuery');
+ if(!isset($query_object->Post['andor']))
+ {
+ return; // used when navigating by pages or changing sorting in search results
+ }
+
+ $this->Application->RemoveVar('keywords');
+ $this->Application->RemoveVar('Search_Keywords');
+
+ $sql = ' SELECT * FROM '.$this->Application->getUnitOption('confs', 'TableName').'
+ WHERE ModuleName="In-Commerce"
+ AND AdvancedSearch=1';
+ $search_config = $this->Conn->Query($sql);
+ $lang = $this->Application->GetVar('m_lang');
+ $object =& $event->getObject();
+ $object->SetPage(1);
+ $user_object =& $this->Application->recallObject('u');
+ $product_table = $this->Application->getUnitOption('p', 'TableName');
+
+ $search_keywords = $this->Application->GetVar('value'); // will not be changed
+
+ $keywords = $this->Application->GetVar('value'); // will be changed down there
+ $verbs = $this->Application->GetVar('verb');
+ $glues = $this->Application->GetVar('andor');
+
+ $and_conditions = Array();
+ $or_conditions = Array();
+ $and_having_conditions = Array();
+ $or_having_conditions = Array();
+ $join_clauses = Array();
+ $highlight_keywords = Array();
+ $relevance_parts = Array();
+
+ $condition_patterns = Array( 'any' => '%s LIKE %s',
+ 'contains' => '%s LIKE %s',
+ 'notcontains' => '(NOT (%1$s LIKE %2$s) OR %1$s IS NULL)',
+ 'is' => '%s = %s',
+ 'isnot' => '(%1$s != %2$s OR %1$s IS NULL)');
+
+ $alias_counter = 0;
+
+ $custom_fields = $this->Application->getUnitOption($event->Prefix, 'CustomFields');
+ if ($custom_fields) {
+ $custom_table = $this->Application->getUnitOption($event->Prefix.'-cdata', 'TableName');
+ $join_clauses[] = ' LEFT JOIN '.$custom_table.' custom_data ON '.$product_table.'.ResourceId = custom_data.ResourceId';
+ }
+
+ $search_log = '';
+ $weight_sum = 0;
+ // processing fields and preparing conditions
+ foreach($search_config as $record)
+ {
+ $field = $record['FieldName'];
+ $join_clause = '';
+ $condition_mode = 'WHERE';
+
+ // field processing
+
+ $options = $object->getFieldOptions($field);
+ $local_table = TABLE_PREFIX.$record['TableName'];
+ $weight_sum += $record['Priority']; // counting weight sum; used when making relevance clause
+
+ // processing multilingual fields
+ if (getArrayValue($options, 'formatter') == 'kMultiLanguage') {
+ $field_name = 'l'.$lang.'_'.$field;
+ }
+ else {
+ $field_name = $field;
+ }
+
+ // processing fields from other tables
+ if ($foreign_field = $record['ForeignField']) {
+ $exploded = explode(':', $foreign_field, 2);
+ if($exploded[0] == 'CALC')
+ {
+ $user_groups = $this->Application->RecallVar('UserGroups');
+ $field_name = str_replace('{PREFIX}', TABLE_PREFIX, $exploded[1]);
+ $join_clause = str_replace('{PREFIX}', TABLE_PREFIX, $record['JoinClause']);
+ $join_clause = str_replace('{USER_GROUPS}', $user_groups, $join_clause);
+ $join_clause = ' LEFT JOIN '.$join_clause;
+
+ $condition_mode = 'HAVING';
+ }
+ else {
+ $exploded = explode('.', $foreign_field);
+ $foreign_table = TABLE_PREFIX.$exploded[0];
+
+ if($record['CustomFieldId']) {
+ $exploded[1] = 'l'.$lang.'_'.$exploded[1];
+ }
+
+ $alias_counter++;
+ $alias = 't'.$alias_counter;
+
+ $field_name = $alias.'.'.$exploded[1];
+ $join_clause = str_replace('{ForeignTable}', $alias, $record['JoinClause']);
+ $join_clause = str_replace('{LocalTable}', $product_table, $join_clause);
+
+ if($record['CustomFieldId'])
+ {
+ $join_clause .= ' AND '.$alias.'.CustomFieldId='.$record['CustomFieldId'];
+ }
+ $join_clause = ' LEFT JOIN '.$foreign_table.' '.$alias.'
+ ON '.$join_clause;
+ }
+ }
+ else
+ {
+ // processing fields from local table
+ if ($record['CustomFieldId']) {
+ $local_table = 'custom_data';
+ $field_name = 'l'.$lang.'_cust_'.array_search($field_name, $custom_fields);
+ }
+
+ $field_name = $local_table.'.'.$field_name;
+ }
+
+ $condition = '';
+ switch($record['FieldType'])
+ {
+ case 'text':
+ $keywords[$field] = unhtmlentities( $keywords[$field] );
+
+ if(strlen($keywords[$field]) >= $this->Application->ConfigValue('Search_MinKeyword_Length'))
+ {
+ $highlight_keywords[] = $keywords[$field];
+ if( in_array($verbs[$field], Array('any', 'contains', 'notcontains')) )
+ {
+ $keywords[$field] = '%'.strtr($keywords[$field], Array('%' => '\\%', '_' => '\\_')).'%';
+ }
+ $condition = sprintf( $condition_patterns[$verbs[$field]],
+ $field_name,
+ $this->Conn->qstr( $keywords[$field] ));
+ }
+ break;
+ case 'boolean':
+ if($keywords[$field] != -1)
+ {
+ $property_mappings = $this->Application->getUnitOption($event->Prefix, 'ItemPropertyMappings');
+ switch($field)
+ {
+ case 'HotItem':
+ $hot_limit_var = getArrayValue($property_mappings, 'HotLimit');
+ if($hot_limit_var)
+ {
+ $sql = 'SELECT Data FROM '.TABLE_PREFIX.'Cache WHERE VarName="'.$hot_limit_var.'"';
+ $hot_limit = (int)$this->Conn->GetOne($sql);
+ $condition = 'IF('.$product_table.'.HotItem = 2,
+ IF('.$product_table.'.Hits >= '.
+ $hot_limit.
+ ', 1, 0), '.$product_table.'.HotItem) = '.$keywords[$field];
+ }
+ break;
+ case 'PopItem':
+ $votes2pop_var = getArrayValue($property_mappings, 'VotesToPop');
+ $rating2pop_var = getArrayValue($property_mappings, 'RatingToPop');
+ if($votes2pop_var && $rating2pop_var)
+ {
+ $condition = 'IF('.$product_table.'.PopItem = 2, IF('.$product_table.'.CachedVotesQty >= '.
+ $this->Application->ConfigValue($votes2pop_var).
+ ' AND '.$product_table.'.CachedRating >= '.
+ $this->Application->ConfigValue($rating2pop_var).
+ ', 1, 0), '.$product_table.'.PopItem) = '.$keywords[$field];
+ }
+ break;
+ case 'NewItem':
+ $new_days_var = getArrayValue($property_mappings, 'NewDays');
+ if($new_days_var)
+ {
+ $condition = 'IF('.$product_table.'.NewItem = 2,
+ IF('.$product_table.'.CreatedOn >= (UNIX_TIMESTAMP() - '.
+ $this->Application->ConfigValue($new_days_var).
+ '*3600*24), 1, 0), '.$product_table.'.NewItem) = '.$keywords[$field];
+ }
+ break;
+ case 'EditorsPick':
+ $condition = $product_table.'.EditorsPick = '.$keywords[$field];
+ break;
+ }
+ }
+ break;
+ case 'range':
+ $range_conditions = Array();
+ if($keywords[$field.'_from'] && !preg_match("/[^0-9]/i", $keywords[$field.'_from']))
+ {
+ $range_conditions[] = $field_name.' >= '.$keywords[$field.'_from'];
+ }
+ if($keywords[$field.'_to'] && !preg_match("/[^0-9]/i", $keywords[$field.'_to']))
+ {
+ $range_conditions[] = $field_name.' <= '.$keywords[$field.'_to'];
+ }
+ if($range_conditions)
+ {
+ $condition = implode(' AND ', $range_conditions);
+ }
+ break;
+ case 'date':
+ if($keywords[$field])
+ {
+ if( in_array($keywords[$field], Array('today', 'yesterday')) )
+ {
+ $current_time = getdate();
+ $day_begin = adodb_mktime(0, 0, 0, $current_time['mon'], $current_time['mday'], $current_time['year']);
+ $time_mapping = Array('today' => $day_begin, 'yesterday' => ($day_begin - 86400));
+ $min_time = $time_mapping[$keywords[$field]];
+ }
+ else
+ {
+ $time_mapping = Array( 'last_week' => 604800, 'last_month' => 2628000,
+ 'last_3_months' => 7884000, 'last_6_months' => 15768000,
+ 'last_year' => 31536000
+ );
+ $min_time = adodb_mktime() - $time_mapping[$keywords[$field]];
+ }
+ $condition = $field_name.' > '.$min_time;
+ }
+ break;
+ }
+
+ if($condition)
+ {
+ if($join_clause)
+ {
+ $join_clauses[] = $join_clause;
+ }
+ $relevance_parts[] = 'IF('.$condition.', '.$record['Priority'].', 0)';
+ if($glues[$field] == 1) // and
+ {
+ if($condition_mode == 'WHERE')
+ {
+ $and_conditions[] = $condition;
+ }
+ else
+ {
+ $and_having_conditions[] = $condition;
+ }
+ }
+ else // or
+ {
+ if($condition_mode == 'WHERE')
+ {
+ $or_conditions[] = $condition;
+ }
+ else
+ {
+ $or_having_conditions[] = $condition;
+ }
+ }
+
+ // create search log record
+ $search_log_data = Array('search_config' => $record, 'verb' => getArrayValue($verbs, $field), 'value' => ($record['FieldType'] == 'range') ? $search_keywords[$field.'_from'].'|'.$search_keywords[$field.'_to'] : $search_keywords[$field]);
+ $search_log[] = $this->Application->Phrase('la_Field').' "'.$this->getHuman('Field', $search_log_data).'" '.$this->getHuman('Verb', $search_log_data).' '.$this->Application->Phrase('la_Value').' '.$this->getHuman('Value', $search_log_data).' '.$this->Application->Phrase($glues[$field] == 1 ? 'lu_And' : 'lu_Or');
+ }
+ }
+
+ $search_log = implode('<br />', $search_log);
+ $search_log = preg_replace('/(.*) '.preg_quote($this->Application->Phrase('lu_and'), '/').'|'.preg_quote($this->Application->Phrase('lu_or'), '/').'$/is', '\\1', $search_log);
+ $this->saveToSearchLog($search_log, 1); // advanced search
+
+ $this->Application->StoreVar('highlight_keywords', serialize($highlight_keywords));
+
+ // making relevance clause
+ if($relevance_parts)
+ {
+ $rel_keywords = $this->Application->ConfigValue('SearchRel_Keyword_products') / 100;
+ $rel_pop = $this->Application->ConfigValue('SearchRel_Pop_products') / 100;
+ $rel_rating = $this->Application->ConfigValue('SearchRel_Rating_products') / 100;
+ $relevance_clause = '('.implode(' + ', $relevance_parts).') / '.$weight_sum.' * '.$rel_keywords;
+ $relevance_clause .= ' + (Hits + 1) / (MAX(Hits) + 1) * '.$rel_pop;
+ $relevance_clause .= ' + (CachedRating + 1) / (MAX(CachedRating) + 1) * '.$rel_rating;
+ }
+ else
+ {
+ $relevance_clause = '0';
+ }
+
+ // building having clause
+ if($or_having_conditions)
+ {
+ $and_having_conditions[] = '('.implode(' OR ', $or_having_conditions).')';
+ }
+ $having_clause = implode(' AND ', $and_having_conditions);
+ $having_clause = $having_clause ? ' HAVING '.$having_clause : '';
+
+ // building where clause
+ if($or_conditions)
+ {
+ $and_conditions[] = '('.implode(' OR ', $or_conditions).')';
+ }
+// $and_conditions[] = $product_table.'.Status = 1';
+ $where_clause = implode(' AND ', $and_conditions);
+ if(!$where_clause)
+ {
+ if($having_clause)
+ {
+ $where_clause = '1';
+ }
+ else
+ {
+ $where_clause = '0';
+ $this->Application->SetVar('adv_search_error', 1);
+ }
+ }
+ $where_clause .= ' AND '.$product_table.'.Status = 1';
+
+ // building final search query
+ $search_table = TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_'.TABLE_PREFIX.'Search';
+
+ $this->Conn->Query('DROP TABLE IF EXISTS '.$search_table);
+
+ $sql = ' CREATE TABLE '.$search_table.'
+ SELECT '.$relevance_clause.' AS Relevance,
+ '.$product_table.'.ProductId AS ItemId,
+ '.$product_table.'.ResourceId AS ResourceId,
+ 11 AS ItemType,
+ '.$product_table.'.EditorsPick AS EdPick
+ FROM '.$product_table.'
+ '.implode(' ', $join_clauses).'
+ WHERE '.$where_clause.'
+ GROUP BY '.$product_table.'.ProductId'.
+ $having_clause;
+
+ $res = $this->Conn->Query($sql);
+ }
+
+
+ function getHuman($type, $search_data)
+ {
+ $type = ucfirst(strtolower($type));
+ extract($search_data);
+
+ switch ($type) {
+ case 'Field':
+ return $this->Application->Phrase($search_config['DisplayName']);
+ break;
+
+ case 'Verb':
+ return $verb ? $this->Application->Phrase('lu_advsearch_'.$verb) : '';
+ break;
+
+ case 'Value':
+ switch ($search_config['FieldType']) {
+ case 'date':
+ $values = Array(0 => 'lu_comm_Any', 'today' => 'lu_comm_Today',
+ 'yesterday' => 'lu_comm_Yesterday', 'last_week' => 'lu_comm_LastWeek',
+ 'last_month' => 'lu_comm_LastMonth', 'last_3_months' => 'lu_comm_Last3Months',
+ 'last_6_months' => 'lu_comm_Last6Months', 'last_year' => 'lu_comm_LastYear');
+ $ret = $this->Application->Phrase($values[$value]);
+ break;
+
+ case 'range':
+ $value = explode('|', $value);
+ return $this->Application->Phrase('lu_comm_From').' "'.$value[0].'" '.$this->Application->Phrase('lu_comm_To').' "'.$value[1].'"';
+ break;
+
+ case 'boolean':
+ $values = Array(1 => 'lu_comm_Yes', 0 => 'lu_comm_No', -1 => 'lu_comm_Both');
+ $ret = $this->Application->Phrase($values[$value]);
+ break;
+
+ case 'text':
+ $ret = $value;
+ break;
+
+ }
+ return '"'.$ret.'"';
+ break;
+ }
+ }
+
+
+
+ /**
+ * Set's correct page for list
+ * based on data provided with event
+ *
+ * @param kEvent $event
+ * @access private
+ * @see OnListBuild
+ */
+ function SetPagination(&$event)
+ {
+ // get PerPage (forced -> session -> config -> 10)
+ $per_page = $this->getPerPage($event);
+
+
+ $object =& $event->getObject();
+ $object->SetPerPage($per_page);
+ $this->Application->StoreVarDefault($event->getPrefixSpecial().'_Page', 1);
+
+ $page = $this->Application->GetVar($event->getPrefixSpecial().'_Page');
+ if (!$page)
+ {
+ $page = $this->Application->GetVar($event->getPrefixSpecial(true).'_Page');
+ }
+
+ if (!$page)
+ {
+ if( $this->Application->RewriteURLs() )
+ {
+ $page = $this->Application->GetVar($event->Prefix.'_Page');
+ if (!$page)
+ {
+ $page = $this->Application->RecallVar($event->Prefix.'_Page');
+ }
+ if($page) $this->Application->StoreVar($event->getPrefixSpecial().'_Page', $page);
+ }
+ else
+ {
+ $page = $this->Application->RecallVar($event->getPrefixSpecial().'_Page');
+ }
+ }
+ else {
+ $this->Application->StoreVar($event->getPrefixSpecial().'_Page', $page);
+ }
+
+ if( !$event->getEventParam('skip_counting') )
+ {
+ $pages = $object->GetTotalPages();
+ if($page > $pages)
+ {
+ $this->Application->StoreVar($event->getPrefixSpecial().'_Page', 1);
+ $page = 1;
+ }
+ }
+
+ /*$cur_per_page = $per_page;
+ $per_page = $event->getEventParam('per_page');
+ if ($per_page == 'list_next') {
+
+ $cur_page = $page;
+
+ $object =& $this->Application->recallObject($event->Prefix);
+ $object->SetPerPage(1);
+ $cur_item_index = $object->CurrentIndex;
+
+ $page = ($cur_page-1) * $cur_per_page + $cur_item_index + 1;
+ $object->SetPerPage(1);
+ }*/
+
+ $object->SetPage($page);
+ }
+
+/* === RELATED TO IMPORT/EXPORT: BEGIN === */
+
+ /**
+ * Returns module folder
+ *
+ * @param kEvent $event
+ * @return string
+ */
+ function getModuleFolder(&$event)
+ {
+ return $this->Application->getUnitOption($event->Prefix, 'ModuleFolder');
+ }
+
+ /**
+ * Shows export dialog
+ *
+ * @param kEvent $event
+ */
+ function OnExport(&$event)
+ {
+ // use old fasion (in-portal) grid
+ $selector_name = $this->Application->getUnitOption($event->Prefix, 'CatalogSelectorName');
+ if ($selector_name) {
+ $selected_ids = $this->Application->GetVar($selector_name);
+ }
+ else {
+ $this->StoreSelectedIDs($event);
+ $selected_ids = $this->getSelectedIDs($event);
+
+ if (implode(',', $selected_ids) == '') {
+ // K4 fix when no ids found bad selected ids array is formed
+ $selected_ids = false;
+ }
+ }
+
+ $selected_cats_ids = $this->Application->GetVar('export_categories');
+
+ $this->Application->StoreVar($event->Prefix.'_export_ids', $selected_ids ? implode(',', $selected_ids) : '' );
+ $this->Application->StoreVar($event->Prefix.'_export_cats_ids', $selected_cats_ids);
+
+ $event->redirect = $this->getModuleFolder($event).'/export';
+
+ $redirect_params = Array( 'm_opener' => 'd',
+ $this->Prefix.'.export_event' => 'OnNew',
+ 'pass' => 'all,'.$this->Prefix.'.export');
+
+ $event->setRedirectParams($redirect_params);
+ }
+
+ /**
+ * Export form validation & processing
+ *
+ * @param kEvent $event
+ */
+ function OnExportBegin(&$event)
+ {
+ $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
+ if (!$items_info)
+ {
+ $items_info = unserialize( $this->Application->RecallVar($event->getPrefixSpecial().'_ItemsInfo') );
+ $this->Application->SetVar($event->getPrefixSpecial(true), $items_info);
+ }
+
+ list($item_id, $field_values) = each($items_info);
+
+ $object =& $event->getObject( Array('skip_autoload' => true) );
+ $object->SetFieldsFromHash($field_values);
+ $field_values['ImportFilename'] = $object->GetDBField('ImportFilename'); //if upload formatter has renamed the file during moving !!!
+
+ $object->setID($item_id);
+ $this->setRequiredFields($event);
+
+ $export_object =& $this->Application->recallObject('CatItemExportHelper');
+
+ // save export/import options
+ if ($event->Special == 'export')
+ {
+ $export_ids = $this->Application->RecallVar($event->Prefix.'_export_ids');
+ $export_cats_ids = $this->Application->RecallVar($event->Prefix.'_export_cats_ids');
+
+ // used for multistep export
+ $field_values['export_ids'] = $export_ids ? explode(',', $export_ids) : false;
+ $field_values['export_cats_ids'] = $export_cats_ids ? explode(',', $export_cats_ids) : Array( $this->Application->GetVar('m_cat_id') );
+ }
+
+ $field_values['ExportColumns'] = $field_values['ExportColumns'] ? explode('|', substr($field_values['ExportColumns'], 1, -1) ) : Array();
+ $field_values['start_from'] = 0;
+ $export_object->saveOptions($event, $field_values);
+
+ if( $export_object->verifyOptions($event) )
+ {
+ $event->redirect = $this->getModuleFolder($event).'/'.$event->Special.'_progress';
+
+ }
+ else
+ {
+ // make uploaded file local & change source selection
+ $filename = getArrayValue($field_values, 'ImportFilename');
+ if ($filename) {
+ $this->updateImportFiles($event);
+ $object->SetDBField('ImportSource', 2);
+ $field_values['ImportSource'] = 2;
+ $object->SetDBField('ImportLocalFilename', $filename);
+ $field_values['ImportLocalFilename'] = $filename;
+ $export_object->saveOptions($event, $field_values);
+ }
+
+ $event->status = erFAIL;
+ $event->redirect = false;
+ }
+ }
+
+ /**
+ * Enter description here...
+ *
+ * @param kEvent $event
+ */
+ function OnExportCancel(&$event)
+ {
+ $this->OnGoBack($event);
+ }
+
+ /**
+ * Sets correct available & export fields
+ *
+ * @param kEvent $event
+ */
+ function prepareExportColumns(&$event)
+ {
+ $object =& $event->getObject( Array('skip_autoload' => true) );
+
+ $available_columns = Array();
+
+ // category field (mixed)
+ $available_columns['__CATEGORY__CategoryPath'] = 'CategoryPath';
+
+ if ($event->Special == 'import') {
+ // category field (separated fields)
+ $max_level = $this->Application->ConfigValue('MaxImportCategoryLevels');
+ $i = 0;
+ while ($i < $max_level) {
+ $available_columns['__CATEGORY__Category'.($i + 1)] = 'Category'.($i + 1);
+ $i++;
+ }
+ }
+
+ // db fields
+ foreach ($object->Fields as $field_name => $field_options)
+ {
+ if (!$object->SkipField($field_name))
+ {
+ $available_columns[$field_name] = $field_name.(getArrayValue($field_options, 'required') ? '*' : '');
+ }
+ }
+
+ $available_columns = array_merge_recursive2($available_columns, $this->getCustomExportColumns($event));
+
+ // custom fields
+ foreach ($object->customFields as $custom_id => $custom_name)
+ {
+ $available_columns['__CUSTOM__'.$custom_name] = $custom_name;
+ }
+
+ // columns already in use
+ $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
+ if ($items_info)
+ {
+ list($item_id, $field_values) = each($items_info);
+ $export_keys = $field_values['ExportColumns'];
+ $export_keys = $export_keys ? explode('|', substr($export_keys, 1, -1) ) : Array();
+ }
+ else {
+ $export_keys = Array();
+ }
+
+ $export_columns = Array();
+ foreach ($export_keys as $field_key)
+ {
+ $field_name = $this->getExportField($field_key);
+ $export_columns[$field_key] = $field_name;
+ unset($available_columns[$field_key]);
+ }
+
+ $options = $object->GetFieldOptions('ExportColumns');
+ $options['options'] = $export_columns;
+ $object->SetFieldOptions('ExportColumns', $options);
+
+ $options = $object->GetFieldOptions('AvailableColumns');
+ $options['options'] = $available_columns;
+ $object->SetFieldOptions('AvailableColumns', $options);
+
+ $this->updateImportFiles($event);
+ }
+
+ /**
+ * Updates uploaded files list
+ *
+ * @param kEvent $event
+ */
+ function updateImportFiles(&$event)
+ {
+ if ($event->Special != 'import') {
+ return false;
+ }
+
+ $object =& $event->getObject();
+
+ $import_filenames = Array();
+
+ if ($folder_handle = opendir(EXPORT_PATH)) {
+ while (false !== ($file = readdir($folder_handle))) {
+ if (is_dir(EXPORT_PATH.'/'.$file) || substr($file, 0, 1) == '.' || strtolower($file) == 'cvs' || strtolower($file) == 'dummy' || filesize(EXPORT_PATH.'/'.$file) == 0) continue;
+
+ $file_size = formatSize( filesize(EXPORT_PATH.'/'.$file) );
+ $import_filenames[$file] = $file.' ('.$file_size.')';
+ }
+ closedir($folder_handle);
+ }
+
+ $options = $object->GetFieldOptions('ImportLocalFilename');
+ $options['options'] = $import_filenames;
+ $object->SetFieldOptions('ImportLocalFilename', $options);
+ }
+
+ /**
+ * Returns specific to each item type columns only
+ *
+ * @param kEvent $event
+ * @return Array
+ */
+ function getCustomExportColumns(&$event)
+ {
+ return Array( '__VIRTUAL__ThumbnailImage' => 'ThumbnailImage',
+ '__VIRTUAL__FullImage' => 'FullImage',
+ '__VIRTUAL__ImageAlt' => 'ImageAlt');
+ }
+
+ /**
+ * Sets non standart virtual fields (e.g. to other tables)
+ *
+ * @param kEvent $event
+ */
+ function setCustomExportColumns(&$event)
+ {
+ $this->restorePrimaryImage($event);
+ }
+
+ /**
+ * Create/Update primary image record in info found in imported data
+ *
+ * @param kEvent $event
+ */
+ function restorePrimaryImage(&$event)
+ {
+ $object =& $event->getObject();
+
+ $has_image_info = $object->GetDBField('ImageAlt') && ($object->GetDBField('ThumbnailImage') || $object->GetDBField('FullImage'));
+ if (!$has_image_info) {
+ return false;
+ }
+
+ $image_data = $object->getPrimaryImageData();
+
+ $image =& $this->Application->recallObject('img', null, Array('skip_autoload' => true));
+ if ($image_data) {
+ $image->Load($image_data['ImageId']);
+ }
+ else {
+ $image->Clear();
+ $image->SetDBField('Name', 'main');
+ $image->SetDBField('DefaultImg', 1);
+ $image->SetDBField('ResourceId', $object->GetDBField('ResourceId'));
+ }
+
+ $image->SetDBField('AltName', $object->GetDBField('ImageAlt'));
+
+ if ($object->GetDBField('ThumbnailImage')) {
+ $thumbnail_field = $this->isURL( $object->GetDBField('ThumbnailImage') ) ? 'ThumbUrl' : 'ThumbPath';
+ $image->SetDBField($thumbnail_field, $object->GetDBField('ThumbnailImage') );
+ $image->SetDBField('LocalThumb', $thumbnail_field == 'ThumbPath' ? 1 : 0);
+ }
+
+ if (!$object->GetDBField('FullImage')) {
+ $image->SetDBField('SameImages', 1);
+ }
+ else {
+ $image->SetDBField('SameImages', 0);
+ $full_field = $this->isURL( $object->GetDBField('FullImage') ) ? 'Url' : 'LocalPath';
+ $image->SetDBField($full_field, $object->GetDBField('FullImage') );
+ $image->SetDBField('LocalImage', $full_field == 'LocalPath' ? 1 : 0);
+ }
+
+ if ($image->isLoaded()) {
+ $image->Update();
+ }
+ else {
+ $image->Create();
+ }
+ }
+
+ function isURL($path)
+ {
+ return preg_match('#(http|https)://(.*)#', $path);
+ }
+
+// ImportLocalFilename
+
+ function getExportField($field_key)
+ {
+ $prepends = Array('__CUSTOM__', '__CATEGORY__');
+ foreach ($prepends as $prepend)
+ {
+ if (substr($field_key, 0, strlen($prepend) ) == $prepend)
+ {
+ $field_key = substr($field_key, strlen($prepend), strlen($field_key) );
+ break;
+ }
+ }
+ return $field_key;
+ }
+
+ /**
+ * Prepares item for import/export operations
+ *
+ * @param kEvent $event
+ */
+ function OnNew(&$event)
+ {
+ parent::OnNew($event);
+
+ if ($event->Special != 'import' && $event->Special != 'export') return ;
+ $this->setRequiredFields($event);
+ $this->Application->StoreVar('ImportCategory', 0);
+ }
+
+ /**
+ * set required fields based on import or export params
+ *
+ * @param kEvent $event
+ */
+ function setRequiredFields(&$event)
+ {
+ $required_fields['common'] = Array('FieldsSeparatedBy', 'LineEndings', 'CategoryFormat');
+
+ $required_fields['export'] = Array('ExportFormat', 'ExportFilename','ExportColumns');
+ $required_fields['import'] = Array('FieldTitles', 'ImportSource', 'CheckDuplicatesMethod'); // ImportFilename, ImportLocalFilename
+
+ $object =& $event->getObject();
+ if ($event->Special == 'import')
+ {
+ $import_source = Array(1 => 'ImportFilename', 2 => 'ImportLocalFilename');
+ $used_field = $import_source[ $object->GetDBField('ImportSource') ];
+
+ $required_fields[$event->Special][] = $used_field;
+ $object->Fields[$used_field]['error_field'] = 'ImportSource';
+
+ if ($object->GetDBField('FieldTitles') == 2) $required_fields[$event->Special][] = 'ExportColumns'; // manual field titles
+ }
+
+ $required_fields = array_merge($required_fields['common'], $required_fields[$event->Special]);
+ foreach ($required_fields as $required_field) {
+ $object->setRequired($required_field, true);
+ }
+ }
+
+ /**
+ * Process items selected in item_selector
+ *
+ * @param kEvent $event
+ */
+ function OnProcessSelected(&$event)
+ {
+ $selected_ids = $this->Application->GetVar('selected_ids');
+
+ $dst_field = $this->Application->RecallVar('dst_field');
+
+ if ($dst_field == 'ItemCategory') {
+ // Item Edit -> Categories Tab -> New Categories
+ $object =& $event->getObject();
+ $category_ids = explode(',', $selected_ids['c']);
+ foreach ($category_ids as $category_id) {
+ $object->assignToCategory($category_id);
+ }
+ }
+
+ if ($dst_field == 'ImportCategory') {
+ // Tools -> Import -> Item Import -> Select Import Category
+ $this->Application->StoreVar('ImportCategory', $selected_ids['c']);
+ $this->Application->StoreVar($event->getPrefixSpecial().'_ForceNotValid', 1); // not to loose import/export values on form refresh
+
+ $this->Application->SetVar($event->getPrefixSpecial().'_id', 0);
+ $this->Application->SetVar($event->getPrefixSpecial().'_event', 'OnExportBegin');
+
+ $passed = $this->Application->GetVar('passed');
+ $this->Application->SetVar('passed', $passed.','.$event->getPrefixSpecial());
+ $event->setEventParam('pass_events', true);
+ }
+
+ $this->finalizePopup($event);
+ }
+
+ /**
+ * Saves Import/Export settings to session
+ *
+ * @param kEvent $event
+ */
+ function OnSaveSettings(&$event)
+ {
+ $event->redirect = false;
+ $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
+ if ($items_info) {
+ list($id, $field_values) = each($items_info);
+
+ $object =& $event->getObject( Array('skip_autoload' => true) );
+ $object->SetFieldsFromHash($field_values);
+ $field_values['ImportFilename'] = $object->GetDBField('ImportFilename'); //if upload formatter has renamed the file during moving !!!
+ $field_values['ImportSource'] = 2;
+ $field_values['ImportLocalFilename'] = $object->GetDBField('ImportFilename');
+ $items_info[$id] = $field_values;
+
+ $this->Application->StoreVar($event->getPrefixSpecial().'_ItemsInfo', serialize($items_info));
+ }
+ }
+
+ function OnCancelAction(&$event)
+ {
+ $event->redirect_params = Array('pass' => 'all,'.$event->GetPrefixSpecial());
+ $event->redirect = $this->Application->GetVar('cancel_template');
+ }
+
+/* === RELATED TO IMPORT/EXPORT: END === */
+
+ /**
+ * Stores item's owner login into separate field together with id
+ *
+ * @param kEvent $event
+ * @param string $id_field
+ * @param string $cached_field
+ */
+ function cacheItemOwner(&$event, $id_field, $cached_field)
+ {
+ $object =& $event->getObject();
+
+ $user_id = $object->GetDBField($id_field);
+ $options = $object->GetFieldOptions($id_field);
+ if (isset($options['options'][$user_id])) {
+ $object->SetDBField($cached_field, $options['options'][$user_id]);
+ }
+ else {
+ $id_field = $this->Application->getUnitOption('u', 'IDField');
+ $table_name = $this->Application->getUnitOption('u', 'TableName');
+
+ $sql = 'SELECT Login
+ FROM '.$table_name.'
+ WHERE '.$id_field.' = '.$user_id;
+ $object->SetDBField($cached_field, $this->Conn->GetOne($sql));
+ }
+ }
+
+ /**
+ * Saves item beeing edited into temp table
+ *
+ * @param kEvent $event
+ */
+ function OnPreSave(&$event)
+ {
+ parent::OnPreSave($event);
+ $use_pending_editing = $this->Application->getUnitOption($event->Prefix, 'UsePendingEditing');
+ if ($event->status == erSUCCESS && $use_pending_editing) {
+ // decision: clone or not clone
+
+ $object =& $event->getObject();
+ if ($object->GetID() == 0 || $object->GetDBField('OrgId') > 0) {
+ // new items or cloned items shouldn't be cloned again
+ return true;
+ }
+ $perm_helper =& $this->Application->recallObject('PermissionsHelper');
+ if ($perm_helper->ModifyCheckPermission($object->GetDBField('CreatedById'), $object->GetDBField('CategoryId'), $event->Prefix) == 2) {
+
+ // 1. clone original item
+ $temp_handler =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
+ $cloned_ids = $temp_handler->CloneItems($event->Prefix, $event->Special, Array($object->GetID()), null, null, null, true);
+ $ci_table = $this->Application->GetTempName(TABLE_PREFIX.'CategoryItems');
+
+ // 2. delete record from CategoryItems (about cloned item) that was automatically created during call of Create method of kCatDBItem
+ $sql = 'SELECT ResourceId
+ FROM '.$object->TableName.'
+ WHERE '.$object->IDField.' = '.$cloned_ids[0];
+ $clone_resource_id = $this->Conn->GetOne($sql);
+
+ $sql = 'DELETE FROM '.$ci_table.'
+ WHERE ItemResourceId = '.$clone_resource_id.' AND PrimaryCat = 1';
+ $this->Conn->Query($sql);
+
+ // 3. copy main item categoryitems to cloned item
+ $sql = ' INSERT INTO '.$ci_table.' (CategoryId, ItemResourceId, PrimaryCat, ItemPrefix, Filename)
+ SELECT CategoryId, '.$clone_resource_id.' AS ItemResourceId, PrimaryCat, ItemPrefix, Filename
+ FROM '.$ci_table.'
+ WHERE ItemResourceId = '.$object->GetDBField('ResourceId');
+ $this->Conn->Query($sql);
+
+ // 4. put cloned id to OrgId field of item being cloned
+ $sql = 'UPDATE '.$object->TableName.'
+ SET OrgId = '.$object->GetID().'
+ WHERE '.$object->IDField.' = '.$cloned_ids[0];
+ $this->Conn->Query($sql);
+
+ // 5. substitute id of item being cloned with clone id
+ $this->Application->SetVar($event->getPrefixSpecial().'_id', $cloned_ids[0]);
+ $selected_ids = explode(',', $this->Application->RecallVar($event->getPrefixSpecial().'_selected_ids'));
+ $selected_ids[ array_search($object->GetID(), $selected_ids) ] = $cloned_ids[0];
+ $this->Application->StoreVar($event->getPrefixSpecial().'_selected_ids', implode(',', $selected_ids));
+
+ // 6. delete original item from temp table
+ $temp_handler->DeleteItems($event->Prefix, $event->Special, Array($object->GetID()));
+ }
+ }
+ }
+
+ /**
+ * Sets default expiration based on module setting
+ *
+ * @param kEvent $event
+ */
+ function OnPreCreate(&$event)
+ {
+ parent::OnPreCreate($event);
+
+ if ($event->status == erSUCCESS) {
+ $object =& $event->getObject();
+ $object->SetDBField('CreatedById', $this->Application->GetVar('u_id'));
+ }
+ }
+
+ /**
+ * Occures before original item of item in pending editing got deleted (for hooking only)
+ *
+ * @param kEvent $event
+ */
+ function OnBeforeDeleteOriginal(&$event)
+ {
+
+ }
+
+ /**
+ * Apply same processing to each item beeing selected in grid
+ *
+ * @param kEvent $event
+ * @access private
+ */
+ function iterateItems(&$event)
+ {
+ if ($event->Name != 'OnMassApprove' && $event->Name != 'OnMassDecline') {
+ return parent::iterateItems($event);
+ }
+
+ if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
+ return;
+ }
+
+ $object =& $event->getObject( Array('skip_autoload' => true) );
+ $ids = $this->StoreSelectedIDs($event);
+
+ if ($ids) {
+ foreach ($ids as $id) {
+ $object->Load($id);
+
+ switch ($event->Name) {
+ case 'OnMassApprove':
+ $ret = $object->ApproveChanges();
+ break;
+
+ case 'OnMassDecline':
+ $ret = $object->DeclineChanges();
+ break;
+ }
+
+ if (!$ret) {
+ $event->status = erFAIL;
+ $event->redirect = false;
+ break;
+ }
+ }
+ }
+ }
+
+}
+
+?>
\ No newline at end of file
Property changes on: branches/unlabeled/unlabeled-1.65.2/kernel/units/general/cat_event_handler.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.65
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: branches/unlabeled/unlabeled-1.65.2/core/units/general/cat_event_handler.php
===================================================================
--- branches/unlabeled/unlabeled-1.65.2/core/units/general/cat_event_handler.php (nonexistent)
+++ branches/unlabeled/unlabeled-1.65.2/core/units/general/cat_event_handler.php (revision 6141)
@@ -0,0 +1,1893 @@
+<?php
+
+$application =& kApplication::Instance();
+$application->Factory->includeClassFile('kDBEventHandler');
+
+class kCatDBEventHandler extends InpDBEventHandler {
+
+ /**
+ * Allows to override standart permission mapping
+ *
+ */
+ function mapPermissions()
+ {
+ parent::mapPermissions();
+ $permissions = Array(
+ 'OnExport' => Array('self' => 'view|advanced:export'),
+ 'OnExportBegin' => Array('self' => 'view|advanced:export'),
+ 'OnSaveSettings' => Array('self' => 'add|edit|advanced:import'),
+ 'OnBeforeDeleteOriginal' => Array('self' => 'edit|advanced:approve'),
+
+ 'OnCancelAction' => Array( 'self' => true),
+
+ );
+ $this->permMapping = array_merge($this->permMapping, $permissions);
+ }
+
+ /**
+ * Checks permissions of user
+ *
+ * @param kEvent $event
+ */
+ function CheckPermission(&$event)
+ {
+ if (!$this->Application->IsAdmin()) {
+ if ($event->Name == 'OnSetSortingDirect') {
+ // allow sorting on front event without view permission
+ return true;
+ }
+ }
+
+ if ($event->Name == 'OnExport') {
+ // save category_id before doing export
+ $this->Application->LinkVar('m_cat_id');
+ }
+
+ if ($event->Name == 'OnNew' && preg_match('/(.*)\/import$/', $this->Application->GetVar('t'), $rets)) {
+ // redirect to item import template, where permission (import) category will be chosen)
+ $root_category = $this->Application->findModule('Path', $rets[1].'/', 'RootCat');
+ $this->Application->StoreVar('m_cat_id', $root_category);
+ }
+
+ if ($event->Name == 'OnEdit' || $event->Name == 'OnSave') {
+ // check each id from selected individually and only if all are allowed proceed next
+ if ($event->Name == 'OnEdit') {
+ $selected_ids = implode(',', $this->StoreSelectedIDs($event));
+ }
+ else {
+ $selected_ids = $this->Application->RecallVar($event->getPrefixSpecial().'_selected_ids');
+ }
+
+ $id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
+ $table_name = $this->Application->getUnitOption($event->Prefix, 'TableName');
+ $sql = 'SELECT '.$id_field.', CreatedById, ci.CategoryId
+ FROM '.$table_name.' item_table
+ LEFT JOIN '.$this->Application->getUnitOption('ci', 'TableName').' ci ON ci.ItemResourceId = item_table.ResourceId
+ WHERE '.$id_field.' IN ('.$selected_ids.') AND (ci.PrimaryCat = 1)';
+ $items = $this->Conn->Query($sql, $id_field);
+
+ $perm_value = true;
+ $perm_helper =& $this->Application->recallObject('PermissionsHelper');
+ foreach ($items as $item_id => $item_data) {
+ if ($perm_helper->ModifyCheckPermission($item_data['CreatedById'], $item_data['CategoryId'], $event->Prefix) == 0) {
+ // one of items selected has no permission
+ $perm_value = false;
+ break;
+ }
+ }
+
+ if (!$perm_value) {
+ $event->status = erPERM_FAIL;
+ }
+
+ return $perm_value;
+ }
+
+ return parent::CheckPermission($event);
+ }
+
+ /**
+ * Add selected items to clipboard with mode = COPY (CLONE)
+ *
+ * @param kEvent $event
+ */
+ function OnCopy(&$event)
+ {
+ $this->Application->RemoveVar('clipboard');
+ $clipboard_helper =& $this->Application->recallObject('ClipboardHelper');
+ $clipboard_helper->setClipboard($event, 'copy', $this->StoreSelectedIDs($event));
+ }
+
+ /**
+ * Add selected items to clipboard with mode = CUT
+ *
+ * @param kEvent $event
+ */
+ function OnCut(&$event)
+ {
+ $this->Application->RemoveVar('clipboard');
+ $clipboard_helper =& $this->Application->recallObject('ClipboardHelper');
+ $clipboard_helper->setClipboard($event, 'cut', $this->StoreSelectedIDs($event));
+ }
+
+ /**
+ * Performs category item paste
+ *
+ * @param kEvent $event
+ */
+ function OnPaste(&$event)
+ {
+ if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
+ return;
+ }
+
+ $clipboard_data = $event->getEventParam('clipboard_data');
+
+ if (!$clipboard_data['cut'] && !$clipboard_data['copy']) {
+ return false;
+ }
+
+ if ($clipboard_data['copy']) {
+ $temp =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
+ $temp->CloneItems($event->Prefix, $event->Special, $clipboard_data['copy']);
+ }
+
+ if ($clipboard_data['cut']) {
+ $object =& $this->Application->recallObject($event->getPrefixSpecial().'.item', $event->Prefix, Array('skip_autoload' => true));
+
+ foreach ($clipboard_data['cut'] as $id) {
+ $object->Load($id);
+ $object->MoveToCat();
+ }
+ }
+ }
+
+ /**
+ * Return type clauses for list bulding on front
+ *
+ * @param kEvent $event
+ * @return Array
+ */
+ function getTypeClauses(&$event)
+ {
+ $types = $event->getEventParam('types');
+ $except_types = $event->getEventParam('except');
+ $type_clauses = Array();
+
+ $type_clauses['pick']['include'] = '%1$s.EditorsPick = 1 AND '.TABLE_PREFIX.'CategoryItems.PrimaryCat = 1';
+ $type_clauses['pick']['except'] = '%1$s.EditorsPick! = 1 AND '.TABLE_PREFIX.'CategoryItems.PrimaryCat = 1';
+ $type_clauses['pick']['having_filter'] = false;
+
+ $type_clauses['hot']['include'] = '`IsHot` = 1 AND PrimaryCat = 1';
+ $type_clauses['hot']['except'] = '`IsHot`! = 1 AND PrimaryCat = 1';
+ $type_clauses['hot']['having_filter'] = true;
+
+ $type_clauses['pop']['include'] = '`IsPop` = 1 AND PrimaryCat = 1';
+ $type_clauses['pop']['except'] = '`IsPop`! = 1 AND PrimaryCat = 1';
+ $type_clauses['pop']['having_filter'] = true;
+
+ $type_clauses['new']['include'] = '`IsNew` = 1 AND PrimaryCat = 1';
+ $type_clauses['new']['except'] = '`IsNew`! = 1 AND PrimaryCat = 1';
+ $type_clauses['new']['having_filter'] = true;
+
+ $type_clauses['displayed']['include'] = '';
+ $displayed = $this->Application->GetVar($event->Prefix.'_displayed_ids');
+ if ($displayed) {
+ $id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
+ $type_clauses['displayed']['except'] = '%1$s.'.$id_field.' NOT IN ('.$displayed.')';
+ }
+ else {
+ $type_clauses['displayed']['except'] = '';
+ }
+ $type_clauses['displayed']['having_filter'] = false;
+
+ if (strpos($types, 'search') !== false || strpos($except_types, 'search') !== false) {
+ $event_mapping = Array(
+ 'simple' => 'OnSimpleSearch',
+ 'subsearch' => 'OnSubSearch',
+ 'advanced' => 'OnAdvancedSearch');
+ if($this->Application->GetVar('INPORTAL_ON') && $this->Application->GetVar('Action') == 'm_simple_subsearch')
+ {
+ $type = 'subsearch';
+ }
+ else
+ {
+ $type = $this->Application->GetVar('search_type') ? $this->Application->GetVar('search_type') : 'simple';
+ }
+
+ if($keywords = $event->getEventParam('keyword_string')) // processing keyword_string param of ListProducts tag
+ {
+ $this->Application->SetVar('keywords', $keywords);
+ $type = 'simple';
+ }
+ $search_event = $event_mapping[$type];
+ $this->$search_event($event);
+ $search_table = TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_'.TABLE_PREFIX.'Search';
+ $sql = 'SHOW TABLES LIKE "'.$search_table.'"';
+ if ( $this->Conn->Query($sql) ) {
+ $search_res_ids = $this->Conn->GetCol('SELECT ResourceId FROM '.$search_table);
+ }
+
+ if ($search_res_ids) {
+ $type_clauses['search']['include'] = '%1$s.ResourceId IN ('.implode(',', $search_res_ids).') AND PrimaryCat = 1';
+ $type_clauses['search']['except'] = '%1$s.ResourceId NOT IN ('.implode(',', $search_res_ids).') AND PrimaryCat = 1';
+ }
+ else {
+ $type_clauses['search']['include'] = '0';
+ $type_clauses['search']['except'] = '1';
+ }
+ $type_clauses['search']['having_filter'] = false;
+ }
+
+ if (strpos($types, 'related') !== false || strpos($except_types, 'related') !== false) {
+
+ $related_to = $event->getEventParam('related_to');
+ if (!$related_to) {
+ $related_prefix = $event->Prefix;
+ }
+ else {
+ $sql = 'SELECT Prefix
+ FROM '.TABLE_PREFIX.'ItemTypes
+ WHERE ItemName = '.$this->Conn->qstr($related_to);
+ $related_prefix = $this->Conn->GetOne($sql);
+ }
+
+ $rel_table = $this->Application->getUnitOption('rel', 'TableName');
+ $item_type = $this->Application->getUnitOption($event->Prefix, 'ItemType');
+
+ $p_item =& $this->Application->recallObject($related_prefix.'.current', null, Array('skip_autoload' => true));
+ $p_item->Load( $this->Application->GetVar($related_prefix.'_id') );
+
+ $p_resource_id = $p_item->GetDBField('ResourceId');
+
+ $sql = 'SELECT SourceId, TargetId FROM '.$rel_table.'
+ WHERE
+ (Enabled = 1)
+ AND (
+ (Type = 0 AND SourceId = '.$p_resource_id.' AND TargetType = '.$item_type.')
+ OR
+ (Type = 1
+ AND (
+ (SourceId = '.$p_resource_id.' AND TargetType = '.$item_type.')
+ OR
+ (TargetId = '.$p_resource_id.' AND SourceType = '.$item_type.')
+ )
+ )
+ )';
+
+ $related_ids_array = $this->Conn->Query($sql);
+ $related_ids = Array();
+
+ foreach ($related_ids_array as $key => $record) {
+ $related_ids[] = $record[ $record['SourceId'] == $p_resource_id ? 'TargetId' : 'SourceId' ];
+ }
+
+ if (count($related_ids) > 0) {
+ $type_clauses['related']['include'] = '%1$s.ResourceId IN ('.implode(',', $related_ids).') AND PrimaryCat = 1';
+ $type_clauses['related']['except'] = '%1$s.ResourceId NOT IN ('.implode(',', $related_ids).') AND PrimaryCat = 1';
+ }
+ else {
+ $type_clauses['related']['include'] = '0';
+ $type_clauses['related']['except'] = '1';
+ }
+ $type_clauses['related']['having_filter'] = false;
+ }
+
+ return $type_clauses;
+ }
+
+ /**
+ * Apply filters to list
+ *
+ * @param kEvent $event
+ */
+ function SetCustomQuery(&$event)
+ {
+ parent::SetCustomQuery($event);
+
+ $object =& $event->getObject();
+
+ // add category filter if needed
+ if ($event->Special != 'showall') {
+ if ( $event->getEventParam('parent_cat_id') ) {
+ $parent_cat_id = $event->getEventParam('parent_cat_id');
+ }
+ else {
+ $parent_cat_id = $this->Application->GetVar('c_id');
+ if (!$parent_cat_id) {
+ $parent_cat_id = $this->Application->GetVar('m_cat_id');
+ }
+ if (!$parent_cat_id) {
+ $parent_cat_id = 0;
+ }
+ }
+
+ if ((string) $parent_cat_id != 'any') {
+ if ($event->getEventParam('recursive')) {
+ $current_path = $this->Conn->GetOne('SELECT ParentPath FROM '.TABLE_PREFIX.'Category WHERE CategoryId='.$parent_cat_id);
+ $subcats = $this->Conn->GetCol('SELECT CategoryId FROM '.TABLE_PREFIX.'Category WHERE ParentPath LIKE "'.$current_path.'%" ');
+ $object->addFilter('category_filter', TABLE_PREFIX.'CategoryItems.CategoryId IN ('.implode(', ', $subcats).')');
+ }
+ else {
+ $object->addFilter('category_filter', TABLE_PREFIX.'CategoryItems.CategoryId = '.$parent_cat_id );
+ }
+ }
+ }
+ else {
+ $object->addFilter('primary_filter', 'PrimaryCat = 1');
+ }
+
+ // add permission filter
+ if ($this->Application->GetVar('u_id') == -1) {
+ // for "root" CATEGORY.VIEW permission is checked for items lists too
+ $view_perm = 1;
+ }
+ else {
+ // for any real user itemlist view permission is checked instead of CATEGORY.VIEW
+ $sql = 'SELECT PermissionConfigId
+ FROM '.TABLE_PREFIX.'PermissionConfig
+ WHERE PermissionName = "'.$this->Application->getUnitOption($event->Prefix, 'PermItemPrefix').'.VIEW"';
+ $view_perm = $this->Conn->GetOne($sql);
+
+ $groups = explode( ',', $this->Application->RecallVar('UserGroups') );
+ foreach($groups as $group)
+ {
+ $view_filters[] = 'FIND_IN_SET('.$group.', perm.acl)';
+ }
+ $view_filter = implode(' OR ', $view_filters);
+ $object->addFilter('perm_filter2', $view_filter);
+ }
+
+ $object->addFilter('perm_filter', 'perm.PermId = '.$view_perm);
+
+ if ( !$this->Application->IsAdmin() )
+ {
+ $object->addFilter('status_filter', $object->TableName.'.Status = 1');
+ if ($this->Application->getUnitOption($event->Prefix, 'UsePendingEditing')) {
+ // if category item uses pending editing abilities, then in no cases show pending copies on front
+ $object->addFilter('original_filter', '%1$s.OrgId = 0 OR %1$s.OrgId IS NULL');
+ }
+ }
+ else {
+ if ($this->Application->getUnitOption($event->Prefix, 'UsePendingEditing')) {
+ $pending_ids = $this->Conn->GetCol(
+ 'SELECT OrgId FROM '.$object->TableName.'
+ WHERE Status = -2 AND OrgId IS NOT NULL');
+ if ($pending_ids) {
+ $object->addFilter('no_original_filter', '%1$s.'.$object->IDField.' NOT IN ('.implode(',', $pending_ids).')');
+ }
+ }
+ }
+
+ $types = $event->getEventParam('types');
+ $except_types = $event->getEventParam('except');
+ $type_clauses = $this->getTypeClauses($event);
+
+ // convert prepared type clauses into list filters
+ $includes_or_filter =& $this->Application->makeClass('kMultipleFilter');
+ $includes_or_filter->setType(FLT_TYPE_OR);
+
+ $excepts_and_filter =& $this->Application->makeClass('kMultipleFilter');
+ $excepts_and_filter->setType(FLT_TYPE_AND);
+
+ $includes_or_filter_h =& $this->Application->makeClass('kMultipleFilter');
+ $includes_or_filter_h->setType(FLT_TYPE_OR);
+
+ $excepts_and_filter_h =& $this->Application->makeClass('kMultipleFilter');
+ $excepts_and_filter_h->setType(FLT_TYPE_AND);
+
+ $except_types_array = explode(',', $types);
+
+ if ($types) {
+ $types_array = explode(',', $types);
+ for ($i = 0; $i < sizeof($types_array); $i++) {
+ $type = trim($types_array[$i]);
+ if (isset($type_clauses[$type])) {
+ if ($type_clauses[$type]['having_filter']) {
+ $includes_or_filter_h->removeFilter('filter_'.$type);
+ $includes_or_filter_h->addFilter('filter_'.$type, $type_clauses[$type]['include']);
+ }else {
+ $includes_or_filter->removeFilter('filter_'.$type);
+ $includes_or_filter->addFilter('filter_'.$type, $type_clauses[$type]['include']);
+ }
+ }
+ }
+ }
+
+ if ($except_types) {
+ $except_types_array = explode(',', $except_types);
+ for ($i = 0; $i < sizeof($except_types_array); $i++) {
+ $type = trim($except_types_array[$i]);
+ if (isset($type_clauses[$type])) {
+ if ($type_clauses[$type]['having_filter']) {
+ $excepts_and_filter_h->removeFilter('filter_'.$type);
+ $excepts_and_filter_h->addFilter('filter_'.$type, $type_clauses[$type]['except']);
+ }else {
+ $excepts_and_filter->removeFilter('filter_'.$type);
+ $excepts_and_filter->addFilter('filter_'.$type, $type_clauses[$type]['except']);
+ }
+ }
+ }
+ }
+
+ /*if ( !$this->Application->IsAdmin() ) {
+ $object->addFilter('expire_filter', '%1$s.Expire IS NULL OR %1$s.Expire > UNIX_TIMESTAMP()');
+ }*/
+
+ /*$list_type = $event->getEventParam('ListType');
+ switch($list_type)
+ {
+ case 'favorites':
+ $fav_table = $this->Application->getUnitOption('fav','TableName');
+ $user_id =& $this->Application->GetVar('u_id');
+
+ $sql = 'SELECT DISTINCT f.ResourceId
+ FROM '.$fav_table.' f
+ LEFT JOIN '.$object->TableName.' p ON p.ResourceId = f.ResourceId
+ WHERE f.PortalUserId = '.$user_id;
+ $ids = $this->Conn->GetCol($sql);
+ if(!$ids) $ids = Array(-1);
+ $object->addFilter('category_filter', TABLE_PREFIX.'CategoryItems.PrimaryCat = 1');
+ $object->addFilter('favorites_filter', '%1$s.`ResourceId` IN ('.implode(',',$ids).')');
+ break;
+ case 'search':
+ $search_results_table = TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_'.TABLE_PREFIX.'Search';
+ $sql = ' SELECT DISTINCT ResourceId
+ FROM '.$search_results_table.'
+ WHERE ItemType=11';
+ $ids = $this->Conn->GetCol($sql);
+ if(!$ids) $ids = Array(-1);
+ $object->addFilter('search_filter', '%1$s.`ResourceId` IN ('.implode(',',$ids).')');
+ break;
+ } */
+
+ $object->addFilter('includes_filter', $includes_or_filter);
+ $object->addFilter('excepts_filter', $excepts_and_filter);
+
+ $object->addFilter('includes_filter_h', $includes_or_filter_h, HAVING_FILTER);
+ $object->addFilter('excepts_filter_h', $excepts_and_filter_h, HAVING_FILTER);
+ }
+
+ /**
+ * Adds calculates fields for item statuses
+ *
+ * @param kCatDBItem $object
+ * @param kEvent $event
+ */
+ function prepareObject(&$object, &$event)
+ {
+ $this->prepareItemStatuses($event);
+
+ $object->addCalculatedField('CachedNavbar', 'l'.$this->Application->GetVar('m_lang').'_CachedNavbar');
+
+ if ($event->Special == 'export' || $event->Special == 'import')
+ {
+ $this->prepareExportColumns($event);
+ }
+ }
+
+ /**
+ * Creates calculated fields for all item statuses based on config settings
+ *
+ * @param kEvent $event
+ */
+ function prepareItemStatuses(&$event)
+ {
+ $object =& $event->getObject( Array('skip_autoload' => true) );
+
+ $property_map = $this->Application->getUnitOption($event->Prefix, 'ItemPropertyMappings');
+ if (!$property_map) {
+ return ;
+ }
+
+ // new items
+ $object->addCalculatedField('IsNew', ' IF(%1$s.NewItem = 2,
+ IF(%1$s.CreatedOn >= (UNIX_TIMESTAMP() - '.
+ $this->Application->ConfigValue($property_map['NewDays']).
+ '*3600*24), 1, 0),
+ %1$s.NewItem
+ )');
+
+ // hot items (cache updated every hour)
+ $sql = 'SELECT Data
+ FROM '.TABLE_PREFIX.'Cache
+ WHERE (VarName = "'.$property_map['HotLimit'].'") AND (Cached >'.(adodb_mktime() - 3600).')';
+ $hot_limit = $this->Conn->GetOne($sql);
+ if ($hot_limit === false) {
+ $hot_limit = $this->CalculateHotLimit($event);
+ }
+ $object->addCalculatedField('IsHot', ' IF(%1$s.HotItem = 2,
+ IF(%1$s.'.$property_map['ClickField'].' >= '.$hot_limit.', 1, 0),
+ %1$s.HotItem
+ )');
+
+ // popular items
+ $object->addCalculatedField('IsPop', ' IF(%1$s.PopItem = 2,
+ IF(%1$s.CachedVotesQty >= '.
+ $this->Application->ConfigValue($property_map['MinPopVotes']).
+ ' AND %1$s.CachedRating >= '.
+ $this->Application->ConfigValue($property_map['MinPopRating']).
+ ', 1, 0),
+ %1$s.PopItem)');
+
+ }
+
+ function CalculateHotLimit(&$event)
+ {
+ $property_map = $this->Application->getUnitOption($event->Prefix, 'ItemPropertyMappings');
+ if (!$property_map) {
+ return;
+ }
+ $click_field = $property_map['ClickField'];
+
+ $last_hot = $this->Application->ConfigValue($property_map['MaxHotNumber']) - 1;
+ $sql = 'SELECT '.$click_field.' FROM '.$this->Application->getUnitOption($event->Prefix, 'TableName').'
+ ORDER BY '.$click_field.' DESC
+ LIMIT '.$last_hot.', 1';
+ $res = $this->Conn->GetCol($sql);
+ $hot_limit = (double)array_shift($res);
+ $this->Conn->Query('REPLACE INTO '.TABLE_PREFIX.'Cache (VarName, Data, Cached) VALUES ("'.$property_map['HotLimit'].'", "'.$hot_limit.'", '.adodb_mktime().')');
+ return $hot_limit;
+
+ return 0;
+ }
+
+ /**
+ * Enter description here...
+ *
+ * @param kEvent $event
+ */
+ function OnBeforeItemUpdate(&$event)
+ {
+ $property_map = $this->Application->getUnitOption($event->Prefix, 'ItemPropertyMappings');
+ if (!$property_map) {
+ return;
+ }
+ $click_field = $property_map['ClickField'];
+
+ $object =& $event->getObject();
+ if( $this->Application->IsAdmin() && ($this->Application->GetVar($click_field.'_original') !== false) &&
+ floor($this->Application->GetVar($click_field.'_original')) != $object->GetDBField($click_field) )
+ {
+ $sql = 'SELECT MAX('.$click_field.') FROM '.$this->Application->getUnitOption($event->Prefix, 'TableName').'
+ WHERE FLOOR('.$click_field.') = '.$object->GetDBField($click_field);
+ $hits = ( $res = $this->Conn->GetOne($sql) ) ? $res + 0.000001 : $object->GetDBField($click_field);
+ $object->SetDBField($click_field, $hits);
+ }
+ }
+
+ /**
+ * Load price from temp table if product mode is temp table
+ *
+ * @param kEvent $event
+ */
+ function OnAfterItemLoad(&$event)
+ {
+ $special = substr($event->Special, -6);
+ $object =& $event->getObject();
+ if ($special == 'import' || $special == 'export') {
+ $image_data = $object->getPrimaryImageData();
+
+ if ($image_data) {
+ $thumbnail_image = $image_data[$image_data['LocalThumb'] ? 'ThumbPath' : 'ThumbUrl'];
+ if ($image_data['SameImages']) {
+ $full_image = '';
+ }
+ else {
+ $full_image = $image_data[$image_data['LocalImage'] ? 'LocalPath' : 'Url'];
+ }
+ $object->SetDBField('ThumbnailImage', $thumbnail_image);
+ $object->SetDBField('FullImage', $full_image);
+ $object->SetDBField('ImageAlt', $image_data['AltName']);
+ }
+ }
+
+ //substituiting pending status value for pending editing
+ if ($object->HasField('OrgId') && $object->GetDBField('OrgId') > 0 && $object->GetDBField('Status') == -2) {
+ $options = $object->Fields['Status']['options'];
+ foreach ($options as $key => $val) {
+ if ($key == 2) $key = -2;
+ $new_options[$key] = $val;
+ }
+ $object->Fields['Status']['options'] = $new_options;
+ }
+
+ }
+
+ function OnAfterItemUpdate(&$event)
+ {
+ $this->CalculateHotLimit($event);
+
+ if ( substr($event->Special, -6) == 'import') {
+ $this->setCustomExportColumns($event);
+ }
+ }
+
+ /**
+ * sets values for import process
+ *
+ * @param kEvent $event
+ */
+ function OnAfterItemCreate(&$event)
+ {
+ if ( substr($event->Special, -6) == 'import') {
+ $this->setCustomExportColumns($event);
+ }
+ }
+
+ /**
+ * Make record to search log
+ *
+ * @param string $keywords
+ * @param int $search_type 0 - simple search, 1 - advanced search
+ */
+ function saveToSearchLog($keywords, $search_type = 0)
+ {
+ $sql = 'UPDATE '.TABLE_PREFIX.'SearchLog
+ SET Indices = Indices + 1
+ WHERE Keyword = '.$this->Conn->qstr($keywords).' AND SearchType = '.$search_type; // 0 - simple search, 1 - advanced search
+ $this->Conn->Query($sql);
+ if ($this->Conn->getAffectedRows() == 0) {
+ $fields_hash = Array('Keyword' => $keywords, 'Indices' => 1, 'SearchType' => $search_type);
+ $this->Conn->doInsert($fields_hash, TABLE_PREFIX.'SearchLog');
+ }
+ }
+
+ /**
+ * Makes simple search for products
+ * based on keywords string
+ *
+ * @param kEvent $event
+ * @todo Change all hardcoded Products table & In-Commerce module usage to dynamic usage from item config !!!
+ */
+ function OnSimpleSearch(&$event)
+ {
+ if($this->Application->GetVar('INPORTAL_ON') && !($this->Application->GetVar('Action') == 'm_simple_search'))
+ {
+ return;
+ }
+
+ $event->redirect = false;
+ $search_table = TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_'.TABLE_PREFIX.'Search';
+
+ $keywords = unhtmlentities( trim($this->Application->GetVar('keywords')) );
+
+ $query_object =& $this->Application->recallObject('HTTPQuery');
+ $sql = 'SHOW TABLES LIKE "'.$search_table.'"';
+
+ if(!isset($query_object->Get['keywords']) &&
+ !isset($query_object->Post['keywords']) &&
+ $this->Conn->Query($sql))
+ {
+ return; // used when navigating by pages or changing sorting in search results
+ }
+ if(!$keywords || strlen($keywords) < $this->Application->ConfigValue('Search_MinKeyword_Length'))
+ {
+ $this->Conn->Query('DROP TABLE IF EXISTS '.$search_table);
+ $this->Application->SetVar('keywords_too_short', 1);
+ return; // if no or too short keyword entered, doing nothing
+ }
+
+ $this->Application->StoreVar('keywords', $keywords);
+ if (!$this->Application->GetVar('INPORTAL_ON')) {
+ // don't save search log, because in-portal already saved it
+ $this->saveToSearchLog($keywords, 0); // 0 - simple search, 1 - advanced search
+ }
+
+
+ $keywords = strtr($keywords, Array('%' => '\\%', '_' => '\\_'));
+
+ $event->setPseudoClass('_List');
+ $object =& $event->getObject();
+ $this->Application->SetVar($event->getPrefixSpecial().'_Page', 1);
+ $lang = $this->Application->GetVar('m_lang');
+ $product_table = $this->Application->getUnitOption('p', 'TableName');
+
+ $sql = ' SELECT * FROM '.$this->Application->getUnitOption('confs', 'TableName').'
+ WHERE ModuleName="In-Commerce"
+ AND SimpleSearch=1';
+ $search_config = $this->Conn->Query($sql, 'FieldName');
+ $field_list = array_keys($search_config);
+
+ $join_clauses = Array();
+
+ // field processing
+ $weight_sum = 0;
+
+ $alias_counter = 0;
+
+ $custom_fields = $this->Application->getUnitOption($event->Prefix, 'CustomFields');
+ if ($custom_fields) {
+ $custom_table = $this->Application->getUnitOption($event->Prefix.'-cdata', 'TableName');
+ $join_clauses[] = ' LEFT JOIN '.$custom_table.' custom_data ON '.$product_table.'.ResourceId = custom_data.ResourceId';
+ }
+
+ // what field in search config becomes what field in sql (key - new field, value - old field (from searchconfig table))
+ $search_config_map = Array();
+
+ foreach ($field_list as $key => $field) {
+ $options = $object->getFieldOptions($field);
+ $local_table = TABLE_PREFIX.$search_config[$field]['TableName'];
+ $weight_sum += $search_config[$field]['Priority']; // counting weight sum; used when making relevance clause
+
+ // processing multilingual fields
+ if (getArrayValue($options, 'formatter') == 'kMultiLanguage') {
+ $field_list[$key.'_primary'] = 'l'.$this->Application->GetDefaultLanguageId().'_'.$field;
+ $field_list[$key] = 'l'.$lang.'_'.$field;
+
+ if(!isset($search_config[$field]['ForeignField']))
+ {
+ $field_list[$key.'_primary'] = $local_table.'.'.$field_list[$key.'_primary'];
+ $search_config_map[ $field_list[$key.'_primary'] ] = $field;
+ }
+ }
+
+ // processing fields from other tables
+ if($foreign_field = $search_config[$field]['ForeignField'])
+ {
+ $exploded = explode(':', $foreign_field, 2);
+ if($exploded[0] == 'CALC')
+ {
+ unset($field_list[$key]);
+ continue; // ignoring having type clauses in simple search
+ /*$user_object =& $this->Application->recallObject('u');
+ $user_groups = $this->Application->RecallVar('UserGroups');
+ $having_list[$key] = str_replace('{PREFIX}', TABLE_PREFIX, $exploded[1]);
+ $join_clause = str_replace('{PREFIX}', TABLE_PREFIX, $search_config[$field]['JoinClause']);
+ $join_clause = str_replace('{USER_GROUPS}', $user_groups, $join_clause);
+ $join_clause = ' LEFT JOIN '.$join_clause;
+ $join_clauses[] = $join_clause;*/
+ }
+ else
+ {
+ $exploded = explode('.', $foreign_field); // format: table.field_name
+ $foreign_table = TABLE_PREFIX.$exploded[0];
+
+ $alias_counter++;
+ $alias = 't'.$alias_counter;
+
+ $field_list[$key] = $alias.'.'.$exploded[1];
+ $search_config_map[ $field_list[$key] ] = $field;
+
+ $join_clause = str_replace('{ForeignTable}', $alias, $search_config[$field]['JoinClause']);
+ $join_clause = str_replace('{LocalTable}', $product_table, $join_clause);
+
+ $join_clauses[] = ' LEFT JOIN '.$foreign_table.' '.$alias.'
+ ON '.$join_clause;
+ }
+ }
+ else {
+ // processing fields from local table
+ if ($search_config[$field]['CustomFieldId']) {
+ $local_table = 'custom_data';
+ $field_list[$key] = 'l'.$lang.'_cust_'.array_search($field_list[$key], $custom_fields);
+ }
+ $field_list[$key] = $local_table.'.'.$field_list[$key];
+ $search_config_map[ $field_list[$key] ] = $field;
+ }
+ }
+
+ // keyword string processing
+ $search_helper =& $this->Application->recallObject('SearchHelper');
+ $where_clause = $search_helper->buildWhereClause($keywords, $field_list);
+
+ $where_clause = $where_clause.' AND '.$product_table.'.Status=1';
+
+ if($this->Application->GetVar('Action') == 'm_simple_subsearch') // subsearch, In-portal
+ {
+ if( $event->getEventParam('ResultIds') )
+ {
+ $where_clause .= ' AND '.$product_table.'.ResourceId IN ('.implode(',', $event->specificParams['ResultIds']).')';
+ }
+ }
+ if( $event->MasterEvent && $event->MasterEvent->Name == 'OnListBuild' ) // subsearch, k4
+ {
+ if( $event->MasterEvent->getEventParam('ResultIds') )
+ {
+ $where_clause .= ' AND '.$product_table.'.ResourceId IN ('.implode(',', $event->MasterEvent->getEventParam('ResultIds')).')';
+ }
+ }
+
+ // making relevance clause
+ $positive_words = $search_helper->getPositiveKeywords($keywords);
+ $this->Application->StoreVar('highlight_keywords', serialize($positive_words));
+ $revelance_parts = Array();
+ reset($search_config);
+ foreach ($field_list as $field) {
+ $config_elem = $search_config[ $search_config_map[$field] ];
+ $weight = $config_elem['Priority'];
+ $revelance_parts[] = 'IF('.$field.' LIKE "%'.implode(' ', $positive_words).'%", '.$weight_sum.', 0)';
+ foreach ($positive_words as $keyword) {
+ $revelance_parts[] = 'IF('.$field.' LIKE "%'.$keyword.'%", '.$weight.', 0)';
+ }
+ }
+ $rel_keywords = $this->Application->ConfigValue('SearchRel_Keyword_products') / 100;
+ $rel_pop = $this->Application->ConfigValue('SearchRel_Pop_products') / 100;
+ $rel_rating = $this->Application->ConfigValue('SearchRel_Rating_products') / 100;
+ $relevance_clause = '('.implode(' + ', $revelance_parts).') / '.$weight_sum.' * '.$rel_keywords;
+ $relevance_clause .= ' + (Hits + 1) / (MAX(Hits) + 1) * '.$rel_pop;
+ $relevance_clause .= ' + (CachedRating + 1) / (MAX(CachedRating) + 1) * '.$rel_rating;
+
+ // building final search query
+ if (!$this->Application->GetVar('INPORTAL_ON')) {
+ $this->Conn->Query('DROP TABLE IF EXISTS '.$search_table); // erase old search table if clean k4 event
+ }
+
+ if ($this->Conn->Query('SHOW TABLES LIKE "'.$search_table.'"')) {
+ $select_intro = 'INSERT INTO '.$search_table.' (Relevance, ItemId, ResourceId, ItemType, EdPick) ';
+ }
+ else {
+ $select_intro = 'CREATE TABLE '.$search_table.' AS ';
+ }
+
+ $sql = $select_intro.' SELECT '.$relevance_clause.' AS Relevance,
+ '.$product_table.'.ProductId AS ItemId,
+ '.$product_table.'.ResourceId,
+ 11 AS ItemType,
+ '.$product_table.'.EditorsPick AS EdPick
+ FROM '.$object->TableName.'
+ '.implode(' ', $join_clauses).'
+ WHERE '.$where_clause.'
+ GROUP BY '.$product_table.'.ProductId';
+
+ $res = $this->Conn->Query($sql);
+ }
+
+ /**
+ * Enter description here...
+ *
+ * @param kEvent $event
+ */
+ function OnSubSearch(&$event)
+ {
+ $search_table = TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_'.TABLE_PREFIX.'Search';
+ $sql = 'SHOW TABLES LIKE "'.$search_table.'"';
+ if($this->Conn->Query($sql))
+ {
+ $sql = 'SELECT DISTINCT ResourceId FROM '.$search_table;
+ $ids = $this->Conn->GetCol($sql);
+ }
+ $event->setEventParam('ResultIds', $ids);
+ $event->CallSubEvent('OnSimpleSearch');
+ }
+
+ /**
+ * Enter description here...
+ *
+ * @param kEvent $event
+ * @todo Change all hardcoded Products table & In-Commerce module usage to dynamic usage from item config !!!
+ */
+ function OnAdvancedSearch(&$event)
+ {
+ $query_object =& $this->Application->recallObject('HTTPQuery');
+ if(!isset($query_object->Post['andor']))
+ {
+ return; // used when navigating by pages or changing sorting in search results
+ }
+
+ $this->Application->RemoveVar('keywords');
+ $this->Application->RemoveVar('Search_Keywords');
+
+ $sql = ' SELECT * FROM '.$this->Application->getUnitOption('confs', 'TableName').'
+ WHERE ModuleName="In-Commerce"
+ AND AdvancedSearch=1';
+ $search_config = $this->Conn->Query($sql);
+ $lang = $this->Application->GetVar('m_lang');
+ $object =& $event->getObject();
+ $object->SetPage(1);
+ $user_object =& $this->Application->recallObject('u');
+ $product_table = $this->Application->getUnitOption('p', 'TableName');
+
+ $search_keywords = $this->Application->GetVar('value'); // will not be changed
+
+ $keywords = $this->Application->GetVar('value'); // will be changed down there
+ $verbs = $this->Application->GetVar('verb');
+ $glues = $this->Application->GetVar('andor');
+
+ $and_conditions = Array();
+ $or_conditions = Array();
+ $and_having_conditions = Array();
+ $or_having_conditions = Array();
+ $join_clauses = Array();
+ $highlight_keywords = Array();
+ $relevance_parts = Array();
+
+ $condition_patterns = Array( 'any' => '%s LIKE %s',
+ 'contains' => '%s LIKE %s',
+ 'notcontains' => '(NOT (%1$s LIKE %2$s) OR %1$s IS NULL)',
+ 'is' => '%s = %s',
+ 'isnot' => '(%1$s != %2$s OR %1$s IS NULL)');
+
+ $alias_counter = 0;
+
+ $custom_fields = $this->Application->getUnitOption($event->Prefix, 'CustomFields');
+ if ($custom_fields) {
+ $custom_table = $this->Application->getUnitOption($event->Prefix.'-cdata', 'TableName');
+ $join_clauses[] = ' LEFT JOIN '.$custom_table.' custom_data ON '.$product_table.'.ResourceId = custom_data.ResourceId';
+ }
+
+ $search_log = '';
+ $weight_sum = 0;
+ // processing fields and preparing conditions
+ foreach($search_config as $record)
+ {
+ $field = $record['FieldName'];
+ $join_clause = '';
+ $condition_mode = 'WHERE';
+
+ // field processing
+
+ $options = $object->getFieldOptions($field);
+ $local_table = TABLE_PREFIX.$record['TableName'];
+ $weight_sum += $record['Priority']; // counting weight sum; used when making relevance clause
+
+ // processing multilingual fields
+ if (getArrayValue($options, 'formatter') == 'kMultiLanguage') {
+ $field_name = 'l'.$lang.'_'.$field;
+ }
+ else {
+ $field_name = $field;
+ }
+
+ // processing fields from other tables
+ if ($foreign_field = $record['ForeignField']) {
+ $exploded = explode(':', $foreign_field, 2);
+ if($exploded[0] == 'CALC')
+ {
+ $user_groups = $this->Application->RecallVar('UserGroups');
+ $field_name = str_replace('{PREFIX}', TABLE_PREFIX, $exploded[1]);
+ $join_clause = str_replace('{PREFIX}', TABLE_PREFIX, $record['JoinClause']);
+ $join_clause = str_replace('{USER_GROUPS}', $user_groups, $join_clause);
+ $join_clause = ' LEFT JOIN '.$join_clause;
+
+ $condition_mode = 'HAVING';
+ }
+ else {
+ $exploded = explode('.', $foreign_field);
+ $foreign_table = TABLE_PREFIX.$exploded[0];
+
+ if($record['CustomFieldId']) {
+ $exploded[1] = 'l'.$lang.'_'.$exploded[1];
+ }
+
+ $alias_counter++;
+ $alias = 't'.$alias_counter;
+
+ $field_name = $alias.'.'.$exploded[1];
+ $join_clause = str_replace('{ForeignTable}', $alias, $record['JoinClause']);
+ $join_clause = str_replace('{LocalTable}', $product_table, $join_clause);
+
+ if($record['CustomFieldId'])
+ {
+ $join_clause .= ' AND '.$alias.'.CustomFieldId='.$record['CustomFieldId'];
+ }
+ $join_clause = ' LEFT JOIN '.$foreign_table.' '.$alias.'
+ ON '.$join_clause;
+ }
+ }
+ else
+ {
+ // processing fields from local table
+ if ($record['CustomFieldId']) {
+ $local_table = 'custom_data';
+ $field_name = 'l'.$lang.'_cust_'.array_search($field_name, $custom_fields);
+ }
+
+ $field_name = $local_table.'.'.$field_name;
+ }
+
+ $condition = '';
+ switch($record['FieldType'])
+ {
+ case 'text':
+ $keywords[$field] = unhtmlentities( $keywords[$field] );
+
+ if(strlen($keywords[$field]) >= $this->Application->ConfigValue('Search_MinKeyword_Length'))
+ {
+ $highlight_keywords[] = $keywords[$field];
+ if( in_array($verbs[$field], Array('any', 'contains', 'notcontains')) )
+ {
+ $keywords[$field] = '%'.strtr($keywords[$field], Array('%' => '\\%', '_' => '\\_')).'%';
+ }
+ $condition = sprintf( $condition_patterns[$verbs[$field]],
+ $field_name,
+ $this->Conn->qstr( $keywords[$field] ));
+ }
+ break;
+ case 'boolean':
+ if($keywords[$field] != -1)
+ {
+ $property_mappings = $this->Application->getUnitOption($event->Prefix, 'ItemPropertyMappings');
+ switch($field)
+ {
+ case 'HotItem':
+ $hot_limit_var = getArrayValue($property_mappings, 'HotLimit');
+ if($hot_limit_var)
+ {
+ $sql = 'SELECT Data FROM '.TABLE_PREFIX.'Cache WHERE VarName="'.$hot_limit_var.'"';
+ $hot_limit = (int)$this->Conn->GetOne($sql);
+ $condition = 'IF('.$product_table.'.HotItem = 2,
+ IF('.$product_table.'.Hits >= '.
+ $hot_limit.
+ ', 1, 0), '.$product_table.'.HotItem) = '.$keywords[$field];
+ }
+ break;
+ case 'PopItem':
+ $votes2pop_var = getArrayValue($property_mappings, 'VotesToPop');
+ $rating2pop_var = getArrayValue($property_mappings, 'RatingToPop');
+ if($votes2pop_var && $rating2pop_var)
+ {
+ $condition = 'IF('.$product_table.'.PopItem = 2, IF('.$product_table.'.CachedVotesQty >= '.
+ $this->Application->ConfigValue($votes2pop_var).
+ ' AND '.$product_table.'.CachedRating >= '.
+ $this->Application->ConfigValue($rating2pop_var).
+ ', 1, 0), '.$product_table.'.PopItem) = '.$keywords[$field];
+ }
+ break;
+ case 'NewItem':
+ $new_days_var = getArrayValue($property_mappings, 'NewDays');
+ if($new_days_var)
+ {
+ $condition = 'IF('.$product_table.'.NewItem = 2,
+ IF('.$product_table.'.CreatedOn >= (UNIX_TIMESTAMP() - '.
+ $this->Application->ConfigValue($new_days_var).
+ '*3600*24), 1, 0), '.$product_table.'.NewItem) = '.$keywords[$field];
+ }
+ break;
+ case 'EditorsPick':
+ $condition = $product_table.'.EditorsPick = '.$keywords[$field];
+ break;
+ }
+ }
+ break;
+ case 'range':
+ $range_conditions = Array();
+ if($keywords[$field.'_from'] && !preg_match("/[^0-9]/i", $keywords[$field.'_from']))
+ {
+ $range_conditions[] = $field_name.' >= '.$keywords[$field.'_from'];
+ }
+ if($keywords[$field.'_to'] && !preg_match("/[^0-9]/i", $keywords[$field.'_to']))
+ {
+ $range_conditions[] = $field_name.' <= '.$keywords[$field.'_to'];
+ }
+ if($range_conditions)
+ {
+ $condition = implode(' AND ', $range_conditions);
+ }
+ break;
+ case 'date':
+ if($keywords[$field])
+ {
+ if( in_array($keywords[$field], Array('today', 'yesterday')) )
+ {
+ $current_time = getdate();
+ $day_begin = adodb_mktime(0, 0, 0, $current_time['mon'], $current_time['mday'], $current_time['year']);
+ $time_mapping = Array('today' => $day_begin, 'yesterday' => ($day_begin - 86400));
+ $min_time = $time_mapping[$keywords[$field]];
+ }
+ else
+ {
+ $time_mapping = Array( 'last_week' => 604800, 'last_month' => 2628000,
+ 'last_3_months' => 7884000, 'last_6_months' => 15768000,
+ 'last_year' => 31536000
+ );
+ $min_time = adodb_mktime() - $time_mapping[$keywords[$field]];
+ }
+ $condition = $field_name.' > '.$min_time;
+ }
+ break;
+ }
+
+ if($condition)
+ {
+ if($join_clause)
+ {
+ $join_clauses[] = $join_clause;
+ }
+ $relevance_parts[] = 'IF('.$condition.', '.$record['Priority'].', 0)';
+ if($glues[$field] == 1) // and
+ {
+ if($condition_mode == 'WHERE')
+ {
+ $and_conditions[] = $condition;
+ }
+ else
+ {
+ $and_having_conditions[] = $condition;
+ }
+ }
+ else // or
+ {
+ if($condition_mode == 'WHERE')
+ {
+ $or_conditions[] = $condition;
+ }
+ else
+ {
+ $or_having_conditions[] = $condition;
+ }
+ }
+
+ // create search log record
+ $search_log_data = Array('search_config' => $record, 'verb' => getArrayValue($verbs, $field), 'value' => ($record['FieldType'] == 'range') ? $search_keywords[$field.'_from'].'|'.$search_keywords[$field.'_to'] : $search_keywords[$field]);
+ $search_log[] = $this->Application->Phrase('la_Field').' "'.$this->getHuman('Field', $search_log_data).'" '.$this->getHuman('Verb', $search_log_data).' '.$this->Application->Phrase('la_Value').' '.$this->getHuman('Value', $search_log_data).' '.$this->Application->Phrase($glues[$field] == 1 ? 'lu_And' : 'lu_Or');
+ }
+ }
+
+ $search_log = implode('<br />', $search_log);
+ $search_log = preg_replace('/(.*) '.preg_quote($this->Application->Phrase('lu_and'), '/').'|'.preg_quote($this->Application->Phrase('lu_or'), '/').'$/is', '\\1', $search_log);
+ $this->saveToSearchLog($search_log, 1); // advanced search
+
+ $this->Application->StoreVar('highlight_keywords', serialize($highlight_keywords));
+
+ // making relevance clause
+ if($relevance_parts)
+ {
+ $rel_keywords = $this->Application->ConfigValue('SearchRel_Keyword_products') / 100;
+ $rel_pop = $this->Application->ConfigValue('SearchRel_Pop_products') / 100;
+ $rel_rating = $this->Application->ConfigValue('SearchRel_Rating_products') / 100;
+ $relevance_clause = '('.implode(' + ', $relevance_parts).') / '.$weight_sum.' * '.$rel_keywords;
+ $relevance_clause .= ' + (Hits + 1) / (MAX(Hits) + 1) * '.$rel_pop;
+ $relevance_clause .= ' + (CachedRating + 1) / (MAX(CachedRating) + 1) * '.$rel_rating;
+ }
+ else
+ {
+ $relevance_clause = '0';
+ }
+
+ // building having clause
+ if($or_having_conditions)
+ {
+ $and_having_conditions[] = '('.implode(' OR ', $or_having_conditions).')';
+ }
+ $having_clause = implode(' AND ', $and_having_conditions);
+ $having_clause = $having_clause ? ' HAVING '.$having_clause : '';
+
+ // building where clause
+ if($or_conditions)
+ {
+ $and_conditions[] = '('.implode(' OR ', $or_conditions).')';
+ }
+// $and_conditions[] = $product_table.'.Status = 1';
+ $where_clause = implode(' AND ', $and_conditions);
+ if(!$where_clause)
+ {
+ if($having_clause)
+ {
+ $where_clause = '1';
+ }
+ else
+ {
+ $where_clause = '0';
+ $this->Application->SetVar('adv_search_error', 1);
+ }
+ }
+ $where_clause .= ' AND '.$product_table.'.Status = 1';
+
+ // building final search query
+ $search_table = TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_'.TABLE_PREFIX.'Search';
+
+ $this->Conn->Query('DROP TABLE IF EXISTS '.$search_table);
+
+ $sql = ' CREATE TABLE '.$search_table.'
+ SELECT '.$relevance_clause.' AS Relevance,
+ '.$product_table.'.ProductId AS ItemId,
+ '.$product_table.'.ResourceId AS ResourceId,
+ 11 AS ItemType,
+ '.$product_table.'.EditorsPick AS EdPick
+ FROM '.$product_table.'
+ '.implode(' ', $join_clauses).'
+ WHERE '.$where_clause.'
+ GROUP BY '.$product_table.'.ProductId'.
+ $having_clause;
+
+ $res = $this->Conn->Query($sql);
+ }
+
+
+ function getHuman($type, $search_data)
+ {
+ $type = ucfirst(strtolower($type));
+ extract($search_data);
+
+ switch ($type) {
+ case 'Field':
+ return $this->Application->Phrase($search_config['DisplayName']);
+ break;
+
+ case 'Verb':
+ return $verb ? $this->Application->Phrase('lu_advsearch_'.$verb) : '';
+ break;
+
+ case 'Value':
+ switch ($search_config['FieldType']) {
+ case 'date':
+ $values = Array(0 => 'lu_comm_Any', 'today' => 'lu_comm_Today',
+ 'yesterday' => 'lu_comm_Yesterday', 'last_week' => 'lu_comm_LastWeek',
+ 'last_month' => 'lu_comm_LastMonth', 'last_3_months' => 'lu_comm_Last3Months',
+ 'last_6_months' => 'lu_comm_Last6Months', 'last_year' => 'lu_comm_LastYear');
+ $ret = $this->Application->Phrase($values[$value]);
+ break;
+
+ case 'range':
+ $value = explode('|', $value);
+ return $this->Application->Phrase('lu_comm_From').' "'.$value[0].'" '.$this->Application->Phrase('lu_comm_To').' "'.$value[1].'"';
+ break;
+
+ case 'boolean':
+ $values = Array(1 => 'lu_comm_Yes', 0 => 'lu_comm_No', -1 => 'lu_comm_Both');
+ $ret = $this->Application->Phrase($values[$value]);
+ break;
+
+ case 'text':
+ $ret = $value;
+ break;
+
+ }
+ return '"'.$ret.'"';
+ break;
+ }
+ }
+
+
+
+ /**
+ * Set's correct page for list
+ * based on data provided with event
+ *
+ * @param kEvent $event
+ * @access private
+ * @see OnListBuild
+ */
+ function SetPagination(&$event)
+ {
+ // get PerPage (forced -> session -> config -> 10)
+ $per_page = $this->getPerPage($event);
+
+
+ $object =& $event->getObject();
+ $object->SetPerPage($per_page);
+ $this->Application->StoreVarDefault($event->getPrefixSpecial().'_Page', 1);
+
+ $page = $this->Application->GetVar($event->getPrefixSpecial().'_Page');
+ if (!$page)
+ {
+ $page = $this->Application->GetVar($event->getPrefixSpecial(true).'_Page');
+ }
+
+ if (!$page)
+ {
+ if( $this->Application->RewriteURLs() )
+ {
+ $page = $this->Application->GetVar($event->Prefix.'_Page');
+ if (!$page)
+ {
+ $page = $this->Application->RecallVar($event->Prefix.'_Page');
+ }
+ if($page) $this->Application->StoreVar($event->getPrefixSpecial().'_Page', $page);
+ }
+ else
+ {
+ $page = $this->Application->RecallVar($event->getPrefixSpecial().'_Page');
+ }
+ }
+ else {
+ $this->Application->StoreVar($event->getPrefixSpecial().'_Page', $page);
+ }
+
+ if( !$event->getEventParam('skip_counting') )
+ {
+ $pages = $object->GetTotalPages();
+ if($page > $pages)
+ {
+ $this->Application->StoreVar($event->getPrefixSpecial().'_Page', 1);
+ $page = 1;
+ }
+ }
+
+ /*$cur_per_page = $per_page;
+ $per_page = $event->getEventParam('per_page');
+ if ($per_page == 'list_next') {
+
+ $cur_page = $page;
+
+ $object =& $this->Application->recallObject($event->Prefix);
+ $object->SetPerPage(1);
+ $cur_item_index = $object->CurrentIndex;
+
+ $page = ($cur_page-1) * $cur_per_page + $cur_item_index + 1;
+ $object->SetPerPage(1);
+ }*/
+
+ $object->SetPage($page);
+ }
+
+/* === RELATED TO IMPORT/EXPORT: BEGIN === */
+
+ /**
+ * Returns module folder
+ *
+ * @param kEvent $event
+ * @return string
+ */
+ function getModuleFolder(&$event)
+ {
+ return $this->Application->getUnitOption($event->Prefix, 'ModuleFolder');
+ }
+
+ /**
+ * Shows export dialog
+ *
+ * @param kEvent $event
+ */
+ function OnExport(&$event)
+ {
+ // use old fasion (in-portal) grid
+ $selector_name = $this->Application->getUnitOption($event->Prefix, 'CatalogSelectorName');
+ if ($selector_name) {
+ $selected_ids = $this->Application->GetVar($selector_name);
+ }
+ else {
+ $this->StoreSelectedIDs($event);
+ $selected_ids = $this->getSelectedIDs($event);
+
+ if (implode(',', $selected_ids) == '') {
+ // K4 fix when no ids found bad selected ids array is formed
+ $selected_ids = false;
+ }
+ }
+
+ $selected_cats_ids = $this->Application->GetVar('export_categories');
+
+ $this->Application->StoreVar($event->Prefix.'_export_ids', $selected_ids ? implode(',', $selected_ids) : '' );
+ $this->Application->StoreVar($event->Prefix.'_export_cats_ids', $selected_cats_ids);
+
+ $event->redirect = $this->getModuleFolder($event).'/export';
+
+ $redirect_params = Array( 'm_opener' => 'd',
+ $this->Prefix.'.export_event' => 'OnNew',
+ 'pass' => 'all,'.$this->Prefix.'.export');
+
+ $event->setRedirectParams($redirect_params);
+ }
+
+ /**
+ * Export form validation & processing
+ *
+ * @param kEvent $event
+ */
+ function OnExportBegin(&$event)
+ {
+ $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
+ if (!$items_info)
+ {
+ $items_info = unserialize( $this->Application->RecallVar($event->getPrefixSpecial().'_ItemsInfo') );
+ $this->Application->SetVar($event->getPrefixSpecial(true), $items_info);
+ }
+
+ list($item_id, $field_values) = each($items_info);
+
+ $object =& $event->getObject( Array('skip_autoload' => true) );
+ $object->SetFieldsFromHash($field_values);
+ $field_values['ImportFilename'] = $object->GetDBField('ImportFilename'); //if upload formatter has renamed the file during moving !!!
+
+ $object->setID($item_id);
+ $this->setRequiredFields($event);
+
+ $export_object =& $this->Application->recallObject('CatItemExportHelper');
+
+ // save export/import options
+ if ($event->Special == 'export')
+ {
+ $export_ids = $this->Application->RecallVar($event->Prefix.'_export_ids');
+ $export_cats_ids = $this->Application->RecallVar($event->Prefix.'_export_cats_ids');
+
+ // used for multistep export
+ $field_values['export_ids'] = $export_ids ? explode(',', $export_ids) : false;
+ $field_values['export_cats_ids'] = $export_cats_ids ? explode(',', $export_cats_ids) : Array( $this->Application->GetVar('m_cat_id') );
+ }
+
+ $field_values['ExportColumns'] = $field_values['ExportColumns'] ? explode('|', substr($field_values['ExportColumns'], 1, -1) ) : Array();
+ $field_values['start_from'] = 0;
+ $export_object->saveOptions($event, $field_values);
+
+ if( $export_object->verifyOptions($event) )
+ {
+ $event->redirect = $this->getModuleFolder($event).'/'.$event->Special.'_progress';
+
+ }
+ else
+ {
+ // make uploaded file local & change source selection
+ $filename = getArrayValue($field_values, 'ImportFilename');
+ if ($filename) {
+ $this->updateImportFiles($event);
+ $object->SetDBField('ImportSource', 2);
+ $field_values['ImportSource'] = 2;
+ $object->SetDBField('ImportLocalFilename', $filename);
+ $field_values['ImportLocalFilename'] = $filename;
+ $export_object->saveOptions($event, $field_values);
+ }
+
+ $event->status = erFAIL;
+ $event->redirect = false;
+ }
+ }
+
+ /**
+ * Enter description here...
+ *
+ * @param kEvent $event
+ */
+ function OnExportCancel(&$event)
+ {
+ $this->OnGoBack($event);
+ }
+
+ /**
+ * Sets correct available & export fields
+ *
+ * @param kEvent $event
+ */
+ function prepareExportColumns(&$event)
+ {
+ $object =& $event->getObject( Array('skip_autoload' => true) );
+
+ $available_columns = Array();
+
+ // category field (mixed)
+ $available_columns['__CATEGORY__CategoryPath'] = 'CategoryPath';
+
+ if ($event->Special == 'import') {
+ // category field (separated fields)
+ $max_level = $this->Application->ConfigValue('MaxImportCategoryLevels');
+ $i = 0;
+ while ($i < $max_level) {
+ $available_columns['__CATEGORY__Category'.($i + 1)] = 'Category'.($i + 1);
+ $i++;
+ }
+ }
+
+ // db fields
+ foreach ($object->Fields as $field_name => $field_options)
+ {
+ if (!$object->SkipField($field_name))
+ {
+ $available_columns[$field_name] = $field_name.(getArrayValue($field_options, 'required') ? '*' : '');
+ }
+ }
+
+ $available_columns = array_merge_recursive2($available_columns, $this->getCustomExportColumns($event));
+
+ // custom fields
+ foreach ($object->customFields as $custom_id => $custom_name)
+ {
+ $available_columns['__CUSTOM__'.$custom_name] = $custom_name;
+ }
+
+ // columns already in use
+ $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
+ if ($items_info)
+ {
+ list($item_id, $field_values) = each($items_info);
+ $export_keys = $field_values['ExportColumns'];
+ $export_keys = $export_keys ? explode('|', substr($export_keys, 1, -1) ) : Array();
+ }
+ else {
+ $export_keys = Array();
+ }
+
+ $export_columns = Array();
+ foreach ($export_keys as $field_key)
+ {
+ $field_name = $this->getExportField($field_key);
+ $export_columns[$field_key] = $field_name;
+ unset($available_columns[$field_key]);
+ }
+
+ $options = $object->GetFieldOptions('ExportColumns');
+ $options['options'] = $export_columns;
+ $object->SetFieldOptions('ExportColumns', $options);
+
+ $options = $object->GetFieldOptions('AvailableColumns');
+ $options['options'] = $available_columns;
+ $object->SetFieldOptions('AvailableColumns', $options);
+
+ $this->updateImportFiles($event);
+ }
+
+ /**
+ * Updates uploaded files list
+ *
+ * @param kEvent $event
+ */
+ function updateImportFiles(&$event)
+ {
+ if ($event->Special != 'import') {
+ return false;
+ }
+
+ $object =& $event->getObject();
+
+ $import_filenames = Array();
+
+ if ($folder_handle = opendir(EXPORT_PATH)) {
+ while (false !== ($file = readdir($folder_handle))) {
+ if (is_dir(EXPORT_PATH.'/'.$file) || substr($file, 0, 1) == '.' || strtolower($file) == 'cvs' || strtolower($file) == 'dummy' || filesize(EXPORT_PATH.'/'.$file) == 0) continue;
+
+ $file_size = formatSize( filesize(EXPORT_PATH.'/'.$file) );
+ $import_filenames[$file] = $file.' ('.$file_size.')';
+ }
+ closedir($folder_handle);
+ }
+
+ $options = $object->GetFieldOptions('ImportLocalFilename');
+ $options['options'] = $import_filenames;
+ $object->SetFieldOptions('ImportLocalFilename', $options);
+ }
+
+ /**
+ * Returns specific to each item type columns only
+ *
+ * @param kEvent $event
+ * @return Array
+ */
+ function getCustomExportColumns(&$event)
+ {
+ return Array( '__VIRTUAL__ThumbnailImage' => 'ThumbnailImage',
+ '__VIRTUAL__FullImage' => 'FullImage',
+ '__VIRTUAL__ImageAlt' => 'ImageAlt');
+ }
+
+ /**
+ * Sets non standart virtual fields (e.g. to other tables)
+ *
+ * @param kEvent $event
+ */
+ function setCustomExportColumns(&$event)
+ {
+ $this->restorePrimaryImage($event);
+ }
+
+ /**
+ * Create/Update primary image record in info found in imported data
+ *
+ * @param kEvent $event
+ */
+ function restorePrimaryImage(&$event)
+ {
+ $object =& $event->getObject();
+
+ $has_image_info = $object->GetDBField('ImageAlt') && ($object->GetDBField('ThumbnailImage') || $object->GetDBField('FullImage'));
+ if (!$has_image_info) {
+ return false;
+ }
+
+ $image_data = $object->getPrimaryImageData();
+
+ $image =& $this->Application->recallObject('img', null, Array('skip_autoload' => true));
+ if ($image_data) {
+ $image->Load($image_data['ImageId']);
+ }
+ else {
+ $image->Clear();
+ $image->SetDBField('Name', 'main');
+ $image->SetDBField('DefaultImg', 1);
+ $image->SetDBField('ResourceId', $object->GetDBField('ResourceId'));
+ }
+
+ $image->SetDBField('AltName', $object->GetDBField('ImageAlt'));
+
+ if ($object->GetDBField('ThumbnailImage')) {
+ $thumbnail_field = $this->isURL( $object->GetDBField('ThumbnailImage') ) ? 'ThumbUrl' : 'ThumbPath';
+ $image->SetDBField($thumbnail_field, $object->GetDBField('ThumbnailImage') );
+ $image->SetDBField('LocalThumb', $thumbnail_field == 'ThumbPath' ? 1 : 0);
+ }
+
+ if (!$object->GetDBField('FullImage')) {
+ $image->SetDBField('SameImages', 1);
+ }
+ else {
+ $image->SetDBField('SameImages', 0);
+ $full_field = $this->isURL( $object->GetDBField('FullImage') ) ? 'Url' : 'LocalPath';
+ $image->SetDBField($full_field, $object->GetDBField('FullImage') );
+ $image->SetDBField('LocalImage', $full_field == 'LocalPath' ? 1 : 0);
+ }
+
+ if ($image->isLoaded()) {
+ $image->Update();
+ }
+ else {
+ $image->Create();
+ }
+ }
+
+ function isURL($path)
+ {
+ return preg_match('#(http|https)://(.*)#', $path);
+ }
+
+// ImportLocalFilename
+
+ function getExportField($field_key)
+ {
+ $prepends = Array('__CUSTOM__', '__CATEGORY__');
+ foreach ($prepends as $prepend)
+ {
+ if (substr($field_key, 0, strlen($prepend) ) == $prepend)
+ {
+ $field_key = substr($field_key, strlen($prepend), strlen($field_key) );
+ break;
+ }
+ }
+ return $field_key;
+ }
+
+ /**
+ * Prepares item for import/export operations
+ *
+ * @param kEvent $event
+ */
+ function OnNew(&$event)
+ {
+ parent::OnNew($event);
+
+ if ($event->Special != 'import' && $event->Special != 'export') return ;
+ $this->setRequiredFields($event);
+ $this->Application->StoreVar('ImportCategory', 0);
+ }
+
+ /**
+ * set required fields based on import or export params
+ *
+ * @param kEvent $event
+ */
+ function setRequiredFields(&$event)
+ {
+ $required_fields['common'] = Array('FieldsSeparatedBy', 'LineEndings', 'CategoryFormat');
+
+ $required_fields['export'] = Array('ExportFormat', 'ExportFilename','ExportColumns');
+ $required_fields['import'] = Array('FieldTitles', 'ImportSource', 'CheckDuplicatesMethod'); // ImportFilename, ImportLocalFilename
+
+ $object =& $event->getObject();
+ if ($event->Special == 'import')
+ {
+ $import_source = Array(1 => 'ImportFilename', 2 => 'ImportLocalFilename');
+ $used_field = $import_source[ $object->GetDBField('ImportSource') ];
+
+ $required_fields[$event->Special][] = $used_field;
+ $object->Fields[$used_field]['error_field'] = 'ImportSource';
+
+ if ($object->GetDBField('FieldTitles') == 2) $required_fields[$event->Special][] = 'ExportColumns'; // manual field titles
+ }
+
+ $required_fields = array_merge($required_fields['common'], $required_fields[$event->Special]);
+ foreach ($required_fields as $required_field) {
+ $object->setRequired($required_field, true);
+ }
+ }
+
+ /**
+ * Process items selected in item_selector
+ *
+ * @param kEvent $event
+ */
+ function OnProcessSelected(&$event)
+ {
+ $selected_ids = $this->Application->GetVar('selected_ids');
+
+ $dst_field = $this->Application->RecallVar('dst_field');
+
+ if ($dst_field == 'ItemCategory') {
+ // Item Edit -> Categories Tab -> New Categories
+ $object =& $event->getObject();
+ $category_ids = explode(',', $selected_ids['c']);
+ foreach ($category_ids as $category_id) {
+ $object->assignToCategory($category_id);
+ }
+ }
+
+ if ($dst_field == 'ImportCategory') {
+ // Tools -> Import -> Item Import -> Select Import Category
+ $this->Application->StoreVar('ImportCategory', $selected_ids['c']);
+ $this->Application->StoreVar($event->getPrefixSpecial().'_ForceNotValid', 1); // not to loose import/export values on form refresh
+
+ $this->Application->SetVar($event->getPrefixSpecial().'_id', 0);
+ $this->Application->SetVar($event->getPrefixSpecial().'_event', 'OnExportBegin');
+
+ $passed = $this->Application->GetVar('passed');
+ $this->Application->SetVar('passed', $passed.','.$event->getPrefixSpecial());
+ $event->setEventParam('pass_events', true);
+ }
+
+ $this->finalizePopup($event);
+ }
+
+ /**
+ * Saves Import/Export settings to session
+ *
+ * @param kEvent $event
+ */
+ function OnSaveSettings(&$event)
+ {
+ $event->redirect = false;
+ $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
+ if ($items_info) {
+ list($id, $field_values) = each($items_info);
+
+ $object =& $event->getObject( Array('skip_autoload' => true) );
+ $object->SetFieldsFromHash($field_values);
+ $field_values['ImportFilename'] = $object->GetDBField('ImportFilename'); //if upload formatter has renamed the file during moving !!!
+ $field_values['ImportSource'] = 2;
+ $field_values['ImportLocalFilename'] = $object->GetDBField('ImportFilename');
+ $items_info[$id] = $field_values;
+
+ $this->Application->StoreVar($event->getPrefixSpecial().'_ItemsInfo', serialize($items_info));
+ }
+ }
+
+ function OnCancelAction(&$event)
+ {
+ $event->redirect_params = Array('pass' => 'all,'.$event->GetPrefixSpecial());
+ $event->redirect = $this->Application->GetVar('cancel_template');
+ }
+
+/* === RELATED TO IMPORT/EXPORT: END === */
+
+ /**
+ * Stores item's owner login into separate field together with id
+ *
+ * @param kEvent $event
+ * @param string $id_field
+ * @param string $cached_field
+ */
+ function cacheItemOwner(&$event, $id_field, $cached_field)
+ {
+ $object =& $event->getObject();
+
+ $user_id = $object->GetDBField($id_field);
+ $options = $object->GetFieldOptions($id_field);
+ if (isset($options['options'][$user_id])) {
+ $object->SetDBField($cached_field, $options['options'][$user_id]);
+ }
+ else {
+ $id_field = $this->Application->getUnitOption('u', 'IDField');
+ $table_name = $this->Application->getUnitOption('u', 'TableName');
+
+ $sql = 'SELECT Login
+ FROM '.$table_name.'
+ WHERE '.$id_field.' = '.$user_id;
+ $object->SetDBField($cached_field, $this->Conn->GetOne($sql));
+ }
+ }
+
+ /**
+ * Saves item beeing edited into temp table
+ *
+ * @param kEvent $event
+ */
+ function OnPreSave(&$event)
+ {
+ parent::OnPreSave($event);
+ $use_pending_editing = $this->Application->getUnitOption($event->Prefix, 'UsePendingEditing');
+ if ($event->status == erSUCCESS && $use_pending_editing) {
+ // decision: clone or not clone
+
+ $object =& $event->getObject();
+ if ($object->GetID() == 0 || $object->GetDBField('OrgId') > 0) {
+ // new items or cloned items shouldn't be cloned again
+ return true;
+ }
+ $perm_helper =& $this->Application->recallObject('PermissionsHelper');
+ if ($perm_helper->ModifyCheckPermission($object->GetDBField('CreatedById'), $object->GetDBField('CategoryId'), $event->Prefix) == 2) {
+
+ // 1. clone original item
+ $temp_handler =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
+ $cloned_ids = $temp_handler->CloneItems($event->Prefix, $event->Special, Array($object->GetID()), null, null, null, true);
+ $ci_table = $this->Application->GetTempName(TABLE_PREFIX.'CategoryItems');
+
+ // 2. delete record from CategoryItems (about cloned item) that was automatically created during call of Create method of kCatDBItem
+ $sql = 'SELECT ResourceId
+ FROM '.$object->TableName.'
+ WHERE '.$object->IDField.' = '.$cloned_ids[0];
+ $clone_resource_id = $this->Conn->GetOne($sql);
+
+ $sql = 'DELETE FROM '.$ci_table.'
+ WHERE ItemResourceId = '.$clone_resource_id.' AND PrimaryCat = 1';
+ $this->Conn->Query($sql);
+
+ // 3. copy main item categoryitems to cloned item
+ $sql = ' INSERT INTO '.$ci_table.' (CategoryId, ItemResourceId, PrimaryCat, ItemPrefix, Filename)
+ SELECT CategoryId, '.$clone_resource_id.' AS ItemResourceId, PrimaryCat, ItemPrefix, Filename
+ FROM '.$ci_table.'
+ WHERE ItemResourceId = '.$object->GetDBField('ResourceId');
+ $this->Conn->Query($sql);
+
+ // 4. put cloned id to OrgId field of item being cloned
+ $sql = 'UPDATE '.$object->TableName.'
+ SET OrgId = '.$object->GetID().'
+ WHERE '.$object->IDField.' = '.$cloned_ids[0];
+ $this->Conn->Query($sql);
+
+ // 5. substitute id of item being cloned with clone id
+ $this->Application->SetVar($event->getPrefixSpecial().'_id', $cloned_ids[0]);
+ $selected_ids = explode(',', $this->Application->RecallVar($event->getPrefixSpecial().'_selected_ids'));
+ $selected_ids[ array_search($object->GetID(), $selected_ids) ] = $cloned_ids[0];
+ $this->Application->StoreVar($event->getPrefixSpecial().'_selected_ids', implode(',', $selected_ids));
+
+ // 6. delete original item from temp table
+ $temp_handler->DeleteItems($event->Prefix, $event->Special, Array($object->GetID()));
+ }
+ }
+ }
+
+ /**
+ * Sets default expiration based on module setting
+ *
+ * @param kEvent $event
+ */
+ function OnPreCreate(&$event)
+ {
+ parent::OnPreCreate($event);
+
+ if ($event->status == erSUCCESS) {
+ $object =& $event->getObject();
+ $object->SetDBField('CreatedById', $this->Application->GetVar('u_id'));
+ }
+ }
+
+ /**
+ * Occures before original item of item in pending editing got deleted (for hooking only)
+ *
+ * @param kEvent $event
+ */
+ function OnBeforeDeleteOriginal(&$event)
+ {
+
+ }
+
+ /**
+ * Apply same processing to each item beeing selected in grid
+ *
+ * @param kEvent $event
+ * @access private
+ */
+ function iterateItems(&$event)
+ {
+ if ($event->Name != 'OnMassApprove' && $event->Name != 'OnMassDecline') {
+ return parent::iterateItems($event);
+ }
+
+ if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
+ return;
+ }
+
+ $object =& $event->getObject( Array('skip_autoload' => true) );
+ $ids = $this->StoreSelectedIDs($event);
+
+ if ($ids) {
+ foreach ($ids as $id) {
+ $object->Load($id);
+
+ switch ($event->Name) {
+ case 'OnMassApprove':
+ $ret = $object->ApproveChanges();
+ break;
+
+ case 'OnMassDecline':
+ $ret = $object->DeclineChanges();
+ break;
+ }
+
+ if (!$ret) {
+ $event->status = erFAIL;
+ $event->redirect = false;
+ break;
+ }
+ }
+ }
+ }
+
+}
+
+?>
\ No newline at end of file
Property changes on: branches/unlabeled/unlabeled-1.65.2/core/units/general/cat_event_handler.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.65
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property

Event Timeline