public function testSpacesSeveralSpaces()
 {
     $this->destroyAllSpaces();
     // Try creating a few spaces, one of which is a default space. This should
     // work fine.
     $actor = $this->generateNewTestUser();
     $default = $this->newSpace($actor, pht('Default Space'), true);
     $this->newSpace($actor, pht('Alternate Space'), false);
     $this->assertEqual(2, count($this->loadAllSpaces()));
     $this->assertEqual(2, count(PhabricatorSpacesNamespaceQuery::getAllSpaces()));
     $cache_default = PhabricatorSpacesNamespaceQuery::getDefaultSpace();
     $this->assertEqual($default->getPHID(), $cache_default->getPHID());
 }
 private function canViewerSeeObjectsInSpace(PhabricatorUser $viewer, $space_phid)
 {
     $spaces = PhabricatorSpacesNamespaceQuery::getAllSpaces();
     // If there are no spaces, everything exists in an implicit default space
     // with no policy controls. This is the default state.
     if (!$spaces) {
         if ($space_phid !== null) {
             return false;
         } else {
             return true;
         }
     }
     if ($space_phid === null) {
         $space = PhabricatorSpacesNamespaceQuery::getDefaultSpace();
     } else {
         $space = idx($spaces, $space_phid);
     }
     if (!$space) {
         return false;
     }
     // This may be more involved later, but for now being able to see the
     // space is equivalent to being able to see everything in it.
     return self::hasCapability($viewer, $space, PhabricatorPolicyCapability::CAN_VIEW);
 }
 /**
  * Constrain the query to include only results in valid Spaces.
  *
  * This method builds part of a WHERE clause which considers the spaces the
  * viewer has access to see with any explicit constraint on spaces added by
  * @{method:withSpacePHIDs}.
  *
  * @param AphrontDatabaseConnection Database connection.
  * @return string Part of a WHERE clause.
  * @task spaces
  */
 private function buildSpacesWhereClause(AphrontDatabaseConnection $conn)
 {
     $object = $this->newResultObject();
     if (!$object) {
         return null;
     }
     if (!$object instanceof PhabricatorSpacesInterface) {
         return null;
     }
     $viewer = $this->getViewer();
     // If we have an omnipotent viewer and no formal space constraints, don't
     // emit a clause. This primarily enables older migrations to run cleanly,
     // without fataling because they try to match a `spacePHID` column which
     // does not exist yet. See T8743, T8746.
     if ($viewer->isOmnipotent()) {
         if ($this->spaceIsArchived === null && $this->spacePHIDs === null) {
             return null;
         }
     }
     $space_phids = array();
     $include_null = false;
     $all = PhabricatorSpacesNamespaceQuery::getAllSpaces();
     if (!$all) {
         // If there are no spaces at all, implicitly give the viewer access to
         // the default space.
         $include_null = true;
     } else {
         // Otherwise, give them access to the spaces they have permission to
         // see.
         $viewer_spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces($viewer);
         foreach ($viewer_spaces as $viewer_space) {
             if ($this->spaceIsArchived !== null) {
                 if ($viewer_space->getIsArchived() != $this->spaceIsArchived) {
                     continue;
                 }
             }
             $phid = $viewer_space->getPHID();
             $space_phids[$phid] = $phid;
             if ($viewer_space->getIsDefaultNamespace()) {
                 $include_null = true;
             }
         }
     }
     // If we have additional explicit constraints, evaluate them now.
     if ($this->spacePHIDs !== null) {
         $explicit = array();
         $explicit_null = false;
         foreach ($this->spacePHIDs as $phid) {
             if ($phid === null) {
                 $space = PhabricatorSpacesNamespaceQuery::getDefaultSpace();
             } else {
                 $space = idx($all, $phid);
             }
             if ($space) {
                 $phid = $space->getPHID();
                 $explicit[$phid] = $phid;
                 if ($space->getIsDefaultNamespace()) {
                     $explicit_null = true;
                 }
             }
         }
         // If the viewer can see the default space but it isn't on the explicit
         // list of spaces to query, don't match it.
         if ($include_null && !$explicit_null) {
             $include_null = false;
         }
         // Include only the spaces common to the viewer and the constraints.
         $space_phids = array_intersect_key($space_phids, $explicit);
     }
     if (!$space_phids && !$include_null) {
         if ($this->spacePHIDs === null) {
             throw new PhabricatorEmptyQueryException(pht('You do not have access to any spaces.'));
         } else {
             throw new PhabricatorEmptyQueryException(pht('You do not have access to any of the spaces this query ' . 'is constrained to.'));
         }
     }
     $alias = $this->getPrimaryTableAlias();
     if ($alias) {
         $col = qsprintf($conn, '%T.spacePHID', $alias);
     } else {
         $col = 'spacePHID';
     }
     if ($space_phids && $include_null) {
         return qsprintf($conn, '(%Q IN (%Ls) OR %Q IS NULL)', $col, $space_phids, $col);
     } else {
         if ($space_phids) {
             return qsprintf($conn, '%Q IN (%Ls)', $col, $space_phids);
         } else {
             return qsprintf($conn, '%Q IS NULL', $col);
         }
     }
 }