Perforce Chronicle 2012.2/486814
API Documentation

Site_Model_PullPathGroup Class Reference

This class models hierarchical groupings of paths. More...

Inheritance diagram for Site_Model_PullPathGroup:
P4Cms_Model P4Cms_ModelInterface

List of all members.

Public Member Functions

 addBasePath ($basePath)
 Add the specified base path to this path group.
 addBasePaths (array $basePaths)
 Add the passed array of base paths to this path group.
 addPath ($path)
 Add a path to this path group.
 addSubGroup ($group)
 Add a sub-group to this path group.
 findById ($id, $group=null)
 Find a group under this group (includes this group) with the given id.
 getBasePaths ()
 Get the base paths for this path group.
 getConflictCount ()
 A convienence method that calls through to getCount returning a shallow count (non-recursive) of conflicts.
 getCount ($options=null)
 Get the count of paths in this path group.
 getCountCallback ()
 Returns the count callback without actually executing it.
 getDetails ($options=null)
 Provides details about the paths held in this group.
 getDetailsCallback ()
 Returns the details callback without actually executing it.
 getId ()
 Get an identifier for this group.
 getIncludePaths ()
 Get a list of paths in this group to use in a pull operation.
 getLabel ()
 Get the label for this path group.
 getParent ()
 Get the parent group for this path group (if one is set)
 getPaths ($options=null)
 Get the paths in this path group (not recursive).
 getSubGroup ($label)
 Try to find a sub-group with the given label under this group.
 getSubGroups ()
 Get the immediate child groups of this group (not recursive).
 inheritPaths ($paths)
 Scans up through parent objects and brings over any paths matching the passed filespec(s).
 setBasePaths ($basePaths)
 Set the base path(s) for this path group.
 setCount ($count)
 Control the count of paths in this path group.
 setDetails ($callback)
 Set a callback which will provide details about the paths held in this group.
 setLabel ($label)
 Set the label for this path group.
 setParent (Site_Model_PullPathGroup $parent=null)
 Set the parent group for this path group.
 setPaths (P4Cms_Model_Iterator $paths=null)
 Set the paths in this path group.
 setSubGroups (P4Cms_Model_Iterator $groups=null)
 Set the sub-groups in this path group.

Static Public Member Functions

static fetchRecords (array $ids, $class, P4Cms_Site $source, P4Cms_Site $target)
 Helper function to fetch records from either the source or the target branch as necessary.
static pathsByRecordId (P4Cms_Model_Iterator $paths, $class, P4Cms_Record_Adapter $adapter=null)
 Helper function to re-index a given paths iterator by record id.

Public Attributes

const ONLY_CONFLICTS = 'onlyConflicts'
const RECURSIVE = 'recursive'

Static Protected Attributes

static $_fields

Detailed Description

This class models hierarchical groupings of paths.

The paths are files affected by merge or copy pull operations. It is desirable to group these files under friendly labels to assist users in selecting which files to include in a pull operation (or to see which files are affected).

One of the other features of this model is to provide control over how files in each path group are counted. In some cases multiple files are stored to represent one logical entry. This allows us to adjust the count to better match the user's expectations.

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

Site_Model_PullPathGroup::addBasePath ( basePath)

Add the specified base path to this path group.

Base path(s) can be set to optimize pull operations (as they will be used instead of paths).

Parameters:
string$basePaththe basepath to add
Returns:
Site_Model_PullPathGroup to maintain a fluent interface
    {
        $basePaths   = $this->getBasePaths();
        $basePaths[] = $basePath;

        return $this->_setValue('basePaths', $basePaths);
    }
Site_Model_PullPathGroup::addBasePaths ( array $  basePaths)

Add the passed array of base paths to this path group.

Base path(s) can be set to optimize pull operations (as they will be used instead of paths).

Parameters:
array$basePathsthe basepaths to add
Returns:
Site_Model_PullPathGroup to maintain a fluent interface
    {
        foreach ($basePaths as $path) {
            $this->addBasePath($path);
        }

        return $this;
    }
Site_Model_PullPathGroup::addPath ( path)

Add a path to this path group.

The path must be an array of information about the path (containing at least a depotFile) or a model. If an array is given it will be normalized to a model.

Parameters:
array | P4Cms_Model$paththe path array or model to add.
Returns:
Site_Model_PullPathGroup provides fluent interface.
    {
        if (!is_array($path) && !$path instanceof P4Cms_Model) {
            throw new InvalidArgumentArgument("Cannot set path. Path must be an array or model");
        }

        if (is_array($path)) {
            $path = new P4Cms_Model($path);
        }

        $paths   = $this->getPaths();
        $paths[] = $path;

        return $this;
    }
Site_Model_PullPathGroup::addSubGroup ( group)

Add a sub-group to this path group.

The sub-group must be an array of information about the group or pull path group model. If an array is given it will be normalized to a model.

This method will set the parent of the given sub-group to be this group.

If the sub-group is passed as an array with a 'inheritPaths' property any matching paths will automatically move from this group (or its parents) to the new sub-group.

Parameters:
array | Site_Model_PullPathGroup$groupthe group array or model to add.
Returns:
Site_Model_PullPathGroup provides fluent interface.
    {
        if (!is_array($group) && !$group instanceof Site_Model_PullPathGroup) {
            throw new InvalidArgumentException(
                "Cannot add sub-group. Group must be a array or path group object."
            );
        }

        $inheritPaths = array();
        if (is_array($group)) {
            if (isset($group['inheritPaths'])) {
                $inheritPaths = $group['inheritPaths'];
                unset($group['inheritPaths']);
            }

            $group = new Site_Model_PullPathGroup($group);
        }

        // ensure the sub-group has a link back to this (its parent)
        $group->setParent($this);
        $group->inheritPaths($inheritPaths);

        $groups = $this->getSubGroups();
        $groups[] = $group;

        return $this;
    }
static Site_Model_PullPathGroup::fetchRecords ( array $  ids,
class,
P4Cms_Site source,
P4Cms_Site target 
) [static]

Helper function to fetch records from either the source or the target branch as necessary.

First attempts to fetch from the source branch and falls back to the target branch if any of the identified records could not be found in the source.

When doing a 'copy' style of pull, we can get into a situation where items that only exist in the target are opened for delete. Naturally, these records can't be fetched from the source, so we fetch them from the target branch instead.

If a given id cannot be found in either the source or the target branch it will not be included in the result.

Parameters:
array$idsa list of ids to fetch
string$classthe type of record to fetch.
P4Cms_Site$sourcethe source site/branch to fetch from.
P4Cms_Site$targetthe target site/branch to fallback to.
Returns:
P4Cms_Model_Iterator fetched records.
    {
        if (!class_exists($class) || (!is_subclass_of($class, 'P4Cms_Record') && $class !== 'P4Cms_Record')) {
            throw new InvalidArgumentException("Cannot fetch entries. Invalid class type specified.");
        }

        // nothing to do if no ids given.
        if (empty($ids)) {
            return new P4Cms_Model_Iterator;
        }

        // first attempt to fetch from the source branch.
        $entries = $class::fetchAll(
            array(
                'ids'               => $ids,
                'includeDeleted'    => true
            ),
            $source->getStorageAdapter()
        );

        // if we got everything, all done!
        $missing = array_diff($ids, $entries->invoke('getId'));
        if (!$missing) {
            return $entries;
        }

        // try to fetch missing records from the target branch.
        return $entries->merge(
            $class::fetchAll(
                array(
                    'ids'               => $missing,
                    'includeDeleted'    => true
                ),
                $target->getStorageAdapter()
            )
        );
    }
Site_Model_PullPathGroup::findById ( id,
group = null 
)

Find a group under this group (includes this group) with the given id.

If no matching group can be found, returns false.

Parameters:
string$idthe id of the group to look for.
Site_Model_PullPathGroup | null$groupused for recursion.
Returns:
Site_Model_PullPathGroup|bool the found group or false.
    {
        $group = $group ?: $this;

        // check for immediate match.
        if ($group->getId() === $id) {
            return $group;
        }

        // check for recursive (sub-group) match.
        foreach ($group->getSubGroups() as $subGroup) {
            $found = $this->findById($id, $subGroup);
            if ($found) {
                return $found;
            }
        }

        return false;
    }
Site_Model_PullPathGroup::getBasePaths ( )

Get the base paths for this path group.

Returns:
array the base-paths for files in this group.
    {
        return $this->_getValue('basePaths');
    }
Site_Model_PullPathGroup::getConflictCount ( )

A convienence method that calls through to getCount returning a shallow count (non-recursive) of conflicts.

Returns:
int The number of conflicting entries (shallow)
Site_Model_PullPathGroup::getCount ( options = null)

Get the count of paths in this path group.

This will execute the count callback and use its result if one is set.

Parameters:
string | array | null$optionsoptions to influence the result: ONLY_CONFLICTS - if passed, only conflicting paths are counted RECURSIVE - if passed, count of all sub groups will be included
Returns:
int the number of paths in this path group. this is not always an exact count of paths as a fixed value or a callback can be used.
    {
        $options       = (array) $options;
        $onlyConflicts = in_array(static::ONLY_CONFLICTS, $options) ? static::ONLY_CONFLICTS : null;
        $computed      = $this->getPaths($onlyConflicts)->count();

        // if a count callback has been set, use it,
        // passing this and the count we computed above
        $count = $this->_getValue('count');
        if (is_callable($count)) {
            // just pass the 'conflictsOnly' option to the callback.
            // we handle recursion ourselves.
            $computed = call_user_func($count, $this, $computed, (array) $onlyConflicts);
        }

        // compute the number of paths recursively if needed.
        if (in_array(static::RECURSIVE, $options)) {
            foreach ($this->getSubGroups() as $group) {
                $computed += $group->getCount($options);
            }
        }

        return $computed;
    }
Site_Model_PullPathGroup::getCountCallback ( )

Returns the count callback without actually executing it.

Returns:
callable|null the count callback or null if none set
    {
        return $this->_getValue('count');
    }
Site_Model_PullPathGroup::getDetails ( options = null)

Provides details about the paths held in this group.

Details are provided as an iterator of Models. The keys/values in the models are intended to represent columns of data. At a minimum a 'label', 'conflict' and 'action' value should be present on each model.

The returned iterator may optionally use a 'columns' property to provide column id's (e.g. label) with custom titles. If no columns property is present the default columns of Label and Action will be used.

If a details callback is present it will be utilized to generate the details. Otherwise, each path will get default details using the depotFile as a label and existing branch action and conflict status.

Parameters:
string | array | null$optionsoptions to influence the result: ONLY_CONFLICTS - if passed, only conflicting path details are returned RECURSIVE - if passed, details of all sub groups paths will be included
Returns:
P4Cms_Model_Iterator the path details
    {
        $options       = (array) $options;
        $onlyConflicts = in_array(static::ONLY_CONFLICTS, $options) ? static::ONLY_CONFLICTS : null;
        $paths         = $this->getPaths($onlyConflicts);
        $callback      = $this->_getValue('details');
        $details       = new P4Cms_Model_Iterator;
        if (is_callable($callback) && $paths->count()) {
            $details = $callback($paths) ?: new P4Cms_Model_Iterator;
            foreach ($details as $detail) {
                if (!$detail->hasField("type")) {
                    $detail->setValue('type', $this->getLabel());
                }
            }
        } else if ($paths->count()) {
            foreach ($paths as $path) {
                $details[] = new P4Cms_Model(
                    array(
                        'action'    => $path->action,
                        'conflict'  => $path->conflict,
                        'type'      => $this->getLabel(),
                        'label'     => preg_replace('#^//[^/]+/[^/]+/#', '', $path->depotFile)
                    )
                );
            }

            $details->setProperty('columns', array('label' => 'File', 'action' => 'Action'));
        }

        $columns = $details->hasProperty('columns') ? $details->getProperty('columns') : array();
        if (in_array(static::RECURSIVE, (array) $options)) {
            foreach ($this->getSubGroups() as $group) {
                $subDetails = $group->getDetails($options);
                if ($subDetails->count()) {
                    if ($subDetails->hasProperty('columns')) {
                        $columns += $subDetails->getProperty('columns');
                    }

                    $details->merge($subDetails);
                }
            }
        }

        // ensure our details iterator has the aggregated columns
        // fall back to defaults of Label and Action if none found.
        $details->setProperty(
            'columns',
            $columns ?: array('label' => 'Label', 'action' => 'Action')
        );

        return $details;
    }
Site_Model_PullPathGroup::getDetailsCallback ( )

Returns the details callback without actually executing it.

Returns:
callable|null the details callback or null if none set
    {
        return $this->_getValue('details');
    }
Site_Model_PullPathGroup::getId ( )

Get an identifier for this group.

If an explicit id is set, it will be returned. Otherwise, we generate an identifier for this path group based on its label and the labels of its parents (e.g. 'configuration/permissions')

Note: this identifier is not guaranteed to be unique!

Returns:
string an identifier for this group.

Reimplemented from P4Cms_Model.

    {
        // if an explicit id was set, use it.
        if (parent::getId()) {
            return parent::getId();
        }

        $ids    = array();
        $filter = new P4Cms_Filter_TitleToId;
        $parent = $this;
        while ($parent) {
            $ids[]  = $filter->filter($parent->getLabel());
            $parent = $parent->getParent();
        }

        return trim(implode('/', array_reverse($ids)), '/');
    }
Site_Model_PullPathGroup::getIncludePaths ( )

Get a list of paths in this group to use in a pull operation.

If base path(s) are set, these will be returned (as an optimization). Otherwise, a list of depotFiles will be taken from getPaths and returned.

Returns:
array paths in this group to use in a pull operation
    {
        return $this->getBasePaths()
            ?: $this->getPaths()->invoke('getValue', array('depotFile'));
    }
Site_Model_PullPathGroup::getLabel ( )

Get the label for this path group.

Returns:
string|null the human-friendly label for this group.
    {
        return $this->_getValue('label');
    }
Site_Model_PullPathGroup::getParent ( )

Get the parent group for this path group (if one is set)

Returns:
Site_Model_PullPathGroup|null parent group or null.
    {
        return $this->_getValue('parent');
    }
Site_Model_PullPathGroup::getPaths ( options = null)

Get the paths in this path group (not recursive).

Parameters:
string | array | null$optionsoptions to influence the result: ONLY_CONFLICTS - if passed, only conflicting paths are returned RECURSIVE - if passed, paths of all sub groups will be included
Returns:
P4Cms_Model_Iterator an iterator of paths in this group.
    {
        // initialize paths to an iterator if necessary.
        $paths = $this->_getValue('paths') ?: new P4Cms_Model_Iterator;
        $this->_setValue('paths', $paths);

        if (in_array(static::ONLY_CONFLICTS, (array) $options)) {
            $paths = $paths->filter('conflict', true, array(P4Cms_Model_Iterator::FILTER_COPY));
        }

        if (in_array(static::RECURSIVE, (array) $options)) {
            foreach ($this->getSubGroups() as $group) {
                $paths->merge($group->getPaths($options));
            }
        }

        return $paths;
    }
Site_Model_PullPathGroup::getSubGroup ( label)

Try to find a sub-group with the given label under this group.

Parameters:
string$labelthe name of the sub-group to look for.
Returns:
Site_Model_PullPathGroup|bool a matching sub-group or false if no such group.
    {
        return $this->getSubGroups()
             ->filter('label', $label, array(P4Cms_Model_Iterator::FILTER_COPY))
             ->first();
    }
Site_Model_PullPathGroup::getSubGroups ( )

Get the immediate child groups of this group (not recursive).

Returns:
P4Cms_Model_Iterator a list of child groups.
    {
        // initialize sub-groups to an iterator if necessary.
        $groups = $this->_getValue('subGroups') ?: new P4Cms_Model_Iterator;
        $this->_setValue('subGroups', $groups);

        return $groups;
    }
Site_Model_PullPathGroup::inheritPaths ( paths)

Scans up through parent objects and brings over any paths matching the passed filespec(s).

If the passed filespec ends in the wildcard '...' anything starting with the value will be considered a match.

If a path model is passed its 'depotFile' value will be used as the search value and any matching paths brought over.

Parameters:
array | Iterator | string | P4Cms_Model$pathsone or more paths to inherit
Returns:
Site_Model_PullPathGroup to maintain a fluent interface
    {
        // we need to selectively 'arrayize' input if only a single
        // path was passed. blindly casting to array would 'toArray'
        // P4Cms_Model's causing a later invalid argument exception.
        if (!$paths instanceof Iterator && !is_array($paths)) {
            $paths = array($paths);
        }

        // if paths are in an iterator the cursor may become corrupt
        // if we take a path from a parent with a shared reference.
        // swap it over to being an array of paths for safety.
        if ($paths instanceof Iterator) {
            $paths = iterator_to_array($paths);
        }

        foreach ($paths as $path) {
            // normalize to a string
            if ($path instanceof P4Cms_Model && $path->depotFile) {
                $path = $path->depotFile;
            }

            if (!$path || !is_string($path)) {
                throw new InvalidArgumentException(
                    'Inherit path must be a non empty string or path model.'
                );
            }

            // our 'needle' starts out as the full path value requiring
            // an exact match. if the path ends in '...' we switch to a
            // starts with match and strip the trailing wildcard.
            $needle = $path;
            $mode   = 'exact';
            if (substr($needle, -3) == '...') {
                $mode   = 'starts';
                $needle = substr($needle, 0, -3);
            }

            $parent = $this->getParent();
            while ($parent) {
                $paths = $parent->getPaths();
                foreach ($paths->toArray(true) as $key => $path) {
                    // if we have an acceptable match, add the path to our group
                    // and remove it from the parent that originally had it.
                    if (($mode == 'exact' && $needle === $path->getValue('depotFile'))
                        || ($mode == 'starts' && strpos($path->getValue('depotFile'), $needle) === 0)
                    ) {
                        $this->addPath($path);
                        unset($paths[$key]);
                    }
                }

                // up the tree.
                $parent = $parent->getParent();
            }
        }
    }
static Site_Model_PullPathGroup::pathsByRecordId ( P4Cms_Model_Iterator paths,
class,
P4Cms_Record_Adapter adapter = null 
) [static]

Helper function to re-index a given paths iterator by record id.

Any paths that are not of the given record class type (ie. not under the appropriate storage path) will be excluded.

Parameters:
P4Cms_Model_Iterator$pathsan iterator of paths to re-index.
string$classthe type of record to use to convert paths to ids.
P4Cms_Record_Adapter | null$adapteroptional - a specific storage adapter to use.
Returns:
P4Cms_Model_Iterator iterator of paths of the given record type indexed by id.
    {
        $byId = new P4Cms_Model_Iterator;
        foreach ($paths as $path) {
            try {
                $id        = $class::depotFileToId($path->depotFile, $adapter);
                $byId[$id] = $path;
            } catch (P4Cms_Record_Exception $e) {
                // skip entries whose id can't be determined (assumed to be of a different type).
            }
        }

        return $byId;
    }
Site_Model_PullPathGroup::setBasePaths ( basePaths)

Set the base path(s) for this path group.

Base path(s) can be set to optimize pull operations (as they will be used instead of paths).

Parameters:
array | string | null$basePathsthe base-path(s) for files in this group.
Returns:
Site_Model_PullPathGroup provides fluent interface.
    {
        $this->_setValue('basePaths', array());

        $basePaths = (array) $basePaths;
        foreach ($basePaths as $basePath) {
            $this->addBasePath($basePath);
        }

        return $this;
    }
Site_Model_PullPathGroup::setCount ( count)

Control the count of paths in this path group.

By default simply returns a count of all paths and paths in sub-groups (recursively). Can be set to null for the default behaviour or a callback that may use whatever logic is desired to return a count.

Parameters:
null | callable$countnull to clear the count (fallback to default), or a callback that returns the count (passed $this, the computed count, $recursive and $onlyConflicts)
Returns:
Site_Model_PullPathGroup provides fluent interface.
    {
        if (!is_null($count) && !is_callable($count)) {
            throw InvalidArgumentException(
                "Cannot set count. Given count is not a valid type."
            );
        }

        return $this->_setValue('count', $count);
    }
Site_Model_PullPathGroup::setDetails ( callback)

Set a callback which will provide details about the paths held in this group.

The callback will be passed an iterator of Paths (output of getPaths) and is expected to return an iterator of Models. The keys/values in the models will inform the columns used to display your data. At a minimum a 'label', 'conflict' and 'action' value should be present.

If no callback is set the default details will be returned. See getDetails for more information.

Parameters:
callable | null$callbackthe callback to use
Returns:
Site_Model_PullPathGroup to maintain a fluent interface
Exceptions:
InvalidArgumentExceptionif an invalid type is passed
    {
        if (!is_callable($callback) && !is_null($callback)) {
            throw new InvalidArgumentException(
                'Details Callback must be callable or null'
            );
        }

        return $this->_setValue('details', $callback);
    }
Site_Model_PullPathGroup::setLabel ( label)

Set the label for this path group.

Parameters:
string | null$labelthe human-friendly label for this group.
Returns:
Site_Model_PullPathGroup provides fluent interface.
    {
        return $this->_setValue('label', $label);
    }
Site_Model_PullPathGroup::setParent ( Site_Model_PullPathGroup parent = null)

Set the parent group for this path group.

This gives sub-groups access to their parent. If this group has basepaths set on it, specifiying a parent will trigger moving any matching paths from parent group(s).

Parameters:
Site_Model_PullPathGroup | null$parentparent group or null.
Returns:
Site_Model_PullPathGroup provides fluent interface.
    {
        $this->_setValue('parent', $parent);

        if ($parent) {
            $this->setBasePaths($this->getBasePaths());
        }

        return $this;
    }
Site_Model_PullPathGroup::setPaths ( P4Cms_Model_Iterator paths = null)

Set the paths in this path group.

Parameters:
P4Cms_Model_Iterator | null$pathsthe list of paths to put in this group (null to clear).
Returns:
Site_Model_PullPathGroup provides fluent interface.
    {
        $paths = $paths ?: new P4Cms_Model_Iterator;

        return $this->_setValue('paths', $paths);
    }
Site_Model_PullPathGroup::setSubGroups ( P4Cms_Model_Iterator groups = null)

Set the sub-groups in this path group.

Parameters:
P4Cms_Model_Iterator | null$groupsthe sub-groups to put in this group (null to clear).
Returns:
Site_Model_PullPathGroup provides fluent interface.
    {
        $groups = $groups ?: new P4Cms_Model_Iterator;

        foreach ($groups as $group) {
            $this->addSubGroup($group);
        }

        return $this->_setValue('subGroups', $groups);
    }

Member Data Documentation

Site_Model_PullPathGroup::$_fields [static, protected]

Reimplemented from P4Cms_Model.


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