66use Lkrms \Concern \HasMutator ;
77use Lkrms \Concern \TReadable ;
88use Lkrms \Concern \TWritable ;
9+ use Lkrms \Contract \IDateFormatter ;
910use Lkrms \Contract \IReadable ;
1011use Lkrms \Contract \IWritable ;
1112use Lkrms \Contract \ProvidesBuilder ;
6768 * @property bool $ExpectJson Request JSON from upstream?
6869 * @property bool $PostJson Use JSON to serialize POST/PUT/PATCH/DELETE data?
6970 * @property bool $PreserveKeys Suppress removal of numeric indices from serialized lists?
70- * @property DateFormatter |null $DateFormatter Specify the date format and timezone used upstream
71+ * @property IDateFormatter |null $DateFormatter Specify the date format and timezone used upstream
7172 * @property string|null $UserAgent Override the default User-Agent header
7273 * @property bool $AlwaysPaginate Pass every response to the pager?
7374 * @property bool $ObjectAsArray Return deserialized objects as associative arrays?
@@ -349,7 +350,7 @@ final class Curler implements IReadable, IWritable, ProvidesBuilder
349350 /**
350351 * Specify the date format and timezone used upstream
351352 *
352- * @var DateFormatter |null
353+ * @var IDateFormatter |null
353354 */
354355 protected $ DateFormatter ;
355356
@@ -428,7 +429,7 @@ public function __construct(
428429 bool $ expectJson = true ,
429430 bool $ postJson = true ,
430431 bool $ preserveKeys = false ,
431- ?DateFormatter $ dateFormatter = null ,
432+ ?IDateFormatter $ dateFormatter = null ,
432433 ?string $ userAgent = null ,
433434 bool $ alwaysPaginate = false ,
434435 bool $ objectAsArray = true
@@ -799,11 +800,14 @@ private function prepareData($data)
799800 !($ value instanceof CurlerFile ||
800801 $ value instanceof DateTimeInterface)
801802 );
802- $ leafIterator = new RecursiveIteratorIterator ($ iterator );
803+ $ leaves = new RecursiveIteratorIterator ($ iterator );
804+ $ iterator = new RecursiveIteratorIterator (
805+ $ iterator , RecursiveIteratorIterator::SELF_FIRST
806+ );
803807
804808 // Does `$data` contain a `CurlerFile`?
805809 $ file = false ;
806- foreach ($ leafIterator as $ value ) {
810+ foreach ($ leaves as $ value ) {
807811 if ($ value instanceof CurlerFile) {
808812 $ file = true ;
809813 break ;
@@ -812,21 +816,32 @@ private function prepareData($data)
812816
813817 // With that answered, start over, replacing `CurlerFile` and
814818 // `DateTimeInterface` instances
815- /** @var RecursiveObjectOrArrayIterator $iterator */
816819 foreach ($ iterator as $ value ) {
820+ $ replace = null ;
821+
817822 if ($ value instanceof CurlerFile) {
818- $ value = $ value ->getCurlFile ();
823+ $ replace = $ value ->getCurlFile ();
819824 } elseif ($ value instanceof DateTimeInterface) {
820- $ value = $ this ->getDateFormatter ()->format ($ value );
821- } elseif ($ file ) {
822- // And if uploading a file, replace every object that isn't a
823- // CURLFile with an array cURL can encode
824- $ iterator ->maybeReplaceCurrentWithArray ();
825+ $ replace = $ this ->getDateFormatter ()->format ($ value );
826+ } elseif (!$ file ) {
825827 continue ;
826- } else {
828+ }
829+
830+ /** @var RecursiveHasChildrenCallbackIterator<array-key,mixed> */
831+ $ inner = $ iterator ->getInnerIterator ();
832+ /** @var RecursiveObjectOrArrayIterator */
833+ $ inner = $ inner ->getInnerIterator ();
834+
835+ if ($ replace !== null ) {
836+ $ inner ->replace ($ replace );
827837 continue ;
828838 }
829- $ iterator ->replace ($ value );
839+
840+ // If uploading a file, replace every object that isn't a CURLFile
841+ // with an array cURL can encode
842+ if ($ file ) {
843+ $ inner ->maybeConvertToArray ();
844+ }
830845 }
831846
832847 if ($ file ) {
@@ -855,7 +870,7 @@ private function getCookieKey(): ?string
855870 : null ;
856871 }
857872
858- private function getDateFormatter (): DateFormatter
873+ private function getDateFormatter (): IDateFormatter
859874 {
860875 return $ this ->DateFormatter
861876 ?: ($ this ->DateFormatter = new DateFormatter ());
0 commit comments