module PIM

Automatically load additional sub-modules for PIM

Constants

DefaultExportFormats

Create Enum type containing all known export formats

EmptyToNilSetAttribute

Special Set type attribute which will always return ‘nil’ if empty in json

InternalSystemHashAttribute

Internal system attribute of base class ‘Hash’ which does not return it’s value as json

PublicationStatus

Create some system types

Public Class Methods

__after_request() click to toggle source
# File pim.rb, line 594
def self.__after_request
  # Reset fiber local caches
  Thread.current[:__caches] = nil
end
__before_request() click to toggle source
# File pim.rb, line 589
def self.__before_request
  # Reset fiber local caches
  Thread.current[:__caches] = nil
end
__fiber_local_cache(name) click to toggle source
# File pim.rb, line 585
def self.__fiber_local_cache name
  (Thread.current[:__caches] ||= {})[name.to_sym] ||= {}
end
active_module() click to toggle source
# File pim.rb, line 22
def self.active_module
  return @current_active_module if @current_active_module
  return PIM if all_modules.empty?
  @all_modules.values.last
end
additional_attributes_as_json(attribute_names_per_module) click to toggle source
# File pim.rb, line 182
def self.additional_attributes_as_json attribute_names_per_module
  return active_module.additional_attributes_as_json(attribute_names_per_module) if not all_modules.empty?
end
additional_categories_as_json(category_names_per_module) click to toggle source
# File pim.rb, line 178
def self.additional_categories_as_json category_names_per_module
  return active_module.additional_categories_as_json(category_names_per_module) if not all_modules.empty?
end
additional_section_attributes_as_json(layout_name, item) click to toggle source
# File pim.rb, line 186
def self.additional_section_attributes_as_json layout_name, item
  return active_module.additional_section_attributes_as_json(layout_name, item) if not all_modules.empty?
end
after_store(new_item, old_item = nil, opts = {}) click to toggle source
# File pim.rb, line 394
def self.after_store new_item, old_item = nil, opts = {}
  execute_item_method 'after_store', new_item, old_item, opts
end
all_modules() click to toggle source
# File pim.rb, line 14
def self.all_modules
  @all_modules ||= {}
end
attribute_rules_as_json() click to toggle source
# File pim.rb, line 131
def self.attribute_rules_as_json
  return active_module.attribute_rules_as_json if not all_modules.empty?
  return []
end
attributes_as_json() click to toggle source
# File pim.rb, line 98
def self.attributes_as_json
  return active_module.attributes_as_json if not all_modules.empty?
end
before_delete(new_item, opts = {}) click to toggle source
# File pim.rb, line 398
def self.before_delete new_item, opts = {}
  execute_item_method 'before_delete', new_item, nil, opts
end
before_store(old_item, new_item, called_from_import) click to toggle source

Old version: Just for compatibility with projects which directly called this method

# File pim.rb, line 354
def self.before_store old_item, new_item, called_from_import
  return [] if all_modules.empty?

  begin
    old_item = Item.from_json old_item, { :init_multivalue => false } if old_item
  rescue Exception => e
    PIM.log_warn("Could not resolve class of old item in 'before_store' (#{old_item})", e)
  end

  begin
    new_item = Item.from_json new_item, { :init_multivalue => false }
  rescue Exception => e
    PIM.log_warn("Could not resolve class of new item in 'before_store' (#{new_item})", e)
  end

  begin
    if new_item && new_item.kind_of?(Item)
      items_changed = [{ "ORIG" => new_item }]
      before_store = new_item.method(:before_store)
      if before_store.arity == 1 and not called_from_import
        items_changed_in_class = new_item.before_store(old_item)
      elsif before_store.arity == 2
        items_changed_in_class = new_item.before_store(old_item, called_from_import)
      end
      items_changed_in_class.each do |item|
        items_changed << { "SAVE" => item }
      end if items_changed_in_class and items_changed_in_class.respond_to? :each
      return items_changed
    end
  rescue Exception => e
    PIM.log_error("Error in 'before_store'", e)
  end

  return []
end
before_store_v2(new_item, old_item = nil, opts = {}) click to toggle source
# File pim.rb, line 390
def self.before_store_v2 new_item, old_item = nil, opts = {}
  execute_item_method 'before_store', new_item, old_item, opts
end
cache() click to toggle source
# File pim.rb, line 581
def self.cache
  PIM.__fiber_local_cache(:__pim_cache)
end
calculate_category(values) click to toggle source
# File pim.rb, line 569
def self.calculate_category values
  return nil if all_modules.empty?
  values = PIM::Utils.symbolized_hash(values)
  active_module.calculate_category values
end
calculate_primary_key(values) click to toggle source
# File pim.rb, line 575
def self.calculate_primary_key values
  return nil if all_modules.empty?
  values = PIM::Utils.symbolized_hash(values)
  active_module.calculate_primary_key values
end
call_item_method(method_name, new_item, old_item = nil, opts = {}) click to toggle source
# File pim.rb, line 498
def self.call_item_method method_name, new_item, old_item = nil, opts = {}

  method_sym = method_name.to_sym
  return nil if not new_item.respond_to?(method_sym)

  item_method = new_item.method(method_sym)
  arity = item_method.arity.abs
  result = nil

  #
  # Omit calling before_store if we are called in the context
  # of a depublication, and the current datamodel is not aware
  # that this can happen.
  #
  if method_name == 'before_store'
    called_from_depublication = opts[:called_from_depublication] || opts['called_from_depublication']
    if called_from_depublication and not active_module.has_option?(:consider_called_from_depublication)
      PIM.log_debug("Store method '#{method_name}' called from depublication, but current datamodel is not aware of this feature. Invocation will be omitted.")
      return nil
    end
  end

  if method_name == 'before_store' and not active_module.has_option?(:use_before_store_opts)
    # For compatibility: 'before_store' only has the 'called_from_import' parameter
    called_from_import = opts[:called_from_import] || opts['called_from_import']
    if arity == 2
      result = item_method.call(old_item, called_from_import)
    elsif arity == 1
      # For compatibility: Without 'called_from_import' parameter, 'before_store' is not called at all
      if not called_from_import
        result = item_method.call(old_item)
      end
    elsif arity == 0
      result = item_method.call()
    else
      PIM.log_warn("Store method '#{method_name}' does not have the correct number of arguments (#{arity} not in 0, 1 or 2)")
    end
  else
    if arity == 2
      result = item_method.call(old_item, opts)
    elsif arity == 1
      opts[:old_item] = opts['old_item'] = old_item
      result = item_method.call(opts)
    elsif arity == 0
      result = item_method.call()
    else
      PIM.log_warn("Item method '#{method_name}' does not have the correct number of arguments (#{arity} not in 0, 1 or 2)")
    end
  end

  return result

end
categories_as_json() click to toggle source
# File pim.rb, line 102
def self.categories_as_json
  return active_module.categories_as_json if not all_modules.empty?
end
category_as_json(category_name) click to toggle source
# File pim.rb, line 145
def self.category_as_json category_name
  return nil if all_modules.empty?
  category = active_module.category category_name
  return category.as_json if category
end
communication_channels_as_json() click to toggle source
# File pim.rb, line 118
def self.communication_channels_as_json
  return active_module.communication_channels_as_json if not all_modules.empty?
end
communication_plans_as_json() click to toggle source
# File pim.rb, line 114
def self.communication_plans_as_json
  return active_module.communication_plans_as_json if not all_modules.empty?
end
compute_item_hierarchies_to_publish(primary_keys, publication = nil) click to toggle source

Should not be overridden in data model!

# File pim.rb, line 289
def self.compute_item_hierarchies_to_publish primary_keys, publication = nil

  return {} if active_module.nil?

  if active_module.respond_to?(:compute_item_hierarchies_to_publish)

    # Data model overrides 'compute_item_hierarchies_to_publish'
    PIM.log_info("Data model overrides 'compute_item_hierarchies_to_publish' method")
    return active_module.compute_item_hierarchies_to_publish(primary_keys)

  elsif active_module.respond_to?(:compute_items_to_publish)

    # Data model implements old 'compute_items_to_publish' method
    PIM.log_warn("Data model still implements old 'compute_items_to_publish' method")
    return active_module.compute_items_to_publish(primary_keys)

  else

    # Simple LRU item cache
    item_cache = PIM::LRUCache.new(20)

    # Options to retrieve publication hierarchies
    publication_type = PIM.get_value(publication, 'publication_type')

    publication_values = PIM.get_value(publication, 'publication_values')
    publish_only_valid = PIM.get_value(publication_values, 'only_valid')
    if publish_only_valid.nil?
      publish_only_valid = publication_type.nil? || publication_type == 'ADD'
    else
      publish_only_valid = publish_only_valid.to_s.downcase == 'true'
    end

    opts = {
      :item_cache => item_cache,
      :only_valid => publish_only_valid,
      :publication => (publication || {})
    }

    # Step one: Determine the top level items for the hierarchies to publish
    top_level_items = active_module.get_top_level_items(primary_keys, opts)

    # Step two: Determine the hierarchies for each top level item
    item_hierarchies = {}

    top_level_items.each do |top_level_item, status|

      # Set status from top_level_item result
      opts[:status] = status

      item_hierarchy = active_module.get_item_hierarchy(top_level_item, opts)
      item_hierarchy = active_module.update_hierarchy(item_hierarchy, opts)
      item_hierarchies[top_level_item] = item_hierarchy unless item_hierarchy.nil?

    end

    return item_hierarchies

  end
end
contact_attributes_as_json() click to toggle source
# File pim.rb, line 75
def self.contact_attributes_as_json
  return active_module.contact_attributes if not all_modules.empty?
  return []
end
copy_item_as_json(item, organization) click to toggle source
# File pim.rb, line 155
def self.copy_item_as_json item, organization
  return nil if all_modules.empty?
  copy = active_module.copy_item item, organization
  return copy.as_json if copy
end
dashboard_attributes_as_json() click to toggle source
# File pim.rb, line 85
def self.dashboard_attributes_as_json
  return active_module.dashboard_attributes if not all_modules.empty?
  return []
end
data_model_as_json() click to toggle source
# File pim.rb, line 90
def self.data_model_as_json
  return active_module.data_model_as_json if not all_modules.empty?
end
default_item_as_json(category_name, organization, user) click to toggle source
# File pim.rb, line 161
def self.default_item_as_json category_name, organization, user
  return nil if all_modules.empty?
  category = active_module.category category_name
  if category and category.respond_to?(:default_item)
    organization = PIM::Services.__convert(organization, to: PIM::Services::OrganizationService::Organization)
    user = PIM::Services.__convert(user, to: PIM::Services::AccountService::LoginAccount)

    arity = category.method(:default_item).arity
    item = case arity
      when 2 then category.default_item(organization, user)
      when 1 then category.default_item(organization)
      else category.default_item
    end
    return item.as_json if !item.nil?
  end
end
execute_item_method(method_name, new_item, old_item = nil, opts = {}) click to toggle source
# File pim.rb, line 402
def self.execute_item_method method_name, new_item, old_item = nil, opts = {}

  return {} if all_modules.empty?

  begin
    new_item = PIM::Item.from_json(new_item, :init_multivalue => false)
  rescue Exception => e
    PIM.log_warn("Could not create new item in '#{method_name}' for:\n#{new_item}", e)
  end
  return {} if not new_item.is_a?(PIM::Item)

  old_item ||= opts[:old_item]
  if old_item
    begin
      old_item = PIM::Item.from_json(old_item, :init_multivalue => false)
    rescue Exception => e
      PIM.log_warn("Could not create old item in '#{method_name}' for:\n#{old_item}", e)
    end
    old_item = nil if not old_item.is_a?(PIM::Item)
  end

  begin
    method_call_result = self.call_item_method(method_name, new_item, old_item, opts)
  rescue Exception => e
    PIM.log_error("Error calling '#{method_name}' method", e)
    return { "exception" => e.message }
  end

  result = {}

  include_empty = active_module.has_option?(:return_empty_values)

  if method_name == 'before_store'

    # Check if 'store_item' was set to false
    if PIM.get_value(method_call_result, :store_item) == false

      # NOTE: We could allow to set 'store_item' to a Hash in order to store the item as specified!
      # This way we would not merge the item with the old values at all!
      result['this'] = false
      result['call_after_store'] = false

    else

      result['this'] = new_item.as_json(:include_empty => include_empty)
      result['call_after_store'] = (self.call_item_method('call_after_store?', new_item, old_item, opts) == true)

    end

  end

  if not is_empty?(method_call_result)
    if is_array?(method_call_result)
      result['others'] = self.map_store_items_result(method_call_result, include_empty)
    elsif is_hash?(method_call_result)

      # Set 'status_values' from call result, if any
      self.set_stringified_method_call_result(result, method_call_result, :status_values)

      # Convert and add store_options and store_items to actual result
      others = {}

      # Use 'stringify' to convert the options to ensure no Ruby Symbol objects are used in Java
      self.set_stringified_method_call_result(others, method_call_result, :store_options)
      self.set_stringified_method_call_result(others, method_call_result, :delete_items)
      self.set_stringified_method_call_result(others, method_call_result, :validate_items)

      store_items = PIM.get_value(method_call_result, :store_items)
      others['store_items'] = self.map_store_items_result(store_items, include_empty) unless is_empty?(store_items)

      result['others'] = others unless PIM.is_empty?(others)

    end
  end

  return result

end
execute_plan_action(action_type, action_creator, action_tags, action_date, channel, organization, data) click to toggle source
# File pim.rb, line 349
def self.execute_plan_action action_type, action_creator, action_tags, action_date, channel, organization, data
  return active_module.execute_plan_action(action_type, action_creator, action_tags, action_date, channel, organization, data) if not all_modules.empty?
end
filters_as_json() click to toggle source
# File pim.rb, line 110
def self.filters_as_json
  return active_module.filters_as_json if not all_modules.empty?
end
has_module?(module_name) click to toggle source
# File pim.rb, line 18
def self.has_module? module_name
  @all_modules && @all_modules.include?(module_name.to_s)
end
in_platform_publication_as_json() click to toggle source
# File pim.rb, line 122
def self.in_platform_publication_as_json
  return as_json(active_module.in_platform_publication) if not all_modules.empty?
end
item_hierarchy_graph(item, hierarchy_name = nil) click to toggle source

Return an item hierarchy graph for the specified item and hierarchy name. If hiearchy_name is nil, returns the “default” hierarchy.

The resulted hierarchy should have the following JSON structure:
 {
   "items": [
       {
           "primaryKey": "22222",    <- Primary key of the item in the hierarchy
           "level": 1                <- Level of hierarchy, starts with 0
       },
       ...
   ], // Alternatively, it is also possible to use primary keys only,
        e.g. items: [ "1234", "4567", ... ] however no mixture of both!
   "relations": [
       {
           "parentItem": "",         <- Primary key of the parent item
           "childItem": "",          <- Primary key of the child item
           "relationValue": "20x",   <- Value of the relationship (optional)
           "relationAttribute": "amount" <- The unit of the relationship (optional)
       },
       ...
   ]

}

# File pim.rb, line 238
def self.item_hierarchy_graph item, hierarchy_name = nil

  return nil if all_modules.empty?

  # Simple LRU item cache
  item_cache = PIM::LRUCache.new(20)

  if is_hash?(item)
    begin
      item = Item.from_json(item, { :init_multivalue => false })
    rescue Exception => e
      PIM.log_warn("Could not create item in 'item_hierarchy_graph' for:\n#{item}", e)
    end
  elsif is_string?(item)
    primary_key = item
    item = load_item_as_ruby(primary_key, item_cache, :init_multivalue => false)
    PIM.log_warn("Item for primary key '#{primary_key}' in item_hierarchy_graph not found") if item.nil?
  end
  return nil if not item.is_a?(Item)

  opts = {
    :item_cache => item_cache
  }

  # Get hierarchy graph for item
  hierarchy_graph = item.method(:hierarchy_graph)
  if hierarchy_graph
    arity = hierarchy_graph.arity
    hierarchy = case arity
      when 0 then item.hierarchy_graph()
      when 1, -1 then item.hierarchy_graph(hierarchy_name)
      when 2, -2 then item.hierarchy_graph(hierarchy_name, opts)
      else
        PIM.log_warn("'hierarchy_graph' method for category #{item.class} does not have the correct number of arguments (#{arity.abs} not in 0, 1 or 2)")
        nil
    end
  else
    PIM.log_info("No 'hierarchy_graph' method in category #{item.class}")
    hierarchy = nil
  end

  if is_hash?(hierarchy)
    hierarchy[:items].map! { |item| camelize(item) } if hierarchy[:items]
    hierarchy[:relations].map! { |relation| camelize(relation) } if hierarchy[:relations]
  end

  return hierarchy

end
layout_as_json(layout_name, opts = {}) click to toggle source
# File pim.rb, line 201
def self.layout_as_json layout_name, opts = {}
  return nil if all_modules.empty?
  layout = active_module.layout layout_name
  return layout.as_json(opts) if layout
end
layouts_as_json() click to toggle source
# File pim.rb, line 106
def self.layouts_as_json
  return active_module.layouts_as_json if not all_modules.empty?
end
managing_user_roles_as_json(user, contact) click to toggle source
# File pim.rb, line 194
  def self.managing_user_roles_as_json user, contact
    # FIXME: Add 'Contact' class in 'ContactService' to support execution on external Ruby!
#    user = PIM::Services.__convert(user, to: PIM::Services::AccountService::LoginAccount)
#    contact = PIM::Services.__convert(contact, to: PIM::Services::ContactService::Contact)
    return active_module.managing_user_roles_as_json(user, contact) if not all_modules.empty?
  end
map_store_items_result(store_items, include_empty) click to toggle source
# File pim.rb, line 486
def self.map_store_items_result store_items, include_empty
  store_items.map do |store_item|
    if store_item.is_a?(PIM::Item)
      json_hash = store_item.as_json(:include_empty => include_empty)
      json_string = json_hash.to_json # Creates a JSON string
      JSON.parse(json_string) # Creates a "cleaned up" JSON Hash
    else
      store_item
    end
  end
end
mapping_functions_as_json() click to toggle source
# File pim.rb, line 151
def self.mapping_functions_as_json
  return active_module.mapping_functions_as_json if not all_modules.empty?
end
media_asset_naming_patterns_as_json() click to toggle source
# File pim.rb, line 136
def self.media_asset_naming_patterns_as_json
  return as_json(active_module.media_asset_naming_patterns)
end
migrate_as_json(args) click to toggle source
# File pim.rb, line 207
def self.migrate_as_json args
  return nil if all_modules.empty?
  migrated_values = active_module.migrate!(args)
  return as_json(migrated_values)
end
option_lists_as_json() click to toggle source
# File pim.rb, line 94
def self.option_lists_as_json
  return active_module.option_lists_as_json if not all_modules.empty?
end
organization_attributes_as_json() click to toggle source
# File pim.rb, line 65
def self.organization_attributes_as_json
  return active_module.organization_attributes if not all_modules.empty?
  return []
end
print_json(object) click to toggle source
reset() click to toggle source
# File pim.rb, line 28
def self.reset
  all_modules.keys.each do |m|
    PIM::Utils.remove_const_on_parent m
  end
  @all_modules = nil
end
reset_active_module() click to toggle source
# File pim.rb, line 35
def self.reset_active_module
  return if all_modules.empty?
  active_module_key = active_module.to_s
  PIM::Utils.remove_const_on_parent(active_module_key)
  new_all_modules = @all_modules.dup
  new_all_modules.delete(active_module_key)
  @all_modules = new_all_modules
end
return_json(object) click to toggle source
# File pim.rb, line 49
def self.return_json object
  return object.is_a?(String)? object : as_json(object).to_json if object
end
review_attributes_as_json() click to toggle source
# File pim.rb, line 80
def self.review_attributes_as_json
  return active_module.review_attributes if not all_modules.empty?
  return []
end
roles_as_json() click to toggle source
# File pim.rb, line 60
def self.roles_as_json
  return active_module.roles_as_json if not all_modules.empty?
  return PIM.all_roles_as_json
end
set_stringified_method_call_result(result, method_call_result, type) click to toggle source
# File pim.rb, line 481
def self.set_stringified_method_call_result result, method_call_result, type
  value = PIM.get_value(method_call_result, type)
  result[type.to_s] = stringify(value) unless is_empty?(value)
end
task_tags_as_json() click to toggle source
# File pim.rb, line 126
def self.task_tags_as_json
  return as_json(active_module.task_tags) if not all_modules.empty?
  return []
end
to_json(object) click to toggle source
# File pim.rb, line 53
def self.to_json object
  return nil if object.nil?
  return object if object.is_a?(String)
  return object.to_json if object.respond_to?(:to_json)
  return object.to_s
end
user_attributes_as_json() click to toggle source
# File pim.rb, line 70
def self.user_attributes_as_json
  return active_module.user_attributes if not all_modules.empty?
  return []
end
user_data_model_as_json(user) click to toggle source
# File pim.rb, line 190
def self.user_data_model_as_json user
  return active_module.user_data_model_as_json(user) if not all_modules.empty?
end
validate_as_json(old_item, new_item, attributes = nil) click to toggle source
# File pim.rb, line 552
def self.validate_as_json old_item, new_item, attributes = nil
  return nil if all_modules.empty?

  old_item = PIM::Utils.symbolized_hash(old_item)
  new_item = PIM::Utils.symbolized_hash(new_item)
  attributes = PIM::Utils.symbolized_array(attributes)

  validation_result = active_module.validate old_item, new_item, *attributes
  validation_result.as_json

end
validate_items_as_json(items) click to toggle source
# File pim.rb, line 564
def self.validate_items_as_json items
  return nil if all_modules.empty?
  return as_json(active_module.validate_items(*items))
end

Protected Class Methods

execute_in_module(execute_module, &block) click to toggle source
# File pim.rb, line 601
def self.execute_in_module execute_module, &block
  old_active_module = @current_active_module
  begin
    execute_module = get_module(execute_module)
    return nil if !execute_module
    @current_active_module = execute_module
    return execute_module.module_exec(&block)
  ensure
    @current_active_module = old_active_module
  end
end