[Jifty-commit] r3557 - in apps/CASPlus/trunk: lib/CASPlus/Model

jifty-commit at lists.jifty.org jifty-commit at lists.jifty.org
Tue Jun 26 09:15:08 EDT 2007


Author: sterling
Date: Tue Jun 26 09:15:08 2007
New Revision: 3557

Modified:
   apps/CASPlus/trunk/   (props changed)
   apps/CASPlus/trunk/lib/CASPlus/Model/User.pm

Log:
 r7775 at dynpc145:  andrew | 2007-06-23 10:42:56 -0500
 Added the recalculate_role_cache() method.


Modified: apps/CASPlus/trunk/lib/CASPlus/Model/User.pm
==============================================================================
--- apps/CASPlus/trunk/lib/CASPlus/Model/User.pm	(original)
+++ apps/CASPlus/trunk/lib/CASPlus/Model/User.pm	Tue Jun 26 09:15:08 2007
@@ -230,6 +230,162 @@
     return ${ $str->string_ref };
 }
 
+=head2 recalculate_role_cache
+
+  $user->recalculate_role_cache;
+
+This is a brute force method for rebuilding the L</member_roles> collection. This causes role memberships to be replaced by a complete recalculation for the current user.
+
+This is provided in case an external utility will be manipulating profiles without using the API that makes sure that roles are correct or if they become somehow corrupted. In general, however, this method is costly and does not need to be called regularly.
+
+=cut
+
+sub recalculate_role_cache {
+    my $self         = shift;
+    my $self_obj     = $self->profile;
+    my $self_profile = $self_obj->profile_definition;
+
+    die "Object/Profile mismatch." unless $self_obj->isa($self_profile->record_class);
+
+    # Queue used for breadth-first search
+    my @open_list = ([ $self_obj, $self_profile, $self_obj->unique_id ]);
+
+    # The roles that have been discovered
+    my %roles;
+
+    # Breadth-first search of parents
+    PARENT: while (my $parent = shift @open_list) {
+        my ($parent_obj, $parent_profile, $parent_path) = @$parent;
+        
+        # If it's a role profile, drop the role in place
+        if ($parent_profile->profile_type eq 'role') {
+            my $parent_role = $parent_obj->role_object;
+
+            # Don't continue if this role has already been added, the children
+            # can be ignored as well on the assumption that the role's children
+            # was already listed in @open_list
+            if ($roles{ $parent_role->id }) {
+                push @{ $roles{ $parent_role->id } }, $parent_path;
+                next PARENT;
+            }
+
+            $roles{ $parent_role->id } = [ $parent_role, $parent_path ];
+        }
+
+        # Find all the parents of the current object that might also contribute
+        # roles to the user
+        my $parent_relationships = $parent_profile->parent_relationships;
+        $parent_relationships->limit(
+            column => 'roles_propagate_to_children',
+            value  => 1,
+        );
+
+        # Iterate through the parents
+        while (my $parent_relationship = $parent_relationships->next) {
+            my $method = $parent_relationship->child_column->name;
+
+            # A one-to-many relationship
+            if ($parent_relationship->many_parents 
+                    and not $parent_relationship->many_children) {
+
+                # Iterate throught the grandparents
+                my $grandparents = $parent->$method;
+                while (my $grandparent_obj = $grandparents->next) {
+                    push @open_list, [ 
+                        $grandparent_obj, 
+                        $parent_relationship->relation_parent,
+                        $parent_path 
+                            . ':@' . $parent_relationship->id 
+                            . ':'  . $grandparent_obj->unique_id,
+                    ];
+                }
+            }
+
+            # A one-to-one or many-to-one relationship
+            elsif (!$parent_relationship->many_parents) {
+                my $grandparent_obj = $parent_obj->$method;
+
+                # Only add it to the list if the link exists
+                if ($grandparent_obj->id) {
+                    push @open_list, [
+                        $grandparent_obj,
+                        $parent_relationship->relation_parent,
+                        $parent_path 
+                            . ':@' . $parent_relationship->id 
+                            . ':'  . $grandparent_obj->unique_id,
+                    ];
+                }
+            }
+
+            # A many-to-many relationship
+            else {
+                my $grandparent_links = $parent_obj->$method;
+
+                # Similar to one-to-many, but an extra jump
+                while (my $grandparent_link = $grandparent_links->next) {
+                    my $grandparent_obj = $grandparent_link->parent;
+                    push @open_list, [ 
+                        $grandparent_obj, 
+                        $parent_relationship->relation_parent,
+                        $parent_path 
+                            . ':@' . $parent_relationship->id 
+                            . ':'  . $grandparent_obj->unique_id,
+                    ];
+                }
+            }
+        }
+    }
+
+    # Delete any removed roles
+    my $member_roles = $self->member_roles;
+    while (my $member_role = $member_roles->next) {
+
+        # Only delete the removed roles
+        unless ($roles{ $member_role->id }) {
+            my $cache_paths = $member_role->cache_paths;
+            while (my $path_cache = $cache_paths->next) {
+                $path_cache->delete;
+            }
+            $member_role->delete;
+        }
+    }
+
+    # Update/add existing/new roles
+    my $role_member = CASPlus::Model::RoleMember->new;
+    for my $role_info (values %roles) {
+        my $role        = shift @$role_info;
+        my %cache_paths = map { (":$_:" => 1) } @$role_info;
+
+        # Try to load it first
+        $role_member->load_by_cols( the_role => $role );
+
+        # If not found, create it
+        unless ($role_member->id) {
+            $role_member->create(
+                the_user => $self,
+                the_role => $role,
+            );
+        }
+
+        # Delete removed cache paths
+        my $cache_paths = $role_member->cache_paths;
+        while (my $path_cache = $cache_paths->next) {
+            # Keep it if it exists, but remove it from the add list
+            $path_cache->delete 
+                unless delete $cache_paths{ $path_cache->cache_path };
+        }
+
+        # All that should be left in %cache_paths are those to add, add'em
+        my $path_cache = CASPlus::Model::RoleMemberPathCache->new;
+        for my $cache_path (values %cache_paths) {
+            $path_cache->create(
+                role_member => $role_member,
+                cache_path  => $cache_path,
+            );
+        }
+    }
+}
+
 =head1 AUTHOR
 
 Andrew Sterling Hanenkamp, C<<hanenkamp at cpan.org>>>


More information about the Jifty-commit mailing list