Pull.php #1

  • //
  • guest/
  • perforce_software/
  • chronicle/
  • main/
  • application/
  • site/
  • forms/
  • Pull.php
  • View
  • Commits
  • Open Download .zip Download (10 KB)
<?php
/**
 * Form to pull changes from one branch to another.
 *
 * @copyright   2011 Perforce Software. All rights reserved.
 * @license     Please see LICENSE.txt in top-level folder of this distribution.
 * @version     <release>/<patch>
 */
class Site_Form_Pull extends P4Cms_Form
{
    const       MODE_MERGE  = 'merge';
    const       MODE_COPY   = 'copy';

    protected   $_pathGroup = null;

    /**
     * Setup form to collect pull information.
     */
    public function init()
    {
        // set the method for the form to POST
        $this->setMethod('post');

        // set id prefix to avoid collisions with other in-page forms.
        $this->setIdPrefix('pull');

        // form should use p4cms-ui styles.
        $this->setAttrib('class', 'p4cms-ui pull-form');

        // add a hidden element to track the headChange (to 'pin' the source)
        $this->addElement('hidden', 'headChange');

        // generate list of possible source branches.
        $options  = array();
        $active   = P4Cms_Site::fetchActive();
        $branches = P4Cms_Site::fetchAll(
            array(
                P4Cms_Site::FETCH_BY_SITE   => $active->getSiteId(),
                P4Cms_Site::FETCH_BY_ACL    => array('branch', 'pull-from'),
                P4Cms_Site::FETCH_SORT_FLAT => true
            )
        );
        foreach ($branches as $branch) {
            if ($branch->getId() != $active->getId()) {
                $options[$branch->getId()] = $branch->getStream()->getName();
            }
        }

        $this->addElement(
            'select',
            'source',
            array(
                'label'         => 'From',
                'required'      => true,
                'multiOptions'  => $options
            )
        );

        $this->addElement(
            'text',
            'target',
            array(
                'label'     => 'To',
                'required'  => true,
                'readOnly'  => true,
                'value'     => $active->getStream()->getName()
            )
        );

        $pathGroup   = $this->getPathGroup();
        $source      = $pathGroup->getValue('source');
        $mode        = $pathGroup->getValue('mode');
        $sourceName  = $source instanceof P4Cms_Site
            ? $this->getView()->escape($source->getStream()->getName())
            : null;

        $this->addElement(
            'radio',
            'mode',
            array(
                'label'         => 'Mode',
                'required'      => true,
                'value'         => $mode,
                'escape'        => false,
                'multiOptions'  => array(
                    static::MODE_MERGE  => 'Update'
                                        .  '<span class=description>Pull items that have changed in the '
                                        .  ($sourceName ?: 'from') . ' branch</span>',
                    static::MODE_COPY   => 'Clone'
                                        .  '<span class=description>Make items identical to the '
                                        .  ($sourceName ?: 'from') . ' branch</span>',
                )
            )
        );

        // add a checklist to control which paths are included.
        $pathOptions = $this->_getPathOptions();
        $this->addElement(
            'nestedCheckbox',
            'paths',
            array(
                'label'         => 'Select What to Pull',
                'required'      => true,
                'escape'        => false,
                'emptyText'     => "Nothing to pull"
                                .  ($sourceName ? " from $sourceName." : '.'),
                'description'   => '<span class="header-items">Items</span>'
                                .  '<span class="header-quantity">Quantity</span>',
                'onClick'       => "p4cms.ui.toggleChildCheckboxes(this);"
                                .  "p4cms.ui.toggleParentCheckbox(this);"
            ) + $pathOptions
        );

        $this->getElement('paths')
             ->getDecorator('description')
             ->setOption('placement', 'prepend')
             ->setEscape(false);

        $conflicts = $this->getPathGroup()->getCount(
            array(Site_Model_PullPathGroup::RECURSIVE, Site_Model_PullPathGroup::ONLY_CONFLICTS)
        );
        if ($conflicts) {
            $message = '<span class="conflict-note">'
                     . 'Changes to <span class="count">' . $conflicts . '</span>'
                     . ' <span class="items">item' . ($conflicts > 1 ? 's' : '') . '</span>'
                     . ' in the ' . $active->getStream()->getName() . ' branch will be overwritten.'
                     . '</span>';

            $this->addElement(
                'note',
                'note',
                array(
                    'value'  => $message,
                )
            );
        }

        // add the submit button (disable it if no pull paths)
        $this->addElement(
            'SubmitButton',
            'pull',
            array(
                'label'     => 'Pull',
                'class'     => 'preferred',
                'required'  => false,
                'ignore'    => true,
                'disabled'  => !$this->getElement('paths')->getMultiOptions()
            )
        );

        // put the button in a fieldset.
        $this->addDisplayGroup(
            array('pull'),
            'buttons',
            array(
                'class' => 'buttons',
                'order' => 100
            )
        );
    }

    /**
     * Set the path group object to inform path inclusion controls.
     *
     * @param   Site_Model_PullPathGroup    $pathGroup  the path groupings
     * @return  Site_Form_Pull              provides fluent interface.
     */
    public function setPathGroup(Site_Model_PullPathGroup $pathGroup)
    {
        $this->_pathGroup = $pathGroup;

        return $this;
    }

    /**
     * Get the path group object to inform path inclusion controls.
     *
     * @return  Site_Model_PullPathGroup    the path groupings.
     */
    public function getPathGroup()
    {
        if (!$this->_pathGroup instanceof Site_Model_PullPathGroup) {
            throw new Site_Exception(
                "Cannot get path group. No path group has been set."
            );
        }

        return $this->_pathGroup;
    }

    /**
     * Generate element options suitable for use with a nested checkbox
     * for all paths and sub-groups in the given pull path group object.
     *
     * Provides the 'multiOptions' and 'value' keys. Label and other
     * details should be added by caller.
     *
     * This function is recursive to deal with the potential for groups
     * to contain sub-groups.
     *
     * @param   Site_Model_PullPathGroup|null   $pathGroup  the path group to use or null to
     *                                                      use the group set on the instance
     * @return  array                           the options for use with nested checkbox
     */
    protected function _getPathOptions(Site_Model_PullPathGroup $pathGroup = null)
    {
        $options   = array();
        $values    = array();
        $class     = array();
        $readOnly  = array();
        $pathGroup = $pathGroup ?: $this->getPathGroup();
        $subGroups = $pathGroup->getSubGroups();
        $subGroups->sortBy(
            array(
                'order'         => array($subGroups::SORT_NUMERIC),
                'pullByDefault' => array($subGroups::SORT_NUMERIC, $subGroups::SORT_DESCENDING),
                'label'         => array($subGroups::SORT_NATURAL, $subGroups::SORT_NO_CASE)
            )
        );

        foreach ($subGroups as $subGroup) {
            // get options/values for this sub-group recursively
            $subResult = $this->_getPathOptions($subGroup);

            // skip empty path groups.
            if (!$subResult['multiOptions'] && !$subGroup->getValue('paths')->count()) {
                continue;
            }

            // option key is the group id.
            $key = $subGroup->getId();

            // compose option label from the group's label and a
            // count of the paths within the group (recursively).
            $label    = $subGroup->getValue('label');
            $classes  = $subGroup->getValue('hideCount') ? ' hidden' : '';
            $classes .= $subGroup->getIncludePaths() ? ' has-paths' : ' no-paths';
            $label   .= '<span class="count-column' . $classes . '">'
                     .  ' <span class="count">' . $subGroup->getCount(Site_Model_PullPathGroup::RECURSIVE) . '</span>'
                     .  ' <span class="conflict-count">' .  $subGroup->getConflictCount() . '</span>'
                     .  '</span>';

            $options[$key] = $label;

            // if sub-group indicates it should be read-only add it
            // to our list of read-only elements
            if ($subGroup->getValue('readOnly')) {
                $readOnly[] = $key;
            }

            // if sub-group indicates it should be pulled by default
            // add it to our values array so it is checked
            if ($subGroup->getValue('pullByDefault')) {
                $values[] = $key;
            }

            // add a class to identify entries with conflicts
            if ($subGroup->getConflictCount()) {
                $class[$key] = 'conflict';
            }

            // the sub-group multiOptions come immediately after our own
            if ($subResult['multiOptions']) {
                $options[$key . '-subGroups'] = $subResult['multiOptions'];
            }

            // include any values provided by the sub-group
            if ($subResult['value']) {
                $values = array_merge($values, $subResult['value']);
            }
            if ($subResult['readOnly']) {
                $readOnly = array_merge($readOnly, $subResult['readOnly']);
            }
            if ($subResult['class']) {
                $class = array_merge($class, $subResult['class']);
            }
        }

        return array(
            'multiOptions' => $options,
            'readOnly'     => $readOnly,
            'value'        => $values,
            'class'        => $class
        );
    }
}
# Change User Description Committed
#1 16170 perforce_software Move Chronicle files to follow new path scheme for branching.
//guest/perforce_software/chronicle/application/site/forms/Pull.php
#1 8972 Matt Attaway Initial add of the Chronicle source code