/
FolderTypeResolver.php
184 lines (163 loc) · 6.12 KB
/
FolderTypeResolver.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
<?php
namespace SilverStripe\AssetAdmin\GraphQL\Resolvers;
use GraphQL\Type\Definition\ResolveInfo;
use SilverStripe\AssetAdmin\Controller\AssetAdminFile;
use SilverStripe\AssetAdmin\GraphQL\FileFilter;
use SilverStripe\Assets\File;
use SilverStripe\Assets\Folder;
use SilverStripe\GraphQL\QueryHandler\UserContextProvider;
use SilverStripe\GraphQL\Schema\DataObject\FieldAccessor;
use SilverStripe\GraphQL\Schema\Schema;
use SilverStripe\ORM\DataList;
use SilverStripe\ORM\DB;
use SilverStripe\ORM\Sortable;
use SilverStripe\Versioned\Versioned;
use InvalidArgumentException;
use Exception;
use Closure;
use SilverStripe\ORM\DataQuery;
class FolderTypeResolver
{
/**
* @param Folder $object
* @param array $args
* @param array $context
* @param ResolveInfo $info
* @return mixed
* @throws InvalidArgumentException
* @throws Exception
*/
public static function resolveFolderChildren(
$object,
array $args,
$context,
ResolveInfo $info
) {
// canView() checks on parent folder are implied by the query returning $object
// Note: The inability to query permissions against the entire set means pagination
// is inaccurate when any item in the list returns false on canView()
$filter = (!empty($args['filter'])) ? $args['filter'] : [];
if (isset($filter['parentId']) && (int)$filter['parentId'] !== (int)$object->ID) {
throw new InvalidArgumentException(sprintf(
'The "parentId" value (#%d) needs to match the current object id (#%d)',
(int)$filter['parentId'],
(int)$object->ID
));
}
$list = Versioned::get_by_stage(File::class, 'Stage');
$filter['parentId'] = $object->ID;
$list = FileFilter::filterList($list, $filter);
// Filter by permission
// DataQuery::column ignores surrogate sorting fields
// see https://github.com/silverstripe/silverstripe-framework/issues/8926
// the following line is a workaround for `$ids = $list->column('ID');`
$ids = $list->dataQuery()->execute()->column('ID');
$permissionChecker = File::singleton()->getPermissionChecker();
$member = UserContextProvider::get($context);
$canViewIDs = array_keys(array_filter($permissionChecker->canViewMultiple(
$ids,
$member
) ?? []));
// Filter by visible IDs (or force empty set if none are visible)
// Remove the limit as it no longer applies. We've already filtered down to the exact
// IDs we need.
$canViewList = $list->filter('ID', $canViewIDs ?: 0)
->limit(null);
return $canViewList;
}
/**
* @param Folder|AssetAdminFile $object
* @param array $args
* @param array $context
* @param ResolveInfo $info
* @return int
*/
public static function resolveFolderDescendantFileCount($object, array $args, $context, ResolveInfo $info)
{
return $object->getDescendantFileCount();
}
/**
* @param Folder|AssetAdminFile $object
* @param array $args
* @param array $context
* @param ResolveInfo $info
* @return int
*/
public static function resolveFolderFilesInUseCount($object, array $args, $context, ResolveInfo $info)
{
return $object->getFilesInUse()->count();
}
/**
* @param File $object
* @param array $args
* @param array $context
* @param ResolveInfo $info
* @return File[]
*/
public static function resolveFolderParents($object, array $args, $context, ResolveInfo $info)
{
$parents = [];
$next = $object->Parent();
while ($next && $next->isInDB()) {
array_unshift($parents, $next);
if ($next->ParentID) {
$next = $next->Parent();
} else {
break;
}
}
return $parents;
}
/**
* @param array $context
* @return Closure
*/
public static function sortChildren(array $context): Closure
{
$fieldName = $context['fieldName'];
return function (?DataList $list, array $args) use ($fieldName) {
if ($list === null) {
return null;
}
$sortArgs = $args[$fieldName] ?? [];
$list = $list->alterDataQuery(static function (DataQuery $dataQuery) use ($sortArgs) {
$query = $dataQuery->query();
$existingOrderBys = [];
foreach ($query->getOrderBy() as $field => $direction) {
if (strpos($field, '.') === false) {
// some fields may be surrogates added by extending augmentSQL
// we have to preserve those expressions rather than auto-generated names
// that SQLSelect::addOrderBy leaves for them (e.g. _SortColumn0)
$field = $query->expressionForField(trim($field, '"')) ?: $field;
}
$existingOrderBys[$field] = $direction;
}
// Folders always go first
$dataQuery->sort(
sprintf(
'(CASE WHEN "ClassName"=%s THEN 1 ELSE 0 END)',
DB::get_conn()->quoteString(Folder::class)
),
'DESC',
true
);
foreach ($sortArgs as $field => $dir) {
$normalised = FieldAccessor::singleton()->normaliseField(File::singleton(), $field);
Schema::invariant(
$normalised,
'Could not find field %s on %s',
$field,
File::class
);
$dataQuery->sort($normalised, $dir, false);
}
// respect default_sort
foreach ($existingOrderBys as $field => $dir) {
$dataQuery->sort($field, $dir, false);
}
return $dataQuery;
});
return $list;
};
}
}