<?xml version="1.0" encoding="UTF-8"?>
<!-- Reviewed: no -->
<sect1 id="zend.acl.advanced">

    <title>Advanced Usage</title>

    <sect2 id="zend.acl.advanced.storing">

        <title>Storing ACL Data for Persistence</title>

        <para>
            <classname>Zend_Acl</classname> was designed in such a way that it does not require any
            particular backend technology such as a database or cache server for storage of the ACL
            data. Its complete PHP implementation enables customized administration tools to be
            built upon <classname>Zend_Acl</classname> with relative ease and flexibility. Many
            situations require some form of interactive maintenance of the ACL, and
            <classname>Zend_Acl</classname> provides methods for setting up, and querying against,
            the access controls of an application.
        </para>

        <para>
            Storage of ACL data is therefore left as a task for the developer, since use cases are
            expected to vary widely for various situations. Because <classname>Zend_Acl</classname>
            is serializable, ACL objects may be serialized with PHP's
            <ulink url="http://php.net/serialize"><code>serialize()</code></ulink> function, and
            the results may be stored anywhere the developer should desire, such as a file,
            database, or caching mechanism.
        </para>

    </sect2>

    <sect2 id="zend.acl.advanced.assertions">

        <title>Writing Conditional ACL Rules with Assertions</title>

        <para>
            Sometimes a rule for allowing or denying a role access to a resource should not be
            absolute but dependent upon various criteria. For example, suppose that certain access
            should be allowed, but only between the hours of 8:00am and 5:00pm. Another example
            would be denying access because a request comes from an IP address that has been
            flagged as a source of abuse. <classname>Zend_Acl</classname> has built-in support for
            implementing rules based on whatever conditions the developer needs.
        </para>

        <para>
            <classname>Zend_Acl</classname> provides support for conditional rules with
            <classname>Zend_Acl_Assert_Interface</classname>. In order to use the rule assertion
            interface, a developer writes a class that implements the <code>assert()</code> method
            of the interface:
        </para>

        <programlisting role="php"><![CDATA[
class CleanIPAssertion implements Zend_Acl_Assert_Interface
{
    public function assert(Zend_Acl $acl,
                           Zend_Acl_Role_Interface $role = null,
                           Zend_Acl_Resource_Interface $resource = null,
                           $privilege = null)
    {
        return $this->_isCleanIP($_SERVER['REMOTE_ADDR']);
    }

    protected function _isCleanIP($ip)
    {
        // ...
    }
}
]]></programlisting>

        <para>
            Once an assertion class is available, the developer must supply an instance of the
            assertion class when assigning conditional rules. A rule that is created with an
            assertion only applies when the assertion method returns true.
        </para>

        <programlisting role="php"><![CDATA[
$acl = new Zend_Acl();
$acl->allow(null, null, null, new CleanIPAssertion());
]]></programlisting>

        <para>
            The above code creates a conditional allow rule that allows access to all privileges
            on everything by everyone, except when the requesting IP is "blacklisted." If a request
            comes in from an IP that is not considered "clean," then the allow rule does not apply.
            Since the rule applies to all roles, all resources, and all privileges, an "unclean" IP
            would result in a denial of access. This is a special case, however, and it should be
            understood that in all other cases (i.e., where a specific role, resource, or privilege
            is specified for the rule), a failed assertion results in the rule not applying, and
            other rules would be used to determine whether access is allowed or denied.
        </para>

        <para>
            The <code>assert()</code> method of an assertion object is passed the ACL, role,
            resource, and privilege to which the authorization query (i.e.,
            <code>isAllowed()</code>) applies, in order to provide a context for the assertion
            class to determine its conditions where needed.
        </para>

    </sect2>

</sect1>
<!--
vim:se ts=4 sw=4 et:
-->
