Perforce Chronicle 2012.2/486814
API Documentation

P4Cms_Form Class Reference

Extends Zend_Form to provide support for an id prefix and show errors by default. More...

Inheritance diagram for P4Cms_Form:
Analytics_Form_Configure Category_Form_Manage Comment_Form_Comment Content_Form_Delete Flickr_Form_Configure Menu_Form_Menu Menu_Form_MenuItem P4Cms_Form_PubSubForm Search_Form_Basic Search_Form_Manage Setup_Form_Administrator Setup_Form_Site Setup_Form_Storage Site_Form_Branch Site_Form_Pull User_Form_Add User_Form_AddRole User_Form_Login Widget_Form_Config Workflow_Form_Workflow

List of all members.

Public Member Functions

 __construct ($options=null)
 Extend Zend_Dojo_Form's constructor to provide our own decorators.
 addElement ($element, $name=null, $options=null)
 Add a new element.
 getElementValidator ($element, $validator)
 Helper method to get the validator of an element.
 getFlattenedValues ()
 Get the values of the form flattened with array notation for keys.
 getIdPrefix ()
 Get the string used to prefix element ids.
 getMessages ($name=null, $suppressArrayNotation=false)
 Retrieve error messages from elements failing validations.
 getStorageAdapter ()
 Get the storage adapter used by this form to access records.
 getValues ($suppressArrayNotation=false)
 Retrieve all form element values.
 hasCsrfProtection ()
 Returns whether or not this form has csrf protection enabled.
 isValid ($data)
 Validate the form, including csrf check.
 loadDefaultDecorators ()
 Add "Errors" and "CsrfForm" to the default set of decorators.
 populate ($values)
 Populate form.
 render (Zend_View_Interface $view=null)
 Add id prefixes, then render the form.
 setCsrfProtection ($csrf)
 Enables or disables the csrf protection for this form; defaults to enabled.
 setDefaults ($defaults)
 Set element values.
 setIdPrefix ($prefix)
 Set a string to prefix element ids with.
 setStorageAdapter (P4Cms_Record_Adapter $adapter)
 Set the storage adapter to use to access records.

Static Public Member Functions

static clearPrefixPathRegistry ()
 Remove any registered form plugin prefix paths.
static getCsrfToken ()
 For authenticated users, returns the current session value or generate a new value (and set on the session) if none is present.
static getLibraryPathRegistry ()
 Get any library prefix paths that are statically registered.
static getPrefixPathRegistry ()
 Get any plugin prefix paths that are statically registered.
static moveCheckboxLabel (Zend_Form_Element $element)
 Helper function to adjust decorators on checkbox element to position the checkbox label to the right of the checkbox, instead of on the left hand side.
static normalizeSubForm ($form, $name=null)
 Ensure consistent presentation of sub-forms.
static prefixFormIds (Zend_Form $form, $prefix)
 Prefix the ids of all elements, fieldsets and sub-forms within a form.
static registerPrefixPath ($prefix, $path, $type)
 Add a form plugin path to be used whenever a form is instantiated.

Public Attributes

const CSRF_TOKEN_NAME = '_csrfToken'
const UTF8_NBSP = "\xc2\xa0"
 Useful for indenting items (e.g.

Static Protected Member Functions

static _applyIdPrefix ($element, $prefix)
 Add prefix to id attribute of given element.
static _getSession ()
 Return the static session object, initializing if necessary.

Protected Attributes

 $_csrfProtection = true
 $_idPrefix = null
 $_populatedCsrfToken = ''
 $_storageAdapter = null

Static Protected Attributes

static $_libraryPaths
static $_prefixPaths = array()
static $_session = null

Detailed Description

Extends Zend_Form to provide support for an id prefix and show errors by default.

Copyright:
2011-2012 Perforce Software. All rights reserved
License:
Please see LICENSE.txt in top-level folder of this distribution.
Version:
2012.2/486814

Constructor & Destructor Documentation

P4Cms_Form::__construct ( options = null)

Extend Zend_Dojo_Form's constructor to provide our own decorators.

Parameters:
array | Zend_Config | null$optionsZend provides no documentation for this param.
Returns:
void

Reimplemented in User_Form_Add, and User_Form_Edit.

    {
        // combine library prefix paths with
        // paths from the static registry.
        $prefixPaths = static::$_libraryPaths + static::$_prefixPaths;

        // add prefix paths to form instance.
        foreach ($prefixPaths as $prefixPath) {
            extract($prefixPath);

            // add element and decorator paths to form.
            if ($type === static::ELEMENT || $type === static::DECORATOR) {
                $this->addPrefixPath($prefix, $path, $type);
            }

            // add decorator, validator and filter paths to elements.
            if ($type !== static::ELEMENT) {
                $this->addElementPrefixPath($prefix, $path, $type);
            }

            // add decorator paths to display groups.
            if ($type === static::DECORATOR) {
                $this->addDisplayGroupPrefixPath($prefix, $path);
            }
        }

        // if no storage adapter specified, use default where available
        if (!isset($options['storageAdapter'])
            && P4Cms_Record::hasDefaultAdapter()
        ) {
            $this->_storageAdapter = P4Cms_Record::getDefaultAdapter();
        }

        parent::__construct($options);
    }

Member Function Documentation

static P4Cms_Form::_applyIdPrefix ( element,
prefix 
) [static, protected]

Add prefix to id attribute of given element.

Parameters:
mixed$elementthe element to prefix the id of - can be a form, fieldset or standard element.
string$prefixthe prefix to apply
    {
        // ensure prefix ends with a dash.
        $prefix = rtrim($prefix, '-') . '-';

        // prefix if id is not blank and not already prefixed.
        if (strlen($element->getId()) && strpos($element->getId(), $prefix) !== 0) {
            $id = $prefix . $element->getId();
            $element->setAttrib('id', $id);
        }
    }
static P4Cms_Form::_getSession ( ) [static, protected]

Return the static session object, initializing if necessary.

Returns:
Zend_Session_Namespace
    {
        if (!static::$_session instanceof Zend_Session_Namespace) {
            static::$_session = new Zend_Session_Namespace('Forms');
        }

        return static::$_session;
    }
P4Cms_Form::addElement ( element,
name = null,
options = null 
)

Add a new element.

This is a wrapper around the parent function that provides more palatable error messages for end users.

Parameters:
string | Zend_Form_Element$elementThe element to add.
string$nameThe name of the element.
array | Zend_Config$optionsThe options for the element.
Returns:
Zend_Form
    {
        try {
            parent::addElement($element, $name, $options);
        } catch (Exception $e) {
            P4Cms_Log::log(
                'P4Cms_Form->addElement exception ('. get_class($e) .') - '. $e->getMessage(),
                P4Cms_Log::DEBUG
            );
            if (preg_match("/^Plugin by name '(.+)' was not found in the registry;/", $e->getMessage(), $matches)) {
                throw new Zend_Form_Exception('Element plugin "'. $matches[1] .'" not found.');
            } else {
                throw $e;
            }
        }
        return $this;
    }
static P4Cms_Form::clearPrefixPathRegistry ( ) [static]

Remove any registered form plugin prefix paths.

    {
        static::$_prefixPaths = array();
    }
static P4Cms_Form::getCsrfToken ( ) [static]

For authenticated users, returns the current session value or generate a new value (and set on the session) if none is present.

For anonymous users this method simply returns null as they don't receive CSRF protection

Returns:
string|null csrf token for this form
    {
        // skip starting a session for anonymous users and simply return null
        if (!P4Cms_User::hasActive() || P4Cms_User::fetchActive()->isAnonymous()) {
            return null;
        }

        $session = static::_getSession();
        if (!$session->csrfToken) {
            $session->csrfToken = (string) new P4Cms_Uuid;

            // Don't let the presence of a CSRF token in the session
            // prevent caching of future unrelated requests.
            if (P4Cms_Cache::canCache('page')) {
                P4Cms_Cache::getCache('page')->addIgnoredSessionVariable('Forms[csrfToken]');
            }
        }

        return $session->csrfToken;
    }
P4Cms_Form::getElementValidator ( element,
validator 
)

Helper method to get the validator of an element.

Calls isValid on the element to load the correct validators. Attempts to preserve original errors and value.

Parameters:
string$elementthe name of the element to get the validator for.
string$validatorthe name of the validator to get.
Returns:
Zend_Validate_Interface the requested validator.
    {
        // create a copy of element (to avoid polluting the element)
        // and call isValid to load the validators.
        $temp = clone $this->getElement($element);
        $temp->isValid(true);

        return $this->getElement($element)
                    ->setValidators($temp->getValidators())
                    ->getValidator($validator);
    }
P4Cms_Form::getFlattenedValues ( )

Get the values of the form flattened with array notation for keys.

Returns:
array the flattened form values.
    {
        $filter = new P4Cms_Filter_FlattenArray;
        return $filter->filter($this->getValues());
    }
P4Cms_Form::getIdPrefix ( )

Get the string used to prefix element ids.

Returns:
string the string used to prefix element ids.
    {
        return $this->_idPrefix;
    }
static P4Cms_Form::getLibraryPathRegistry ( ) [static]

Get any library prefix paths that are statically registered.

Returns:
array the list of registered library prefix paths.
P4Cms_Form::getMessages ( name = null,
suppressArrayNotation = false 
)

Retrieve error messages from elements failing validations.

Fix for an issue where output from parent method is not consistent with the form structure when form contains nested sub-forms with 'isArray' flag set to false. See description for getValues() method where we fix the same issue.

Parameters:
string$namea element or sub-form to get messages for.
bool$suppressArrayNotationzend provides no description for this param.
Returns:
array list of error messages organized by element/sub-form
    {
        if (null !== $name) {
            if (isset($this->_elements[$name])) {
                return $this->getElement($name)->getMessages();
            } else if (isset($this->_subForms[$name])) {
                return $this->getSubForm($name)->getMessages(null, true);
            }
            foreach ($this->getSubForms() as $key => $subForm) {
                if ($subForm->isArray()) {
                    $belongTo = $subForm->getElementsBelongTo();
                    if ($name == $this->_getArrayName($belongTo)) {
                        return $subForm->getMessages(null, true);
                    }
                }
            }
        }

        $customMessages = $this->_getErrorMessages();
        if ($this->isErrors() && !empty($customMessages)) {
            return $customMessages;
        }

        $messages = array();

        foreach ($this->getElements() as $name => $element) {
            $eMessages = $element->getMessages();
            if (!empty($eMessages)) {
                $messages[$name] = $eMessages;
            }
        }

        foreach ($this->getSubForms() as $key => $subForm) {
            $merge = $subForm->getMessages(null, true);
            if (!empty($merge)) {
                if ($subForm->isArray()) {
                    $merge = $this->_attachToArray(
                        $merge,
                        $subForm->getElementsBelongTo()
                    );
                }
                $messages = $this->_array_replace_recursive($messages, $merge);
            }
        }

        if (!$suppressArrayNotation &&
            $this->isArray() &&
            !$this->_getIsRendered()) {
            $messages = $this->_attachToArray($messages, $this->getElementsBelongTo());
        }

        return $messages;
    }
static P4Cms_Form::getPrefixPathRegistry ( ) [static]

Get any plugin prefix paths that are statically registered.

Returns:
array the list of registered plugin prefix paths.
    {
        return static::$_prefixPaths;
    }
P4Cms_Form::getStorageAdapter ( )

Get the storage adapter used by this form to access records.

Returns:
P4Cms_Record_Adapter the adapter used by this form.
    {
        if ($this->_storageAdapter instanceof P4Cms_Record_Adapter) {
            return $this->_storageAdapter;
        }

        throw new P4Cms_Form_Exception(
            "Cannot get storage adapter. Adapter has not been set."
        );
    }
P4Cms_Form::getValues ( suppressArrayNotation = false)

Retrieve all form element values.

Override parent to fix an issue where form structure and form->getValues() are inconsistent if form has a sub-form with 'isArray' property set to false.

See: http://framework.zend.com/issues/browse/ZF-12027

Parameters:
bool$suppressArrayNotationzend provides no description for this param.
Returns:
array all form values organized by element/sub-form.

Reimplemented in Menu_Form_MenuItem, and Menu_Form_MenuItemMvc.

    {
        $values = array();
        $eBelongTo = null;

        if ($this->isArray()) {
            $eBelongTo = $this->getElementsBelongTo();
        }

        foreach ($this->getElements() as $key => $element) {
            if (!$element->getIgnore()) {
                $merge = array();
                if (($belongsTo = $element->getBelongsTo()) !== $eBelongTo) {
                    if ('' !== (string)$belongsTo) {
                        $key = $belongsTo . '[' . $key . ']';
                    }
                }
                $merge = $this->_attachToArray($element->getValue(), $key);
                $values = $this->_array_replace_recursive($values, $merge);
            }
        }
        foreach ($this->getSubForms() as $key => $subForm) {
            $merge = array();
            if (!$subForm->isArray()) {
                $merge = $subForm->getValues();
            } else {
                $merge = $this->_attachToArray(
                    $subForm->getValues(true),
                    $subForm->getElementsBelongTo()
                );
            }
            $values = $this->_array_replace_recursive($values, $merge);
        }

        if (!$suppressArrayNotation &&
            $this->isArray() &&
            !$this->_getIsRendered()) {
            $values = $this->_attachToArray($values, $this->getElementsBelongTo());
        }

        return $values;
    }
P4Cms_Form::hasCsrfProtection ( )

Returns whether or not this form has csrf protection enabled.

Protection is always turned off for anonymous users. For authenticated users protection is on by default but can optionally be disabled.

Returns:
boolean whether or not csrf protection is enabled for the form
    {
        return $this->_csrfProtection
            && P4Cms_User::hasActive()
            && !P4Cms_User::fetchActive()->isAnonymous();
    }
P4Cms_Form::isValid ( data)

Validate the form, including csrf check.

Parameters:
array$datathe data to validate.
Returns:
boolean

Reimplemented in Category_Form_Manage, Content_Form_Type, Menu_Form_MenuItem, Menu_Form_MenuItemContentQuick, Menu_Form_MenuItemMvc, Setup_Form_Administrator, Setup_Form_Site, Setup_Form_Storage, Site_Form_Branch, User_Form_Add, User_Form_AddRole, User_Form_Edit, Workflow_Form_Workflow, P4Cms_Form_PubSubForm, Analytics_Form_Configure, and Flickr_Form_Configure.

    {
        $isValid = parent::isValid($data);

        // validate the CSRF token if protection is enabled
        if ($this->hasCsrfProtection()) {
            if (array_key_exists(static::CSRF_TOKEN_NAME, $data)) {
                $this->_populatedCsrfToken = $data[static::CSRF_TOKEN_NAME];
            }
            if ($this->getPopulatedCsrfToken() != static::getCsrfToken()) {
                $isValid = false;
                $this->addError('Form failed security validation.');
            }
        }

        return $isValid;
    }
P4Cms_Form::loadDefaultDecorators ( )

Add "Errors" and "CsrfForm" to the default set of decorators.

Returns:
void
    {
        if ($this->loadDefaultDecoratorsIsDisabled()) {
            return;
        }

        $decorators = $this->getDecorators();
        $prepend    = Zend_Form_Decorator_Abstract::PREPEND;
        if (empty($decorators)) {
            $this->addDecorator('FormElements')
                 ->addDecorator('HtmlTag', array('tag' => 'dl', 'class' => 'zend_form_dojo'))
                 ->addDecorator('Errors',  array('placement' => $prepend))
                 ->addDecorator('Csrf',    array('placement' => $prepend))
                 ->addDecorator('DijitForm');
        }
    }
static P4Cms_Form::moveCheckboxLabel ( Zend_Form_Element $  element) [static]

Helper function to adjust decorators on checkbox element to position the checkbox label to the right of the checkbox, instead of on the left hand side.

Parameters:
Zend_Form_Element$elementthe element to adjust decorators on.
Returns:
Zend_Form_Element the updated element.
    {
        // adjust how the auto-label element is decorated
        // to put the label immediately after the checkbox.
        $decorators = array(
            'Zend_Form_Decorator_ViewHelper' => null,
            'P4Cms_Form_Decorator_Label'     => null
        );
        $element->setDecorators(array_merge($decorators, $element->getDecorators()));
        $element->getDecorator('label')
                ->setOption('placement', 'append')
                ->setOption('tag', null);

        return $element;
    }
static P4Cms_Form::normalizeSubForm ( form,
name = null 
) [static]

Ensure consistent presentation of sub-forms.

Parameters:
Zend_Form$formthe sub-form to normalize.
string$namethe name of the sub-form.
Returns:
Zend_Form the updated form.
    {
        $name = $name ?: $form->getName();

        $form->setDecorators(
            array(
                'FormElements',
                array(
                    'decorator' => 'HtmlTag',
                    'options'   => array('tag' => 'dl')
                ),
                'Fieldset',
                array(
                    'decorator' => array('DdTag' => 'HtmlTag'),
                    'options'   => array('tag'   => 'dd')
                ),
            )
        );

        // ensure form is identified with a css class.
        $class = $name ? $name . '-sub-form' : '';
        if (!preg_match("/(^| )$class( |$)/", $form->getAttrib('class'))) {
            $form->setAttrib('class', trim($class . ' ' . $form->getAttrib('class')));
        }

        // normalized sub-forms should always put values in an array.
        $form->setIsArray(true);

        return $form;
    }
P4Cms_Form::populate ( values)

Populate form.

Records CSRF token, if enabled and present, for later use, then calls the parent populate method.

Parameters:
P4Cms_Record | array$valuesthe values to populate from
Returns:
P4Cms_Form provides fluent interface

Reimplemented in Content_Form_Content, and P4Cms_Form_PubSubForm.

    {
        if ($this->hasCsrfProtection() && array_key_exists(static::CSRF_TOKEN_NAME, $values)) {
            $this->_populatedCsrfToken = $values[static::CSRF_TOKEN_NAME];
        }

        return $this->setDefaults($values);
    }
static P4Cms_Form::prefixFormIds ( Zend_Form $  form,
prefix 
) [static]

Prefix the ids of all elements, fieldsets and sub-forms within a form.

Parameters:
Zend_Form$forma specific form to prefix the ids of.
string$prefixthe prefix to use
    {
        // prefix id of form itself.
        static::_applyIdPrefix($form, $prefix);

        // prefix elements in form.
        foreach ($form->getElements() as $element) {
            static::_applyIdPrefix($element, $prefix);
        }

        // prefix display groups.
        foreach ($form->getDisplayGroups() as $displayGroup) {
            static::_applyIdPrefix($displayGroup, $prefix);
        }

        // prefix sub-forms.
        foreach ($form->getSubForms() as $subForm) {
            $subForm->setIdPrefix($prefix);
        }
    }
static P4Cms_Form::registerPrefixPath ( prefix,
path,
type 
) [static]

Add a form plugin path to be used whenever a form is instantiated.

Parameters:
string$prefixthe class prefix (e.g. Foo_Form_Element)
string$paththe path containing the classes
string$typethe type of plugin (e.g. element, decorator validator, filter)
    {
        static::$_prefixPaths[$prefix] = array(
            'prefix'    => $prefix,
            'path'      => $path,
            'type'      => strtoupper($type)
        );
    }
P4Cms_Form::render ( Zend_View_Interface $  view = null)

Add id prefixes, then render the form.

Parameters:
Zend_View_Interface$viewThe Zend View Interface to render.
Returns:
string
    {
        // prefix form element ids if id prefix is set.
        if ($this->getIdPrefix()) {
            static::prefixFormIds($this, $this->getIdPrefix());
        }

        return parent::render($view);
    }
P4Cms_Form::setCsrfProtection ( csrf)

Enables or disables the csrf protection for this form; defaults to enabled.

Parameters:
boolean$csrfWhether or not to enable csrf protection
Returns:
P4Cms_Form provides fluid interface
    {
        $this->_csrfProtection = (boolean)$csrf;
        return $this;
    }
P4Cms_Form::setDefaults ( defaults)

Set element values.

Extended here to support setting values from a record object. Accepting a record object allows 'enhanced' elements to look at other aspects of the record and make decisions accordingly.

Parameters:
P4Cms_Record | array$defaultsthe default values to set on elements
Returns:
Zend_Form provides fluent interface

Reimplemented in Menu_Form_MenuItem, Menu_Form_MenuItemContent, Menu_Form_MenuItemContentQuick, Menu_Form_MenuItemMvc, Setup_Form_Site, and Site_Form_Branch.

    {
        // handle record input.
        if ($defaults instanceof P4Cms_Record) {
            $record   = $defaults;
            $defaults = $record->getValues();

            // handle enhanced elements.
            foreach ($defaults as $field => $value) {
                $element = $this->getElement($field);
                if ($element instanceof P4Cms_Record_EnhancedElementInterface) {
                    $element->populateFromRecord($record);
                    unset($defaults[$field]);
                }
            }
        }

        // Zend form has a strange behavior where sub-forms will populate
        // from the entire values array, rather than their designated portion
        // of the values array if there is no matching key in defaults for
        // the sub-form (e.g. from $defaults instead of $defaults['subForm'])
        // and parent form has no element matching the key.
        //
        // This can have some unfortunate side-effects (top-level values
        // polluting the sub-forms) - to avoid this problem we ensure that
        // there is an entry in the defaults array for every sub-form.
        //
        // Example:
        // assuming we have a $form with element [foo] and a sub-form 'subForm'
        // with elements [foo] and [bar], then
        //    $form->setDefaults(array('foo' => 'foo_value'))
        // will populate only [foo] element, whereas
        //    $form->setDefaults(array('bar' => 'bar_value'))
        // will populate [subForm][bar] element. This fix is to prevent the
        // second case above (i.e. [subForm][bar] will be populated only if
        // defaults array contains 'subForm' => array('bar' => 'bar_value').
        foreach ($this->getSubForms() as $subForm) {
            $key = $subForm->getElementsBelongTo();
            if ($subForm->isArray() && !isset($defaults[$key])) {
                $defaults[$key] = array();
            }
        }

        return parent::setDefaults($defaults);
    }
P4Cms_Form::setIdPrefix ( prefix)

Set a string to prefix element ids with.

Parameters:
string$prefixthe string to prefix element ids with.
Returns:
P4Cms_Form_Decorator_IdPrefix the decorator instance.
    {
        $this->_idPrefix = (string) $prefix;
        return $this;
    }
P4Cms_Form::setStorageAdapter ( P4Cms_Record_Adapter adapter)

Set the storage adapter to use to access records.

Parameters:
P4Cms_Record_Adapter$adapterthe adapter to use for record access
Returns:
P4Cms_Form provides fluent interface.
    {
        $this->_storageAdapter = $adapter;

        return $this;
    }

Member Data Documentation

P4Cms_Form::$_csrfProtection = true [protected]
P4Cms_Form::$_idPrefix = null [protected]
P4Cms_Form::$_libraryPaths [static, protected]
P4Cms_Form::$_populatedCsrfToken = '' [protected]
P4Cms_Form::$_prefixPaths = array() [static, protected]
P4Cms_Form::$_session = null [static, protected]
P4Cms_Form::$_storageAdapter = null [protected]
const P4Cms_Form::CSRF_TOKEN_NAME = '_csrfToken'
const P4Cms_Form::UTF8_NBSP = "\xc2\xa0"

Useful for indenting items (e.g.

in select elements)


The documentation for this class was generated from the following file: