33namespace App \Nova \Actions ;
44
55use App \MediaUpload ;
6- use DigitalCreative \Filepond \Filepond ;
7- use DigitalCreative \Filepond \Data \Data ;
86use Illuminate \Bus \Queueable ;
9- use Illuminate \Http \UploadedFile ;
7+ use Illuminate \Http \Request ;
108use Illuminate \Queue \InteractsWithQueue ;
119use Illuminate \Queue \SerializesModels ;
1210use Illuminate \Support \Collection ;
13- use Illuminate \Support \Facades \Log ;
14- use Illuminate \Support \Facades \Storage ;
1511use Illuminate \Support \Str ;
1612use Laravel \Nova \Actions \Action ;
1713use Laravel \Nova \Fields \ActionFields ;
14+ use Laravel \Nova \Fields \File ;
1815use Laravel \Nova \Http \Requests \NovaRequest ;
1916
2017class BulkUploadMediaFiles extends Action
@@ -37,7 +34,7 @@ class BulkUploadMediaFiles extends Action
3734 */
3835 public function handle (ActionFields $ fields , Collection $ models )
3936 {
40- $ uploadedFiles = $ this ->collectUploadedFiles ($ fields );
37+ $ uploadedFiles = $ this ->collectUploadedFiles ($ fields, request () );
4138 if (empty ($ uploadedFiles )) {
4239 return Action::danger ('Please select one or more files. ' );
4340 }
@@ -56,11 +53,7 @@ public function handle(ActionFields $fields, Collection $models)
5653 continue ;
5754 }
5855
59- $ originalName = $ this ->extractOriginalName ($ file );
60- if ($ originalName === null ) {
61- $ skipped ++;
62- continue ;
63- }
56+ $ originalName = $ file ->getClientOriginalName ();
6457 $ extension = strtolower ((string ) pathinfo ($ originalName , PATHINFO_EXTENSION ));
6558 if (!in_array ($ extension , $ allowedExtensions , true )) {
6659 $ skipped ++;
@@ -71,7 +64,7 @@ public function handle(ActionFields $fields, Collection $models)
7164 $ safeBaseName = Str::slug ($ baseName ) ?: 'upload-file ' ;
7265 $ destination = 'nova/uploads/ ' . now ()->format ('Y/m ' );
7366 $ finalFileName = $ safeBaseName . '- ' . Str::random (8 ) . '. ' . $ extension ;
74- $ storedPath = $ this -> storeFile ( $ file , $ destination , $ finalFileName );
67+ $ storedPath = $ file -> storeAs ( $ destination , $ finalFileName, ' resources ' );
7568
7669 if (!$ storedPath ) {
7770 $ skipped ++;
@@ -98,123 +91,34 @@ public function handle(ActionFields $fields, Collection $models)
9891 */
9992 public function fields (NovaRequest $ request ): array
10093 {
101- return [
102- Filepond::make ('Files ' , 'files ' )
103- ->multiple ()
104- ->limit (50 )
105- ->acceptedTypes ('.jpg,.jpeg,.png,.gif,.webp,.svg,.pdf,.doc,.docx,.ppt,.pptx,.xls,.xlsx,.txt ' )
106- ->rules ('required ' )
107- ->help ('Drag and drop multiple files or click to select. Supported: images, PDF, Office docs, and TXT. ' ),
108- ];
109- }
110-
111- /**
112- * Collect uploaded files from Nova action fields + raw request payload.
113- *
114- * @return UploadedFile[]
115- */
116- protected function collectUploadedFiles (ActionFields $ fields ): array
117- {
118- $ candidates = [];
119-
120- if (isset ($ fields ->files )) {
121- $ candidates [] = $ fields ->files ;
122- }
94+ $ fields = [];
12395
124- $ requestItems = request ()-> collect ( ' files ' )-> all ();
125- if (! empty ( $ requestItems )) {
126- $ candidates [] = $ requestItems ;
96+ for ( $ i = 1 ; $ i <= 20 ; $ i ++) {
97+ $ fields [] = File:: make ( " File { $ i }" , " file_ { $ i }" )
98+ -> rules ( ' nullable ' , ' max:51200 ' , ' mimes:jpg,jpeg,png,gif,webp,svg,pdf,doc,docx,ppt,pptx,xls,xlsx,txt ' ) ;
12799 }
128100
129- $ requestFiles = request ()->allFiles ();
130- if (!empty ($ requestFiles )) {
131- $ candidates [] = $ requestFiles ;
132- }
133-
134- $ flatten = function ($ value ) use (&$ flatten ): array {
135- if ($ value instanceof UploadedFile) {
136- return [$ value ];
137- }
138-
139- if (is_string ($ value )) {
140- return [$ value ];
141- }
142-
143- if (!is_array ($ value )) {
144- return [];
145- }
146-
147- $ result = [];
148- foreach ($ value as $ item ) {
149- $ result = array_merge ($ result , $ flatten ($ item ));
150- }
101+ $ fields [0 ]->help ('Upload up to 20 files in one run (mix of images/docs). ' );
151102
152- return $ result ;
153- };
154-
155- $ files = [];
156- foreach ($ candidates as $ candidate ) {
157- $ files = array_merge ($ files , $ flatten ($ candidate ));
158- }
159-
160- return $ files ;
161- }
162-
163- protected function extractOriginalName (UploadedFile |string $ file ): ?string
164- {
165- if ($ file instanceof UploadedFile) {
166- return $ file ->getClientOriginalName ();
167- }
168-
169- try {
170- $ data = Data::fromEncrypted ($ file );
171- return $ data ->filename ;
172- } catch (\Throwable $ e ) {
173- return null ;
174- }
103+ return $ fields ;
175104 }
176105
177- protected function storeFile (UploadedFile |string $ file , string $ destination , string $ finalFileName ): ?string
106+ /**
107+ * Collect uploaded files from explicit action slots.
108+ *
109+ * @return array
110+ */
111+ protected function collectUploadedFiles (ActionFields $ fields , Request $ request ): array
178112 {
179- if ($ file instanceof UploadedFile) {
180- return $ file ->storeAs ($ destination , $ finalFileName , 'resources ' );
181- }
182-
183- try {
184- $ data = Data::fromEncrypted ($ file );
185- } catch (\Throwable $ e ) {
186- return null ;
187- }
188-
189- $ targetPath = $ destination . '/ ' . $ finalFileName ;
190- $ stream = Storage::disk ($ data ->disk )->readStream ($ data ->path );
191-
192- if (is_resource ($ stream )) {
193- try {
194- $ stored = Storage::disk ('resources ' )->writeStream ($ targetPath , $ stream , ['visibility ' => 'public ' ]);
195- } finally {
196- fclose ($ stream );
197- }
198- } else {
199- // Some environments return null instead of a stream for temp files.
200- // Fallback to reading file contents directly.
201- $ contents = Storage::disk ($ data ->disk )->get ($ data ->path );
202- if (!is_string ($ contents ) || $ contents === '' ) {
203- Log::warning ('[BulkUploadMediaFiles] Unable to read temp file contents ' , [
204- 'disk ' => $ data ->disk ,
205- 'path ' => $ data ->path ,
206- ]);
207- return null ;
113+ $ files = [];
114+ for ($ i = 1 ; $ i <= 20 ; $ i ++) {
115+ $ key = "file_ {$ i }" ;
116+ $ file = $ fields ->{$ key } ?? $ request ->file ($ key );
117+ if ($ file ) {
118+ $ files [] = $ file ;
208119 }
209-
210- $ stored = Storage::disk ('resources ' )->put ($ targetPath , $ contents , 'public ' );
211120 }
212121
213- // Clean only this temp file. Deleting the whole directory can remove
214- // sibling files from the same multi-upload batch.
215- $ data ->deleteFile ();
216-
217- return $ stored ? $ targetPath : null ;
122+ return $ files ;
218123 }
219-
220124}
0 commit comments