module Scrivito # This class represents a CMS obj class. Obj classes can be created, updated and all properties # can be read. The class also provides methods to find obj classes. The attributes of an obj class # are defined by {Scrivito::Attribute} instances. # # @api public class ObjClass include ModelIdentity class << self # Returns all the obj classes. # # @api public # # @example Find all obj classes in the current {Scrivito::Workspace}. # ObjClass.all # # @return [Array] def all Workspace.current.obj_classes.to_a end # Finds an obj class by its name. # # @api public # # @example Find the obj class named "Homepage" in the current {Scrivito::Workspace}. # ObjClass.find('Homepage') # # @param [String] name The name of the obj class. # @return [Scrivito::ObjClass] # @raise [Scrivito::ResourceNotFound] Raised when no obj class with the given +name+ can be found. def find(name) obj_class = Workspace.current.obj_classes[name] unless obj_class raise ResourceNotFound, "Could not find '#{ObjClass}' with name '#{name}'." end obj_class end # Creates a new obj class and persists it in the CMS. # # @api public # # This allows you to set the different properties of an obj class by # providing a hash with the property names as keys and the values you want # to set as values. Attributes can be either given as {Scrivito::Attribute} instances or as # an attribute property hash. # # @example Create a obj class # ObjClass.create(name: 'Homepage', attributes: [ # { name: 'title', type: :string }, # { name: 'body', type: :widget } # ]) # # @example Create a binary obj class. # ObjClass.create(name: 'Image', attributes: [ # { name: 'blob', type: :binary } # ]) # # @example Create an obj class with attributes passed in as an Array of attribute property hashes. # ObjClass.create(name: 'Blog', attributes: [ # { name: 'headline', type: :string }, # { name: 'category', type: :enum, values: %w(tech social) }, # ]) # # @example Create an obj class with attributes passed in as an Array of {Scrivito::Attribute} instances. # ObjClass.create(name: 'Blog', attributes: [ # Attribute.new(name: 'headline', type: :string), # Attribute.new(name: 'category', type: :enum, values: %w(tech social)), # ]) # # @param [Hash] properties # @option properties [String] :name The name of the obj class. # @option properties [Boolean] :is_active Is it possible to create instances of this obj class? # @option properties [Array, Array] :attributes A list of # attributes for this obj class. Can be either a list of attribute instances or attribute # property hashes. # # @note the +is_binary+ option is deprecated # # @return [Scrivito::ObjClass] def create(properties) properties = properties.with_indifferent_access if properties.key?(:is_binary) Scrivito::Deprecation.warn( "`is_binary' is deprecated and should not be used anymore."\ "Please remove the parameter and specify all attributes you need "\ "including the previously provided attributes 'title', 'body', 'blob'" ) end if properties[:attributes] properties[:attributes].map! do |attribute| attribute.respond_to?(:to_cms_rest_api) ? attribute : Attribute.new(attribute) end end workspace = Workspace.current raw_obj_class_data = workspace.api_request(:post, '/obj_classes', obj_class: format_properties_for_cms(properties)) new(ObjClassData.new(raw_obj_class_data), workspace) end private # Formats obj class properties into a CMS REST API format. # @param [Hash] properties # @return [Hash] Properties formated for the CMS. def format_properties_for_cms(properties) params = properties.dup if params.has_key?(:is_binary) params[:type] = params.delete(:is_binary) ? :generic : :publication end if params.has_key?(:attributes) params[:attributes] = params[:attributes].map(&:to_cms_rest_api) end params end end # Initializes a new obj class. It expects the CMS backend representation of an obj class. # # See {ObjClass.create} for a detailed overview of how to set properties. # # @param [Hash] obj_class_data # @param [Workspace,NilClass] workspace # @raise [Scrivito::ScrivitoError] # @return [Scrivito::ObjClass] def initialize(obj_class_data, workspace) update_obj_class_data(obj_class_data) @workspace = workspace end # @api public # Returns true if this ObjClass was created with a +is_binary+ option. # Creating ObjClass with this option is deprecated and will be removed. # # @return [Boolean] def legacy_type? !!obj_class_data.type end # @!attribute [r] id # @api public # @return [String] unique identifier of this obj class # @!attribute [r] name # @api public # @return [String] the name of this obj class # @!attribute [r] is_active # @api public # @return [Boolean] whether instances can be created with this obj class delegate :id, :name, :is_active, to: :obj_class_data # @api public # @return [Boolean] whether instances of this class are binary, e.g. images or PDFs # @deprecated Please create objects without using the +is_binary+ option # @raise [ScrivitoError] if the method is called on a non-legacy-type ObjClass def is_binary if legacy_type? obj_class_data.is_binary else raise ScrivitoError, %(`is_binary' and `binary?' can only be called on ObjClasses with a legacy_type.) end end alias_method :active?, :is_active alias_method :binary?, :is_binary # @api public # @return [Scrivito::AttributeCollection] the attributes of this obj class. # # @example Find an attribute named "locale" for the obj class "Homepage". # ObjClass.find('Homepage').attributes['locale'] # # @example Add a new +string+ attribute named "headline" to the "Homepage" obj class by providing an attribute property hash. # ObjClass.find('Homepage').attributes.add(name: 'headline', type: :string) # # @example Add a new +enum+ attribute named "category" to the "Homepage" obj class by providing an attribute instance. # attribute = Attribute.new(name: 'category', type: :enum, values: %w(tech social)) # ObjClass.find('Homepage').attributes.add(attribute) # # @example Iterate over the list of attributes from the obj class "Homepage" and print their name and type. # ObjClass.find('Homepage').attributes.each do |attribute| # puts "#{attribute.name}:#{attribute.type}" # end attr_reader :attributes # @api public # Updates this obj class and persists the changes in the CMS. It is not possible to # update the +name+. # # See {Scrivito::ObjClass.create} for a detailed overview of # what properties are allowed and how to set them. # # The +is_binary+ option can only be removed. By passing +nil+ for the # +is_binary+ option to update, you can convert legacy objects. This conversion # removes the fields +title+, +body+ (if +is_binary+ was +false+) or +blob+ (if # +is_binary+ was +true+). If you add the fields in the same request the values # will be kept for all objs. # # @example Removing +is_binary+ but keeping the previously predefined fields # ObjClass.find('Homepage').update(is_binary: nil, attributes: [ # {name: 'title', type: 'string'}, # {name: 'body', type: 'html'} # ]) # # # Binary ObjClass # ObjClass.find('Image').update(is_binary: nil, attributes: [ # {name: 'title', type: 'string'}, # {name: 'blob', type: 'binary'} # ]) # # @param [Hash] properties # # @raise [ScrivitoError] Raised when trying to change +name+ or +is_binary+. # # @return [nil] def update(properties) params = properties.with_indifferent_access if params.has_key?(:is_binary) if params[:is_binary].nil? params[:type] = params.delete(:is_binary) else raise ScrivitoError, "#{self.class} only supports removing the `is_binary' property" end end if params.has_key?(:name) raise ScrivitoError, "#{self.class} does not support changing 'name'. Please remove" \ " the key from the properties." end if params.has_key?(:attributes) params[:attributes].map! do |attribute| attribute = Attribute.new(attribute) unless attribute.respond_to?(:to_cms_rest_api) attribute.obj_class = self attribute.to_cms_rest_api end end raw_obj_class_data = workspace.api_request(:put, "/obj_classes/#{name}", obj_class: params) update_obj_class_data(ObjClassData.new(raw_obj_class_data)) workspace.reload nil end def update_obj_class_data(obj_class_data) @obj_class_data = obj_class_data update_attributes end private attr_reader :obj_class_data, :workspace def update_attributes attributes = @obj_class_data.attributes.map do |attribute_data| attribute = Attribute.new(attribute_data) attribute.obj_class = self attribute end @attributes = AttributeCollection.new(self, attributes) end end end