public function enforce(string $ruleName, $user, $resource = null, array $options = []): bool
    {
        $this->errors = [];
        // If there is dynamic attributes, we pass them to the comparison manager
        // When a comparison will be performed, the passed values will be retrieved and used
        if (isset($options[ 'dynamic_attributes' ])) {
            $this->comparisonManager->setDynamicAttributes($options[ 'dynamic_attributes' ]);
        }
        // Retrieve cache value for the current rule and values if cache item is valid
        if (($cacheResult = isset($options[ 'cache_result' ]) && $options[ 'cache_result' ] === true) === true) {
            $cacheItem = $this->cacheManager->getItem("$ruleName-{$user->getId()}-" . (($resource !== null) ? $resource->getId() : ''), (isset($options[ 'cache_driver' ])) ? $options[ 'cache_driver' ] : null, (isset($options[ 'cache_ttl' ])) ? $options[ 'cache_ttl' ] : null);
            // We check if the cache value s valid before returning it
            if (($cacheValue = $cacheItem->get()) !== null) {
                return $cacheValue;
            }
        }
        $policyRules = $this->policyRuleManager->getRule($ruleName, $user, $resource);
        
        foreach ($policyRules as $policyRule) {
            // For each policy rule attribute, we retrieve the attribute value and proceed configured extra data
            foreach ($policyRule->getPolicyRuleAttributes() as $pra) {
                /** @var PolicyRuleAttribute $pra */
                $attribute = $pra->getAttribute();
                
                $getter_params = $this->prepareGetterParams($pra->getGetterParams(), $user, $resource);
                $attribute->setValue($this->attributeManager->retrieveAttribute($attribute, $user, $resource, $getter_params));
                if (count($pra->getExtraData()) > 0) {
                    $this->processExtraData($pra, $user, $resource);
                }
                $this->comparisonManager->compare($pra);
            }
            // The given result could be an array of rejected attributes or true
            // True means that the rule is correctly enforced for the given user and resource
            $this->errors = $this->comparisonManager->getResult();
            if (count($this->errors) === 0) {
                break;
            }
        }
        if ($cacheResult) {
            $cacheItem->set((count($this->errors) > 0) ? $this->errors : true);
            $this->cacheManager->save($cacheItem);
        }
        return count($this->errors) === 0;
    }