33namespace App \Nova \Actions ;
44
55use App \MediaUpload ;
6+ use DigitalCreative \Filepond \Filepond ;
7+ use DigitalCreative \Filepond \Data \Data ;
68use Illuminate \Bus \Queueable ;
79use Illuminate \Http \UploadedFile ;
810use Illuminate \Queue \InteractsWithQueue ;
911use Illuminate \Queue \SerializesModels ;
1012use Illuminate \Support \Collection ;
13+ use Illuminate \Support \Facades \Storage ;
1114use Illuminate \Support \Str ;
1215use Laravel \Nova \Actions \Action ;
1316use Laravel \Nova \Fields \ActionFields ;
14- use Laravel \Nova \Fields \File ;
1517use Laravel \Nova \Http \Requests \NovaRequest ;
1618
1719class BulkUploadMediaFiles extends Action
@@ -53,20 +55,22 @@ public function handle(ActionFields $fields, Collection $models)
5355 continue ;
5456 }
5557
56- $ extension = strtolower ((string ) $ file ->getClientOriginalExtension ());
58+ $ originalName = $ this ->extractOriginalName ($ file );
59+ if ($ originalName === null ) {
60+ $ skipped ++;
61+ continue ;
62+ }
63+ $ extension = strtolower ((string ) pathinfo ($ originalName , PATHINFO_EXTENSION ));
5764 if (!in_array ($ extension , $ allowedExtensions , true )) {
5865 $ skipped ++;
5966 continue ;
6067 }
6168
62- $ baseName = pathinfo ($ file -> getClientOriginalName () , PATHINFO_FILENAME );
69+ $ baseName = pathinfo ($ originalName , PATHINFO_FILENAME );
6370 $ safeBaseName = Str::slug ($ baseName ) ?: 'upload-file ' ;
6471 $ destination = 'nova/uploads/ ' . now ()->format ('Y/m ' );
65- $ storedPath = $ file ->storeAs (
66- $ destination ,
67- $ safeBaseName . '- ' . Str::random (8 ) . '. ' . $ extension ,
68- 'resources '
69- );
72+ $ finalFileName = $ safeBaseName . '- ' . Str::random (8 ) . '. ' . $ extension ;
73+ $ storedPath = $ this ->storeFile ($ file , $ destination , $ finalFileName );
7074
7175 if (!$ storedPath ) {
7276 $ skipped ++;
@@ -94,14 +98,10 @@ public function handle(ActionFields $fields, Collection $models)
9498 public function fields (NovaRequest $ request ): array
9599 {
96100 return [
97- File::make ('Files ' , 'files ' )
98- ->withMeta ([
99- 'extraAttributes ' => [
100- 'name ' => 'files[] ' ,
101- 'multiple ' => true ,
102- 'accept ' => '.jpg,.jpeg,.png,.gif,.webp,.svg,.pdf,.doc,.docx,.ppt,.pptx,.xls,.xlsx,.txt ' ,
103- ],
104- ])
101+ Filepond::make ('Files ' , 'files ' )
102+ ->multiple ()
103+ ->limit (50 )
104+ ->acceptedTypes ('.jpg,.jpeg,.png,.gif,.webp,.svg,.pdf,.doc,.docx,.ppt,.pptx,.xls,.xlsx,.txt ' )
105105 ->rules ('required ' )
106106 ->help ('Drag and drop multiple files or click to select. Supported: images, PDF, Office docs, and TXT. ' ),
107107 ];
@@ -120,6 +120,11 @@ protected function collectUploadedFiles(ActionFields $fields): array
120120 $ candidates [] = $ fields ->files ;
121121 }
122122
123+ $ requestItems = request ()->collect ('files ' )->all ();
124+ if (!empty ($ requestItems )) {
125+ $ candidates [] = $ requestItems ;
126+ }
127+
123128 $ requestFiles = request ()->allFiles ();
124129 if (!empty ($ requestFiles )) {
125130 $ candidates [] = $ requestFiles ;
@@ -130,6 +135,10 @@ protected function collectUploadedFiles(ActionFields $fields): array
130135 return [$ value ];
131136 }
132137
138+ if (is_string ($ value )) {
139+ return [$ value ];
140+ }
141+
133142 if (!is_array ($ value )) {
134143 return [];
135144 }
@@ -150,4 +159,47 @@ protected function collectUploadedFiles(ActionFields $fields): array
150159 return $ files ;
151160 }
152161
162+ protected function extractOriginalName (UploadedFile |string $ file ): ?string
163+ {
164+ if ($ file instanceof UploadedFile) {
165+ return $ file ->getClientOriginalName ();
166+ }
167+
168+ try {
169+ $ data = Data::fromEncrypted ($ file );
170+ return $ data ->filename ;
171+ } catch (\Throwable $ e ) {
172+ return null ;
173+ }
174+ }
175+
176+ protected function storeFile (UploadedFile |string $ file , string $ destination , string $ finalFileName ): ?string
177+ {
178+ if ($ file instanceof UploadedFile) {
179+ return $ file ->storeAs ($ destination , $ finalFileName , 'resources ' );
180+ }
181+
182+ try {
183+ $ data = Data::fromEncrypted ($ file );
184+ } catch (\Throwable $ e ) {
185+ return null ;
186+ }
187+
188+ $ stream = Storage::disk ($ data ->disk )->readStream ($ data ->path );
189+ if ($ stream === false ) {
190+ return null ;
191+ }
192+
193+ $ targetPath = $ destination . '/ ' . $ finalFileName ;
194+ $ stored = Storage::disk ('resources ' )->put ($ targetPath , $ stream , 'public ' );
195+ if (is_resource ($ stream )) {
196+ fclose ($ stream );
197+ }
198+
199+ // Clean temporary Filepond directory.
200+ $ data ->deleteDirectory ();
201+
202+ return $ stored ? $ targetPath : null ;
203+ }
204+
153205}
0 commit comments