These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace SilverStripe\Subsites\Extensions; |
||
4 | |||
5 | use SilverStripe\Control\Cookie; |
||
6 | use SilverStripe\Core\Convert; |
||
7 | use SilverStripe\Forms\CheckboxSetField; |
||
8 | use SilverStripe\Forms\FieldList; |
||
9 | use SilverStripe\Forms\OptionsetField; |
||
10 | use SilverStripe\Forms\ReadonlyField; |
||
11 | use SilverStripe\ORM\DataExtension; |
||
12 | use SilverStripe\ORM\DataQuery; |
||
13 | use SilverStripe\ORM\DB; |
||
14 | use SilverStripe\ORM\Queries\SQLSelect; |
||
15 | use SilverStripe\Security\Group; |
||
16 | use SilverStripe\Security\PermissionProvider; |
||
17 | use SilverStripe\Subsites\Model\Subsite; |
||
18 | |||
19 | /** |
||
20 | * Extension for the Group object to add subsites support |
||
21 | * |
||
22 | * @package subsites |
||
23 | */ |
||
24 | class GroupSubsites extends DataExtension implements PermissionProvider |
||
25 | { |
||
26 | private static $db = [ |
||
27 | 'AccessAllSubsites' => 'Boolean' |
||
28 | ]; |
||
29 | |||
30 | private static $many_many = [ |
||
31 | 'Subsites' => Subsite::class |
||
32 | ]; |
||
33 | |||
34 | private static $defaults = [ |
||
35 | 'AccessAllSubsites' => true |
||
36 | ]; |
||
37 | |||
38 | /** |
||
39 | * Migrations for GroupSubsites data. |
||
40 | */ |
||
41 | public function requireDefaultRecords() |
||
42 | { |
||
43 | if (!$this->owner) { |
||
44 | return; |
||
45 | } |
||
46 | // Migration for Group.SubsiteID data from when Groups only had a single subsite |
||
47 | $ownerClass = get_class($this->owner); |
||
48 | $schema = $ownerClass::getSchema(); |
||
49 | $groupFields = DB::field_list($schema->tableName(Group::class)); |
||
50 | |||
51 | // Detection of SubsiteID field is the trigger for old-style-subsiteID migration |
||
52 | if (isset($groupFields['SubsiteID'])) { |
||
53 | // Migrate subsite-specific data |
||
54 | DB::query('INSERT INTO "Group_Subsites" ("GroupID", "SubsiteID") |
||
55 | SELECT "ID", "SubsiteID" FROM "Group" WHERE "SubsiteID" > 0'); |
||
56 | |||
57 | // Migrate global-access data |
||
58 | DB::query('UPDATE "Group" SET "AccessAllSubsites" = 1 WHERE "SubsiteID" = 0'); |
||
59 | |||
60 | // Move the field out of the way so that this migration doesn't get executed again |
||
61 | DB::get_schema()->renameField(Group::class, 'SubsiteID', '_obsolete_SubsiteID'); |
||
62 | |||
63 | // No subsite access on anything means that we've just installed the subsites module. |
||
64 | // Make all previous groups global-access groups |
||
65 | } else { |
||
66 | if (!DB::query('SELECT "Group"."ID" FROM "Group" |
||
67 | LEFT JOIN "Group_Subsites" ON "Group_Subsites"."GroupID" = "Group"."ID" AND "Group_Subsites"."SubsiteID" > 0 |
||
68 | WHERE "AccessAllSubsites" = 1 |
||
69 | OR "Group_Subsites"."GroupID" IS NOT NULL ')->value() |
||
70 | ) { |
||
71 | DB::query('UPDATE "Group" SET "AccessAllSubsites" = 1'); |
||
72 | } |
||
73 | } |
||
74 | } |
||
75 | |||
76 | public function updateCMSFields(FieldList $fields) |
||
77 | { |
||
78 | if ($this->owner->canEdit()) { |
||
79 | // i18n tab |
||
80 | $fields->findOrMakeTab('Root.Subsites', _t('GroupSubsites.SECURITYTABTITLE', 'Subsites')); |
||
81 | |||
82 | $subsites = Subsite::accessible_sites(['ADMIN', 'SECURITY_SUBSITE_GROUP'], true); |
||
83 | $subsiteMap = $subsites->map(); |
||
84 | |||
85 | // Prevent XSS injection |
||
86 | $subsiteMap = Convert::raw2xml($subsiteMap->toArray()); |
||
87 | |||
88 | // Interface is different if you have the rights to modify subsite group values on |
||
89 | // all subsites |
||
90 | if (isset($subsiteMap[0])) { |
||
91 | $fields->addFieldToTab('Root.Subsites', new OptionsetField( |
||
92 | 'AccessAllSubsites', |
||
93 | _t('GroupSubsites.ACCESSRADIOTITLE', 'Give this group access to'), |
||
94 | [ |
||
95 | 1 => _t('GroupSubsites.ACCESSALL', 'All subsites'), |
||
96 | 0 => _t('GroupSubsites.ACCESSONLY', 'Only these subsites'), |
||
97 | ] |
||
98 | )); |
||
99 | |||
100 | unset($subsiteMap[0]); |
||
101 | $fields->addFieldToTab('Root.Subsites', new CheckboxSetField( |
||
102 | 'Subsites', |
||
103 | '', |
||
104 | $subsiteMap |
||
105 | )); |
||
106 | } else { |
||
107 | if (sizeof($subsiteMap) <= 1) { |
||
108 | $fields->addFieldToTab('Root.Subsites', new ReadonlyField( |
||
109 | 'SubsitesHuman', |
||
110 | _t('GroupSubsites.ACCESSRADIOTITLE', 'Give this group access to'), |
||
111 | reset($subsiteMap) |
||
112 | )); |
||
113 | } else { |
||
114 | $fields->addFieldToTab('Root.Subsites', new CheckboxSetField( |
||
115 | 'Subsites', |
||
116 | _t('GroupSubsites.ACCESSRADIOTITLE', 'Give this group access to'), |
||
117 | $subsiteMap |
||
118 | )); |
||
119 | } |
||
120 | } |
||
121 | } |
||
122 | } |
||
123 | |||
124 | /** |
||
125 | * If this group belongs to a subsite, |
||
126 | * append the subsites title to the group title |
||
127 | * to make it easy to distinguish in the tree-view |
||
128 | * of the security admin interface. |
||
129 | */ |
||
130 | public function alternateTreeTitle() |
||
131 | { |
||
132 | if ($this->owner->AccessAllSubsites) { |
||
133 | $title = _t('GroupSubsites.GlobalGroup', 'global group'); |
||
134 | return htmlspecialchars($this->owner->Title, ENT_QUOTES) . ' <i>(' . $title . ')</i>'; |
||
135 | } |
||
136 | |||
137 | $subsites = Convert::raw2xml(implode(', ', $this->owner->Subsites()->column('Title'))); |
||
138 | return htmlspecialchars($this->owner->Title) . " <i>($subsites)</i>"; |
||
139 | } |
||
140 | |||
141 | /** |
||
142 | * Update any requests to limit the results to the current site |
||
143 | * @param SQLSelect $query |
||
144 | * @param DataQuery|null $dataQuery |
||
145 | */ |
||
146 | public function augmentSQL(SQLSelect $query, DataQuery $dataQuery = null) |
||
147 | { |
||
148 | if (Subsite::$disable_subsite_filter) { |
||
149 | return; |
||
150 | } |
||
151 | if (Cookie::get('noSubsiteFilter') == 'true') { |
||
152 | return; |
||
153 | } |
||
154 | |||
155 | // If you're querying by ID, ignore the sub-site - this is a bit ugly... |
||
156 | if (!$query->filtersOnID()) { |
||
157 | /*if($context = DataObject::context_obj()) $subsiteID = (int)$context->SubsiteID; |
||
0 ignored issues
–
show
|
|||
158 | |||
159 | else */ |
||
160 | $subsiteID = (int)Subsite::currentSubsiteID(); |
||
161 | |||
162 | // Don't filter by Group_Subsites if we've already done that |
||
163 | $hasGroupSubsites = false; |
||
164 | foreach ($query->getFrom() as $item) { |
||
165 | if ((is_array($item) && strpos( |
||
166 | $item['table'], |
||
167 | 'Group_Subsites' |
||
168 | ) !== false) || (!is_array($item) && strpos( |
||
169 | $item, |
||
170 | 'Group_Subsites' |
||
171 | ) !== false) |
||
172 | ) { |
||
173 | $hasGroupSubsites = true; |
||
174 | break; |
||
175 | } |
||
176 | } |
||
177 | |||
178 | if (!$hasGroupSubsites) { |
||
179 | if ($subsiteID) { |
||
180 | $query->addLeftJoin('Group_Subsites', "\"Group_Subsites\".\"GroupID\" |
||
181 | = \"Group\".\"ID\" AND \"Group_Subsites\".\"SubsiteID\" = $subsiteID"); |
||
182 | $query->addWhere('("Group_Subsites"."SubsiteID" IS NOT NULL OR |
||
183 | "Group"."AccessAllSubsites" = 1)'); |
||
184 | } else { |
||
185 | $query->addWhere('"Group"."AccessAllSubsites" = 1'); |
||
186 | } |
||
187 | } |
||
188 | |||
189 | // WORKAROUND for databases that complain about an ORDER BY when the column wasn't selected (e.g. SQL Server) |
||
190 | $select = $query->getSelect(); |
||
191 | if (isset($select[0]) && !$select[0] == 'COUNT(*)') { |
||
192 | $query->addOrderBy('AccessAllSubsites', 'DESC'); |
||
193 | } |
||
194 | } |
||
195 | } |
||
196 | |||
197 | public function onBeforeWrite() |
||
198 | { |
||
199 | // New record test approximated by checking whether the ID has changed. |
||
200 | // Note also that the after write test is only used when we're *not* on a subsite |
||
201 | if ($this->owner->isChanged('ID') && !Subsite::currentSubsiteID()) { |
||
202 | $this->owner->AccessAllSubsites = 1; |
||
203 | } |
||
204 | } |
||
205 | |||
206 | public function onAfterWrite() |
||
207 | { |
||
208 | // New record test approximated by checking whether the ID has changed. |
||
209 | // Note also that the after write test is only used when we're on a subsite |
||
210 | if ($this->owner->isChanged('ID') && $currentSubsiteID = Subsite::currentSubsiteID()) { |
||
211 | $subsites = $this->owner->Subsites(); |
||
212 | $subsites->add($currentSubsiteID); |
||
213 | } |
||
214 | } |
||
215 | |||
216 | public function alternateCanEdit() |
||
217 | { |
||
218 | // Find the sites that this group belongs to and the sites where we have appropriate perm. |
||
219 | $accessibleSites = Subsite::accessible_sites('CMS_ACCESS_SecurityAdmin')->column('ID'); |
||
220 | $linkedSites = $this->owner->Subsites()->column('ID'); |
||
221 | |||
222 | // We are allowed to access this site if at we have CMS_ACCESS_SecurityAdmin permission on |
||
223 | // at least one of the sites |
||
224 | return (bool)array_intersect($accessibleSites, $linkedSites); |
||
225 | } |
||
226 | |||
227 | public function providePermissions() |
||
228 | { |
||
229 | return [ |
||
230 | 'SECURITY_SUBSITE_GROUP' => [ |
||
231 | 'name' => _t('GroupSubsites.MANAGE_SUBSITES', 'Manage subsites for groups'), |
||
232 | 'category' => _t('Permissions.PERMISSIONS_CATEGORY', 'Roles and access permissions'), |
||
233 | 'help' => _t( |
||
234 | 'GroupSubsites.MANAGE_SUBSITES_HELP', |
||
235 | 'Ability to limit the permissions for a group to one or more subsites.' |
||
236 | ), |
||
237 | 'sort' => 200 |
||
238 | ] |
||
239 | ]; |
||
240 | } |
||
241 | } |
||
242 |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.