Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/fact/engine/PhabricatorManiphestTaskFactEngine.php
12256 views
1
<?php
2
3
final class PhabricatorManiphestTaskFactEngine
4
extends PhabricatorTransactionFactEngine {
5
6
public function newFacts() {
7
return array(
8
id(new PhabricatorCountFact())
9
->setKey('tasks.count.create'),
10
11
id(new PhabricatorCountFact())
12
->setKey('tasks.open-count.create'),
13
id(new PhabricatorCountFact())
14
->setKey('tasks.open-count.status'),
15
16
id(new PhabricatorCountFact())
17
->setKey('tasks.count.create.project'),
18
id(new PhabricatorCountFact())
19
->setKey('tasks.count.assign.project'),
20
id(new PhabricatorCountFact())
21
->setKey('tasks.open-count.create.project'),
22
id(new PhabricatorCountFact())
23
->setKey('tasks.open-count.status.project'),
24
id(new PhabricatorCountFact())
25
->setKey('tasks.open-count.assign.project'),
26
27
id(new PhabricatorCountFact())
28
->setKey('tasks.count.create.owner'),
29
id(new PhabricatorCountFact())
30
->setKey('tasks.count.assign.owner'),
31
id(new PhabricatorCountFact())
32
->setKey('tasks.open-count.create.owner'),
33
id(new PhabricatorCountFact())
34
->setKey('tasks.open-count.status.owner'),
35
id(new PhabricatorCountFact())
36
->setKey('tasks.open-count.assign.owner'),
37
38
id(new PhabricatorPointsFact())
39
->setKey('tasks.points.create'),
40
id(new PhabricatorPointsFact())
41
->setKey('tasks.points.score'),
42
43
id(new PhabricatorPointsFact())
44
->setKey('tasks.open-points.create'),
45
id(new PhabricatorPointsFact())
46
->setKey('tasks.open-points.status'),
47
id(new PhabricatorPointsFact())
48
->setKey('tasks.open-points.score'),
49
50
id(new PhabricatorPointsFact())
51
->setKey('tasks.points.create.project'),
52
id(new PhabricatorPointsFact())
53
->setKey('tasks.points.assign.project'),
54
id(new PhabricatorPointsFact())
55
->setKey('tasks.points.score.project'),
56
id(new PhabricatorPointsFact())
57
->setKey('tasks.open-points.create.project'),
58
id(new PhabricatorPointsFact())
59
->setKey('tasks.open-points.status.project'),
60
id(new PhabricatorPointsFact())
61
->setKey('tasks.open-points.score.project'),
62
id(new PhabricatorPointsFact())
63
->setKey('tasks.open-points.assign.project'),
64
65
id(new PhabricatorPointsFact())
66
->setKey('tasks.points.create.owner'),
67
id(new PhabricatorPointsFact())
68
->setKey('tasks.points.assign.owner'),
69
id(new PhabricatorPointsFact())
70
->setKey('tasks.points.score.owner'),
71
id(new PhabricatorPointsFact())
72
->setKey('tasks.open-points.create.owner'),
73
id(new PhabricatorPointsFact())
74
->setKey('tasks.open-points.status.owner'),
75
id(new PhabricatorPointsFact())
76
->setKey('tasks.open-points.score.owner'),
77
id(new PhabricatorPointsFact())
78
->setKey('tasks.open-points.assign.owner'),
79
);
80
}
81
82
public function supportsDatapointsForObject(PhabricatorLiskDAO $object) {
83
return ($object instanceof ManiphestTask);
84
}
85
86
public function newDatapointsForObject(PhabricatorLiskDAO $object) {
87
$xaction_groups = $this->newTransactionGroupsForObject($object);
88
89
$old_open = false;
90
$old_points = 0;
91
$old_owner = null;
92
$project_map = array();
93
$object_phid = $object->getPHID();
94
$is_create = true;
95
96
$specs = array();
97
$datapoints = array();
98
foreach ($xaction_groups as $xaction_group) {
99
$add_projects = array();
100
$rem_projects = array();
101
102
$new_open = $old_open;
103
$new_points = $old_points;
104
$new_owner = $old_owner;
105
106
if ($is_create) {
107
// Assume tasks start open.
108
// TODO: This might be a questionable assumption?
109
$new_open = true;
110
}
111
112
$group_epoch = last($xaction_group)->getDateCreated();
113
foreach ($xaction_group as $xaction) {
114
$old_value = $xaction->getOldValue();
115
$new_value = $xaction->getNewValue();
116
switch ($xaction->getTransactionType()) {
117
case ManiphestTaskStatusTransaction::TRANSACTIONTYPE:
118
$new_open = !ManiphestTaskStatus::isClosedStatus($new_value);
119
break;
120
case ManiphestTaskMergedIntoTransaction::TRANSACTIONTYPE:
121
// When a task is merged into another task, it is changed to a
122
// closed status without generating a separate status transaction.
123
$new_open = false;
124
break;
125
case ManiphestTaskPointsTransaction::TRANSACTIONTYPE:
126
$new_points = (int)$xaction->getNewValue();
127
break;
128
case ManiphestTaskOwnerTransaction::TRANSACTIONTYPE:
129
$new_owner = $xaction->getNewValue();
130
break;
131
case PhabricatorTransactions::TYPE_EDGE:
132
$edge_type = $xaction->getMetadataValue('edge:type');
133
switch ($edge_type) {
134
case PhabricatorProjectObjectHasProjectEdgeType::EDGECONST:
135
$record = PhabricatorEdgeChangeRecord::newFromTransaction(
136
$xaction);
137
$add_projects += array_fuse($record->getAddedPHIDs());
138
$rem_projects += array_fuse($record->getRemovedPHIDs());
139
break;
140
}
141
break;
142
}
143
}
144
145
// If a project was both added and removed, moot it.
146
$mix_projects = array_intersect_key($add_projects, $rem_projects);
147
$add_projects = array_diff_key($add_projects, $mix_projects);
148
$rem_projects = array_diff_key($rem_projects, $mix_projects);
149
150
$project_sets = array(
151
array(
152
'phids' => $rem_projects,
153
'scale' => -1,
154
),
155
array(
156
'phids' => $add_projects,
157
'scale' => 1,
158
),
159
);
160
161
if ($is_create) {
162
$action = 'create';
163
$action_points = $new_points;
164
$include_open = $new_open;
165
} else {
166
$action = 'assign';
167
$action_points = $old_points;
168
$include_open = $old_open;
169
}
170
171
foreach ($project_sets as $project_set) {
172
$scale = $project_set['scale'];
173
foreach ($project_set['phids'] as $project_phid) {
174
if ($include_open) {
175
$specs[] = array(
176
"tasks.open-count.{$action}.project",
177
1 * $scale,
178
$project_phid,
179
);
180
181
$specs[] = array(
182
"tasks.open-points.{$action}.project",
183
$action_points * $scale,
184
$project_phid,
185
);
186
}
187
188
$specs[] = array(
189
"tasks.count.{$action}.project",
190
1 * $scale,
191
$project_phid,
192
);
193
194
$specs[] = array(
195
"tasks.points.{$action}.project",
196
$action_points * $scale,
197
$project_phid,
198
);
199
200
if ($scale < 0) {
201
unset($project_map[$project_phid]);
202
} else {
203
$project_map[$project_phid] = $project_phid;
204
}
205
}
206
}
207
208
if ($new_owner !== $old_owner) {
209
$owner_sets = array(
210
array(
211
'phid' => $old_owner,
212
'scale' => -1,
213
),
214
array(
215
'phid' => $new_owner,
216
'scale' => 1,
217
),
218
);
219
220
foreach ($owner_sets as $owner_set) {
221
$owner_phid = $owner_set['phid'];
222
if ($owner_phid === null) {
223
continue;
224
}
225
226
$scale = $owner_set['scale'];
227
228
if ($old_open != $new_open) {
229
$specs[] = array(
230
"tasks.open-count.{$action}.owner",
231
1 * $scale,
232
$owner_phid,
233
);
234
235
$specs[] = array(
236
"tasks.open-points.{$action}.owner",
237
$action_points * $scale,
238
$owner_phid,
239
);
240
}
241
242
$specs[] = array(
243
"tasks.count.{$action}.owner",
244
1 * $scale,
245
$owner_phid,
246
);
247
248
if ($action_points) {
249
$specs[] = array(
250
"tasks.points.{$action}.owner",
251
$action_points * $scale,
252
$owner_phid,
253
);
254
}
255
}
256
}
257
258
if ($is_create) {
259
$specs[] = array(
260
'tasks.count.create',
261
1,
262
);
263
264
$specs[] = array(
265
'tasks.points.create',
266
$new_points,
267
);
268
269
if ($new_open) {
270
$specs[] = array(
271
'tasks.open-count.create',
272
1,
273
);
274
$specs[] = array(
275
'tasks.open-points.create',
276
$new_points,
277
);
278
}
279
} else if ($new_open !== $old_open) {
280
if ($new_open) {
281
$scale = 1;
282
} else {
283
$scale = -1;
284
}
285
286
$specs[] = array(
287
'tasks.open-count.status',
288
1 * $scale,
289
);
290
291
$specs[] = array(
292
'tasks.open-points.status',
293
$action_points * $scale,
294
);
295
296
if ($new_owner !== null) {
297
$specs[] = array(
298
'tasks.open-count.status.owner',
299
1 * $scale,
300
$new_owner,
301
);
302
$specs[] = array(
303
'tasks.open-points.status.owner',
304
$action_points * $scale,
305
$new_owner,
306
);
307
}
308
309
foreach ($project_map as $project_phid) {
310
$specs[] = array(
311
'tasks.open-count.status.project',
312
1 * $scale,
313
$project_phid,
314
);
315
$specs[] = array(
316
'tasks.open-points.status.project',
317
$action_points * $scale,
318
$project_phid,
319
);
320
}
321
}
322
323
// The "score" facts only apply to rescoring tasks which already
324
// exist, so we skip them if the task is being created.
325
if (($new_points !== $old_points) && !$is_create) {
326
$delta = ($new_points - $old_points);
327
328
$specs[] = array(
329
'tasks.points.score',
330
$delta,
331
);
332
333
foreach ($project_map as $project_phid) {
334
$specs[] = array(
335
'tasks.points.score.project',
336
$delta,
337
$project_phid,
338
);
339
340
if ($old_open && $new_open) {
341
$specs[] = array(
342
'tasks.open-points.score.project',
343
$delta,
344
$project_phid,
345
);
346
}
347
}
348
349
if ($new_owner !== null) {
350
$specs[] = array(
351
'tasks.points.score.owner',
352
$delta,
353
$new_owner,
354
);
355
356
if ($old_open && $new_open) {
357
$specs[] = array(
358
'tasks.open-points.score.owner',
359
$delta,
360
$new_owner,
361
);
362
}
363
}
364
365
if ($old_open && $new_open) {
366
$specs[] = array(
367
'tasks.open-points.score',
368
$delta,
369
);
370
}
371
}
372
373
$old_points = $new_points;
374
$old_open = $new_open;
375
$old_owner = $new_owner;
376
377
foreach ($specs as $spec) {
378
$spec_key = $spec[0];
379
$spec_value = $spec[1];
380
381
// Don't write any facts with a value of 0. The "count" facts never
382
// have a value of 0, and the "points" facts aren't meaningful if
383
// they have a value of 0.
384
if ($spec_value == 0) {
385
continue;
386
}
387
388
$datapoint = $this->getFact($spec_key)
389
->newDatapoint();
390
391
$datapoint
392
->setObjectPHID($object_phid)
393
->setValue($spec_value)
394
->setEpoch($group_epoch);
395
396
if (isset($spec[2])) {
397
$datapoint->setDimensionPHID($spec[2]);
398
}
399
400
$datapoints[] = $datapoint;
401
}
402
403
$specs = array();
404
$is_create = false;
405
}
406
407
return $datapoints;
408
}
409
410
411
}
412
413