include/model_handler.rb in baza-0.0.8 vs include/model_handler.rb in baza-0.0.9

- old
+ new

@@ -1,6 +1,7 @@ require "#{File.dirname(__FILE__)}/model_handler_sqlhelper.rb" +require "string-cases" class Baza::ModelHandler attr_reader :args, :events, :data, :ids_cache, :ids_cache_should def initialize(args) @@ -30,19 +31,18 @@ raise "No DB given." if !@args[:db] and !@args[:custom] raise "No class path given." if !@args[:class_path] and (@args[:require] or !@args.key?(:require)) if args[:require_all] - Knj.gem_require(:Php4r, "php4r") loads = [] Dir.foreach(@args[:class_path]) do |file| next if file == "." or file == ".." or !file.match(/\.rb$/) file_parsed = file file_parsed.gsub!(@args[:class_pre], "") if @args.key?(:class_pre) file_parsed.gsub!(/\.rb$/, "") - file_parsed = Php4r.ucwords(file_parsed) + file_parsed = StringCases.snake_to_camel(file_parsed) loads << file_parsed self.requireclass(file_parsed, {:load => false}) end @@ -196,23 +196,21 @@ else raise "Unknown number of arguments: #{arity}" end callback["block"].call(*callargs) - elsif callback["callback"] - require "php4r" if !Kernel.const_defined?(:Php4r) - Php4r.call_user_func(callback["callback"], args) else raise "No valid callback given." end end end end def requireclass(classname, args = {}) classname = classname.to_sym return false if @objects.key?(classname) + classname_snake = StringCases.camel_to_snake(classname) @lock_require.synchronize do #Maybe the classname got required meanwhile the synchronized wait - check again. return false if @objects.key?(classname) @@ -230,12 +228,12 @@ elsif @args[:require] or !@args.key?(:require) doreq = true end if doreq - filename = "#{@args[:class_path]}/#{@args[:class_pre]}#{classname.to_s.downcase}.rb" - filename_req = "#{@args[:class_path]}/#{@args[:class_pre]}#{classname.to_s.downcase}" + filename = "#{@args[:class_path]}/#{@args[:class_pre]}#{classname_snake}.rb" + filename_req = "#{@args[:class_path]}/#{@args[:class_pre]}#{classname_snake}" raise "Class file could not be found: #{filename}." if !File.exists?(filename) require filename_req end end @@ -358,17 +356,11 @@ if @args[:cache] == :weak and obj = @objects[classname].get!(id) and obj.id.to_i == id return obj end #Spawn object. - if @args[:datarow] or @args[:custom] - obj = @args[:module].const_get(classname).new(data, args) - else - pass_args = [data] - pass_args = pass_args | @args[:extra_args] if @args[:extra_args] - obj = @args[:module].const_get(classname).new(*pass_args) - end + obj = @args[:module].const_get(classname).new(data, args) #Save object in cache. case @args[:cache] when :none return obj @@ -412,10 +404,17 @@ end return false end + #Searches for an object with the given data. If not found it creates it. Returns the found or created object in the end. + def get_or_add(classname, data, args = nil) + obj = self.get_by(classname, data) + obj = self.add(classname, data) if !obj + return obj + end + def get_try(obj, col_name, obj_name = nil) if !obj_name if match = col_name.to_s.match(/^(.+)_id$/) obj_name = Php4r.ucwords(match[1]).to_sym else @@ -443,19 +442,12 @@ classname = classname.to_sym self.requireclass(classname) classob = @args[:module].const_get(classname) raise "list-function has not been implemented for '#{classname}'." if !classob.respond_to?("list") + ret = classob.list(Knj::Hash_methods.new(:args => args, :ob => self, :db => @args[:db]), &block) - if @args[:datarow] or @args[:custom] - ret = classob.list(Knj::Hash_methods.new(:args => args, :ob => self, :db => @args[:db]), &block) - else - realargs = [args] - realargs = realargs | @args[:extra_args] if @args[:extra_args] - ret = classob.list(*realargs, &block) - end - #If 'ret' is an array and a block is given then the list-method didnt return blocks. We emulate it instead with the following code. if block and ret.is_a?(Array) ret.each do |obj| block.call(obj) end @@ -653,12 +645,18 @@ def add(classname, data = {}, args = nil) raise "data-variable was not a hash: '#{data.class.name}'." if !data.is_a?(Hash) classname = classname.to_sym self.requireclass(classname) - if @args[:datarow] + if @args[:custom] classobj = @args[:module].const_get(classname) + retob = classobj.add(Knj::Hash_methods.new( + :ob => self, + :data => data + )) + else + classobj = @args[:module].const_get(classname) #Run the class 'add'-method to check various data. classobj.add(Knj::Hash_methods.new(:ob => self, :db => @args[:db], :data => data)) if classobj.respond_to?(:add) #Check if various required data is given. If not then raise an error telling about it. @@ -684,20 +682,10 @@ #Skip the rest if we are told not to return result. return nil if args and args[:skip_ret] #Spawn the object. retob = self.get(classname, ins_id, {:skip_reload => true}) - elsif @args[:custom] - classobj = @args[:module].const_get(classname) - retob = classobj.add(Knj::Hash_methods.new( - :ob => self, - :data => data - )) - else - args = [data] - args = args | @args[:extra_args] if @args[:extra_args] - retob = @args[:module].const_get(classname).add(*args) end self.call("object" => retob, "signal" => "add") retob.send(:add_after, {}) if retob.respond_to?(:add_after) @@ -706,52 +694,37 @@ #Adds several objects to the database at once. This is faster than adding every single object by itself, since this will do multi-inserts if supported by the database. #===Examples # ob.adds(:User, [{:username => "User 1"}, {:username => "User 2"}) def adds(classname, datas) - if !@args[:datarow] + if @args[:module].const_get(classname).respond_to?(:add) datas.each do |data| - @args[:module].const_get(classname).add(*args) - self.call("object" => retob, "signal" => "add") + @args[:module].const_get(classname).add(Knj::Hash_methods.new( + :ob => self, + :db => self.db, + :data => data + )) end - else - if @args[:module].const_get(classname).respond_to?(:add) - datas.each do |data| - @args[:module].const_get(classname).add(Knj::Hash_methods.new( - :ob => self, - :db => self.db, - :data => data - )) - end - end - - db.insert_multi(classname, datas) end + db.insert_multi(classname, datas) self.cache_ids(classname) end #Calls a static method on a class. Passes the d-variable which contains the Objects-object, database-reference and more... def static(class_name, method_name, *args, &block) - raise "Only available with datarow enabled." if !@args[:datarow] and !@args[:custom] class_name = class_name method_name = method_name self.requireclass(class_name) class_obj = @args[:module].const_get(class_name) #Sometimes this raises the exception but actually responds to the class? Therefore commented out. - knj #raise "The class '#{class_obj.name}' has no such method: '#{method_name}' (#{class_obj.methods.sort.join(", ")})." if !class_obj.respond_to?(method_name) - pass_args = [] + pass_args = [Knj::Hash_methods.new(:ob => self, :db => self.db)] - if @args[:datarow] - pass_args << Knj::Hash_methods.new(:ob => self, :db => self.db) - else - pass_args << Knj::Hash_methods.new(:ob => self) - end - args.each do |arg| pass_args << arg end class_obj.send(method_name, *pass_args, &block) @@ -803,95 +776,87 @@ self.call("object" => object, "signal" => "delete_before") self.unset(object) obj_id = object.id object.delete if object.respond_to?(:delete) - if @args[:datarow] - #If autodelete is set by 'has_many'-method, go through it and delete the various objects first. - if autodelete_data = object.class.autodelete_data - autodelete_data.each do |adel_data| - self.list(adel_data[:classname], {adel_data[:colname].to_s => object.id}) do |obj_del| - self.delete(obj_del, args) - end + #If autodelete is set by 'has_many'-method, go through it and delete the various objects first. + if autodelete_data = object.class.autodelete_data + autodelete_data.each do |adel_data| + self.list(adel_data[:classname], {adel_data[:colname].to_s => object.id}) do |obj_del| + self.delete(obj_del, args) end end - - #If depend is set by 'has_many'-method, check if any objects exists and raise error if so. - if dep_datas = object.class.depending_data - dep_datas.each do |dep_data| - if obj = self.get_by(dep_data[:classname], {dep_data[:colname].to_s => object.id}) - raise "Cannot delete <#{object.class.name}:#{object.id}> because <#{obj.class.name}:#{obj.id}> depends on it." - end + end + + #If depend is set by 'has_many'-method, check if any objects exists and raise error if so. + if dep_datas = object.class.depending_data + dep_datas.each do |dep_data| + if obj = self.get_by(dep_data[:classname], {dep_data[:colname].to_s => object.id}) + raise "Cannot delete <#{object.class.name}:#{object.id}> because <#{obj.class.name}:#{obj.id}> depends on it." end end - - #If autozero is set by 'has_many'-method, check if any objects exists and set the ID to zero. - if autozero_datas = object.class.autozero_data - autozero_datas.each do |zero_data| - self.list(zero_data[:classname], {zero_data[:colname].to_s => object.id}) do |obj_zero| - obj_zero[zero_data[:colname].to_sym] = 0 - end + end + + #If autozero is set by 'has_many'-method, check if any objects exists and set the ID to zero. + if autozero_datas = object.class.autozero_data + autozero_datas.each do |zero_data| + self.list(zero_data[:classname], {zero_data[:colname].to_s => object.id}) do |obj_zero| + obj_zero[zero_data[:colname].to_sym] = 0 end end - - #Delete any translations that has been set on the object by 'has_translation'-method. - if object.class.translations - begin - _hb.trans_del(object) - rescue NameError - _kas.trans_del(object) - end + end + + #Delete any translations that has been set on the object by 'has_translation'-method. + if object.class.translations + begin + _hb.trans_del(object) + rescue NameError + _kas.trans_del(object) end - - - #If a buffer is given in arguments, then use that to delete the object. - if args and buffer = args[:db_buffer] - buffer.delete(object.table, {:id => obj_id}) - else - @args[:db].delete(object.table, {:id => obj_id}) - end end + + #If a buffer is given in arguments, then use that to delete the object. + if args and buffer = args[:db_buffer] + buffer.delete(object.table, {:id => obj_id}) + else + @args[:db].delete(object.table, {:id => obj_id}) + end + @ids_cache[classname].delete(obj_id.to_i) if @ids_cache_should.key?(classname) self.call("object" => object, "signal" => "delete") object.destroy return nil end #Deletes several objects as one. If running datarow-mode it checks all objects before it starts to actually delete them. Its faster than deleting every single object by itself... def deletes(objs) - if !@args[:datarow] + tables = {} + + begin objs.each do |obj| - self.delete(obj) - end - else - tables = {} - - begin - objs.each do |obj| - next if obj.deleted? - tablen = obj.table - - if !tables.key?(tablen) - tables[tablen] = [] - end - - tables[tablen] << obj.id - obj.delete if obj.respond_to?(:delete) - - #Remove from ID-cache. - classname = obj.class.classname.to_sym - @ids_cache[classname].delete(obj.id.to_i) if @ids_cache_should.key?(classname) - - #Unset any data on the object, so it seems deleted. - obj.destroy + next if obj.deleted? + tablen = obj.table + + if !tables.key?(tablen) + tables[tablen] = [] end - ensure - #An exception may occur, and we should make sure, that objects that has gotten 'delete' called also are deleted from their tables. - tables.each do |table, ids| - ids.each_slice(1000) do |ids_slice| - @args[:db].delete(table, {:id => ids_slice}) - end + + tables[tablen] << obj.id + obj.delete if obj.respond_to?(:delete) + + #Remove from ID-cache. + classname = obj.class.classname.to_sym + @ids_cache[classname].delete(obj.id.to_i) if @ids_cache_should.key?(classname) + + #Unset any data on the object, so it seems deleted. + obj.destroy + end + ensure + #An exception may occur, and we should make sure, that objects that has gotten 'delete' called also are deleted from their tables. + tables.each do |table, ids| + ids.each_slice(1000) do |ids_slice| + @args[:db].delete(table, {:id => ids_slice}) end end end end \ No newline at end of file