module PIM::DataModel
Constants
- AVAILABLE_OPTIONS
- DATA_MODEL_DEFINITIONS_FILE_EXTENSIONS
- PRELOAD_REFERENCED_ITEMS_DEFAULT_SIZE
- PRELOAD_REFERENCED_ITEMS_MAX_SIZE
Attributes
Public Instance Methods
Adds all contained items to a hierarchy. Return true, if all items in the hierarchy exist and are valid, false otherwise. Should not be overridden in data model!
# File pim.rb, line 3031 def add_item_to_hierarchy hierarchy, primary_key, status, opts = {} # Hierarchy is complete, if the same item was already added if hierarchy.include?(primary_key) return true end contained_items = get_contained_items(primary_key, opts) return false if contained_items.nil? # Add item with status to hierarchy add_to_collection hierarchy, primary_key, status # Iterate over contained items and add them to hierarchy contained_items.each do |contained_item_primary_key, status| return false if not add_item_to_hierarchy(hierarchy, contained_item_primary_key, status, opts) end return true end
# File pim.rb, line 2756 def attribute_rules_as_json attribute_rules_as_json = {} all_attributes.each_value do |attribute| attribute_rules_as_json[attribute.name] = all_rules_by_attribute(attribute.name).keys attribute_rules_as_json[attribute.name] += all_rules_by_params(*attribute.params.keys).keys end attribute_rules_as_json end
# File pim.rb, line 3069 def attribute_to_xml attribute, values, parent_node, no_ignore = false attribute = attribute(attribute) unless attribute.is_a?(PIM::Attribute) # Only write out known/existing attributes return if attribute.nil? # Don't write out meta/system attributes return if attribute.is_meta_attribute? # Ignore attribute, if specified return if not no_ignore and attribute.param(:xml_ignore) value = PIM.get_value(values, attribute.name) context = XmlContext.new( parent_node: parent_node, attribute: attribute, value: value, values: values ) to_xml = attribute.param(:to_xml) || PIM::Attributes::DEFAULT_TO_XML begin to_xml.call(context, XmlUtils) rescue Exception => e log_error("Error in to_xml of attribute '#{attribute.name}'", e) raise e end end
# File pim.rb, line 3099 def attributes_to_xml attributes, values, parent_node return if PIM.is_empty?(attributes) parent_node ||= XmlUtils.create_xml_document attributes.each do |attribute| attribute_to_xml(attribute, values, parent_node) end return parent_node end
# File pim.rb, line 2729 def cache PIM.__fiber_local_cache(:__data_model_cache) end
# File pim.rb, line 2673 def contact_attributes *attributes @contact_attributes ||= [] if attributes attributes.each do |attribute| check_attribute!(attribute, "Attribute '#{attribute}' used as contact attribute is not defined") end @contact_attributes.concat(attributes) end @contact_attributes end
# File pim.rb, line 3118 def create_xml_item values, parent_node = nil parent_node ||= XmlUtils.create_xml_document return PIM::Utils.timed(group: "validation", key: "create_xml_item", message: "Creating XmlItem from values") do category_name = PIM.get_value(values, 'category__') if PIM.is_empty?(category_name) category = PIM::Item xml = attributes_to_xml(all_attributes.values, values, parent_node) else category = category(category_name) raise "Category '#{category_name}' does not exist" if category.nil? xml = category.to_xml(values, parent_node) end primary_key = PIM.get_value(values, :primaryKey__) category.create_xml_item(xml, category: category.name, primary_key: primary_key, values: values) end end
# File pim.rb, line 2695 def dashboard_attributes *attributes @dashboard_attributes ||= [] if attributes attributes.each do |attribute| check_attribute!(attribute, "Attribute '#{attribute}' used as dashboard attribute is not defined") end @dashboard_attributes.concat(attributes) end @dashboard_attributes end
# File pim.rb, line 2765 def data_model_as_json return { :name => self.to_s, :label => (@label || self.to_s), :optionLists => option_lists_as_json, :attributes => attributes_as_json, :categories => categories_as_json, :layouts => layouts_as_json, :organizationAttributes => organization_attributes, :userAttributes => user_attributes, :contactAttributes => contact_attributes, :reviewAttributes => review_attributes, :dashboardAttributes => dashboard_attributes, :mappingFunctions => mapping_functions_as_json, :communicationPlans => communication_plans_as_json, :filters => filters_as_json, :roles => roles_as_json, :attributeRules => attribute_rules_as_json, :taskTags => task_tags, :inPlatformPublication => as_json(in_platform_publication) } end
# File pim.rb, line 2523 def data_model_definitions_file location = nil, force: false if location # Only set the location unless running on internal JRuby return nil if PIM::Services.is_java_services_available? if force @data_model_definitions_file = location return location end if @data_model_definitions_file raise "Data model definitions file location for data model '#{self.to_s}' is already defined" end extname = File.extname(location) if not extname.empty? and not DATA_MODEL_DEFINITIONS_FILE_EXTENSIONS.include?(extname) PIM.log_warn "Specified data model definitions file '#{location}' not supported; File must have either of these extensions: #{DATA_MODEL_DEFINITIONS_FILE_EXTENSIONS}" return nil end basename = File.basename(location, extname) dirname = File.dirname(location) # Determine location via "preferred" extensions preferred_location = nil DATA_MODEL_DEFINITIONS_FILE_EXTENSIONS.each do |extname| test_location = File.expand_path(basename + extname, dirname) if File.readable?(test_location) preferred_location = test_location break end end if preferred_location PIM.log_info "Using data model definitions file in '#{preferred_location}'" unless preferred_location == location location = preferred_location elsif not File.readable?(location) PIM.log_warn "Data model definitions location '#{location}' not found or not readable" return nil end @data_model_definitions_file = location end return @data_model_definitions_file end
# File pim.rb, line 2476 def data_model_manager &block data_model_manager = DataModelManager.new data_module if block data_model_manager.instance_eval(&block) end end
# File pim.rb, line 2483 def data_module self end
# File pim.rb, line 2595 def extension type, &block @extensions ||= {} @extensions[type] ||= [] @extensions[type] << block end
# File pim.rb, line 2601 def extension_point type unless @extensions.nil? or @extensions.empty? blocks = @extensions[type] return false if blocks.nil? or blocks.empty? blocks.each do |block| self.instance_eval &block end true end end
# File pim.rb, line 2748 def find_first_in_parent_modules &block ([self] | parent_modules).each do |m| value = block.call(m) return value unless value.nil? end return nil end
# File pim.rb, line 3146 def get_attribute_options_validator attribute, param_name, option_groups_param_name = nil options = attribute.param(to_sym(param_name)) option_groups = attribute.param(to_sym(option_groups_param_name)) unless option_groups_param_name.nil? if PIM.is_symbol_or_string?(options) option_list = option_list(options) raise "Option list '#{options}' referenced in param '#{param_name}' of attribute '#{attribute.name}' does not exist" if option_list.nil? if !PIM.is_empty?(option_list.service) lambda do |option| return PIM::Services::DataModelService.has_data_model_option?(option_list.service, option_list.name, option, *PIM.stringify(option_groups)) end else lambda do |option| return option_list.includes_option?(option, *option_groups) end end else lambda do |option| return PIM.includes_value?(option, options) end end end
Return a list of items directly contained in an item. Return nil, if item itself does not exist or is not valid. Should be overridden in data model! Default implementation: Just return an empty list.
# File pim.rb, line 2998 def get_contained_items primary_key, opts = {} return [] end
# File pim.rb, line 2921 def get_converter attribute, converter_param return nil if attribute.nil? converter = attribute.param(converter_param) return nil if converter.nil? if not converter.respond_to?(:call) # If converter was specified as String, we expect it to contain the module and the method converter_module, converter_method = converter.to_s.split('.') converter_module = PIM.constantize(converter_module) converter = converter_module.method(PIM.to_sym(converter_method)) end if converter.arity == 0 PIM.log_error("Converter '#{converter_param}' for attribute '#{attribute.name}' has no arguments and will be ignored") converter = nil end converter end
# File pim.rb, line 2507 def get_data_model_definitions_file *extensions return nil if data_model_definitions_file.nil? filename = data_model_definitions_file if not File.readable?(filename) PIM.log_warn "Data model definitions not found in '#{filename}'" return nil end extension = File.extname(filename) return nil unless extensions.include?(extension) return filename end
Return a hierarchical list of items which are contained in an item. Return nil, if any item in the hierarchy does not exist or is not valid. Should not be overridden in data model!
# File pim.rb, line 3005 def get_item_hierarchy primary_key, opts = {} # For compatibility with old data model which (illegally!) overwrite 'add_item_hierarchy' if self.respond_to?(:add_item_hierarchy) # Old method only works with hierachy Array hierarchy = [] has_hierarchy = add_item_hierarchy(primary_key, hierarchy, opts) else # Create hierarchy either as Array or Hash, depending on 'status' status = PIM.get_value(opts, :status) hierarchy = status.nil? ? [] : {} has_hierarchy = add_item_to_hierarchy(hierarchy, primary_key, status, opts) end return has_hierarchy ? hierarchy : nil end
Convenience method to return the attribute value for either a Java item, a Hash or a PIM::Item
This method should be used, if the origin of the item is unknown.
# File pim.rb, line 2956 def get_item_value item, attribute return nil if attribute.nil? attribute_name = (attribute.is_a?(PIM::Attribute) ? attribute.name : attribute).to_s if item.is_a?(PIM::Item) return item[attribute_name] elsif is_hash?(item) return (item[attribute_name.to_sym] || item[attribute_name]) else return nil end end
# File pim.rb, line 2585 def get_option option, default = false return PIM::Utils.get_opt(@options, option, default) end
Return a list of unique top level items for a list of items. Should be overridden in data model! Default implementation: Just return the specified primary keys. NOTE: This method ONLY returns ‘valid’ items, i.e. the data model MUST override it if it wants to allow the publication to differentiate between valid, invalid and skipped items!
# File pim.rb, line 2974 def get_top_level_items primary_keys, opts = {} item_cache = opts[:item_cache] only_valid = opts[:only_valid] top_level_items = Set.new primary_keys.each do |primary_key| # Ignore item if it is not "compliant" item = load_item(primary_key, item_cache) next if not item or (only_valid and not item.is_validation_compliant) top_level_items << primary_key end return top_level_items end
Checks if an additional attribute should actually be added to a category. Should be overridden in data model! Default implementation: All additional attributes will added to any category
# File pim.rb, line 3065 def has_additional_attribute? item, additional_module, additional_category, additional_attribute true end
# File pim.rb, line 2630 def has_initialization_point? type initialization = PIM.get_value(@initializations, type) return !initialization.nil? end
# File pim.rb, line 2590 def has_option? option, default = false return PIM::Utils.is_opt?(@options, option, default) end
# File pim.rb, line 2719 def in_platform_publication &block unless block.nil? raise "In-Platform-Publication already defined" unless @in_platform_publication.nil? @in_platform_publication = InPlatformPublication.build(&block) end @in_platform_publication end
# File pim.rb, line 2612 def initialization type, &block @initializations ||= {} @initializations[type] ||= [] @initializations[type] << block end
# File pim.rb, line 2618 def initialization_point type unless @initializations.nil? or @initializations.empty? blocks = @initializations[type] return false if blocks.nil? or blocks.empty? while !blocks.empty? do block = blocks.shift self.instance_eval &block end true end end
# File pim.rb, line 2733 def item_cache type: item_caches = PIM.__fiber_local_cache(:__item_caches) item_caches[type] ||= LRUCache.new item_caches[type] end
# File pim.rb, line 2487 def label label = nil if label if @label raise "Label for data model '#{self.to_s}' is already defined" end @label = label end @label end
# File pim.rb, line 2706 def managing_user_roles *default_roles, &block unless default_roles.empty? and block.nil? raise "Default managing user roles for data model '#{self.to_s}' are already defined" unless @default_managing_user_roles.nil? raise "Block to determine managing user roles for data model '#{self.to_s}' is already defined" unless @managing_user_roles_block.nil? @default_managing_user_roles = default_roles.empty? ? nil : default_roles @managing_user_roles_block = block end return @default_managing_user_roles end
# File pim.rb, line 2797 def managing_user_roles_as_json user, contact # Get defined block to determine the support roles roles_block = find_first_in_parent_modules { |m| m.managing_user_roles_block } managing_roles = roles_block.call(user, contact) unless roles_block.nil? # Use default support roles or even user's roles, if no roles were determined managing_roles = find_first_in_parent_modules { |m| m.default_managing_user_roles } if is_empty?(managing_roles) managing_roles = user.roles if is_empty?(managing_roles) return managing_roles end
# File pim.rb, line 2635 def media_asset_naming_patterns patterns = nil @media_asset_naming_patterns ||= {} if patterns @media_asset_naming_patterns.merge! patterns end @media_asset_naming_patterns end
Merges the values from the old_item_review with the values of the new item_review
Note: returning an empty object means, that reviews should be merged by the
old manner
# File pim.rb, line 2950 def merge_item_reviews new_item_review, old_item_review nil # default merge end
# File pim.rb, line 2913 def normalize_value value, disable_value_normalization = false, &normalize_block return nil if is_empty?(value) # Normalize value to ensure value is of the correct type normalized_value = normalize_block.call(value) return value if disable_value_normalization return normalized_value end
# File pim.rb, line 2576 def options options = nil @options ||= {} if options @options.merge!(options) end @options end
# File pim.rb, line 2651 def organization_attributes *attributes @organization_attributes ||= [] if attributes attributes.each do |attribute| check_attribute!(attribute, "Attribute '#{attribute}' used as organization attribute is not defined") end @organization_attributes.concat(attributes) end @organization_attributes end
# File pim.rb, line 2739 def parent_modules modules = [] (@parent_modules || []).each do |p| modules << p modules.concat p.parent_modules if p.respond_to?(:parent_modules) end modules end
# File pim.rb, line 2684 def review_attributes *attributes @review_attributes ||= [] if attributes attributes.each do |attribute| check_attribute!(attribute, "Attribute '#{attribute}' used as review attribute is not defined") end @review_attributes.concat(attributes) end @review_attributes end
# File pim.rb, line 2497 def service_name service_name = nil if service_name if @service_name raise "Service name for data model '#{self.to_s}' is already defined" end @service_name = service_name end @service_name end
Called after “computing” a hierarchy via ‘get_top_level_items’ and ‘get_contained_items’. Used to update the hierarchy based on the contained items. May be overridden in data model! Return the updated hierarchy or nil, to skip it. Default implementation: Keep the hierarchy as-is.
# File pim.rb, line 3058 def update_hierarchy hierarchy, opts = {} hierarchy end
# File pim.rb, line 2662 def user_attributes *attributes @user_attributes ||= [] if attributes attributes.each do |attribute| check_attribute!(attribute, "Attribute '#{attribute}' used as user attribute is not defined") end @user_attributes.concat(attributes) end @user_attributes end
# File pim.rb, line 2788 def user_data_model_as_json user categories_overview = user_categories_overview(user) layout_mappings = user_layout_mapping(user) return { :categoriesOverview => categories_overview.as_json, :layoutMapping => layout_mappings.as_json } end
# File pim.rb, line 2810 def value_as_json attribute, value return nil if value.nil? return value.error_value if value.is_a?(ErrorValue) return value if attribute.nil? if attribute.is_a?(Class) base_class = attribute formatter = nil else attribute = attribute(attribute) unless attribute.is_a?(PIM::Attribute) return value if attribute.nil? base_class = attribute.base_class formatter = get_converter(attribute, :formatter) uniq = attribute.param(:uniq) PIM.log_trace "value_as_json: attribute.name=#{attribute.name}, base_classclass=#{base_class}, uniq=#{uniq}" end case when formatter return formatter.call(value) if formatter.arity == 1 return formatter.call(value, attribute) when base_class <= Array return array_value_as_json(attribute, value, uniq) when base_class <= Set return array_value_as_json(attribute, value, true) when base_class <= Hash return hash_value_as_json(attribute, value) when base_class <= DateTime return datetime_value_as_json(attribute, value) when base_class <= Date return date_value_as_json(attribute, value) when value.respond_to?(:as_json) return value.as_json else return value end end
# File pim.rb, line 2856 def value_from_json attribute, value return nil if value.nil? return value if value.is_a?(ErrorValue) return value if attribute.nil? if attribute.is_a?(Class) base_class = attribute parser = nil disable_value_normalization = false else attribute = attribute(attribute) unless attribute.is_a?(PIM::Attribute) return value if attribute.nil? base_class = attribute.base_class parser = get_converter(attribute, :parser) disable_value_normalization = attribute.param(:disable_value_normalization) uniq = attribute.param(:uniq) PIM.log_trace "value_from_json: attribute.name=#{attribute.name}, base_class=#{base_class}, uniq=#{uniq}" end begin case when parser return parser.call(value) if parser.arity == 1 return parser.call(value, attribute) when base_class <= Float return normalize_value(value, disable_value_normalization) { |v| Float(v.to_s) } when base_class <= Integer return normalize_value(value, disable_value_normalization) { |v| Integer(v.to_s, 10) } when base_class <= DateTime return normalize_value(value, disable_value_normalization) { |v| parse_datetime(v) } when base_class <= Date return normalize_value(value, disable_value_normalization) { |v| Date.parse(v.to_s) } when base_class <= Array return collection_value_from_json attribute, value, uniq when base_class <= Set return collection_value_from_json attribute, value, true when base_class <= Hash return hash_value_from_json attribute, value when base_class.respond_to?(:from_json) return base_class.from_json(value) else return value end rescue Exception => e log_warn "Could not convert value #{value_msg(value)}for attribute #{attribute.name} to base class #{base_class}", e return PIM::ErrorValue.new(value, base_class, e.message.length > 0 ? e.message.force_encoding(Encoding::UTF_8) : "") end end
# File pim.rb, line 3113 def values_to_xml values, parent_node = nil xml_item = create_xml_item(values, parent_node) return xml_item.xml end
Protected Instance Methods
# File pim.rb, line 3205 def add_parent_module parent_module @parent_modules ||= [] @parent_modules << parent_module end
# File pim.rb, line 3182 def extended submodule return if self == submodule return if PIM.has_module?(submodule) PIM.add_module submodule submodule.extend XmlUtils submodule.extend Logging submodule.extend DataModel submodule.extend OptionLists submodule.extend Attributes submodule.extend AttributeTemplates submodule.extend Categories submodule.extend Layouts submodule.extend Authorization submodule.extend Filters submodule.extend Validations submodule.extend Calculations submodule.extend CommunicationChannels submodule.extend CommunicationPlans submodule.extend Migrations submodule.extend MappingFunctions submodule.add_parent_module self end