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.

We've moved the forum!

Please use forum.silverstripe.org for any new questions (announcement).
The forum archive will stick around, but will be read only.

You can also use our Slack channel or StackOverflow to ask for help.
Check out our community overview for more options to contribute.

Form Questions /

Moderators: martimiz, Sean, Ed, biapar, Willr, Ingo, swaiba

Problem with search and scaffolded searchform


Go to End


9 Posts   4933 Views

Avatar
Euphemismus

Community Member, 82 Posts

2 April 2010 at 6:42am

Hi,
I'm currently working with a scaffolded searchform and need to modify the generated query (ss 2.4b2).
The basic situation is:
I've got a list of entries with an expiry date - initially I show all entries with expiry dates larger or equal then today ( "( ExpiryDate >= DATE( NOW() ) )" ). But when searching, the query is built from the defined search fields/filters. Concerning those, an equal or greater than filter is missing ;-)
My problem is: How can I tell the query to add another filter like "ExpiryDarte" >= DATE( NOW() ) or something similar or even alter the query manually?

Regards,
Marc

Avatar
Double-A-Ron

Community Member, 607 Posts

6 April 2010 at 5:06pm

Hi mate.

I did something similar to this for removing searches through PDF's and Word docs in the Assets directory. It's more removing results matching certain criteria rather than ignoring them during the search. Probably not the most effient way, but it works. Where is my results code. Check out the foreach loop.

public function results($data, $form)
  {
    
    $results = $form->getResults();
  
    foreach($results AS $result) {
      if($result->ClassName == "File") $results->remove($result);
    }      
    
    $data = array(
      'Results' => $form->getResults(),
      'Query' => $form->getSearchQuery(),
      'Title' => 'Search Results'
    );
    
    return $this->customise($data)->renderWith(array('ContentPage', 'Page')); 
  }

So you could theoritically run a comparison on any field and remove it from the results. E.G.

 if($result->LastEdited == "2010/03/06 12:00:00") $results->remove($result);

I haven't tried this, and not sure about custom page types with custom fields. The query runs on the SiteTree_Live table as far as I know, so you may only have access to those fields.

The only other thing I can think of is creating a custom object us DataObject::get() and making sure your result array ($data in the above code) is in the same format/structure. Definately do-able. That way you can bypass the default methods and customize the query as much as you like.

Aaron

Avatar
Euphemismus

Community Member, 82 Posts

6 April 2010 at 7:04pm

Hi Aaron,

thank you! I've tried a lot of things and found another way around ;-)
In my special case with the ExpiryDate it was possible to have a GreaterThanFilter on a hidden "ExpiryDate" field and after creating the scaffolded search form I did this:

// workaround for presetted searchfields
$expiryDateYesterday = date( "d.m.Y", mktime( 0, 0, 0, date( "m" ), date( "d" )-1, date( "Y" ) ) );
$objExpiryDate = new HiddenField( 'ExpiryDate', 'ExpiryDate', $expiryDateYesterday );
$fields->replaceField( 'ExpiryDate', $objExpiryDate );

I think this is a bite more efficient than removing results from an already generated resultset.

Regards,
Marc

Avatar
Double-A-Ron

Community Member, 607 Posts

6 April 2010 at 7:09pm

That looks like a cool solution Marc.

So did you put that in your form generator? What did you need to change on your results() method?

Aaron

Avatar
Euphemismus

Community Member, 82 Posts

7 April 2010 at 1:55am

Edited: 07/04/2010 1:58am

Hi Aaron,

thanks :-)
I didn't have to modify the results() method. The only thing I did was:

        public function getCustomSearchContext()
        {
                $fields = $this->scaffoldSearchFields( array(
                                                'restrictFields' => array(
                                                                'Title',
                                                                'Content',
                                                                'Instrument',
                                                                'Plz',
                                                                'Location',
                                                                'Ambition',
                                                                'ExpiryDate',
                                                                'EntryCategoryID',
                                                        ),
                                                'fieldClasses' => array(
                                                                'ExpiryDate' => 'HiddenField',
                                                        )
                                        )
                                );

                $filters = array(
                                        'Title'                       => new PartialMatchFilter( 'Title' ),
                                        'Content'                 => new PartialMatchFilter( 'Content' ),
                                        'Instrument'            => new ExactMatchFilter( 'Instrument' ),
                                        'Plz'                         => new PartialMatchFilter( 'Plz' ),
                                        'Location'                => new ExactMatchFilter( 'Location' ),
                                        'Ambition'                => new ExactMatchFilter( 'Ambition' ),
                                        'ExpiryDate'            => new GreaterThanFilter( 'ExpiryDate' ),
                                        'EntryCategoryID'   => new ExactMatchFilter( 'EntryCategoryID' ),
                                );

                $expiryDateYesterday = date( "d.m.Y", mktime( 0, 0, 0, date( "m" ), date( "d" )-1, date( "Y" ) ) );
                $objExpiryDate = new HiddenField( 'ExpiryDate', 'ExpiryDate', $expiryDateYesterday );
                $fields->replaceField( 'ExpiryDate', $objExpiryDate );

                return new SearchContext(
                                        $this->class,
                                        $fields,
                                        $filters
                                );
        }

Initially on the controller I do:

        public function ActiveEntries()
        {
                return $this->Entries(
                        "( ExpiryDate >= DATE( NOW() ) )"
                );
        }

This gives me a reduced resultset initially. Since the searchContext doesn't work like this, I had to do it ugly with the hidden field within the model where the CustomSearchContext is defined :-(

Edit: It woud be really nice to have some more possibilities like presetting values in a i.e. fieldsPreset = array( 'fieldname' => 'value' ) or something like that. Also the the filters are lacking >= and <=
Plus there needs to be a possibility to restrict the resultset otherwise, too. Like with an addition WHERE statement.
This might be a nice candidate for a changerequest ;-)

Avatar
javelin

Community Member, 12 Posts

16 April 2010 at 5:48am

Thank you Aaron and Marc! This solved two problems for me at once. I needed to restrict searches on a specific page to only dataobjects related to that page (has_many) and at the same time offer the possibility of equal-to-or-greater-than date-search.

Both your approaches solved this for me at once:

This was my code for filtering only related dataobjects:

$context = singleton('Apartment')->getDefaultSearchContext();
$results = $context->getResults($data);
//Filter out any apartments not related to this page.
foreach($results AS $result) { 
	if($result->ApartmentListID != $this->ID) $results->remove($result); 
}
		
return $this->customise(array('Results' => $results))->renderWith('ApartmentList_results');

Thank you again!

Avatar
Euphemismus

Community Member, 82 Posts

16 April 2010 at 9:02am

Hi :-)
Yo could also do the filtering while searching if you modify the searchform like with the ID field.
-> push a new hidden field into the searchform and do a ExactMatchFilter on the ID.
This will significantly reduce your costs when searching large heaps of data.
The solution with iterating the whole resultset and removing entries could get slow.

Regards,
Marc

Avatar
Double-A-Ron

Community Member, 607 Posts

16 April 2010 at 10:09am

I agree with Marc, his method is alot more efficient in the long term, especially if you end up adding alot of Pages to your site. The method I posted (and you used) will pull even objects you don't need, then remove them.

Makes sense to ignore those redundant records right from the start.

Aaron

Go to Top