bitrix_on_rails 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "shoulda", ">= 0"
10
+ gem "bundler", "~> 1.0.0"
11
+ gem "jeweler", "~> 1.6.4"
12
+ gem "rcov", ">= 0"
13
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,20 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ git (1.2.5)
5
+ jeweler (1.6.4)
6
+ bundler (~> 1.0)
7
+ git (>= 1.2.5)
8
+ rake
9
+ rake (0.9.2)
10
+ rcov (0.9.9)
11
+ shoulda (2.11.3)
12
+
13
+ PLATFORMS
14
+ ruby
15
+
16
+ DEPENDENCIES
17
+ bundler (~> 1.0.0)
18
+ jeweler (~> 1.6.4)
19
+ rcov
20
+ shoulda
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Danil Pismenny
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
File without changes
data/README.rdoc ADDED
@@ -0,0 +1,86 @@
1
+ = bitrix_on_rails
2
+
3
+ Приблуды для использования под рельсами базы 1С:Битрикс.
4
+
5
+ Для каждого инфоблока что лежит в b_iblock есть своя таблица название которой с номером инфоблока, например b_iblock_element_prop_s7
6
+ prop_s - для одиночных свойтсв, prop_m - для множестенный.
7
+ У каждого инфоблока нескоолько секций (iblock_section), в каждой секции несколько элементов (iblock_element) у каждого элемента разные свойства которые лежат в prop_s/_m.
8
+ Соответсвенно я эти свойства вытащил в одно место - они все доступны из модели IblockElement. Или напрямую; IblockElement.find(123).НАЗВАНИЕ_СВОЙСТВА или через метод properties
9
+
10
+ == Что есть:
11
+
12
+ === mysql2_downcase адаптер
13
+ 1. Адаптер mysql2_downcase для автоматической конвертации заглавных наименований полей в прописные.
14
+
15
+ === Инфоблоки
16
+
17
+ 1. Все модели для таблиц b_iblock_*
18
+ 2. Автоматическая установка свойств из таблиц prop_s*/prop_m* в методы объекта IblockElement.
19
+ Например IblockElement.find(1).name_emittents, где name_emittent - свойство из prop_s.
20
+ Все подобные свойства также доступны через метод IblockElement#properties.
21
+
22
+ 3. IblockElementS*
23
+ 1. Тоже самое и для моделей IblockElementPropertyS*, плюс в них значения полей можно еще и устанавливать:
24
+
25
+ p = IblockElementPropertyS3.find(1)
26
+ p.name_emittents='новое имя'
27
+ p.save
28
+
29
+ 2. Поиск по кодовым названиям полей таблицы
30
+
31
+ IblockElementPropertyS3.find_by_post_id(123)
32
+
33
+ вместо
34
+
35
+ .find_by_property_149(123)
36
+
37
+ Таким образом если мы знаем что инфоблок S3 связан с таблицей постов и хотим получить все свойства поста 63, делаем:
38
+
39
+ IblockElementPropS3.find_by_post_id(63).iblock_element.properties
40
+
41
+ 3. IblockElement.properties выдает хеш соответсвия кодов свойств и названия их полей в prop_s
42
+ Автоматическое определение привязки элемента к объекту. Например: если мы спрашиваем iblock_element.post
43
+ то он ищет ключ :post_id в свойствах элемента, и если находит, то возвращает Post.find_by_id(properties[:post_id])
44
+
45
+ 4. Все свойства IblockProperty кешируются и доступны через find(id)
46
+
47
+ 5. В IblockElement автоматически добавляются has_one :iblock_element_prop_s* и has_many :iblock_element_prop_m* при создании соответвующих классов.
48
+
49
+ 6. Модель можно расширять инфоблоком с помощью:
50
+
51
+ class Post << ActiveRecord::Base
52
+
53
+ has_infoblock(3, :property_19) # где property_19 поле ссылающееся на Post
54
+
55
+ для этой модели автоматически создадутся ассоциации
56
+
57
+ :iblock_element - класс PostElement
58
+
59
+ Класс PostElement будет иметь ассоциации
60
+
61
+ :property_set (он же iblock_element_prop_sNUMBER) и
62
+ :m_prop_values
63
+
64
+ а также default_scope с номером инфоблока, поэтому PostElement.all выдаст только элементы к специфичному инфоблоку
65
+
66
+
67
+ === Битрикс-авторизация
68
+
69
+ == mysql2_downcase
70
+
71
+ Подключать просто:
72
+
73
+ development:
74
+ adapter: mysql2_downcase
75
+ encoding: cp1251
76
+ ...
77
+
78
+ == Contributing to bitrix_on_rails
79
+
80
+ * С нетерпением жду форков, пулеквестов, замечаний и предложений.
81
+
82
+ == Copyright
83
+
84
+ Copyright (c) 2011 Danil Pismenny. See LICENSE.txt for
85
+ further details.
86
+
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "bitrix_on_rails"
18
+ gem.homepage = "http://github.com/dapi/bitrix_on_rails"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Работа с инфоблоками 1С-Битрикс}
21
+ gem.description = %Q{Использование инфоблоков 1С-Битрикс в Ruby On Rails проектах}
22
+ gem.email = "danil@orionet.ru"
23
+ gem.authors = ["Danil Pismenny"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+
35
+ require 'rcov/rcovtask'
36
+ Rcov::RcovTask.new do |test|
37
+ test.libs << 'test'
38
+ test.pattern = 'test/**/test_*.rb'
39
+ test.verbose = true
40
+ test.rcov_opts << '--exclude "gems/*"'
41
+ end
42
+
43
+ task :default => :test
44
+
45
+ require 'rake/rdoctask'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "bitrix_on_rails #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.1
@@ -0,0 +1,87 @@
1
+ # -*- coding: utf-8 -*-
2
+ class Iblock < ActiveRecord::Base
3
+ set_table_name :b_iblock
4
+
5
+ # version - 1 или 2
6
+
7
+ # iblock_type_id это строка, поэтом он срабатывает только если его указывать явано в foreign_key
8
+ belongs_to :iblock_type, :foreign_key=>'iblock_type_id'
9
+
10
+ # Они еще связаны между собой через iblock_section_element
11
+ has_many :iblock_sections
12
+ has_many :iblock_elements
13
+
14
+ # has_many :iblock_section_elements, :through=>:iblock_sections
15
+
16
+ # Список типов свойств по номерам которых создаются поля в
17
+ # таблицах iblock_element_prop_sN
18
+ has_many :iblock_properties
19
+
20
+ has_many :iblock_fields
21
+ has_many :iblock_groups
22
+
23
+ class << self
24
+ def s_props_class(id)
25
+ # raise 'Только для инфоблоков 2-й версии' unless version==2
26
+ "IblockElementPropS#{id}".constantize
27
+ end
28
+
29
+ def m_props_class(id)
30
+ # raise 'Только для инфоблоков 2-й версии' unless version==2
31
+ "IblockElementPropM#{id}".constantize
32
+ end
33
+
34
+ def all
35
+ @cached_all ||= super
36
+ end
37
+ end
38
+
39
+ def to_s
40
+ name
41
+ end
42
+
43
+
44
+ def init_property_models
45
+ return unless version==2
46
+ iblock_id = self.id
47
+
48
+ # Создаем классы IblockElementPropSНОМЕР
49
+ #
50
+ const_name = "IblockElementPropS#{iblock_id}"
51
+ unless Kernel.const_defined? const_name
52
+ e = Class.new(ActiveRecord::Base) do
53
+ extend BitrixOnRails::IblockElementPropS
54
+
55
+ class << self
56
+ @m_prop_class = nil
57
+ @m_props = nil
58
+
59
+ def m_prop_class
60
+ Kernel.const_get(@m_prop_class)
61
+ end
62
+
63
+ def m_props
64
+ @m_props
65
+ end
66
+ end
67
+
68
+ acts_as_iblock_element_prop_s(iblock_id)
69
+ end
70
+ Kernel.const_set const_name, e
71
+ end
72
+ Kernel.const_get(const_name).init
73
+
74
+ # Создаем классы IblockElementPropMНОМЕР
75
+ #
76
+ const_name = "IblockElementPropM#{iblock_id}"
77
+ unless Kernel.const_defined? const_name
78
+ e = Class.new(ActiveRecord::Base) do
79
+ extend BitrixOnRails::IblockElementPropM
80
+ acts_as_iblock_element_prop_m(iblock_id)
81
+ end
82
+ Kernel.const_set "IblockElementPropM#{iblock_id}", e
83
+ end
84
+ Kernel.const_get(const_name).init
85
+ end
86
+
87
+ end
@@ -0,0 +1,108 @@
1
+ # -*- coding: utf-8 -*-
2
+ class IblockElement < ActiveRecord::Base
3
+ class << self
4
+ @block_id = nil
5
+ @iblock_properties = nil
6
+
7
+ def iblock_id
8
+ @iblock_id
9
+ end
10
+
11
+ def iblock_properties
12
+ @iblock_properties
13
+ end
14
+ end
15
+
16
+ set_table_name :b_iblock_element
17
+
18
+ belongs_to :iblock
19
+ belongs_to :iblock_section
20
+
21
+ # Применяется только для iblock-ов 1-й версии
22
+ #
23
+ has_many :iblock_element_properties
24
+
25
+ # Применяется для iblock-ов 2-й версии
26
+ #
27
+ has_many :iblock_section_elements
28
+ has_many :iblock_sections, :through => :iblock_section_elements
29
+
30
+ after_find :initialize_properties
31
+
32
+ attr_accessor :properties
33
+
34
+ def to_s
35
+ name
36
+ end
37
+
38
+ def s_props
39
+ # has_one
40
+ @s_props ||= Iblock.s_props_class(iblock_id).find_by_iblock_element_id( id )
41
+ end
42
+
43
+ def iblock_element_prop_m
44
+ Iblock.m_props_class(iblock_id).where(:iblock_element_id=>id)
45
+ end
46
+
47
+ def m_props
48
+ # TODO Cache
49
+ @m_props={}
50
+ iblock_element_prop_m.each do |p|
51
+ @m_props[p.code]||=[]
52
+ @m_props[p.code] << p.get_value
53
+ end
54
+ @m_props
55
+ end
56
+
57
+ # Если мы спрашиваем iblock_element.post
58
+ # то он ищет ключ :post_id в свойствах элемента
59
+ # и если находит, то возвращает Post.find_by_id(properties[:post_id])
60
+ #
61
+ def method_missing(method, *args)
62
+ id_name = "#{method}_id".to_sym
63
+ if properties and properties.include?(id_name)
64
+ # TODO Проверять на наличие такого класса и то что он ActiveRecord
65
+ # Кешировать
66
+ method.to_s.capitalize.constantize.find_by_id(properties[id_name])
67
+ else
68
+ super
69
+ end
70
+ end
71
+
72
+ def self.set_iblock_id(id)
73
+ @iblock_id = id
74
+ @iblock_properties = IblockProperty.where(:iblock_id => id).inject({}){ |a,e| a[e.code] = e.id; a }
75
+
76
+ prop_s_class = "::IblockElementPropS#{id}"
77
+ prop_m_class = "::IblockElementPropM#{id}"
78
+
79
+ has_one :property_set, :class_name => prop_s_class, :foreign_key => 'iblock_element_id', :autosave => true
80
+ has_many :m_prop_values, :class_name => prop_m_class, :foreign_key => 'iblock_element_id'
81
+
82
+ default_scope where(:iblock_id => id, :active => 'Y')
83
+ end
84
+
85
+ private
86
+
87
+ def initialize_properties
88
+ # TODO Могу повторяться именя в m_props, ругаться чтоли
89
+ @properties = (s_props ? s_props.properties : {}).merge m_props
90
+
91
+ # TODO Переписать на автоматическое определение названия свойства в моделях property_set и m_prop_values
92
+ # чтобы уйти от хеша @properties (оставить его массивом для дебаггинга)
93
+
94
+ # TODO Сделать в элементе автоделегейт
95
+ @properties.keys.each do |prop|
96
+ # TODO Перенести на прямой вызов объектов s_props/m_props
97
+ instance_eval "def #{prop}; @properties[:#{prop}]; end"
98
+ instance_eval "def #{prop}=(val); @properties[:#{prop}]=property_set.#{prop}=val; end"
99
+ end
100
+ end
101
+
102
+ end
103
+
104
+
105
+ # Это здесь для того чтобы при перезагрузке в development
106
+ # режиме заново создавались ассоциации iblock_element_prop_s3
107
+ # TODO переделать на более элегантное решение
108
+ Iblock.all.map &:init_property_models
@@ -0,0 +1,6 @@
1
+ class IblockElementProperty < ActiveRecord::Base
2
+ set_table_name :b_iblock_element_property
3
+
4
+ belongs_to :iblock_property
5
+ belongs_to :iblock_element
6
+ end
@@ -0,0 +1,6 @@
1
+ # -*- coding: utf-8 -*-
2
+ class IblockField < ActiveRecord::Base
3
+ set_table_name :b_iblock_fields
4
+
5
+ belongs_to :iblock
6
+ end
@@ -0,0 +1,6 @@
1
+ # -*- coding: utf-8 -*-
2
+ class IblockGroup < ActiveRecord::Base
3
+ set_table_name :b_iblock_group
4
+
5
+ belongs_to :iblock
6
+ end
@@ -0,0 +1,32 @@
1
+ # -*- coding: utf-8 -*-
2
+ class IblockProperty < ActiveRecord::Base
3
+ set_table_name :b_iblock_property
4
+
5
+ belongs_to :iblock
6
+
7
+ # TODO Что это за link_iblock?
8
+ belongs_to :link_iblock, :class_name=>'Iblock'
9
+
10
+ has_many :iblock_property_enums, :foreign_key=>:property_id
11
+ has_many :iblock_element_properties
12
+
13
+ cattr_accessor :cache
14
+
15
+ class << self
16
+ def find(id)
17
+ cache_all unless @@cache
18
+ @@cache[id] or raise "Не найдено такое свойство iblock_property #{id}"
19
+ end
20
+
21
+ # Запускается в ./lib/bitrix_on_rails при загрузке
22
+ def cache_all
23
+ @@cache = IblockProperty.all.inject({}) { |hash, prop| hash[prop.id]=prop; hash }
24
+ end
25
+ end
26
+
27
+ def code
28
+ val = read_attribute('code')
29
+ return nil if val.nil?
30
+ val.downcase.to_sym
31
+ end
32
+ end
@@ -0,0 +1,6 @@
1
+ # -*- coding: utf-8 -*-
2
+ class IblockPropertyEnum < ActiveRecord::Base
3
+ set_table_name :b_iblock_property_enum
4
+
5
+ belongs_to :iblock_property, :foreign_key=>:property_id
6
+ end
@@ -0,0 +1,30 @@
1
+ # -*- coding: utf-8 -*-
2
+ class IblockSection < ActiveRecord::Base
3
+ class << self
4
+ @iblock_id = nil
5
+
6
+ def iblock_id
7
+ @iblock_id
8
+ end
9
+ end
10
+
11
+ set_table_name :b_iblock_section
12
+
13
+ belongs_to :iblock
14
+
15
+ default_scope order(:sort)
16
+
17
+ has_many :direct_iblock_elements, :class_name=>'IblockElement'
18
+
19
+ has_many :iblock_section_elements
20
+ has_many :iblock_elements, :through => :iblock_section_elements
21
+
22
+ def self.set_iblock_id(id)
23
+ @iblock_id = id
24
+ default_scope where(:iblock_id => id, :active => 'Y')
25
+ end
26
+
27
+ def to_s
28
+ name
29
+ end
30
+ end
@@ -0,0 +1,8 @@
1
+ # -*- coding: utf-8 -*-
2
+ class IblockSectionElement < ActiveRecord::Base
3
+ set_table_name :b_iblock_section_element
4
+
5
+ belongs_to :iblock_section
6
+ belongs_to :iblock_element
7
+ belongs_to :additional_property, :class_name=>'IblockProperty'
8
+ end
@@ -0,0 +1,5 @@
1
+ class IblockType < ActiveRecord::Base
2
+ set_table_name :b_iblock_type
3
+
4
+ has_many :blocks, :class_name=>"Iblock"
5
+ end
@@ -0,0 +1,77 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{bitrix_on_rails}
8
+ s.version = "0.1.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Danil Pismenny"]
12
+ s.date = %q{2011-08-02}
13
+ s.description = %q{Использование инфоблоков 1С-Битрикс в Ruby On Rails проектах}
14
+ s.email = %q{danil@orionet.ru}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README",
18
+ "README.rdoc"
19
+ ]
20
+ s.files = [
21
+ ".document",
22
+ "Gemfile",
23
+ "Gemfile.lock",
24
+ "LICENSE.txt",
25
+ "README",
26
+ "README.rdoc",
27
+ "Rakefile",
28
+ "VERSION",
29
+ "app/models/iblock.rb",
30
+ "app/models/iblock_element.rb",
31
+ "app/models/iblock_element_property.rb",
32
+ "app/models/iblock_field.rb",
33
+ "app/models/iblock_group.rb",
34
+ "app/models/iblock_property.rb",
35
+ "app/models/iblock_property_enum.rb",
36
+ "app/models/iblock_section.rb",
37
+ "app/models/iblock_section_element.rb",
38
+ "app/models/iblock_type.rb",
39
+ "bitrix_on_rails.gemspec",
40
+ "init.rb",
41
+ "lib/active_record/connection_adapters/mysql2_downcase_adapter.rb",
42
+ "lib/bitrix_on_rails.rb",
43
+ "lib/bitrix_on_rails/active_record.rb",
44
+ "lib/bitrix_on_rails/engine.rb",
45
+ "lib/bitrix_on_rails/iblock_element_prop_m.rb",
46
+ "lib/bitrix_on_rails/iblock_element_prop_s.rb",
47
+ "test/helper.rb",
48
+ "test/test_bitrix_on_rails.rb"
49
+ ]
50
+ s.homepage = %q{http://github.com/dapi/bitrix_on_rails}
51
+ s.licenses = ["MIT"]
52
+ s.require_paths = ["lib"]
53
+ s.rubygems_version = %q{1.6.2}
54
+ s.summary = %q{Работа с инфоблоками 1С-Битрикс}
55
+
56
+ if s.respond_to? :specification_version then
57
+ s.specification_version = 3
58
+
59
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
60
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
61
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
62
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
63
+ s.add_development_dependency(%q<rcov>, [">= 0"])
64
+ else
65
+ s.add_dependency(%q<shoulda>, [">= 0"])
66
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
67
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
68
+ s.add_dependency(%q<rcov>, [">= 0"])
69
+ end
70
+ else
71
+ s.add_dependency(%q<shoulda>, [">= 0"])
72
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
73
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
74
+ s.add_dependency(%q<rcov>, [">= 0"])
75
+ end
76
+ end
77
+
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'bitrix_on_rails'
@@ -0,0 +1,76 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Just use 'mysql2_downcase' adapter in database.yml
3
+ #
4
+
5
+ require 'active_record/connection_adapters/mysql2_adapter'
6
+
7
+ module ActiveRecord
8
+ class Base
9
+ # Establishes a connection to the database that's used by all Active Record objects.
10
+ def self.mysql2_downcase_connection(config)
11
+ config[:username] = 'root' if config[:username].nil?
12
+
13
+ if Mysql2::Client.const_defined? :FOUND_ROWS
14
+ config[:flags] = Mysql2::Client::FOUND_ROWS
15
+ end
16
+
17
+ client = Mysql2::Client.new(config.symbolize_keys)
18
+ options = [config[:host], config[:username], config[:password], config[:database], config[:port], config[:socket], 0]
19
+ ConnectionAdapters::Mysql2DowncaseAdapter.new(client, logger, options, config)
20
+ # ActiveRecord::Base.mysql2_connection(config)
21
+ end
22
+ end
23
+
24
+ class Result
25
+
26
+ # Это выполняется через ActiveRecord::Result.new в mysql2_adapter
27
+ # при выполнении запроса
28
+ def initialize(columns, rows)
29
+ @columns = columns.map { |c| c.downcase }
30
+ @rows = rows
31
+ @hash_rows = nil
32
+ end
33
+ end
34
+
35
+ module ConnectionAdapters
36
+ class Column
37
+
38
+ alias_method :old_initialize, :initialize
39
+
40
+ # Это выполняется при выборке списка аттрибутов на уровне класса
41
+ #
42
+ def initialize(name, default, sql_type = nil, null = true)
43
+ old_initialize name.downcase, default, sql_type, null
44
+ end
45
+
46
+ end
47
+
48
+ class Mysql2DowncaseAdapter < Mysql2Adapter
49
+
50
+ ADAPTER_NAME = 'Mysql2Downcase'
51
+
52
+ # Надо бы глобально сделать тут:
53
+ # def execute(sql, name = nil)
54
+ # debugger
55
+ # end
56
+
57
+ # Это чтобы нормально определся primary_key
58
+ def pk_and_sequence_for(table)
59
+ keys = []
60
+ result = execute("DESCRIBE #{quote_table_name(table)}", 'SCHEMA')
61
+ result.each(:symbolize_keys => true, :as => :hash) do |row|
62
+ keys << row[:Field].downcase if row[:Key] == "PRI"
63
+ end
64
+ keys.length == 1 ? [keys.first, nil] : nil
65
+ end
66
+
67
+ end
68
+ end
69
+ end
70
+
71
+
72
+ # Возможно понадобится исправить этот метод
73
+ # quote_column_name
74
+
75
+ # Хороший пример адаптера - http://virtuoso.rubyforge.org/activerecord-mysql2spatial-adapter/
76
+ # https://github.com/dazuma/activerecord-mysql2spatial-adapter
@@ -0,0 +1,21 @@
1
+ # -*- coding: utf-8 -*-
2
+ # require 'rails'
3
+
4
+ module BitrixOnRails
5
+ end
6
+
7
+ require 'active_record'
8
+
9
+ require 'bitrix_on_rails/active_record'
10
+ require 'bitrix_on_rails/iblock_element_prop_s'
11
+ require 'bitrix_on_rails/iblock_element_prop_m'
12
+ # require 'bitrix_on_rails/engine'
13
+
14
+ # ActiveRecord::Base.connection.tables
15
+
16
+ ActiveRecord::Base.extend BitrixOnRails::ActiveRecord
17
+
18
+ # Просто подгружаем модель, тогда в ней появятся ассоциации типа iblock_element_prop_s3
19
+ IblockElement.class
20
+
21
+ # IblockProperty.cache_all
@@ -0,0 +1,28 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ IblockElement.class
4
+
5
+ module BitrixOnRails
6
+ module ActiveRecord
7
+
8
+ def has_infoblock(iblock_id, property_name, &blk)
9
+ prop_s_name = "iblock_element_prop_s#{iblock_id}".to_sym
10
+ has_one prop_s_name, :foreign_key=>property_name, :class_name=>"::IblockElementPropS#{iblock_id}", :autosave => true
11
+
12
+ element_class_name = self.name + 'Element'
13
+ unless Kernel.const_defined?(element_class_name)
14
+ element_class = Class.new(IblockElement) do
15
+ set_iblock_id iblock_id
16
+ end
17
+
18
+ if block_given?
19
+ element_class.instance_eval(&blk)
20
+ end
21
+
22
+ self.const_set(element_class_name, element_class)
23
+ end
24
+
25
+ has_one :iblock_element, :through => prop_s_name, :class_name => element_class_name, :autosave => true
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,4 @@
1
+ module BitrixOnRails
2
+ class Engine < Rails::Engine
3
+ end
4
+ end
@@ -0,0 +1,64 @@
1
+ # -*- coding: utf-8 -*-
2
+ # -*- coding: utf-8 -*-
3
+ module BitrixOnRails::IblockElementPropM
4
+ def acts_as_iblock_element_prop_m(id)
5
+ extend ClassMethods
6
+ include InstanceMethods
7
+
8
+ # Убираем лишнюю s вконце
9
+ #set_table_name 'b_'+table_name.chop
10
+ set_table_name "b_iblock_element_prop_m#{id}"
11
+
12
+ # delegate :code, :to=>:property
13
+
14
+ belongs_to :iblock_element
15
+ belongs_to :iblock_property
16
+ end
17
+
18
+ module ClassMethods
19
+ def init
20
+ self.to_s=~/(\d+)/
21
+ iblock_id = $1.to_i
22
+ IblockElement.send :has_many, "iblock_element_prop_m#{iblock_id}".to_sym, :class_name=>"::IblockElementPropM#{iblock_id}"
23
+ end
24
+ end
25
+
26
+ module InstanceMethods
27
+
28
+ def property
29
+ # Достаем кешированный вариант
30
+ IblockProperty.find(iblock_property_id)
31
+ end
32
+
33
+ def code
34
+ @code||=property.code
35
+ end
36
+
37
+ def get_value
38
+ case property.property_type
39
+ when 'S' # String
40
+ self.value
41
+ when 'N' # Numeric
42
+ self.value_num.to_i # Когда BigDecimal - не приятно
43
+ # when 'E' # Enum?
44
+ # self.value_enum
45
+ # when 'L' # WTF?
46
+ else
47
+ raise "Не установленный тип (#{iblock_property.property_type}) свойства (#{self.class} #{id})"
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+
54
+ # Table b_iblock_element_prop_m7
55
+ # ==============================
56
+ # ID, IBLOCK_ELEMENT_ID, IBLOCK_PROPERTY_ID, VALUE, VALUE_ENUM, VALUE_NUM, DESCRIPTION
57
+ # ------------------------------
58
+ # ID int(11) PK
59
+ # IBLOCK_ELEMENT_ID int(11)
60
+ # IBLOCK_PROPERTY_ID int(11)
61
+ # VALUE text
62
+ # VALUE_ENUM int(11)
63
+ # VALUE_NUM decimal(18,4)
64
+ # DESCRIPTION varchar(255)
@@ -0,0 +1,119 @@
1
+ # -*- coding: utf-8 -*-
2
+ module BitrixOnRails::IblockElementPropS
3
+ def acts_as_iblock_element_prop_s(id)
4
+ extend ClassMethods
5
+ include InstanceMethods
6
+
7
+ @m_prop_class = "IblockElementPropM#{id}"
8
+ # Название свойства сохраняется только для наглядности, чтобы можно было через консоль понять
9
+ # что за свойство.
10
+ @m_props = IblockProperty.where(:iblock_id => id).inject({}){ |a,e| a[e.code] = e.id if e.multiple == 'Y'; a }
11
+
12
+ # Убираем лишнюю s вконце
13
+ #set_table_name 'b_'+table_name.chop
14
+ set_table_name "b_iblock_element_prop_s#{id}"
15
+
16
+ belongs_to :iblock_element
17
+
18
+ # Хеш соответсвия кодов свойств названию полей: post_id -> property_149
19
+ cattr_accessor :properties
20
+
21
+ # Хеш свойств объекта по кодам
22
+ attr_accessor :properties
23
+
24
+ after_find do
25
+ self.properties = self.class.properties.keys.inject({}) { |hash, prop| hash[prop] = send prop; hash }
26
+ end
27
+
28
+ before_save do
29
+ self.class.m_props.each_value { |id|
30
+ values = m_prop_values(id)
31
+ self.send("property_#{id}=", PHP.serialize({'VALUE' => values, 'DESCRIPTION' => Array.new(values.size, nil)}))
32
+ # self.send("property_#{id}=", PhpSerialization.dump({'VALUE' => values, 'DESCRIPTION' => Array.new(values.size, nil)}))
33
+ }
34
+ end
35
+
36
+ end
37
+
38
+ def create_element_association
39
+ IblockElement.send :has_one, "iblock_element_prop_s#{id}".to_sym, :class_name=>"::IblockElementPropS#{id}"
40
+ end
41
+
42
+ module ClassMethods
43
+
44
+ # code - врое как кодовое название свойства
45
+ # name - русское описание
46
+
47
+ # Дальше идут пары:
48
+ # property_120
49
+ # description_120
50
+ # ..
51
+ # определяются они в iblock.iblock_properties
52
+
53
+ # Берем список свойств из таблицы iblock_properties
54
+ # и создаем такие же методы для опроса и установки, чтобы можно было использовать
55
+ # их напрямую:
56
+ #
57
+ # self.кодовое_имя_свойства
58
+ #
59
+ # Например:
60
+ #
61
+ # self.post_id вместо self.property_120
62
+ #
63
+ def init
64
+ self.to_s=~/(\d+)/
65
+ iblock_id = $1.to_i
66
+
67
+ IblockElement.send :has_one, "iblock_element_prop_s#{iblock_id}".to_sym, :class_name=>"::IblockElementPropS#{iblock_id}"
68
+
69
+ self.properties = {}
70
+ attribute_names.select {|a| a[0,4]=='prop' }.each do |name|
71
+ prop_id = name.slice(9,5).to_i
72
+ iblock_property = IblockProperty.find(prop_id)
73
+ code = iblock_property.code.downcase.to_sym
74
+ self.properties[code] = name
75
+ define_method code do
76
+ val = send name
77
+ return val.to_i if val.is_a?(BigDecimal)
78
+
79
+ # Вот так мы проверяем сериализацию
80
+ # Есть еще вариант что поле сериализовано если iblock_property.user_type=='HTML'
81
+ #
82
+ if val.is_a? String and val.length>5 and val[0,3]=~/[a-z]:\d/
83
+ res = PHP.unserialize(val)
84
+ # res = PhpSerialization.load(val)
85
+ return iblock_property.property_type=='S' && res.is_a?(Hash) && res.include?('TEXT') ? res['TEXT'] : res
86
+ end
87
+ val
88
+ end
89
+ define_method "#{code}=" do |val|
90
+ send "#{name}=", val
91
+ end
92
+ eval "def self.find_by_#{code}(val); find_by_#{name}(val); end"
93
+ end
94
+ end
95
+ end
96
+
97
+ module InstanceMethods
98
+
99
+ # Возвращает десериализованное (при необходимости) значение свойства
100
+ #
101
+ # prop - код свойства (post_id к примеру)
102
+ def get_value(prop)
103
+ send prop
104
+ end
105
+
106
+ def m_prop_values(prop_id)
107
+ self.class.m_prop_class.where(:iblock_element_id => self.id, :iblock_property_id => prop_id).collect { |e| e.value }
108
+ end
109
+
110
+ def create_m_prop_value(prop_id, value)
111
+ self.class.m_prop_class.create(:iblock_element_id => self.id, :iblock_property_id => prop_id, :value => value)
112
+ end
113
+
114
+ def destroy_m_prop_value(prop_id, value)
115
+ m_props = self.class.m_prop_class.where(:iblock_element_id => self.iblock_element_id, :iblock_property_id => prop_id, :value => value)
116
+ m_props.each { |p| p.destroy } if m_props.any?
117
+ end
118
+ end
119
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ require 'bitrix_on_rails'
16
+
17
+ class Test::Unit::TestCase
18
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestBitrixOnRails < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,125 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bitrix_on_rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Danil Pismenny
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-08-02 00:00:00.000000000 +04:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: shoulda
17
+ requirement: &2155895220 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: *2155895220
26
+ - !ruby/object:Gem::Dependency
27
+ name: bundler
28
+ requirement: &2155894360 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 1.0.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: *2155894360
37
+ - !ruby/object:Gem::Dependency
38
+ name: jeweler
39
+ requirement: &2155893580 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ version: 1.6.4
45
+ type: :development
46
+ prerelease: false
47
+ version_requirements: *2155893580
48
+ - !ruby/object:Gem::Dependency
49
+ name: rcov
50
+ requirement: &2155892440 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ type: :development
57
+ prerelease: false
58
+ version_requirements: *2155892440
59
+ description: Использование инфоблоков 1С-Битрикс в Ruby On Rails проектах
60
+ email: danil@orionet.ru
61
+ executables: []
62
+ extensions: []
63
+ extra_rdoc_files:
64
+ - LICENSE.txt
65
+ - README
66
+ - README.rdoc
67
+ files:
68
+ - .document
69
+ - Gemfile
70
+ - Gemfile.lock
71
+ - LICENSE.txt
72
+ - README
73
+ - README.rdoc
74
+ - Rakefile
75
+ - VERSION
76
+ - app/models/iblock.rb
77
+ - app/models/iblock_element.rb
78
+ - app/models/iblock_element_property.rb
79
+ - app/models/iblock_field.rb
80
+ - app/models/iblock_group.rb
81
+ - app/models/iblock_property.rb
82
+ - app/models/iblock_property_enum.rb
83
+ - app/models/iblock_section.rb
84
+ - app/models/iblock_section_element.rb
85
+ - app/models/iblock_type.rb
86
+ - bitrix_on_rails.gemspec
87
+ - init.rb
88
+ - lib/active_record/connection_adapters/mysql2_downcase_adapter.rb
89
+ - lib/bitrix_on_rails.rb
90
+ - lib/bitrix_on_rails/active_record.rb
91
+ - lib/bitrix_on_rails/engine.rb
92
+ - lib/bitrix_on_rails/iblock_element_prop_m.rb
93
+ - lib/bitrix_on_rails/iblock_element_prop_s.rb
94
+ - test/helper.rb
95
+ - test/test_bitrix_on_rails.rb
96
+ has_rdoc: true
97
+ homepage: http://github.com/dapi/bitrix_on_rails
98
+ licenses:
99
+ - MIT
100
+ post_install_message:
101
+ rdoc_options: []
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ segments:
111
+ - 0
112
+ hash: 3152042687155228433
113
+ required_rubygems_version: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ! '>='
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ requirements: []
120
+ rubyforge_project:
121
+ rubygems_version: 1.6.2
122
+ signing_key:
123
+ specification_version: 3
124
+ summary: Работа с инфоблоками 1С-Битрикс
125
+ test_files: []