Index: admin_templates/scheduled_tasks/scheduled_task_edit.tpl =================================================================== --- admin_templates/scheduled_tasks/scheduled_task_edit.tpl (revision 15504) +++ admin_templates/scheduled_tasks/scheduled_task_edit.tpl (working copy) @@ -83,6 +83,7 @@ + Index: install/english.lang =================================================================== --- install/english.lang (revision 15504) +++ install/english.lang (working copy) @@ -627,6 +627,7 @@ U2VudA== U2VydmVy U2Vzc2lvbiBMb2cgSUQ= + U2V0dGluZ3M= U2hvcnQgRGF0ZSBGb3JtYXQ= U2hvcnQgSVNPIENvZGU= U2hvcnQgVGltZSBGb3JtYXQ= Index: install/install_schema.sql =================================================================== --- install/install_schema.sql (revision 15504) +++ install/install_schema.sql (working copy) @@ -350,6 +350,7 @@ StylesheetId int(10) unsigned NOT NULL DEFAULT '0', LanguagePackInstalled tinyint(3) unsigned NOT NULL DEFAULT '0', TemplateAliases text, + ImageResizeRules text, PRIMARY KEY (ThemeId), KEY Enabled (Enabled), KEY StylesheetId (StylesheetId), @@ -729,6 +730,7 @@ Timeout int(10) unsigned DEFAULT NULL, LastTimeoutOn int(10) unsigned DEFAULT NULL, SiteDomainLimitation varchar(255) NOT NULL DEFAULT '', + Settings text, PRIMARY KEY (ScheduledTaskId), KEY `Status` (`Status`), KEY LastRunOn (LastRunOn), Index: install/upgrades.sql =================================================================== --- install/upgrades.sql (revision 15504) +++ install/upgrades.sql (working copy) @@ -2798,3 +2798,7 @@ INSERT INTO Permissions VALUES(DEFAULT, 'in-portal:configure_advanced.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES(DEFAULT, 'in-portal:configure_categories.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES(DEFAULT, 'in-portal:configure_users.add', 11, 1, 1, 0); + +# ===== v 5.3.0-B1 ===== +ALTER TABLE ScheduledTasks ADD Settings TEXT NULL; +ALTER TABLE Themes ADD ImageResizeRules TEXT NULL; Index: kernel/managers/scheduled_task_manager.php =================================================================== --- kernel/managers/scheduled_task_manager.php (revision 15504) +++ kernel/managers/scheduled_task_manager.php (working copy) @@ -112,7 +112,7 @@ ignore_user_abort(true); set_time_limit(0); - + $events_source = $this->getAll(); $user_id = $this->Application->RecallVar('user_id'); @@ -135,7 +135,7 @@ // remember LastTimeoutOn only for events that are still running and will be reset if ( $event_data['LastRunStatus'] == ScheduledTask::LAST_RUN_RUNNING ) { - $this->update($short_name, Array ('LastTimeoutOn' => adodb_mktime())); + $this->update($event_data, Array ('LastTimeoutOn' => adodb_mktime())); } $next_run = (int)$event_data['NextRunOn']; @@ -144,7 +144,6 @@ continue; } - $event_data['Name'] = $short_name; $this->run($event_data); } @@ -179,9 +178,15 @@ 'NextRunOn' => $cron_helper->getMatch($scheduled_task_data['RunSchedule'], $start_time), ); - $this->update($scheduled_task_data['Name'], $fields_hash); + $this->update($scheduled_task_data, $fields_hash); + $scheduled_task = $this->Application->recallObject('scheduled-task', null, Array ('skip_autoload' => true)); + /* @var $scheduled_task kDBItem */ + + $scheduled_task->LoadFromHash($scheduled_task_data); + $event->redirect = false; + $event->MasterEvent = new kEvent('scheduled-task:OnRun'); $this->Application->HandleEvent($event); $now = adodb_mktime(); @@ -199,7 +204,7 @@ 'LastRunStatus' => $event->status == kEvent::erSUCCESS ? ScheduledTask::LAST_RUN_SUCCEEDED : ScheduledTask::LAST_RUN_FAILED, ); - $this->update($scheduled_task_data['Name'], $fields_hash); + $this->update($scheduled_task_data, $fields_hash); return true; } @@ -207,17 +212,19 @@ /** * Updates scheduled task record with latest changes about it's invocation progress * - * @param string $scheduled_task_name + * @param Array $scheduled_task_data * @param Array $fields_hash * @return void * @access protected */ - protected function update($scheduled_task_name, $fields_hash) + protected function update(&$scheduled_task_data, $fields_hash) { $this->Conn->doUpdate( $fields_hash, $this->Application->getUnitOption('scheduled-task', 'TableName'), - 'Name = ' . $this->Conn->qstr($scheduled_task_name) + 'Name = ' . $this->Conn->qstr($scheduled_task_data['Name']) ); + + $scheduled_task_data = array_merge($scheduled_task_data, $fields_hash); } } \ No newline at end of file Index: units/admin/admin_config.php =================================================================== --- units/admin/admin_config.php (revision 15504) +++ units/admin/admin_config.php (working copy) @@ -26,6 +26,7 @@ 'ScheduledTasks' => Array( 'optimize_performance' => Array('EventName' => 'OnOptimizePerformance', 'RunSchedule' => '0 0 * * *'), + 'pre_resize_images' => Array('EventName' => 'OnPreResizeImages', 'RunSchedule' => '0 * * * *'), ), 'TitlePresets' => Array ( Index: units/admin/admin_events_handler.php =================================================================== --- units/admin/admin_events_handler.php (revision 15504) +++ units/admin/admin_events_handler.php (working copy) @@ -1131,9 +1131,164 @@ $this->Conn->Query('OPTIMIZE TABLE ' . $table_name); } } + + /** + * [SCHEDULED TASK] Pre-resizes images, used in templates + * + * @param kEvent $event + * @return void + * @access protected + */ + protected function OnPreResizeImages(kEvent $event) + { + $scheduled_task = $event->MasterEvent->getObject(); + /* @var $scheduled_task kDBItem */ + + $mass_resizer = new MassImageResizer(); + + // rules from scheduled task itself + $mass_resizer->addRules($scheduled_task->GetDBField('Settings')); + + // rules from all enabled themes + $sql = 'SELECT ImageResizeRules + FROM ' . $this->Application->getUnitOption('theme', 'TableName') . ' + WHERE Enabled = 1'; + $mass_resizer->addRules($this->Conn->GetCol($sql)); + + $mass_resizer->run(); + } } +/** + * Resizes multiple images according to given rules + */ +class MassImageResizer extends kBase { + /** + * Rules, that tell how images must be resized + * + * @var Array + * @access private + */ + private $_rules = Array (); + + /** + * Remembers, which fields of which unit are used + * + * @var Array + * @access private + */ + private $_unitFields = Array (); + + /** + * Remembers which fields of which units require which format + * + * @var Array + * @access private + */ + private $_unitFieldFormats = Array (); + + /** + * Adds more resize rules + * + * @param string|Array $rules + * @return void + * @access public + */ + public function addRules($rules) + { + $rules = (array)$rules; + + foreach ($rules as $rule) { + $rule = $this->_cleanup($rule); + + if ( $rule ) { + $this->_rules = array_merge($this->_rules, $rule); + } + } + } + + /** + * Normalizes given set of rules + * + * @param string $rules + * @return Array + * @access private + */ + private function _cleanup($rules) + { + $ret = explode("\n", str_replace(Array ("\r\n", "\r"), "\n", $rules)); + + return array_filter(array_map('trim', $ret)); + } + + /** + * Transforms rules given in raw format into 3D array of easily manageable rules + * + * @return void + * @access private + */ + private function _preProcessRules() + { + foreach ($this->_rules as $raw_rule) { + list ($prefix, $field, $format) = explode(':', $raw_rule, 3); + + if ( !isset($this->_unitFields[$prefix]) ) { + $this->_unitFields[$prefix] = Array (); + $this->_unitFieldFormats[$prefix] = Array (); + } + + $this->_unitFields[$prefix][] = $field; + + if ( !isset($this->_unitFieldFormats[$prefix][$field]) ) { + $this->_unitFieldFormats[$prefix][$field] = Array (); + } + + $this->_unitFieldFormats[$prefix][$field][] = $format; + } + } + + /** + * Performs resize operation + * + * @return void + * @access public + */ + public function run() + { + $this->_preProcessRules(); + + foreach ($this->_unitFields as $prefix => $fields) { + $sql = 'SELECT ' . implode(',', array_unique($fields)) . ' + FROM ' . $this->Application->getUnitOption($prefix, 'TableName'); + $unit_data = $this->Conn->GetIterator($sql); + + if ( !count($unit_data) ) { + continue; + } + + $object = $this->Application->recallObject($prefix . '.resize', null, Array ('skip_autoload' => true)); + /* @var $object kDBItem */ + + foreach ($unit_data as $field_values) { + foreach ($field_values as $field => $value) { + if ( !$value ) { + continue; + } + + $object->SetDBField($field, $value); + + foreach ($this->_unitFieldFormats[$prefix][$field] as $format) { + // will trigger image resize if needed + $object->GetField($field, $format); + } + } + } + } + } +} + + class UnitConfigDecorator { var $parentPath = Array (); Index: units/helpers/image_helper.php =================================================================== --- units/helpers/image_helper.php (revision 15504) +++ units/helpers/image_helper.php (working copy) @@ -114,6 +114,7 @@ if ($needs_resize || array_intersect(array_keys($params), $transform_keys)) { // resize required OR watermarking required -> change resulting image name ! + ksort($params); $src_path_escaped = preg_replace('/(\\\[\d]+)/', '\\\\\1', $src_path); // escape replacement patterns, like "\" $dst_image = preg_replace('/^'.preg_quote($src_path, '/').'(.*)\.(.*)$/', $src_path_escaped . DIRECTORY_SEPARATOR . 'resized\\1_' . crc32(serialize($params)) . '.\\2', $src_image); Index: units/helpers/themes_helper.php =================================================================== --- units/helpers/themes_helper.php (revision 15504) +++ units/helpers/themes_helper.php (working copy) @@ -134,16 +134,27 @@ $this->Conn->doUpdate($fields_hash, $table_name, $id_field . ' = ' . $theme_id); } - $fields_hash = Array ( - 'TemplateAliases' => serialize( $this->getTemplateAliases($theme_id, $theme_path) ), - ); + $this->_saveThemeSettings($theme_id, $theme_path); - $this->Conn->doUpdate($fields_hash, $table_name, $id_field . ' = ' . $theme_id); - return $theme_id; } /** + * Saves information from "/_install/theme.xml" files in theme + * + * @param int $theme_id + * @param string $theme_path + * @return void + * @access protected + */ + protected function _saveThemeSettings($theme_id, $theme_path) + { + $id_field = $this->Application->getUnitOption('theme', 'IDField'); + $table_name = $this->Application->getUnitOption('theme', 'TableName'); + $this->Conn->doUpdate($this->_getThemeSettings($theme_id, $theme_path), $table_name, $id_field . ' = ' . $theme_id); + } + + /** * Installs module(-s) language pack for given theme * * @param string $theme_path @@ -176,16 +187,17 @@ } /** - * Returns template aliases from "/_install/theme.xml" files in theme + * Parses information, discovered from "/_install/theme.xml" files in theme * * @param int $theme_id * @param string $theme_path * @return Array * @access protected */ - protected function getTemplateAliases($theme_id, $theme_path) + protected function _getThemeSettings($theme_id, $theme_path) { - $template_aliases = Array (); + $setting_mapping = Array ('image_resize_rules' => 'ImageResizeRules'); + $ret = Array ('TemplateAliases' => Array (), 'ImageResizeRules' => Array ()); foreach ($this->Application->ModuleInfo as $module_name => $module_info) { $xml_file = $theme_path . '/' . $module_info['TemplatePath'] . '_install/theme.xml'; @@ -201,12 +213,20 @@ continue; } - foreach ($theme as $design) { - /* @var $design SimpleXMLElement */ + foreach ($theme as $setting) { + /* @var $setting SimpleXMLElement */ - $template_path = trim($design); - $module_override = (string)$design['module']; + $setting_name = $setting->getName(); + $setting_value = trim($setting); + if ( isset($setting_mapping[$setting_name]) ) { + $ret[$setting_mapping[$setting_name]][] = $setting_value; + continue; + } + + // this is template alias + $module_override = (string)$setting['module']; + if ( $module_override ) { // allow to put template mappings form all modules into single theme.xml file $module_folder = $this->Application->findModule('Name', $module_override, 'TemplatePath'); @@ -217,19 +237,22 @@ } // only store alias, when template exists on disk - if ( $this->getTemplateId($template_path, $theme_id) ) { - $alias = '#' . $module_folder . strtolower($design->getName()) . '#'; + if ( $this->getTemplateId($setting_value, $theme_id) ) { + $alias = '#' . $module_folder . strtolower($setting->getName()) . '#'; // remember alias in global theme mapping - $template_aliases[$alias] = $template_path; + $ret['TemplateAliases'][$alias] = $setting_value; // store alias in theme file record to use later in design dropdown - $this->updateTemplate($template_path, $theme_id, Array ('TemplateAlias' => $alias)); + $this->updateTemplate($setting_value, $theme_id, Array ('TemplateAlias' => $alias)); } } } - return $template_aliases; + $ret['TemplateAliases'] = serialize($ret['TemplateAliases']); + $ret['ImageResizeRules'] = implode("\n", array_filter($ret['ImageResizeRules'])); + + return $ret; } /** @@ -307,11 +330,7 @@ $this->installThemeLanguagePack($theme_path, $module_name); // update TemplateAliases mapping - $fields_hash = Array ( - 'TemplateAliases' => serialize( $this->getTemplateAliases($theme_id, $theme_path) ), - ); - - $this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'Themes', 'ThemeId = ' . $theme_id); + $this->_saveThemeSettings($theme_id, $theme_path); } } Index: units/scheduled_tasks/scheduled_task_eh.php =================================================================== --- units/scheduled_tasks/scheduled_task_eh.php (revision 15504) +++ units/scheduled_tasks/scheduled_task_eh.php (working copy) @@ -200,7 +200,6 @@ $scheduled_tasks = $this->Conn->Query($sql); foreach ($scheduled_tasks as $scheduled_task_data) { - $scheduled_task_data['EventName'] = $scheduled_task_data['Event']; $this->Application->EventManager->runScheduledTask($scheduled_task_data); } } Index: units/scheduled_tasks/scheduled_tasks_config.php =================================================================== --- units/scheduled_tasks/scheduled_tasks_config.php (revision 15504) +++ units/scheduled_tasks/scheduled_tasks_config.php (working copy) @@ -139,6 +139,7 @@ 'formatter' => 'kOptionsFormatter', 'options_sql' => 'SELECT %s FROM ' . TABLE_PREFIX . 'SiteDomains ORDER BY DomainName ASC', 'option_key_field' => 'DomainId', 'option_title_field' => 'DomainName', 'multiple' => 1, 'not_null' => 1, 'default' => '' ), + 'Settings' => Array ('type' => 'string', 'default' => NULL), ), 'Grids' => Array ( Index: units/themes/themes_config.php =================================================================== --- units/themes/themes_config.php (revision 15504) +++ units/themes/themes_config.php (working copy) @@ -129,6 +129,7 @@ 'not_null' => 1, 'default' => 0 ), 'TemplateAliases' => Array ('type' => 'string', 'formatter' => 'kSerializedFormatter', 'default' => 'a:0:{}'), + 'ImageResizeRules' => Array ('type' => 'string', 'default' => NULL), ), 'Grids' => Array(