@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.)
hq.recaptime.dev/wiki/Phorge
phorge
phabricator
1<?php
2
3final class DivinerAtomRef extends Phobject {
4
5 private $book;
6 private $context;
7 private $type;
8 private $name;
9 private $group;
10 private $summary;
11 private $index;
12 private $title;
13
14 public function getSortKey() {
15 return implode(
16 "\0",
17 array(
18 $this->getName(),
19 $this->getType(),
20 $this->getContext(),
21 $this->getBook(),
22 $this->getIndex(),
23 ));
24 }
25
26 public function setIndex($index) {
27 $this->index = $index;
28 return $this;
29 }
30
31 public function getIndex() {
32 return $this->index;
33 }
34
35 public function setSummary($summary) {
36 $this->summary = $summary;
37 return $this;
38 }
39
40 public function getSummary() {
41 return $this->summary;
42 }
43
44 public function setName($name) {
45 $normal_name = self::normalizeString($name);
46 if (preg_match('/^@\d+\z/', $normal_name)) {
47 throw new Exception(
48 pht(
49 "Atom names must not be in the form '%s'. This pattern is ".
50 "reserved for disambiguating atoms with similar names.",
51 '/@\d+/'));
52 }
53 $this->name = $normal_name;
54 return $this;
55 }
56
57 public function getName() {
58 return $this->name;
59 }
60
61 public function setType($type) {
62 $this->type = self::normalizeString($type);
63 return $this;
64 }
65
66 public function getType() {
67 return $this->type;
68 }
69
70 public function setContext($context) {
71 if ($context === null) {
72 $this->context = $context;
73 } else {
74 $this->context = self::normalizeString($context);
75 }
76 return $this;
77 }
78
79 public function getContext() {
80 return $this->context;
81 }
82
83 public function setBook($book) {
84 if ($book === null) {
85 $this->book = $book;
86 } else {
87 $this->book = self::normalizeString($book);
88 }
89 return $this;
90 }
91
92 public function getBook() {
93 return $this->book;
94 }
95
96 public function setGroup($group) {
97 $this->group = $group;
98 return $this;
99 }
100
101 public function getGroup() {
102 return $this->group;
103 }
104
105 public function setTitle($title) {
106 $this->title = $title;
107 return $this;
108 }
109
110 public function getTitle() {
111 return $this->title;
112 }
113
114 public function getTitleSlug() {
115 return self::normalizeTitleString($this->getTitle());
116 }
117
118 public function toDictionary() {
119 return array(
120 'book' => $this->getBook(),
121 'context' => $this->getContext(),
122 'type' => $this->getType(),
123 'name' => $this->getName(),
124 'group' => $this->getGroup(),
125 'summary' => $this->getSummary(),
126 'index' => $this->getIndex(),
127 'title' => $this->getTitle(),
128 );
129 }
130
131 public function toHash() {
132 $dict = $this->toDictionary();
133
134 unset($dict['group']);
135 unset($dict['index']);
136 unset($dict['summary']);
137 unset($dict['title']);
138
139 ksort($dict);
140 return md5(serialize($dict)).'S';
141 }
142
143 public static function newFromDictionary(array $dict) {
144 return id(new DivinerAtomRef())
145 ->setBook(idx($dict, 'book'))
146 ->setContext(idx($dict, 'context'))
147 ->setType(idx($dict, 'type'))
148 ->setName(idx($dict, 'name'))
149 ->setGroup(idx($dict, 'group'))
150 ->setSummary(idx($dict, 'summary'))
151 ->setIndex(idx($dict, 'index'))
152 ->setTitle(idx($dict, 'title'));
153 }
154
155 public static function normalizeString($str) {
156 // These characters create problems on the filesystem or in URIs. Replace
157 // them with non-problematic approximations (instead of simply removing
158 // them) to keep the URIs fairly useful and avoid unnecessary collisions.
159 // These approximations are selected based on some domain knowledge of
160 // common languages: where a character is used as a delimiter, it is more
161 // helpful to replace it with a "." or a ":" or similar, while it's better
162 // if operator overloads read as, e.g., "operator_div".
163
164 $map = array(
165 // Hopefully not used anywhere by anything.
166 '#' => '.',
167
168 // Used in Ruby methods.
169 '?' => 'Q',
170
171 // Used in PHP namespaces.
172 '\\' => '.',
173
174 // Used in "operator +" in C++.
175 '+' => 'plus',
176
177 // Used in "operator %" in C++.
178 '%' => 'mod',
179
180 // Used in "operator /" in C++.
181 '/' => 'div',
182 );
183 $str = str_replace(array_keys($map), array_values($map), $str);
184
185 // Replace all spaces with underscores.
186 $str = preg_replace('/ +/', '_', $str);
187
188 // Replace control characters with "X".
189 $str = preg_replace('/[\x00-\x19]/', 'X', $str);
190
191 // Replace specific problematic names with alternative names.
192 $alternates = array(
193 '.' => 'dot',
194 '..' => 'dotdot',
195 '' => 'null',
196 );
197
198 return idx($alternates, $str, $str);
199 }
200
201 public static function normalizeTitleString($str) {
202 // Remove colons from titles. This is mostly to accommodate legacy rules
203 // from the old Diviner, which generated a significant number of article
204 // URIs without colons present in the titles.
205 $str = str_replace(':', '', $str);
206 $str = self::normalizeString($str);
207 return phutil_utf8_strtolower($str);
208 }
209
210}