diff --git a/include/ajax.search.php b/include/ajax.search.php index 684a2e5a43debb86b0f6a50b7d6c182d1b1a7b91..ffb5f9dd4815fef5c6862a7f72d4edc1d0d97914 100644 --- a/include/ajax.search.php +++ b/include/ajax.search.php @@ -56,6 +56,7 @@ class SearchAjaxAPI extends AjaxController { case ':ticket': case ':user': case ':organization': + case ':field': // Support nested field ids for list properties and such if (strpos($id, '.') !== false) list(,$id) = explode('!', $id, 2); @@ -67,7 +68,12 @@ class SearchAjaxAPI extends AjaxController { } self::ensureConsistentFormFieldIds($_GET['ff_uid']); - $fields = SavedSearch::getSearchField($field->getImpl(), $name); + + $impl = $field->getImpl(); + $impl->set('label', sprintf('%s / %s', + $field->form->getLocal('title'), $field->getLocal('label') + )); + $fields = SavedSearch::getSearchField($impl, $name); $form = new Form($fields); // Check the box to search the field by default if ($F = $form->getField("{$name}+search")) @@ -80,6 +86,8 @@ class SearchAjaxAPI extends AjaxController { return $this->encode(array( 'success' => true, 'html' => $html, + // Send the current formfield UID to be resent with the next + // addField request and set above 'ff_uid' => FormField::$uid, )); } @@ -161,6 +169,15 @@ class SearchAjaxAPI extends AjaxController { */ } } + $fields = &$matches[__('Custom Forms')]; + foreach (DynamicForm::objects()->filter(array('type'=>'G')) as $form) { + foreach ($form->getFields() as $f) { + if (!$f->hasData() || $f->isPresentationOnly()) + continue; + $key = sprintf(':field!%d', $f->get('id'), $f->get('id')); + $fields[$key] = $form->getLocal('title').' / '.$f->getLocal('label'); + } + } return $matches; } diff --git a/include/class.dynamic_forms.php b/include/class.dynamic_forms.php index ebe6c6bb01138f642f03c3ac06e9350ec6935f5d..1ff552bd0d80edd5d56242312e1cc8ff4dab00e2 100644 --- a/include/class.dynamic_forms.php +++ b/include/class.dynamic_forms.php @@ -412,6 +412,7 @@ class DynamicFormField extends VerySimpleModel { 'table' => FORM_FIELD_TABLE, 'ordering' => array('sort'), 'pk' => array('id'), + 'select_related' => array('form'), 'joins' => array( 'form' => array( 'null' => true, diff --git a/include/class.orm.php b/include/class.orm.php index 8d32361b8d43272f3cb78d4ef5697ea2106807e4..627338c4c1f48cc21036f1227bd26e709210a670 100644 --- a/include/class.orm.php +++ b/include/class.orm.php @@ -62,35 +62,39 @@ class ModelMeta implements ArrayAccess { if (!isset($meta['joins'])) $meta['joins'] = array(); foreach ($meta['joins'] as $field => &$j) { - if (isset($j['reverse'])) { - list($fmodel, $key) = explode('.', $j['reverse']); - $info = $fmodel::$meta['joins'][$key]; - $constraint = array(); - if (!is_array($info['constraint'])) - throw new OrmConfigurationException(sprintf(__( - // `reverse` here is the reverse of an ORM relationship - '%s: Reverse does not specify any constraints'), - $j['reverse'])); - foreach ($info['constraint'] as $foreign => $local) { - list(,$field) = explode('.', $local); - $constraint[$field] = "$fmodel.$foreign"; - } - $j['constraint'] = $constraint; - if (!isset($j['list'])) - $j['list'] = true; - if (!isset($j['null'])) - $j['null'] = $info['null'] ?: false; - } - // XXX: Make this better (ie. composite keys) - $keys = array_keys($j['constraint']); - $foreign = $j['constraint'][$keys[0]]; - $j['fkey'] = explode('.', $foreign); - $j['local'] = $keys[0]; + $this->processJoin($j); } unset($j); $this->base = $meta; } + function processJoin(&$j) { + if (isset($j['reverse'])) { + list($fmodel, $key) = explode('.', $j['reverse']); + $info = $fmodel::$meta['joins'][$key]; + $constraint = array(); + if (!is_array($info['constraint'])) + throw new OrmConfigurationException(sprintf(__( + // `reverse` here is the reverse of an ORM relationship + '%s: Reverse does not specify any constraints'), + $j['reverse'])); + foreach ($info['constraint'] as $foreign => $local) { + list(,$field) = explode('.', $local); + $constraint[$field] = "$fmodel.$foreign"; + } + $j['constraint'] = $constraint; + if (!isset($j['list'])) + $j['list'] = true; + if (!isset($j['null'])) + $j['null'] = $info['null'] ?: false; + } + // XXX: Make this better (ie. composite keys) + $keys = array_keys($j['constraint']); + $foreign = $j['constraint'][$keys[0]]; + $j['fkey'] = explode('.', $foreign); + $j['local'] = $keys[0]; + } + function offsetGet($field) { if (!isset($this->base[$field])) $this->setupLazy($field); diff --git a/include/class.search.php b/include/class.search.php index b43798495d2847ae270737fe91a7bd54587c05f3..3faf623bbfd7872e807a9528a9f00a7466d5e490 100644 --- a/include/class.search.php +++ b/include/class.search.php @@ -681,7 +681,11 @@ class SavedSearch extends VerySimpleModel { } $id = $info[2]; if (is_numeric($id) && ($field = DynamicFormField::lookup($id))) { - $core[":{$info[1]}!{$info[2]}"] = $field->getImpl(); + $impl = $field->getImpl(); + $impl->set('label', sprintf('%s / %s', + $field->form->getLocal('title'), $field->getLocal('label') + )); + $core[":{$info[1]}!{$info[2]}"] = $impl; } } } @@ -743,23 +747,26 @@ class SavedSearch extends VerySimpleModel { ':organization' => 'user__org__cdata__', ); $column = $field->get('name') ?: 'field_'.$field->get('id'); - foreach ($other_paths as $k => $OP) { - if (substr($name, 0, strlen($k)) == $k) { - // XXX: Last mile — find a better idea - switch (array($k, $column)) { - case array(':user', 'name'): - $name = 'user__name'; - break; - case array(':user', 'email'): - $name = 'user__emails__address'; - break; - case array(':organization', 'name'): - $name = 'user__org__name'; - break; - default: - $name = $OP . $column; - } - } + list($type,$id) = explode('!', $name, 2); + $OP = $other_paths[$type]; + if ($type == ':field') { + $DF = DynamicFormField::lookup($id); + TicketModel::registerCustomData($DF->form); + $OP = 'cdata+'.$DF->form->id.'__'; + } + // XXX: Last mile — find a better idea + switch (array($type, $column)) { + case array(':user', 'name'): + $name = 'user__name'; + break; + case array(':user', 'email'): + $name = 'user__emails__address'; + break; + case array(':organization', 'name'): + $name = 'user__org__name'; + break; + default: + $name = $OP . $column; } } diff --git a/include/class.ticket.php b/include/class.ticket.php index 3183caf8242f7f59520ee1431023c58ca04d0a29..25798eada6d869b02fb35770330bf90a618d325a 100644 --- a/include/class.ticket.php +++ b/include/class.ticket.php @@ -92,6 +92,43 @@ class TicketModel extends VerySimpleModel { return false; } + + static function registerCustomData(DynamicForm $form) { + if (!isset(static::$meta['joins']['cdata+'.$form->id])) { + $cdata_class = <<<EOF +class DynamicForm{$form->id} extends DynamicForm { + static function getInstance() { + static \$instance; + if (!isset(\$instance)) + \$instance = static::lookup({$form->id}); + return \$instance; + } +} +class TicketCdataForm{$form->id} { + static \$meta = array( + 'view' => true, + 'pk' => array('ticket_id'), + 'joins' => array( + 'ticket' => array( + 'constraint' => array('ticket_id' => 'TicketModel.ticket_id'), + ), + ) + ); + static function getQuery(\$compiler) { + return '('.DynamicForm{$form->id}::getCrossTabQuery('T', 'ticket_id').')'; + } +} +EOF; + eval($cdata_class); + static::$meta['joins']['cdata+'.$form->id] = array( + 'reverse' => 'TicketCdataForm'.$form->id.'.ticket', + 'null' => true, + ); + // This may be necessary if the model has already been inspected + if (static::$meta instanceof ModelMeta) + static::$meta->processJoin(static::$meta['joins']['cdata+'.$form->id]); + } + } } class TicketCData extends VerySimpleModel {