Passed
Push — master ( 3256e3...60c4f2 )
by Georgi
03:14
created

File::thumbnailPossible()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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