Too many parameter types.
Further refactoring
Approaching the development of the ELH_ListingsRetriever
class I’ve took another look at the code of the previously developed ELH_ShopRetriever
class and was able to reduce its code moving it to the parent both classes share; the class itself is slimmer now
class ELH_ShopRetriever extends ELH_RequestingSyncStep {
public static function instance( ELH_KeychainInterface $keychain, ELH_ApiInterface $api, ELH_ApiRequestInterface $request, ELH_RequestCompilerInterface $request_compiler ) {
$instance = new self();
$instance->keychain = $keychain;
$instance->api = $api;
$instance->request = $request;
$instance->request_compiler = $request_compiler;
return $instance;
}
/**
* @param $data
*
* @throws ELH_SyncException
*/
protected function ensure_request_specifics( $data ) {
if ( $data['response']['code'] != '200' ) {
$message = sprintf( 'Shop retrieving failed with code %d and message "%s"', $data['response']['code'], $data['response']['message'] );
throw new ELH_SyncException( $message );
}
}
/**
* @return array
*/
protected function get_request_data() {
$data = array(
'user_id' => get_option( ELH_Main::USER_ID_OPTION ),
'api_key' => $this->api->get_api_key()
);
return $data;
}
}
and would be even further if I had eschewed the code duplication in the instance
method in favor of late static binding throwing PHP 5.2 compatibility out of the window; I’ve decided to develop for WordPress current minimum requirements and will get along.
Why all this refactoring?
In a world: laziness and adherence to some self-imposed and commonly accepted TDD rules: I want to cover all the code I write so any additional code I write will force me to pay in new tests (code nonetheless). So keep code down to write less tests.
New types
A quick look at the Etsy documentation about the method reveals that the request to fetch a shop listings will take more parameters and of a more complex nature then the ones that are required to fetch the list of a user shops.
Due to this I need to get back to the class responsible for the validation of the request parameters and add the missing types.
Some TDDing later all the needed types are added and I will be able to begin working on the class responsible for the retrieval of a shop listings.
class ELH_TypeUtils {
public static function is_a( $value, $type ) {
if ( ! is_scalar( $value ) ) {
return false;
}
$check = false;
try {
$types = strpos( $type, '|' ) ? explode( '|', $type ) : array( $type );
foreach ( $types as $_type ) {
switch ( $_type ) {
case 'string':
$check = $check || self::is_string( $value );
break;
case 'int':
$check = $check || self::is_int( $value );
break;
case 'float':
$check = $check || self::is_float( $value );
break;
case 'bool':
$check = true;
break;
case 'hsv';
$check = $check || self::is_hsv( $value );
break;
case 'rgb';
$check = $check || self::is_rgb( $value );
break;
default:
$check = $check || self::is_in_enum( $value, $_type ) || self::is_in_interval( $value, $_type ) || self::is_in_list( $value, $_type );
break;
}
}
} catch ( Exception $e ) {
}
return $check;
}
public static function is_string( $value ) {
return is_string( $value );
}
public static function is_int( $value ) {
return ( is_numeric( $value ) && intval( $value ) == floatval( $value ) );
}
public static function is_float( $value ) {
return is_numeric( $value ) && ( is_float( floatval( $value ) ) || is_int( intval( $value ) ) );
}
public static function is_hsv( $value ) {
$m = array();
if ( preg_match( '/^(\\d+);(\\d+);(\\d+)$/', $value, $m ) ) {
return $m[1] >= '0' && $m[2] >= '0' && $m[3] >= '0' && $m[1] <= '360' && $m[2] <= '100' && $m[3] <= '100';
}
return false;
}
public static function is_rgb( $value ) {
return preg_match( '/^#*(?:[0-9a-fA-F]{3}){1,2}$/', $value );
}
public static function is_in_enum( $value, $type ) {
$m = array();
if ( preg_match( '/^\\{(.+)\\}$/', $type, $m ) ) {
$legit = $m[1];
return in_array( $value, explode( ',', $legit ) );
}
return false;
}
public static function is_in_interval( $value, $_type ) {
$m = array();
if ( preg_match( '/^\\[(.+)-(.+)\\]$/', $_type, $m ) ) {
return in_array( $value, range( $m[1], $m[2] ) );
}
return false;
}
public static function is_in_list( $value, $_type ) {
$m = array();
if ( preg_match( '/^\\[(\w+)\\]$/', $_type, $m ) ) {
if ( is_string( $value ) ) {
if ( ! strpos( $value, ',' ) ) {
return true;
}
foreach ( explode( ',', $value ) as $v ) {
if ( ! self::is_a( $v, $m[1] ) ) {
return false;
}
return true;
}
}
return false;
}
return false;
}
}
I’ve also modified the ELH_ShopListingsApiRequest
to use the new fields
class ELH_ShopListingsApiRequest implements ELH_ApiRequestInterface {
private $parameters;
public function __construct() {
$this->parameters = array(
new ELH_ApiRequestParameter( 'shop_id', true, false, 'string|int' ),
new ELH_ApiRequestParameter( 'limit', false, 25, 'int' ),
new ELH_ApiRequestParameter( 'offset', false, 0, 'int' ),
new ELH_ApiRequestParameter( 'page', false, false, 'int' ),
new ELH_ApiRequestParameter( 'keywords', false, false, 'string' ),
new ELH_ApiRequestParameter( 'sort_on', false, 'created', '{created,price,score}' ),
new ELH_ApiRequestParameter( 'sort_order', false, 'down', '{up,down}' ),
new ELH_ApiRequestParameter( 'min_price', false, false, 'float' ),
new ELH_ApiRequestParameter( 'max_price', false, false, 'float' ),
new ELH_ApiRequestParameter( 'color', false, false, 'hsv|rgb' ),
new ELH_ApiRequestParameter( 'color_accuracy', false, 0, '[0-30]' ),
new ELH_ApiRequestParameter( 'tags', false, false, '[string]' ),
new ELH_ApiRequestParameter( 'category', false, false, 'string' ),
new ELH_ApiRequestParameter( 'translate_keywords', false, 0, 'bool' ),
new ELH_ApiRequestParameter( 'include_private', false, 0, 'bool' ),
);
}
/**
* @return string
*/
public function uri() {
return '/users/:shop_id/listings/active';
}
/**
* @return string
*/
public function method() {
return 'findAllShopListingsActive';
}
/**
* @return bool
*/
public function requires_OAuth() {
return false;
}
/**
* @return string
*/
public function permission_scope() {
return 'none';
}
public function http_method() {
return 'GET';
}
public function parameters() {
return $this->parameters;
}
}
Next
I will finally code the ELH_ShopRetriever
class and begin a complete thought about what the sync chain is supposed to do.