qcubed/framework

View on GitHub
includes/base_controls/QListBoxBase.class.php

Summary

Maintainability
C
1 day
Test Coverage
<?php
    /**
     * contains QListBoxBase class
     * @package Controls
     */

    /**
     * QListBoxBase will render an HTML DropDown or MultiSelect box [SELECT] element.
     * It extends {@link QListControl}.  By default, the number of visible rows is set to 1 and
     * the selection mode is set to single, creating a dropdown select box.
     *
     * @property integer $Rows          specifies how many rows you want to have shown.
     * @property string  $LabelForRequired
     * @property string  $LabelForRequiredUnnamed
     * @property string  $SelectionMode {@link QSelectionMode} specifies if this is a "Single" or "Multiple" select control.
     * @see     QSelectionMode
     * @package Controls
     */
    abstract class QListBoxBase extends QListControl {
        ///////////////////////////
        // Private Member Variables
        ///////////////////////////

        // APPEARANCE
        /** @var string Error to be shown if the box is empty, has a name and is marked as required */
        protected $strLabelForRequired;
        /** @var string Error to be shown If the box is empty, doesn't have a name and is marked as required */
        protected $strLabelForRequiredUnnamed;

        //////////
        // Methods
        //////////
        /**
         * QControl-Constructor
         * 
         * @param QControl|QForm $objParentObject
         * @param string $strControlId
         */
        public function __construct($objParentObject, $strControlId = null) {
            parent::__construct($objParentObject, $strControlId);

            $this->strLabelForRequired = QApplication::Translate('%s is required');
            $this->strLabelForRequiredUnnamed = QApplication::Translate('Required');
            $this->objItemStyle = new QListItemStyle();
        }

        /**
         * Parses the data received back from the client/browser
         */
        public function ParsePostData() {
            if (array_key_exists($this->strControlId, $_POST)) {
                if (is_array($_POST[$this->strControlId])) {
                    // Multi-Select, so find them all.
                    $this->SetSelectedItemsById($_POST[$this->strControlId], false);
                } elseif ($_POST[$this->strControlId] === '') {
                    $this->UnselectAllItems(false);
                }
                else {
                    // Single-select
                    $this->SetSelectedItemsById(array($_POST[$this->strControlId]), false);
                }
            } else {
                // Multiselect forms with nothing passed via $_POST means that everything was DE selected
                if ($this->SelectionMode == QSelectionMode::Multiple) {
                    $this->UnselectAllItems(false);
                }
            }
        }

        /**
         * Returns the HTML-Code for a single Item
         * 
         * @param QListItem $objItem
         * @return string resulting HTML
         */
        protected function GetItemHtml(QListItem $objItem) {
            // The Default Item Style
            if ($this->objItemStyle) {
                $objStyler = clone ($this->objItemStyle);
            } else {
                $objStyler = new QListItemStyle();
            }

            // Apply any Style Override (if applicable)
            if ($objStyle = $objItem->ItemStyle) {
                $objStyler->Override($objStyle);
            }

            $objStyler->SetHtmlAttribute('value', ($objItem->Empty) ? '' : $objItem->Id);
            if ($objItem->Selected) {
                $objStyler->SetHtmlAttribute('selected', 'selected');
            }

            $strHtml = QHtml::RenderTag('option', $objStyler->RenderHtmlAttributes(), QApplication::HtmlEntities($objItem->Name), false, true) . _nl();

            return $strHtml;
        }

        /**
         * Returns the html for the entire control.
         * @return string
         */
        protected function GetControlHtml() {
            // If no selection is specified, we select the first item, because once we draw this, that is what the browser
            // will consider selected on the screen.
            // We need to make sure that what we draw is mirrored in our current state
            if ($this->SelectionMode == QSelectionMode::Single &&
                    $this->SelectedIndex == -1 &&
                    $this->ItemCount > 0) {
                $this->SelectedIndex = 0;
            }

            if ($this->SelectionMode == QSelectionMode::Multiple) {
                $attrOverride['name'] = $this->strControlId . "[]";
            } else {
                $attrOverride['name'] = $this->strControlId;
            }

            $strToReturn = $this->RenderTag('select', $attrOverride, null, $this->RenderInnerHtml());

            // If MultiSelect and if NOT required, add a "Reset" button to deselect everything
            if (($this->SelectionMode == QSelectionMode::Multiple) && (!$this->blnRequired) && ($this->Enabled) && ($this->blnVisible)) {
                $strToReturn .= $this->GetResetButtonHtml();
            }
            return $strToReturn;
        }

        /**
         * Return the inner html for the select box.
         * @return string
         */
        protected function RenderInnerHtml() {
            $strHtml = '';
            $intItemCount = $this->GetItemCount();
            if (!$intItemCount) return '';
            $groups = array();

            for ($intIndex = 0; $intIndex < $intItemCount; $intIndex++) {
                $objItem = $this->GetItem ($intIndex);
                // Figure Out Groups (if applicable)
                if ($strGroup = $objItem->ItemGroup) {
                    $groups[$strGroup][] = $objItem;
                } else {
                    $groups[''][] = $objItem;
                }
            }

            foreach ($groups as $strGroup=>$items) {
                if (!$strGroup) {
                    foreach ($items as $objItem) {
                        $strHtml .= $this->GetItemHtml($objItem);
                    }
                }
                else {
                    $strGroupHtml = '';
                    foreach ($items as $objItem) {
                        $strGroupHtml .= $this->GetItemHtml($objItem);
                    }
                    $strHtml .= QHtml::RenderTag('optgroup', ['label' => QApplication::HtmlEntities($strGroup)], $strGroupHtml);
                }
            }
            return $strHtml;
        }

        // For multiple-select based listboxes, you must define the way a "Reset" button should look
        abstract protected function GetResetButtonHtml();

        /**
         * Determines whether the supplied input data is valid or not.
         * @return bool
         */
        public function Validate() {
            if ($this->blnRequired) {
                if ($this->SelectedIndex == -1) {
                    if ($this->strName)
                        $this->ValidationError = sprintf($this->strLabelForRequired, $this->strName);
                    else
                        $this->ValidationError = $this->strLabelForRequiredUnnamed;
                    return false;
                }

                if (($this->SelectedIndex == 0) && (strlen($this->SelectedValue) == 0)) {
                    if ($this->strName)
                        $this->ValidationError = sprintf($this->strLabelForRequired, $this->strName);
                    else
                        $this->ValidationError = $this->strLabelForRequiredUnnamed;
                    return false;
                }
            }

            return true;
        }

        /**
         * Override of superclass that will update the selection using javascript so that the whole control does
         * not need to be redrawn.
         */
        protected function RefreshSelection() {
            $items = $this->SelectedItems;
            $values = [];
            foreach ($items as $objItem) {
                $values[] = $objItem->Id;
            }
            QApplication::ExecuteControlCommand($this->ControlId, 'val', $values);
        }

        /**
         * Restore the  state of the control. This override makes sure the item exists before putting it. Otherwise,
         * if the item did not exist, the default selection would be removed and nothing would be selected.
         * @param mixed $state
         */
        public function PutState($state) {
            if (!empty($state['SelectedValues'])) {
                // assume only one selection in list
                $strValue = reset($state['SelectedValues']);
                if ($this->FindItemByValue($strValue)) {
                    $this->SelectedValues = [$strValue];
                }
            }
        }


        /////////////////////////
        // Public Properties: GET
        /////////////////////////
        /**
         * PHP magic function
         * @param string $strName
         *
         * @return mixed
         * @throws Exception|QCallerException
         */
        public function __get($strName) {
            switch ($strName) {
                // APPEARANCE
                case "Rows": return $this->GetHtmlAttribute('size');
                case "LabelForRequired": return $this->strLabelForRequired;
                case "LabelForRequiredUnnamed": return $this->strLabelForRequiredUnnamed;

                // BEHAVIOR
                case "SelectionMode": return $this->HasHtmlAttribute('multiple') ? QSelectionMode::Multiple : QSelectionMode::Single;

                default:
                    try {
                        return parent::__get($strName);
                    } catch (QCallerException $objExc) {
                        $objExc->IncrementOffset();
                        throw $objExc;
                    }
            }
        }

        /////////////////////////
        // Public Properties: SET
        /////////////////////////
        /**
         * PHP magic method
         * @param string $strName
         * @param string $mixValue
         *
         * @return mixed
         * @throws Exception|QCallerException|QInvalidCastException
         */
        public function __set($strName, $mixValue) {
            switch ($strName) {
                // APPEARANCE
                case "Rows":
                    try {
                        $this->SetHtmlAttribute('size', QType::Cast($mixValue, QType::Integer));
                        break;
                    } catch (QInvalidCastException $objExc) {
                        $objExc->IncrementOffset();
                        throw $objExc;
                    }
                case "LabelForRequired":
                    try {
                        $this->strLabelForRequired = QType::Cast($mixValue, QType::String);
                        break;
                    } catch (QInvalidCastException $objExc) {
                        $objExc->IncrementOffset();
                        throw $objExc;
                    }
                case "LabelForRequiredUnnamed":
                    try {
                        $this->strLabelForRequiredUnnamed = QType::Cast($mixValue, QType::String);
                        break;
                    } catch (QInvalidCastException $objExc) {
                        $objExc->IncrementOffset();
                        throw $objExc;
                    }

                // BEHAVIOR
                case "SelectionMode":
                    try {
                        if (QType::Cast($mixValue, QType::String) == QSelectionMode::Multiple) {
                            $this->SetHtmlAttribute('multiple', 'multiple');
                        } else {
                            $this->RemoveHtmlAttribute('multiple');
                        }
                        break;
                    } catch (QInvalidCastException $objExc) {
                        $objExc->IncrementOffset();
                        throw $objExc;
                    }
                
                default:
                    try {
                        parent::__set($strName, $mixValue);
                    } catch (QCallerException $objExc) {
                        $objExc->IncrementOffset();
                        throw $objExc;
                    }
                    break;
            }
        }

        /**
         * Returns an description of the options available to modify by the designer for the code generator.
         *
         * @return QModelConnectorParam[]
         */
        public static function GetModelConnectorParams() {
            return array_merge(parent::GetModelConnectorParams(), array(
                new QModelConnectorParam (get_called_class(), 'Rows', 'Height of field for multirow field', QType::Integer),
                new QModelConnectorParam (get_called_class(), 'SelectionMode', 'Single or multiple selections', QModelConnectorParam::SelectionList,
                    array (null=>'Default',
                        'QSelectionMode::Single'=>'Single',
                        'QSelectionMode::Multiple'=>'Multiple'
                    ))
            ));
        }

    }