Ho creato un servizio Web di prima esecuzione su Zend Framework (1.10), e ora sto cercando i modi per ridefinire parte della logica nei miei controller di azione in modo che sia più facile per me e il resto della mia squadra per espandere e mantenere il servizio.Zend Action Controller - strategia di refactoring
Posso vedere dove ci sono opportunità per il refactoring, ma non sono chiaro sulle migliori strategie su come. La migliore documentazione e tutorial sui controller parlano solo di applicazioni su piccola scala e non discutono in realtà su come astrarre il codice più ripetitivo che si insinua in scale più grandi.
La struttura di base per i nostri controllori di azione sono:
- estratto messaggio XML dal corpo della richiesta - Questo include la convalida contro uno schema relaxNG specifica azione
- Preparare la risposta XML
- convalidare i dati nel messaggio di richiesta (i dati non validi generano un'eccezione - un messaggio viene aggiunto alla risposta che viene inviata immediatamente)
- Eseguire l'azione del database (selezionare/inserire/aggiornare/eliminare)
- Rientro successo o il fallimento di azione, con le informazioni richieste
Un semplice esempio è questa azione che restituisce un elenco di fornitori sulla base di un insieme flessibile di criteri:
class Api_VendorController extends Lib_Controller_Action
{
public function getDetailsAction()
{
try {
$request = new Lib_XML_Request('1.0');
$request->load($this->getRequest()->getRawBody(), dirname(__FILE__) . '/../resources/xml/relaxng/vendor/getDetails.xml');
} catch (Lib_XML_Request_Exception $e) {
// Log exception, if logger available
if ($log = $this->getLog()) {
$log->warn('API/Vendor/getDetails: Error validating incoming request message', $e);
}
// Elevate as general error
throw new Zend_Controller_Action_Exception($e->getMessage(), 400);
}
$response = new Lib_XML_Response('API/vendor/getDetails');
try {
$criteria = array();
$fields = $request->getElementsByTagName('field');
for ($i = 0; $i < $fields->length; $i++) {
$name = trim($fields->item($i)->attributes->getNamedItem('name')->nodeValue);
if (!isset($criteria[$name])) {
$criteria[$name] = array();
}
$criteria[$name][] = trim($fields->item($i)->childNodes->item(0)->nodeValue);
}
$vendors = $this->_mappers['vendor']->find($criteria);
if (count($vendors) < 1) {
throw new Api_VendorController_Exception('Could not find any vendors matching your criteria');
}
$response->append('success');
foreach ($vendors as $vendor) {
$v = $vendor->toArray();
$response->append('vendor', $v);
}
} catch (Api_VendorController_Exception $e) {
// Send failure message
$error = $response->append('error');
$response->appendChild($error, 'message', $e->getMessage());
// Log exception, if logger available
if ($log = $this->getLog()) {
$log->warn('API/Account/GetDetails: ' . $e->getMessage(), $e);
}
}
echo $response->save();
}
}
Così - sapere dove i punti in comune sono nei miei controller, qual è la migliore strategia per il refactoring mantenendola simile a Zend e anche testabile con PHPUnit?
Ho pensato di astrarre maggiormente la logica del controllore in una classe genitore (Lib_Controller_Action), ma ciò rende la verifica dell'unità più complicata in un modo che mi sembra sbagliato.
Forse spingere la comunanza verso il basso nelle classi servizio/repository? Tali classi sarebbero testabili, sarebbero utilizzabili su tutti i controller e potrebbero rendere il codice del controller più compatto. –
Un altro approccio sarebbe quello di raccogliere comunanza in aiutanti di azione. –