Finish parser and unit test

This commit is contained in:
claudiulodro 2017-05-04 14:20:59 -07:00
parent d642212205
commit b907aa74f6
2 changed files with 286 additions and 44 deletions

View File

@ -114,18 +114,14 @@ class WC_Product_Importer extends WP_Importer {
$this->import_start();
$raw_data = $this->read_csv( $file, array( 'lines' => 3, 'parse' => true ) );
// TODO: Remove temporary code once mapping screen is ready.
// Mapping screen.
var_dump( $raw_data );
$data = $this->read_csv( $file, array( 'parse' => true ) );
// Show Result
echo '<div class="updated settings-error"><p>';
/* translators: %s: products count */
printf(
__( 'Import complete - imported %s products.', 'woocommerce' ),
'<strong>' . count( $raw_data['data'] ) . '</strong>'
'<strong>' . count( $data ) . '</strong>'
);
echo '</p></div>';
@ -174,7 +170,7 @@ class WC_Product_Importer extends WP_Importer {
* @param array $args See $default_args
* @return array
*/
public function read_csv( $file, $args ) {
public function read_csv( $file, $args = array() ) {
$default_args = array(
'start_pos' => 0, // File pointer start.
@ -202,7 +198,7 @@ class WC_Product_Importer extends WP_Importer {
$data['data'][] = $row;
$position = ftell( $handle );
if ( ( $args['end_pos'] > 0 && ftell( $handle ) >= $args['end_pos'] ) || 0 >= --$args[
if ( ( $args['end_pos'] > 0 && ftell( $handle ) >= $args['end_pos'] ) || 0 === --$args[
'lines'] ) {
break;
}
@ -223,7 +219,7 @@ class WC_Product_Importer extends WP_Importer {
/**
* @param array $mapping 'raw column name' => 'mapped column name'
*/
private function map_headers( $data, $mapping ) {
public function map_headers( $data, $mapping ) {
$data['headers'] = array();
foreach ( $data['raw_headers'] as $heading ) {
$data['headers'] = isset( $mapping[ $heading ] ) ? $mapping[ $heading ] : $heading;
@ -235,22 +231,26 @@ class WC_Product_Importer extends WP_Importer {
* Map and format raw data to known fields.
*
* @param array $data
* @return array
*/
private function parse_data( $data ) {
public function parse_data( $data ) {
// Columns not mentioned here will get parsed with 'esc_attr'.
// column_name => callback
$data_formatting = array(
'ID' => 'absint',
'Published' => 'boolval',
'Is featured' => 'boolval',
//'Date sale price starts' => 'wc_format_datetime',
//'Date sale price ends' => 'wc_format_datetime',
'In stock?' => 'boolval',
'Sold individually?' => 'boolval',
'Weight' => 'absint',
'Length' => 'absint',
'Height' => 'absint',
'Width' => 'absint',
'Allow customer reviews?' => 'boolval',
'Published' => array( $this, 'parse_bool_field' ),
'Is featured?' => array( $this, 'parse_bool_field' ),
'Date sale price starts' => 'strtotime',
'Date sale price ends' => 'strtotime',
'In stock?' => array( $this, 'parse_bool_field' ),
'Backorders allowed?' => array( $this, 'parse_bool_field' ),
'Sold individually?' => array( $this, 'parse_bool_field' ),
'Weight' => array( $this, 'parse_float_field' ),
'Length' => array( $this, 'parse_float_field' ),
'Height' => array( $this, 'parse_float_field' ),
'Width' => array( $this, 'parse_float_field' ),
'Allow customer reviews?' => array( $this, 'parse_bool_field' ),
'Purchase Note' => 'wp_kses',
'Price' => 'wc_format_decimal',
'Regular Price' => 'wc_format_decimal',
@ -263,52 +263,129 @@ class WC_Product_Importer extends WP_Importer {
'Download Limit' => 'absint',
'Download Expiry Days' => 'absint',
);
$regex_match_data_formatting = array(
'/Attribute * Value\(s\)/' => array( $this, 'parse_comma_field' ),
'/Attribute * Visible/' => 'boolval',
'/Download * URL/' => 'esc_url',
);
// special cases: attribute * name, attribute * value(s), attribute * default, attribute * visible
// Download 1 Name, Download 1 URL,
$headers = isset( $data['headers'] ) && ! empty( $data['headers'] ) ? $data['headers'] : $data['raw_headers'];
$parse_functions = array();
$parsed_data = array();
// Figure out the parse function for each column.
foreach ( $headers as $index => $heading ) {
// Figure out the parse function.
$formatting_function = 'esc_attr';
$parse_function = 'esc_attr';
if ( isset( $data_formatting[ $heading ] ) ) {
$formatting_function = $data_formatting[ $heading ];
$parse_function = $data_formatting[ $heading ];
}
else {
foreach ( $regex_match_data_formatting as $regex => $callback ) {
if ( preg_match( $regex, $heading ) ) {
$formatting_function = $callback;
$parse_function = $callback;
break;
}
}
}
// Go down the column parsing.
foreach ( $data['data'] as &$row ) {
$row[ $index ] = call_user_func( $formatting_function, $row[ $index ] );
$parse_functions[] = $parse_function;
}
// Parse the data.
foreach ( $data['data'] as $row ) {
$item = array();
foreach ( $row as $index => $field ) {
$item[ $headers[ $index ] ] = call_user_func( $parse_functions[ $index ], $field );
}
$parsed_data[] = $item;
}
return apply_filters( 'woocommerce_csv_product_parsed_data', $parsed_data, $data );
}
/**
* Parse a comma-delineated field from a CSV.
*
* @param string $field
* @return array
*/
public function parse_comma_field( $field ) {
if ( empty( $field ) ) {
return array();
}
return array_map( 'esc_attr', array_map( 'trim', explode( ',', $field ) ) );
}
/**
* Parse a field that is generally '1' or '0' but can be something else.
*
* @param string $field
* @return bool|string
*/
public function parse_bool_field( $field ) {
if ( '0' === $field ) {
return false;
}
if ( '1' === $field ) {
return true;
}
// Don't return explicit true or false for empty fields or values like 'notify'.
return esc_attr( $field );
}
/**
* Parse a float value field.
*
* @param string $field
* @return float|string
*/
public function parse_float_field( $field ) {
if ( '' === $field ) {
return $field;
}
return floatval( $field );
}
/**
* Parse a category field from a CSV.
* Categories are separated by commas and subcategories are "parent > subcategory".
*
* @param string $field
* @return array of arrays with "parent" and "name" keys.
*/
public function parse_categories( $field ) {
if ( empty( $field ) ) {
return array();
}
$sections = array_map( 'trim', explode( ',', $field ) );
$categories = array();
foreach ( $sections as $section ) {
// Top level category.
if ( false === strpos( $section, '>' ) ) {
$categories[] = array(
'parent' => false,
'name' => esc_attr( $section ),
);
// Subcategory.
} else {
$chunks = array_map( 'trim', explode( '>', $section ) );
$categories[] = array(
'parent' => esc_attr( reset( $chunks ) ),
'name' => esc_attr( end( $chunks ) ),
);
}
}
return $data;
}
public function parse_comma_field( $field ) {
return array_map( 'esc_attr', explode( ',', $field ) );
}
public function parse_categories( $field ) {
$sections = explode( ',', $field );
return $field;
return $categories;
}
/**

View File

@ -0,0 +1,165 @@
<?php
/**
* Meta
* @package WooCommerce\Tests\Importer
*/
class WC_Tests_Product_Importer extends WC_Unit_Test_Case {
/**
* Load up the importer classes since they aren't loaded by default.
*/
public function setUp() {
require_once ABSPATH . 'wp-admin/includes/import.php';
if ( ! class_exists( 'WP_Importer' ) ) {
$class_wp_importer = ABSPATH . 'wp-admin/includes/class-wp-importer.php';
if ( file_exists( $class_wp_importer ) ) {
require $class_wp_importer;
}
}
$bootstrap = WC_Unit_Tests_Bootstrap::instance();
require_once $bootstrap->plugin_dir . '/includes/admin/importers/class-wc-product-importer.php';
}
/**
* Test parse_comma_field.
* @since 3.1.0
*/
public function test_parse_comma_field() {
$importer = new WC_Product_Importer();
$field1 = 'thing 1, thing 2, thing 3';
$field2 = 'thing 1';
$field3 = '';
$expected1 = array( 'thing 1', 'thing 2', 'thing 3' );
$expected2 = array( 'thing 1' );
$expected3 = array();
$this->assertEquals( $expected1, $importer->parse_comma_field( $field1 ) );
$this->assertEquals( $expected2, $importer->parse_comma_field( $field2 ) );
$this->assertEquals( $expected3, $importer->parse_comma_field( $field3 ) );
}
/**
* Test parse_bool_field.
* @since 3.1.0
*/
public function test_parse_bool_field() {
$importer = new WC_Product_Importer();
$field1 = '1';
$field2 = '0';
$field3 = '';
$field4 = 'notify';
$this->assertEquals( true, $importer->parse_bool_field( $field1 ) );
$this->assertEquals( false, $importer->parse_bool_field( $field2 ) );
$this->assertEquals( '', $importer->parse_bool_field( $field3 ) );
$this->assertEquals( 'notify', $importer->parse_bool_field( $field4 ) );
}
/**
* Test parse_float_field.
* @since 3.1.0
*/
public function test_parse_float_field() {
$importer = new WC_Product_Importer();
$field1 = '12.45';
$field2 = '5';
$field3 = '';
$this->assertEquals( 12.45, $importer->parse_float_field( $field1 ) );
$this->assertEquals( 5, $importer->parse_float_field( $field2 ) );
$this->assertEquals( '', $importer->parse_float_field( $field3 ) );
}
/**
* Test parse_categories.
* @since 3.1.0
*/
public function test_parse_categories() {
$importer = new WC_Product_Importer();
$field1 = 'category1';
$field2 = 'category1, category2, category1 > subcategory1, category1 > subcategory2';
$field3 = '';
$expected1 = array(
array(
'parent' => false,
'name' => 'category1'
)
);
$expected2 = array(
array(
'parent' => false,
'name' => 'category1'
),
array(
'parent' => false,
'name' => 'category2'
),
array(
'parent' => 'category1',
'name' => 'subcategory1'
),
array(
'parent' => 'category1',
'name' => 'subcategory2'
)
);
$expected3 = array();
$this->assertEquals( $expected1, $importer->parse_categories( $field1 ) );
$this->assertEquals( $expected2, $importer->parse_categories( $field2 ) );
$this->assertEquals( $expected3, $importer->parse_categories( $field3 ) );
}
/**
* Test parse_data.
* @since 3.1.0
*/
public function test_parse_data() {
$importer = new WC_Product_Importer();
$data = array(
'headers' => array( 'ID', 'Weight', 'Price', 'Categories', 'Tags', 'Extra thing', 'Is featured?', 'Download 1 URL' ),
'data' => array(
array( '', '12.2', '12.50', 'category1, category1 > subcategory', 'products, things, etc', 'metadata', '1', '' ),
array( '12', '', '5', 'category2', '', '', '0', 'http://www.example.com' ),
)
);
$expected = array(
array(
'ID' => 0,
'Weight' => 12.2,
'Price' => '12.50',
'Categories' => array(
array( 'parent' => false, 'name' => 'category1' ),
array( 'parent' => 'category1', 'name' => 'subcategory' ),
),
'Tags' => array( 'products', 'things', 'etc' ),
'Extra thing' => 'metadata',
'Is featured?' => true,
'Download 1 URL' => '',
),
array(
'ID' => 12,
'Weight' => '',
'Price' => '5',
'Categories' => array(
array( 'parent' => false, 'name' => 'category2' ),
),
'Tags' => array(),
'Extra thing' => '',
'Is featured?' => false,
'Download 1 URL' => 'http://www.example.com',
),
);
$this->assertEquals( $expected, $importer->parse_data( $data ) );
}
}