<?xml version="1.0" encoding="UTF-8"?>
<!-- EN-Revision: 24249 -->
<!-- Reviewed: no -->
<sect1 id="zend.db.profiler" xmlns:xi="http://www.w3.org/2001/XInclude">
    <title>Zend_Db_Profiler</title>

    <sect2 id="zend.db.profiler.introduction">
        <title>Introduction</title>

        <para>
            <classname>Zend_Db_Profiler</classname> peut être activé pour permettre le
            profilage de requête. Les profils incluent les requêtes exécutées par l'adaptateur,
            ainsi que leur temps d'exécution, permettant l'inspection des requêtes qui ont été
            exécutées sans avoir besoin de rajouter le code spécifique de débogage aux classes.
            L'utilisation avancée permet aussi au développeur de filtrer quelles requêtes il
            souhaite profiler.
        </para>

        <para>
            Le profileur s'active soit en passant une directive au constructeur de
            l'adaptateur, soit en spécifiant à l'adaptateur de l'activer plus tard.
        </para>

        <programlisting language="php"><![CDATA[
$params = array(
    'host'     => '127.0.0.1',
    'username' => 'webuser',
    'password' => 'xxxxxxxx',
    'dbname'   => 'test',
    'profiler' => true  // active le profileur ;
                        // mettre à false pour désactiver
                        // (désactivé par défaut)
);

$db = Zend_Db::factory('PDO_MYSQL', $params);

// stoppe le profileur :
$db->getProfiler()->setEnabled(false);

// active le profileur :
$db->getProfiler()->setEnabled(true);
]]></programlisting>

        <para>
            La valeur de l'option <property>profiler</property> est souple. Elle est interprétée
            différemment suivant son type. La plupart du temps, vous devriez simplement utiliser une
            variable booléenne, mais d'autres valeurs vous permettent de personnaliser le
            comportement du profileur.
        </para>

        <para>
            Un argument booléen active le profileur si c'est une valeur <constant>TRUE</constant>,
            ou le désactive si <constant>FALSE</constant>. La classe de profileur est celle par
            défaut, par exemple <classname>Zend_Db_Profiler</classname>.
        </para>

        <programlisting language="php"><![CDATA[
$params['profiler'] = true;
$db = Zend_Db::factory('PDO_MYSQL', $params);
]]></programlisting>

        <para>
            Une instance d'un objet profileur fait que l'adaptateur utilise cet objet. L'objet
            doit être de type <classname>Zend_Db_Profiler</classname> ou une sous-classe.
            L'activation du profileur est faite séparément.
        </para>

        <programlisting language="php"><![CDATA[
$profiler = Mon_Db_Profiler();
$profiler->setEnabled(true);
$params['profiler'] = $profiler;
$db = Zend_Db::factory('PDO_MYSQL', $params);
]]></programlisting>

        <para>
            L'argument peut être un tableau associatif contenant une ou toutes les clés
            suivantes : "<property>enabled</property>", "<property>instance</property>", et
            "<property>class</property>". Les clés "<property>enabled</property>" et
            "<property>instance</property>" correspondent aux types booléen et instance décrites
            ci-dessus. La clé "<property>class</property>" est utilisée pour
            nommer une classe à prendre en tant que profileur personnalisé. La classe doit être de
            type <classname>Zend_Db_Profiler</classname> ou une sous-classe. La classe est
            instanciée sans aucun argument de constructeur. L'option "<property>class</property>"
            est ignorée quand l'option "<property>instance</property>" est fournie.
        </para>

        <programlisting
            language="php"><![CDATA[
$params['profiler'] = array(
    'enabled' => true,
    'class'   => 'Mon_Db_Profiler'
);
$db = Zend_Db::factory('PDO_MYSQL', $params);
]]></programlisting>

        <para>
            Enfin, l'argument peut être un objet de type <classname>Zend_Config</classname>
            contenant des propriétés, qui sont traitées comme les clés de tableaux décrites
            ci-dessus. Par exemple, un fichier "<filename>config.ini</filename>" peut
            contenir les données suivantes&#160;:
        </para>

        <programlisting language="ini"><![CDATA[
[main]
db.profiler.class   = "Mon_Db_Profiler"
db.profiler.enabled = true
]]></programlisting>

        <para>
            Cette configuration peut être appliquée par le code <acronym>PHP</acronym>
            suivant&#160;:
        </para>

        <programlisting language="php"><![CDATA[
$config = new Zend_Config_Ini('config.ini', 'main');
$params['profiler'] = $config->db->profiler;
$db = Zend_Db::factory('PDO_MYSQL', $params);
]]></programlisting>

        <para>
            La propriété "<property>instance</property>" peut être utilisée comme ceci&#160;:
        </para>

        <programlisting language="php"><![CDATA[
$profiler = new Mon_Db_Profiler();
$profiler->setEnabled(true);
$configData = array(
    'instance' => $profiler
    );
$config = new Zend_Config($configData);
$params['profiler'] = $config;
$db = Zend_Db::factory('PDO_MYSQL', $params);
]]></programlisting>
    </sect2>

    <sect2 id="zend.db.profiler.using">
        <title>Utiliser le profileur</title>

        <para>
            A n'importe quel moment, vous pouvez récupérer le profileur en utilisant la
            méthode <methodname>getProfiler()</methodname> de l'adaptateur&#160;:
        </para>

        <programlisting language="php"><![CDATA[
$profileur = $db->getProfiler();
]]></programlisting>

        <para>
            Ceci retourne une instance de <classname>Zend_Db_Profiler</classname>. Avec cette
            instance, le développeur peut examiner les requêtes en utilisant un éventail de
            méthodes&#160;:
        </para>

        <itemizedlist>
            <listitem>
                <para>
                    <methodname>getTotalNumQueries()</methodname> retourne le nombre total de
                    requêtes profilées.
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>getTotalElapsedSecs()</methodname> retourne le nombre total de
                    secondes écoulées pour chaque requête profilée.
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>getQueryProfiles()</methodname> retourne un tableau de tous les
                    profils de requêtes.
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>getLastQueryProfile()</methodname> retourne le profil de requête le
                    plus récent, peut importe si la requête à fini de s'exécuter ou pas (si
                    l'exécution n'est pas finie, le temps de fin sera <constant>NULL</constant>).
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>clear()</methodname> nettoie tous les anciens profils de la pile.
                </para>
            </listitem>
        </itemizedlist>

        <para>
            La valeur de retour de <methodname>getLastQueryProfile()</methodname> et les éléments
            individuels de <methodname>getQueryProfiles()</methodname> sont des objets de type
            <classname>Zend_Db_Profiler_Query</classname> qui permettent d'inspecter les
            requêtes&#160;:
        </para>

        <itemizedlist>
            <listitem>
                <para>
                    <methodname>getQuery()</methodname> retourne le <acronym>SQL</acronym> de la
                    requête sous forme de texte. Le texte de <acronym>SQL</acronym> d'une requête
                    préparée avec des paramètres est le texte au moment où la requête a été
                    préparée, donc il contient les emplacements de paramètre, mais pas les
                    valeurs utilisées quand la déclaration est exécutée.
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>getQueryParams()</methodname> retourne un tableau des valeurs de
                    paramètres utilisées lors de l'exécution d'une requête préparée. Ceci inclue à
                    la fois les paramètres attachés et les arguments de la méthode
                    <methodname>execute()</methodname>. Les clés du tableau sont les positions
                    (base 1) ou les noms des paramètres.
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>getElapsedSecs()</methodname> retourne le nombre de secondes
                    d'exécution de la requête.
                </para>
            </listitem>
        </itemizedlist>

        <para>
            L'information que <classname>Zend_Db_Profiler</classname> fourni est utile pour
            profiler des goulots d'étranglement dans les applications, ainsi que pour déboguer les
            requêtes qui viennent d'être exécutées. Par exemple, pour voir la dernière requête qui
            vient de s'exécuter&#160;:
        </para>

        <programlisting language="php"><![CDATA[
$query = $profileur->getLastQueryProfile();
echo $query->getQuery();
]]></programlisting>

        <para>
            Si une page se génère lentement, utilisez le profileur pour déterminer le nombre
            total de requêtes, et ensuite passer d'une requête à l'autre pour voir laquelle
            a été la plus longue&#160;:
        </para>

        <programlisting language="php"><![CDATA[
$tempsTotal       = $profileur->getTotalElapsedSecs();
$nombreRequetes   = $profileur->getTotalNumQueries();
$tempsLePlusLong  = 0;
$requeteLaPlusLongue = null;

foreach ($profileur->getQueryProfiles() as $query) {
    if ($query->getElapsedSecs() > $tempsLePlusLong) {
        $tempsLePlusLong  = $query->getElapsedSecs();
        $requeteLaPlusLongue = $query->getQuery();
    }
}

echo 'Exécution de '
   . $nombreRequetes
   . ' requêtes en '
   . $tempsTotal
   . ' secondes' . "\n";
echo 'Temps moyen : '
   . $tempsTotal / $nombreRequetes
   . ' secondes' . "\n";
echo 'Requêtes par seconde: '
   . $nombreRequetes / $tempsTotal
   . ' seconds' . "\n";
echo 'Requête la plus lente (secondes) : '
   . $tempsLePlusLong . "\n";
echo "Requête la plus lente (SQL) : \n"
   . $requeteLaPlusLongue . "\n";
]]></programlisting>
    </sect2>

    <sect2 id="zend.db.profiler.advanced">
        <title>Utilisation avancée du profileur</title>

        <para>
            En plus de l'inspection de requête, le profileur permet aussi au développeur de
            filtrer quelles requêtes il veut profiler. Les méthodes suivantes fonctionnent avec une
            instance de <classname>Zend_Db_Profiler</classname>&#160;:
        </para>

        <sect3 id="zend.db.profiler.advanced.filtertime">
            <title>Filtrer par temps d'exécution</title>

            <para>
                <methodname>setFilterElapsedSecs()</methodname> permet au développeur de définir un
                temps minimum d'exécution de la requête avant que celle-ci soit profilée. Pour
                retirer le filtre, passez une valeur <constant>NULL</constant> à la méthode.
            </para>

            <programlisting language="php"><![CDATA[
// Seules les requêtes qui durent au moins 5 secondes sont profilées :
$profileur->setFilterElapsedSecs(5);

// Profil de toutes les requêtes, peu importe leur durée :
$profileur->setFilterElapsedSecs(null);
]]></programlisting>
        </sect3>

        <sect3 id="zend.db.profiler.advanced.filtertype">
            <title>Filtrer par type de requête</title>

            <para>
                <methodname>setFilterQueryType()</methodname> permet au développeur de définir quels
                types de requêtes doivent être profilées ; pour profiler des types multiples vous
                pouvez utiliser le OU logique. Les types de requêtes sont définis sous forme de
                constantes de <classname>Zend_Db_Profiler</classname>&#160;:
            </para>

            <itemizedlist>
                <listitem>
                    <para>
                        <constant>Zend_Db_Profiler::CONNECT</constant>&#160;: opérations de
                        connexion ou de sélection de base de données.
                    </para>
                </listitem>

                <listitem>
                    <para>
                        <constant>Zend_Db_Profiler::QUERY</constant>&#160;: requête générale qui
                        ne correspond pas aux autres types.
                    </para>
                </listitem>

                <listitem>
                    <para>
                        <constant>Zend_Db_Profiler::INSERT</constant>&#160;: toute requête qui
                        ajoute des données dans la base de données, généralement
                        du <acronym>SQL</acronym> <acronym>INSERT</acronym>.
                    </para>
                </listitem>

                <listitem>
                    <para>
                        <constant>Zend_Db_Profiler::UPDATE</constant>&#160;: toute requête qui
                        met à jour des données, généralement du <acronym>SQL</acronym>
                        <acronym>UPDATE</acronym>.
                    </para>
                </listitem>

                <listitem>
                    <para>
                        <constant>Zend_Db_Profiler::DELETE</constant>&#160;: toute requête qui
                        efface des données, généralement du <acronym>SQL</acronym>
                        <constant>DELETE</constant>.
                    </para>
                </listitem>

                <listitem>
                    <para>
                        <constant>Zend_Db_Profiler::SELECT</constant>&#160;: toute requête qui
                        récupère des données, généralement du <acronym>SQL</acronym>
                        <acronym>SELECT</acronym>.
                    </para>
                </listitem>

                <listitem>
                    <para>
                        <constant>Zend_Db_Profiler::TRANSACTION</constant>&#160;: toute requête
                        qui concerne des opérations de transaction, comme start transaction,
                        commit, ou rollback.
                    </para>
                </listitem>
            </itemizedlist>

            <para>
                Comme avec <methodname>setFilterElapsedSecs()</methodname>, vous pouvez retirer
                tous les filtres en passant <constant>NULL</constant> comme unique argument.
            </para>

            <programlisting language="php"><![CDATA[
// profile uniquement les requêtes SELECT
$profileur->setFilterQueryType(Zend_Db_Profiler::SELECT);

// profile les requêtes SELECT, INSERT, et UPDATE
$profileur->setFilterQueryType(Zend_Db_Profiler::SELECT
                             | Zend_Db_Profiler::INSERT
                             | Zend_Db_Profiler::UPDATE);

// profile les requêtes DELETE
$profileur->setFilterQueryType(Zend_Db_Profiler::DELETE);

// Efface tous les filtres
$profileur->setFilterQueryType(null);
]]></programlisting>
        </sect3>

        <sect3 id="zend.db.profiler.advanced.getbytype">
            <title>Récupérer les profils par type de requête</title>

            <para>
                Utiliser <methodname>setFilterQueryType()</methodname> peut réduire les profils
                générés. Cependant il est parfois utile de garder tous les profils et voir
                uniquement ceux dont on a besoin, à un moment donné. Une autre possibilité de
                <methodname>getQueryProfiles()</methodname> est qu'il est possible de filtrer
                à la volée, en passant un type de requête (ou une combinaison logique de types
                de requête) comme premier argument ; voir
                <link linkend="zend.db.profiler.advanced.filtertype">cette section</link>
                pour la liste des constantes de types de requête.
            </para>

            <programlisting language="php"><![CDATA[
// Récupère uniquement les profils des requêtes SELECT
$profiles = $profiler->getQueryProfiles(Zend_Db_Profiler::SELECT);

// Récupère uniquement les profils des requêtes :
// SELECT, INSERT, et UPDATE
$profiles = $profiler->getQueryProfiles(Zend_Db_Profiler::SELECT
                                      | Zend_Db_Profiler::INSERT
                                      | Zend_Db_Profiler::UPDATE);

// Récupère uniquement les profils des requêtes DELETE
// (on peut donc comprendre pourquoi les données disparaissent)
$profiles = $profiler->getQueryProfiles(Zend_Db_Profiler::DELETE);
]]></programlisting>
        </sect3>
    </sect2>

    <sect2 id="zend.db.profiler.profilers">
        <title>Profileurs spécialisés</title>

        <para>
            Un profileur spécialisé est un objet qui hérite de
            <classname>Zend_Db_Profiler</classname>. Les profileurs spécialisés traitent les
            informations de profilage de manière spécifique.
        </para>

        <xi:include href="Zend_Db_Profiler-Firebug.xml" />
    </sect2>
</sect1>