Architecture: API con un comportamento leggermente diverso a seconda dei ruoli utente registrati

3

Come dovrei strutturare un pezzo di codice che esegue un'operazione, ma potrebbe avere un comportamento leggermente diverso a seconda, diciamo, dei ruoli utente?

Esempio: La mia app ha ruoli "manager" e "dipendenti". Ci sono molti manager nella mia app e ognuno di loro ha molti dipendenti. Ho una dashboard in cui i manager e i loro dipendenti possono aggiungere / modificare / eliminare prodotti.

Entrambi possono modificare i prodotti creati da loro stessi, ma i manager possono modificare i prodotti appartenenti ai suoi dipendenti. Se un manager modifica un prodotto creato da un dipendente, il dipendente riceverà una notifica via email sulla modifica.

Il problema che ho, è che sto creando if / else o istruzioni switch / case per controllare i ruoli utente, e sento che una volta che aggiungo nuovi ruoli il mio codice dovrà controllarli anch'essi e il mio codice diventerà più difficile da leggere.

Ad esempio:

// What I currently have:
public function updateProductForUser(Product $product, UserInterface $user)
{
    $userWhoCreatedProduct = $product->getCreatedByUser();

    if ($userWhoCreatedProduct === $user) {
        // If the user who created the product is the same one trying to update it,
        // then go ahead and execute the update.
        $this->_doUpdateProductForUser($product, $user);
        return;

    } elseif ($user instanceof Manager) {
        $allManagerEmployees = $this->someService->findAllEmployeesOfManager($user);

        if (in_array($userWhoCreatedProduct, $allManagerEmployees)) {
            // If the user trying to update the product is a manager, and the product was
            // created by an employee of the manager, then execute the update but also
            // send an notification to the employee that the product he created got updated
            // by his manager.
            $this->_doUpdateProductForUser($product, $user);
            $this->notifyUserThatProductGotUpdated($product);
        }
    }
}

Come posso migliorare questo? Esiste un modo migliore? Quali sono le insidie dell'attuazione? Qualsiasi consiglio è molto gradito. Grazie!

    
posta Oscar Balladares 23.01.2016 - 21:50
fonte

1 risposta

7

Puoi rendere il codice un po 'più gestibile se tu

  • Inserire la logica di gestione del prodotto (senza logica di autorizzazione e senza altri effetti collaterali) in una classe di servizio separata ProductDomain. (Vedi Separazione dei dubbi per i dettagli)
  • Crea una classe ProductHandlingService che utilizza ProductDomain e applica le autorizzazioni e altri effetti collaterali
  • dai un nome alle condizioni (vedi Schema di strategia per i dettagli)

Il ProductHandlingService potrebbe assomigliare a questo:

public function updateProductForUser(Product $product, UserInterface $userWhoWantsToModify)
{
  if ($strategy->userIsAllowedToModifyProduct($product, $userWhoWantsToModify) {
    $ProductDomain->_doUpdateProductForUser($product, $userWhoWantsToModify);
    if ($strategy->userNeedsInfoAboutProductUpdate($product, $product->getCreatedByUser(),
          $userWhoWantsToModify) {
      $this->notifyUserThatProductGotUpdated($product);
    }
  }
}

Vantaggi rispetto al design originale:

  • core-ProductDomain, il rilevamento dei permessi e la gestione speciale possono essere testati in modo indipendente.
  • Durante la vita del software è probabile che il rilevamento dei permessi e la gestione speciale cambino spesso a causa di motivi politici.
  • core-ProductDomain è probabile che cambi non molto spesso e principalmente a causa di motivi tecnici.
risposta data 25.01.2016 - 13:53
fonte

Leggi altre domande sui tag