Correct a parameter order swap in "diffusion.historyquery" for Mercurial
[phabricator.git] / src / applications / project / engineextension / PhabricatorProjectsMembershipIndexEngineExtension.php
blob91b150ce923b3a4b2a706fc7c63ce922b1fa793e
1 <?php
3 final class PhabricatorProjectsMembershipIndexEngineExtension
4 extends PhabricatorIndexEngineExtension {
6 const EXTENSIONKEY = 'project.members';
8 public function getExtensionName() {
9 return pht('Project Members');
12 public function shouldIndexObject($object) {
13 if (!($object instanceof PhabricatorProject)) {
14 return false;
17 return true;
20 public function indexObject(
21 PhabricatorIndexEngine $engine,
22 $object) {
24 $this->rematerialize($object);
27 public function rematerialize(PhabricatorProject $project) {
28 $materialize = $project->getAncestorProjects();
29 array_unshift($materialize, $project);
31 foreach ($materialize as $project) {
32 $this->materializeProject($project);
36 private function materializeProject(PhabricatorProject $project) {
37 $material_type = PhabricatorProjectMaterializedMemberEdgeType::EDGECONST;
38 $member_type = PhabricatorProjectProjectHasMemberEdgeType::EDGECONST;
40 $project_phid = $project->getPHID();
42 if ($project->isMilestone()) {
43 $source_phids = array($project->getParentProjectPHID());
44 $has_subprojects = false;
45 } else {
46 $descendants = id(new PhabricatorProjectQuery())
47 ->setViewer($this->getViewer())
48 ->withAncestorProjectPHIDs(array($project->getPHID()))
49 ->withIsMilestone(false)
50 ->withHasSubprojects(false)
51 ->execute();
52 $descendant_phids = mpull($descendants, 'getPHID');
54 if ($descendant_phids) {
55 $source_phids = $descendant_phids;
56 $has_subprojects = true;
57 } else {
58 $source_phids = array($project->getPHID());
59 $has_subprojects = false;
63 $conn_w = $project->establishConnection('w');
65 $any_milestone = queryfx_one(
66 $conn_w,
67 'SELECT id FROM %T
68 WHERE parentProjectPHID = %s AND milestoneNumber IS NOT NULL
69 LIMIT 1',
70 $project->getTableName(),
71 $project_phid);
72 $has_milestones = (bool)$any_milestone;
74 $project->openTransaction();
76 // Copy current member edges to create new materialized edges.
78 // See T13596. Avoid executing this as an "INSERT ... SELECT" to reduce
79 // the required level of table locking. Since we're decomposing it into
80 // "SELECT" + "INSERT" anyway, we can also compute exactly which rows
81 // need to be modified.
83 $have_rows = queryfx_all(
84 $conn_w,
85 'SELECT dst FROM %T
86 WHERE src = %s AND type = %d',
87 PhabricatorEdgeConfig::TABLE_NAME_EDGE,
88 $project_phid,
89 $material_type);
91 $want_rows = queryfx_all(
92 $conn_w,
93 'SELECT dst, dateCreated, seq FROM %T
94 WHERE src IN (%Ls) AND type = %d',
95 PhabricatorEdgeConfig::TABLE_NAME_EDGE,
96 $source_phids,
97 $member_type);
99 $have_phids = ipull($have_rows, 'dst', 'dst');
100 $want_phids = ipull($want_rows, null, 'dst');
102 $rem_phids = array_diff_key($have_phids, $want_phids);
103 $rem_phids = array_keys($rem_phids);
105 $add_phids = array_diff_key($want_phids, $have_phids);
106 $add_phids = array_keys($add_phids);
108 $rem_sql = array();
109 foreach ($rem_phids as $rem_phid) {
110 $rem_sql[] = qsprintf(
111 $conn_w,
112 '%s',
113 $rem_phid);
116 $add_sql = array();
117 foreach ($add_phids as $add_phid) {
118 $add_row = $want_phids[$add_phid];
119 $add_sql[] = qsprintf(
120 $conn_w,
121 '(%s, %d, %s, %d, %d)',
122 $project_phid,
123 $material_type,
124 $add_row['dst'],
125 $add_row['dateCreated'],
126 $add_row['seq']);
129 // Remove materialized members who are no longer project members.
131 if ($rem_sql) {
132 foreach (PhabricatorLiskDAO::chunkSQL($rem_sql) as $sql_chunk) {
133 queryfx(
134 $conn_w,
135 'DELETE FROM %T
136 WHERE src = %s AND type = %s AND dst IN (%LQ)',
137 PhabricatorEdgeConfig::TABLE_NAME_EDGE,
138 $project_phid,
139 $material_type,
140 $sql_chunk);
144 // Add project members who are not yet materialized members.
146 if ($add_sql) {
147 foreach (PhabricatorLiskDAO::chunkSQL($add_sql) as $sql_chunk) {
148 queryfx(
149 $conn_w,
150 'INSERT IGNORE INTO %T (src, type, dst, dateCreated, seq)
151 VALUES %LQ',
152 PhabricatorEdgeConfig::TABLE_NAME_EDGE,
153 $sql_chunk);
157 // Update the hasSubprojects flag.
158 queryfx(
159 $conn_w,
160 'UPDATE %T SET hasSubprojects = %d WHERE id = %d',
161 $project->getTableName(),
162 (int)$has_subprojects,
163 $project->getID());
165 // Update the hasMilestones flag.
166 queryfx(
167 $conn_w,
168 'UPDATE %T SET hasMilestones = %d WHERE id = %d',
169 $project->getTableName(),
170 (int)$has_milestones,
171 $project->getID());
173 $project->saveTransaction();