/src/applications/feed/publisher/PhabricatorFeedStoryPublisher.php
PHP | 133 lines | 78 code | 19 blank | 36 comment | 6 complexity | c5d6cee8f981a59971e2af28dd6f5e4e MD5 | raw file
Possible License(s): JSON, MPL-2.0-no-copyleft-exception, Apache-2.0, BSD-3-Clause, LGPL-2.0, MIT, LGPL-2.1, LGPL-3.0
- <?php
- /*
- * Copyright 2011 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- final class PhabricatorFeedStoryPublisher {
- private $relatedPHIDs;
- private $storyType;
- private $storyData;
- private $storyTime;
- private $storyAuthorPHID;
- public function setRelatedPHIDs(array $phids) {
- $this->relatedPHIDs = $phids;
- return $this;
- }
- public function setStoryType($story_type) {
- $this->storyType = $story_type;
- return $this;
- }
- public function setStoryData(array $data) {
- $this->storyData = $data;
- return $this;
- }
- public function setStoryTime($time) {
- $this->storyTime = $time;
- return $this;
- }
- public function setStoryAuthorPHID($phid) {
- $this->storyAuthorPHID = $phid;
- return $this;
- }
- public function publish() {
- if (!$this->relatedPHIDs) {
- throw new Exception("There are no PHIDs related to this story!");
- }
- if (!$this->storyType) {
- throw new Exception("Call setStoryType() before publishing!");
- }
- $chrono_key = $this->generateChronologicalKey();
- $story = new PhabricatorFeedStoryData();
- $story->setStoryType($this->storyType);
- $story->setStoryData($this->storyData);
- $story->setAuthorPHID($this->storyAuthorPHID);
- $story->setChronologicalKey($chrono_key);
- $story->save();
- $ref = new PhabricatorFeedStoryReference();
- $sql = array();
- $conn = $ref->establishConnection('w');
- foreach (array_unique($this->relatedPHIDs) as $phid) {
- $sql[] = qsprintf(
- $conn,
- '(%s, %s)',
- $phid,
- $chrono_key);
- }
- queryfx(
- $conn,
- 'INSERT INTO %T (objectPHID, chronologicalKey) VALUES %Q',
- $ref->getTableName(),
- implode(', ', $sql));
- return $story;
- }
- /**
- * We generate a unique chronological key for each story type because we want
- * to be able to page through the stream with a cursor (i.e., select stories
- * after ID = X) so we can efficiently perform filtering after selecting data,
- * and multiple stories with the same ID make this cumbersome without putting
- * a bunch of logic in the client. We could use the primary key, but that
- * would prevent publishing stories which happened in the past. Since it's
- * potentially useful to do that (e.g., if you're importing another data
- * source) build a unique key for each story which has chronological ordering.
- *
- * @return string A unique, time-ordered key which identifies the story.
- */
- private function generateChronologicalKey() {
- // Use the epoch timestamp for the upper 32 bits of the key. Default to
- // the current time if the story doesn't have an explicit timestamp.
- $time = nonempty($this->storyTime, time());
- // Generate a random number for the lower 32 bits of the key.
- $rand = head(unpack('L', Filesystem::readRandomBytes(4)));
- // On 32-bit machines, we have to get creative.
- if (PHP_INT_SIZE < 8) {
- // We're on a 32-bit machine.
- if (function_exists('bcadd')) {
- // Try to use the 'bc' extension.
- return bcadd(bcmul($time, bcpow(2, 32)), $rand);
- } else {
- // Do the math in MySQL. TODO: If we formalize a bc dependency, get
- // rid of this.
- $conn_r = id(new PhabricatorFeedStoryData())->establishConnection('r');
- $result = queryfx_one(
- $conn_r,
- 'SELECT (%d << 32) + %d as N',
- $time,
- $rand);
- return $result['N'];
- }
- } else {
- // This is a 64 bit machine, so we can just do the math.
- return ($time << 32) + $rand;
- }
- }
- }