$value) $this->$attribute = $value; if (!empty($data['date_captured']) && $data['date_captured'] !== 'NULL') $this->date_captured = new DateTime($data['date_captured']); } public static function fromId($id_asset, $return_format = 'object') { $db = Registry::get('db'); $row = $db->queryAssoc(' SELECT * FROM assets WHERE id_asset = {int:id_asset}', [ 'id_asset' => $id_asset, ]); // Asset not found? if (empty($row)) return false; $row['meta'] = $db->queryPair(' SELECT variable, value FROM assets_meta WHERE id_asset = {int:id_asset}', [ 'id_asset' => $id_asset, ]); return $return_format == 'object' ? new Asset($row) : $row; } public static function fromIds(array $id_assets, $return_format = 'array') { if (empty($id_assets)) return []; $db = Registry::get('db'); $res = $db->query(' SELECT * FROM assets WHERE id_asset IN ({array_int:id_assets}) ORDER BY id_asset', [ 'id_assets' => $id_assets, ]); $assets = []; while ($asset = $db->fetch_assoc($res)) { $assets[$asset['id_asset']] = $asset; $assets[$asset['id_asset']]['meta'] = []; } $metas = $db->queryRows(' SELECT id_asset, variable, value FROM assets_meta WHERE id_asset IN ({array_int:id_assets}) ORDER BY id_asset', [ 'id_assets' => $id_assets, ]); foreach ($metas as $meta) $assets[$meta[0]]['meta'][$meta[1]] = $meta[2]; if ($return_format == 'array') return $assets; else { $objects = []; foreach ($assets as $id => $asset) $objects[$id] = new Asset($asset); return $objects; } } public static function byPostId($id_post, $return_format = 'object') { $db = Registry::get('db'); // !!! TODO } public static function createNew(array $data, $return_format = 'object') { // Extract the data array. extract($data); // No filename? Abort! if (!isset($filename_to_copy) || !is_file($filename_to_copy)) return false; // No subdir? Use YYYY/MM if (!isset($preferred_subdir)) $preferred_subdir = date('Y') . '/' . date('m'); // Does this dir exist yet? If not, create it. if (!is_dir(ASSETSDIR . '/' . $preferred_subdir)) mkdir(ASSETSDIR . '/' . $preferred_subdir, 0755, true); // Construct the destination filename. Make sure we don't accidentally overwrite anything. if (!isset($preferred_filename)) $preferred_filename = basename($filename_to_copy); $new_filename = $preferred_filename; $destination = ASSETSDIR . '/' . $preferred_subdir . '/' . $preferred_filename; while (file_exists($destination)) { $filename = pathinfo($preferred_filename, PATHINFO_FILENAME) . '_' . mt_rand(10, 99); $extension = pathinfo($preferred_filename, PATHINFO_EXTENSION); $new_filename = $filename . '.' . $extension; $destination = dirname($destination) . '/' . $new_filename; } // Can we write to the target directory? Then copy the file. if (is_writable(ASSETSDIR . '/' . $preferred_subdir)) copy($filename_to_copy, $destination); else return false; // Figure out the mime type for the file. $finfo = finfo_open(FILEINFO_MIME_TYPE); $mimetype = finfo_file($finfo, $destination); finfo_close($finfo); // Do we have a title yet? Otherwise, use the filename. $title = isset($data['title']) ? $data['title'] : pathinfo($preferred_filename, PATHINFO_FILENAME); // Same with the slug. $slug = isset($data['slug']) ? $data['slug'] : $preferred_subdir . '/' . pathinfo($preferred_filename, PATHINFO_FILENAME); // Detected an image? if (substr($mimetype, 0, 5) == 'image') { $image = new Imagick($destination); $d = $image->getImageGeometry(); // Get image dimensions, bearing orientation in mind. switch ($image->getImageOrientation()) { case Imagick::ORIENTATION_LEFTBOTTOM: case Imagick::ORIENTATION_RIGHTTOP: $image_width = $d['height']; $image_height = $d['width']; break; default: $image_width = $d['width']; $image_height = $d['height']; } unset($image); $exif = EXIF::fromFile($destination); $date_captured = intval($exif->created_timestamp); } $db = Registry::get('db'); $res = $db->query(' INSERT INTO assets (subdir, filename, title, slug, mimetype, image_width, image_height, date_captured, priority) VALUES ({string:subdir}, {string:filename}, {string:title}, {string:slug}, {string:mimetype}, {int:image_width}, {int:image_height}, IF({int:date_captured} > 0, FROM_UNIXTIME({int:date_captured}), NULL), {int:priority})', [ 'subdir' => $preferred_subdir, 'filename' => $new_filename, 'title' => $title, 'slug' => $slug, 'mimetype' => $mimetype, 'image_width' => isset($image_width) ? $image_width : 'NULL', 'image_height' => isset($image_height) ? $image_height : 'NULL', 'date_captured' => isset($date_captured) ? $date_captured : 'NULL', 'priority' => isset($priority) ? (int) $priority : 0, ]); if (!$res) { unlink($destination); return false; } $data['id_asset'] = $db->insert_id(); return $return_format == 'object' ? new self($data) : $data; } public function getId() { return $this->id_asset; } public function getDateCaptured() { return $this->date_captured; } public function getFilename() { return $this->filename; } public function getLinkedPosts() { $posts = Registry::get('db')->queryValues(' SELECT id_post FROM posts_assets WHERE id_asset = {int:id_asset}', ['id_asset' => $this->id_asset]); // TODO: fix empty post iterator. if (empty($posts)) return []; return PostIterator::getByOptions([ 'ids' => $posts, 'type' => '', ]); } public function getMeta() { return $this->meta; } public function getPath() { return $this->subdir; } public function getPriority() { return $this->priority; } public function getTags() { if (!isset($this->tags)) $this->tags = Tag::byAssetId($this->id_asset); return $this->tags; } public function getTitle() { return $this->title; } public function getUrl() { return BASEURL . '/assets/' . $this->subdir . '/' . $this->filename; } public function getType() { return substr($this->mimetype, 0, strpos($this->mimetype, '/')); } public function getDimensions($as_type = 'string') { return $as_type === 'string' ? $this->image_width . 'x' . $this->image_height : [$this->image_width, $this->image_height]; } public function isImage() { return substr($this->mimetype, 0, 5) === 'image'; } public function getImage() { if (!$this->isImage()) throw new Exception('Trying to upgrade an Asset to an Image while the Asset is not an image!'); return new Image(get_object_vars($this)); } public function replaceFile($filename) { // No filename? Abort! if (!isset($filename) || !is_readable($filename)) return false; // Can we write to the target file? $destination = ASSETSDIR . '/' . $this->subdir . '/' . $this->filename; if (!is_writable($destination)) return false; copy($filename, $destination); // Figure out the mime type for the file. $finfo = finfo_open(FILEINFO_MIME_TYPE); $this->mimetype = finfo_file($finfo, $destination); finfo_close($finfo); // Detected an image? if (substr($this->mimetype, 0, 5) == 'image') { $image = new Imagick($destination); $d = $image->getImageGeometry(); $this->image_width = $d['width']; $this->image_height = $d['height']; unset($image); $exif = EXIF::fromFile($destination); if (!empty($exif->created_timestamp)) $this->date_captured = new DateTime(date('r', $exif->created_timestamp)); else $this->date_captured = null; } else { $this->image_width = null; $this->image_height = null; $this->date_captured = null; } return Registry::get('db')->query(' UPDATE assets SET mimetype = {string:mimetype}, image_width = {int:image_width}, image_height = {int:image_height}, date_captured = {datetime:date_captured}, priority = {int:priority} WHERE id_asset = {int:id_asset}', [ 'id_asset' => $this->id_asset, 'mimetype' => $this->mimetype, 'image_width' => isset($this->image_width) ? $this->image_width : 'NULL', 'image_height' => isset($this->image_height) ? $this->image_height : 'NULL', 'date_captured' => isset($this->date_captured) ? $this->date_captured : 'NULL', 'priority' => $this->priority, ]); } protected function saveMetaData() { $this->setMetaData($this->meta); } public function setMetaData(array $new_meta, $mode = 'replace') { $db = Registry::get('db'); // If we're replacing, delete current data first. if ($mode === 'replace') { $to_remove = array_diff_key($this->meta, $new_meta); if (!empty($to_remove)) $db->query(' DELETE FROM assets_meta WHERE id_asset = {int:id_asset} AND variable IN({array_string:variables})', [ 'id_asset' => $this->id_asset, 'variables' => array_keys($to_remove), ]); } // Build rows $to_insert = []; foreach ($new_meta as $key => $value) $to_insert[] = [ 'id_asset' => $this->id_asset, 'variable' => $key, 'value' => $value, ]; // Do the insertion $res = Registry::get('db')->insert('replace', 'assets_meta', [ 'id_asset' => 'int', 'variable' => 'string', 'value' => 'string', ], $to_insert, ['id_asset', 'variable']); if ($res) $this->meta = $new_meta; } public function delete() { return Registry::get('db')->query(' DELETE FROM assets WHERE id_asset = {int:id_asset}', [ 'id_asset' => $this->id_asset, ]); } public function linkTags(array $id_tags) { if (empty($id_tags)) return true; $pairs = []; foreach ($id_tags as $id_tag) $pairs[] = ['id_asset' => $this->id_asset, 'id_tag' => $id_tag]; Registry::get('db')->insert('ignore', 'assets_tags', [ 'id_asset' => 'int', 'id_tag' => 'int', ], $pairs, ['id_asset', 'id_tag']); Tag::recount($id_tags); } public function unlinkTags(array $id_tags) { if (empty($id_tags)) return true; Registry::get('db')->query(' DELETE FROM assets_tags WHERE id_asset = {int:id_asset} AND id_tag IN ({array_int:id_tags})', [ 'id_asset' => $this->id_asset, 'id_tags' => $id_tags, ]); Tag::recount($id_tags); } public static function getCount() { return $db->queryValue(' SELECT COUNT(*) FROM assets'); } public function setKeyData($title, DateTime $date_captured = null, $priority) { $params = [ 'id_asset' => $this->id_asset, 'title' => $title, 'priority' => $priority, ]; if (isset($date_captured)) $params['date_captured'] = $date_captured->format('Y-m-d H:i:s'); return Registry::get('db')->query(' UPDATE assets SET title = {string:title},' . (isset($date_captured) ? ' date_captured = {datetime:date_captured},' : '') . ' priority = {int:priority} WHERE id_asset = {int:id_asset}', $params); } }