Question

Mise à jour:. 09/02/2009 - Question révisée, à condition de meilleurs exemples, bounty ajouté


Salut,
Je construis une application PHP en utilisant le modèle de mappeur de données entre la base de données et les entités (objets de domaine). Ma question est:

Quelle est la meilleure façon de résumer une tâche généralement effectuée?

Par exemple, une tâche commune récupère une ou plusieurs entités du site du mappeur du site, et leurs entités associées (page d'accueil) de la mappeur page. À l'heure actuelle, je le ferais comme ceci:

$siteMapper = new Site_Mapper();
$site = $siteMapper->findByid(1);

$pageMapper = new Page_Mapper();
$site->addPage($pageMapper->findHome($site->getId()));

Maintenant, c'est un exemple assez trivial, mais cela devient plus compliqué en réalité, que chaque site dispose également d'un lieu associé, et la page a fait plusieurs révisions (bien que pour les besoins de cette tâche que je ne serais intéressé par le plus un récent).

Je vais devoir le faire (obtenir le site et la page d'accueil associée, locale, etc.) à plusieurs endroits dans mon application et je ne peux pas penser à la meilleure façon / place pour résumer cette tâche, de sorte que je ne pas le répéter partout. Idéalement, je voudrais finir avec quelque chose comme ceci:

$someObject = new SomeClass();
$site = $someObject->someMethod(1); // or
$sites = $someObject->someOtherMethod();

Lorsque les entités du site résultant ont déjà leurs entités associées créées et prêtes à l'emploi.

Le même problème se produit lors de l'enregistrement de ces objets en arrière. Dire que j'ai une entité du site et entité page d'accueil associée, et ils ont tous deux été modifiés, je dois faire quelque chose comme ceci:

$siteMapper->save($site);
$pageMapper->save($site->getHomePage());

Encore une fois, trivial, mais cet exemple est simplifié. Duplication code est toujours valable.

Dans mon esprit, il est logique d'avoir une sorte d'objet central qui pourrait prendre en charge:

  • Récupération d'un site (ou sites) et toutes les entités associées nessessary
  • Création de nouvelles entités du site avec de nouvelles entités associées
  • Prendre un site (ou sites) et de l'enregistrer et de toutes les entités associées (si elles ont changé)

Revenons donc à ma question, quel devrait être cet objet?

  • L'objet mappeur existant?
  • Quelque chose basé sur le modèle référentiel? *
  • Quelque chose basé sur l'unité de travail patten? *
  • Quelque chose d'autre?

* Je ne pleinement comprennent une ou l'autre d'entre eux, comme vous pouvez probablement le deviner.

Yat-il un moyen standard pour aborder ce problème, et que quelqu'un pourrait fournir une brève description de la façon dont ils avaient la mettre en œuvre? Je ne cherche pas à quiconque de fournir une implémentation fonctionnelle complète, juste la théorie.

Merci,
Jack

Était-ce utile?

La solution

Utilisation du référentiel / modèle de service, vos cours du référentiel fourniraient une simple interface CRUD pour chacune de vos entités, puis les classes de service serait une couche supplémentaire qui effectue une logique supplémentaire comme la fixation des dépendances d'entités. Le reste de votre application utilise alors uniquement les services. Votre exemple pourrait ressembler à ceci:

$site = $siteService->getSiteById(1); // or
$sites = $siteService->getAllSites();

Ensuite, à l'intérieur de la classe SiteService vous auriez quelque chose comme ceci:

function getSiteById($id) {
  $site = $siteRepository->getSiteById($id);
  foreach ($pageRepository->getPagesBySiteId($site->id) as $page)
  {
    $site->pages[] = $page;
  }
  return $site;
}

Je ne sais pas PHP bien si s'il vous plaît excuse s'il y a quelque chose de mal syntaxiquement.

Autres conseils

[Edit: cette entrée tente de tenir compte du fait qu'il est souvent plus facile d'écrire du code personnalisé pour traiter directement avec une situation que d'essayer d'adapter le problème dans un schéma.]

Les motifs sont bien dans le concept, mais ils ne sont pas toujours « carte ». Après des années de développement PHP haut de gamme, nous avons réglé d'une manière très directe de traiter ces questions. Considérez ceci:

Fichier: site.php

class Site
{
   public static function Select($ID)
   {
      //Ensure current user has access to ID
      //Lookup and return data
   }

   public static function Insert($aData)
   {
      //Validate $aData
      //In the event of errors, raise a ValidationError($ErrorList)

      //Do whatever it is you are doing

      //Return new ID
   }

   public static function Update($ID, $aData)
   {
      //Validate $aData
      //In the event of errors, raise a ValidationError($ErrorList)

      //Update necessary fields
   }

Ensuite, pour l'appeler (de partout), il suffit d'exécuter:

$aData = Site::Select(123);

Site::Update(123, array('FirstName' => 'New First Name'));

$ID = Site::Insert(array(...))

Une chose à garder à l'esprit sur la programmation orientée objet et PHP ... PHP ne tient pas « état » entre les demandes, créant ainsi une instance d'objet juste pour avoir immédiatement détruit ne fait pas souvent de sens.

Je serais probablement commencer par l'extraction de la tâche commune à une méthode d'aide quelque part, puis d'attendre pour voir ce que la conception appelle. Il se sent comme il est trop tôt pour le dire.

Qu'est-ce que vous nommez cette méthode? Ce nom fait allusion généralement à où la méthode appartient.

class Page {

  public $id, $title, $url;

  public function __construct($id=false) {
    $this->id = $id;
  }

  public function save() {
    // ...
  }

}

class Site {

  public $id = '';
  public $pages = array();

  function __construct($id) {
     $this->id = $id;
     foreach ($this->getPages() as $page_id) {
       $this->pages[] = new Page($page_id);
     }
  }

  private function getPages() {
    // ...
  }

  public function addPage($url) {
    $page = ($this->pages[] = new Page());
    $page->url = $url;
    return $page;
  }

  public function save() {
    foreach ($this->pages as $page) {
      $page->save();
    } 
    // ..
  }

}

$site = new Site($id);
$page = $site->addPage('/');
$page->title = 'Home';
$site->save();

Faites votre site objet racine globale pour encapsuler l'association complexe et d'assurer la cohérence .

Ensuite, créez un SiteRepository qui a la responsabilité de récupérer l'ensemble du site et de remplir ses enfants (y compris toutes les pages).

Vous ne aurez pas besoin d'une PageRepository séparée (en supposant que vous ne faites pas la page une racine globale séparée), et votre SiteRepository devrait avoir la responsabilité de récupérer les objets Page ainsi (dans votre cas en utilisant vos cartographes existants).

$siteRepository = new SiteRepository($myDbConfig);
$site = $siteRepository->findById(1); // will have Page children attached

Et puis la méthode serait responsable findById de trouver aussi tous les enfants de la page du site. Cela aura une structure similaire à la réponse CodeMonkey1 a donné, mais je crois que vous bénéficierez plus en utilisant les modèles agrégats et du référentiel, plutôt que de créer un service spécifique pour cette tâche. Toute autre recherche / interrogation / mise à jour de l'ensemble du site, y compris l'un de ses objets enfants, serait fait par le même SiteRepository.

Edit: Voici un petit guide DDD pour vous aider la terminologie, bien que je vous recommande vraiment lire Evans si vous voulez que l'image entière.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top