Pergunta

Atualizado:. 09/02/2009 - pergunta Revisada, fornecidos exemplos melhores, recompensa adicionado


Oi,
Estou construindo uma aplicação PHP utilizando o padrão de mapeador de dados entre o banco de dados e as entidades (objetos de domínio). A minha pergunta é:

O que é a melhor maneira de encapsular uma tarefa geralmente executada?

Por exemplo, uma tarefa comum é a recuperação de uma ou mais entidades do site do mapeador site e suas entidades (casa) de página associados do mapeador página. No momento, eu faria isso como este:

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

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

Agora que é um exemplo bastante trivial, mas fica mais complicado, na realidade, uma vez que cada site tem também um local associado, ea página na verdade tem múltiplas revisões (embora, para efeitos de esta tarefa eu só estaria interessado na mais recente).

Vou necessidade de fazer isso (entrar no site e home page associado, local etc.) em vários lugares dentro do meu aplicativo, e eu não posso pensar na melhor maneira / local para encapsular esta tarefa, de modo que eu não tem que repeti-lo em todo o lugar. Idealmente, eu gostaria de acabar com algo parecido com isto:

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

Onde as entidades do site resultantes já as suas entidades associadas criado e pronto para uso.

O mesmo problema ocorre quando guardar esses objetos de volta. Digamos que eu tenha uma entidade local e entidade home page associado, e eles tanto sido modificado, eu tenho que fazer algo como isto:

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

Mais uma vez, trivial, mas este exemplo é simplificado. Duplicação de código ainda se aplica.

Na minha mente, faz sentido ter algum tipo de objeto central que poderia cuidar de:

  • Recuperar um site (ou locais) e todas as entidades associadas nessessary
  • A criação de novas entidades de sites com novas entidades associadas
  • Tomar um site (ou locais) e salvá-lo e todas as entidades associadas (se eles mudaram)

Então, de volta à minha pergunta, o que deve este objeto ser?

  • O mapeador de objeto existente?
  • Algo baseado no padrão de repositório? *
  • Algo com base na unidade de Patten trabalho? *
  • Algo mais?

* Eu não faço totalmente compreender qualquer um destes, como você provavelmente pode adivinhar.

Existe uma maneira padrão para abordar este problema, e alguém poderia fornecer uma breve descrição de como eles implementá-lo? Eu não estou procurando alguém para fornecer uma implementação totalmente funcional, apenas a teoria.

Obrigado,
Jack

Foi útil?

Solução

Usando o padrão de repositório / serviço, suas classes Repositório iria fornecer uma interface CRUD simples para cada uma de suas entidades, em seguida, as classes de serviço seria uma camada adicional que executa a lógica adicional como anexando dependências entidade. O resto do seu aplicativo só então utiliza os Serviços. O seu exemplo pode parecer com isto:

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

Em seguida, dentro da classe SiteService você teria algo como isto:

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

Eu não sei PHP que também por isso, desculpa se há algo errado sintaticamente.

Outras dicas

[Edit: este tentativas de entrada para abordar o fato de que é muitas vezes mais fácil de código personalizado de escrita para lidar diretamente com uma situação que é para tentar encaixar o problema em um padrão.]

Patterns são bons em termos de conceito, mas eles nem sempre "mapa". Depois de anos de high-end desenvolvimento PHP, que se instalaram em uma maneira muito direta de lidar com tais assuntos. Considere o seguinte:

arquivo: 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
   }

Então, a fim de chamá-lo (em qualquer lugar), basta executar:

$aData = Site::Select(123);

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

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

Uma coisa a ter em mente sobre a programação OO e PHP ... PHP não mantém "estado" entre os pedidos, por isso, a criação de uma instância de objeto apenas para tê-lo imediatamente destruído muitas vezes não fazem sentido.

Eu provavelmente começar por extrair a tarefa comum a algum lugar método auxiliar, em seguida, esperando para ver o que as chamadas de design para. Parece que é muito cedo para dizer.

O que você nomear este método? O nome geralmente sugestões para onde o método pertence.

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();

Faça o seu objeto de site um Aggregate Raiz para encapsular a associação complexa e assegurar a consistência .

Em seguida, crie um SiteRepository que tem a responsabilidade de recuperar o agregado do site e preencher seus filhos (incluindo todas as páginas).

Você não vai precisar de um PageRepository separado (assumindo que você não faça Página um Aggregate Raiz separado), e seu SiteRepository deve ter a responsabilidade de recuperar a página objetos, bem como (no seu caso, usando seus Mappers existentes).

Assim:

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

E, em seguida, o método findById seria responsável também encontrar todas as crianças página do site. Isto terá uma estrutura semelhante à resposta CodeMonkey1 deu, porém eu acredito que você vai beneficiar mais, usando os padrões de agregação e repositório, em vez de criar um serviço específico para esta tarefa. Qualquer outra recuperação / consulta / actualização do agregado Site, incluindo qualquer um dos seus objetos filho, seria feito através do mesmo SiteRepository.

Edit: Aqui está um guia curta DDD para ajudá-lo com a terminologia, embora eu realmente recomendo a leitura Evans se você quiser toda a imagem.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top