Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

DataObjectManager Module /

Discuss the DataObjectManager module, and the related ImageGallery module.

Moderators: martimiz, UncleCheese, Sean, biapar, Willr, Ingo, swaiba, simon_w

showing images with unique captions


Reply


7 Posts   1182 Views

Avatar
tonito

Community Member, 24 Posts

20 August 2010 at 5:09pm

Edited: 22/08/2010 10:54am

Is there such thing as a "unique" element function already established in SilverStripe or in ImageGallery or DataObjectManager?

I am trying to do the following: I have an album associated to a page. If images have the same caption, I would like to show the first one and hide the subsequent ones.

Something like:
<% control GalleryItems %>
<% if Caption.AlreadyDisplayed %>
<a href="" style="display: none"><img src="" /></a>
<% else %>
<a href=""><img src="" /></a>
<% end_if %>
<% end_control %>

I am a complete starter with php or jQuery, if someone has a hint, I would gladly take it.

Avatar
UncleCheese

Forum Moderator, 4096 Posts

21 August 2010 at 1:51am

Edited: 21/08/2010 1:52am

You're going to have to handle that in your controller.. I assume this is the ImageGallery module?

Create a subclass called MyImageGalleryPage (or whatever you want)

and overload the GalleryItems() function.

public function GalleryItems() {
$items = parent::GalleryItems();
$used_captions = array();
foreach($items as $i) {
if(in_array($i->Caption, $used_captions)) {
$i->destroy();
}
else {
$used_captions[] = $i->Caption;
}
}
return $items;
}

Something like that should work.

Avatar
tonito

Community Member, 24 Posts

22 August 2010 at 10:52am

Edited: 22/08/2010 10:54am

Wooaw, thank you. It would have taken me weeks to figure something like that. Yes this is with the Image Gallery Module.
Thank you for your help and your fantastic modules.

I created a PressImageGalleryPage.php in image_gallery/code

<?php

class PressImageGalleryPage extends ImageGalleryPage {

   public function GalleryItemsUnique() {
   $items = parent::GalleryItems();
   $used_captions = array();
   foreach($items as $i) {
   if(in_array($i->Caption, $used_captions)) {
   $i->destroy();
   }
   else {
   $used_captions[] = $i->Caption;
   }
   }
   return $items;
   }

}

?>

Changed the page type of my page to Press Image Gallery Page, but I get the following error:

[User Error] Uncaught Exception: Object->__call(): the method 'handlerequest' does not exist on 'PressImageGalleryPage'
GET /mywebsite/info/press?flush=1

Line 724 in /Users/MyComputer/Sites/mywebsite/sapphire/core/Object.php
Source

715             
716             default :
717                throw new Exception (
718                   "Object->__call(): extra method $method is invalid on $this->class:" . var_export($config, true)
719                );
720          }
721       } else {
722          // Please do not change the exception code number below.
723          
724          throw new Exception("Object->__call(): the method '$method' does not exist on '$this->class'", 2175);
725       }
726    }
727    
728    // -----------------------------------------------------------------------------------------------------------------
729    
730    /**

Trace

* Object->__call(handleRequest,Array)
* PressImageGalleryPage->handleRequest(SS_HTTPRequest)
Line 184 of ContentController.php
* ContentController->handleRequest(SS_HTTPRequest)
Line 67 of ModelAsController.php
* ModelAsController->handleRequest(SS_HTTPRequest)
Line 283 of Director.php
* Director::handleRequest(SS_HTTPRequest,Session)
Line 127 of Director.php
* Director::direct(/info/press)
Line 127 of main.php

NOTE:
The code your offered seems like it will not return (destroy) the GalleryItem that has a same caption as another GalleryItem. If possible I do need to have all GalleryItem displayed in the page, but the ones with a hidden.

Each elements of the gallery with same captions will be added consecutively by the user, hence I would just need some kind of controller that checks if the previous gallery item has the same caption as the current one and returns true or false.

Avatar
UncleCheese

Forum Moderator, 4096 Posts

22 August 2010 at 12:18pm

Did you create a controller for it, as well?

PressImageGalleryPage_Controller extends ImageGalleryPage_Controller??

Avatar
tonito

Community Member, 24 Posts

22 August 2010 at 4:18pm

Edited: 22/08/2010 4:27pm

UncleCheese,

I still have a way to go to build with silverstripe. Thank you for your help.

This is how my PressImageGalleryPage.php looks like now:

<?php

class PressImageGalleryPage extends ImageGalleryPage {
   
   public function GalleryItems() {
   $items = parent::GalleryItems();
   $used_captions = array();
   foreach($items as $i) {
   if(in_array($i->Caption, $used_captions)) {
   $i->destroy();
   }
   else {
   $used_captions[] = $i->Caption;
   }
   }
   return $items;
   }
}

class PressImageGalleryPage_Controller extends ImageGalleryPage_Controller {      
}

?>

My Press Image Gallery Page doesn't throw errors anymore, however, the <% control GalleryItems %> doesn't return anything (empty). I created a PressImageGalleryPage.ss in image_gallery/templates/Layout with just hello to test, and the page is not parsed and "hello" does not appear.

Alternatively, I seem to have found a solution with jQuery -- in a mere 6 hours of trial and error :(.

Here my markup (in GalleryUI_layout.ss):

<div class="gallery-layout-wrapper">   
   <% if GalleryItems %>
   <ul class="gallery-layout" id="gallery-list">
      <% control GalleryItems %>
         <li style="list-style: none;" name="$Caption.EscapeXML">$GalleryItem</li>
      <% end_control %>
   </ul>
   
   <script>
    $(document).ready(function() {
    $('ul#gallery-list').find('li').each(function(i) {
      var t = $(this).attr("name");
      if (($('ul#gallery-list').find("li[name="+t+"]").length) > 1) {
         if (t!="") {
            $('ul#gallery-list').find("li[name="+t+"]").nextUntil("li[name!="+t+"]").css("display", "none");
            }
         }
    });   
    });
   </script>
   <% end_if %>
</div>

The little jQuery script looks for li elements with specific captions and hides the li elements with following identical captions. Maybe this little code can help someone.

The idea is to show in the gallery only the first element of an Image Gallery with a given caption, and to hide the other images with the same caption. In the case of a press page, the gallery shows the magazine cover, and hides the subsequent inside pages of the magazine. Once clicked on the cover magazine image, Lightroom or FancyBox (etc) shows the cover image and the inside pages of the magazine in a sequence.

Avatar
UncleCheese

Forum Moderator, 4096 Posts

22 August 2010 at 4:50pm

You shouldn't be modifying anything in the core image_gallery directory. Silverstripe allows you to override templates and CSS in your theme dir. You new template belongs there, not in image_gallery. That directory should never change.. otherwise, upgrades would be a pain.

Anytime you create new templates, make sure you're running a flush=1. Otherwise, they don't get loaded into the manifest.

What happens when you comment out the $i->destroy(); line?

Avatar
tonito

Community Member, 24 Posts

23 August 2010 at 11:30am

Edited: 24/08/2010 4:35pm

Arrrgh, it makes sense. I will never modify modules ruthlessly the way I used to. Customizing them is so simple, I didn't realize. Once more, thank you.

Once again, I consider the problem solved, with the jQuery script I made. I am curious to troubleshoot your solution though at your leisure.

The initial non-rendering problem was because I didn't have a MyImageGalleryPage_album.ss in my Includes in my theme folder. Once I did, the page rendered with custom code, that's with the $i->destroy(); commented. Once I un-comment the $i->destroy(); line, I get new errors:

array_key_exists() [function.array-key-exists]: The second argument should be either an array or an object
GET /mywebsite/info/press?flush=1

Line 2156 in /Users/someuser/Sites/mywebsite/sapphire/core/model/DataObject.php
Source

2147     * Returns true if the given field exists
2148     * in a database column on any of the objects tables,
2149     * or as a dynamic getter with get<fieldName>().
2150     *
2151     * @param string $field Name of the field
2152     * @return boolean True if the given field exists
2153     */
2154    public function hasField($field) {
2155       return (
2156          array_key_exists($field, $this->record)
2157          || $this->db($field)
2158          || $this->hasMethod("get{$field}")
2159       );
2160    }
2161
2162    /**

Trace

* array_key_exists(Caption,)
Line 2156 of DataObject.php
* DataObject->hasField(Caption)
Line 113 of ViewableData.php
* ViewableData->__get(Caption)
Line 371 of ViewableData.php
* ViewableData->obj(Caption,,1)
Line 42 of .cache.Users.someuser.Sites.mywebsite.themes.mywebsite.templates.image_gallery.templates.Includes.GalleryUI_layout.ss
* include(/Users/someuser/Sites/shopshabd/silverstripe-cache/.cache.Users.someuser.Sites.mywebsite.themes.mywebsite.templates.image_gallery.templates.Includes.GalleryUI_layout.ss)
Line 392 of SSViewer.php

.....