<?xml version="1.0" encoding="UTF-8"?>
<!-- Reviewed: no -->
<!-- EN-Revision: 24249 -->
<sect1 id="zend.paginator.advanced">
    <title>高度な使用法</title>

    <sect2 id="zend.paginator.advanced.adapters">
        <title>独自のデータソースアダプタ</title>

        <para>
            同梱のアダプタでは対応していないようなデータ形式を処理したくなることもあるでしょう。
            そんな場合は自分でアダプタを書く必要があります。
        </para>

        <para>
            そのためには
            <classname>Zend_Paginator_Adapter_Interface</classname>
            を実装しなければなりません。このインターフェイスでは
            2 つのメソッドが必須となっています。
        </para>

        <itemizedlist>
            <listitem>
                <para>count()</para>
            </listitem>
            <listitem>
                <para>getItems($offset, $itemCountPerPage)</para>
            </listitem>
        </itemizedlist>

        <para>
            さらに、コンストラクタを実装してそのパラメータでデータソースを受け取り、
            protected あるいは private なプロパティにそれを保存する処理も作りたくなることでしょう。
            これをどのように実装するかはあなた次第です。
        </para>

        <para>
            これまでに SPL の
            <ulink url="http://www.php.net/~helly/php/ext/spl/interfaceCountable.html">Countable</ulink>
            インターフェイスを使ったことがある方なら
            <methodname>count()</methodname> はおなじみでしょう。
            <classname>Zend_Paginator</classname> と組み合わせて使う場合、
            これはデータコレクション内の項目総数を返します。
            さらに、 <classname>Zend_Paginator</classname> のインスタンスには
            <methodname>countAllItems()</methodname> メソッドがあります。
            これはアダプタの <methodname>count()</methodname> メソッドへのプロキシです。
        </para>

        <para>
            <methodname>getItems()</methodname> メソッドは、ほんの少しだけ複雑です。
            これは、オフセットおよび 1 ページあたりの項目数を受け取ります。
            それにあわせて適切なデータを返す必要があります。
            配列の場合はこのようになるでしょう。
        </para>

        <programlisting language="php"><![CDATA[
return array_slice($this->_array, $offset, $itemCountPerPage);
]]></programlisting>

        <para>
            同梱のアダプタ (すべて <classname>Zend_Paginator_Adapter_Interface</classname>
            を実装しています) を見れば、
            自分のアダプタでこれをどのように実装すればいいのか参考になるでしょう。
        </para>
    </sect2>

    <sect2 id="zend.paginator.advanced.scrolling-styles">
        <title>独自のスクロール形式</title>

        <para>
            独自のスクロール形式を作成するには
            <classname>Zend_Paginator_ScrollingStyle_Interface</classname>
            を実装しなければなりません。このインターフェイスには
            <methodname>getPages()</methodname> メソッドが定義されています。
        </para>

        <programlisting language="php"><![CDATA[
public function getPages(Zend_Paginator $paginator, $pageRange = null);
]]></programlisting>

        <para>
            このメソッドは、いわゆる "ローカル" ページ
            (現在のページの周辺のページたち) の範囲のページの最小値・
            最大値を計算しなければなりません。
        </para>

        <para>
            他のスクロール形式を継承している (たとえば
            <classname>Zend_Paginator_ScrollingStyle_Elastic</classname>)
            のでない限り、自作のスクロール形式は必ずといっていいほど
            次のようなコードで終わることになるでしょう。
        </para>

        <programlisting language="php"><![CDATA[
return $paginator->getPagesInRange($lowerBound, $upperBound);
]]></programlisting>

        <para>
            このコールには特別な意味はありません。
            単に最小値と最大値の妥当性をチェックして、
            その範囲の配列を返しているだけです。
        </para>

        <para>
            新しいスクロール形式が用意できたら、どのディレクトリからそれを探すのかを
            <classname>Zend_Paginator</classname> に通知する必要があります。
            そのためには、次のようにします。
        </para>

        <programlisting language="php"><![CDATA[
$prefix = 'My_Paginator_ScrollingStyle';
$path   = 'My/Paginator/ScrollingStyle/';
Zend_Paginator::addScrollingStylePrefixPath($prefix, $path);
]]></programlisting>
    </sect2>

    <sect2 id="zend.paginator.advanced.caching">
        <title>キャッシュ機能</title>

        <para>
            <classname>Zend_Paginator</classname> は、渡されたデータをキャッシュする機能があります。
            これを使用すると、アダプタが毎回データを取得することを回避できます。
            アダプタのデータを自動的にキャッシュさせるよう設定するには、
            <methodname>setCache()</methodname> メソッドに <classname>Zend_Cache_Core</classname> のインスタンスを渡します。
        </para>

        <programlisting language="php"><![CDATA[
$paginator = Zend_Paginator::factory($someData);
$fO = array('lifetime' => 3600, 'automatic_serialization' => true);
$bO = array('cache_dir'=>'/tmp');
$cache = Zend_cache::factory('Core', 'File', $fO, $bO);
Zend_Paginator::setCache($cache);
]]></programlisting>

        <para>
            <classname>Zend_Paginator</classname> が <classname>Zend_Cache_Core</classname> のインスタンスを受け取ると、
            データがキャッシュされるようになります。キャッシュインスタンスを渡した後でも、
            場合によってはデータをキャッシュしたくないこともあるでしょう。そんな場合は
            <methodname>setCacheEnable()</methodname> を使用します。
        </para>

        <programlisting language="php"><![CDATA[
$paginator = Zend_Paginator::factory($someData);
// $cache は Zend_Cache_Core のインスタンスです
Zend_Paginator::setCache($cache);
// ... スクリプトの後半で次のようにすると
$paginator->setCacheEnable(false);
// キャッシュが無効になります
]]></programlisting>

        <para>
            キャッシュが設定されると、データは自動的に格納され、必要に応じて取り出されるようになります。
            キャッシュを手動で空にできると便利でしょう。そうするには
            <methodname>clearPageItemCache($pageNumber)</methodname> をコールします。
            何もパラメータを渡さなければ、キャッシュ全体が空になります。
            ページ番号をパラメータとして渡すと、そのページのキャッシュを空にします。
        </para>

        <programlisting language="php"><![CDATA[
$paginator = Zend_Paginator::factory($someData);
Zend_Paginator::setCache($cache);
$items = $paginator->getCurrentItems();
// これで 1 ページ目がキャッシュに入りました
$page3Items = $paginator->getItemsByPage(3);
// これで 3 ページ目がキャッシュに入りました

// 3 ページ目のキャッシュをクリアします
$paginator->clearPageItemCache(3);

// すべてのキャッシュをクリアします
$paginator->clearPageItemCache();
]]></programlisting>

        <para>
            1 ページあたりのアイテム数を変更すると、キャッシュ全体が空になります。
            キャッシュの内容が無効になるからです。
        </para>

        <programlisting language="php"><![CDATA[
$paginator = Zend_Paginator::factory($someData);
Zend_Paginator::setCache($cache);
// アイテムを取得します
$items = $paginator->getCurrentItems();

// すべてのキャッシュデータが消去されます
$paginator->setItemCountPerPage(2);
]]></programlisting>

        <para>
            キャッシュ内のデータを見たり、直接アクセスしたりすることもできます。その場合には
            <methodname>getPageItemCache()</methodname> を使用します。
        </para>

        <programlisting language="php"><![CDATA[
$paginator = Zend_Paginator::factory($someData);
$paginator->setItemCountPerPage(3);
Zend_Paginator::setCache($cache);

// アイテムを取得します
$items = $paginator->getCurrentItems();
$otherItems = $paginator->getItemsPerPage(4);

// キャッシュされたアイテムを二次元配列で取得します
var_dump($paginator->getPageItemCache());
]]></programlisting>
    </sect2>

    <sect2 id="zend.paginator.advanced.aggregator">
        <title>Zend_Paginator_AdapterAggregate インターフェイス</title>

        <para>
            作成するアプリケーションによっては、「内部のデータ構造は既存のアダプタと同じだけれども
            そのデータにアクセスするためにカプセル化を崩したくない」ということもあるでしょう。
            あるいは、<classname>Zend_Paginator_Adapter_Abstract</classname>
            が提供するような「オブジェクト "is-a" アダプタ」形式ではなく
            「オブジェクト "has-a" アダプタ」形式であることもあるでしょう。
            そんな場合は <classname>Zend_Paginator_AdapterAggregate</classname>
            インターフェイスを使用します。これは、 <acronym>PHP</acronym> の SPL 拡張モジュールにある
            <classname>IteratorAggregate</classname> と同じ動きをします。
        </para>

        <programlisting language="php"><![CDATA[
interface Zend_Paginator_AdapterAggregate
{
    /**
     * Return a fully configured Paginator Adapter from this method.
     *
     * @return Zend_Paginator_Adapter_Abstract
     */
    public function getPaginatorAdapter();
}
]]></programlisting>

        <para>
            このインターフェイスは小さく、ただ
            <classname>Zend_Paginator_Adapter_Abstract</classname>
            のインスタンスを返すだけのものです。このインスタンスは
            <methodname>Zend_Paginator::factory</methodname> および <classname>Zend_Paginator</classname>
            コンストラクタの両方で使用可能で、適切に処理されます。
        </para>
    </sect2>
</sect1>
<!--
vim:se ts=4 sw=4 et:
-->
