Updating an Entity through a Service
Posted
by
GeorgeK
on Programmers
See other posts from Programmers
or by GeorgeK
Published on 2014-02-08T12:06:56Z
Indexed on
2014/06/09
21:39 UTC
Read the original article
Hit count: 286
I'm separating my software into three main layers (maybe tiers would be a better term):
- Presentation ('Views')
- Business logic ('Services' and 'Repositories')
- Data access ('Entities' (e.g. ActiveRecords))
What do I have now?
In Presentation, I use read-only access to Entities, returned from Repositories or Services, to display data.
$banks = $banksRegistryService->getBanksRepository()->getBanksByCity( $city );
$banksViewModel = new PaginatedList( $banks ); // some way to display banks;
// example, not real code
I find this approach quite efficient in terms of performance and code maintanability and still safe as long as all write operations (create, update, delete) are preformed through a 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;
}
}
Where am I stuck?
I'm struggling about how to update certain fields in Bank
Entity.
Bad solution #1: Making a series of setters in Service
for each setter in Bank
; - seems to be quite reduntant, increases Service
interface complexity and proportionally decreases it's simplicity - something to avoid if you care about code maitainability. I try to follow KISS and DRY principles.
Bad solution #2: Modifying Bank
directly through it's native setters; - really bad. If you'll ever need to move modification into the Service
, it will be pain. Business logic should remain in Business logic layer. Plus, there are plans on logging all of the actions and maybe even involve user permissions (perhaps, through decorators) in future, so all modifications should be made only through the Service
.
Possible good solution: Creating an updateBank( Bank $bank, $array_of_fields_to_update)
method; - makes the interface as simple as possible, but there is a problem: one should not try to manually set isDefault
flag on a Bank, this operation should be performed through setDefaultBank
method. It gets even worse when you have relations that you don't want to be directly modified.
Of course, you can just limit the fields that can be modified by this method, but how do you tell method's user what they can and cannot modify? Exceptions?
© Programmers or respective owner