From dfb6f1274f05a2a7ce6ec5003ccd7bfa92f2fec4 Mon Sep 17 00:00:00 2001 From: Peter Rotich <peter@osticket.com> Date: Fri, 30 Jan 2015 05:04:26 +0000 Subject: [PATCH] cdata: Make DynamicDataView generic This is necessary to allow objects to register data views on the fly. --- bootstrap.php | 4 +- include/class.dynamic_forms.php | 107 ++++++++++++++++++++++++++++---- 2 files changed, 98 insertions(+), 13 deletions(-) diff --git a/bootstrap.php b/bootstrap.php index 47f617b62..cae6611cd 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -94,8 +94,10 @@ class Bootstrap { define('THREAD_ENTRY_TABLE', $prefix.'thread_entry'); define('THREAD_ENTRY_EMAIL_TABLE', $prefix.'thread_entry_email'); - define('TICKET_TABLE',$prefix.'ticket'); define('LOCK_TABLE',$prefix.'lock'); + + define('TICKET_TABLE',$prefix.'ticket'); + define('TICKET_CDATA_TABLE', $prefix.'ticket__cdata'); define('TICKET_EVENT_TABLE',$prefix.'ticket_event'); define('THREAD_COLLABORATOR_TABLE', $prefix.'thread_collaborator'); define('TICKET_STATUS_TABLE', $prefix.'ticket_status'); diff --git a/include/class.dynamic_forms.php b/include/class.dynamic_forms.php index e569f8379..fd4d11e93 100644 --- a/include/class.dynamic_forms.php +++ b/include/class.dynamic_forms.php @@ -254,6 +254,87 @@ class DynamicForm extends VerySimpleModel { return true; } + static function ensureDynamicDataView() { + + if (!($cdata=static::$cdata) || !$cdata['table']) + return false; + + $sql = 'SHOW TABLES LIKE \''.$cdata['table'].'\''; + if (!db_num_rows(db_query($sql))) + return static::buildDynamicDataView($cdata); + } + + static function buildDynamicDataView($cdata) { + $sql = 'CREATE TABLE `'.$cdata['table'].'` (PRIMARY KEY + ('.$cdata['object_id'].')) AS ' + . static::getCrossTabQuery( $cdata['object_type'], $cdata['object_id']); + db_query($sql); + } + + static function dropDynamicDataView($table) { + db_query('DROP TABLE IF EXISTS `'.$table.'`'); + } + + static function updateDynamicDataView($answer, $data) { + // TODO: Detect $data['dirty'] for value and value_id + // We're chiefly concerned with Ticket form answers + + $cdata = static::$cdata; + if (!$cdata + || !$cdata['table'] + || !($e = $answer->getEntry()) + || $e->getForm()->get('type') != $cdata['object_type']) + return; + + // $record = array(); + // $record[$f] = $answer->value' + // TicketFormData::objects()->filter(array('ticket_id'=>$a)) + // ->merge($record); + $sql = 'SHOW TABLES LIKE \''.$cdata['table'].'\''; + if (!db_num_rows(db_query($sql))) + return; + + $f = $answer->getField(); + $name = $f->get('name') ? $f->get('name') + : 'field_'.$f->get('id'); + $fields = sprintf('`%s`=', $name) . db_input( + implode(',', $answer->getSearchKeys())); + $sql = 'INSERT INTO `'.$cdata['table'].'` SET '.$fields + . sprintf(', `%s`= %s', + $cdata['object_id'], + db_input($answer->getEntry()->get('object_id'))) + .' ON DUPLICATE KEY UPDATE '.$fields; + if (!db_query($sql) || !db_affected_rows()) + return self::dropDynamicDataView($cdata['table']); + } + + static function updateDynamicFormEntryAnswer($answer, $data) { + if (!$answer + || !($e = $answer->getEntry()) + || !$e->getForm()) + return; + + switch ($e->getForm()->get('type')) { + case 'T': + return TicketForm::updateDynamicDataView($answer, $data); + case 'A': + return TaskForm::updateDynamicDataView($answer, $data); + } + + } + + static function updateDynamicFormField($field, $data) { + if (!$field || !$field->getForm()) + return; + + switch ($field->getForm()->get('type')) { + case 'T': + return TicketForm::dropDynamicDataView(TicketForm::$cdata['table']); + case 'A': + return TaskForm::dropDynamicDataView(TicketForm::$cdata['table']); + } + + } static function getCrossTabQuery($object_type, $object_id='object_id', $exclude=array()) { $fields = static::getDynamicDataViewFields($exclude); @@ -264,8 +345,7 @@ class DynamicForm extends VerySimpleModel { WHERE entry.object_type='$object_type' GROUP BY entry.object_id"; } - // Materialized View for Ticket custom data (MySQL FlexViews would be - // nice) + // Materialized View for custom data (MySQL FlexViews would be nice) // // @see http://code.google.com/p/flexviews/ static function getDynamicDataViewFields($exclude) { @@ -347,6 +427,12 @@ Filter::addSupportedMatches(/* @trans */ 'User Data', function() { class TicketForm extends DynamicForm { static $instance; + static $cdata = array( + 'table' => TICKET_CDATA_TABLE, + 'object_id' => 'ticket_id', + 'object_type' => 'T', + ); + static function objects() { $os = parent::objects(); return $os->filter(array('type'=>'T')); @@ -435,27 +521,24 @@ Filter::addSupportedMatches(/* @trans */ 'Ticket Data', function() { }, 30); // Manage materialized view on custom data updates Signal::connect('model.created', - array('TicketForm', 'updateDynamicDataView'), + array('DynamicForm', 'updateDynamicFormEntryAnswer'), 'DynamicFormEntryAnswer'); Signal::connect('model.updated', - array('TicketForm', 'updateDynamicDataView'), + array('DynamicForm', 'updateDynamicFormEntryAnswer'), 'DynamicFormEntryAnswer'); // Recreate the dynamic view after new or removed fields to the ticket // details form Signal::connect('model.created', - array('TicketForm', 'dropDynamicDataView'), - 'DynamicFormField', - function($o) { return $o->form->type == 'T'; }); + array('DynamicForm', 'updateDynamicFormField'), + 'DynamicFormField'); Signal::connect('model.deleted', - array('TicketForm', 'dropDynamicDataView'), - 'DynamicFormField', - function($o) { return $o->form->type == 'T'; }); + array('DynamicForm', 'updateDynamicFormField'), + 'DynamicFormField'); // If the `name` column is in the dirty list, we would be renaming a // column. Delete the view instead. Signal::connect('model.updated', - array('TicketForm', 'dropDynamicDataView'), + array('DynamicForm', 'updateDynamicFormField'), 'DynamicFormField', - // TODO: Lookup the dynamic form to verify {type == 'T'} function($o, $d) { return isset($d['dirty']) && (isset($d['dirty']['name']) || isset($d['dirty']['type'])); }); -- GitLab