From ab4a8ea07ec43e062b97d795ad439560c56cffd3 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Sat, 13 Aug 2011 22:54:18 -0700 Subject: [PATCH] Use the page context changes to display elements to properly set the next and previous buttons in an image display. The method 'display_context' returns the theme page values that depend on which context the item is being displayed. --- 3.0/modules/dynamic/controllers/dynamic.php | 33 +++-- 3.0/modules/dynamic/helpers/dynamic.php | 118 ++++++++++++++++++ .../libraries/Dynamic_Display_Context.php | 56 +++++++++ 3 files changed, 194 insertions(+), 13 deletions(-) create mode 100644 3.0/modules/dynamic/helpers/dynamic.php create mode 100644 3.0/modules/dynamic/libraries/Dynamic_Display_Context.php diff --git a/3.0/modules/dynamic/controllers/dynamic.php b/3.0/modules/dynamic/controllers/dynamic.php index 10a7a6f5..598c64f6 100644 --- a/3.0/modules/dynamic/controllers/dynamic.php +++ b/3.0/modules/dynamic/controllers/dynamic.php @@ -27,18 +27,25 @@ class Dynamic_Controller extends Controller { private function _show($album) { $page_size = module::get_var("gallery", "page_size", 9); - $page = Input::instance()->get("page", "1"); $album_defn = unserialize(module::get_var("dynamic", $album)); - $display_limit = $album_defn->limit; - $children_count = ORM::factory("item") - ->viewable() - ->where("type", "!=", "album") - ->count_all(); - if (!empty($display_limit)) { - $children_count = min($children_count, $display_limit); + + $input = Input::instance(); + $show = $input->get("show"); + + if ($show) { + $child = ORM::factory("item", $show); + $index = dynamic::get_position($album_defn, $child); + if ($index) { + $page = ceil($index / $page_size); + url::redirect("dynamic/$album" . ($page == 1 ? "" : "?page=$page")); + } + } else { + $page = (int) $input->get("page", "1"); } + $children_count = dynamic::get_display_count($album_defn); + $offset = ($page - 1) * $page_size; $max_pages = max(ceil($children_count / $page_size), 1); @@ -47,15 +54,15 @@ class Dynamic_Controller extends Controller { throw new Kohana_404_Exception(); } + Display_Context::factory("dynamic") + ->set(array("dynamic_type" => $album_defn, "path" => $album)) + ->save(); + $template = new Theme_View("page.html", "collection", "dynamic"); $template->set_global("page", $page); $template->set_global("page_size", $page_size); $template->set_global("max_pages", $max_pages); - $template->set_global("children", ORM::factory("item") - ->viewable() - ->where("type", "!=", "album") - ->order_by($album_defn->key_field, "DESC") - ->find_all($page_size, $offset)); + $template->set_global("children", dynamic::items($album_defn->key_field, $page_size, $offset)); $template->set_global("children_count", $children_count); $template->content = new View("dynamic.html"); $template->content->title = t($album_defn->title); diff --git a/3.0/modules/dynamic/helpers/dynamic.php b/3.0/modules/dynamic/helpers/dynamic.php new file mode 100644 index 00000000..3c654c76 --- /dev/null +++ b/3.0/modules/dynamic/helpers/dynamic.php @@ -0,0 +1,118 @@ +limit; + $children_count = ORM::factory("item") + ->viewable() + ->where("type", "!=", "album") + ->count_all(); + if (!empty($display_limit)) { + $children_count = min($children_count, $display_limit); + } + return $children_count; + } + + static function items($key_field, $limit=null, $offset=null) { + return ORM::factory("item") + ->viewable() + ->where("type", "!=", "album") + ->order_by($key_field, "DESC") + ->find_all($limit, $offset); + } + + /** + * Find the position of the given item in the tag collection. The resulting + * value is 1-indexed, so the first child in the album is at position 1. + * + * @param Tag_Model $tag + * @param Item_Model $item + * @param array $where an array of arrays, each compatible with ORM::where() + */ + static function get_position($dynamic_type_definition, $item) { + + $sort_column = $dynamic_type_definition->key_field; + $display_limit = self::get_display_count($dynamic_type_definition); + + $query_model = ORM::factory("item"); + + // If the comparison column has NULLs in it, we can't use comparators on it + // and will have to deal with it the hard way. + $count = $query_model->viewable() + ->where($sort_column, "IS", null) + ->where("type", "!=", "album") + ->count_all(); + + if (empty($count)) { + // There are no NULLs in the sort column, so we can just use it directly. + + $position = $query_model->viewable() + ->where($sort_column, ">", $item->$sort_column) + ->where("type", "!=", "album") + ->order_by(array($dynamic_type_definition->key_field => "DESC", "id" => "ASC")) + ->count_all(); + + // We stopped short of our target value in the sort (notice that we're + // using a inequality comparator above) because it's possible that we have + // duplicate values in the sort column. An equality check would just + // arbitrarily pick one of those multiple possible equivalent columns, + // which would mean that if you choose a sort order that has duplicates, + // it'd pick any one of them as the child's "position". + // + // Fix this by doing a 2nd query where we iterate over the equivalent + // columns and add them to our position count. + foreach ($query_model->viewable() + ->select("id") + ->where($sort_column, "=", $item->$sort_column) + ->where("type", "!=", "album") + ->order_by(array("id" => "ASC")) + ->find_all($display_limit) as $row) { + $position++; + if ($row->id == $item->id) { + break; + } + } + } else { + // There are NULLs in the sort column, so we can't use MySQL comparators. + // Fall back to iterating over every child row to get to the current one. + // This can be wildly inefficient for really large albums, but it should + // be a rare case that the user is sorting an album with null values in + // the sort column. + // + // Reproduce the children() functionality here using Database directly to + // avoid loading the whole ORM for each row. + $order_by = array($sort_column => "DESC", $order_by["id"] => "ASC"); + + $position = 0; + foreach ($query_model->viewable() + ->select("id") + ->where("parent_id", "=", $album->id) + ->where("type", "!=", "album") + ->order_by($order_by) + ->find_all($display_limit) as $row) { + $position++; + if ($row->id == $item->id) { + break; + } + } + } + + return $position; + } +} diff --git a/3.0/modules/dynamic/libraries/Dynamic_Display_Context.php b/3.0/modules/dynamic/libraries/Dynamic_Display_Context.php new file mode 100644 index 00000000..97381272 --- /dev/null +++ b/3.0/modules/dynamic/libraries/Dynamic_Display_Context.php @@ -0,0 +1,56 @@ +get("dynamic_type"); + + $position = dynamic::get_position($dynamic_type_definition, $item); + if ($position > 1) { + list ($previous_item, $ignore, $next_item) = dynamic::items($dynamic_type_definition->key_field, 3, $position - 2); + } else { + $previous_item = null; + list ($next_item) = dynamic::items($dynamic_type_definition->key_field, 1, $position); + } + + $root = item::root(); + return array("position" =>$position, + "previous_item" => $previous_item, + "next_item" =>$next_item, + "sibling_count" => dynamic::get_display_count($dynamic_type_definition), + "breadcrumbs" => array( + Breadcrumb::instance($root->title, $root->url())->set_first(), + Breadcrumb::instance($dynamic_type_definition->title, $this->_url("show={$item->id}")), + Breadcrumb::instance($item->title, $item->url())->set_last())); + } + + private function _url($query=null) { + $albumPath = $this->get("path"); + $url = url::site("dynamic/$albumPath"); + if ($query) { + $url .= "?$query"; + } + return $url; + } +}