Perforce Chronicle 2012.2/486814
API Documentation

P4Cms_Record_Volatile Class Reference

Provides volatile (unsubmitted/unversioned) storage in Perforce. More...

Inheritance diagram for P4Cms_Record_Volatile:
P4Cms_Record_Connected P4Cms_Model P4Cms_ModelInterface P4Cms_Content_Opened

List of all members.

Public Member Functions

 delete ()
 Remove the volatile record.
 getClientMasquerade ()
 Get the client workspace we are set to masquerade as.
 save ()
 Save the values in this volatile record to Perforce.
 setClientMasquerade ($client)
 Set the client workspace to masquerade as.
 setId ($id)
 Set the id of this record.

Static Public Member Functions

static exists ($id, $adapter, $masquerade=null)
 Check for the existance of a volatile record by id.
static fetch ($id, $adapter, $masquerade=null)
 Fetch a stored volatile record by id.

Public Attributes

const CLIENT = 'volatileClient'

Protected Member Functions

 _beginCharade ()
 Begin masquerading as another client/host.
 _endCharade ()
 Stop masquerading - restore original client/host.
 _getDepotFile ()
 Get the (depot-syntax formatted) path to this record in Perforce.
 _populate ()
 Load values into this record from Perforce.
 _runFree ($command, $params)
 Run a Perforce command with no exceptions.

Protected Attributes

 $_clientMasquerade = null
 $_depotFile = null
 $_originalClient = null
 $_originalHost = null
 $_storageSubPath = null

Detailed Description

Provides volatile (unsubmitted/unversioned) storage in Perforce.

This works by creating pending files and setting open attributes on those files. This storage is useful for casual data that has high turn-over or that we simply don't want to make permanent.

Opened attributes can only be viewed by the client workspace that set them. Therefore, this class introduces get/setClientMasquerade() methods that cause it to masquerade as another client workspace when executing Perforce commands.

Volatile records have many limitations:

  • much simpler than regular records
  • no support for file content fields
  • no support for fetching multiple records
  • only string values are supported
  • no auto-generation of ids
  • no lazy-loading
Copyright:
2011-2012 Perforce Software. All rights reserved
License:
Please see LICENSE.txt in top-level folder of this distribution.
Version:
2012.2/486814

Member Function Documentation

P4Cms_Record_Volatile::_beginCharade ( ) [protected]

Begin masquerading as another client/host.

    {
        // nothing to do if not masquerading.
        $masquerade = $this->getClientMasquerade();
        if (!$masquerade) {
            return;
        }

        $adapter = $this->getAdapter();
        $p4      = $adapter->getConnection();

        // clobber the current client and host, but remember
        // them so we can restore them afterwards.
        $this->_originalClient = $p4->getClient();
        $this->_originalHost   = $p4->getHost();
        $p4->setClient($masquerade->getId() ?: $p4->getClient());
        $p4->setHost($masquerade->getHost() ?: $p4->getHost());
    }
P4Cms_Record_Volatile::_endCharade ( ) [protected]

Stop masquerading - restore original client/host.

    {
        // nothing to do if not masquerading.
        if (!$this->_originalClient) {
            return;
        }

        $adapter = $this->getAdapter();
        $p4      = $adapter->getConnection();

        $p4->setClient($this->_originalClient);
        $p4->setHost($this->_originalHost);

        $this->_originalClient = null;
        $this->_originalHost   = null;
    }
P4Cms_Record_Volatile::_getDepotFile ( ) [protected]

Get the (depot-syntax formatted) path to this record in Perforce.

Returns:
string the path to this record in depot-syntax.
    {
        // must have an id to get depot file.
        if (!$this->getId()) {
            throw new P4Cms_Record_Exception("Cannot get record file path without an id.");
        }

        // convert id to depot file syntax if we haven't already.
        if (!$this->_depotFile) {
            $adapter = $this->getAdapter();
            $subPath = trim($this->_storageSubPath, '/\\');
            $subPath = $subPath ? '/' . $subPath . '/' : '/';
            $file    = $adapter->getBasePath() . $subPath . $this->getId();
            $result  = $adapter->getConnection()->run('where', $file);

            $this->_depotFile = $result->getData(0, 'depotFile');
        }

        return $this->_depotFile;
    }
P4Cms_Record_Volatile::_populate ( ) [protected]

Load values into this record from Perforce.

Clobbers any existing in-memory values.

Returns:
P4Cms_Record_Volatile provides fluent interface.
    {
        $file = $this->_getDepotFile();

        // masquerade as another client
        $this->_beginCharade();

        try {
            $result = $this->getAdapter()->getConnection()->run('fstat', array('-Oa', $file));

            // extract information if no warings (ie. file exists).
            if (!$result->hasWarnings()) {
                $this->_values = array();
                foreach ((array) $result->getData(0) as $key => $value) {
                    $parts = explode('-', $key, 2);
                    if (count($parts) !== 2 || $parts[0] !== 'openattr') {
                        continue;
                    }

                    $this->_setValue($parts[1], $value);
                }
            } else {
                // warnings indicate no such record.
                $e = new P4Cms_Record_NotFoundException(
                    "Cannot fetch record: " . $this->getId() . ". No matching record."
                );
            }
        } catch (Exception $e) {
            // look away!
        }

        // restore original client.
        $this->_endCharade();

        // if an exception occurred, throw it now.
        if (isset($e)) {
            throw $e;
        }

        return $this;
    }
P4Cms_Record_Volatile::_runFree ( command,
params 
) [protected]

Run a Perforce command with no exceptions.

Parameters:
string$commandthe command to run.
array | string$paramsoptional - one or more arguments.
Returns:
bool|P4_Result command result or false if it failed.
    {
        $adapter = $this->getAdapter();
        $p4      = $adapter->getConnection();

        try {
            return $p4->run($command, $params);
        } catch (P4_Exception $e) {
            return false;
        }
    }
P4Cms_Record_Volatile::delete ( )

Remove the volatile record.

Since volatile records are never submitted, this is actually a 'p4 revert' operation.

Returns:
P4Cms_Record_Volatile provides fluent interface.
    {
        $file = $this->_getDepotFile();

        // masquerade as another client
        $this->_beginCharade();

        try {
            $this->getAdapter()->getConnection()->run('revert', array('-k', $file));
        } catch (Exception $e) {
            // look away!
        }

        // restore original client.
        $this->_endCharade();

        // if an exception occurred, throw it now.
        if (isset($e)) {
            throw $e;
        }

        return $this;
    }
static P4Cms_Record_Volatile::exists ( id,
adapter,
masquerade = null 
) [static]

Check for the existance of a volatile record by id.

Parameters:
string$idthe id of the record to lookup
P4Cms_Record_Adapter$adapterthe storage adapter to use
P4_Client | string | null$masqueradethe client to masquerade as
Returns:
bool true if the record exists; false otherwise.
    {
        try {
            static::fetch($id, $adapter, $masquerade);
            return true;
        } catch (P4Cms_Record_NotFoundException $e) {
            return false;
        }
    }
static P4Cms_Record_Volatile::fetch ( id,
adapter,
masquerade = null 
) [static]

Fetch a stored volatile record by id.

Parameters:
string$idthe id of the record to fetch
P4Cms_Record_Adapter$adapterthe storage adapter to use
P4_Client | string | null$masqueradethe client to masquerade as
Returns:
P4Cms_Record_Volatile the populated volatile record
Exceptions:
P4Cms_Record_NotFoundExceptionif no matching record can be found.
    {
        $record = new static;
        $record->setId($id)
               ->setAdapter($adapter)
               ->setClientMasquerade($masquerade)
               ->_populate();

        return $record;
    }
P4Cms_Record_Volatile::getClientMasquerade ( )

Get the client workspace we are set to masquerade as.

If no masquerade client has been explicitly set we will fetch/create one based on the presence of a 'volatileClient' property on the storage adapter.

Returns:
P4_Client|null the client workspace to masquerade as.
    {
        // if we already have a client that we're masquerading as, return it.
        if ($this->_clientMasquerade) {
            return $this->_clientMasquerade;
        }

        // the adapter may specify a volatile client property (the site
        // branch object does this), if we don't have one early exit.
        $adapter = $this->getAdapter();
        if (!$adapter->hasProperty(static::CLIENT)) {
            return null;
        }

        $p4       = $adapter->getConnection();
        $clientId = $adapter->getProperty(static::CLIENT);

        // try to fetch the volatile client - if it does not exist, create one
        // based on the adapter's existing client (ie. same view/stream).
        try {
            $client = P4_Client::fetch($clientId, $p4);
        } catch (P4_Spec_NotFoundException $e) {
            $client = P4_Client::fetch($p4->getClient(), $p4);
            $client->setId($clientId)
                   ->setDescription("Chronicle generated 'volatile' record client.")
                   ->setRoot(P4_Environment::isWindows() ? "NUL" : "/dev/null")
                   ->touchUpView()
                   ->save();
        }

        $this->_clientMasquerade = $client;

        return $this->_clientMasquerade;
    }
P4Cms_Record_Volatile::save ( )

Save the values in this volatile record to Perforce.

Note that the values are not submitted, only pended.

Returns:
P4Cms_Record_Volatile provides fluent interface.
    {
        $file = $this->_getDepotFile();

        // masquerade as another client
        $this->_beginCharade();

        try {
            // ensure pending file is opened for add (or edit)
            // we use flush and -t/k to avoid touching files on disk.
            $this->_runFree('flush', $file);
            $this->_runFree('add',   array('-t',  'text', $file));
            $this->_runFree('edit',  array('-kt', 'text', $file));

            $params = array();
            foreach ($this->_values as $key => $value) {
                $params[] = "-n";
                $params[] = $key;
                $params[] = "-v";
                $params[] = (string) $value;
            }
            $params[] = $file;

            $this->getAdapter()->getConnection()->run('attribute', $params);
        } catch (Exception $e) {
            // look away!
        }

        // restore original client.
        $this->_endCharade();

        // if an exception occurred, throw it now.
        if (isset($e)) {
            throw $e;
        }

        return $this;
    }
P4Cms_Record_Volatile::setClientMasquerade ( client)

Set the client workspace to masquerade as.

Parameters:
P4_Client | string | null$clientthe client workspace to masquerade as
Returns:
P4Cms_Record_Volatile provides fluent interface.
    {
        // upgrade client to a client object.
        $client = (!$client instanceof P4_Client && !is_null($client))
            ? P4_Client::fetch($client, $this->getAdapter()->getConnection())
            : $client;

        $this->_clientMasquerade = $client;

        return $this;
    }
P4Cms_Record_Volatile::setId ( id)

Set the id of this record.

Extended to clear depotFile anytime id changes.

Parameters:
mixed$idthe value of the id of this record.
Returns:
P4Cms_Record_Volatile provides a fluent interface

Reimplemented from P4Cms_Model.

    {
        $this->_depotFile = null;
        return parent::setId($id);
    }

Member Data Documentation

P4Cms_Record_Volatile::$_clientMasquerade = null [protected]
P4Cms_Record_Volatile::$_depotFile = null [protected]
P4Cms_Record_Volatile::$_originalClient = null [protected]
P4Cms_Record_Volatile::$_originalHost = null [protected]
P4Cms_Record_Volatile::$_storageSubPath = null [protected]

Reimplemented in P4Cms_Content_Opened.

const P4Cms_Record_Volatile::CLIENT = 'volatileClient'

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