1111
1212use Sabre \DAV \Server ;
1313use Sabre \DAV \ServerPlugin ;
14+ use Sabre \DAV \Xml \Element \Response ;
1415use Sabre \HTTP \RequestInterface ;
1516use Sabre \HTTP \ResponseInterface ;
1617
@@ -54,8 +55,13 @@ public function onMultiStatus(&$fileProperties): void {
5455 ) {
5556 $ pageSize = (int )$ request ->getHeader (self ::PAGINATE_COUNT_HEADER ) ?: $ this ->pageSize ;
5657 $ offset = (int )$ request ->getHeader (self ::PAGINATE_OFFSET_HEADER );
58+
5759 $ copyIterator = new LimitedCopyIterator ($ fileProperties , $ pageSize , $ offset );
58- ['token ' => $ token , 'count ' => $ count ] = $ this ->cache ->store ($ url , $ copyIterator );
60+ // wrap the iterator with another that renders XML, this way we
61+ // cache XML, but we keep the first $pageSize elements as objects
62+ // to use for the response of the first page.
63+ $ rendererGenerator = $ this ->getXmlRendererGenerator ($ copyIterator );
64+ ['token ' => $ token , 'count ' => $ count ] = $ this ->cache ->store ($ url , $ rendererGenerator );
5965
6066 $ fileProperties = $ copyIterator ->getRequestedItems ();
6167 $ this ->server ->httpResponse ->addHeader (self ::PAGINATE_HEADER , 'true ' );
@@ -65,6 +71,44 @@ public function onMultiStatus(&$fileProperties): void {
6571 }
6672 }
6773
74+ /**
75+ * Returns a generator that yields rendered XML entries for the provided
76+ * $fileProperties, as they would appear in the MultiStatus response.
77+ */
78+ private function getXmlRendererGenerator (iterable $ fileProperties ): \Generator {
79+ $ writer = $ this ->server ->xml ->getWriter ();
80+ $ prefer = $ this ->server ->getHTTPPrefer ();
81+ $ minimal = $ prefer ['return ' ] === 'minimal ' ;
82+ $ writer ->contextUri = $ this ->server ->getBaseUri ();
83+
84+ $ writer ->openMemory ();
85+ $ writer ->startDocument ();
86+ $ writer ->startElement ('{DAV:}multistatus ' );
87+
88+ // throw away the beginning of the document
89+ $ writer ->flush ();
90+
91+ foreach ($ fileProperties as $ entry ) {
92+ $ href = $ entry ['href ' ];
93+ unset($ entry ['href ' ]);
94+ if ($ minimal ) {
95+ unset($ entry [404 ]);
96+ }
97+ $ response = new Response (
98+ ltrim ($ href , '/ ' ),
99+ $ entry
100+ );
101+ $ writer ->write ([
102+ 'name ' => '{DAV:}response ' ,
103+ 'value ' => $ response ,
104+ ]);
105+
106+ // flushing does not remove the > for the previous element
107+ // (multistatus)
108+ yield ltrim ($ writer ->flush (), '> ' );
109+ }
110+ }
111+
68112 public function onMethod (RequestInterface $ request , ResponseInterface $ response ) {
69113 $ url = $ this ->server ->httpRequest ->getUrl ();
70114 if (
@@ -83,11 +127,20 @@ public function onMethod(RequestInterface $request, ResponseInterface $response)
83127 $ response ->setHeader ('Content-Type ' , 'application/xml; charset=utf-8 ' );
84128 $ response ->setHeader ('Vary ' , 'Brief,Prefer ' );
85129
86- $ prefer = $ this ->server ->getHTTPPrefer ();
87- $ minimal = $ prefer ['return ' ] === 'minimal ' ;
88-
89- $ data = $ this ->server ->generateMultiStatus ($ items , $ minimal );
90- $ response ->setBody ($ data );
130+ // as we cached strings of XML, rebuild the multistatus response
131+ // and output the RAW entries, as stored in the cache
132+ $ writer = $ this ->server ->xml ->getWriter ();
133+ $ writer ->contextUri = $ this ->server ->getBaseUri ();
134+ $ writer ->openMemory ();
135+ $ writer ->startDocument ();
136+ $ writer ->startElement ('{DAV:}multistatus ' );
137+ foreach ($ items as $ item ) {
138+ $ writer ->writeRaw ($ item );
139+ }
140+ $ writer ->endElement ();
141+ $ writer ->endDocument ();
142+
143+ $ response ->setBody ($ writer ->flush ());
91144
92145 return false ;
93146 }
0 commit comments