Skip to content

Commit

Permalink
Add support for sessions
Browse files Browse the repository at this point in the history
  • Loading branch information
zaerl committed Dec 18, 2024
1 parent d957171 commit f10f145
Show file tree
Hide file tree
Showing 3 changed files with 225 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1022,8 +1022,7 @@ public function import_post_meta( $meta_item, $post_id ) {
}

do_action( 'wxr_importer_processed_post_meta', $post_id, $meta_item );
// @TODO: Check if post_id as ID is correct
$this->topological_sorter->map_entity( 'post_meta', $meta_item, $post_id );
$this->topological_sorter->map_entity( 'post_meta', $meta_item, $key );

return true;
}
Expand Down
191 changes: 110 additions & 81 deletions packages/playground/data-liberation/src/import/WP_Topological_Sorter.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ class WP_Topological_Sorter {
*/
protected $current_item = 0;

/**
* The entity types saved in the database.
*/
const ENTITY_TYPES = array(
'comment' => 1,
'comment_meta' => 2,
Expand All @@ -52,6 +55,18 @@ class WP_Topological_Sorter {
'term_meta' => 6,
);

/**
* The name of the field where the ID is saved.
*/
const ENTITY_TYPES_ID = array(
'comment' => 'comment_id',
'comment_meta' => 'meta_key',
'post' => 'post_id',
'post_meta' => 'meta_key',
'term' => 'term_id',
'term_meta' => 'meta_key',
);

/**
* Set the current session ID.
*/
Expand Down Expand Up @@ -200,15 +215,13 @@ public function map_entity( $entity_type, $data, $id = null, $additional_id = nu
// Items with a parent has at least a sort order of 2.
'sort_order' => 1,
);
$entity_id = null;
// Get the ID of the entity.
$entity_id = (string) $data[ self::ENTITY_TYPES_ID[ $entity_type ] ];

// Map the parent ID if the entity has one.
switch ( $entity_type ) {
case 'comment':
$entity_id = (string) $data['comment_id'];
break;
// @TODO: missing comment parent ID.
case 'comment_meta':
$entity_id = (string) $data['meta_key'];

if ( array_key_exists( 'comment_id', $data ) ) {
$new_entity['parent_id'] = $data['comment_id'];
}
Expand All @@ -219,30 +232,22 @@ public function map_entity( $entity_type, $data, $id = null, $additional_id = nu
$new_entity['parent_id'] = $data['post_parent'];
}
}

$entity_id = (string) $data['post_id'];
break;
case 'post_meta':
$entity_id = (string) $data['meta_key'];

if ( array_key_exists( 'post_id', $data ) ) {
$new_entity['parent_id'] = $data['post_id'];
}
break;
case 'term_meta':
$entity_id = (string) $data['meta_key'];

if ( array_key_exists( 'term_id', $data ) ) {
$new_entity['parent_id'] = $data['term_id'];
}
break;
case 'term':
$entity_id = (string) $data['term_id'];

if ( array_key_exists( 'parent', $data ) ) {
$new_entity['parent_id'] = $data['parent'];
}
break;
case 'term_meta':
if ( array_key_exists( 'term_id', $data ) ) {
$new_entity['parent_id'] = $data['term_id'];
}
break;
}

// The entity has been imported, so we can use the ID.
Expand All @@ -259,6 +264,7 @@ public function map_entity( $entity_type, $data, $id = null, $additional_id = nu
array(
'entity_id' => (string) $entity_id,
'entity_type' => self::ENTITY_TYPES[ $entity_type ],
'session_id' => $this->current_session,
),
array( '%s' )
);
Expand All @@ -279,65 +285,75 @@ public function map_entity( $entity_type, $data, $id = null, $additional_id = nu
* @return mixed|bool The mapped entity or false if the post is not found.
*/
public function get_mapped_entity( $entity_type, $entity, $id = null, $additional_id = null ) {
$current_session = $this->current_session;
$already_mapped = false;

switch ( $entity_type ) {
case 'comment':
// The ID is the post ID.
$mapped_ids = $this->get_mapped_ids( $id, self::ENTITY_TYPES['post'] );

if ( $mapped_ids && ! is_null( $mapped_ids['mapped_id'] ) ) {
$entity['comment_post_ID'] = $mapped_ids['mapped_id'];
}
break;
case 'comment_meta':
// The ID is the comment ID.
$mapped_ids = $this->get_mapped_ids( $id, self::ENTITY_TYPES['comment'] );

if ( $mapped_ids && ! is_null( $mapped_ids['mapped_id'] ) ) {
$entity['comment_id'] = $mapped_ids['mapped_id'];
}
break;
case 'post':
// The ID is the parent post ID.
$mapped_ids = $this->get_mapped_ids( $id, self::ENTITY_TYPES['post'] );
$already_mapped = false;
$mapped_entity = null;

if ( $mapped_ids && ! is_null( $mapped_ids['mapped_id'] ) ) {
$entity['post_parent'] = $mapped_ids['mapped_id'];
}
if ( ! array_key_exists( $entity_type, self::ENTITY_TYPES ) ) {
return $entity;
}

$mapped_ids = $this->get_mapped_ids( $entity['post_id'], self::ENTITY_TYPES['post'] );
// Get the mapped IDs of the entity.
$id_field = self::ENTITY_TYPES_ID[ $entity_type ];
$mapped_entity = $this->get_mapped_ids( $entity[ $id_field ], self::ENTITY_TYPES[ $entity_type ] );

if ( $mapped_ids && ! is_null( $mapped_ids['mapped_id'] ) ) {
$entity['post_id'] = $mapped_ids['mapped_id'];
$already_mapped = true;
}
break;
case 'post_meta':
// The ID is the post ID.
$mapped_ids = $this->get_mapped_ids( $id, self::ENTITY_TYPES['post'] );

if ( $mapped_ids ) {
$entity['post_id'] = $mapped_ids['mapped_id'];
}
break;
case 'term':
// No ID provided.
break;
case 'term_meta':
// The ID is the term ID.
$mapped_ids = $this->get_mapped_ids( $id, self::ENTITY_TYPES['term'] );
if ( $mapped_entity ) {
// Get entity parents.
switch ( $entity_type ) {
case 'comment':
// The ID is the post ID.
$mapped_ids = $this->get_mapped_ids( $id, self::ENTITY_TYPES['post'] );

if ( $mapped_ids && ! is_null( $mapped_ids['mapped_id'] ) ) {
$entity['term_id'] = $mapped_ids['mapped_id'];
}
break;
if ( $mapped_ids && ! is_null( $mapped_ids['mapped_id'] ) ) {
// Save the mapped ID of comment parent post.
$entity['comment_post_ID'] = $mapped_ids['mapped_id'];
}
break;
case 'comment_meta':
// The ID is the comment ID.
$mapped_ids = $this->get_mapped_ids( $id, self::ENTITY_TYPES['comment'] );

if ( $mapped_ids && ! is_null( $mapped_ids['mapped_id'] ) ) {
// Save the mapped ID of comment meta parent comment.
$entity['comment_id'] = $mapped_ids['mapped_id'];
}
break;
case 'post':
// The ID is the parent post ID.
$mapped_ids = $this->get_mapped_ids( $id, self::ENTITY_TYPES['post'] );

if ( $mapped_ids && ! is_null( $mapped_ids['mapped_id'] ) ) {
// Save the mapped ID of post parent.
$entity['post_parent'] = $mapped_ids['mapped_id'];
}
break;
case 'post_meta':
// The ID is the post ID.
$mapped_ids = $this->get_mapped_ids( $id, self::ENTITY_TYPES['post'] );

if ( $mapped_ids ) {
// Save the mapped ID of post meta parent post.
$entity['post_id'] = $mapped_ids['mapped_id'];
}
break;
case 'term_meta':
// The ID is the term ID.
$mapped_ids = $this->get_mapped_ids( $id, self::ENTITY_TYPES['term'] );

if ( $mapped_ids && ! is_null( $mapped_ids['mapped_id'] ) ) {
// Save the mapped ID of term meta parent term.
$entity['term_id'] = $mapped_ids['mapped_id'];
}
}
}

if ( $already_mapped ) {
// This is used to skip the post if it has already been mapped.
$entity['_already_mapped'] = true;
if ( $mapped_entity ) {
if ( ! is_null( $mapped_entity['mapped_id'] ) ) {
// This is used to skip an entity if it has already been mapped.
$entity[ $id_field ] = $mapped_entity['mapped_id'];
$entity['_already_mapped'] = true;
} else {
$entity['_already_mapped'] = false;
}
}

return $entity;
Expand All @@ -358,15 +374,28 @@ private function get_mapped_ids( $id, $type ) {
return null;
}

$results = $wpdb->get_results(
$wpdb->prepare(
'SELECT entity_id, mapped_id FROM %i WHERE entity_id = %s AND entity_type = %d LIMIT 1',
self::get_table_name(),
(string) $id,
$type
),
ARRAY_A
);
if ( is_null( $this->current_session ) ) {
$results = $wpdb->get_results(
$wpdb->prepare(
'SELECT entity_id, mapped_id FROM %i WHERE entity_id = %s AND entity_type = %d AND session_id IS NULL LIMIT 1',
self::get_table_name(),
(string) $id,
$type
),
ARRAY_A
);
} else {
$results = $wpdb->get_results(
$wpdb->prepare(
'SELECT entity_id, mapped_id FROM %i WHERE entity_id = %s AND entity_type = %d AND session_id = %d LIMIT 1',
self::get_table_name(),
(string) $id,
$type,
$this->current_session
),
ARRAY_A
);
}

if ( $results && 1 === count( $results ) ) {
return $results[0];
Expand Down
114 changes: 114 additions & 0 deletions packages/playground/data-liberation/tests/WPTopologicalSorterTests.php
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,120 @@ public function _no_test_serialized_term_meta() {
$this->assertSame( $expected_array, get_term_meta( $term->term_id, 'array', true ) );
}

/**
* Multiple sessions tests.
*/
public function test_topological_sorter_set_session() {
$sorter = new WP_Topological_Sorter();
$post = array( 'post_id' => 1 );
$mapped = array(
'post_id' => 1,
'_already_mapped' => false
);

// Add a first session.
$sorter->set_session( 1 );
$sorter->map_entity( 'post', $post );
$this->assertSame( $mapped, $sorter->get_mapped_entity( 'post', $post ) );
// Map the same entity again but with a different ID (the real one).
$sorter->map_entity( 'post', $post, 2 );

$mapped['_already_mapped'] = true;
$mapped['post_id'] = '2';
$this->assertSame( $mapped, $sorter->get_mapped_entity( 'post', $post ) );

$mapped = array(
'post_id' => 1,
'_already_mapped' => false
);

// Add a second session.
$sorter->set_session( 2 );
$sorter->map_entity( 'post', $post );
$this->assertSame( $mapped, $sorter->get_mapped_entity( 'post', $post ) );
// Map the same entity again but with a different ID (the real one).
$sorter->map_entity( 'post', $post, 3 );

$mapped['_already_mapped'] = true;
$mapped['post_id'] = '3';
$this->assertSame( $mapped, $sorter->get_mapped_entity( 'post', $post ) );

$sorter->set_session( 1 );
$mapped['post_id'] = '2';
// First session should still have the old mapping.
$this->assertSame( $mapped, $sorter->get_mapped_entity( 'post', $post ) );

$sorter->delete_session( 1 );
$this->assertSame( $post, $sorter->get_mapped_entity( 'post', $post ) );

$sorter->set_session( 2 );
$mapped['post_id'] = '3';
$this->assertSame( $mapped, $sorter->get_mapped_entity( 'post', $post ) );

$sorter->delete_session( 2 );
$this->assertSame( $post, $sorter->get_mapped_entity( 'post', $post ) );
}

/**
* Null session tests.
*/
public function test_topological_sorter_no_session() {
$sorter = new WP_Topological_Sorter();
$post = array( 'post_id' => 1 );
$mapped = array(
'post_id' => 1,
'_already_mapped' => false
);

// Add a first session.
$sorter->map_entity( 'post', $post );
$this->assertSame( $mapped, $sorter->get_mapped_entity( 'post', $post ) );
// Map the same entity again but with a different ID (the real one).
$sorter->map_entity( 'post', $post, 2 );

$mapped['_already_mapped'] = true;
$mapped['post_id'] = '2';
$this->assertSame( $mapped, $sorter->get_mapped_entity( 'post', $post ) );
}

/**
* Null session tests.
*/
public function test_topological_sorter_multiple_entities() {
$sorter = new WP_Topological_Sorter();
$post = array( 'post_id' => 1 );
$term = array( 'term_id' => 1 );
$mapped_post = array(
'post_id' => 1,
'_already_mapped' => false
);
$mapped_term = array(
'term_id' => 1,
'_already_mapped' => false
);

// Add a first session.
$sorter->set_session( 1 );

$sorter->map_entity( 'post', $post );
$sorter->map_entity( 'term', $term );

$this->assertSame( $mapped_post, $sorter->get_mapped_entity( 'post', $post ) );
$this->assertSame( $mapped_term, $sorter->get_mapped_entity( 'term', $term ) );

// Map the same entity again but with a different ID (the real one).
$sorter->map_entity( 'post', $post, 2 );
$sorter->map_entity( 'term', $term, 2 );

$mapped_post['_already_mapped'] = true;
$mapped_post['post_id'] = '2';
$this->assertSame( $mapped_post, $sorter->get_mapped_entity( 'post', $post ) );

$mapped_term['_already_mapped'] = true;
$mapped_term['term_id'] = '2';
$this->assertSame( $mapped_term, $sorter->get_mapped_entity( 'term', $term ) );
}

/**
* Import a WXR file.
*/
Expand Down

0 comments on commit f10f145

Please sign in to comment.