Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/owners/storage/PhabricatorOwnersPackage.php
12256 views
1
<?php
2
3
final class PhabricatorOwnersPackage
4
extends PhabricatorOwnersDAO
5
implements
6
PhabricatorPolicyInterface,
7
PhabricatorApplicationTransactionInterface,
8
PhabricatorCustomFieldInterface,
9
PhabricatorDestructibleInterface,
10
PhabricatorConduitResultInterface,
11
PhabricatorFulltextInterface,
12
PhabricatorFerretInterface,
13
PhabricatorNgramsInterface {
14
15
protected $name;
16
protected $autoReview;
17
protected $description;
18
protected $status;
19
protected $viewPolicy;
20
protected $editPolicy;
21
protected $dominion;
22
protected $properties = array();
23
protected $auditingState;
24
protected $authorityMode;
25
26
private $paths = self::ATTACHABLE;
27
private $owners = self::ATTACHABLE;
28
private $customFields = self::ATTACHABLE;
29
private $pathRepositoryMap = array();
30
31
const STATUS_ACTIVE = 'active';
32
const STATUS_ARCHIVED = 'archived';
33
34
const AUTOREVIEW_NONE = 'none';
35
const AUTOREVIEW_SUBSCRIBE = 'subscribe';
36
const AUTOREVIEW_SUBSCRIBE_ALWAYS = 'subscribe-always';
37
const AUTOREVIEW_REVIEW = 'review';
38
const AUTOREVIEW_REVIEW_ALWAYS = 'review-always';
39
const AUTOREVIEW_BLOCK = 'block';
40
const AUTOREVIEW_BLOCK_ALWAYS = 'block-always';
41
42
const DOMINION_STRONG = 'strong';
43
const DOMINION_WEAK = 'weak';
44
45
const AUTHORITY_STRONG = 'strong';
46
const AUTHORITY_WEAK = 'weak';
47
48
const PROPERTY_IGNORED = 'ignored';
49
50
public static function initializeNewPackage(PhabricatorUser $actor) {
51
$app = id(new PhabricatorApplicationQuery())
52
->setViewer($actor)
53
->withClasses(array('PhabricatorOwnersApplication'))
54
->executeOne();
55
56
$view_policy = $app->getPolicy(
57
PhabricatorOwnersDefaultViewCapability::CAPABILITY);
58
$edit_policy = $app->getPolicy(
59
PhabricatorOwnersDefaultEditCapability::CAPABILITY);
60
61
return id(new PhabricatorOwnersPackage())
62
->setAuditingState(PhabricatorOwnersAuditRule::AUDITING_NONE)
63
->setAutoReview(self::AUTOREVIEW_NONE)
64
->setDominion(self::DOMINION_STRONG)
65
->setAuthorityMode(self::AUTHORITY_STRONG)
66
->setViewPolicy($view_policy)
67
->setEditPolicy($edit_policy)
68
->attachPaths(array())
69
->setStatus(self::STATUS_ACTIVE)
70
->attachOwners(array())
71
->setDescription('');
72
}
73
74
public static function getStatusNameMap() {
75
return array(
76
self::STATUS_ACTIVE => pht('Active'),
77
self::STATUS_ARCHIVED => pht('Archived'),
78
);
79
}
80
81
public static function getAutoreviewOptionsMap() {
82
return array(
83
self::AUTOREVIEW_NONE => array(
84
'name' => pht('No Autoreview'),
85
),
86
self::AUTOREVIEW_REVIEW => array(
87
'name' => pht('Review Changes With Non-Owner Author'),
88
'authority' => true,
89
),
90
self::AUTOREVIEW_BLOCK => array(
91
'name' => pht('Review Changes With Non-Owner Author (Blocking)'),
92
'authority' => true,
93
),
94
self::AUTOREVIEW_SUBSCRIBE => array(
95
'name' => pht('Subscribe to Changes With Non-Owner Author'),
96
'authority' => true,
97
),
98
self::AUTOREVIEW_REVIEW_ALWAYS => array(
99
'name' => pht('Review All Changes'),
100
),
101
self::AUTOREVIEW_BLOCK_ALWAYS => array(
102
'name' => pht('Review All Changes (Blocking)'),
103
),
104
self::AUTOREVIEW_SUBSCRIBE_ALWAYS => array(
105
'name' => pht('Subscribe to All Changes'),
106
),
107
);
108
}
109
110
public static function getDominionOptionsMap() {
111
return array(
112
self::DOMINION_STRONG => array(
113
'name' => pht('Strong (Control All Paths)'),
114
'short' => pht('Strong'),
115
),
116
self::DOMINION_WEAK => array(
117
'name' => pht('Weak (Control Unowned Paths)'),
118
'short' => pht('Weak'),
119
),
120
);
121
}
122
123
public static function getAuthorityOptionsMap() {
124
return array(
125
self::AUTHORITY_STRONG => array(
126
'name' => pht('Strong (Package Owns Paths)'),
127
'short' => pht('Strong'),
128
),
129
self::AUTHORITY_WEAK => array(
130
'name' => pht('Weak (Package Watches Paths)'),
131
'short' => pht('Weak'),
132
),
133
);
134
}
135
136
protected function getConfiguration() {
137
return array(
138
// This information is better available from the history table.
139
self::CONFIG_TIMESTAMPS => false,
140
self::CONFIG_AUX_PHID => true,
141
self::CONFIG_SERIALIZATION => array(
142
'properties' => self::SERIALIZATION_JSON,
143
),
144
self::CONFIG_COLUMN_SCHEMA => array(
145
'name' => 'sort',
146
'description' => 'text',
147
'auditingState' => 'text32',
148
'status' => 'text32',
149
'autoReview' => 'text32',
150
'dominion' => 'text32',
151
'authorityMode' => 'text32',
152
),
153
) + parent::getConfiguration();
154
}
155
156
public function getPHIDType() {
157
return PhabricatorOwnersPackagePHIDType::TYPECONST;
158
}
159
160
public function isArchived() {
161
return ($this->getStatus() == self::STATUS_ARCHIVED);
162
}
163
164
public function getMustMatchUngeneratedPaths() {
165
$ignore_attributes = $this->getIgnoredPathAttributes();
166
return !empty($ignore_attributes['generated']);
167
}
168
169
public function getPackageProperty($key, $default = null) {
170
return idx($this->properties, $key, $default);
171
}
172
173
public function setPackageProperty($key, $value) {
174
$this->properties[$key] = $value;
175
return $this;
176
}
177
178
public function getIgnoredPathAttributes() {
179
return $this->getPackageProperty(self::PROPERTY_IGNORED, array());
180
}
181
182
public function setIgnoredPathAttributes(array $attributes) {
183
return $this->setPackageProperty(self::PROPERTY_IGNORED, $attributes);
184
}
185
186
public function loadOwners() {
187
if (!$this->getID()) {
188
return array();
189
}
190
return id(new PhabricatorOwnersOwner())->loadAllWhere(
191
'packageID = %d',
192
$this->getID());
193
}
194
195
public function loadPaths() {
196
if (!$this->getID()) {
197
return array();
198
}
199
return id(new PhabricatorOwnersPath())->loadAllWhere(
200
'packageID = %d',
201
$this->getID());
202
}
203
204
public static function loadAffectedPackages(
205
PhabricatorRepository $repository,
206
array $paths) {
207
208
if (!$paths) {
209
return array();
210
}
211
212
return self::loadPackagesForPaths($repository, $paths);
213
}
214
215
public static function loadAffectedPackagesForChangesets(
216
PhabricatorRepository $repository,
217
DifferentialDiff $diff,
218
array $changesets) {
219
assert_instances_of($changesets, 'DifferentialChangeset');
220
221
$paths_all = array();
222
$paths_ungenerated = array();
223
224
foreach ($changesets as $changeset) {
225
$path = $changeset->getAbsoluteRepositoryPath($repository, $diff);
226
227
$paths_all[] = $path;
228
229
if (!$changeset->isGeneratedChangeset()) {
230
$paths_ungenerated[] = $path;
231
}
232
}
233
234
if (!$paths_all) {
235
return array();
236
}
237
238
$packages_all = self::loadAffectedPackages(
239
$repository,
240
$paths_all);
241
242
// If there are no generated changesets, we can't possibly need to throw
243
// away any packages for matching only generated paths. Just return the
244
// full set of packages.
245
if ($paths_ungenerated === $paths_all) {
246
return $packages_all;
247
}
248
249
$must_match_ungenerated = array();
250
foreach ($packages_all as $package) {
251
if ($package->getMustMatchUngeneratedPaths()) {
252
$must_match_ungenerated[] = $package;
253
}
254
}
255
256
// If no affected packages have the "Ignore Generated Paths" flag set, we
257
// can't possibly need to throw any away.
258
if (!$must_match_ungenerated) {
259
return $packages_all;
260
}
261
262
if ($paths_ungenerated) {
263
$packages_ungenerated = self::loadAffectedPackages(
264
$repository,
265
$paths_ungenerated);
266
} else {
267
$packages_ungenerated = array();
268
}
269
270
// We have some generated paths, and some packages that ignore generated
271
// paths. Take all the packages which:
272
//
273
// - ignore generated paths; and
274
// - didn't match any ungenerated paths
275
//
276
// ...and remove them from the list.
277
278
$must_match_ungenerated = mpull($must_match_ungenerated, null, 'getID');
279
$packages_ungenerated = mpull($packages_ungenerated, null, 'getID');
280
$packages_all = mpull($packages_all, null, 'getID');
281
282
foreach ($must_match_ungenerated as $package_id => $package) {
283
if (!isset($packages_ungenerated[$package_id])) {
284
unset($packages_all[$package_id]);
285
}
286
}
287
288
return $packages_all;
289
}
290
291
public static function loadOwningPackages($repository, $path) {
292
if (empty($path)) {
293
return array();
294
}
295
296
return self::loadPackagesForPaths($repository, array($path), 1);
297
}
298
299
private static function loadPackagesForPaths(
300
PhabricatorRepository $repository,
301
array $paths,
302
$limit = 0) {
303
304
$fragments = array();
305
foreach ($paths as $path) {
306
foreach (self::splitPath($path) as $fragment) {
307
$fragments[$fragment][$path] = true;
308
}
309
}
310
311
$package = new PhabricatorOwnersPackage();
312
$path = new PhabricatorOwnersPath();
313
$conn = $package->establishConnection('r');
314
315
$repository_clause = qsprintf(
316
$conn,
317
'AND p.repositoryPHID = %s',
318
$repository->getPHID());
319
320
// NOTE: The list of $paths may be very large if we're coming from
321
// the OwnersWorker and processing, e.g., an SVN commit which created a new
322
// branch. Break it apart so that it will fit within 'max_allowed_packet',
323
// and then merge results in PHP.
324
325
$rows = array();
326
foreach (array_chunk(array_keys($fragments), 1024) as $chunk) {
327
$indexes = array();
328
foreach ($chunk as $fragment) {
329
$indexes[] = PhabricatorHash::digestForIndex($fragment);
330
}
331
332
$rows[] = queryfx_all(
333
$conn,
334
'SELECT pkg.id, pkg.dominion, p.excluded, p.path
335
FROM %T pkg JOIN %T p ON p.packageID = pkg.id
336
WHERE p.pathIndex IN (%Ls) AND pkg.status IN (%Ls) %Q',
337
$package->getTableName(),
338
$path->getTableName(),
339
$indexes,
340
array(
341
self::STATUS_ACTIVE,
342
),
343
$repository_clause);
344
}
345
$rows = array_mergev($rows);
346
347
$ids = self::findLongestPathsPerPackage($rows, $fragments);
348
349
if (!$ids) {
350
return array();
351
}
352
353
arsort($ids);
354
if ($limit) {
355
$ids = array_slice($ids, 0, $limit, $preserve_keys = true);
356
}
357
$ids = array_keys($ids);
358
359
$packages = $package->loadAllWhere('id in (%Ld)', $ids);
360
$packages = array_select_keys($packages, $ids);
361
362
return $packages;
363
}
364
365
public static function loadPackagesForRepository($repository) {
366
$package = new PhabricatorOwnersPackage();
367
$ids = ipull(
368
queryfx_all(
369
$package->establishConnection('r'),
370
'SELECT DISTINCT packageID FROM %T WHERE repositoryPHID = %s',
371
id(new PhabricatorOwnersPath())->getTableName(),
372
$repository->getPHID()),
373
'packageID');
374
375
return $package->loadAllWhere('id in (%Ld)', $ids);
376
}
377
378
public static function findLongestPathsPerPackage(array $rows, array $paths) {
379
380
// Build a map from each path to all the package paths which match it.
381
$path_hits = array();
382
$weak = array();
383
foreach ($rows as $row) {
384
$id = $row['id'];
385
$path = $row['path'];
386
$length = strlen($path);
387
$excluded = $row['excluded'];
388
389
if ($row['dominion'] === self::DOMINION_WEAK) {
390
$weak[$id] = true;
391
}
392
393
$matches = $paths[$path];
394
foreach ($matches as $match => $ignored) {
395
$path_hits[$match][] = array(
396
'id' => $id,
397
'excluded' => $excluded,
398
'length' => $length,
399
);
400
}
401
}
402
403
// For each path, process the matching package paths to figure out which
404
// packages actually own it.
405
$path_packages = array();
406
foreach ($path_hits as $match => $hits) {
407
$hits = isort($hits, 'length');
408
409
$packages = array();
410
foreach ($hits as $hit) {
411
$package_id = $hit['id'];
412
if ($hit['excluded']) {
413
unset($packages[$package_id]);
414
} else {
415
$packages[$package_id] = $hit;
416
}
417
}
418
419
$path_packages[$match] = $packages;
420
}
421
422
// Remove packages with weak dominion rules that should cede control to
423
// a more specific package.
424
if ($weak) {
425
foreach ($path_packages as $match => $packages) {
426
427
// Group packages by length.
428
$length_map = array();
429
foreach ($packages as $package_id => $package) {
430
$length_map[$package['length']][$package_id] = $package;
431
}
432
433
// For each path length, remove all weak packages if there are any
434
// strong packages of the same length. This makes sure that if there
435
// are one or more strong claims on a particular path, only those
436
// claims stand.
437
foreach ($length_map as $package_list) {
438
$any_strong = false;
439
foreach ($package_list as $package_id => $package) {
440
if (!isset($weak[$package_id])) {
441
$any_strong = true;
442
break;
443
}
444
}
445
446
if ($any_strong) {
447
foreach ($package_list as $package_id => $package) {
448
if (isset($weak[$package_id])) {
449
unset($packages[$package_id]);
450
}
451
}
452
}
453
}
454
455
$packages = isort($packages, 'length');
456
$packages = array_reverse($packages, true);
457
458
$best_length = null;
459
foreach ($packages as $package_id => $package) {
460
// If this is the first package we've encountered, note its length.
461
// We're iterating over the packages from longest to shortest match,
462
// so packages of this length always have the best claim on the path.
463
if ($best_length === null) {
464
$best_length = $package['length'];
465
}
466
467
// If this package has the same length as the best length, its claim
468
// stands.
469
if ($package['length'] === $best_length) {
470
continue;
471
}
472
473
// If this is a weak package and does not have the best length,
474
// cede its claim to the stronger package.
475
if (isset($weak[$package_id])) {
476
unset($packages[$package_id]);
477
}
478
}
479
480
$path_packages[$match] = $packages;
481
}
482
}
483
484
// For each package that owns at least one path, identify the longest
485
// path it owns.
486
$package_lengths = array();
487
foreach ($path_packages as $match => $hits) {
488
foreach ($hits as $hit) {
489
$length = $hit['length'];
490
$id = $hit['id'];
491
if (empty($package_lengths[$id])) {
492
$package_lengths[$id] = $length;
493
} else {
494
$package_lengths[$id] = max($package_lengths[$id], $length);
495
}
496
}
497
}
498
499
return $package_lengths;
500
}
501
502
public static function splitPath($path) {
503
$result = array(
504
'/',
505
);
506
507
$parts = explode('/', $path);
508
$buffer = '/';
509
foreach ($parts as $part) {
510
if (!strlen($part)) {
511
continue;
512
}
513
514
$buffer = $buffer.$part.'/';
515
$result[] = $buffer;
516
}
517
518
return $result;
519
}
520
521
public function attachPaths(array $paths) {
522
assert_instances_of($paths, 'PhabricatorOwnersPath');
523
$this->paths = $paths;
524
525
// Drop this cache if we're attaching new paths.
526
$this->pathRepositoryMap = array();
527
528
return $this;
529
}
530
531
public function getPaths() {
532
return $this->assertAttached($this->paths);
533
}
534
535
public function getPathsForRepository($repository_phid) {
536
if (isset($this->pathRepositoryMap[$repository_phid])) {
537
return $this->pathRepositoryMap[$repository_phid];
538
}
539
540
$map = array();
541
foreach ($this->getPaths() as $path) {
542
if ($path->getRepositoryPHID() == $repository_phid) {
543
$map[] = $path;
544
}
545
}
546
547
$this->pathRepositoryMap[$repository_phid] = $map;
548
549
return $this->pathRepositoryMap[$repository_phid];
550
}
551
552
public function attachOwners(array $owners) {
553
assert_instances_of($owners, 'PhabricatorOwnersOwner');
554
$this->owners = $owners;
555
return $this;
556
}
557
558
public function getOwners() {
559
return $this->assertAttached($this->owners);
560
}
561
562
public function getOwnerPHIDs() {
563
return mpull($this->getOwners(), 'getUserPHID');
564
}
565
566
public function isOwnerPHID($phid) {
567
if (!$phid) {
568
return false;
569
}
570
571
$owner_phids = $this->getOwnerPHIDs();
572
$owner_phids = array_fuse($owner_phids);
573
574
return isset($owner_phids[$phid]);
575
}
576
577
public function getMonogram() {
578
return 'O'.$this->getID();
579
}
580
581
public function getURI() {
582
// TODO: Move these to "/O123" for consistency.
583
return '/owners/package/'.$this->getID().'/';
584
}
585
586
public function newAuditingRule() {
587
return PhabricatorOwnersAuditRule::newFromState($this->getAuditingState());
588
}
589
590
public function getHasStrongAuthority() {
591
return ($this->getAuthorityMode() === self::AUTHORITY_STRONG);
592
}
593
594
/* -( PhabricatorPolicyInterface )----------------------------------------- */
595
596
597
public function getCapabilities() {
598
return array(
599
PhabricatorPolicyCapability::CAN_VIEW,
600
PhabricatorPolicyCapability::CAN_EDIT,
601
);
602
}
603
604
public function getPolicy($capability) {
605
switch ($capability) {
606
case PhabricatorPolicyCapability::CAN_VIEW:
607
return $this->getViewPolicy();
608
case PhabricatorPolicyCapability::CAN_EDIT:
609
return $this->getEditPolicy();
610
}
611
}
612
613
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
614
switch ($capability) {
615
case PhabricatorPolicyCapability::CAN_VIEW:
616
if ($this->isOwnerPHID($viewer->getPHID())) {
617
return true;
618
}
619
break;
620
}
621
622
return false;
623
}
624
625
public function describeAutomaticCapability($capability) {
626
return pht('Owners of a package may always view it.');
627
}
628
629
630
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
631
632
633
public function getApplicationTransactionEditor() {
634
return new PhabricatorOwnersPackageTransactionEditor();
635
}
636
637
public function getApplicationTransactionTemplate() {
638
return new PhabricatorOwnersPackageTransaction();
639
}
640
641
642
/* -( PhabricatorCustomFieldInterface )------------------------------------ */
643
644
645
public function getCustomFieldSpecificationForRole($role) {
646
return PhabricatorEnv::getEnvConfig('owners.fields');
647
}
648
649
public function getCustomFieldBaseClass() {
650
return 'PhabricatorOwnersCustomField';
651
}
652
653
public function getCustomFields() {
654
return $this->assertAttached($this->customFields);
655
}
656
657
public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) {
658
$this->customFields = $fields;
659
return $this;
660
}
661
662
663
/* -( PhabricatorDestructibleInterface )----------------------------------- */
664
665
666
public function destroyObjectPermanently(
667
PhabricatorDestructionEngine $engine) {
668
669
$this->openTransaction();
670
$conn_w = $this->establishConnection('w');
671
672
queryfx(
673
$conn_w,
674
'DELETE FROM %T WHERE packageID = %d',
675
id(new PhabricatorOwnersPath())->getTableName(),
676
$this->getID());
677
678
queryfx(
679
$conn_w,
680
'DELETE FROM %T WHERE packageID = %d',
681
id(new PhabricatorOwnersOwner())->getTableName(),
682
$this->getID());
683
684
$this->delete();
685
$this->saveTransaction();
686
}
687
688
689
/* -( PhabricatorConduitResultInterface )---------------------------------- */
690
691
692
public function getFieldSpecificationsForConduit() {
693
return array(
694
id(new PhabricatorConduitSearchFieldSpecification())
695
->setKey('name')
696
->setType('string')
697
->setDescription(pht('The name of the package.')),
698
id(new PhabricatorConduitSearchFieldSpecification())
699
->setKey('description')
700
->setType('string')
701
->setDescription(pht('The package description.')),
702
id(new PhabricatorConduitSearchFieldSpecification())
703
->setKey('status')
704
->setType('string')
705
->setDescription(pht('Active or archived status of the package.')),
706
id(new PhabricatorConduitSearchFieldSpecification())
707
->setKey('owners')
708
->setType('list<map<string, wild>>')
709
->setDescription(pht('List of package owners.')),
710
id(new PhabricatorConduitSearchFieldSpecification())
711
->setKey('review')
712
->setType('map<string, wild>')
713
->setDescription(pht('Auto review information.')),
714
id(new PhabricatorConduitSearchFieldSpecification())
715
->setKey('audit')
716
->setType('map<string, wild>')
717
->setDescription(pht('Auto audit information.')),
718
id(new PhabricatorConduitSearchFieldSpecification())
719
->setKey('dominion')
720
->setType('map<string, wild>')
721
->setDescription(pht('Dominion setting information.')),
722
id(new PhabricatorConduitSearchFieldSpecification())
723
->setKey('authority')
724
->setType('map<string, wild>')
725
->setDescription(pht('Authority setting information.')),
726
id(new PhabricatorConduitSearchFieldSpecification())
727
->setKey('ignored')
728
->setType('map<string, wild>')
729
->setDescription(pht('Ignored attribute information.')),
730
);
731
}
732
733
public function getFieldValuesForConduit() {
734
$owner_list = array();
735
foreach ($this->getOwners() as $owner) {
736
$owner_list[] = array(
737
'ownerPHID' => $owner->getUserPHID(),
738
);
739
}
740
741
$review_map = self::getAutoreviewOptionsMap();
742
$review_value = $this->getAutoReview();
743
if (isset($review_map[$review_value])) {
744
$review_label = $review_map[$review_value]['name'];
745
} else {
746
$review_label = pht('Unknown ("%s")', $review_value);
747
}
748
749
$review = array(
750
'value' => $review_value,
751
'label' => $review_label,
752
);
753
754
$audit_rule = $this->newAuditingRule();
755
756
$audit = array(
757
'value' => $audit_rule->getKey(),
758
'label' => $audit_rule->getDisplayName(),
759
);
760
761
$dominion_value = $this->getDominion();
762
$dominion_map = self::getDominionOptionsMap();
763
if (isset($dominion_map[$dominion_value])) {
764
$dominion_label = $dominion_map[$dominion_value]['name'];
765
$dominion_short = $dominion_map[$dominion_value]['short'];
766
} else {
767
$dominion_label = pht('Unknown ("%s")', $dominion_value);
768
$dominion_short = pht('Unknown ("%s")', $dominion_value);
769
}
770
771
$dominion = array(
772
'value' => $dominion_value,
773
'label' => $dominion_label,
774
'short' => $dominion_short,
775
);
776
777
778
$authority_value = $this->getAuthorityMode();
779
$authority_map = self::getAuthorityOptionsMap();
780
if (isset($authority_map[$authority_value])) {
781
$authority_label = $authority_map[$authority_value]['name'];
782
$authority_short = $authority_map[$authority_value]['short'];
783
} else {
784
$authority_label = pht('Unknown ("%s")', $authority_value);
785
$authority_short = pht('Unknown ("%s")', $authority_value);
786
}
787
788
$authority = array(
789
'value' => $authority_value,
790
'label' => $authority_label,
791
'short' => $authority_short,
792
);
793
794
// Force this to always emit as a JSON object even if empty, never as
795
// a JSON list.
796
$ignored = $this->getIgnoredPathAttributes();
797
if (!$ignored) {
798
$ignored = (object)array();
799
}
800
801
return array(
802
'name' => $this->getName(),
803
'description' => $this->getDescription(),
804
'status' => $this->getStatus(),
805
'owners' => $owner_list,
806
'review' => $review,
807
'audit' => $audit,
808
'dominion' => $dominion,
809
'authority' => $authority,
810
'ignored' => $ignored,
811
);
812
}
813
814
public function getConduitSearchAttachments() {
815
return array(
816
id(new PhabricatorOwnersPathsSearchEngineAttachment())
817
->setAttachmentKey('paths'),
818
);
819
}
820
821
822
/* -( PhabricatorFulltextInterface )--------------------------------------- */
823
824
825
public function newFulltextEngine() {
826
return new PhabricatorOwnersPackageFulltextEngine();
827
}
828
829
830
/* -( PhabricatorFerretInterface )----------------------------------------- */
831
832
833
public function newFerretEngine() {
834
return new PhabricatorOwnersPackageFerretEngine();
835
}
836
837
838
/* -( PhabricatorNgramsInterface )----------------------------------------- */
839
840
841
public function newNgrams() {
842
return array(
843
id(new PhabricatorOwnersPackageNameNgrams())
844
->setValue($this->getName()),
845
);
846
}
847
848
}
849
850