Job.php #1

  • //
  • guest/
  • perforce_software/
  • chronicle/
  • main/
  • library/
  • P4/
  • Job.php
  • View
  • Commits
  • Open Download .zip Download (13 KB)
<?php
/**
 * Abstracts operations against Perforce jobs.
 *
 * @license     Please see LICENSE.txt in top-level folder of this distribution.
 * @version     <release>/<patch>
 * @todo        Add support for the following commands:
 *              fix
 *              fixes
 */
class P4_Job extends P4_Spec_PluralAbstract
{
    const   FETCH_BY_FILTER         = 'filter';
    const   FETCH_DESCRIPTION       = 'descriptions';

    protected static    $_specType  = 'job';
    protected static    $_idField   = 'Job';

    protected static    $_accessors = array(
        102             => 'getStatus',
        103             => 'getUser',
        104             => 'getDate',
        105             => 'getDescription',
    );
    protected static    $_mutators  = array(
        102             => 'setStatus',
        103             => 'setUser',
        105             => 'setDescription',
    );

    /**
     * Get field value. If a custom field accessor exists, it will be used.
     * Extends parent to add support for accessors keyed on field code instead of name.
     *
     * @param   string  $field  the name of the field to get the value of.
     * @return  mixed   the value of the field.
     * @throws  P4_Spec_Exception   if the field does not exist.
     */
    public function getValue($field)
    {
        // if field has custom accessor based on field code, use it.
        $fieldCode = $this->_fieldNameToCode($field);
        if (isset(static::$_accessors[$fieldCode])) {
            return $this->{static::$_accessors[$fieldCode]}();
        }

        return parent::getValue($field);
    }

    /**
     * Set field value. If a custom field mutator exists, it will be used.
     * Extends parent to add support for mutators keyed on field code instead of name.
     *
     * @param   string  $field  the name of the field to set the value of.
     * @param   mixed   $value  the value to set in the field.
     * @return  P4_SpecAbstract     provides a fluent interface
     */
    public function setValue($field, $value)
    {
        // if field has custom mutator based on field code, use it.
        $fieldCode = $this->_fieldNameToCode($field);
        if (isset(static::$_mutators[$fieldCode])) {
            return $this->{static::$_mutators[$fieldCode]}($value);
        }

        return parent::setValue($field, $value);
    }

    /**
     * Get all Jobs from Perforce. Adds filtering options.
     *
     * @param   array   $options    optional - array of options to augment fetch behavior.
     *                              supported options are:
     *
     *                                   FETCH_MAXIMUM - set to integer value to limit to the
     *                                                   first 'max' number of entries.
     *                                 FETCH_BY_FILTER - set to jobview filter
     *                               FETCH_DESCRIPTION - description will be fetched if true,
     *                                                   left for later lazy loading if false.
     *                                                   * defaults to true if not specified
     * @param   P4_Connection_Interface $connection  optional - a specific connection to use.
     * @return  P4_Model_Iterator   all records of this type.
     */
    public static function fetchAll($options = array(), P4_Connection_Interface $connection = null)
    {
        // simply return parent - method exists to document options.
        return parent::fetchAll($options, $connection);
    }

    /**
     * Determine if the given job id exists.
     *
     * @param   string|int                  $id             the id to check for.
     * @param   P4_Connection_Interface     $connection     optional - a specific connection to use.
     * @return  bool    true if the given id matches an existing job.
     */
    public static function exists($id, P4_Connection_Interface $connection = null)
    {
        // check id for valid format
        if (!static::_isValidId($id)) {
            return false;
        }

        $jobs = static::fetchAll(
            array(
                static::FETCH_BY_FILTER => static::_getIdField() .'='. $id,
                static::FETCH_MAXIMUM   => 1
            ),
            $connection
        );

        return (bool) count($jobs);
    }

    /**
     * Override parent to set id to 'new' if unset and capture id returned by save.
     *
     * @return  P4_Job  provides a fluent interface
     */
    public function save()
    {
        $values = $this->_getValues();
        if ($this->getId() === null) {
            $values[static::_getIdField()] = "new";
        }

        // ensure all required fields have values.
        $this->_validateRequiredFields($values);

        $result = $this->getConnection()->run(static::_getSpecType(), "-i", $values);

        // Saved job Id is returned as a string, capture it.
        $data = $result->getData(0);

        if (!preg_match('/^Job ([^ ]+) saved\./', $data, $match)) {
            throw new P4_Spec_Exception('Cannot find ID for saved Job.');
        }

        // Store the retrieved ID
        $this->setId($match[1]);

        // should re-populate (server may change values).
        $this->_deferPopulate(true);

        return $this;
    }

    /**
     * Returns the status of this job. This will return the value of field 102 even if the
     * field name has been changed in the jobspec.
     *
     * Out of the box valid status options are: open/suspended/closed or null. Modifying the
     * jobspec can change the list of valid options.
     *
     * @return  string|null     Status of this job or null if unset.
     */
    public function getStatus()
    {
        return $this->_getValue($this->_fieldCodeToName(102));
    }

    /**
     * Update the status of this job. This will update the value of field 102 even if the
     * field name has been changed in the jobspec.
     *
     * @param   string|null $status Status of this job or null
     * @return  P4_Job  provides a fluent interface.
     * @throws  InvalidArgumentException    For input which isn't a string or null
     */
    public function setStatus($status)
    {
        if (!is_string($status) && !is_null($status)) {
            throw new InvalidArgumentException('Status must be a string or null');
        }

        return $this->_setValue($this->_fieldCodeToName(102), $status);
    }


    /**
     * Returns the user who created this job. This will return the value of field 103
     * even if the field name has been changed in the jobspec.
     *
     * @return  string|null     User who created this job or null if unset.
     */
    public function getUser()
    {
        return $this->_getValue($this->_fieldCodeToName(103));
    }

    /**
     * Update the user who created this job. This will update the value of field 103
     * even if the field name has been changed in the jobspec.
     *
     * @param   string|P4_User|null $user User who created this job, or null
     * @return  P4_Job  provides a fluent interface.
     * @throws  InvalidArgumentException    For input which isn't a string, P4_User or null
     */
    public function setUser($user)
    {
        if ($user instanceof P4_User) {
            $user = $user->getId();
        }

        if (!is_null($user) && !is_string($user)) {
            throw new InvalidArgumentException('User must be a string, P4_User or null');
        }

        return $this->_setValue($this->_fieldCodeToName(103), $user);
    }

    /**
     * Returns the date this job was created. This will return the value of field 104
     * even if the field name has been changed in the jobspec.
     *
     * @return  string|null     Date this job was created or null if unset.
     */
    public function getDate()
    {
        return $this->_getValue($this->_fieldCodeToName(104));
    }

    /**
     * Returns the description for this job. This will return the value of field 105
     * even if the field name has been changed in the jobspec.
     *
     * @return  string|null     Description for this job or null if unset.
     */
    public function getDescription()
    {
        return $this->_getValue($this->_fieldCodeToName(105));
    }

    /**
     * Update the decription for this job. This will update the value of field 105
     * even if the field name has been changed in the jobspec.
     *
     * @param   string|null $description    Description for this job, or null
     * @return  P4_Job  provides a fluent interface.
     * @throws  InvalidArgumentException    For input which isn't a string or null
     */
    public function setDescription($description)
    {
        if (!is_null($description) && !is_string($description)) {
            throw new InvalidArgumentException('Description must be a string or null');
        }

        return $this->_setValue($this->_fieldCodeToName(105), $description);
    }

    /**
     * Produce set of flags for the spec list command, given fetch all options array.
     * Extends parent to add support for filter option.
     *
     * @param   array   $options    array of options to augment fetch behavior.
     *                              see fetchAll for documented options.
     * @return  array   set of flags suitable for passing to spec list command.
     */
    protected static function _getFetchAllFlags($options)
    {
        $flags = parent::_getFetchAllFlags($options);

        if (isset($options[static::FETCH_BY_FILTER])) {
            $filter = $options[static::FETCH_BY_FILTER];

            if (!is_string($filter) || trim($filter) === "") {
                throw new InvalidArgumentException(
                    'Fetch by Filter expects a non-empty string as input'
                );
            }

            $flags[] = '-e';
            $flags[] = $filter;
        }

        // if they have not specified FETCH_DESCRIPTION or
        // they have and its true; include full descriptions
        if (!isset($options[static::FETCH_DESCRIPTION]) ||
            $options[static::FETCH_DESCRIPTION]) {
            $flags[] = '-l';
        }

        return $flags;
    }

    /**
     * Check if the given id is in a valid format for this spec type.
     *
     * @param   string|int  $id     the id to check
     * @return  bool        true if id is valid, false otherwise
     */
    protected static function _isValidId($id)
    {
        $validator = new P4_Validate_SpecName;
        $validator->allowPurelyNumeric(true);
        return $validator->isValid($id);
    }

    /**
     * Extends parent to control description inclusion based on FETCH options.
     *
     * @param   array                       $listEntry      a single spec entry from spec list output.
     * @param   array                       $flags          the flags that were used for this 'fetchAll' run.
     * @param   P4_Connection_Interface     $connection     a specific connection to use.
     * @return  P4_Job                      a (partially) populated instance of this spec class.
     */
    protected static function _fromSpecListEntry($listEntry, $flags, P4_Connection_Interface $connection)
    {
        // discard the description if it isn't the 'long' version
        if (!in_array('-l', $flags)) {
            unset($listEntry['Description']);
        }

        return parent::_fromSpecListEntry($listEntry, $flags, $connection);
    }

    /**
     * Given a field name this function will return the associated field code.
     *
     * @param   string  $name   String representing the field's name.
     * @return  int     The field code associated with the passed name.
     */
    protected function _fieldNameToCode($name)
    {
        $field = $this->getSpecDefinition()->getField($name);

        return (int) $field['code'];
    }

    /**
     * Given a field code this function will return the associated field name.
     *
     * @param   int|string  $code   Int or string representing value between 101-199 inclusive.
     * @return  string  The field name associated with the passed code
     * @throws  InvalidArgumentException    If passed an invalid or non-existent field code
     */
    protected function _fieldCodeToName($code)
    {
        // if we are passed a string, and casting through int doesn't change it,
        // it is purely numeric, cast to an int.
        if (is_string($code) &&
            $code === (string)(int)$code) {
            $code = (int)$code;
        }

        // if we made it this far, fail unless we have an int
        if (!is_int($code)) {
            throw new InvalidArgumentException('Field must be a purely numeric string or int.');
        }

        // job spec defines this is the valid range for field id's
        if ($code < 101 || $code > 199) {
            throw new InvalidArgumentException('Field code must be between 101 and 199 inclusive.');
        }

        $fields = $this->getSpecDefinition()->getFields();

        foreach ($fields as $name => $field) {
            if ($field['code'] == $code) {
                return $name;
            }
        }

        throw new InvalidArgumentException('Specified field code does not exist.');
    }
}
# Change User Description Committed
#1 16170 perforce_software Move Chronicle files to follow new path scheme for branching.
//guest/perforce_software/chronicle/library/P4/Job.php
#1 8972 Matt Attaway Initial add of the Chronicle source code