Я построил первый веб-сервис на Zend Framework (1.10), и теперь я ищу способы рефакторинга некоторой логики в моих контроллерах действий, чтобы было легче для меня и всей моей команды, чтобы расширить и поддерживать обслуживание.Zend Action Controller - стратегия рефакторинга
Я могу видеть, где есть возможности для рефакторинга, но я не знаю, как наилучшие стратегии. Лучшая документация и учебные пособия на контроллерах говорят только о небольших приложениях, и на самом деле не обсуждают, как абстрагироваться от более повторяющегося кода, который проникает в более крупные масштабы.
Базовая структура для наших контроллеров действий являются:
- Извлечения XML сообщение из тела запроса - Это включает в себя проверку на действия конкретного RelaxNG схему
- Подготовьте ответ XML
- проверки достоверности данных в сообщении запроса (неверные данные генерируют исключение - сообщение добавляется в ответ, который отправляется немедленно)
- Выполнение действия базы данных (select/insert/update/delete)
- Возвращение успех или неудачу действий, с необходимой информацией
Простой пример это действие, которое возвращает список поставщиков, основанный на гибком наборе критериев:
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();
}
}
Так что - зная, где общие черты находятся в моих контроллерах, что является лучшей стратегией для рефакторинга, сохраняя его Zend-подобным, а также проверяемым с помощью PHPUnit?
Я действительно думал об абстрагировании большей логики контроллера в родительский класс (Lib_Controller_Action), но это делает модульное тестирование более сложным способом, который кажется мне неправильным.
Может быть, вытесните общность в классы обслуживания/хранилища? Такие классы будут тестируемыми, будут использоваться для контроллеров и могут сделать код контроллера более компактным. –
Другим подходом было бы собрать общность в помощниках действий. –