I re-wrote an old project and tried to update my spaghetti code with SOLID principles and design patterns. Most of the re-write seemed straight forward, but my front-end controller still looks complicated. I attempted a 'strategy' pattern where the controller instantiates four objects - Interpreter, URLConstructor, Extractor, & Builder - by selecting a specific class for each of the four based on setting in a config file. The code sample is below (sorry if it's long, but I thought I should include the real code.) Is this actually a 'strategy' pattern? As written is this code unit testable? I would like to learn more about dependency injection and unit testing and I worry that this code is a bad example for either.
<?php
interface iController
{
public function processRequest(iConfig $config, iHTTPRequest $http_request);
}
?>
<?php
class ControllerSearch extends aController implements iController
{
public function __construct(iConfig $config, iHTTPRequest $http_request){
$this->_results = new Results();
$this->_process_profiles = $config->getProcessProfiles();
$this->_resource_packages = new Set();
}
public function processRequest(iConfig $config, iHTTPRequest $http_request){
if ( $http_request->getKEV('query') !== '' ) {
$this->_createResourcePackages($config, $http_request);
$this->_retrieveURLs($config);
$this->_executeDataModeling($config);
$this->_results->titleSort();
foreach ( $this->_results as $result ) {
$this->_setSessionData($result);
}
}
$view = new ViewSearch($config, $http_request);
$view->compose($this->_results, $http_request);
$arr = array();
$arr['logo_src'] = $config->getParam('logo_src');
$arr['css_default_href'] = $config->getParam('css_default_href');
$arr['css_custom_href'] = $config->getParam('css_custom_href');
$arr['resource_packages'] = $this->_resource_packages;
$arr['http_request'] = $http_request->getArray();
$arr['model'] = $this->_results; //TODO: remove in prod
$view->renderTemplate($arr);
}
}
?>
<?php
class ControllerAvailability extends aController implements iController
{
public function __construct(iConfig $config, iHTTPRequest $http_request){
$this->_results = new Results();
$this->_process_profiles = $config->getProcessProfiles();
$this->_resource_packages = new Set();
}
public function processRequest(iConfig $config, iHTTPRequest $http_request){
$this->_createResourcePackages($config, $http_request);
$this->_retrieveURLs($config);
$this->_executeDataModeling($config);
$this->_results->titleSort();
$arr = array();
$arr['resource_packages'] = $this->_resource_packages;
$view = new ViewAvailability($config, $http_request);
$view->compose($this->_results, $http_request);
$view->renderTemplate($arr);
}
}
?>
<?php
abstract class aController
{
protected $_results = NULL;
protected $_process_profiles = NULL;
protected $_resource_packages = NULL;
protected function _createResourcePackages(iConfig $config, iHTTPRequest $http_request){
foreach ( $this->_process_profiles as $process_profile ) {
if ( $resource_package = $this->_createResourcePackage($config, $process_profile, $http_request) ) {
$this->_resource_packages->addMember($resource_package);
}
}
}
protected function _retrieveURLs(iConfig $config){
$all_content_loaded = TRUE;
foreach ($this->_resource_packages as $i => $rp) {
if ( $content = $this->_getCachedData($rp->getURL()) ) {
$rp->setContent($content);
} else {
$all_content_loaded = FALSE;
trigger_error('Could not retrieve a URL: ' . $rp->getURL(), E_USER_ERROR);
}
}
return $all_content_loaded;
}
protected function _executeDataModeling(iConfig $config){
$modeled_data_added = TRUE;
foreach ( $this->_resource_packages as $resource_package ) {
$extractor = $this->_selectExtractor($config, $resource_package->getProcessProfile());
$builder = $this->_selectBuilder($config, $resource_package->getProcessProfile());
if ( $extractor !== FALSE && $builder !== FALSE ) {
$extractor->extract($resource_package->getContent());
$resource_package->setHits($extractor->getHits());
$elements = $extractor->getElements();
foreach ( $elements as $element ) {
$builder->buildModel($element);
if ( $this->_results->addResult($builder->getModel()) === FALSE ) {
$modeled_data_added = FALSE;
trigger_error('Could not add model to Results.', E_USER_ERROR);
}
}
} else {
$modeled_data_added = FALSE;
trigger_error('Failed to select Extractor and Builder', E_USER_ERROR);
}
}
return $modeled_data_added;
}
private function _createResourcePackage(iConfig $config, iProcessProfile $process_profile, iHTTPRequest $http_request){
$interpreter = $this->_selectInterpreter($config, $process_profile);
$url_constructor = $this->_selectURLConstuctor($config, $process_profile);
if ( $interpreter !== FALSE && $url_constructor !== FALSE ) {
$interpreter->interpret($config, $process_profile, $http_request);
$url_constructor->configure($config, $process_profile);
$url_constructor->setInterpretation($interpreter);
$url_constructor->evaluateHTTPRequest($http_request);
$url_constructor->buildURL();
if ( $rp = ResourcePackage::build($process_profile, $interpreter->getInterpretation(), $url_constructor->getURL()) ) {
return $rp;
} else {
trigger_error('Could not build ResourcePackage. ' . $process_profile->getID() . ' ' . $url_constructor->getURL(), E_USER_ERROR);
}
} else {
trigger_error('Failed to select Interpreter and URLConstructor', E_USER_ERROR);
}
return FALSE;
}
private function _selectInterpreter($config, $process_profile){
$name_interpreter = $config->getProcessParam($process_profile, 'interpreter');
if ( class_exists($name_interpreter) ){
return new $name_interpreter();
} else {
trigger_error('Interpreter class (' . $name_interpreter . ') does not exist for ' . $process_profile->getID(), E_USER_ERROR);
}
return FALSE;
}
private function _selectURLConstuctor($config, $process_profile){
$name_url_constructor = $config->getProcessParam($process_profile, 'url_constructor');
if ( class_exists($name_url_constructor) ){
return new $name_url_constructor();
} else {
trigger_error('URLConstuctor class (' . $name_url_constructor . ') does not exist for ' . $process_profile->getID(), E_USER_ERROR);
}
return FALSE;
}
private function _selectExtractor($config, $process_profile){
$name_extractor = $config->getProcessParam($process_profile, 'extractor');
if ( class_exists($name_extractor) ){
return new $name_extractor();
} else {
trigger_error('Extractor class (' . $name_extractor . ') does not exist for ' . $process_profile->getID(), E_USER_ERROR);
}
return FALSE;
}
private function _selectBuilder($config, $process_profile){
$name_builder = $config->getProcessParam($process_profile, 'builder');
if ( class_exists($name_builder) ){
return new $name_builder($config, $process_profile);
} else {
trigger_error('Builder class (' . $name_builder . ') does not exist for ' . $process_profile->getID(), E_USER_ERROR);
}
return FALSE;
}
private function _getCachedData($uri){
$response = FALSE;
if ( is_string($uri) && $uri !== '' ) {
$options = array(
'http' => array('timeout'=>5) //NOTE: timeout in seconds
);
$ctx = stream_context_create($options);
$response = @file_get_contents($uri, NULL, $ctx);
}
return $response;
}
protected function _setSessionData(iResult $result){
if ( session_id() !== '' ) {
if ( $result->getValue('session_key') !== '' ) {
$_SESSION[$result->getValue('session_key')]['iResult'] = serialize($result);
} else {
trigger_error('Could not get value for "session_key."', E_USER_ERROR);
}
} else {
trigger_error('No active PHP session, no session data stored.', E_USER_ERROR);
}
}
}
?>
Aucun commentaire:
Enregistrer un commentaire