Newer
Older
<?php
/*********************************************************************
class.dynamic_forms.php
Forms models built on the VerySimpleModel paradigm. Allows for arbitrary
data to be associated with tickets. Eventually this model can be
extended to associate arbitrary data with registered clients and thread
entries.
Jared Hancock <jared@osticket.com>
Copyright (c) 2006-2013 osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
vim: expandtab sw=4 ts=4 sts=4:
**********************************************************************/
require_once(INCLUDE_DIR . 'class.orm.php');
require_once(INCLUDE_DIR . 'class.forms.php');
require_once(INCLUDE_DIR . 'class.list.php');
require_once(INCLUDE_DIR . 'class.filter.php');
require_once(INCLUDE_DIR . 'class.signal.php');
/**
* Form template, used for designing the custom form and for entering custom
* data for a ticket
*/
class DynamicForm extends VerySimpleModel {
static $meta = array(
'table' => FORM_SEC_TABLE,
'ordering' => array('title'),
'pk' => array('id'),
'joins' => array(
'fields' => array(
'reverse' => 'DynamicFormField.form',
),
),
// Registered form types
static $types = array(
'T' => 'Ticket Information',
'U' => 'User Information',
const FLAG_DELETABLE = 0x0001;
const FLAG_DELETED = 0x0002;
function getInfo() {
$base = $this->ht;
unset($base['fields']);
return $base;
}
function getId() {
return $this->id;
}
/**
* Fetch a list of field implementations for the fields defined in this
* form. This method should *always* be preferred over
* ::getDynamicFields() to avoid caching confusion
*/
function getFields() {
if (!$this->_fields) {
$this->_fields = new ListObject();
$this->_fields->append($f->getImpl($f));
return $this->_fields;
/**
* Fetch the dynamic fields associated with this dynamic form. Do not
* use this list for data processing or validation. Use ::getFields()
* for that.
*/
// Multiple inheritance -- delegate methods not defined to a forms API
// Form
function __call($what, $args) {
$delegate = array($this->getForm(), $what);
if (!is_callable($delegate))
throw new Exception(sprintf(__('%s: Call to non-existing function'), $what));
return call_user_func_array($delegate, $args);
function getTitle() {
return $this->getLocal('title');
function getInstructions() {
return $this->getLocal('instructions');
/**
* Drop field errors clean info etc. Useful when replacing the source
* content of the form. This is necessary because the field listing is
* cached under some circumstances.
*/
function reset() {
foreach ($this->getFields() as $f)
$f->reset();
return $this;
}
if ($source)
$this->reset();
$fields = $this->getFields();
'title' => $this->getLocal('title'),
'instructions' => $this->getLocal('instructions'))
);
return $form;
}
function isDeletable() {
function setFlag($flag) {
$this->flags |= $flag;
function hasAnyVisibleFields($user=false) {
global $thisstaff, $thisclient;
$user = $user ?: $thisstaff ?: $thisclient;
$visible = 0;
$isstaff = $user instanceof Staff;
foreach ($this->getFields() as $F) {
if ($isstaff) {
if ($F->isVisibleToStaff())
$visible++;
}
elseif ($F->isVisibleToUsers()) {
$visible++;
}
}
return $visible > 0;
function instanciate($sort=1, $data=null) {
$inst = DynamicFormEntry::create(
array('form_id'=>$this->get('id'), 'sort'=>$sort)
);
$inst->setSource($data);
return $inst;
function disableFields(array $ids) {
foreach ($this->getFields() as $F) {
if (in_array($F->get('id'), $ids)) {
$F->disable();
}
function getTranslateTag($subtag) {
return _H(sprintf('form.%s.%s', $subtag, $this->id));
}
function getLocal($subtag) {
$tag = $this->getTranslateTag($subtag);
$T = CustomDataTranslation::translate($tag);
return $T != $tag ? $T : $this->get($subtag);
}
function save($refetch=false) {
if (count($this->dirty))
$this->set('updated', new SqlFunction('NOW'));
if ($rv = parent::save($refetch | $this->dirty))
return $this->saveTranslations();
return $rv;
}
function delete() {
if (!$this->isDeletable())
return false;
// Soft Delete: Mark the form as deleted.
$this->setFlag(self::FLAG_DELETED);
return $this->save();
function getExportableFields($exclude=array(), $prefix='__') {
$fields = array();
foreach ($this->getFields() as $f) {
// Ignore core fields
if ($exclude && in_array($f->get('name'), $exclude))
continue;
// Ignore non-data fields
// FIXME: Consider ::isStorable() too
elseif (!$f->hasData() || $f->isPresentationOnly())
continue;
$name = $f->get('name') ?: ('field_'.$f->get('id'));
$fields[$prefix.$name] = $f;
}
return $fields;
}
$inst = new static($ht);
$inst->set('created', new SqlFunction('NOW'));
if (isset($ht['fields'])) {
$inst->save();
foreach ($ht['fields'] as $f) {
$field = DynamicFormField::create(array('form' => $inst) + $f);
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
function saveTranslations($vars=false) {
global $thisstaff;
$vars = $vars ?: $_POST;
$tags = array(
'title' => $this->getTranslateTag('title'),
'instructions' => $this->getTranslateTag('instructions'),
);
$rtags = array_flip($tags);
$translations = CustomDataTranslation::allTranslations($tags, 'phrase');
foreach ($translations as $t) {
$T = $rtags[$t->object_hash];
$content = @$vars['trans'][$t->lang][$T];
if (!isset($content))
continue;
// Content is not new and shouldn't be added below
unset($vars['trans'][$t->lang][$T]);
$t->text = $content;
$t->agent_id = $thisstaff->getId();
$t->updated = SqlFunction::NOW();
if (!$t->save())
return false;
}
// New translations (?)
if ($vars['trans'] && is_array($vars['trans'])) {
foreach ($vars['trans'] as $lang=>$parts) {
if (!Internationalization::isLanguageEnabled($lang))
foreach ($parts as $T => $content) {
$content = trim($content);
if (!$content)
continue;
$t = CustomDataTranslation::create(array(
'type' => 'phrase',
'object_hash' => $tags[$T],
'lang' => $lang,
'text' => $content,
'agent_id' => $thisstaff->getId(),
'updated' => SqlFunction::NOW(),
));
if (!$t->save())
return false;
}
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 IF NOT EXISTS `'.$cdata['table'].'` (PRIMARY KEY
('.$cdata['object_id'].')) DEFAULT CHARSET=utf8 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;
Loading
Loading full blame...