module Scrivito # This class represents a CMS attribute. Attributes can be created, updated, deleted and all # attribute properties can be read. Attributes are part of an # {Scrivito::ObjClass} and therefore each attribute belongs to exactly # one {Scrivito::ObjClass}. Most of the operations interact with the currently # selected {Scrivito::Workspace}. Operations like +create+, +destroy+ # and +update+ need to be performed in the "rtc" workspace. # # @api public class Attribute include ModelIdentity # Initializes a new attribute. # # @api public # # This allows you to set the different properties of an attribute by # providing a Hash with the property names as keys and the values you want to set as values. # # @example Create a new attribute with name "locale" and type "string". # Attribute.new(name: 'locale', type: :string) # # @example Create a new "enum" attribute named "category" and provide values. # Attribute.new(name: 'category', type: :enum, values: %w(tech social)) # # @param [Hash] properties # @option properties [String] :name The name of the attribute. # @option properties [String] :type The type of the attribute, can be +string+, +text+, +html+, +linklist+, +link+, +reference+, +referencelist+, +date+, +binary+, +widget+, +enum+ or +multienum+. # @option properties [Array] :values Possible values if the type is either +enum+ or +multienum+. # # @return [Scrivito::Attribute] # @raise [Scrivito::ScrivitoError] Raised when no +properties+ are provided. def initialize(properties) raise ScrivitoError, 'Please provide a hash of Attribute properties.' unless properties update_instance_properties(properties) end # Returns the name of this attribute. # @api public # @return [String] def name @name end # Returns the type of this attribute. The type is either +string+, +text+, +html+, +linklist+, # +link+, +reference+, +referencelist+, +date+, +binary+, +widget+, +enum+ or +multienum+. # @api public # @return [String] def type @type end # Returns the values of this attribute, if it is of type +enum+ or +multienum+. # @api public # @return [Array] values def values @values end # Returns the obj class this attribute belongs to. # @api public # @return [Scrivito::ObjClass] attr_reader :obj_class # Returns a unique identifier of this attribute. An attribute is unique by # its +name+ and its +obj_class+. Implements the {Scrivito::ModelIdentity} interface. # @return [Array] def id [name, obj_class] end # Binds this attribute to an obj class. # @return [Scrivito::ObjClass] attr_writer :obj_class # Updates this attribute and persists the changes # in the CMS on its obj class. The +obj_class+ and +name+ of this attribute can not be updated. # # @api public # # See {Attribute#initialize} for a detailed overview of what properties are allowed # and how to set them. # # @example Change the +type+ of the "locale" attribute to "string". # attribute = ObjClass.find('Homepage').attributes['locale'] # attribute.update(type: :string) # # @example Adding the value "sports" to the +enum+ attribute "category" on the "Homepage" obj class. # attribute = ObjClass.find('Homepage').attributes['category'] # attribute.update(values: attribute.values << 'sports') # # @param [Hash] properties # # @return [nil] # @raise [Scrivito::ScrivitoError] Raised when trying to change the +name+ or +obj_class+ property. def update(properties) properties = properties.with_indifferent_access if properties.has_key?(:name) raise ScrivitoError, "#{self.class} does not support changing its 'name'. Please remove" \ " the key from the properties." end properties = to_cms_rest_api.merge(properties) update_instance_properties(properties) obj_class.update(attributes: obj_class.attributes.to_a) nil end # Destroys this attribute and persists the change in the CMS. # # @api public # # @example Remove the "locale" attribute from the "Homepage" obj class. # ObjClass.find('Homepage').attributes['locale'].destroy # # @return [nil] def destroy obj_class.attributes.delete(self) obj_class.update(attributes: obj_class.attributes.to_a) nil end # Returns this attribute in the CMS REST API format. # # @return [Hash] def to_cms_rest_api data = { name: name, type: type, } if %w(enum multienum).include?(type) data[:values] = values end data end private # Updates the instance properties of this attribute with +properties+ # given in the CMS REST API format. # # @param [Hash] properties # @return [void] def update_instance_properties(properties) properties = properties.with_indifferent_access @name = properties[:name].to_s @type = properties[:type].to_s @values = (properties[:values] || []).map(&:to_s) end end end