]> BookStack Code Mirror - bookstack/blob - app/Services/FileService.php
Added attachment creation from link/name
[bookstack] / app / Services / FileService.php
1 <?php namespace BookStack\Services;
2
3
4 use BookStack\Exceptions\FileUploadException;
5 use BookStack\File;
6 use Exception;
7 use Illuminate\Contracts\Filesystem\FileNotFoundException;
8 use Illuminate\Support\Collection;
9 use Symfony\Component\HttpFoundation\File\UploadedFile;
10
11 class FileService extends UploadService
12 {
13
14     /**
15      * Get a file from storage.
16      * @param File $file
17      * @return string
18      */
19     public function getFile(File $file)
20     {
21         $filePath = $this->getStorageBasePath() . $file->path;
22         return $this->getStorage()->get($filePath);
23     }
24
25     /**
26      * Store a new file upon user upload.
27      * @param UploadedFile $uploadedFile
28      * @param int $page_id
29      * @return File
30      * @throws FileUploadException
31      */
32     public function saveNewUpload(UploadedFile $uploadedFile, $page_id)
33     {
34         $fileName = $uploadedFile->getClientOriginalName();
35         $fileData = file_get_contents($uploadedFile->getRealPath());
36
37         $storage = $this->getStorage();
38         $fileBasePath = 'uploads/files/' . Date('Y-m-M') . '/';
39         $storageBasePath = $this->getStorageBasePath() . $fileBasePath;
40
41         $uploadFileName = $fileName;
42         while ($storage->exists($storageBasePath . $uploadFileName)) {
43             $uploadFileName = str_random(3) . $uploadFileName;
44         }
45
46         $filePath = $fileBasePath . $uploadFileName;
47         $fileStoragePath = $this->getStorageBasePath() . $filePath;
48
49         try {
50             $storage->put($fileStoragePath, $fileData);
51         } catch (Exception $e) {
52             throw new FileUploadException('File path ' . $fileStoragePath . ' could not be uploaded to. Ensure it is writable to the server.');
53         }
54
55         $largestExistingOrder = File::where('uploaded_to', '=', $page_id)->max('order');
56
57         $file = File::forceCreate([
58             'name' => $fileName,
59             'path' => $filePath,
60             'uploaded_to' => $page_id,
61             'created_by' => user()->id,
62             'updated_by' => user()->id,
63             'order' => $largestExistingOrder + 1
64         ]);
65
66         return $file;
67     }
68
69     /**
70      * Save a new File attachment from a given link and name.
71      * @param string $name
72      * @param string $link
73      * @param int $page_id
74      * @return File
75      */
76     public function saveNewFromLink($name, $link, $page_id)
77     {
78         $largestExistingOrder = File::where('uploaded_to', '=', $page_id)->max('order');
79         return File::forceCreate([
80             'name' => $name,
81             'path' => $link,
82             'external' => true,
83             'uploaded_to' => $page_id,
84             'created_by' => user()->id,
85             'updated_by' => user()->id,
86             'order' => $largestExistingOrder + 1
87         ]);
88     }
89
90     /**
91      * Get the file storage base path, amended for storage type.
92      * This allows us to keep a generic path in the database.
93      * @return string
94      */
95     private function getStorageBasePath()
96     {
97         return $this->isLocal() ? 'storage/' : '';
98     }
99
100     /**
101      * Updates the file ordering for a listing of attached files.
102      * @param array $fileList
103      * @param $pageId
104      */
105     public function updateFileOrderWithinPage($fileList, $pageId)
106     {
107         foreach ($fileList as $index => $file) {
108             File::where('uploaded_to', '=', $pageId)->where('id', '=', $file['id'])->update(['order' => $index]);
109         }
110     }
111
112     /**
113      * Delete a file and any empty folders the deletion leaves.
114      * @param File $file
115      */
116     public function deleteFile(File $file)
117     {
118         if ($file->external) {
119             $file->delete();
120             return;
121         }
122         
123         $storedFilePath = $this->getStorageBasePath() . $file->path;
124         $storage = $this->getStorage();
125         $dirPath = dirname($storedFilePath);
126
127         $storage->delete($storedFilePath);
128         if (count($storage->allFiles($dirPath)) === 0) {
129             $storage->deleteDirectory($dirPath);
130         }
131
132         $file->delete();
133     }
134
135 }