Passed
Push — master ( 60c4f2...db8d73 )
by Georgi
02:28
created

File::unlink()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Epesi\FileStorage\Database\Models;
4
5
use Illuminate\Database\Eloquent\Model;
6
use Illuminate\Database\Eloquent\SoftDeletes;
7
use Illuminate\Support\Facades\Auth;
8
9
class LinkNotFound extends \Exception {}
10
class LinkDuplicate extends \Exception {}
11
class FileNotFound extends \Exception {}
12
13
class File extends Model
14
{
15
	use SoftDeletes;
16
	
17
    protected $table = 'filestorage_files';
18
    protected static $unguarded = true;
19
20
    public function content()
21
    {
22
    	return $this->belongsTo(FileContent::class, 'content_id');
23
    }
24
    
25
    public function links()
26
    {
27
    	return $this->hasMany(FileRemoteAccess::class, 'file_id');
28
    }
29
    
30
    
31
    /**
32
     * Retrieve the file
33
     *
34
     * @param int|string $idOrLink Filestorage ID or unique link string
35
     * @param bool $useCache Use cache or not
36
     *
37
     * @return static
38
     * 
39
     * @throws FileNotFound
40
     */
41
    public static function get($idOrLink, $useCache = true)
42
    {
43
    	static $cache = [];
44
    	
45
    	if (is_object($idOrLink)) return $idOrLink;
0 ignored issues
show
introduced by
The condition is_object($idOrLink) is always false.
Loading history...
46
47
    	$id = self::getIdByLink($idOrLink, true, true);
48
49
    	if ($useCache && isset($cache[$id])) {
50
    		return $cache[$id];
51
    	}
52
53
    	$file = self::with('content')->findOrFail($id);
54
    	
55
    	if (empty($file->content['hash'])) {
56
    		throw new FileNotFound('File object does not have corresponding content');
57
    	}
58
59
    	return $cache[$id] = $file;
60
    }
61
    
62
    /**
63
     * Get Filestorage ID by link
64
     *
65
     * @param string $link            Unique link
66
     * @param bool   $useCache       Use cache or not
67
     * @param bool   $throwException Throw exception if link is not found
68
     *
69
     * @return int Filestorage ID
70
     * @throws LinkNotFound
71
     */
72
    public static function getIdByLink($link, $useCache = true, $throwException = false)
73
    {
74
    	static $cache = [];
75
    	
76
    	if (is_numeric($link)) return $link;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $link returns the type string which is incompatible with the documented return type integer.
Loading history...
77
    	
78
    	if (!$useCache || !isset($cache[$link])) {
79
    		$cache[$link] = self::where('link', $link)->value('id');
80
    		
81
    		if (!$cache[$link] && $throwException) {
82
    			throw new LinkNotFound($link);
83
    		}
84
    	}
85
    	
86
    	return $cache[$link];
87
    }
88
89
    /**
90
     * Mark file as deleted. Does not remove any content!
91
     *
92
     * @param int|string $idOrLink Filestorage ID or unique link
93
     */
94
    public static function unlink($idOrLink)
95
    {
96
   		if ($id = self::getIdByLink($idOrLink, false)) {
97
   			self::find($id)->delete();
98
    	}
99
    }
100
    
101
    /**
102
     * Check if file exists
103
     *
104
     * @param int|static $idOrMeta              Filestorage ID or file object
105
     * @param bool      $throwException Throw exception on missing file or return false
106
     *
107
     * @return bool True if file exists, false otherwise
108
     * @throws FileNotFound May be thrown if $throwException set to true
109
     */
110
    public static function exists($idOrMeta, $throwException = false)
111
    {
112
    	try {
113
    		$file = is_numeric($idOrMeta) ? self::get($idOrMeta) : $idOrMeta;
114
    		
115
    		if (! file_exists($file->content->path)) {
116
    			throw new FileNotFound('Exception - file not found: ' . $file->content->path);
117
    		}
118
    	} catch (\Exception $exception) {
119
    		if ($throwException)
120
    			throw $exception;
121
    		else
122
    			return false;
123
    	}
124
    	
125
    	return true;
126
    }
127
    
128
    /**
129
     * Add multiple files, clone file if file id is provided.
130
     * May be used to update backref for all files.
131
     *
132
     * @param array $files array of existing filestorage ids or array with values for the new file
133
     * @param string|null $backref Backref for all files
134
     * @return array Newly created Meta Ids sorted in ascending order
135
     */
136
    public static function putMany($files, $backref = null)
137
    {
138
    	$ids = [];
139
    	foreach ((array) $files as $filePath) {
140
    		if (! is_numeric($filePath)) {
141
    			$ids[] = self::put($filePath);
142
    			
143
    			continue;
144
    		}
145
    		
146
    		$file = self::get($filePath, false)->toArray();
147
    			
148
    		if ($backref && $file['backref'] != $backref) {
149
    			$file['backref'] = $backref;
150
    			unset($file['link']);
151
    			
152
    			self::put($file);
153
    		}
154
    			
155
    		$ids[] = $file;
156
    	}
157
    	
158
    	sort($ids);
159
    	
160
    	return $ids;
161
    }
162
        
163
    /**
164
     * @param string|array     $fileOrPath
165
     * @param string     $content    Content of the file
166
     * 
167
     * @return int Filestorage ID
168
     * @throws LinkDuplicate
169
     */
170
    public static function put($fileOrPath, $content = null) 
171
    {
172
    	$file = $fileOrPath;
173
    	if (! $content && is_string($fileOrPath)) {
174
    		$content = file_get_contents($fileOrPath);
175
    		
176
    		$file = [
177
    				'name' => basename($fileOrPath)
178
    		];
179
    	}
180
    	
181
    	if (!empty($file['link']) && self::getIdByLink($file['link'], false)) {
182
    		throw new LinkDuplicate($file['link']);
183
    	}
184
    	
185
    	$content = $file['content']?? $content;
186
    	
187
    	if (is_array($content)) {
188
    		$path = $content['path'];
189
    			
190
    		$file['name'] = $file['name']?? basename($path);
191
    			
192
    		$content = file_get_contents($path);
193
    	}
194
195
    	unset($file['content']);
196
    	
197
    	return self::updateOrCreate(['id' => $file['id']?? null], array_merge([
198
    			'created_at' => time(),
199
    			'created_by' => Auth::id(),
200
    			'content_id' => FileContent::put($content)
201
    	], $file))->id;
202
    }
203
    
204
    public function getThumbnailAttribute()
205
    {
206
    	if (! $this->thumbnailPossible()) return false;
207
    	
208
    	$image = new \Imagick($this->content->path . '[0]');
209
    	
210
    	$image->setImageFormat('jpg');
211
    	
212
    	$mime = 'image/jpeg';
213
    	
214
    	$name = 'preview.jpeg';
215
    	
216
    	$contents = $image . '';
217
    	
218
    	return collect(compact('mime', 'name', 'contents'));
219
    }
220
    
221
    protected function thumbnailPossible() {
222
    	return $this->content->type == 'application/pdf' && class_exists('Imagick');
223
    }
224
}