Passed
Push — master ( bc7b5c...925ca7 )
by Georgi
03:13
created

File::userActiveLinks()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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