Is extending SugarACLStrategy working properly in Sugar 11?


In the past, I have been able to follow this guide I am trying to make individual rows in a module ReadOnly based upon the values of fields in a Bean. It doesn't appear that the SugarACLReadOnly is working properly in Sugar 11.0.2. Is that correct? Does it not work properly?

  • FWIW I am using an ACLLock based on that guide by   and it still works in 11.0.2 Pro
    In my implementation I make records read only for regular users (Admin can still edit) in a custom module based on a date field.


    class SugarACLLockSalesGoals extends SugarACLStrategy
        // allowed user ids
        protected $user_ids_to_allow = array(
        // denied actions
        protected $denied_actions = array(
        // our custom method to check permissions
        protected function _canUserWrite($context)
            $date = new DateTime("now",new DateTimeZone('UTC')); //now in UTC
            $today = $date->format('Y-m-d H:i:s');
            // retrieve user from context
            $user = $this->getCurrentUser($context);
            if($user->isAdmin() || in_array($user->id, $this->user_ids_to_allow)) {
                return true;
            } else {
                // check additional beans conditions here
                // is there a bean?
                if(!empty($context['bean']) && is_object($context['bean']) && !empty($context['bean']->id)) {
                    // do we have a mapped known object instance?
                    if($context['bean'] instanceof SugarBean && !empty($context['bean']->module_dir) && $context['bean']->module_dir == 'sgoal_SalesGoals') {
                        // retrieve the full bean as in some occastions (like listviews), not all fields are available on the context
                        $bean = BeanFactory::getBean($context['bean']->module_dir, $context['bean']->id);
                        if($bean->goal_end_date_c >= $today){
                          //if the goal end date is in the future, proceed and give permission
                          return true;
                        // default do not allow once here
                        return false;
                return true;
        // runtime access check
        public function checkAccess($module, $view, $context)
            $view = SugarACLStrategy::fixUpActionName($view);
            // if it is not a blocked action, or there is no bean, allow it
            if(!in_array($view, $this->denied_actions) || !isset($context['bean'])) {
                return true;
            // can user write?
            if($this->_canUserWrite($context)) return true;
            // everyone else for everything else is denied
            return false;
        // mostly for front-end access checks (cached on the application, per user)
        public function getUserAccess($module, $access_list = array(), $context = array())
            // retrieve original ACL
            $acl = parent::getUserAccess($module, $access_list, $context);
            // if user can't write
            if(!$this->_canUserWrite($context)) {
                // override access, disable access where required if not admin and not special user
                foreach($acl as $access => $value) {
                    if(in_array($access, $this->denied_actions)) {
                        $acl[$access] = 0;
            // return modified acl  
            return $acl;

  • Thanks !

    This is quite cool! I keep seeing the same code in more and more instances I touch, which gives me a warm and fuzzy feeling Slight smile

    Yes  it still works today. But.. acl can be finicky, it is easy to "mess it up" or create a performance nightmare.

    There are some parts of ACL that are cached when a user logs in (eg: module level permissions), and some part that happen for every piece of data/field. If you leverage the correct parts of the acl, you should be able to achieve what you are asking.



    Enrico Simonetti

    Senior Manager, Integrations Development

    SugarCRM Inc