array( 'properties' => self::SERIALIZATION_JSON, ), self::CONFIG_COLUMN_SCHEMA => array( 'version' => 'uint32', ), self::CONFIG_KEY_SCHEMA => array( 'key_object' => array( 'columns' => array('objectPHID', 'authorPHID', 'version'), 'unique' => true, ), ), ) + parent::getConfiguration(); } public function setProperty($key, $value) { $this->properties[$key] = $value; return $this; } public function getProperty($key, $default = null) { return idx($this->properties, $key, $default); } public static function loadDrafts( array $object_phids, $viewer_phid) { $rows = id(new self())->loadAllWhere( 'objectPHID IN (%Ls) AND authorPHID = %s ORDER BY version ASC', $object_phids, $viewer_phid); $map = array(); foreach ($rows as $row) { $map[$row->getObjectPHID()] = $row; } return $map; } public static function loadDraft( $object_phid, $viewer_phid) { return id(new PhabricatorVersionedDraft())->loadOneWhere( 'objectPHID = %s AND authorPHID = %s ORDER BY version DESC LIMIT 1', $object_phid, $viewer_phid); } public static function loadOrCreateDraft( $object_phid, $viewer_phid, $version) { $draft = self::loadDraft($object_phid, $viewer_phid); if ($draft) { return $draft; } try { return id(new self()) ->setObjectPHID($object_phid) ->setAuthorPHID($viewer_phid) ->setVersion((int)$version) ->save(); } catch (AphrontDuplicateKeyQueryException $ex) { $duplicate_exception = $ex; } // In rare cases we can race ourselves, and at one point there was a bug // which caused the browser to submit two preview requests at exactly // the same time. If the insert failed with a duplicate key exception, // try to load the colliding row to recover from it. $draft = self::loadDraft($object_phid, $viewer_phid); if ($draft) { return $draft; } throw $duplicate_exception; } public static function purgeDrafts( $object_phid, $viewer_phid) { $draft = new PhabricatorVersionedDraft(); $conn_w = $draft->establishConnection('w'); queryfx( $conn_w, 'DELETE FROM %T WHERE objectPHID = %s AND authorPHID = %s', $draft->getTableName(), $object_phid, $viewer_phid); } }