'int', ]; /** * People in Multimedia Object * * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany */ public function people() { return $this->belongsToMany(Person::class); } /** * Software used to create Multimedia Object * * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function software() { return $this->belongsTo(Software::class); } /** * Tags added to Multimedia Object * * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany */ public function tags() { return $this->belongsToMany(Tag::class); } /** * Find records marked as duplicate * * @param $query * @return mixed */ public function scopeDuplicates($query) { $query->notRemove() ->where('duplicate',TRUE) ->where(function($q) { $q->Where('ignore_duplicate','<>',TRUE) ->orWhereNull('ignore_duplicate'); }); } /** * Search Database for duplicates of this object * * @param $query * @return mixed */ public function scopeMyDuplicates($query) { if (! $this->exists) return $query; // Exclude this record $query->where('id','<>',$this->attributes['id']); // Skip ignore dups $query->where(function($q) { $q->whereNull('ignore_duplicate') ->orWhere('ignore_duplicate','=',0); }); // Exclude those marked as remove $query->where(function ($q) { $q->where('remove','<>',TRUE) ->orWhere('remove','=',NULL); }); $query->where(function ($q) { $q->where('signature','=',$this->attributes['signature']) ->orWhere('file_signature','=',$this->attributes['file_signature']) // Where the signature is the same ->orWhere(function($q) { // Or they have the same time taken with the same camera if ($this->attributes['created'] AND $this->software_id) { $q->where(function ($q) { $q->where('created','=',$this->attributes['created']) ->orWhere('created_manual','=',$this->attributes['created']); }); if (static::$includeSubSecTime) $q->where('subsectime','=',Arr::get($this->attributes,'subsectime')); $q->where('software_id','=',$this->attributes['software_id']); } elseif ($this->attributes['created_manual'] AND $this->software_id) { $q->where(function ($q) { $q->where('created','=',$this->attributes['created_manual']) ->orWhere('created_manual','=',$this->attributes['created_manual']); }); if (static::$includeSubSecTime) $q->where('subsectime','=',Arr::get($this->attributes,'subsectime')); $q->where('software_id','=',$this->attributes['software_id']); } }); }); } /** * Multimedia NOT duplicate. * * @return \Illuminate\Database\Eloquent\Builder */ public function scopeNotDuplicate($query) { return $query->where(function($query) { $query->where('duplicate','<>',TRUE) ->orWhere('duplicate','=',NULL); }); } /** * Multimedia NOT pending removal. * * @return \Illuminate\Database\Eloquent\Builder */ public function scopeNotRemove($query) { return $query->where(function($query) { $query->where('remove','<>',TRUE) ->orWhere('remove','=',NULL); }); } /** * Multimedia NOT scanned. * * @return \Illuminate\Database\Eloquent\Builder */ public function scopeNotScanned($query) { return $query->where(function($query) { $query->where('scanned','<>',TRUE) ->orWhere('scanned','=',NULL); }); } // Children objects must inherit this methods abstract public function setLocation(); abstract public function setSubSecTime(); abstract public function setThumbnail(); abstract public function getHtmlImageURL(); /** * Date the multimedia was created */ public function date_taken(): string { return $this->created ? $this->created->format('Y-m-d H:i:s').(static::$includeSubSecTime ? sprintf('.%03d',$this->subsectime) : '') : 'UNKNOWN'; } /** * What device was the multimedia created on * * @return string */ public function device(): string { $result = ''; if ($this->software_id) { if ($this->software->model_id) { if ($this->software->model->make_id) { $result .= $this->software->model->make->name; } $result .= ($result ? ' ' : '').$this->software->model->name; } $result .= ($result ? ' ' : '').$this->software->name; } return $result; } /** * Return the date of the file * @todo return Carbon date or NULL */ public function file_date($type,$format=FALSE) { if (! is_readable($this->file_path())) return NULL; switch ($type) { case 'a': $t = fileatime($this->file_path()); break; case 'c': $t = filectime($this->file_path()); break; case 'm': $t = filemtime($this->file_path()); break; } return $format ? date('d-m-Y H:i:s',$t) : $t; } /** * Return what the filename should be. * * @return string */ public function file_name(bool $short=TRUE): string { // If the date created is not set, the file name will be based on the ID of the file. $file = sprintf('%s.%s',(is_null($this->created) ? sprintf('UNKNOWN/%07s',$this->file_path_id()) : $this->created->format('Y/m/d-His'). ((! is_null($this->subsectime)) ? sprintf('_%03d',$this->subsectime) : '' ). sprintf('-%05s',$this->id)) ,$this->type() ); return (($short OR preg_match('/^\//',$file)) ? '' : config($this->type.'.dir').DIRECTORY_SEPARATOR).$file; } /** * Determine the new name for the image * @deprecated */ public function file_path($short=FALSE,$new=FALSE) { $file = $this->filename; if ($new) $file = $this->file_name(FALSE); return (($short OR preg_match('/^\//',$file)) ? '' : config($this->type.'.dir').DIRECTORY_SEPARATOR).$file; } /** * Calculate a file path ID based on the id of the file */ public function file_path_id($sep=3,$depth=9): string { return trim(chunk_split(sprintf("%0{$depth}s",$this->id),$sep,'/'),'/'); } /** * Display the file signature */ public function file_signature($short=FALSE): string { return $short ? static::stringtrim($this->file_signature) : $this->file_signature; } /** * Return the file size * @deprecated */ public function file_size() { return (! is_readable($this->file_path())) ? NULL : filesize($this->file_path()); } public function getCreatedAttribute(): Carbon { return $this->created_manual ?: $this->asDateTime($this->attributes['created']); } /** * Return item dimensions */ public function getDimensionsAttribute(): string { return $this->width.'x'.$this->height; } /** * Return HTML Checkbox for duplicate */ public function getDuplicateCheckboxAttribute() { return $this->HTMLCheckbox('duplicate',$this->id,$this->duplicate); } /** * Return the file size * * @return false|int|null */ public function getFileSizeAttribute() { return (! is_readable($this->file_path())) ? NULL : filesize($this->file_path()); } /** * Return HTML Checkbox for flagged */ public function getFlagCheckboxAttribute() { return $this->HTMLCheckbox('flag',$this->id,$this->flag); } /** * Return HTML Checkbox for ignore */ public function getIgnoreCheckboxAttribute() { return $this->HTMLCheckbox('ignore_duplicate',$this->id,$this->ignore_duplicate); } /** * @deprecated */ public function getDuplicateTextAttribute() { return $this->TextTrueFalse($this->duplicate); } /** * @deprecated */ public function getFlagTextAttribute() { return $this->TextTrueFalse($this->flag); } /** * Return HTML Checkbox for remove */ public function getRemoveCheckboxAttribute() { return $this->HTMLCheckbox('remove',$this->id,$this->remove); } /** * Return the object type * @return string * @deprecated Use objecttype() */ public function getTypeAttribute(): string { switch(get_class($this)) { case 'App\Models\Photo': return 'photo'; case 'App\Models\Video': return 'video'; default: return 'unknown'; } } /** * Display the GPS coordinates */ public function gps(): string { return ($this->gps_lat AND $this->gps_lon) ? sprintf('%s/%s',$this->gps_lat,$this->gps_lon) : 'UNKNOWN'; } /** * Return if this source file is readable. * * @return bool */ public function isReadable(): bool { return is_readable($this->file_path()); } /** * Return an HTML checkbox */ protected function HTMLCheckbox($name,$id,$value) { return sprintf('',$name,$id,$value ? ' checked="checked"' : ''); } /** * Get ID Info link */ protected function HTMLLinkAttribute($id,$url) { return sprintf('%s',url($url,$id),$id,$id); } /** * Determine if the parent dir is writable * * @param $dir * @return bool */ public function isParentWritable($dir): bool { if (file_exists($dir) AND is_writable($dir) AND is_dir($dir)) return TRUE; elseif ($dir == dirname($dir) OR file_exists($dir)) return FALSE; else return ($this->isParentWritable(dirname($dir))); } /** * Determine if a file is moveable * * useID boolean Determine if the path is based on the the ID or date * @todo Change to boolean and rename isMoveable() Log any FALSE reason. */ public function moveable() { // If the source and target are the same, we dont need to move it if ($this->file_path() == $this->file_path(FALSE,TRUE)) return FALSE; // If there is already a file in the target. // @todo If the target file is to be deleted, we could move this file if (file_exists($this->file_path(FALSE,TRUE))) return 1; // Test if the source is readable if (! is_readable($this->file_path())) return 2; // Test if the dir is writable (so we can remove the file) if (! $this->isParentWritable(dirname($this->file_path()))) return 3; // Test if the target dir is writable // @todo The target dir may not exist yet, so we should check that a parent exists and is writable. if (! $this->isParentWritable($this->file_path(FALSE,TRUE))) return 4; return TRUE; } /** * Get the id of the previous record */ public function next() { return DB::table($this->getTable()) ->where('id','>',$this->id) ->orderby('id','ASC') ->first(); } abstract public function property(string $property); /** * Return my class shortname */ public function objectType(): string { return (new \ReflectionClass($this))->getShortName(); } /** * Get the id of the previous record */ public function previous() { return DB::table($this->getTable()) ->where('id','<',$this->id) ->orderby('id','DESC') ->first(); } public function setDateCreated() { $this->created = $this->property('creationdate'); } public function setHeightWidth() { $this->height = $this->property('height'); $this->width = $this->property('width'); $this->orientation = $this->property('orientation'); } public function setSignature() { $this->signature = $this->property('signature'); $this->file_signature = md5_file($this->file_path()); } /** * Display the media signature */ public function signature($short=FALSE) { return ($short AND $this->signature) ? static::stringtrim($this->signature) : $this->signature; } /** * Trim a string * * @param string $string * @param int $chrs * @return string */ public static function stringtrim(string $string,int $chrs=6) { return sprintf('%s...%s',substr($string,0,$chrs),substr($string,-1*$chrs)); } /** * @deprecated * @param string $string * @param int $chrs * @return string */ public static function signaturetrim(string $string,int $chrs=6) { return static::stringtrim($string,$chrs); } /** * Determine if the image should be moved */ public function shouldMove(): bool { return $this->filename !== $this->file_name(); } protected function TextTrueFalse($value): string { return $value ? 'TRUE' : 'FALSE'; } /** * @todo Check if this is redundant * * @param bool $includeme * @return mixed */ private function list_duplicate($includeme=FALSE) { return $this->list_duplicates($includeme)->pluck('id'); } /** * Find duplicate images based on some attributes of the current image * @deprecate Use static::duplicates() */ private function list_duplicates($includeme=FALSE) { $o = static::select(); if ($this->id AND ! $includeme) $o->where('id','!=',$this->id); // Ignore photo's pending removal. if (! $includeme) $o->where(function($query) { $query->where('remove','<>',TRUE) ->orWhere('remove','=',NULL); }); // Where the signature is the same $o->where(function($query) { $query->where('signature','=',$this->signature); // Or they have the same time taken with the same camera if ($this->date_created AND ($this->model OR $this->make)) { $query->orWhere(function($query) { $query->where('date_created','=',$this->date_created ? $this->date_created : NULL); if (Schema::hasColumn($this->getTable(),'subsectime')) $query->where('subsectime','=',$this->subsectime ? $this->subsectime : NULL); if (! is_null($this->model)) $query->where('model','=',$this->model); if (! is_null($this->make)) $query->where('make','=',$this->make); }); } }); return $o->get(); } }