[ Index ] |
PHP Cross Reference of Phabricator |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Nov 30 09:20:46 2014 | Cross-referenced by PHPXref 0.7.1 |