public function getCMSFields() { $fields = parent::getCMSFields(); $cssFiles = new UploadField('CustomCSSFiles', _t('UserTemplatesExtension.CustomCSSFiles', "Custom CSS Files")); $jsFiles = new UploadField('CustomJSFiles', _t('UserTemplatesExtension.CustomJSFiles', "Custom JS Files")); $cssFiles->setFolderName(self::$css_folder); $jsFiles->setFolderName(self::$js_folder); $fields->removeByName('CustomCSSFiles'); $fields->removeByName('CustomJSFiles'); $templates = $this->fileBasedTemplates(); if (count($templates)) { $fields->addFieldToTab('Root.Main', $dd = new DropdownField('ContentFile', _t('UserTemplatesExtension.CONTENT_FILE', 'File containing template'), $templates)); $dd->setRightTitle('If selected, any Content set above will be ignored'); } else { $fields->removeByName('ContentFile'); } $fields->push($strict = CheckboxField::create('StrictActions', _t('UserTemplates.STRICT_ACTIONS', 'Require actions to be explicitly overridden'))); $text = <<<DOC When applied to a page type that has sub-actions, an action template will be used ONLY if the action is listed below, and this main \t template will only be used for the 'index' action. If this is not checked, then this template will be used for ALL actions \t in the page it is applied to. DOC; $strict->setRightTitle(_t('UserTemplates.STRICT_HELP', $text)); $templates = DataList::create('UserTemplate')->filter(array('ID:not' => $this->ID)); if ($templates->count()) { $templates = $templates->map(); $fields->addFieldToTab('Root.Main', $kv = new KeyValueField('ActionTemplates', _t('UserTemplates.ACTION_TEMPLATES', 'Action specific templates'), array(), $templates)); $kv->setRightTitle(_t('UserTemplates.ACTION_TEMPLATES_HELP', 'Specify an action name and select another user defined template to handle a specific action. Only used for Layout templates')); } $fields->addFieldToTab('Root.Main', $cssFiles); $fields->addFieldToTab('Root.Main', $jsFiles); return $fields; }
public function getCMSFields() { $fields = parent::getCMSFields(); Requirements::css(EXTENSIBLE_SEARCH_PATH . '/css/extensible-search.css'); // Restrict the search suggestion approval appropriately. $user = Member::currentUserID(); if (Permission::checkMember($user, 'EXTENSIBLE_SEARCH_SUGGESTIONS')) { Requirements::javascript(EXTENSIBLE_SEARCH_PATH . '/javascript/extensible-search-approval.js'); } // Determine if full text search is enabled. $engines = array('' => ''); $searchable = Config::inst()->get('FulltextSearchable', 'searchable_classes'); if (is_array($searchable) && count($searchable) > 0) { $engines['Full-Text'] = 'Full-Text'; } // Retrieve a list of search engine extensions currently applied that end with 'Search'. $extensions = $this->get_extensions(get_class()); foreach ($extensions as $extension) { $reversed = strrev($extension); if (strpos($reversed, strrev('Search')) === 0) { $engine = strrev(substr($reversed, 6)); $engines[$engine] = $engine; } } // Allow selection of the search engine extension to use. $fields->addFieldToTab('Root.Main', new DropdownField('SearchEngine', 'Search Engine', $engines), 'Content'); // Make sure a search engine is being used before allowing customisation. if ($this->SearchEngine) { // Construct the support array to determine the CMS customisation available to the current search engine/wrapper. $support = self::$support; if ($this->SearchEngine !== 'Full-Text' && $this->extension_instances) { $engine = "{$this->SearchEngine}Search"; foreach ($this->extension_instances as $instance) { if (get_class($instance) === $engine) { $instance->setOwner($this); if (isset($instance::$support)) { $support = array_merge($support, $instance::$support); } $instance->clearOwner(); break; } } } // Use the support array to determine the CMS customisation available to the current search engine/wrapper. if ($support['StartWithListing']) { $fields->addFieldToTab('Root.Main', new CheckboxField('StartWithListing', _t('ExtensibleSearchPage.START_LISTING', 'Display initial listing - useful for filterable "data type" lists')), 'Content'); } if (class_exists('ListingTemplate') && $support['ListingTemplateID']) { $templates = DataObject::get('ListingTemplate'); if ($templates) { $templates = $templates->map(); } else { $templates = array(); } $label = _t('ExtensibleSearchPage.CONTENT_TEMPLATE', 'Listing Template - if not set, theme template will be used'); $fields->addFieldToTab('Root.Main', $template = DropdownField::create('ListingTemplateID', $label, $templates, '', null)->setEmptyString('(results template)'), 'Content'); $template->setEmptyString('(results template)'); } if ($support['ResultsPerPage']) { $perPage = array('5' => '5', '10' => '10', '15' => '15', '20' => '20'); $fields->addFieldToTab('Root.Main', new DropdownField('ResultsPerPage', _t('ExtensibleSearchPage.RESULTS_PER_PAGE', 'Results per page'), $perPage), 'Content'); } if ($support['SearchTrees']) { $fields->addFieldToTab('Root.Main', new TreeMultiselectField('SearchTrees', 'Restrict results to these subtrees', 'Page'), 'Content'); } if (!$this->SortBy) { $this->SortBy = 'Created'; } $objFields = $this->getSelectableFields(); if ($support['SortBy']) { $sortFields = $objFields; // Remove content and groups from being sortable (as they are not relevant). unset($sortFields['Content']); unset($sortFields['Groups']); $fields->addFieldToTab('Root.Main', new DropdownField('SortBy', _t('ExtensibleSearchPage.SORT_BY', 'Sort By'), $sortFields), 'Content'); } if ($support['SortDir']) { $fields->addFieldToTab('Root.Main', new DropdownField('SortDir', _t('ExtensibleSearchPage.SORT_DIR', 'Sort Direction'), $this->dbObject('SortDir')->enumValues()), 'Content'); } $types = SiteTree::page_type_classes(); $source = array_combine($types, $types); if ($this->SearchEngine !== 'Full-Text' && $this->extension_instances) { $engine = "{$this->SearchEngine}Search"; foreach ($this->extension_instances as $instance) { if (get_class($instance) === $engine) { $instance->setOwner($this); // Trigger the following methods on the current search engine extension. if (method_exists($instance, 'updateSource')) { // add in any explicitly configured asort($source); $instance->updateSource($source); } if (method_exists($instance, 'getQueryBuilders') && $support['QueryType']) { $parsers = $instance->getQueryBuilders(); $options = array(); foreach ($parsers as $key => $objCls) { $obj = new $objCls(); $options[$key] = $obj->title; } $fields->addFieldToTab('Root.Main', new DropdownField('QueryType', _t('ExtensibleSearchPage.QUERY_TYPE', 'Query Type'), $options), 'Content'); } $instance->clearOwner(); break; } } } if ($support['SearchType']) { ksort($source); $source = array_merge($source, self::$additional_search_types); $types = new MultiValueDropdownField('SearchType', _t('ExtensibleSearchPage.SEARCH_ITEM_TYPE', 'Search items of type'), $source); $fields->addFieldToTab('Root.Main', $types, 'Content'); } if ($support['SearchOnFields']) { $fields->addFieldToTab('Root.Main', new MultiValueDropdownField('SearchOnFields', _t('ExtensibleSearchPage.INCLUDE_FIELDS', 'Search On Fields'), $objFields), 'Content'); } $boostVals = array(); for ($i = 1; $i <= 5; $i++) { $boostVals[$i] = $i; } if ($support['BoostFields']) { $fields->addFieldToTab('Root.Main', new KeyValueField('BoostFields', _t('ExtensibleSearchPage.BOOST_FIELDS', 'Boost values'), $objFields, $boostVals), 'Content'); } if ($support['BoostMatchFields']) { $fields->addFieldToTab('Root.Main', $f = new KeyValueField('BoostMatchFields', _t('ExtensibleSearchPage.BOOST_MATCH_FIELDS', 'Boost fields with field/value matches'), array(), $boostVals), 'Content'); $f->setRightTitle('Enter a field name, followed by the value to boost if found in the result set, eg "title:Home" '); } if ($support['FilterFields']) { $fields->addFieldToTab('Root.Main', $kv = new KeyValueField('FilterFields', _t('ExtensibleSearchPage.FILTER_FIELDS', 'Fields to filter by')), 'Content'); } if ($this->SearchEngine !== 'Full-Text') { $fields->addFieldToTab('Root.Main', new HeaderField('FacetHeader', _t('ExtensibleSearchPage.FACET_HEADER', 'Facet Settings')), 'Content'); } if ($support['FacetFields']) { $fields->addFieldToTab('Root.Main', new MultiValueDropdownField('FacetFields', _t('ExtensibleSearchPage.FACET_FIELDS', 'Fields to create facets for'), $objFields), 'Content'); } if ($support['CustomFacetFields']) { $fields->addFieldToTab('Root.Main', new MultiValueTextField('CustomFacetFields', _t('ExtensibleSearchPage.CUSTOM_FACET_FIELDS', 'Additional fields to create facets for')), 'Content'); } if ($support['FacetMapping']) { $facetMappingFields = $objFields; if ($this->CustomFacetFields && ($cff = $this->CustomFacetFields->getValues())) { foreach ($cff as $facetField) { $facetMappingFields[$facetField] = $facetField; } } $fields->addFieldToTab('Root.Main', new KeyValueField('FacetMapping', _t('ExtensibleSearchPage.FACET_MAPPING', 'Mapping of facet title to nice title'), $facetMappingFields), 'Content'); } if ($support['FacetQueries']) { $fields->addFieldToTab('Root.Main', new KeyValueField('FacetQueries', _t('ExtensibleSearchPage.FACET_QUERIES', 'Fields to create query facets for')), 'Content'); } if ($support['MinFacetCount']) { $fields->addFieldToTab('Root.Main', new NumericField('MinFacetCount', _t('ExtensibleSearchPage.MIN_FACET_COUNT', 'Minimum facet count for inclusion in facet results'), 2), 'Content'); } $this->extend('updateExtensibleSearchPageCMSFields', $fields); } else { $fields->addFieldToTab('Root.Main', LiteralField::create('SearchEngineNotification', "<p class='extensible-search notification'><strong>Select a Search Engine</strong></p>"), 'Title'); } // Retrieve the extensible search analytics, when enabled. if (Config::inst()->get('ExtensibleSearch', 'enable_analytics')) { // Retrieve the search analytics. $history = $this->History(); $query = new SQLQuery("Term, COUNT(*) AS Frequency, ((COUNT(*) * 100.00) / {$history->count()}) AS FrequencyPercentage, AVG(Time) AS AverageTimeTaken, (Results > 0) AS Results", 'ExtensibleSearch', "ExtensibleSearchPageID = {$this->ID}", array('Frequency' => 'DESC', 'Term' => 'ASC'), 'Term'); $analytics = ArrayList::create(); foreach ($query->execute() as $result) { $result = ArrayData::create($result); $result->FrequencyPercentage = sprintf('%.2f %%', $result->FrequencyPercentage); $result->AverageTimeTaken = sprintf('%.5f', $result->AverageTimeTaken); $result->Results = $result->Results ? 'true' : 'false'; $analytics->push($result); } // Instantiate the search analytic summary display. $fields->addFieldToTab('Root.SearchAnalytics', $summary = GridField::create('Summary', 'Summary', $analytics)->setModelClass('ExtensibleSearch')); $summaryConfiguration = $summary->getConfig(); $summaryConfiguration->removeComponentsByType('GridFieldFilterHeader'); $summaryConfiguration->addComponent($summaryExport = new GridFieldExportButton()); $summaryConfiguration->getComponentByType('GridFieldSortableHeader')->setFieldSorting(array('FrequencyPercentage' => 'Frequency')); // Update the export fields, since we're not using a data list. $summaryDisplay = array('Term' => 'Search Term', 'Frequency' => 'Frequency', 'FrequencyPercentage' => 'Frequency %', 'AverageTimeTaken' => 'Average Time Taken (s)', 'Results' => 'Has Results?'); $summaryExport->setExportColumns($summaryDisplay); // Update the summary fields. $summaryConfiguration->getComponentByType('GridFieldDataColumns')->setDisplayFields($summaryDisplay); // Instantiate the search analytic history display. $fields->addFieldToTab('Root.SearchAnalytics', $history = GridField::create('History', 'History', $history)->setModelClass('ExtensibleSearch')); $historyConfiguration = $history->getConfig(); $historyConfiguration->removeComponentsByType('GridFieldFilterHeader'); $historyConfiguration->addComponent($historyExport = new GridFieldExportButton()); // Update the custom summary fields to be sortable. $historyConfiguration->getComponentByType('GridFieldSortableHeader')->setFieldSorting(array('TimeSummary' => 'Created', 'TimeTakenSummary' => 'Time')); } // Retrieve the extensible search suggestions, when enabled. if (Config::inst()->get('ExtensibleSearchSuggestion', 'enable_suggestions')) { // Instantiate the search suggestion display. $fields->addFieldToTab('Root.SearchSuggestions', GridField::create('Suggestions', 'Suggestions', $this->Suggestions(), $suggestionsConfiguration = GridFieldConfig_RecordEditor::create())->setModelClass('ExtensibleSearchSuggestion')); $suggestionsConfiguration->removeComponentsByType('GridFieldFilterHeader'); // Update the custom summary fields to be sortable. $suggestionsConfiguration->getComponentByType('GridFieldSortableHeader')->setFieldSorting(array('FrequencySummary' => 'Frequency', 'FrequencyPercentage' => 'Frequency', 'ApprovedField' => 'Approved')); } return $fields; }
public function updateExtensibleSearchPageCMSFields(FieldList $fields) { if ($this->owner->SearchEngine === get_class($this)) { $types = SiteTree::page_type_classes(); $source = array_combine($types, $types); // add in any explicitly configured asort($source); $source = $this->owner->updateSource($source); $parsers = $this->owner->getQueryBuilders(); $options = array(); foreach ($parsers as $key => $objCls) { $obj = new $objCls(); $options[$key] = $obj->title; } $fields->addFieldToTab('Root.Main', new DropdownField('QueryType', _t('ExtensibleSearchPage.QUERY_TYPE', 'Query Type'), $options), 'Content'); ksort($source); $source = array_merge($source, ExtensibleSearchPage::config()->additional_search_types); $types = MultiValueDropdownField::create('SearchType', _t('ExtensibleSearchPage.SEARCH_ITEM_TYPE', 'Search items of type'), $source); $fields->addFieldToTab('Root.Main', $types, 'Content'); $objFields = $this->owner->getSelectableFields(); $sortFields = $objFields; // Remove content and groups from being sortable (as they are not relevant). unset($sortFields['Content']); unset($sortFields['Groups']); $fields->replaceField('SortBy', new DropdownField('SortBy', _t('ExtensibleSearchPage.SORT_BY', 'Sort By'), $sortFields)); $fields->addFieldToTab('Root.Main', MultiValueDropdownField::create('SearchOnFields', _t('ExtensibleSearchPage.INCLUDE_FIELDS', 'Search On Fields'), $objFields), 'Content'); $fields->addFieldToTab('Root.Main', MultiValueTextField::create('ExtraSearchFields', _t('SolrSearch.EXTRA_FIELDS', 'Custom solr fields to search')), 'Content'); $boostVals = array(); for ($i = 1; $i <= static::BOOST_MAX; $i++) { $boostVals[$i] = $i; } $fields->addFieldToTab('Root.Main', new KeyValueField('BoostFields', _t('ExtensibleSearchPage.BOOST_FIELDS', 'Boost values'), $objFields, $boostVals), 'Content'); $fields->addFieldToTab('Root.Main', $f = new KeyValueField('BoostMatchFields', _t('ExtensibleSearchPage.BOOST_MATCH_FIELDS', 'Boost fields with field/value matches'), array(), $boostVals), 'Content'); $f->setRightTitle('Enter a field name, followed by the value to boost if found in the result set, eg "title:Home" '); $fields->addFieldToTab('Root.Main', $kv = new KeyValueField('FilterFields', _t('ExtensibleSearchPage.FILTER_FIELDS', 'Fields to filter by')), 'Content'); $fields->addFieldToTab('Root.Main', new HeaderField('FacetHeader', _t('ExtensibleSearchPage.FACET_HEADER', 'Facet Settings')), 'Content'); $fields->addFieldToTab('Root.Main', new MultiValueDropdownField('FacetFields', _t('ExtensibleSearchPage.FACET_FIELDS', 'Fields to create facets for'), $objFields), 'Content'); $fields->addFieldToTab('Root.Main', new MultiValueTextField('CustomFacetFields', _t('ExtensibleSearchPage.CUSTOM_FACET_FIELDS', 'Additional fields to create facets for')), 'Content'); $facetMappingFields = $objFields; if ($this->owner->CustomFacetFields && ($cff = $this->owner->CustomFacetFields->getValues())) { foreach ($cff as $facetField) { $facetMappingFields[$facetField] = $facetField; } } $fields->addFieldToTab('Root.Main', new KeyValueField('FacetMapping', _t('ExtensibleSearchPage.FACET_MAPPING', 'Mapping of facet title to nice title'), $facetMappingFields), 'Content'); $fields->addFieldToTab('Root.Main', new KeyValueField('FacetQueries', _t('ExtensibleSearchPage.FACET_QUERIES', 'Fields to create query facets for')), 'Content'); $fields->addFieldToTab('Root.Main', new NumericField('MinFacetCount', _t('ExtensibleSearchPage.MIN_FACET_COUNT', 'Minimum facet count for inclusion in facet results'), 2), 'Content'); } // Make sure previously existing hooks are carried across. $this->owner->extend('updateSolrCMSFields', $fields); }