File.php #1

  • //
  • guest/
  • perforce_software/
  • chronicle/
  • main/
  • application/
  • content/
  • forms/
  • elements/
  • File.php
  • View
  • Commits
  • Open Download .zip Download (10 KB)
<?php
/**
 * Extends Zend_Form_Element_File to provide support to
 * keep/remove/replace existing files and to enhance for
 * use with content records.
 *
 * Adds options to display a icon for an existing file.
 * Adds method to get the uploaded file contents.
 *
 * @copyright   2011 Perforce Software. All rights reserved.
 * @license     Please see LICENSE.txt in top-level folder of this distribution.
 * @version     <release>/<patch>
 */
class Content_Form_Element_File
    extends     Zend_Form_Element_File
    implements  P4Cms_Content_EnhancedElementInterface,
                P4Cms_Record_EnhancedElementInterface
{
    const       ACTION_KEEP         = 'keep';
    const       ACTION_REMOVE       = 'remove';
    const       ACTION_REPLACE      = 'replace';

    protected   $_contentRecord     = null;
    protected   $_existingFileInfo  = null;
    protected   $_formData          = null;

    /**
     * Set information about an existing file.
     *
     * Info can be set by passing an array of key/value pairs, or
     * by passing a string (key) as the first argument and a value
     * for the second argument to set a specific property.
     *
     * If there is an existing file, but nothing is known about
     * it, pass an empty array. Setting to false or null will indicate
     * there is no existing file (the default case).
     *
     * File info may contain any key/value pairs. The following keys
     * are used to inform how the file element is rendered:
     *
     *  - filename
     *  - mimeType
     *  - iconUri
     *
     * @param   array|string    $info   information about an existing file
     *                                  if a string is given, sets the named
     *                                  key in the file info array.
     * @param   string          $value  optional - value to set when called
     *                                  with a string (key) for the first param.
     * @return  P4Cms_Form_Element_ImageFile    provides fluent interface.
     */
    public function setExistingFileInfo($info, $value = null)
    {
        if (is_string($info)) {
            $key        = $info;
            $info       = $this->_existingFileInfo ?: array();
            $info[$key] = $value;
        }

        $this->_existingFileInfo = $info;

        return $this;
    }

    /**
     * Get any available information about an existing file.
     *
     * @return  array   information about an existing file
     *                  false if no existing file is set.
     */
    public function getExistingFileInfo()
    {
        if ($this->hasExistingFile()) {
            return $this->_existingFileInfo;
        }

        return false;
    }

    /**
     * Determine if this field has an existing file set.
     * Set existing file info to indicate there is an existing file.
     *
     * @return  bool    true if there is an existing file; false otherwise.
     */
    public function hasExistingFile()
    {
        if (is_array($this->_existingFileInfo)
            || array_key_exists($this->getActionFieldName(), $this->getFormData())
        ) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * Determine if the existing file has been marked for removal.
     *
     * @return  bool    true if the file is marked for removal; false otherwise.
     */
    public function isRemoved()
    {
        return ($this->getActionFieldValue() === self::ACTION_REMOVE);
    }

    /**
     * Determine if the existing file has been marked for replacement.
     *
     * @return  bool    true if the file is marked for replacement; false otherwise.
     */
    public function isReplaced()
    {
        return ($this->getActionFieldValue() === self::ACTION_REPLACE);
    }

    /**
     * Get the name of the action field (which indicates the disposition
     * of the existing file). Derived from this file element's name.
     *
     * @return  string  the name of the 'action' field associated with this file input.
     */
    public function getActionFieldName()
    {
        return $this->getName() . "-existing-file-action";
    }

    /**
     * Get the action for the existing file (e.g. keep, remove, replace).
     * Defaults to 'keep'.
     *
     * @return  string  the value of the existing file action field.
     */
    public function getActionFieldValue()
    {
        $data   = $this->getFormData();
        $action = $this->getActionFieldName();
        return array_key_exists($action, $data) ? $data[$action] : self::ACTION_KEEP;
    }

    /**
     * Get the contents of the uploaded file on the server.
     */
    public function getFileContent()
    {
        return file_get_contents($this->getFileTempName());
    }

    /**
     * Get the temporary name of the uploaded file on the server.
     */
    public function getFileTempName()
    {
        if (!$this->isUploaded()) {
            throw new Content_Exception("Cannot get file temp name if file not uploaded.");
        }

        $fileInfo = $this->getFileInfo();
        return $fileInfo[$this->getName()]['tmp_name'];
    }

    /**
     * Set the form data from which the existing file action will be read.
     * Normally it is unnecessary to set this as the element will read from
     * $_POST by default.
     *
     * @param   array   $data                   the form data to pull the file action from.
     * @return  P4Cms_Form_Element_ImageFile    provides fluent interface.
     */
    public function setFormData($data)
    {
        $this->_formData = $data;
    }

    /**
     * Get the form data from which the existing file action will be read.
     * Reads from $_POST directly unless data has been explicitly set via
     * setFormData().
     *
     * @return  array   the form data to pull file action from.
     */
    public function getFormData()
    {
        return isset($this->_formData) ? $this->_formData : $_POST;
    }

    /**
     * Get the associated content record (if set).
     *
     * @return  null|P4Cms_Content  the associated content record or null if none set.
     */
    public function getContentRecord()
    {
        return $this->_contentRecord;
    }

    /**
     * Set the associated content record for this element.
     *
     * @param   P4Cms_Content   $content  the associated content record for this element.
     */
    public function setContentRecord($content)
    {
        $this->_contentRecord = $content;
    }

    /**
     * Get the default display decorators to use when rendering
     * content elements of this type.
     *
     * @return  array   decorators configuration array suitable for passing
     *                  to element setDecorators().
     */
    public function getDefaultDisplayDecorators()
    {
        return array(
            array(
                'decorator' => 'DisplayFileLink',
                'options'   => array(
                    'placement' => Content_Form_Decorator_DisplayFileLink::REPLACE
                )
            )
        );
    }

    /**
     * Retrieve all validators; proxy to adapter
     *
     * @return array
     */
    public function getValidators()
    {
        $adapter    = $this->getTransferAdapter();
        $validators = $adapter->getValidators($this->getName());
        if (!$validators) {
            $validators = $adapter->getValidators();
        }

        return $validators;
    }

    /**
     * Validate upload
     * Overridden to handle content edit's "keep existing file" option.
     *
     * @param  string $value   File, can be optional, give null to validate all files
     * @param  mixed  $context optional context
     * @return bool
     */
    public function isValid($value, $context = null)
    {
        if ($this->_validated) {
            return true;
        }

        $isRequired = $this->isRequired();

        if ($isRequired
            && $this->hasExistingFile()
            && $this->getActionFieldValue() == self::ACTION_KEEP
        ) {
            $this->setRequired(false);
        }

        $result = parent::isValid($value, $context);

        $this->setRequired($isRequired);

        return $result;
    }

    /**
     * Set the file value on the given record.
     *
     * File elements require special handling. Three cases:
     *
     *  - File is flagged for removal, clear the record value and metadata.
     *  - New file is uploaded, set the record value and metadata.
     *  - Existing file is 'kept', do nothing.
     *
     * @param   P4Cms_Record    $record                 the record to populate
     * @return  P4Cms_Record_EnhancedElementInterface   provides fluent interface
     */
    public function populateRecord(P4Cms_Record $record)
    {
        $field = $this->getName();

        // if file is flagged for removal, clear it.
        if ($this->isRemoved()) {
            $record->setValue($field, null);
            $record->setFieldMetadata($field, null);
        }

        // if a new file has been uploaded, store it.
        if ($this->isUploaded() && ($this->isReplaced() || !$this->hasExistingFile())) {
            $record->setValueFromFile(
                $field,
                $this->getFileTempName(),
                basename($this->getFileName()),
                $this->getMimeType()
            );
        }

        return $this;
    }

    /**
     * Populate the file element from the given record.
     * If there is an existing file, set file info on the form.
     *
     * @param   P4Cms_Record    $record                 the record to populate from
     * @return  P4Cms_Record_EnhancedElementInterface   provides fluent interface
     */
    public function populateFromRecord(P4Cms_Record $record)
    {
        $field = $this->getName();

        // nothing to do if record doesn't have a field with this name.
        if (!$record->hasField($field)) {
            return $this;
        }

        $metadata = $record->getFieldMetadata($field);
        if (is_array($metadata) && !empty($metadata)) {
            $this->setExistingFileInfo($metadata);
        }

        return $this;
    }
}
# Change User Description Committed
#1 16170 perforce_software Move Chronicle files to follow new path scheme for branching.
//guest/perforce_software/chronicle/application/content/forms/elements/File.php
#1 8972 Matt Attaway Initial add of the Chronicle source code