refactoing exposers, mappers has no function only props, class exposers do the mapping, some function modification for using on export feature, some fix and docs

This commit is contained in:
Jacson Passold 2018-04-12 16:45:29 -03:00
parent 5e8b2a08a0
commit 7967702910
9 changed files with 128 additions and 86 deletions

View File

@ -12,6 +12,16 @@ class Exposers {
private $types = []; private $types = [];
private $mappers = []; private $mappers = [];
private static $instance = null;
const MAPPER_CLASS_PREFIX = 'Tainacan\Exposers\Mappers\\';
public static function get_instance() {
if ( ! isset( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
public function __construct() { public function __construct() {
$this->register_exposer_type('Tainacan\Exposers\Types\Xml'); $this->register_exposer_type('Tainacan\Exposers\Types\Xml');
@ -59,17 +69,30 @@ class Exposers {
} }
} }
protected function check_class_name($class_name, $root = false, $prefix = 'Tainacan\Exposers\Types\\') { /**
* Return namespaced class name
* @param string $class_name
* @param boolean $root
* @param string $prefix
* @return string
*/
public function check_class_name($class_name, $root = false, $prefix = 'Tainacan\Exposers\Types\\') {
$class = $prefix.sanitize_text_field($class_name); $class = $prefix.sanitize_text_field($class_name);
$class = str_replace(['-', ' '], ['_', '_'], $class); $class = str_replace(['-', ' '], ['_', '_'], $class);
return ($root ? '\\' : '').$class; return ($root ? '\\' : '').$class;
} }
/**
* Check if rest response need mapper
* @param array $item_arr
* @param \WP_REST_Request $request
* @return array
*/
public function rest_response($item_arr, $request) { public function rest_response($item_arr, $request) {
if($request->get_method() == 'GET' && substr($request->get_route(), 0, strlen('/tainacan/v2')) == '/tainacan/v2') { if($request->get_method() == 'GET' && substr($request->get_route(), 0, strlen('/tainacan/v2')) == '/tainacan/v2') {
if($exposer = $this->hasMapper($request)) { if($exposer = $this->request_has_mapper($request)) {
return $exposer->rest_response($item_arr, $request); return $this->map($item_arr, $exposer, $request); //TODO request -> args
} }
} }
return $item_arr; return $item_arr;
@ -77,6 +100,36 @@ class Exposers {
/** /**
* *
* @param array $item_arr
* @param Mappers\Mapper $mapper
* @param \WP_REST_Request $resquest
* @return array
*/
protected function map($item_arr, $mapper, $resquest) {
$ret = $item_arr;
if(array_key_exists('field', $item_arr)){ // getting a unique field
$field_mapping = $item_arr['field']['exposer_mapping'];
if(array_key_exists($mapper->slug, $field_mapping)) {
$ret = [$mapper->prefix.$field_mapping[$mapper->slug]['name'].$mapper->sufix => $item_arr['value']];
} else if($mapper->slug == 'value') {
$ret = [$item_field['field']['name'] => $item_arr['value']];
}
} else { // array of elements
$ret = [];
foreach ($item_arr as $item_field) {
$field_mapping = $item_field['field']['exposer_mapping'];
if(array_key_exists($mapper->slug, $field_mapping)) {
$ret[$mapper->prefix.$field_mapping[$mapper->slug]['name'].$mapper->sufix] = $item_field['value'];
} else if($mapper->slug == 'value') {
$ret[$item_field['field']['name']] = $item_field['value'];
}
}
}
return $ret;
}
/**
* adapt request response to exposer type
* @param \WP_REST_Response $response * @param \WP_REST_Response $response
* @param \WP_REST_Server $handler * @param \WP_REST_Server $handler
* @param \WP_REST_Request $request * @param \WP_REST_Request $request
@ -84,7 +137,7 @@ class Exposers {
*/ */
public function rest_request_after_callbacks( $response, $handler, $request ) { public function rest_request_after_callbacks( $response, $handler, $request ) {
if($request->get_method() == 'GET' && substr($request->get_route(), 0, strlen('/tainacan/v2')) == '/tainacan/v2') { if($request->get_method() == 'GET' && substr($request->get_route(), 0, strlen('/tainacan/v2')) == '/tainacan/v2') {
if($exposer = $this->hasType($request)) { if($exposer = $this->request_has_type($request)) {
return $exposer->rest_request_after_callbacks($response, $handler, $request); return $exposer->rest_request_after_callbacks($response, $handler, $request);
} }
} }
@ -92,45 +145,64 @@ class Exposers {
return $response; return $response;
} }
/**
* Return if type is registered
* @param string $type
* @return boolean
*/
public function has_type($type) {
return in_array($this->check_class_name($type), $this->types);
}
/** /**
* Return Type with request has type, false otherwise * Return Type with request has type, false otherwise
* @param \WP_REST_Request $request * @param \WP_REST_Request $request
* @return Types\Type|boolean false * @return Types\Type|boolean false
*/ */
public function hasType($request) { public static function request_has_type($request) {
$body = json_decode( $request->get_body(), true ); $body = json_decode( $request->get_body(), true );
$Tainacan_Exposers = self::get_instance();
if( if(
is_array($body) && array_key_exists('exposer-type', $body) && is_array($body) && array_key_exists('exposer-type', $body) &&
in_array($this->check_class_name($body['exposer-type']), $this->types) $Tainacan_Exposers->has_type($body['exposer-type'])
) { ) {
$type = $this->check_class_name($body['exposer-type'], true); $type = $Tainacan_Exposers->check_class_name($body['exposer-type'], true);
return new $type; return new $type;
} }
return false; return false;
} }
/**
* Return if mapper is registered
* @param string $mapper
* @return boolean
*/
public function has_mapper($mapper) {
return in_array($this->check_class_name($mapper, false, self::MAPPER_CLASS_PREFIX), $this->mappers);
}
/** /**
* Check if there is a mapper * Check if there is a mapper
* @param \WP_REST_Request $request * @param \WP_REST_Request $request
* @return Mappers/Mapper|boolean false * @return Mappers\Mapper|boolean false
*/ */
public function hasMapper($request) { public static function request_has_mapper($request) {
$body = json_decode( $request->get_body(), true ); $body = json_decode( $request->get_body(), true );
$class_prefix = 'Tainacan\Exposers\Mappers\\'; $Tainacan_Exposers = self::get_instance();
$type = $this->hasType($request);
$type = self::request_has_type($request);
if( // There are a defined mapper if( // There are a defined mapper
is_array($body) && array_key_exists('exposer-map', $body) && is_array($body) && array_key_exists('exposer-map', $body) &&
in_array($this->check_class_name($body['exposer-map'], false, $class_prefix), $this->mappers) $Tainacan_Exposers->has_mapper($body['exposer-map'])
) { ) {
if( if(
$type === false || // do not have a exposer type $type === false || // do not have a exposer type
$type->mappers === true || // the type accept all mappers $type->mappers === true || // the type accept all mappers
( is_array($type->mappers) && in_array($body['exposer-map'], $type->mappers) ) ) { // the current mapper is accepted by type ( is_array($type->mappers) && in_array($body['exposer-map'], $type->mappers) ) ) { // the current mapper is accepted by type
$mapper = $this->check_class_name($body['exposer-map'], true, $class_prefix); $mapper = $Tainacan_Exposers->check_class_name($body['exposer-map'], true, self::MAPPER_CLASS_PREFIX);
return new $mapper; return new $mapper;
} }
} elseif( is_array($type->mappers) && count($type->mappers) > 0 ) { //there are no defined mapper, let use the first one o list if has a list } elseif( is_array($type->mappers) && count($type->mappers) > 0 ) { //there are no defined mapper, let use the first one o list if has a list
$mapper = $this->check_class_name($type->mappers[0], true, $class_prefix); $mapper = $Tainacan_Exposers->check_class_name($type->mappers[0], true, self::MAPPER_CLASS_PREFIX);
return new $mapper; return new $mapper;
} }
return false; // No mapper need, using Tainacan defautls return false; // No mapper need, using Tainacan defautls

View File

@ -3,47 +3,19 @@
namespace Tainacan\Exposers\Mappers; namespace Tainacan\Exposers\Mappers;
class Dublin_Core extends Mapper { class Dublin_Core extends Mapper {
public $type = 'DublinCore'; public $slug = 'dublin-core';
public $name = 'Dublin Core'; public $name = 'Dublin Core';
public $allow_extra_fields = true; public $allow_extra_fields = true;
public $context_url = 'http://dublincore.org/documents/dcmi-terms/'; public $context_url = 'http://dublincore.org/documents/dcmi-terms/';
public $header = ''; public $header = '<?xml version="1.0"?><!DOCTYPE rdf:RDF SYSTEM "http://dublincore.org/2000/12/01-dcmes-xml-dtd.dtd"><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" ></rdf:RDF>';
const XML_DC_NAMESPACE = 'http://purl.org/dc/elements/1.1/'; public $prefix = 'dc:';
const XML_RDF_NAMESPACE = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
public $options = []; public $options = [];
public function rest_response($item_arr, $request) { /** XML especial case **/
$ret = $item_arr; const XML_DC_NAMESPACE = 'http://purl.org/dc/elements/1.1/';
if(array_key_exists('field', $item_arr)){ // getting a unique field const XML_RDF_NAMESPACE = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
$field_mapping = $item_arr['field']['exposer_mapping']; public $XML_namespace = 'http://purl.org/dc/elements/1.1/';
if(array_key_exists('dublin-core', $field_mapping)) { public $XML_append_root = 'rdf:Description';
$ret = ['dc:'.$field_mapping['dublin-core']['name'] => $item_arr['value']]; /** END: XML especial case **/
}
} else { // array of elements
$ret = [];
foreach ($item_arr as $item_field) {
$field_mapping = $item_field['field']['exposer_mapping'];
if(array_key_exists('dublin-core', $field_mapping)) {
$ret['dc:'.$field_mapping['dublin-core']['name']] = $item_field['value'];
}
}
}
$body = json_decode( $request->get_body(), true );
if( // treat special cases TODO better way
is_array($body) && array_key_exists('exposer-type', $body) &&
strtolower($body['exposer-type']) == 'xml'
) {
add_filter('tainacan-exposer-head', [$this, 'tainacan_xml_exposer_head']);
add_filter('tainacan-xml-namespace', function($namespace) {return self::XML_DC_NAMESPACE;});
add_filter('tainacan-xml-root', function($xml) { return $xml->addChild('rdf:Description'); });
}
return $ret;
}
public function tainacan_xml_exposer_head($head) {
$head = '<?xml version="1.0"?><!DOCTYPE rdf:RDF SYSTEM "http://dublincore.org/2000/12/01-dcmes-xml-dtd.dtd"><rdf:RDF xmlns:rdf="'.self::XML_RDF_NAMESPACE.'" xmlns:dc="'.self::XML_DC_NAMESPACE.'" ></rdf:RDF>';
return $head;
}
} }

View File

@ -3,10 +3,14 @@
namespace Tainacan\Exposers\Mappers; namespace Tainacan\Exposers\Mappers;
abstract class Mapper { abstract class Mapper {
public $type = null; public $slug = null;
public $name = null; public $name = null;
public $allow_extra_fields = true; public $allow_extra_fields = true;
public $context_url = null; public $context_url = null;
public $opstions = false;
public $prefix = '';
public $sufix = '';
public $header = false;
public abstract function rest_response($item_arr, $request); //public abstract function rest_response($item_arr, $request);
} }

View File

@ -3,33 +3,11 @@
namespace Tainacan\Exposers\Mappers; namespace Tainacan\Exposers\Mappers;
class Value extends Mapper { class Value extends Mapper {
public $type = 'Value'; public $slug = 'value';
public $name = 'value'; public $name = 'Value';
public $allow_extra_fields = true; public $allow_extra_fields = true;
public $context_url = ''; public $context_url = '';
public $header = ''; public $header = '';
public $options = []; public $options = [];
public function rest_response($item_arr, $request) {
$ret = $item_arr;
if(array_key_exists('field', $item_arr)){ // getting a unique field
$field_mapping = $item_arr['field']['exposer_mapping'];
if(array_key_exists($this->name, $field_mapping)) {
$ret = [$field_mapping['value']['name'] => $item_arr['value']];
} else {
$ret = [$item_field['field']['name'] => $item_arr['value']];
}
} else { // array of elements
$ret = [];
foreach ($item_arr as $item_field) {
$field_mapping = $item_field['field']['exposer_mapping'];
if(array_key_exists($this->name, $field_mapping)) {
$ret[$field_mapping[$this->name]['name']] = $item_field['value'];
} else {
$ret[$item_field['field']['name']] = $item_field['value'];
}
}
}
return $ret;
}
} }

View File

@ -4,7 +4,7 @@ namespace Tainacan\Exposers\Types;
class Csv extends Type { class Csv extends Type {
public $mappers = ['value']; public $mappers = ['Value'];
/** /**
* *

View File

@ -4,7 +4,7 @@ namespace Tainacan\Exposers\Types;
class Html extends Type { class Html extends Type {
public $mappers = ['value']; public $mappers = ['Value'];
/** /**
* *

View File

@ -4,7 +4,7 @@ namespace Tainacan\Exposers\Types;
class Txt extends Type { class Txt extends Type {
public $mappers = ['value']; public $mappers = ['Value'];
/** /**
* *

View File

@ -10,9 +10,24 @@ class Xml extends Type {
*/ */
public function rest_request_after_callbacks( $response, $handler, $request ) { public function rest_request_after_callbacks( $response, $handler, $request ) {
$response->set_headers( ['Content-Type: application/xml; charset=' . get_option( 'blog_charset' )] ); $response->set_headers( ['Content-Type: application/xml; charset=' . get_option( 'blog_charset' )] );
$xml = new \SimpleXMLElement(apply_filters('tainacan-exposer-head', '<?xml version="1.0"?><data></data>')); $mapper = \Tainacan\Exposers\Exposers::request_has_mapper($request);
$namespace = apply_filters('tainacan-xml-namespace', null); $xml = new \SimpleXMLElement( '<?xml version="1.0"?><data></data>' );
$this->array_to_xml($response->get_data(), apply_filters('tainacan-xml-root', $xml), $namespace); $namespace = null;
$xml_root = $xml;
if($mapper) {
if(!empty($mapper->header)) {
$xml = new \SimpleXMLElement( $mapper->header );
}
if(property_exists($mapper, 'XML_namespace') && !empty($mapper->XML_namespace)) {
$namespace = $mapper->XML_namespace;
}
if(property_exists($mapper, 'XML_append_root') && !empty($mapper->XML_append_root)) {
$xml_root = $xml->addChild($mapper->XML_append_root);
}
}
$this->array_to_xml($response->get_data(), $xml_root, $namespace);
$response->set_data($xml->asXml()); $response->set_data($xml->asXml());
return $response; return $response;
} }

View File

@ -58,6 +58,9 @@ class TAINACAN_REST_Exposers extends TAINACAN_UnitApiTestCase {
return ['collection' => $collection, 'item' => $item, 'field' => $field]; return ['collection' => $collection, 'item' => $item, 'field' => $field];
} }
/**
* @group xml_exposer
*/
public function test_xml_exposer() { public function test_xml_exposer() {
global $Tainacan_Fields, $Tainacan_Item_Metadata; global $Tainacan_Fields, $Tainacan_Item_Metadata;
@ -99,7 +102,6 @@ class TAINACAN_REST_Exposers extends TAINACAN_UnitApiTestCase {
$response = $this->server->dispatch($request); $response = $this->server->dispatch($request);
$this->assertEquals(200, $response->get_status()); $this->assertEquals(200, $response->get_status());
$data = $response->get_data(); $data = $response->get_data();
$this->assertEquals('TestValues_exposers', $data['dc:language']); $this->assertEquals('TestValues_exposers', $data['dc:language']);
$item_exposer_json = json_encode([ $item_exposer_json = json_encode([
@ -155,14 +157,13 @@ class TAINACAN_REST_Exposers extends TAINACAN_UnitApiTestCase {
$item_exposer_json = json_encode([ $item_exposer_json = json_encode([
'exposer-type' => 'Html', 'exposer-type' => 'Html',
'exposer-map' => 'value' 'exposer-map' => 'Value'
]); ]);
$request = new \WP_REST_Request('GET', $this->namespace . '/item/' . $item->get_id() . '/metadata' ); $request = new \WP_REST_Request('GET', $this->namespace . '/item/' . $item->get_id() . '/metadata' );
$request->set_body($item_exposer_json); $request->set_body($item_exposer_json);
$response = $this->server->dispatch($request); $response = $this->server->dispatch($request);
$this->assertEquals(200, $response->get_status()); $this->assertEquals(200, $response->get_status());
$data = $response->get_data(); $data = $response->get_data();
// Parse HTML reponse // Parse HTML reponse
$doc = new \DOMDocument(); $doc = new \DOMDocument();
$this->assertTrue($doc->loadHTML($data)); $this->assertTrue($doc->loadHTML($data));