Skip to content

Commit bf68c20

Browse files
committed
docs: add documentation for DAV collection preloading event
Signed-off-by: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com>
1 parent a2c1a51 commit bf68c20

3 files changed

Lines changed: 111 additions & 0 deletions

File tree

developer_manual/app_publishing_maintenance/app_upgrade_guide/upgrade_to_32.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ Back-end changes
8282
- These new attributes will be applied on a "defacto standard" basis to the best of our knowledge.
8383
In case an API was flagged unexpectedly, leave a comment on the respective pull request in the server repository asking for clarification.
8484

85+
Added Events
86+
^^^^^^^^^^^^
87+
88+
- New ``preloadCollection`` event emitted by the DAV server during PROPFIND requests. See :ref:`collection_preload` for details.
89+
8590
Added APIs
8691
^^^^^^^^^^
8792

developer_manual/digging_deeper/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,5 @@ Digging deeper
4848
user_migration
4949
users
5050
web_host_metadata
51+
webdav_collection_preload
5152
time
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
.. _collection_preload:
2+
3+
=================================
4+
WebDAV collection preload events
5+
=================================
6+
7+
Overview
8+
--------
9+
10+
During a WebDAV PROPFIND on a SabreDAV Collection with Depth > 0,
11+
Nextcloud emits a preload event so DAV plugins can fetch data for the collection's
12+
children in one go. The goal is to avoid N+1 database queries by
13+
preloading what your property handlers will need before per-node property
14+
handling starts. In practice this means your plugin can fill a cache up
15+
front and then read from it in the usual ``propFind`` handlers for a faster
16+
and more efficient response.
17+
18+
When is the event emitted
19+
-------------------------
20+
21+
The event is emitted during PROPFIND requests, before the ``propFind`` event
22+
is emitted, against nodes implementing ``Sabre\DAV\ICollection`` with Depth > 0.
23+
24+
The event may be emitted multiple times for a single request path; plugins should
25+
check their cache to avoid duplicate work.
26+
27+
Subscribing to the event in a plugin
28+
------------------------------------
29+
30+
Register a listener in your implementation of Sabre's ``ServerPlugin::initialize()`` method:
31+
32+
.. code-block:: php
33+
34+
use Sabre\DAV\ICollection;
35+
use Sabre\DAV\PropFind;
36+
37+
class MyDavPlugin extends ServerPlugin {
38+
39+
public function initialize(\Sabre\DAV\Server $server): void {
40+
// Called before per-node property handlers
41+
$server->on('preloadCollection', $this->preloadCollection(...));
42+
43+
// Your usual property handlers
44+
$server->on('propFind', $this->handleGetProperties(...));
45+
}
46+
47+
private function preloadCollection(PropFind $propFind, ICollection $collection): void {
48+
// Only preload when your properties have been requested to avoid unnecessary queries
49+
$requested = [
50+
'{http://appdomain.example/ns}your-prop',
51+
'{http://appdomain.example/ns}another-prop',
52+
];
53+
$anyRequested = array_reduce(
54+
$requested,
55+
fn($result, $property) => $result || $propFind->getStatus($property) !== null,
56+
false
57+
);
58+
if (!$anyRequested) {
59+
return;
60+
}
61+
62+
// Fetch data for the collection and its children in bulk
63+
// and cache results for use in your propFind handler
64+
$this->cache = $this->bulkLoadDataForCollection($collection); // implement your own caching
65+
}
66+
67+
private function handleGetProperties(PropFind $propFind, \Sabre\DAV\INode $node): void {
68+
// Read and return values from $this->cache here to avoid per-node queries
69+
70+
// Handle per-node property loading here, to handle Depth = 0
71+
// and cases where the `preloadCollection` event is not emitted.
72+
}
73+
74+
}
75+
76+
77+
Built-in examples
78+
-----------------
79+
80+
- Tags: ``OCA\DAV\Connector\Sabre\TagsPlugin`` preloads tags and favorite
81+
info for a folder and its children.
82+
- Shares: ``OCA\DAV\Connector\Sabre\SharesPlugin`` preloads share types and
83+
sharees for items within a folder.
84+
- Comments: ``OCA\DAV\Connector\Sabre\CommentPropertiesPlugin`` preloads unread
85+
comment counts for items within a folder.
86+
87+
Best practices
88+
--------------
89+
90+
- Check requested properties: Use ``$propFind->getStatus('{ns}property')`` to
91+
confirm that your properties were actually requested before querying.
92+
- Cache results: The event can fire multiple times; cache by file id or path
93+
to avoid redundant work during the same request.
94+
- Scope your preload: Only fetch data for the current collection and (at most)
95+
its direct children; avoid fetching across the whole tree.
96+
- Depth awareness: The event fires for Depth > 0; design your preload logic so
97+
that sibling PROPFIND calls don’t repeat heavy queries or perform one query
98+
per node for too many nodes.
99+
100+
Compatibility
101+
-------------
102+
103+
- The ``preloadCollection`` event is available starting with Nextcloud 32.
104+
Plugins listening for the event will simply not be invoked on earlier
105+
versions (no extra guards required).

0 commit comments

Comments
 (0)