Class: ActiveCMIS::Object
- Inherits:
-
Object
- Object
- ActiveCMIS::Object
- Includes:
- Internal::Caching
- Defined in:
- lib/active_cmis/object.rb
Direct Known Subclasses
Class Attribute Summary collapse
-
.repository ⇒ Repository
readonly
The repository this type is defined in.
Instance Attribute Summary collapse
-
#key ⇒ String?
readonly
The cmis:objectId of the object, or nil if the document does not yet exist in the repository.
-
#repository ⇒ Repository
readonly
The repository that contains this object.
-
#updated_attributes ⇒ Array<String>
readonly
A list of all attributes that have changed locally.
Class Method Summary collapse
-
.attributes(inherited = false) ⇒ Hash{String => PropertyDefinition}
A list of all attributes defined on this object.
- .from_atom_entry(repository, data, parameters = {}) ⇒ Object
- .from_parameters(repository, parameters) ⇒ Object
-
.key ⇒ String
The key of the CMIS Type.
Instance Method Summary collapse
-
#acl ⇒ Acl?
The ACL of the document, if there is any at all.
-
#allowable_actions ⇒ Hash{String => Boolean,String}
A hash containing all actions allowed on this object for the current user.
-
#attribute(name) ⇒ Object
Attribute getter for the CMIS attributes of an object.
-
#attributes ⇒ Hash{String => ::Object}
Attribute getter for the CMIS attributes of an object.
-
#destroy ⇒ Object
Tries to delete the object To delete all versions of a Document try #all_versions.delete.
-
#file(folder) ⇒ void
Files an object in a folder, if the repository supports multi-filing this will be an additional folder, else it will replace the previous folder.
-
#id ⇒ String?
The cmis:objectId of the object, or nil if the document does not yet exist in the repository.
-
#initialize(repository, data, parameters) ⇒ Object
constructor
Creates a representation of an CMIS Object in the repository.
- #inspect ⇒ String
-
#method_missing(method, *parameters) ⇒ Object
Via method missing attribute accessors and setters are provided for the CMIS attributes of an object.
-
#name ⇒ String
Shorthand for the cmis:name of an object.
-
#parent_folders ⇒ Array<Folder>, Collection
Depending on the repository there can be more than 1 parent folder Always returns [] for relationships, policies may also return [].
-
#reload ⇒ void
Empties the locally cached and updated values, updated data is asked from the server the next time a value is requested.
-
#save ⇒ Object
Saves all changes to the object in the repository.
-
#source_relations ⇒ Collection
Returns all relationships where this object is the source.
-
#target_relations ⇒ Collection
Returns all relationships where this object is the target.
-
#unfile(folder = nil) ⇒ void
Removes an object from a given folder or all folders.
-
#update(attributes) ⇒ {String => ::Object}
Attribute setter for all CMIS attributes.
Methods included from Internal::Caching
Constructor Details
#initialize(repository, data, parameters) ⇒ Object
Creates a representation of an CMIS Object in the repository
Not meant for direct use, use Repository#object_by_id instead. To create a new object use the new method on the type that you want the new object to have.
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/active_cmis/object.rb', line 21 def initialize(repository, data, parameters) @repository = repository @data = data @updated_attributes = [] if @data.nil? # Creating a new type from scratch raise Error::Constraint.new("This type is not creatable") unless self.class.creatable @key = parameters["id"] @allowable_actions = {} @parent_folders = [] # start unlinked else @key = parameters["id"] || attribute('cmis:objectId') @self_link = data.xpath("at:link[@rel = 'self']/@href", NS::COMBINED).first @self_link = @self_link.text end @used_parameters = parameters # FIXME: decide? parameters to use?? always same ? or parameter with reload ? end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method, *parameters) ⇒ Object
Via method missing attribute accessors and setters are provided for the CMIS attributes of an object. If attributes have a colon in their name you can access them by changing the colon in a dot
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/active_cmis/object.rb', line 51 def method_missing(method, *parameters) string = method.to_s if string[-1] == ?= assignment = true string = string[0..-2] end if attributes.keys.include? string if assignment update(string => parameters.first) else attribute(string) end elsif self.class.attribute_prefixes.include? string if assignment raise NotImplementedError.new("Mass assignment not yet supported to prefix") else @attribute_prefix ||= {} @attribute_prefix[method] ||= AttributePrefix.new(self, string) end else super end end |
Class Attribute Details
.repository ⇒ Repository (readonly)
The repository this type is defined in
522 523 524 |
# File 'lib/active_cmis/object.rb', line 522 def repository @repository end |
Instance Attribute Details
#key ⇒ String? (readonly)
The cmis:objectId of the object, or nil if the document does not yet exist in the repository
11 12 13 |
# File 'lib/active_cmis/object.rb', line 11 def key @key end |
#repository ⇒ Repository (readonly)
The repository that contains this object
7 8 9 |
# File 'lib/active_cmis/object.rb', line 7 def repository @repository end |
#updated_attributes ⇒ Array<String>
A list of all attributes that have changed locally
89 90 91 |
# File 'lib/active_cmis/object.rb', line 89 def updated_attributes @updated_attributes end |
Class Method Details
.attributes(inherited = false) ⇒ Hash{String => PropertyDefinition}
A list of all attributes defined on this object
550 551 552 |
# File 'lib/active_cmis/object.rb', line 550 def attributes(inherited = false) {} end |
.from_atom_entry(repository, data, parameters = {}) ⇒ Object
525 526 527 528 529 530 531 532 533 534 535 536 537 538 |
# File 'lib/active_cmis/object.rb', line 525 def from_atom_entry(repository, data, parameters = {}) query = "cra:object/c:properties/c:propertyId[@propertyDefinitionId = '%s']/c:value" type_id = data.xpath(query % "cmis:objectTypeId", NS::COMBINED).text klass = repository.type_by_id(type_id) if klass if klass <= self klass.new(repository, data, parameters) else raise "You tried to do from_atom_entry on a type which is not a supertype of the type of the document you identified" end else raise "The object #{extract_property(data, "String", 'cmis:name')} has an unrecognized type #{type_id}" end end |
.from_parameters(repository, parameters) ⇒ Object
541 542 543 544 545 |
# File 'lib/active_cmis/object.rb', line 541 def from_parameters(repository, parameters) url = repository.object_by_id_url(parameters) data = repository.conn.get_atom_entry(url) from_atom_entry(repository, data, parameters) end |
.key ⇒ String
The key of the CMIS Type
557 558 559 |
# File 'lib/active_cmis/object.rb', line 557 def key raise NotImplementedError end |
Instance Method Details
#acl ⇒ Acl?
Returns The ACL of the document, if there is any at all.
207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/active_cmis/object.rb', line 207 def acl if repository.acls_readable? && allowable_actions["GetACL"] # FIXME: actual query should perhaps look at CMIS version before deciding which relation is applicable? query = "at:link[@rel = '#{Rel[repository.cmis_version][:acl]}']/@href" link = data.xpath(query, NS::COMBINED) if link.length == 1 Acl.new(repository, self, link.first.text, data.xpath("cra:object/c:acl", NS::COMBINED)) else raise "Expected exactly 1 acl for #{key}, got #{link.length}" end end end |
#allowable_actions ⇒ Hash{String => Boolean,String}
Returns A hash containing all actions allowed on this object for the current user.
165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/active_cmis/object.rb', line 165 def allowable_actions actions = {} _allowable_actions.children.map do |node| actions[node.name.sub("can", "")] = case t = node.text when "true", "1"; true when "false", "0"; false else t end end actions end |
#attribute(name) ⇒ Object
Attribute getter for the CMIS attributes of an object
93 94 95 |
# File 'lib/active_cmis/object.rb', line 93 def attribute(name) attributes[name] end |
#attributes ⇒ Hash{String => ::Object}
Attribute getter for the CMIS attributes of an object
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/active_cmis/object.rb', line 99 def attributes self.class.attributes.inject({}) do |hash, (key, attr)| if data.nil? if key == "cmis:objectTypeId" hash[key] = self.class.id else hash[key] = nil end else properties = data.xpath("cra:object/c:properties", NS::COMBINED) values = attr.extract_property(properties) hash[key] = if values.nil? || values.empty? if attr.repeating [] else nil end elsif attr.repeating values.map do |value| attr.property_type.cmis2rb(value) end else attr.property_type.cmis2rb(values.first) end end hash end end |
#destroy ⇒ Object
Tries to delete the object To delete all versions of a Document try #all_versions.delete
For policies this may just remove the policy from the policy group of a document, this depends on how you retrieved the policy. Be careful
296 297 298 |
# File 'lib/active_cmis/object.rb', line 296 def destroy conn.delete(self_link) end |
#file(folder) ⇒ void
This method returns an undefined value.
Files an object in a folder, if the repository supports multi-filing this will be an additional folder, else it will replace the previous folder
244 245 246 247 248 249 250 251 252 |
# File 'lib/active_cmis/object.rb', line 244 def file(folder) raise Error::Constraint.new("Filing not supported for objects of type: #{self.class.id}") unless self.class.fileable @original_parent_folders ||= parent_folders.dup if repository.capabilities["MultiFiling"] @parent_folders << folder unless @parent_folders.detect {|f| f.id == folder.id } else @parent_folders = [folder] end end |
#id ⇒ String?
The cmis:objectId of the object, or nil if the document does not yet exist in the repository
12 13 14 |
# File 'lib/active_cmis/object.rb', line 12 def key @key end |
#inspect ⇒ String
76 77 78 |
# File 'lib/active_cmis/object.rb', line 76 def inspect "#<#{self.class.inspect} @key=#{key}>" end |
#name ⇒ String
Shorthand for the cmis:name of an object
82 83 84 |
# File 'lib/active_cmis/object.rb', line 82 def name attribute('cmis:name') end |
#parent_folders ⇒ Array<Folder>, Collection
Depending on the repository there can be more than 1 parent folder Always returns [] for relationships, policies may also return []
224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
# File 'lib/active_cmis/object.rb', line 224 def parent_folders parent_feed = Internal::Utils.extract_links(data, 'up', 'application/atom+xml','type' => 'feed') unless parent_feed.empty? Collection.new(repository, parent_feed.first) else parent_entry = Internal::Utils.extract_links(data, 'up', 'application/atom+xml','type' => 'entry') unless parent_entry.empty? e = conn.get_atom_entry(parent_entry.first) [ActiveCMIS::Object.from_atom_entry(repository, e)] else [] end end end |
#reload ⇒ void
This method returns an undefined value.
Empties the locally cached and updated values, updated data is asked from the server the next time a value is requested.
281 282 283 284 285 286 287 288 289 |
# File 'lib/active_cmis/object.rb', line 281 def reload if @self_link.nil? raise "Can't reload unsaved object" else __reload @updated_attributes = [] @original_parent_folders = nil end end |
#save ⇒ Object
Saves all changes to the object in the repository.
WARNING: because of the way CMIS is constructed the save operation is not atomic if updates happen to different aspects of the object (parent folders, attributes, content stream, acl), we can’t work around this because CMIS lacks transactions
154 155 156 157 158 159 160 161 162 |
# File 'lib/active_cmis/object.rb', line 154 def save # FIXME: find a way to handle errors? # FIXME: what if multiple objects are created in the course of a save operation? result = self updated_aspects.each do |hash| result = result.send(hash[:message], *hash[:parameters]) end result end |
#source_relations ⇒ Collection
Returns all relationships where this object is the source
194 195 196 197 198 199 200 201 202 203 |
# File 'lib/active_cmis/object.rb', line 194 def source_relations query = "at:link[@rel = '#{Rel[repository.cmis_version][:relationships]}']/@href" link = data.xpath(query, NS::COMBINED) if link.length == 1 link = Internal::Utils.append_parameters(link.text, "relationshipDirection" => "source", "includeSubRelationshipTypes" => true) Collection.new(repository, link) else raise "Expected exactly 1 relationships link for #{key}, got #{link.length}, are you sure this is a document/folder?" end end |
#target_relations ⇒ Collection
Returns all relationships where this object is the target
180 181 182 183 184 185 186 187 188 189 |
# File 'lib/active_cmis/object.rb', line 180 def target_relations query = "at:link[@rel = '#{Rel[repository.cmis_version][:relationships]}']/@href" link = data.xpath(query, NS::COMBINED) if link.length == 1 link = Internal::Utils.append_parameters(link.text, "relationshipDirection" => "target", "includeSubRelationshipTypes" => true) Collection.new(repository, link) else raise "Expected exactly 1 relationships link for #{key}, got #{link.length}, are you sure this is a document/folder?" end end |
#unfile(folder = nil) ⇒ void
This method returns an undefined value.
Removes an object from a given folder or all folders. If the repository does not support unfiling this method throws an error if the document would have no folders left after unfiling.
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
# File 'lib/active_cmis/object.rb', line 258 def unfile(folder = nil) # Conundrum: should this throw exception if folder is not actually among parent_folders? raise Error::Constraint.new("Filing not supported for objects of type: #{self.class.id}") unless self.class.fileable @original_parent_folders ||= parent_folders.dup if repository.capabilities["UnFiling"] if folder.nil? @parent_folders = [] else @parent_folders.delete_if {|f| f.id == folder.id} end else @parent_folders.delete_if {|f| f.id == folder.id} if @parent_folders.empty? @parent_folders = @original_parent_folders @original_parent_folders = nil raise Error::NotSupported.new("Unfiling not supported for this repository") end end end |
#update(attributes) ⇒ {String => ::Object}
Attribute setter for all CMIS attributes. This only updates this copy of the object. Use save to make these changes permanent and visible in the repositorhy. (use #reload after save on other instances of this document to reflect these changes)
137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/active_cmis/object.rb', line 137 def update(attributes) attributes.each do |key, value| if (property = self.class.attributes[key.to_s]).nil? raise Error::Constraint.new("You are trying to add an unknown attribute (#{key})") else property.validate_ruby_value(value) end end self.updated_attributes.concat(attributes.keys).uniq! self.attributes.merge!(attributes) end |