protected function loadPage()
 {
     if ($this->object && $this->phids) {
         throw new Exception(pht('You can not issue a policy query with both %s and %s.', 'setObject()', 'setPHIDs()'));
     } else {
         if ($this->object) {
             $phids = $this->loadObjectPolicyPHIDs();
         } else {
             $phids = $this->phids;
         }
     }
     $phids = array_fuse($phids);
     $results = array();
     // First, load global policies.
     foreach (self::getGlobalPolicies() as $phid => $policy) {
         if (isset($phids[$phid])) {
             $results[$phid] = $policy;
             unset($phids[$phid]);
         }
     }
     // Now, load object policies.
     foreach (self::getObjectPolicies($this->object) as $phid => $policy) {
         if (isset($phids[$phid])) {
             $results[$phid] = $policy;
             unset($phids[$phid]);
         }
     }
     // If we still need policies, we're going to have to fetch data. Bucket
     // the remaining policies into rule-based policies and handle-based
     // policies.
     if ($phids) {
         $rule_policies = array();
         $handle_policies = array();
         foreach ($phids as $phid) {
             $phid_type = phid_get_type($phid);
             if ($phid_type == PhabricatorPolicyPHIDTypePolicy::TYPECONST) {
                 $rule_policies[$phid] = $phid;
             } else {
                 $handle_policies[$phid] = $phid;
             }
         }
         if ($handle_policies) {
             $handles = id(new PhabricatorHandleQuery())->setViewer($this->getViewer())->withPHIDs($handle_policies)->execute();
             foreach ($handle_policies as $phid) {
                 $results[$phid] = PhabricatorPolicy::newFromPolicyAndHandle($phid, $handles[$phid]);
             }
         }
         if ($rule_policies) {
             $rules = id(new PhabricatorPolicy())->loadAllWhere('phid IN (%Ls)', $rule_policies);
             $results += mpull($rules, null, 'getPHID');
         }
     }
     $results = msort($results, 'getSortKey');
     return $results;
 }
 protected function renderPolicyName($phid, $state = 'old')
 {
     $policy = PhabricatorPolicy::newFromPolicyAndHandle($phid, $this->getHandleIfExists($phid));
     if ($this->renderingTarget == self::TARGET_HTML) {
         switch ($policy->getType()) {
             case PhabricatorPolicyType::TYPE_CUSTOM:
                 $policy->setHref('/transactions/' . $state . '/' . $this->getPHID() . '/');
                 $policy->setWorkflow(true);
                 break;
             default:
                 break;
         }
         $output = $policy->renderDescription();
     } else {
         $output = hsprintf('%s', $policy->getFullName());
     }
     return $output;
 }
 protected function getOptions()
 {
     $capability = $this->capability;
     $policies = $this->policies;
     $viewer = $this->getUser();
     // Check if we're missing the policy for the current control value. This
     // is unusual, but can occur if the user is submitting a form and selected
     // an unusual project as a policy but the change has not been saved yet.
     $policy_map = mpull($policies, null, 'getPHID');
     $value = $this->getValue();
     if ($value && empty($policy_map[$value])) {
         $handle = id(new PhabricatorHandleQuery())->setViewer($viewer)->withPHIDs(array($value))->executeOne();
         if ($handle->isComplete()) {
             $policies[] = PhabricatorPolicy::newFromPolicyAndHandle($value, $handle);
         }
     }
     // Exclude object policies which don't make sense here. This primarily
     // filters object policies associated from template capabilities (like
     // "Default Task View Policy" being set to "Task Author") so they aren't
     // made available on non-template capabilities (like "Can Bulk Edit").
     foreach ($policies as $key => $policy) {
         if ($policy->getType() != PhabricatorPolicyType::TYPE_OBJECT) {
             continue;
         }
         $rule = PhabricatorPolicyQuery::getObjectPolicyRule($policy->getPHID());
         if (!$rule) {
             continue;
         }
         $target = nonempty($this->templateObject, $this->object);
         if (!$rule->canApplyToObject($target)) {
             unset($policies[$key]);
             continue;
         }
     }
     $options = array();
     foreach ($policies as $policy) {
         if ($policy->getPHID() == PhabricatorPolicies::POLICY_PUBLIC) {
             // Never expose "Public" for capabilities which don't support it.
             $capobj = PhabricatorPolicyCapability::getCapabilityByKey($capability);
             if (!$capobj || !$capobj->shouldAllowPublicPolicySetting()) {
                 continue;
             }
         }
         $policy_short_name = id(new PhutilUTF8StringTruncator())->setMaximumGlyphs(28)->truncateString($policy->getName());
         $options[$policy->getType()][$policy->getPHID()] = array('name' => $policy_short_name, 'full' => $policy->getName(), 'icon' => $policy->getIcon(), 'sort' => phutil_utf8_strtolower($policy->getName()));
     }
     $type_project = PhabricatorPolicyType::TYPE_PROJECT;
     // Make sure we have a "Projects" group before we adjust it.
     if (empty($options[$type_project])) {
         $options[$type_project] = array();
     }
     $options[$type_project] = isort($options[$type_project], 'sort');
     $placeholder = id(new PhabricatorPolicy())->setName(pht('Other Project...'))->setIcon('fa-search');
     $options[$type_project][$this->getSelectProjectKey()] = array('name' => $placeholder->getName(), 'full' => $placeholder->getName(), 'icon' => $placeholder->getIcon());
     // If we were passed several custom policy options, throw away the ones
     // which aren't the value for this capability. For example, an object might
     // have a custom view policy and a custom edit policy. When we render
     // the selector for "Can View", we don't want to show the "Can Edit"
     // custom policy -- if we did, the menu would look like this:
     //
     //   Custom
     //     Custom Policy
     //     Custom Policy
     //
     // ...where one is the "view" custom policy, and one is the "edit" custom
     // policy.
     $type_custom = PhabricatorPolicyType::TYPE_CUSTOM;
     if (!empty($options[$type_custom])) {
         $options[$type_custom] = array_select_keys($options[$type_custom], array($this->getValue()));
     }
     // If there aren't any custom policies, add a placeholder policy so we
     // render a menu item. This allows the user to switch to a custom policy.
     if (empty($options[$type_custom])) {
         $placeholder = new PhabricatorPolicy();
         $placeholder->setName(pht('Custom Policy...'));
         $options[$type_custom][$this->getSelectCustomKey()] = array('name' => $placeholder->getName(), 'full' => $placeholder->getName(), 'icon' => $placeholder->getIcon());
     }
     $options = array_select_keys($options, array(PhabricatorPolicyType::TYPE_GLOBAL, PhabricatorPolicyType::TYPE_OBJECT, PhabricatorPolicyType::TYPE_USER, PhabricatorPolicyType::TYPE_CUSTOM, PhabricatorPolicyType::TYPE_PROJECT));
     return $options;
 }