1. Présentation de SSRS et de son SDK PHP

Au cas où vous n'êtes pas familier du terme, ce qu'on appelle un rapport (anciennement appelé "état") est un document de synthèse de certaines informations d'une base de données métier, présenté en général sous forme de tableaux et de graphiques, qui a pour vocation d'aider à la prise de décisions. Ce qui explique que cela fait partie du monde de la Business Intelligence (BI). Le "reporting" désigne l'action de créer et diffuser des rapports. Mais beaucoup d'entre vous font déjà du reporting sans le savoir. Afficher une liste des clients ou des dernières ventes d'un commerce en PHP, que ce soit dans une "simple" page html ou en PDF, c'est un rapport. Alors pourquoi des outils dédiés ? Il y a plusieurs raisons à cela, parmi lesquelles :

  • l'éditeur de rapports permet de générer des documents à la mise en page complexe et agréable à l'oeil avec un outil visuel (accessible aux non informaticiens, ce qui est très intéressant car cela permet à certains utilisateurs de créer eux-mêmes leurs rapports selon leurs besoins et leurs préférences de travail)
  • les données contenues dans le rapport peuvent être agrégées depuis de multiples sources : bases de données relationnelles classiques, datawarehouse (entrepôt de données dédié aux analyses BI), fichiers plats dans de multiples formats, webservices, et même des classes de vos propres applications
  • le moteur de reporting permet d'effectuer le rendu d'un rapport unique dans de multiples formats nativement : HTML, PDF, Word, Excel...
  • le serveur de rapports permet de paramétrer finement l'accès aux rapports et aux données qu'ils contiennent

SQL Server Reporting Services (SSRS) est la solution de reporting de Microsoft pour sa base de données SQL Server. La solution se compose de plusieurs outils :

  • deux éditeurs de rapports (Report Builder, plutôt destiné à l'utilisateur final, ou BI Developement Studio, plutôt dédié au professionnel BI)
  • un backoffice permettant de diffuser les rapports de manière sécurisée grâce à une politique de droits d'accès poussée
  • un webservice SOAP pour rendre les rapports accessibles depuis des applications tierces

C'est donc le webservice qui va nous intéresser ici. On pourrait y accéder directement en PHP grâce à la classe standard SoapClient ou à son équivalent Zend_Soap_Client, mais Microsoft nous rend la tâche encore plus facile en mettant à disposition un SDK qui est un ensemble de classes PHP de haut niveau encapsulant les appels SOAP. Le code PHP pour récupérer un rapport est ainsi minimal.

Existe-t-il un ou plusieurs équivalents à SSRS en libre ?
Oui bien sûr ! Le plus célèbre étant JasperServer. Je vous invite d'ailleurs à lire le livre blanc sur le monde de la BI open source pour plus d'informations.

2. Intégration du SDK dans une application Zend Framework

2.1. Installation du SDK et configuration de SSRS

La première étape sera bien sûr de télécharger le SDK. Après extraction de l'archive, seul le répertoire "bin" est à intégrer dans notre projet PHP, le reste étant de la documentation. Nous partons d'une application MVC avec l'arborescence standard de ZF (version 1.8 ou supérieur) telle que décrite dans la documentation officielle. Nous allons donc créer un répertoire library/SSRS et y copier le contenu du répertoire "bin" du SDK SSRS.

Il va falloir ensuite créer un accès pour notre application et pour cela SSRS utilise l'authentification Windows. Il faut donc ajouter un compte utilisateur Windows (ou utiliser le vôtre à des fins de test), et autoriser ce compte à accéder à la base de données. Pour cela, rendez-vous dans l'outil d'administration de SQL Server, allez dans les propriétés de sécurité / connexion, ajoutez l'utilisateur (avec le nom complet MACHINE\username ou DOMAIN\username). Sélectionnez ensuite la base de données qui servira aux rapports, ajoutez le compte utilisateur et donnez-lui les privilèges db_datareader et db_datawriter.

Reste maintenant à ajuster le degré de sécurité de SSRS. Pour cela, ouvrez le fichier rsreportserver.config localisé dans le répertoire de SSRS : C:\Program Files\Microsoft SQL Server \MSRS10.SQLEXPRESS\Reporting Services\ReportServer. Ce fichier est au format XML, et il faut ajouter l'élément <RSWindowsBasic/> au noeud <AuthenticationTypes> :

 
Sélectionnez

<Authentication>
    <AuthenticationTypes>
        <RSWindowsNegotiate/>
        <RSWindowsNTLM/>
        <RSWindowsKerberos />
        <RSWindowsBasic/>
    </AuthenticationTypes>
    <EnableAuthPersistence>true</EnableAuthPersistence>
</Authentication>

La directive RSWindowsNegotiate permet de basculer en Kerberos ou NTLM selon le protocole d'authentification supporté.

2.2. Réalisation d'un helper d'action

Pour pouvoir récupérer des rapports dans toute l'application, le plus simple est de créer un helper d'action qui pourra donc être appelé depuis n'importe quelle action de contrôleur.

La première chose à faire est de stocker les paramètres de connexion : URL du webservice, identifiant et mot de passe. Nous utilisons donc le fichier application/configs/application.ini dans lequel nous ajoutons les lignes suivantes :

 
Sélectionnez
ssrs.url      = "http://localhost:85/ReportsServer"
ssrs.username = "MACHINE\toto"
ssrs.password = "xxx"

Attention ! J'ai constaté une bizarrerie avec le SDK SSRS : celui-ci semble utiliser en interne le nom de machine. Qu'on appelle le serveur de reporting par son IP ou par son nom, il est impératif de préciser dans le fichier hosts du serveur PHP le nom de la machine SSRS avec son IP. Pour localhost c'est bien sûr inutile car l'entrée existe déjà par défaut dans le fichier hosts, mais si votre SSRS est sur une autre IP, il faudra le renseigner.

Mettez donc une ligne comme celle-ci dans votre fichier C:\Windows\system32\drivers\etc\hosts (ou /etc/hosts sous Linux) :

Fichier hosts
Sélectionnez
192.168.1.5    reportserver

Si ce n'est pas déjà fait, rendez la configuration accessible aisément dans toute votre application en ajoutant la méthode suivante au bootstrap :

application/Bootstrap.php
Sélectionnez
protected function _initConfig()
{
    $config = new Zend_Config($this->getOptions());
    Zend_Registry::set('config', $config);
    return $config;
}

La configuration sera ainsi accessible partout via un simple Zend_Registry::get('config').

Nous créons ensuite le fichier library/Application/Helper/Rapport.php. La classe ne comportera qu'une méthode direct() ce qui permet au helper d'être appelé directement dans les contrôleurs (pour plus de détails sur la manière de réaliser ses propres helpers d'action, voyez le manuel de Zend Framework). Voici le code source :

 
Sélectionnez
class Application_Helper_Rapport extends Zend_Controller_Action_Helper_Abstract
{
    /**
     * Récupère un rapport SSRS et l'affiche inline au format PDF
     * @param array $options paramètres d'affichage
     */
    public function direct($options)
    {
        $controller = $this->getActionController();
        $config = Zend_Registry::get('config');
        require_once(ROOT_PATH . '/library/ssrs/SSRSReport.php');
        try {
            // se connecte au webservice de SSRS
            $ssrs = new SSRSReport(new Credentials($config->ssrs->user, $config->ssrs->password), $config->ssrs->url);
            // charge le rapport demandé
            $report = $ssrs->LoadReport2($options['rapport']);
            // passe les éventuels paramètres
            if (array_key_exists('param', $options) and is_array($options['param']) and count($options['param']) > 0) {
                $params = array();
                foreach ($options['param'] as $key => $val) {
                    $param = new ParameterValue();
                    $param->Name = $key;
                    $param->Value = $val;
                    $params[] = $param;
                }
                $ssrs->SetExecutionParameters2($params);
            }
            // effectue le rendu en PDF
            $renderPdf = new RenderAsPDF();
            $rapport = $ssrs->Render2($renderPdf,
                PageCountModeEnum::$Actual,
                $Extension,
                $MimeType,
                $Encoding,
                $Warnings,
                $StreamIds);
            // prépare l'affichage en purgeant la vue et en mettant les bons headers HTTP
            $controller->getHelper('viewRenderer')->setNoRender();
            $controller->getHelper('layout')->disableLayout();
            $controller->getResponse()->clearBody();
            $controller->getResponse()
                       ->setHeader('Content-Disposition', 'inline; filename=document.pdf')
                       ->setHeader('Content-type', 'application/pdf')
                       ;
            // affiche le contenu du rapport sur le flux de sortie
            echo $rapport;
        } catch (SSRSReportException $serviceException) {
            throw new Exception($serviceException->GetErrorMessage());
        }
    }
}

La méthode Render2() prend un certain nombre de paramètres par référence, qui contiendront différentes informations sur la production du rapport au retour de l'appel de fonction. Dans le cas présent, je n'en ai pas besoin, mais cela peut servir par exemple à récupérer les images jointes pour un rapport affiché au format HTML.

Nous avons ici traité uniquement le cas des rapports PDF, mais les méthodes sont sensiblement équivalentes pour les autres formats, nous vous invitons à consulter la documentation fournie avec le SDK. Il faudra éventuellement adapter les headers http, et surtout le type mime (application/*) si vous utilisez un autre format que le PDF comme illustré dans l'exemple.

Il faut enfin veiller à ce que notre helper soit chargé dans le Bootstrap, pour cela créez une méthode _initHelpers, ou ajoutez une ligne à votre méthode existante :

application/Bootstrap.php
Sélectionnez
protected function _initHelpers()
{
    Zend_Controller_Action_HelperBroker::addHelper(new Application_Helper_Rapport());
}

2.3. Récupération d'un rapport dans un contrôleur

La récupération d'un rapport consiste en un seul appel de fonction dans une action de contrôleur, comme illustré ci-dessous :

 
Sélectionnez
public function printAction()
{
    $this->_helper->rapport(
        'rapport' => "/chemin/vers/le/rapport",
        'param' => array(
            'param1' => 'valeur1',
            'param2' => 'valeur2',
        ),
    );
}

3. Conclusion

Comme vous avez pu le voir, l'affichage de rapports SSRS dans une application PHP est très simple grâce au SDK. Vous pourrez donc aisément utiliser du reporting professionnel dans vos applications web basées sur SQL Server.

N'hésitez pas à me contacter sur le forum pour toute question ou commentaire. Merci à toute l'équipe de developpez.com pour la relecture.