1

I have some logics that I bashed together a while ago, and now I need to make it generic so as to look for a parent on an infinite number of parent-levels. What would be the most efficient way of structuring this code as a loop instead of my spaghetti-nests?

public function hasAccess($user,$container)
{

    //If user is admin
    $roles = $user->getRoles();
    foreach ($roles as $role) {
        if ($role == 'ROLE_ADMIN') {
            return true;
        }    
    };

    //Or if user has access to object
    foreach ($container->getUsers() as $userWithAccess) {
        if ($userWithAccess == $user) {
            return true;
        }
    }

    //Or if object has parent and user has access to the parent
    $parent = $container->getParent();
    if ($parent) {
        foreach ($parent->getUsers() as $userWithAccess) {
            if ($userWithAccess == $user) {
                return true;
            }
        }
    }

    //Or if object has grandparent and user has access to the grandparent
    $parent = $container->getParent();
    if ($parent) {
        $grandparent = $parent->getParent();   
        if ($grandparent) {        
            foreach ($grandparent->getUsers() as $userWithAccess) {
                if ($userWithAccess == $user) {
                    return true;
                }
            }
        }
    }     

    //Or if object has greatgrandparent (=entire company access) and user has access to the greatgrandparent ('entire company')
    $parent = $container->getParent();
    if ($parent) {
        $grandparent = $parent->getParent();   
        if ($grandparent) {
            $greatgrandparent = $grandparent->getParent();   
                if ($greatgrandparent) {                        
                foreach ($greatgrandparent->getUsers() as $userWithAccess) {
                    if ($userWithAccess == $user) {
                        return true;
                    }
                }
            }
        }
    }

    //Or if object has greatgreatgrandparent (=entire company if this content lives within a module, otherwise this level doesn't exist) and user has access to the greatgreatgrandparent (ie entire company)
    $parent = $container->getParent();
    if ($parent) {
        $grandparent = $parent->getParent();   
        if ($grandparent) {
            $greatgrandparent = $grandparent->getParent();   
            if ($greatgrandparent) {  
                $greatgreatgrandparent = $greatgrandparent->getParent();                        
                if ($greatgreatgrandparent) {                       
                    foreach ($greatgreatgrandparent->getUsers() as $userWithAccess) {
                        if ($userWithAccess == $user) {
                            return true;
                        }
                    }
                }
            }
        }
    }        

    //At the moment, access to 'entire company' does NOT grant access to monitors outside the hierarchy.
    //It is still possible to add privileges to those individual monitors.


    //If none of the above has matched...
    return false;

}
Matt Welander
  • 8,234
  • 24
  • 88
  • 138
  • 1
    wow thats a rabbit warren. Look at self recursion should do what you want :) – Dave Dec 16 '13 at 16:47
  • read these most can be modified to do what you want http://stackoverflow.com/questions/4627208/php-object-parent-child-recursion http://stackoverflow.com/questions/11990531/a-recursive-function-to-sort-through-parent-and-child-nodes-in-php-using-a-forea http://stackoverflow.com/questions/18234510/php-recursive-function-to-display-family-tree-with-parents-and-partners This is the thread i was initially looking for and couldn't find http://stackoverflow.com/questions/10729211/recursive-function-inside-class-with-foreach-changes-public-value-where-it-shoul – Dave Dec 16 '13 at 16:52

2 Answers2

1

Maybe a while loop that checks for the existence of $parent, checking access for all of them users then making $parent parent the current one. Something like this:

$parent = $container->getParent();
while ($parent) {
  foreach ($parent->getUsers() as $userWithAccess) {
    if ($userWithAccess == $user) {
      return true;
    }
  }
  $parent = $parent->getParent();
}
MurifoX
  • 14,991
  • 3
  • 36
  • 60
1

If you're trying to get the ancestor, using while may help:

$ancestor = $parent;
while($parent = $ancestor->getParent())
  $ancestor = $parent;

// foreach($ancestor->getUsers() ...

To get the 4th parent, just add a counter variable and break the loop if $counter > 4

Also you could probably use in_array() to avoid all those foreach statements (if the get* methods return arrays)

nice ass
  • 16,471
  • 7
  • 50
  • 89