/** * Create a new movie. * @param integer $parent_id id of parent album * @param string $filename path to the photo file on disk * @param string $name the filename to use for this photo in the album * @param integer $title the title of the new photo * @param string $description (optional) the longer description of this photo * @return Item_Model */ static function create($parent, $filename, $name, $title, $description = null, $owner_id = null) { if (!$parent->loaded || !$parent->is_album()) { throw new Exception("@todo INVALID_PARENT"); } if (!is_file($filename)) { throw new Exception("@todo MISSING_MOVIE_FILE"); } if (strpos($name, "/")) { throw new Exception("@todo NAME_CANNOT_CONTAIN_SLASH"); } // We don't allow trailing periods as a security measure // ref: http://dev.kohanaphp.com/issues/684 if (rtrim($name, ".") != $name) { throw new Exception("@todo NAME_CANNOT_END_IN_PERIOD"); } $movie_info = movie::getmoviesize($filename); // Force an extension onto the name $pi = pathinfo($filename); if (empty($pi["extension"])) { $pi["extension"] = image_type_to_extension($movie_info[2], false); $name .= "." . $pi["extension"]; } $movie = ORM::factory("item"); $movie->type = "movie"; $movie->title = $title; $movie->description = $description; $movie->name = $name; $movie->owner_id = $owner_id ? $owner_id : user::active(); $movie->width = $movie_info[0]; $movie->height = $movie_info[1]; $movie->mime_type = strtolower($pi["extension"]) == "mp4" ? "video/mp4" : "video/x-flv"; $movie->thumb_dirty = 1; $movie->resize_dirty = 1; $movie->sort_column = "weight"; $movie->rand_key = (double) mt_rand() / (double) mt_getrandmax(); // Randomize the name if there's a conflict while (ORM::Factory("item")->where("parent_id", $parent->id)->where("name", $movie->name)->find()->id) { // @todo Improve this. Random numbers are not user friendly $movie->name = rand() . "." . $pi["extension"]; } // This saves the photo $movie->add_to_parent($parent); // If the thumb or resize already exists then rename it if (file_exists($movie->resize_path()) || file_exists($movie->thumb_path())) { $movie->name = $pi["filename"] . "-" . rand() . "." . $pi["extension"]; $movie->save(); } copy($filename, $movie->file_path()); module::event("item_created", $movie); // Build our thumbnail graphics::generate($movie); // If the parent has no cover item, make this it. if (access::can("edit", $parent) && $parent->album_cover_item_id == null) { item::make_album_cover($movie); } return $movie; }
/** * Handle any business logic necessary to create or modify an item. * @see ORM::save() * * @return ORM Item_Model */ public function save() { $significant_changes = $this->changed; unset($significant_changes["view_count"]); unset($significant_changes["relative_url_cache"]); unset($significant_changes["relative_path_cache"]); if (!empty($this->changed) && $significant_changes) { $this->updated = time(); if (!$this->loaded()) { // Create a new item. // Set a weight if it's missing. We don't do this in the constructor because it's not a // simple assignment. if (empty($this->weight)) { $this->weight = item::get_max_weight(); } // Make an url friendly slug from the name, if necessary if (empty($this->slug)) { $tmp = pathinfo($this->name, PATHINFO_FILENAME); $tmp = preg_replace("/[^A-Za-z0-9-_]+/", "-", $tmp); $this->slug = trim($tmp, "-"); } // Get the width, height and mime type from our data file for photos and movies. if ($this->is_movie() || $this->is_photo()) { $pi = pathinfo($this->data_file); if ($this->is_photo()) { $image_info = getimagesize($this->data_file); $this->width = $image_info[0]; $this->height = $image_info[1]; $this->mime_type = $image_info["mime"]; // Force an extension onto the name if necessary if (empty($pi["extension"])) { $pi["extension"] = image_type_to_extension($image_info[2], false); $this->name .= "." . $pi["extension"]; } } else { list($this->width, $this->height) = movie::getmoviesize($this->data_file); // No extension? Assume FLV. if (empty($pi["extension"])) { $pi["extension"] = "flv"; $this->name .= "." . $pi["extension"]; } $this->mime_type = strtolower($pi["extension"]) == "mp4" ? "video/mp4" : "video/x-flv"; } } // Randomize the name or slug if there's a conflict. Preserve the extension. // @todo Improve this. Random numbers are not user friendly $base_name = pathinfo($this->name, PATHINFO_FILENAME); $base_ext = pathinfo($this->name, PATHINFO_EXTENSION); $base_slug = $this->slug; while (ORM::factory("item")->where("parent_id", "=", $this->parent_id)->and_open()->where("name", "=", $this->name)->or_where("slug", "=", $this->slug)->close()->find()->id) { $rand = rand(); if ($base_ext) { $this->name = "{$base_name}-{$rand}.{$base_ext}"; } else { $this->name = "{$base_name}-{$rand}"; } $this->slug = "{$base_slug}-{$rand}"; } parent::save(); // Build our url caches, then save again. We have to do this after it's already been // saved once because we use only information from the database to build the paths. If we // could depend on a save happening later we could defer this 2nd save. $this->_build_relative_caches(); parent::save(); // Take any actions that we can only do once all our paths are set correctly after saving. switch ($this->type) { case "album": mkdir($this->file_path()); mkdir(dirname($this->thumb_path())); mkdir(dirname($this->resize_path())); break; case "photo": case "movie": // The thumb or resize may already exist in the case where a movie and a photo generate // a thumbnail of the same name (eg, foo.flv movie and foo.jpg photo will generate // foo.jpg thumbnail). If that happens, randomize and save again. if (file_exists($this->resize_path()) || file_exists($this->thumb_path())) { $pi = pathinfo($this->name); $this->name = $pi["filename"] . "-" . rand() . "." . $pi["extension"]; parent::save(); } copy($this->data_file, $this->file_path()); break; } // This will almost definitely trigger another save, so put it at the end so that we're // tail recursive. module::event("item_created", $this); } else { // Update an existing item // If any significant fields have changed, load up a copy of the original item and // keep it around. $original = ORM::factory("item", $this->id); if (array_intersect($this->changed, array("parent_id", "name", "slug"))) { $original->_build_relative_caches(); $this->relative_path_cache = null; $this->relative_url_cache = null; } parent::save(); // Now update the filesystem and any database caches if there were significant value // changes. If anything past this point fails, then we'll have an inconsistent database // so this code should be as robust as we can make it. // Update the MPTT pointers, if necessary. We have to do this before we generate any // cached paths! if ($original->parent_id != $this->parent_id) { parent::move_to($this->parent()); } if ($original->parent_id != $this->parent_id || $original->name != $this->name) { // Move all of the items associated data files @rename($original->file_path(), $this->file_path()); if ($this->is_album()) { @rename(dirname($original->resize_path()), dirname($this->resize_path())); @rename(dirname($original->thumb_path()), dirname($this->thumb_path())); } else { @rename($original->resize_path(), $this->resize_path()); @rename($original->thumb_path(), $this->thumb_path()); } if ($original->parent_id != $this->parent_id) { // This will result in 2 events since we'll still fire the item_updated event below module::event("item_moved", $this, $original->parent()); } } // Changing the name, slug or parent ripples downwards if ($this->is_album() && ($original->name != $this->name || $original->slug != $this->slug || $original->parent_id != $this->parent_id)) { db::build()->update("items")->set("relative_url_cache", null)->set("relative_path_cache", null)->where("left_ptr", ">", $this->left_ptr)->where("right_ptr", "<", $this->right_ptr)->execute(); } module::event("item_updated", $original, $this); } } else { if (!empty($this->changed)) { // Insignificant changes only. Don't fire events or do any special checking to try to keep // this lightweight. parent::save(); } } return $this; }
/** * Create a new movie. * @param integer $parent_id id of parent album * @param string $filename path to the photo file on disk * @param string $name the filename to use for this photo in the album * @param integer $title the title of the new photo * @param string $description (optional) the longer description of this photo * @param string $slug (optional) the url component for this photo * @return Item_Model */ static function create($parent, $filename, $name, $title, $description = null, $owner_id = null, $slug = null) { if (!$parent->loaded || !$parent->is_album()) { throw new Exception("@todo INVALID_PARENT"); } if (!is_file($filename)) { throw new Exception("@todo MISSING_MOVIE_FILE"); } if (strpos($name, "/")) { throw new Exception("@todo NAME_CANNOT_CONTAIN_SLASH"); } // We don't allow trailing periods as a security measure // ref: http://dev.kohanaphp.com/issues/684 if (rtrim($name, ".") != $name) { throw new Exception("@todo NAME_CANNOT_END_IN_PERIOD"); } try { $movie_info = movie::getmoviesize($filename); } catch (Exception $e) { // Assuming this is MISSING_FFMPEG for now $movie_info = getimagesize(MODPATH . "gallery/images/missing_movie.png"); } // Force an extension onto the name $pi = pathinfo($filename); if (empty($pi["extension"])) { $pi["extension"] = image_type_to_extension($movie_info[2], false); $name .= "." . $pi["extension"]; } if (empty($slug)) { $slug = item::convert_filename_to_slug($name); } $movie = ORM::factory("item"); $movie->type = "movie"; $movie->title = $title; $movie->description = $description; $movie->name = $name; $movie->owner_id = $owner_id ? $owner_id : identity::active_user()->id; $movie->width = $movie_info[0]; $movie->height = $movie_info[1]; $movie->mime_type = strtolower($pi["extension"]) == "mp4" ? "video/mp4" : "video/x-flv"; $movie->thumb_dirty = 1; $movie->resize_dirty = 1; $movie->sort_column = "weight"; $movie->slug = $slug; $movie->rand_key = (double) mt_rand() / (double) mt_getrandmax(); // Randomize the name if there's a conflict // @todo Improve this. Random numbers are not user friendly while (ORM::factory("item")->where("parent_id", $parent->id)->open_paren()->where("name", $movie->name)->orwhere("slug", $movie->slug)->close_paren()->find()->id) { $rand = rand(); $movie->name = "{$name}.{$rand}.{$pi['extension']}"; $movie->slug = "{$slug}-{$rand}"; } // This saves the photo $movie->add_to_parent($parent); // If the thumb or resize already exists then rename it if (file_exists($movie->resize_path()) || file_exists($movie->thumb_path())) { $movie->name = $pi["filename"] . "-" . rand() . "." . $pi["extension"]; $movie->save(); } copy($filename, $movie->file_path()); // @todo: publish this from inside Item_Model::save() when we refactor to the point where // there's only one save() happening here. module::event("item_created", $movie); // Build our thumbnail graphics::generate($movie); // If the parent has no cover item, make this it. if (access::can("edit", $parent) && $parent->album_cover_item_id == null) { item::make_album_cover($movie); } return $movie; }