Aggiornamento di un'entità tramite un servizio

2

Sto separando il mio software in tre livelli principali (forse livelli sarebbe un termine migliore):

  • Presentazione ('Visualizzazioni')
  • Logica aziendale ("Servizi" e "Archivi")
  • Accesso ai dati ("Entità" (ad esempio ActiveRecords))

Che cosa ho ora?

In Presentazione, utilizzo l'accesso in sola lettura alle Entità, restituito da Archivi o Servizi, per visualizzare i dati.

$banks = $banksRegistryService->getBanksRepository()->getBanksByCity( $city );

$banksViewModel = new PaginatedList( $banks ); // some way to display banks;
                                               // example, not real code

Trovo che questo approccio sia abbastanza efficiente in termini di prestazioni e manutenibilità del codice e comunque sicuro finché tutte le operazioni di scrittura (creazione, aggiornamento, eliminazione) sono preformate tramite Service :

namespace Service\BankRegistry;

use Service\AbstractDatabaseService;
use Service\IBankRegistryService;
use Model\BankRegistry\Bank;

class Service
    extends AbstractDatabaseService
    implements IBankRegistryService
{
    /**
     * Registers a new Bank
     *
     * @param string $name                  Bank's name
     * @param string $bik                   Bank's Identification Code
     * @param string $correspondent_account Bank's correspondent account
     *
     * @return Bank
     */
    public function registerBank( $name, $bik, $correspondent_account )
    {
        $bank = new Bank();

        $bank
            -> setName( $name )
            -> setBik( $bik )
            -> setCorrespondentAccount( $correspondent_account );


        if( null === $this->getBanksRepository()->getDefaultBank() )
            $this->setDefaultBank( $bank );


        $this->getEntityManager()->persist( $bank );

        return $bank;
    }


    /**
     * Makes the $bank system's default bank
     *
     * @param Bank $bank
     * @return IBankRegistryService
     */
    public function setDefaultBank( Bank $bank )
    {
        $default_bank = $this->getBanksRepository()->getDefaultBank();  

        if( null !== $default_bank )
            $default_bank->setDefault( false );

        $bank->setDefault( true );

        return $this;
    }
}

Dove sono bloccato?

Ho difficoltà a come aggiornare determinati campi in Bank Entity.

Cattiva soluzione n. 1 : creazione di una serie di setter in Service per ogni setter in Bank ; - sembra essere abbastanza ridondante, aumenta Service interfaccia complessità e diminuisce proporzionalmente la semplicità - qualcosa da evitare se ti interessa la padronanza del codice. Provo a seguire i principi KISS e DRY

Cattiva soluzione n. 2 : modifica di Bank direttamente attraverso i setter nativi; - veramente male. Se avrai mai bisogno di spostare le modifiche in Service , sarà doloroso. La logica aziendale dovrebbe rimanere nel livello della logica aziendale. Inoltre , ci sono piani per la registrazione di tutte le azioni e forse anche per le autorizzazioni degli utenti (forse attraverso i decoratori) in futuro, quindi tutte le modifiche dovrebbero essere apportate solo tramite Service .

Possibile soluzione valida : creazione di un metodo updateBank( Bank $bank, $array_of_fields_to_update) ; - rende l'interfaccia il più semplice possibile, ma c'è un problema: uno dovrebbe non provare a impostare manualmente isDefault flag su un banco, questa operazione dovrebbe essere eseguita attraverso il metodo setDefaultBank . Diventa ancora peggio quando hai relazioni che non vuoi modificare direttamente.

Ovviamente, puoi semplicemente limitare i campi che possono essere modificati con questo metodo, ma come fai a dire all'utente del metodo che cosa possono e non possono modificare? Eccezioni?

    
posta G. Kashtanov 08.02.2014 - 13:06
fonte

2 risposte

1

La decisione che ho preso

Ho reso setDefaultBank un metodo protetto e rimosso da IBankService interfaccia pubblica. Ho anche creato un metodo updateBank( $bank, array $fields ) che filtra l'array $fields e chiama setter corrispondenti su Bank . Se viene rilevato un campo default , viene verificato uguale a true e setDefaultBank viene chiamato. Qualsiasi elemento non valido in $fields causa la generazione di \InvalidArgumentException .

/**
 * Updates Bank fields
 *
 * @param int|Bank $bank    Bank ID or instance
 * @param array    $fields  Associative array of Bank fields
 *
 * @return IBankRegistryService
 * @throws \InvalidArgumentException
 */
public function updateBank( $bank, array $fields )
{
    if(    false === $bank instanceof Bank
        && 0 < intval( $bank ) )
    {
        /** @var $bank Bank */
        $bank = $this->getBanksRepository()->find( $bank );
    }
    else
        throw new \InvalidArgumentException( '$bank should be either an ID or a Bank instance.' );

    foreach( $fields AS $key => $value )
    {
        switch( $key )
        {
            case 'bik':
                $bank->setBik( $value );
                break;

            case 'name':
                $bank->setName( $value );
                break;

            case 'correspondent_account':
                $bank->setCorrespondentAccount( $value );
                break;

            case 'default':
                if( !$value )
                    throw new \InvalidArgumentException( 'Property "default" can only be equal to true' );

                $this->setDefaultBank( $bank );

                break;

            default:
                throw new \InvalidArgumentException( 'Cannot change "' . $key . '" property of a Bank' );
        }
    }

    return $this;
}
    
risposta data 09.02.2014 - 15:24
fonte
-1

Forse CQRS vale la pena cercarti.

link

Più in particolare:

Interacting with the command-model naturally falls into commands or events, which meshes well with Event Sourcing.

Quindi, in questo modello, si inviano aggiornamenti al modello di dominio utilizzando i comandi inviati tramite. eventi.

    
risposta data 08.10.2014 - 10:39
fonte

Leggi altre domande sui tag