Skip to content
Snippets Groups Projects
class.list.php 13 KiB
Newer Older
<?php
/*********************************************************************
    class.list.php

    Custom List utils

    Jared Hancock <jared@osticket.com>
    Peter Rotich <peter@osticket.com>
    Copyright (c)  2014 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.dynamic_forms.php');

/**
 * Interface for Custom Lists
 *
 * Custom lists are used to represent list of arbitrary data that can be
 * used as dropdown or typeahead selections in dynamic forms. This model
 * defines a list. The individual items are stored in the "Item" model.
 *
 */

interface CustomList {

    function getId();
    function getName();
    function getPluralName();

    function getNumItems();
    function getAllItems();
    function getItems($criteria);

    function getForm(); // Config form
    function hasProperties();

    function getSortModes();
    function getListOrderBy();

    function isBuiltIn();

    function update($vars, &$errors);
    function delete();

    static function create($vars, &$errors);
}

/*
 * Base class for Built-in Custom Lists
 *
 * Built-in custom lists are lists that can be extended but within the
 * constrains of system defined parameters.
 *
 */

abstract class BuiltInCustomList implements CustomList {
    static $sort_modes = array(
            'Alpha'     => 'Alphabetical',
            '-Alpha'    => 'Alphabetical (Reversed)',
            'SortCol'   => 'Manually Sorted'
    );

    var $config = null;

    function __construct() {
        $this->config = new Config('CL'.$this->getId());
    }

    abstract function getId();
    abstract function getName();
    abstract function getPluralName();

    abstract  function getInfo();

    abstract function getNumItems();
    abstract function getAllItems();
    abstract function getItems($criteria);

    abstract function getForm(); // Config form
    abstract function hasProperties();

    abstract function getListOrderBy();

    function getSortModes() {
        return static::$sort_modes;
    }

    function isBuiltIn() {
        return true;
    }

    function set($field, $value) {

        if (!$this->config)
            return false;

        return $this->config->set($field, $value);
    }

    abstract function update($vars, &$errors);

    // Built-in list cannot be deleted
    function delete() {
        return false;
    }

    // Built-in list is defined - not created.
    static function create($vars, &$errors) {
        return false;
    }

    static function lookup($id) {

        if (!($list=static::getLists())
                // Built-in list exists
                || !isset($list[$id])
                // Handler exits
                || !($handler = $list[$id]['handler'])
                // It's a collable handler
                || !class_exists($handler))
           return null;

        return new $handler();
    }

    static function getLists() {
Peter Rotich's avatar
Peter Rotich committed

        $list['status'] = array ( //Ticket statuses
                'name' => 'Ticket Status',
                'handler' => 'TicketStatusList',
                'icon' => 'icon-flag',
                );

        return $list;
    }

}

/**
 * Dynamic lists are Custom Lists solely defined by the user.
 *
 */
class DynamicList extends VerySimpleModel implements CustomList {

    static $meta = array(
        'table' => LIST_TABLE,
        'ordering' => array('name'),
        'pk' => array('id'),
    );

    static $sort_modes = array(
            'Alpha'     => 'Alphabetical',
            '-Alpha'    => 'Alphabetical (Reversed)',
            'SortCol'   => 'Manually Sorted'
            );

    // Required fields
    static $fields = array('name', 'name_plural', 'sort_mode', 'notes');


    var $_items;
    var $_form;

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

    function isBuiltIn() {
        return false;
    }

    function getInfo() {
        return $this->ht;
    }

    function hasProperties() {
        return ($this->getForm() && $this->getForm()->getFields());
    }

    function getSortModes() {
       return static::$sort_modes;
    }

    function getListOrderBy() {
        switch ($this->sort_mode) {
            case 'Alpha':   return 'value';
            case '-Alpha':  return '-value';
            case 'SortCol': return 'sort';
        }
    }

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

    function getPluralName() {
        if ($name = $this->get('name_plural'))
            return $name;
        else
            return $this->get('name') . 's';
    }

    function getItemCount() {
        return DynamicListItem::objects()->filter(array('list_id'=>$this->id))
            ->count();
    }

    function getNumItems() {
        return $this->getItemCount();
    }

    function getAllItems() {
         return DynamicListItem::objects()->filter(
                array('list_id'=>$this->get('id')))
                ->order_by($this->getListOrderBy());
    }

    function getItems($limit=false, $offset=false) {
        if (!$this->_items) {
            $this->_items = DynamicListItem::objects()->filter(
                array('list_id'=>$this->get('id'),
                      'status__hasbit'=>DynamicListItem::ENABLED))
                ->order_by($this->getListOrderBy());
            if ($limit)
                $this->_items->limit($limit);
            if ($offset)
                $this->_items->offset($offset);
        }
        return $this->_items;
    }

    function addItem($vars) {

        $item = DynamicListItem::create(array(
            'list_id' => $this->getId(),
            'sort'  => $vars['sort'],
            'value' => $vars['value'],
            'extra' => $vars['abbrev']
        ));

        $item->save();

        $this->_items = false;

        return $item;
    }

    function getConfigurationForm() {
        if (!$this->_form) {
            $this->_form = DynamicForm::lookup(
                array('type'=>'L'.$this->get('id')));
        }
        return $this->_form;
    }

    function getForm() {
        return $this->getConfigurationForm();
    }

    function update($vars, &$errors) {
        $required = array('name');
        foreach (static::$fields as $f) {
            if (in_array($f, $required) && !$vars[$f])
                $errors[$f] = sprintf('%s is required', mb_convert_case($f, MB_CASE_TITLE));
            elseif (isset($vars[$f]))
                $this->set($f, $vars[$f]);
        }

        if ($errors)
            return false;

        return $this->save(true);
    }

    function save($refetch=false) {
        if (count($this->dirty))
            $this->set('updated', new SqlFunction('NOW'));
        if (isset($this->dirty['notes']))
            $this->notes = Format::sanitize($this->notes);
        return parent::save($refetch);
    }

    function delete() {
        $fields = DynamicFormField::objects()->filter(array(
            'type'=>'list-'.$this->id))->count();
        if ($fields == 0)
            return parent::delete();
        else
            // Refuse to delete lists that are in use by fields
            return false;
    }

    static function create($ht=false, &$errors=array()) {
        $inst = parent::create($ht);
        $inst->set('created', new SqlFunction('NOW'));
        return $inst;
    }

    static function getSelections() {
        $selections = array();
        foreach (DynamicList::objects() as $list) {
            $selections['list-'.$list->id] =
                array($list->getPluralName(),
                    SelectionField, $list->get('id'));
        }
        return $selections;
    }

}
FormField::addFieldTypes('Custom Lists', array('DynamicList', 'getSelections'));

/**
 * Represents a single item in a dynamic list
 *
 * Fields:
 * value - (char * 255) Actual list item content
 * extra - (char * 255) Other values that represent the same item in the
 *      list, such as an abbreviation. In practice, should be a
 *      space-separated list of tokens which should hit this list item in a
 *      search
 * sort - (int) If sorting by this field, represents the numeric sort order
 *      that this item should come in the dropdown list
 */
class DynamicListItem extends VerySimpleModel {

    static $meta = array(
        'table' => LIST_ITEM_TABLE,
        'pk' => array('id'),
        'joins' => array(
            'list' => array(
                'null' => true,
                'constraint' => array('list_id' => 'DynamicList.id'),
            ),
        ),
    );

    var $_config;
    var $_form;

    const ENABLED               = 0x0001;

    protected function hasStatus($flag) {
        return 0 !== ($this->get('status') & $flag);
    }

    protected function clearStatus($flag) {
        return $this->set('status', $this->get('status') & ~$flag);
    }

    protected function setStatus($flag) {
        return $this->set('status', $this->get('status') | $flag);
    }

    function isEnabled() {
        return $this->hasStatus(self::ENABLED);
    }

    function enable() {
        $this->setStatus(self::ENABLED);
    }
    function disable() {
        $this->clearStatus(self::ENABLED);
    }

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

    function getValue() {
        return $this->get('value');
    }

    function getAbbrev() {
        return $this->get('extra');
    }

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

    function getConfiguration() {
        if (!$this->_config) {
            $this->_config = $this->get('properties');
            if (is_string($this->_config))
                $this->_config = JsonDataParser::parse($this->_config);
            elseif (!$this->_config)
                $this->_config = array();
        }
        return $this->_config;
    }

    function setConfiguration(&$errors=array()) {
        $config = array();
        foreach ($this->getConfigurationForm()->getFields() as $field) {
            $val = $field->to_database($field->getClean());
            $config[$field->get('id')] = is_array($val) ? $val[1] : $val;
            $errors = array_merge($errors, $field->errors());
        }
        if (count($errors) === 0)
            $this->set('properties', JsonDataEncoder::encode($config));

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

    function getConfigurationForm() {
        if (!$this->_form) {
            $this->_form = DynamicForm::lookup(
                array('type'=>'L'.$this->get('list_id')));
        }
        return $this->_form;
    }

    function getVar($name) {
        $config = $this->getConfiguration();
        $name = mb_strtolower($name);
        foreach ($this->getConfigurationForm()->getFields() as $field) {
            if (mb_strtolower($field->get('name')) == $name)
                return $config[$field->get('id')];
        }
    }

    function toString() {
        return $this->get('value');
    }

    function __toString() {
        return $this->toString();
    }

    function update($vars, $save = true) {

        foreach (array(
                    'sort' => 'sort',
                    'value' => 'value',
                    'abbrev' => 'extra') as $k => $v) {
            if (isset($vars[$k]))
                $this->set($v, $vars[$k]);

        }

        if ($save)
            $this->save();

        return true;
    }

    function delete() {
        # Don't really delete, just unset the list_id to un-associate it with
        # the list
        $this->set('list_id', null);
        return $this->save();
    }
}

Peter Rotich's avatar
Peter Rotich committed

/*
 * Ticket status List
 *
 *
 */

class TicketStatusList extends BuiltInCustomList {

    var $ht = array(
            'id' => 'status',
            'name' => 'Status',
            'name_plural' => 'Statuses',
    );
    // Fields of interest we need to store
    static $config_fields = array('sort_mode', 'notes');

    function getId() {
        return $this->ht['id'];
    }

    function getName() {
        return $this->ht['name'];
    }

    function getPluralName() {
        return $this->ht['name_plural'];
    }

    function getSortMode() {
        return $this->ht['sort_mode'];
    }

    function getNotes() {
        return $this->ht['notes'];
    }

    function getInfo() {
        return $this->config->getInfo() + $this->ht;
    }

    function getNumItems() {
        return 0;
    }

    function getAllItems() {

    }

    function getItems($criteria) {

    }

    function hasProperties() {
        return true;
    }

    function getListOrderBy() {
        switch ($this->setSortMode()) {
            case 'Alpha':
                return 'name';
            case '-Alpha':
                return '-name';
            case 'SortCol':
            default:
                return 'sort';
        }
    }

    function getForm() {
       return null;
    }

    function update($vars, &$errors) {

        foreach (static::$config_fields as $f) {
            if (!isset($vars[$f])) continue;

            if (parent::set($f, $vars[$f]))
                $this->ht[$field] = $vars[$f];
        }

        return true;
    }
}