[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/src/applications/project/storage/ -> PhabricatorProject.php (source)

   1  <?php
   2  
   3  final class PhabricatorProject extends PhabricatorProjectDAO
   4    implements
   5      PhabricatorFlaggableInterface,
   6      PhabricatorPolicyInterface,
   7      PhabricatorSubscribableInterface,
   8      PhabricatorCustomFieldInterface,
   9      PhabricatorDestructibleInterface {
  10  
  11    protected $name;
  12    protected $status = PhabricatorProjectStatus::STATUS_ACTIVE;
  13    protected $authorPHID;
  14    protected $subprojectPHIDs = array();
  15    protected $phrictionSlug;
  16    protected $profileImagePHID;
  17    protected $icon;
  18    protected $color;
  19  
  20    protected $viewPolicy;
  21    protected $editPolicy;
  22    protected $joinPolicy;
  23    protected $isMembershipLocked;
  24  
  25    private $memberPHIDs = self::ATTACHABLE;
  26    private $watcherPHIDs = self::ATTACHABLE;
  27    private $sparseWatchers = self::ATTACHABLE;
  28    private $sparseMembers = self::ATTACHABLE;
  29    private $customFields = self::ATTACHABLE;
  30    private $profileImageFile = self::ATTACHABLE;
  31    private $slugs = self::ATTACHABLE;
  32  
  33    const DEFAULT_ICON = 'fa-briefcase';
  34    const DEFAULT_COLOR = 'blue';
  35  
  36    const TABLE_DATASOURCE_TOKEN = 'project_datasourcetoken';
  37  
  38    public static function initializeNewProject(PhabricatorUser $actor) {
  39      $app = id(new PhabricatorApplicationQuery())
  40        ->setViewer(PhabricatorUser::getOmnipotentUser())
  41        ->withClasses(array('PhabricatorProjectApplication'))
  42        ->executeOne();
  43  
  44      $view_policy = $app->getPolicy(
  45        ProjectDefaultViewCapability::CAPABILITY);
  46      $edit_policy = $app->getPolicy(
  47        ProjectDefaultEditCapability::CAPABILITY);
  48      $join_policy = $app->getPolicy(
  49        ProjectDefaultJoinCapability::CAPABILITY);
  50  
  51      return id(new PhabricatorProject())
  52        ->setName('')
  53        ->setAuthorPHID($actor->getPHID())
  54        ->setIcon(self::DEFAULT_ICON)
  55        ->setColor(self::DEFAULT_COLOR)
  56        ->setViewPolicy($view_policy)
  57        ->setEditPolicy($edit_policy)
  58        ->setJoinPolicy($join_policy)
  59        ->setIsMembershipLocked(0)
  60        ->attachMemberPHIDs(array())
  61        ->attachSlugs(array());
  62    }
  63  
  64    public function getCapabilities() {
  65      return array(
  66        PhabricatorPolicyCapability::CAN_VIEW,
  67        PhabricatorPolicyCapability::CAN_EDIT,
  68        PhabricatorPolicyCapability::CAN_JOIN,
  69      );
  70    }
  71  
  72    public function getPolicy($capability) {
  73      switch ($capability) {
  74        case PhabricatorPolicyCapability::CAN_VIEW:
  75          return $this->getViewPolicy();
  76        case PhabricatorPolicyCapability::CAN_EDIT:
  77          return $this->getEditPolicy();
  78        case PhabricatorPolicyCapability::CAN_JOIN:
  79          return $this->getJoinPolicy();
  80      }
  81    }
  82  
  83    public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
  84  
  85      switch ($capability) {
  86        case PhabricatorPolicyCapability::CAN_VIEW:
  87          if ($this->isUserMember($viewer->getPHID())) {
  88            // Project members can always view a project.
  89            return true;
  90          }
  91          break;
  92        case PhabricatorPolicyCapability::CAN_EDIT:
  93          break;
  94        case PhabricatorPolicyCapability::CAN_JOIN:
  95          $can_edit = PhabricatorPolicyCapability::CAN_EDIT;
  96          if (PhabricatorPolicyFilter::hasCapability($viewer, $this, $can_edit)) {
  97            // Project editors can always join a project.
  98            return true;
  99          }
 100          break;
 101      }
 102  
 103      return false;
 104    }
 105  
 106    public function describeAutomaticCapability($capability) {
 107      switch ($capability) {
 108        case PhabricatorPolicyCapability::CAN_VIEW:
 109          return pht('Members of a project can always view it.');
 110        case PhabricatorPolicyCapability::CAN_JOIN:
 111          return pht('Users who can edit a project can always join it.');
 112      }
 113      return null;
 114    }
 115  
 116    public function isUserMember($user_phid) {
 117      if ($this->memberPHIDs !== self::ATTACHABLE) {
 118        return in_array($user_phid, $this->memberPHIDs);
 119      }
 120      return $this->assertAttachedKey($this->sparseMembers, $user_phid);
 121    }
 122  
 123    public function setIsUserMember($user_phid, $is_member) {
 124      if ($this->sparseMembers === self::ATTACHABLE) {
 125        $this->sparseMembers = array();
 126      }
 127      $this->sparseMembers[$user_phid] = $is_member;
 128      return $this;
 129    }
 130  
 131    public function getConfiguration() {
 132      return array(
 133        self::CONFIG_AUX_PHID => true,
 134        self::CONFIG_SERIALIZATION => array(
 135          'subprojectPHIDs' => self::SERIALIZATION_JSON,
 136        ),
 137        self::CONFIG_COLUMN_SCHEMA => array(
 138          'name' => 'sort128',
 139          'status' => 'text32',
 140          'phrictionSlug' => 'text128?',
 141          'isMembershipLocked' => 'bool',
 142          'profileImagePHID' => 'phid?',
 143          'icon' => 'text32',
 144          'color' => 'text32',
 145  
 146          // T6203/NULLABILITY
 147          // These are definitely wrong and should always exist.
 148          'editPolicy' => 'policy?',
 149          'viewPolicy' => 'policy?',
 150          'joinPolicy' => 'policy?',
 151        ),
 152        self::CONFIG_KEY_SCHEMA => array(
 153          'key_phid' => null,
 154          'phid' => array(
 155            'columns' => array('phid'),
 156            'unique' => true,
 157          ),
 158          'key_icon' => array(
 159            'columns' => array('icon'),
 160          ),
 161          'key_color' => array(
 162            'columns' => array('color'),
 163          ),
 164          'phrictionSlug' => array(
 165            'columns' => array('phrictionSlug'),
 166            'unique' => true,
 167          ),
 168          'name' => array(
 169            'columns' => array('name'),
 170            'unique' => true,
 171          ),
 172        ),
 173      ) + parent::getConfiguration();
 174    }
 175  
 176    public function generatePHID() {
 177      return PhabricatorPHID::generateNewPHID(
 178        PhabricatorProjectProjectPHIDType::TYPECONST);
 179    }
 180  
 181    public function attachMemberPHIDs(array $phids) {
 182      $this->memberPHIDs = $phids;
 183      return $this;
 184    }
 185  
 186    public function getMemberPHIDs() {
 187      return $this->assertAttached($this->memberPHIDs);
 188    }
 189  
 190    public function setPhrictionSlug($slug) {
 191  
 192      // NOTE: We're doing a little magic here and stripping out '/' so that
 193      // project pages always appear at top level under projects/ even if the
 194      // display name is "Hack / Slash" or similar (it will become
 195      // 'hack_slash' instead of 'hack/slash').
 196  
 197      $slug = str_replace('/', ' ', $slug);
 198      $slug = PhabricatorSlug::normalize($slug);
 199      $this->phrictionSlug = $slug;
 200      return $this;
 201    }
 202  
 203    public function getFullPhrictionSlug() {
 204      $slug = $this->getPhrictionSlug();
 205      return 'projects/'.$slug;
 206    }
 207  
 208    // TODO - once we sever project => phriction automagicalness,
 209    // migrate getPhrictionSlug to have no trailing slash and be called
 210    // getPrimarySlug
 211    public function getPrimarySlug() {
 212      $slug = $this->getPhrictionSlug();
 213      return rtrim($slug, '/');
 214    }
 215  
 216    public function isArchived() {
 217      return ($this->getStatus() == PhabricatorProjectStatus::STATUS_ARCHIVED);
 218    }
 219  
 220    public function getProfileImageURI() {
 221      return $this->getProfileImageFile()->getBestURI();
 222    }
 223  
 224    public function attachProfileImageFile(PhabricatorFile $file) {
 225      $this->profileImageFile = $file;
 226      return $this;
 227    }
 228  
 229    public function getProfileImageFile() {
 230      return $this->assertAttached($this->profileImageFile);
 231    }
 232  
 233  
 234    public function isUserWatcher($user_phid) {
 235      if ($this->watcherPHIDs !== self::ATTACHABLE) {
 236        return in_array($user_phid, $this->watcherPHIDs);
 237      }
 238      return $this->assertAttachedKey($this->sparseWatchers, $user_phid);
 239    }
 240  
 241    public function setIsUserWatcher($user_phid, $is_watcher) {
 242      if ($this->sparseWatchers === self::ATTACHABLE) {
 243        $this->sparseWatchers = array();
 244      }
 245      $this->sparseWatchers[$user_phid] = $is_watcher;
 246      return $this;
 247    }
 248  
 249    public function attachWatcherPHIDs(array $phids) {
 250      $this->watcherPHIDs = $phids;
 251      return $this;
 252    }
 253  
 254    public function getWatcherPHIDs() {
 255      return $this->assertAttached($this->watcherPHIDs);
 256    }
 257  
 258    public function attachSlugs(array $slugs) {
 259      $this->slugs = $slugs;
 260      return $this;
 261    }
 262  
 263    public function getSlugs() {
 264      return $this->assertAttached($this->slugs);
 265    }
 266  
 267    public function getColor() {
 268      if ($this->isArchived()) {
 269        return PHUITagView::COLOR_DISABLED;
 270      }
 271  
 272      return $this->color;
 273    }
 274  
 275    public function save() {
 276      $this->openTransaction();
 277        $result = parent::save();
 278        $this->updateDatasourceTokens();
 279      $this->saveTransaction();
 280  
 281      return $result;
 282    }
 283  
 284    public function updateDatasourceTokens() {
 285      $table = self::TABLE_DATASOURCE_TOKEN;
 286      $conn_w = $this->establishConnection('w');
 287      $id = $this->getID();
 288  
 289      $slugs = queryfx_all(
 290        $conn_w,
 291        'SELECT * FROM %T WHERE projectPHID = %s',
 292        id(new PhabricatorProjectSlug())->getTableName(),
 293        $this->getPHID());
 294  
 295      $all_strings = ipull($slugs, 'slug');
 296      $all_strings[] = $this->getName();
 297      $all_strings = implode(' ', $all_strings);
 298  
 299      $tokens = PhabricatorTypeaheadDatasource::tokenizeString($all_strings);
 300  
 301      $sql = array();
 302      foreach ($tokens as $token) {
 303        $sql[] = qsprintf($conn_w, '(%d, %s)', $id, $token);
 304      }
 305  
 306      $this->openTransaction();
 307        queryfx(
 308          $conn_w,
 309          'DELETE FROM %T WHERE projectID = %d',
 310          $table,
 311          $id);
 312  
 313        foreach (PhabricatorLiskDAO::chunkSQL($sql) as $chunk) {
 314          queryfx(
 315            $conn_w,
 316            'INSERT INTO %T (projectID, token) VALUES %Q',
 317            $table,
 318            $chunk);
 319        }
 320      $this->saveTransaction();
 321    }
 322  
 323  
 324  /* -(  PhabricatorSubscribableInterface  )----------------------------------- */
 325  
 326  
 327    public function isAutomaticallySubscribed($phid) {
 328      return false;
 329    }
 330  
 331    public function shouldShowSubscribersProperty() {
 332      return false;
 333    }
 334  
 335    public function shouldAllowSubscription($phid) {
 336      return $this->isUserMember($phid) &&
 337             !$this->isUserWatcher($phid);
 338    }
 339  
 340  
 341  /* -(  PhabricatorCustomFieldInterface  )------------------------------------ */
 342  
 343  
 344    public function getCustomFieldSpecificationForRole($role) {
 345      return PhabricatorEnv::getEnvConfig('projects.fields');
 346    }
 347  
 348    public function getCustomFieldBaseClass() {
 349      return 'PhabricatorProjectCustomField';
 350    }
 351  
 352    public function getCustomFields() {
 353      return $this->assertAttached($this->customFields);
 354    }
 355  
 356    public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) {
 357      $this->customFields = $fields;
 358      return $this;
 359    }
 360  
 361  
 362  /* -(  PhabricatorDestructibleInterface  )----------------------------------- */
 363  
 364    public function destroyObjectPermanently(
 365      PhabricatorDestructionEngine $engine) {
 366  
 367      $this->openTransaction();
 368        $this->delete();
 369  
 370        $columns = id(new PhabricatorProjectColumn())
 371          ->loadAllWhere('projectPHID = %s', $this->getPHID());
 372        foreach ($columns as $column) {
 373          $engine->destroyObject($column);
 374        }
 375  
 376        $slugs = id(new PhabricatorProjectSlug())
 377          ->loadAllWhere('projectPHID = %s', $this->getPHID());
 378        foreach ($slugs as $slug) {
 379          $slug->delete();
 380        }
 381  
 382      $this->saveTransaction();
 383    }
 384  
 385  }


Generated: Sun Nov 30 09:20:46 2014 Cross-referenced by PHPXref 0.7.1