Class: Blacklight::SearchState

Inherits:
Object
  • Object
show all
Extended by:
Deprecation
Includes:
Deprecations::SearchStateNormalization
Defined in:
lib/blacklight/search_state.rb,
lib/blacklight/search_state/filter_field.rb

Overview

This class encapsulates the search state as represented by the query parameters namely: :f, :q, :page, :per_page and, :sort

Defined Under Namespace

Classes: FilterField

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(params, blacklight_config, controller = nil) ⇒ SearchState

Returns a new instance of SearchState.

Parameters:

  • params (ActionController::Parameters)
  • blacklight_config (Blacklight::Config)
  • controller (ApplicationController) (defaults to: nil)

    used for the routing helpers



40
41
42
43
44
45
# File 'lib/blacklight/search_state.rb', line 40

def initialize(params, blacklight_config, controller = nil)
  @blacklight_config = blacklight_config
  @controller = controller
  @params = SearchState.modifiable_params(params)
  normalize_params! if needs_normalization?
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_name, *arguments, &block) ⇒ Object



95
96
97
98
99
100
101
102
103
104
# File 'lib/blacklight/search_state.rb', line 95

def method_missing(method_name, *arguments, &block)
  if @params.respond_to?(method_name)
    Deprecation.warn(self.class, "Calling `#{method_name}` on Blacklight::SearchState " \
      'is deprecated and will be removed in Blacklight 8. Call #to_h first if you ' \
      ' need to use hash methods (or, preferably, use your own SearchState implementation)')
    @params.public_send(method_name, *arguments, &block)
  else
    super
  end
end

Instance Attribute Details

#blacklight_configObject (readonly)

Must be called blacklight_config, because Blacklight::Facet calls blacklight_config.



13
14
15
# File 'lib/blacklight/search_state.rb', line 13

def blacklight_config
  @blacklight_config
end

#controllerObject (readonly)

This method is never accessed in this class, but may be used by subclasses that need to access the url_helpers



18
19
20
# File 'lib/blacklight/search_state.rb', line 18

def controller
  @controller
end

#paramsObject (readonly)

Returns the value of attribute params.



14
15
16
# File 'lib/blacklight/search_state.rb', line 14

def params
  @params
end

Class Method Details

.modifiable_params(params) ⇒ Object



22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/blacklight/search_state.rb', line 22

def self.modifiable_params(params)
  if params.respond_to?(:to_unsafe_h)
    # This is the typical (not-ActionView::TestCase) code path.
    params = params.to_unsafe_h
    # In Rails 5 to_unsafe_h returns a HashWithIndifferentAccess, in Rails 4 it returns Hash
    params = params.with_indifferent_access if params.instance_of? Hash
  elsif params.is_a? Hash
    # This is an ActionView::TestCase workaround for Rails 4.2.
    params = params.dup.with_indifferent_access
  else
    params = params.dup.to_h.with_indifferent_access
  end
  params
end

Instance Method Details

#add_facet_params(field, item) ⇒ Object

adds the value and/or field to params Does NOT remove request keys and otherwise ensure that the hash is suitable for a redirect. See add_facet_params_and_redirect



181
182
183
# File 'lib/blacklight/search_state.rb', line 181

def add_facet_params(field, item)
  filter(field).add(item).params
end

#add_facet_params_and_redirect(field, item) ⇒ Object

Used in catalog/facet action, facets.rb view, for a click on a facet value. Add on the facet params to existing search constraints. Remove any paginator-specific request params, or other request params that should be removed for a 'fresh' display. Change the action to 'index' to send them back to catalog/index with their new facet choice.



193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/blacklight/search_state.rb', line 193

def add_facet_params_and_redirect(field, item)
  new_params = Deprecation.silence(self.class) do
    add_facet_params(field, item)
  end

  # Delete any request params from facet-specific action, needed
  # to redir to index action properly.
  request_keys = blacklight_config.facet_paginator_class.request_keys
  new_params.extract!(*request_keys.values)

  new_params
end

#clause_paramsObject



124
125
126
# File 'lib/blacklight/search_state.rb', line 124

def clause_params
  params[:clause] || {}
end

#facet_pageObject



269
270
271
# File 'lib/blacklight/search_state.rb', line 269

def facet_page
  [params[facet_request_keys[:page]].to_i, 1].max
end

#facet_prefixObject



277
278
279
# File 'lib/blacklight/search_state.rb', line 277

def facet_prefix
  params[facet_request_keys[:prefix]]
end

#facet_sortObject



273
274
275
# File 'lib/blacklight/search_state.rb', line 273

def facet_sort
  params[facet_request_keys[:sort]]
end

#filter(field_key_or_field) ⇒ Object



169
170
171
172
173
174
175
# File 'lib/blacklight/search_state.rb', line 169

def filter(field_key_or_field)
  field = field_key_or_field if field_key_or_field.is_a? Blacklight::Configuration::Field
  field ||= blacklight_config.facet_fields[field_key_or_field]
  field ||= Blacklight::Configuration::NullField.new(key: field_key_or_field)

  (field.filter_class || FilterField).new(field, self)
end

#filter_paramsObject



128
129
130
# File 'lib/blacklight/search_state.rb', line 128

def filter_params
  params[:f] || {}
end

#filtersObject



165
166
167
# File 'lib/blacklight/search_state.rb', line 165

def filters
  @filters ||= filter_fields.select(&:any?)
end

#has_constraints?Boolean

Returns:

  • (Boolean)


114
115
116
117
118
# File 'lib/blacklight/search_state.rb', line 114

def has_constraints?
  Deprecation.silence(Blacklight::SearchState) do
    !(query_param.blank? && filter_params.blank? && filters.blank? && clause_params.blank?)
  end
end

#has_facet?(config, value: nil) ⇒ Boolean

Returns:

  • (Boolean)


217
218
219
220
221
222
223
# File 'lib/blacklight/search_state.rb', line 217

def has_facet?(config, value: nil)
  if value
    filter(config).include?(value)
  else
    filter(config).any?
  end
end

#needs_normalization?Boolean

Returns:

  • (Boolean)


47
48
49
50
51
52
# File 'lib/blacklight/search_state.rb', line 47

def needs_normalization?
  return false if params.blank?
  return true if (params.keys.map(&:to_s) - permitted_fields.map(&:to_s)).present?

  !!filters.detect { |filter| filter.values.detect { |value| filter.needs_normalization?(value) } }
end

#normalize_paramsObject



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/blacklight/search_state.rb', line 58

def normalize_params
  return params unless needs_normalization?

  base_params = params.slice(*blacklight_config.search_state_fields)
  normal_state = blacklight_config.facet_fields.each_value.inject(reset(base_params)) do |working_state, filter_key|
    f = filter(filter_key)
    next working_state unless f.any?

    filter_values = f.values(except: [:inclusive_filters]).inject([]) do |memo, filter_value|
      # flatten arrays that had been mangled into integer-indexed hashes
      memo.concat([f.normalize(filter_value)].flatten)
    end
    filter_values = f.values(except: [:filters, :missing]).inject(filter_values) do |memo, filter_value|
      memo << f.normalize(filter_value)
    end
    filter_values.inject(working_state) do |memo, filter_value|
      memo.filter(filter_key).add(filter_value)
    end
  end
  normal_state.params
end

#normalize_params!Object



54
55
56
# File 'lib/blacklight/search_state.rb', line 54

def normalize_params!
  @params = normalize_params
end

#pageObject



245
246
247
# File 'lib/blacklight/search_state.rb', line 245

def page
  [params[:page].to_i, 1].max
end

#params_for_search(params_to_merge = {}) {|params| ... } ⇒ ActionController::Parameters

Merge the source params with the params_to_merge hash

Parameters:

  • params_to_merge (Hash) (defaults to: {})

    to merge into above

Yields:

  • (params)

    The merged parameters hash before being sanitized

Returns:

  • (ActionController::Parameters)

    the current search parameters after being sanitized by Blacklight::Parameters.sanitize



230
231
232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/blacklight/search_state.rb', line 230

def params_for_search(params_to_merge = {})
  # params hash we'll return
  my_params = params.dup.merge(self.class.new(params_to_merge, blacklight_config, controller))

  if block_given?
    yield my_params
  end

  if my_params[:page] && (my_params[:per_page] != params[:per_page] || my_params[:sort] != params[:sort])
    my_params[:page] = 1
  end

  Parameters.sanitize(my_params)
end

#per_pageObject



249
250
251
252
253
# File 'lib/blacklight/search_state.rb', line 249

def per_page
  params[:rows].presence&.to_i ||
    params[:per_page].presence&.to_i ||
    blacklight_config.default_per_page
end

#permitted_fieldsObject



80
81
82
83
# File 'lib/blacklight/search_state.rb', line 80

def permitted_fields
  filter_keys = filter_fields.inject(Set.new) { |memo, filter| memo.merge [filter.filters_key, filter.inclusive_filters_key] }
  blacklight_config.search_state_fields + filter_keys.subtract([nil, '']).to_a
end

#query_paramObject



120
121
122
# File 'lib/blacklight/search_state.rb', line 120

def query_param
  params[:q]
end

#remove_facet_params(field, item) ⇒ Object

copies the current params (or whatever is passed in as the 3rd arg) removes the field value from params removes the field if there are no more values in params[field] removes additional params (page, id, etc..)

Parameters:

  • field (String)
  • item (String)


212
213
214
# File 'lib/blacklight/search_state.rb', line 212

def remove_facet_params(field, item)
  filter(field).remove(item).params
end

#remove_query_paramsObject



159
160
161
162
163
# File 'lib/blacklight/search_state.rb', line 159

def remove_query_params
  p = reset_search_params
  p.delete(:q)
  p
end

#reset(params = nil) ⇒ Blacklight::SearchState



134
135
136
# File 'lib/blacklight/search_state.rb', line 134

def reset(params = nil)
  self.class.new(params || ActionController::Parameters.new, blacklight_config, controller)
end

#reset_search(additional_params = {}) ⇒ Blacklight::SearchState



139
140
141
# File 'lib/blacklight/search_state.rb', line 139

def reset_search(additional_params = {})
  reset(reset_search_params.merge(additional_params))
end

#respond_to_missing?(method_name, include_private = false) ⇒ Boolean

Returns:

  • (Boolean)


106
107
108
# File 'lib/blacklight/search_state.rb', line 106

def respond_to_missing?(method_name, include_private = false)
  @params.respond_to?(method_name, include_private) || super
end

#search_fieldObject



265
266
267
# File 'lib/blacklight/search_state.rb', line 265

def search_field
  blacklight_config.search_fields[search_field_key]
end

#sort_fieldObject



255
256
257
258
259
260
261
262
263
# File 'lib/blacklight/search_state.rb', line 255

def sort_field
  if sort_field_key.blank?
    # no sort param provided, use default
    blacklight_config.default_sort_field
  else
    # check for sort field key
    blacklight_config.sort_fields[sort_field_key]
  end
end

#to_hashObject Also known as: to_h



85
86
87
# File 'lib/blacklight/search_state.rb', line 85

def to_hash
  @params.deep_dup
end

#to_unsafe_hObject



90
91
92
93
# File 'lib/blacklight/search_state.rb', line 90

def to_unsafe_h
  Deprecation.warn(self.class, 'Use SearchState#to_h instead of SearchState#to_unsafe_h')
  to_hash
end

#url_for_document(doc, options = {}) ⇒ Object

Extension point for downstream applications to provide more interesting routing to documents



147
148
149
150
151
152
153
154
155
156
157
# File 'lib/blacklight/search_state.rb', line 147

def url_for_document(doc, options = {})
  if respond_to?(:blacklight_config) &&
      blacklight_config.view_config(:show).route &&
      (!doc.respond_to?(:to_model) || doc.to_model.is_a?(SolrDocument))
    route = blacklight_config.view_config(:show).route.merge(action: :show, id: doc).merge(options)
    route[:controller] = params[:controller] if route[:controller] == :current
    route
  else
    doc
  end
end