forked from chicks/sugarcrm
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor Associations for Cleanliness(tm)
- Loading branch information
Showing
8 changed files
with
208 additions
and
87 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,4 @@ | ||
require 'sugarcrm/associations/association' | ||
require 'sugarcrm/associations/association_cache' | ||
require 'sugarcrm/associations/association_methods' | ||
require 'sugarcrm/associations/association_collection' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
module SugarCRM | ||
# Represents an association and it's metadata | ||
class Association | ||
# Returns an array of Association objects | ||
class << self | ||
def register(owner) | ||
associations = [] | ||
owner.link_fields.each_pair do |link_field,attributes| | ||
associations << Association.new(owner,link_field,attributes) | ||
end | ||
associations | ||
end | ||
end | ||
|
||
attr :owner | ||
attr :target | ||
attr :link_field | ||
attr :attributes | ||
attr :methods | ||
|
||
def initialize(owner,link_field,attributes) | ||
@owner = owner | ||
@link_field = link_field | ||
@attributes = attributes | ||
@target = resolve_target | ||
@methods = define_methods | ||
self | ||
end | ||
|
||
def to_s | ||
"#{@link_field} => [#{@methods.join ","}] " | ||
end | ||
|
||
protected | ||
|
||
# Attempts to determine the class of the target in the association | ||
def resolve_target | ||
# Use the link_field name first | ||
klass = @link_field.singularize.camelize | ||
return "SugarCRM::#{klass}".constantize if SugarCRM.const_defined? klass | ||
|
||
# Use the link_field attribute "module" | ||
if @attributes["module"].length > 0 | ||
module_name = SugarCRM::Module.find(@attributes["module"]) | ||
return "SugarCRM::#{module_name.klass}".constantize if SugarCRM.const_defined? module_name.klass | ||
end | ||
# Use the link_field attribute "relationship" | ||
if @attributes["relationship"].length > 0 | ||
klass = humanized_link_name(@attributes["relationship"]).singularize.camelize | ||
return "SugarCRM::#{klass}".constantize if SugarCRM.const_defined? klass | ||
end | ||
end | ||
|
||
# Generates the association proxy method for related module | ||
def define_method(link_field, pretty_name=nil) | ||
pretty_name ||= link_field | ||
@owner.class.module_eval %Q? | ||
def #{pretty_name} | ||
query_association :#{link_field} | ||
end | ||
? | ||
pretty_name | ||
end | ||
|
||
# Defines methods for accessing the association target on the owner class. | ||
# If the link_field name includes the owner class name, it is stripped before | ||
# creating the method. If this occurs, we also create an alias to the stripped | ||
# method using the full link_field name. | ||
def define_methods | ||
methods = [] | ||
pretty_name = humanized_link_name(@link_field) | ||
methods << define_method(pretty_name) | ||
if pretty_name != @link_field | ||
@owner.class.module_eval %Q? | ||
alias :#{@link_field} #{pretty_name} | ||
? | ||
methods << @link_field | ||
end | ||
methods | ||
end | ||
|
||
# Return the name of the relationship excluding the owner part of the name. | ||
# e.g. if a custom relationship is defined in Studio between Tasks and Documents, | ||
# the link_field will be `tasks_documents` but a human would call the relationship `documents` | ||
def humanized_link_name(link_field) | ||
# Split the relationship name into parts | ||
# "contact_accounts" => ["contact","accounts"] | ||
m = link_field.split(/_/) | ||
# Determine the parts we don't want | ||
# SugarCRM::Contact => ["contacts", "contact"] | ||
o = @owner.class._module.table_name | ||
# Use array subtraction to remove parts representing the owner side of the relationship | ||
# ["contact", "accounts"] - ["contacts", "contact"] => ["accounts"] | ||
t = m - [o, o.singularize] | ||
# Reassemble whatever's left | ||
# "accounts" | ||
t.join('_') | ||
end | ||
|
||
end | ||
end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
module SugarCRM; module AssociationCache | ||
|
||
attr :association_cache, false | ||
|
||
|
||
|
||
# Returns true if an association is cached | ||
def association_cached?(association) | ||
@association_cache.keys.include? association | ||
end | ||
|
||
protected | ||
|
||
# Returns true if an association collection has changed | ||
def associations_changed? | ||
@association_cache.values.each do |collection| | ||
return true if collection.changed? | ||
end | ||
false | ||
end | ||
|
||
def save_modified_associations | ||
@association_cache.values.each do |collection| | ||
if collection.changed? | ||
return false unless collection.save | ||
end | ||
end | ||
true | ||
end | ||
|
||
# Updates an association cache entry if it's been initialized | ||
def update_association_cache_for(association, target) | ||
# only add to the cache if the relationship has been queried | ||
@association_cache[association] << target if association_cached? association | ||
end | ||
|
||
# Resets the association cache | ||
def clear_association_cache | ||
@association_cache = {}.with_indifferent_access | ||
end | ||
end; end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.