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.

General Questions /

General questions about getting started with SilverStripe that don't fit in any of the categories above.

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

Help with DOM/many_many and Search


Go to End


2 Posts   2599 Views

Avatar
AlaVive

Community Member, 42 Posts

6 November 2009 at 9:46am

Edited: 07/11/2009 11:57am

I have to be able to display a list of PDF "resource" files using DOM that lists the following attributes:

Name
Description
Keywords
Language
Date of upload/modification
Brand
Category
Document Type

In the end, I need to be able to search the documents using the following search criteria:

Keywords (should search "keywords," "Description," "Date," Category" and "Keywords" fields)
Language
Brand
Category
Document Type

I've managed to make this work (to some extent-- still didn't figure out how to merge the attributes to be searched by the Keywords field) using the following-- implementing ComplexSearch:

In Resource.php (I must warn you, I'm green at this!)

<?php

class Resource extends DataObject
{
	static $db = array (
		'Name' => 'Text',
		'Type' => "Enum('Management Guides, Performance Goals, Technical Articles, Nutrition Guides')",
		'Description' => 'Text',
		'Category' => "Enum('Corporate, Chicken, Turkey')",
		'Brand' => "Text",
		'Language' => "Enum('English–USA, English–EUR, Arabic, Balkan, Bulgarian, Chinese, Czech, French, Hungarian, Portuguese, Russian, Romanian, Spanish')",
		"Keywords" => "Text",
		'Date' => 'Date'
		
	);
	
	static $has_one = array (
		'Attachment' => 'File',
		'ResourcePage' => 'ResourcePage'
	);
	
	static $searchable_fields = array(
	'Keywords' => 'PartialMatchFilter',
	'Type' => 'PartialMatchFilter',
	'Language' => 'PartialMatchFilter',
	'Brand' => 'PartialMatchFilter'
	
	);
	
	public function getCMSFields_forPopup()
	{
		return new FieldSet(
			new TextField('Name'),
			new DropdownField('Type','Document Type', singleton('Resource')->dbObject('Type')->enumValues()),
			new TextareaField('Description'),
			new DropdownField('Category','Category', singleton('Resource')->dbObject('Category')->enumValues()),
			new TextField('Brand'),
			new DropdownField('Language','Language', singleton('Resource')->dbObject('Language')->enumValues()),
			new CalendarDateField('Date'),
			new TextAreaField('Keywords'),
			new FileIFrameField('Attachment')
		);
	}
	public function getCustomSearchContext() {
		$fields = $this->scaffoldSearchFields(array('Keywords','Name','Type','Category','Brand','Language')
		);
		$filters = array(
			'Keywords' => new PartialMatchFilter('Keywords'),
			'Name' => new PartialMatchFilter('Name'),
			'Type' => new PartialMatchFilter('Type'),
			'Category' => new PartialMatchFilter('Category'),
			'Brand' => new PartialMatchFilter('Brand'),
			'Language' => new PartialMatchFilter('Language'),
			
		);
		return new SearchContext(
			$this->class, 
			$fields, 
			$filters
		);
	}
}
?>

In my ResourcePage.php

<?php 
class ResourcePage extends Page 
{ 
   static $has_many = array ( 
      'Resources' => 'Resource' 
   ); 
    
   public function getCMSFields() 
   { 
      $f = parent::getCMSFields(); 
	  $f->removeByName("Row 2 Content");	
      $manager = new FileDataObjectManager( 
         $this, // Controller 
         'Resources', // Source name 
         'Resource', // Source class 
         'Attachment', // File name on DataObject 
         array( 
            'Name' => 'Name', 
            'Description' => 'Description', 
            'Category' => 'Category', 
			'Brand' => 'Brand',
			'Language' => 'Language',
			'Date' => 'Date'
         ), // Headings 
         'getCMSFields_forPopup' // Detail fields (function name or FieldSet object) 
         // Filter clause 
         // Sort clause 
         // Join clause 
      ); 
       
      $manager->setFilter( 
         'Category', // Name of field to filter 
         'Filter by Category', // Label for filter 
         singleton('Resource')->dbObject('Category')->enumValues() // Map for filter (could be $dataObject->toDropdownMap(), e.g.) 
      ); 
       
      // If undefined, all types are allowed. Pass with or without a leading "."       
      $manager->setAllowedFileTypes(array('pdf')); 
       
      // Label for the upload button in the popup 
      $manager->setBrowseButtonText("Upload (PDF files only)"); 
       
      // In grid view, what field will appear underneath the icon. If left out, it defaults to the file title. 
      $manager->setGridLabelField('Name'); 
       
      // Plural form of the objects being managed. Used on the "Add" button. 
      // If left out, this defaults to [MyObjectName]s 
      $manager->setPluralTitle('Resources'); 
             
      $f->addFieldToTab("Root.Content.Resources", $manager);

      return $f; 
   } 
    
   function MyFileObjects() 
   { 
      $filter = Director::urlParam('Action'); 
      return $filter ? $this->Resources("Category = '$filter'") : $this->Resources();
   }

}

class ResourcePage_Controller extends Page_Controller 
{
function FilteredResources() 
{ 
$filter = Director::urlParam('Action'); 
return $filter ? $this->Resources("Category = '$filter'") : $this->Resources(); 
} 
} 
?>

In my page.php

/**
	 * Tech Documents Search
	 */
   public function TechSearchForm() {
		$context = singleton('Resource')->getCustomSearchContext();
		$fields = $context->getSearchFields();
		$form = new Form($this, "TechSearchForm",
			$fields,
			new FieldSet(
				new FormAction('doSearch')
			)
		);
		return $form;
	}
	/**
	 * Process and render Tech Documents search results
	 */
	public function doSearch($data, $form) {
	$context = singleton('Resource')->getCustomSearchContext();
	$results = $this->getResults($data);
	return $this->customise(array(
		'Results' => $results
	))->renderWith(array('ResourceSearch_results', 'Page'));
}

The problem is that the Brand, Category, and Document Type attributes need to be changed to a many_many relationship, so that multiple brand names, multiple category names, and multiple Document Types can be added to each PDF.

Furthermore, when I run a search, the search has to appear differetly on three different levels of the site:
On the corporate level, all files should be searched.
On the division level, only files related to that division and its related brands should be searched.
On the Brand pages, only files relevant to the brand should be searched.

I believe I can create three different search functions if I can just figure out the many_many relationship issue and the initial search. But, I am struggling and am on a deadline.

Can ANYONE help me?
(Thanks in advance to anyone willing to TRY!)

Avatar
javelin

Community Member, 12 Posts

16 April 2010 at 5:06am

I have the exact same problem, but without DOM mixed in. I guess the only viable way is to filter the results after the search has been performed because I can't find any support for limiting the search-context to any less than a full class.

I found another forum post with a different problem that might give us some clues (post number 2):
http://www.silverstripe.org/form-questions/show/282088?start=0

I'll be working from that from now on.

Now if you've found a solution?