Adapter.php #1

  • //
  • guest/
  • perforce_software/
  • chronicle/
  • main/
  • library/
  • P4Cms/
  • Record/
  • Adapter.php
  • View
  • Commits
  • Open Download .zip Download (10 KB)
<?php
/**
 * Encapsulates everything needed for Records to read from and write
 * to storage. Specifically, a p4 connection, a base path in perforce,
 * and a prefix for sequence counters.
 *
 * @copyright   2011 Perforce Software. All rights reserved.
 * @license     Please see LICENSE.txt in top-level folder of this distribution.
 * @version     <release>/<patch>
 * @todo        consider adding callbacks for batch operations (e.g.
 *              preCommit, postCommit, commitError, revertBatch, etc.)
 */
class P4Cms_Record_Adapter
{
    const               COMMIT_THROW_CONFLICT = "throw";

    protected           $_basePath            = null;
    protected           $_connection          = null;
    protected           $_batchId             = null;
    protected           $_properties          = array();

    /**
     * Get the connection object to use to communicate with Perforce.
     *
     * @return  P4_Connection_Abstract  the p4 connection to use.
     * @throws  P4Cms_Record_Exception  if no valid connection is set.
     */
    public function getConnection()
    {
        if (!$this->_connection instanceof P4_Connection_Abstract) {
            throw new P4Cms_Record_Exception(
                "Cannot get connection. No valid p4 connection has been set."
            );
        }

        return $this->_connection;
    }

    /**
     * Set the Perforce connection to use to communicate with the
     * Perforce backend.
     *
     * @param   P4_Connection_Abstract  $p4     the p4 connection to use.
     * @return  P4Cms_Record_Adapter    provides fluent interface.
     * @throws  P4Cms_Record_Exception  if the connection object is invalid.
     */
    public function setConnection($p4)
    {
        if (!$p4 instanceof P4_Connection_Abstract) {
            throw new P4Cms_Record_Exception(
                "Cannot set connection. The given argument is not a valid p4 connection."
            );
        }

        $this->_connection = $p4;
        return $this;
    }

    /**
     * Get the base path in Perforce under which records should be
     * read from and written to.
     *
     * @return  string                  the record storage base path.
     * @throws  P4Cms_Record_Exception  if no base path is set.
     */
    public function getBasePath()
    {
        if (!is_string($this->_basePath) || !strlen($this->_basePath)) {
            throw new P4Cms_Record_Exception(
                "Cannot get base path. No base path is set."
            );
        }

        return $this->_basePath;
    }

    /**
     * Set the base path in Perforce under which records should be
     * read from and written to.
     *
     * @param   string  $path           the record storage base path.
     * @return  P4Cms_Record_Adapter    provides fluent interface.
     * @throws  P4Cms_Record_Exception  if the base path is not a valid string.
     */
    public function setBasePath($path)
    {
        if (!is_string($path) || !strlen($path)) {
            throw new P4Cms_Record_Exception(
                "Cannot set base path. Given path is not a valid string."
            );
        }

        $this->_basePath = $path;
        return $this;
    }

    /**
     * Check if adapter has a particular property.
     *
     * @param   string  $name   the property name to check for the existence of
     * @return  boolean         true if the adapter has the named property, false otherwise.
     */
    public function hasProperty($name)
    {
        return array_key_exists($name, $this->_properties);
    }

    /**
     * Get a particular property value of this adapter.
     *
     * @param   string  $name           name of the property to get the value of
     * @return  mixed                   the value of the property name
     * @throws  P4Cms_Record_Exception  if the property name does not exist
     */
    public function getProperty($name)
    {
        // return property value if it was set, otherwise throw an exception
        if ($this->hasProperty($name)) {
            return $this->_properties[$name];
        }

        throw new P4Cms_Record_Exception(
            "Cannot find adapter property '$name'. Property was not set."
        );
    }

    /**
     * Get all properties of this adapter.
     *
     * @return  array   all properties set to this adapter
     */
    public function getProperties()
    {
        return $this->_properties;
    }

    /**
     * Set a particular property of this adapter.
     *
     * @param   string                  $name   name of the property to set the value of
     * @param   mixed                   $value  value to set
     * @return  P4Cms_Record_Adapter            provides a fluent interface
     */
    public function setProperty($name, $value)
    {
        $this->_properties[$name] = $value;
        return $this;
    }

    /**
     * Set adapter properties.
     *
     * @param   array   $properties     array with properties to set
     * @return  P4Cms_Record_Adapter    provides fluent interface
     */
    public function setProperties(array $properties)
    {
        $this->_properties = $properties;
        return $this;
    }

    /**
     * Start a batch. Changes made to records will be
     * placed in a numbered pending change and will not be
     * submitted until the batch is committed.
     *
     * Batches cannot be nested. Attempting to begin a
     * batch while in a batch will result in an
     * exception.
     *
     * @param   string  $description    required - a description of the batch.
     * @return  P4Cms_Record_Adapter    provides fluent interface.
     * @throws  P4Cms_Record_Exception  if already in a batch.
     * @todo    automatically aggregate descriptions when in batches.
     */
    public function beginBatch($description)
    {
        if ($this->inBatch()) {
            throw new P4Cms_Record_Exception(
                "Cannot begin batch. Already in a batch."
            );
        }

        // create a new pending change.
        $change = new P4_Change($this->getConnection());
        $change->setDescription($description)->save();

        return $this->_batchId = $change->getId();
    }

    /**
     * Commit the batch. Submits the pending change
     * corresponding to the batch id.
     *
     * @param   string              $description    optional - a final description of the batch.
     * @param   null|string|array   $options        optional - passing the SAVE_THROW_CONFLICTS
     *                                              flag will cause exceptions on conflict; default
     *                                              behaviour is to crush any conflicts.
     * @return  P4Cms_Record_Adapter    provides fluent interface.
     * @throws  P4Cms_Record_Exception  if not in a batch.
     */
    public function commitBatch($description = null, $options = null)
    {
        if (!$this->inBatch()) {
            throw new P4Cms_Record_Exception(
                "Cannot commit batch. Not in a batch."
            );
        }

        // submit the change identified by batch id.
        $change = P4_Change::fetch(
            $this->getBatchId(),
            $this->getConnection()
        );
        try {
            // default option is to 'accept yours' but we switch to
            // null if SAVE_THROW_CONFLICTS flag is passed.
            $resolveFlag = P4_Change::RESOLVE_ACCEPT_YOURS;
            if (in_array(static::COMMIT_THROW_CONFLICT, (array)$options)) {
                $resolveFlag = null;
            }

            $change->submit($description, $resolveFlag);
        } catch (P4_Connection_CommandException $e) {
            // ignore exception if change is empty - otherwise rethrow.
            if (count($change->getFiles()) == 0) {
                $change->delete();
            } else {
                throw $e;
            }
        }

        // clear the batch id.
        $this->_batchId = null;

        return $this;
    }

    /**
     * Reverts all files in the pending change corresponding to
     * the batch id.
     *
     * @return  P4Cms_Record_Adapter    provides fluent interface.
     * @throws  P4Cms_Record_Exception  if not in a batch.
     * @todo    automatically revert batches when unhandled exceptions/errors occur.
     */
    public function revertBatch()
    {
        if (!$this->inBatch()) {
            throw new P4Cms_Record_Exception(
                "Cannot revert batch. Not in a batch."
            );
        }

        // revert the change identified by batch id.
        $change = P4_Change::fetch(
            $this->getBatchId(),
            $this->getConnection()
        );
        $change->revert()
               ->delete();

        // clear the batch id.
        $this->_batchId = null;

        return $this;
    }

    /**
     * Get the id of the current batch. The batch id
     * corresponds to a pending changelist in Perforce.
     *
     * @return  int                     the batch id (pending change number).
     * @throws  P4Cms_Record_Exception  if not in a batch.
     */
    public function getBatchId()
    {
        if (!$this->inBatch()) {
            throw new P4Cms_Record_Exception(
                "Cannot get batch id. Not in a batch."
            );
        }

        return (int) $this->_batchId;
    }

    /**
     * Determine if we are currently in a batch on this
     * storage adapter.
     *
     * @return  bool    true if we are in a batch.
     */
    public function inBatch()
    {
        $id = $this->_batchId;
        return (int) $id > 0;
    }

    /**
     * Change the description of the current batch
     *
     * @param   string  $description    the description of the current batch.
     * @return  P4Cms_Record_Adapter    provides fluent interface.
     */
    public function setBatchDescription($description)
    {
        $change = P4_Change::fetch(
            $this->getBatchId(),
            $this->getConnection()
        );
        $change->setDescription($description)
               ->save();

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