Meilleure pratique pour organiser des requêtes DBA réutilisables en Symfony2?

je travaille sur un projet Symfony2 en ce moment. Pour la plupart, c'est totalement standard; j'utilise la couche ORM pour me connecter à la base de données via mes Entities. Pas de problèmes là-bas.

cependant, je dois faire des requêtes peu fréquentes à une petite poignée de tableaux dans un schéma existant ailleurs dans le système, qui contient ce que j'appellerais des informations de "référence": des choses comme les taux de conversion des devises et autres. J'ai SELECT accès seulement à ce schéma.

j'ai mis en place une autre connexion et je suis passé à la couche DBAL pour faire les requêtes sur ce schéma, qui a fonctionné assez bien jusqu'à présent.

mon problème est que, bien que peu fréquent, je pense que je vais avoir besoin de répéter certaines de mes requêtes DBA à plus d'un endroit dans mon application; je voudrais refactoriser ces requêtes dans une sorte de dépôt, où ils sont plus facilement utilisés/testés/etc. J'ai pensé à créer des entités pour les tables, mais je pense que c'est overkill dans ce cas. Ai-je raison de penser que vous avez besoin Entités pour créer un référentiel?

au lieu de cela, je me demande s'il n'y a pas un "moyen symbolique" de faire cela? Quelque chose d'agréable et élégant :)

Merci! Darragh

8
demandé sur Darragh Enright 2011-11-23 15:03:58

2 réponses

mise à Jour

2013-10-03

Pardonnez-moi d'avoir édité une réponse vieille de deux ans... Cependant, quelques personnes ont remis en question l'approche actuelle, et bien qu'elle fonctionne (et qu'elle ait bien fonctionné pour mon cas d'utilisation particulier), la définition des services est bien sûr la Symfony.

personne n'a fourni d'exemple donc, pour référence/exhaustivité, je vais mettre à jour ma réponse. Je dois admettre que je n'étais pas vraiment au fait avec définir les services personnalisés lorsque j'ai posté cette réponse à l'origine, mais nous vivons et apprenons.

la réponse originale est conservée ci-dessous.

1. Créer une connexion supplémentaire DBAL

  • Créer une connexion fooapp/config/config.yml.
  • Argument wrapper_class n'est pas nécessaire dans ce cas (voir la réponse originale).
doctrine:
    dbal:
        connections:
            default:
                driver:   %database_driver%
                host:     %database_host%
                dbname:   %database_name%
                user:     %database_user%
            foo:
                driver:   %foo_driver%
                host:     %foo_host%
                dbname:   %foo_name%
                user:     %foo_user%

2. Configurer le service

  • selon le format YAML.
  • Ajouter configuration à src/Acme/TestBundle/Resources/config/services.yml.
  • Remarque, nous sommes d'injecter de l'défini ci-dessus DBAL foo_connection dans le service.
services:
    foo_query_service:
        class: Acme\TestBundle\Services\FooQueryService
        arguments:
            - @doctrine.dbal.foo_connection

3. Créer une classe pour le service configuré

  • Créer la classe suivante à src/Acme/TestBundle/Services/FooQueryService.php:
<?php

namespace Acme\TestBundle\Services;

use DateTime;
use Doctrine\DBAL\Connection;

class FooQueryService
{
    private $connection;

    public function __construct(Connection $connection)
    {
        $this->connection = $connection;
    }

    public function findBarByDate(DateTime $date)
    {
        $stmt = $this->connection->prepare('SELECT * FROM bar WHERE date = :date');
        $stmt->bindValue('date', $date, 'datetime');
        $stmt->execute();

        return $stmt->fetch();
    }
}

4. Enfin, utilisez vos requêtes partout où vous en avez besoin!

Par exemple, dans un contrôleur...

/**
 * @Route("/", name="home")
 * @Template()
 */
public function indexAction()
{
    $date = new \DateTime();

    $result = $this->get('foo_query_service')
        ->findBarByDate($date);

    return array();
}

Fait :) Merci Acayra et koskoz pour leur rétroaction.


OK, je pense que j'ai trouvé une solution qui fonctionne pour moi dans ce cas.

j'ai en fait jeté un autre regard sur la création d'entités / gestionnaires - en fait, la documentation Symfony2 autour de la mise en correspondance d'entités spécifiques à plusieurs gestionnaires semble faire défaut. Il semble encore qu'il s'agisse d'une approche exagérée dans ce cas-ci (et les schémas de "référence" sont assez désordonnés).

heureusement, il est possible de spécifier une classe d'enrubannage pour un DBAL connexion et requêtes abstraites dans des méthodes spécifiques.

  1. créer une connexion supplémentaire DBAL avec une classe wrapper dans config.yml:
doctrine:
    orm:
        connections:
            default:
                driver:   %driver%
                host:     %host%
                dbname:   %name%
                user:     %user%
            foo:
                wrapper_class: 'Acme\TestBundle\Doctrine\DBAL\FooConnection'
                driver:   %foo_driver%
                host:     %foo_host%
                dbname:   %foo_name%
                user:     %foo_user%
  1. Créer la classe wrapper sur le chemin d'accès spécifié:
<?php

namespace Acme\TestBundle\Doctrine\DBAL\FooConnection;
use Doctrine\DBAL\Connection;

class FooConnection extends Connection
{
    // custom query...
    public function findBarByDate(\DateTime $date)
    {
        $stmt = $this->prepare('SELECT * FROM bar WHERE date = :date');
        $stmt->bindValue('date', $date, 'datetime');
        $stmt->execute();  

        return $stmt->fetch();
    }
}

notez que la classe wrapper doit étendre \Doctrine\DBAL\Connection.

  1. Utilisez vos requêtes partout où vous en avez besoin:
$date   = new \DateTime();
$conn   = $this->getDoctrine()->getConnection('foo');
$result = $conn->findBarByDate($date);

J'espère que cela vous aidera!

11
répondu Darragh Enright 2013-10-04 00:59:08

Wow, votre réponse implique que vous avez toutes vos requêtes aux mêmes endroits pour chaque table.

Je n'aime pas ce truc d'emballage, je préfère avoir des services. Un service par table ou par forfait, cela dépend si vous avez beaucoup de tables et comment vous souhaitez organiser vos requêtes.

puis je passe la connexion désirée comme argument d'un service et c'est tout.

0
répondu DevAntoine 2013-10-03 14:39:06