Skip to content
Snippets Groups Projects
class.list.php 40.8 KiB
Newer Older
                'visibility' => new VisibilityConstraint(
                    new Q(array('state__eq'=>'closed')),
                    VisibilityConstraint::HIDDEN
                ),
            )),
            'reopenstatus' => new ChoiceField(array(
                'label' => __('Reopen Status'),
Peter Rotich's avatar
Peter Rotich committed
                'editable' => true,
                'required' => false,
                'default' => isset($source['reopenstatus'])
                    ? $source['reopenstatus'] : 0,
                'id' => 'reopenstatus',
                'name' => 'reopenstatus',
                'choices' => $status_choices,
                'configuration' => array(
                    'widget' => 'dropdown',
                    'multiselect' =>false
                ),
                'visibility' => new VisibilityConstraint(
                    new Q(array('allowreopen__eq'=> true)),
                    VisibilityConstraint::HIDDEN
                ),
            ))
        );
    }

    function getConfigurationForm($source=null) {
        if (!($form = $this->getForm()))
            return null;

        $form = $form->getForm($source);
        $fields = $form->getFields();
        foreach ($fields as $k => $f) {
            if ($f->get('name') == 'state' //TODO: check if editable.
                    && ($extras=$this->getExtraConfigOptions($source))) {
                foreach ($extras as $extra) {
                    $extra->setForm($form);
                    $fields->insert(++$k, $extra);
Peter Rotich's avatar
Peter Rotich committed

            if (!isset($f->ht['editable']))
                $f->ht['editable'] = true;
        // Enable selection and display of private states
        $form->getField('state')->options['private_too'] = true;
    function getListItemBasicForm($source=null, $item=false) {
        return new SimpleForm(array(
            'name' => new TextboxField(array(
                'required' => true,
                'label' => __('Value'),
                'configuration' => array(
                    'translatable' => $item ? $item->getTranslateTag('value') : false,
                    'size' => 60,
                    'length' => 0,
                    'autofocus' => true,
                ),
            )),
            'extra' => new TextboxField(array(
                'label' => __('Abbreviation'),
                'configuration' => array(
                    'size' => 60,
                    'length' => 0,
                ),
            )),
        ), $source);
    }

    function getSummaryFields() {
        // Like the main one, except the description and state fields are
        // welcome on the screen
        $prop_fields = array();
        foreach ($this->getConfigurationForm()->getFields() as $f) {
            if (in_array($f->get('type'), array('state', 'text', 'datetime', 'phone')))
                $prop_fields[] = $f;
            elseif (strpos($f->get('type'), 'list-') === 0)
                $prop_fields[] = $f;
            elseif ($f->get('name') == 'description')
                $prop_fields[] = $f;

            // 4 property columns max
            if (count($prop_fields) == 4)
                break;
        }
        return $prop_fields;
    }
}
CustomListHandler::register('ticket-status', 'TicketStatusList');

class TicketStatus
extends VerySimpleModel
implements CustomListItem, TemplateVariable {

    static $meta = array(
        'table' => TICKET_STATUS_TABLE,
        'ordering' => array('name'),
        'pk' => array('id'),
        'joins' => array(
            'tickets' => array(
                'reverse' => 'TicketModel.status',
                )
        )
    );

    var $_list;
    var $_form;
    var $_settings;
    var $_properties;

    const ENABLED   = 0x0001;
    const INTERNAL  = 0x0002; // Forbid deletion or name and status change.

    protected function hasFlag($field, $flag) {
        return 0 !== ($this->get($field) & $flag);
    }

    protected function clearFlag($field, $flag) {
        return $this->set($field, $this->get($field) & ~$flag);
    }

    protected function setFlag($field, $flag) {
        return $this->set($field, $this->get($field) | $flag);
    }

Peter Rotich's avatar
Peter Rotich committed
    function hasProperties() {
        return ($this->get('properties'));
    }

Peter Rotich's avatar
Peter Rotich committed
    function isEnabled() {
        return $this->hasFlag('mode', self::ENABLED);
    }

    function isReopenable() {

        if (strcasecmp($this->get('state'), 'closed'))
            return true;

        if (($c=$this->getConfiguration())
                && $c['allowreopen']
                && isset($c['reopenstatus']))
            return true;

        return false;
    }

    function getReopenStatus() {
        global $cfg;

        $status = null;
        if ($this->isReopenable()
                && ($c = $this->getConfiguration())
                && isset($c['reopenstatus']))
            $status = TicketStatus::lookup(
                    $c['reopenstatus'] ?: $cfg->getDefaultTicketStatusId());

        return ($status
                && !strcasecmp($status->getState(), 'open'))
            ?  $status : null;
    }

Peter Rotich's avatar
Peter Rotich committed
    function enable() {

        // Ticket status without properties cannot be enabled!
        if (!$this->isEnableable())
            return false;

        return $this->setFlag('mode', self::ENABLED);
    }

    function disable() {
        return (!$this->isInternal()
Peter Rotich's avatar
Peter Rotich committed
                && !$this->isDefault()
Peter Rotich's avatar
Peter Rotich committed
                && $this->clearFlag('mode', self::ENABLED));
    }

Peter Rotich's avatar
Peter Rotich committed
    function isDefault() {
        global $cfg;

        return ($cfg
                && $cfg->getDefaultTicketStatusId() == $this->getId());
    }

Peter Rotich's avatar
Peter Rotich committed
    function isEnableable() {
        return ($this->getState());
Peter Rotich's avatar
Peter Rotich committed
    function isDisableable() {
        return !($this->isInternal() || $this->isDefault());
    }

Peter Rotich's avatar
Peter Rotich committed
    function isDeletable() {
Peter Rotich's avatar
Peter Rotich committed

        return !($this->isInternal()
                || $this->isDefault()
                || $this->getNumTickets());
Peter Rotich's avatar
Peter Rotich committed
    }

    function isInternal() {
        return ($this->isDefault()
                || $this->hasFlag('mode', self::INTERNAL));
    }


    function getNumTickets() {
        return $this->tickets->count();
Peter Rotich's avatar
Peter Rotich committed
    }

    function getId() {
        return $this->get('id');
    }

    function getName() {
        return $this->get('name');
    }

Peter Rotich's avatar
Peter Rotich committed
    function getState() {
        return $this->get('state');
    }

Peter Rotich's avatar
Peter Rotich committed
    function getValue() {
        return $this->getName();
    }
    function getLocalName() {
Peter Rotich's avatar
Peter Rotich committed
        return $this->getLocal('value', $this->getName());
Peter Rotich's avatar
Peter Rotich committed

    function getAbbrev() {
        return '';
    }

    function getSortOrder() {
        return $this->get('sort');
    }

    private function getProperties() {

        if (!isset($this->_properties)) {
            $this->_properties = $this->get('properties');
            if (is_string($this->_properties))
                $this->_properties = JsonDataParser::parse($this->_properties);
            elseif (!$this->_properties)
                $this->_properties = array();
        }

        return $this->_properties;
    }

    function getTranslateTag($subtag) {
        return _H(sprintf('status.%s.%s', $subtag, $this->id));
    }
Peter Rotich's avatar
Peter Rotich committed
    function getLocal($subtag, $default) {
        $tag = $this->getTranslateTag($subtag);
        $T = CustomDataTranslation::translate($tag);
Peter Rotich's avatar
Peter Rotich committed
        return $T != $tag ? $T : $default;
    static function getLocalById($id, $subtag, $default) {
        $tag = _H(sprintf('status.%s.%s', $subtag, $id));
        $T = CustomDataTranslation::translate($tag);
        return $T != $tag ? $T : $default;
    }
    // TemplateVariable interface
    static function getVarScope() {
        $base = array(
            'name' => __('Status label'),
            'state' => __('State name (e.g. open or closed)'),
        );
        return $base;
    }

    function getList() {
        if (!isset($this->_list))
            $this->_list = DynamicList::lookup(array('type' => 'ticket-status'));
        return $this->_list;
    }

Peter Rotich's avatar
Peter Rotich committed
    function getListId() {
        if (($list = $this->getList()))
            return $list->getId();
    }

    function getConfigurationForm($source=null) {
        if (!$this->_form) {
            $config = $this->getConfiguration();
Peter Rotich's avatar
Peter Rotich committed
            // Forcefully retain state for internal statuses
            if ($source && $this->isInternal())
                $source['state'] = $this->getState();
            $this->_form = $this->getList()->getConfigurationForm($source);
            if (!$source && $config) {
                $fields = $this->_form->getFields();
                foreach ($fields as $f) {
                    $val = $config[$f->get('id')] ?: $config[$f->get('name')];
                    if (isset($val))
                        $f->value = $f->to_php($val);
                    elseif ($f->get('default'))
                        $f->value = $f->get('default');
                }
            }
Peter Rotich's avatar
Peter Rotich committed

            if ($this->isInternal()
                    && ($f=$this->_form->getField('state'))) {
                $f->ht['required'] = $f->ht['editable'] = false;
Peter Rotich's avatar
Peter Rotich committed
                $f->options['render_mode'] = 'view';
Peter Rotich's avatar
Peter Rotich committed
    function getFields() {
        return $this->getConfigurationForm()->getFields();
    }

Peter Rotich's avatar
Peter Rotich committed
    function getConfiguration() {

        if (!$this->_settings) {
            $this->_settings = $this->getProperties();
            if (!$this->_settings)
                $this->_settings = array();
            if ($form = $this->getList()->getForm()) {
                foreach ($form->getFields() as $f)  {
Peter Rotich's avatar
Peter Rotich committed
                    $name = mb_strtolower($f->get('name'));
                    $id = $f->get('id');
                    switch($name) {
                        case 'flags':
                            foreach (TicketFlagField::$_flags as $k => $v)
Peter Rotich's avatar
Peter Rotich committed
                                if ($this->hasFlag('flags', $v['flag']))
                                    $this->_settings[$id][$k] = $v['name'];
Peter Rotich's avatar
Peter Rotich committed
                            break;
                        case 'state':
                            $this->_settings[$id][$this->get('state')] = $this->get('state');
Peter Rotich's avatar
Peter Rotich committed
                            break;
                        default:
                            if (!$this->_settings[$id] && $this->_settings[$name])
                                $this->_settings[$id] = $this->_settings[$name];
                    }
                }
            }
        }

        return $this->_settings;
    }

    function setConfiguration($vars, &$errors=array()) {
Peter Rotich's avatar
Peter Rotich committed
        $properties = array();
Peter Rotich's avatar
Peter Rotich committed
        foreach ($this->getConfigurationForm($vars)->getFields() as $f) {
            // Only bother with editable fields
            if (!$f->isEditable()) continue;

Peter Rotich's avatar
Peter Rotich committed
            $val = $f->getClean();
            $errors = array_merge($errors, $f->errors());
            if ($f->errors()) continue;
Peter Rotich's avatar
Peter Rotich committed
            $name = mb_strtolower($f->get('name'));
            switch ($name) {
                case 'flags':
                    if ($val && is_array($val)) {
                        $flags = 0;
                        foreach ($val as $k => $v) {
                            if (isset(TicketFlagField::$_flags[$k]))
                                $flags += TicketFlagField::$_flags[$k]['flag'];
Peter Rotich's avatar
Peter Rotich committed
                            elseif (!$f->errors())
                                $f->addError(__('Unknown or invalid flag'), $name);
Peter Rotich's avatar
Peter Rotich committed
                        }
                        $this->set('flags', $flags);
                    } elseif ($val && !$f->errors()) {
                        $f->addError(__('Unknown or invalid flag format'), $name);
Peter Rotich's avatar
Peter Rotich committed
                    }
                    break;
                case 'state':
Peter Rotich's avatar
Peter Rotich committed
                    // Internal statuses cannot change state
                    if ($this->isInternal())
                        break;

                    if ($val)
                        $this->set('state', $val);
Peter Rotich's avatar
Peter Rotich committed
                    else
                        $f->addError(__('Unknown or invalid state'), $name);
Peter Rotich's avatar
Peter Rotich committed
                    break;
                default: //Custom properties the user might add.
Peter Rotich's avatar
Peter Rotich committed
                    $properties[$f->get('id')] = $f->to_php($val);
            // Add field specific validation errors (warnings)
Peter Rotich's avatar
Peter Rotich committed
            $errors = array_merge($errors, $f->errors());
        }

        if (count($errors) === 0) {
            if ($properties && is_array($properties))
                $properties = JsonDataEncoder::encode($properties);

            $this->set('properties', $properties);
Peter Rotich's avatar
Peter Rotich committed
            $this->save(true);
        }

        return count($errors) === 0;
    }

Peter Rotich's avatar
Peter Rotich committed
    function display() {
        return sprintf('<a class="preview" href="#"
                data-preview="#list/%d/items/%d/preview">%s</a>',
                $this->getListId(),
                $this->getId(),
                $this->getLocalName()
                );
    }

Peter Rotich's avatar
Peter Rotich committed
    function update($vars, &$errors) {
        $fields = array('name', 'sort');
        foreach($fields as $k) {
Peter Rotich's avatar
Peter Rotich committed
            if (isset($vars[$k]))
                $this->set($k, $vars[$k]);
        return $this->save();
Peter Rotich's avatar
Peter Rotich committed
    }

    function delete() {

        // Statuses with tickets are not deletable
Peter Rotich's avatar
Peter Rotich committed
        if (!$this->isDeletable())
            return false;

        return parent::delete();
Peter Rotich's avatar
Peter Rotich committed
    }

    function __toString() {
        return $this->getName();
    static function create($ht=false) {
        if (!is_array($ht))
            return null;

        if (!isset($ht['mode']))
            $ht['mode'] = 1;

        $ht['created'] = new SqlFunction('NOW');

        return new static($ht);
    static function lookup($var, $list=null) {

        if (!($item = parent::lookup($var)))
            return null;

        $item->_list = $list;

        return $item;
    }


Peter Rotich's avatar
Peter Rotich committed
    static function __create($ht, &$error=false) {
        global $ost;

        $ht['properties'] = JsonDataEncoder::encode($ht['properties']);
        if (($status = TicketStatus::create($ht)))
Peter Rotich's avatar
Peter Rotich committed
            $status->save(true);

        return $status;
    }

    static function status_options() {
Peter Rotich's avatar
Peter Rotich committed
        include(STAFFINC_DIR . 'templates/status-options.tmpl.php');
    }
}